Skip to content

Commit 383b9a9

Browse files
authored
Merge pull request #36 from OrangeFox86/31-fault-while-using-retro-fighters-controller
31 addressed faults with retro fighters controller
2 parents 45331bf + 2d4ac27 commit 383b9a9

10 files changed

Lines changed: 148 additions & 55 deletions

src/coreLib/DreamcastMainNode.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ DreamcastMainNode::DreamcastMainNode(MapleBusInterface& bus,
1717
playerData),
1818
mSubNodes(),
1919
mTransmissionTimeliner(bus, prioritizedTxScheduler),
20-
mScheduleId(-1)
20+
mScheduleId(-1),
21+
mCommFailCount(0)
2122
{
2223
addInfoRequestToSchedule();
2324
mSubNodes.reserve(DreamcastPeripheral::MAX_SUB_PERIPHERALS);
@@ -57,6 +58,9 @@ void DreamcastMainNode::txComplete(std::shared_ptr<const MaplePacket> packet,
5758
DEBUG_PRINT("P%lu connected (", mPlayerData.playerIndex + 1);
5859
debugPrintPeripherals();
5960
DEBUG_PRINT(")\n");
61+
62+
// Reset failure count
63+
mCommFailCount = 0;
6064
}
6165

6266
if (mask > 0)
@@ -93,6 +97,9 @@ void DreamcastMainNode::readTask(uint64_t currentTimeUs)
9397
// See if there is anything to receive
9498
if (readStatus.busPhase == MapleBusInterface::Phase::READ_COMPLETE)
9599
{
100+
// Reset failure count
101+
mCommFailCount = 0;
102+
96103
// Check addresses to determine what sub nodes are attached
97104
uint8_t sendAddr = readStatus.received->getFrameSenderAddr();
98105
uint8_t recAddr = readStatus.received->getFrameRecipientAddr();
@@ -137,7 +144,7 @@ void DreamcastMainNode::readTask(uint64_t currentTimeUs)
137144
|| readStatus.busPhase == MapleBusInterface::Phase::WRITE_FAILED)
138145
{
139146
uint8_t recipientAddr = readStatus.transmission->packet->getFrameRecipientAddr();
140-
if (recipientAddr & mAddr)
147+
if ((recipientAddr & mAddr) && ++mCommFailCount >= MAX_FAILURE_DISCONNECT_COUNT)
141148
{
142149
// A transmission failure on a main node must cause peripheral disconnect
143150
if (mPeripherals.size() > 0)
@@ -147,6 +154,7 @@ void DreamcastMainNode::readTask(uint64_t currentTimeUs)
147154

148155
disconnectMainPeripheral(currentTimeUs);
149156
}
157+
mCommFailCount = 0;
150158
}
151159
else
152160
{

src/coreLib/DreamcastMainNode.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ class DreamcastMainNode : public DreamcastNode
6565
public:
6666
//! Number of microseconds in between each info request when no peripheral is detected
6767
static const uint32_t US_PER_CHECK = 16000;
68+
//! Number of communication failures before main peripheral is disconnected
69+
static const uint32_t MAX_FAILURE_DISCONNECT_COUNT = 3;
6870

6971
protected:
7072
//! The sub nodes under this node
@@ -73,4 +75,6 @@ class DreamcastMainNode : public DreamcastNode
7375
TransmissionTimeliner mTransmissionTimeliner;
7476
//! ID of the device info request auto reload transmission this object added to the schedule
7577
int64_t mScheduleId;
78+
//! Current count of number of communication failures
79+
uint32_t mCommFailCount;
7680
};

src/coreLib/PrioritizedTxScheduler.cpp

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@ PrioritizedTxScheduler::PrioritizedTxScheduler() :
1414
mSchedule.resize(PRIORITY_COUNT);
1515
}
1616

17+
PrioritizedTxScheduler::PrioritizedTxScheduler(uint32_t max) :
18+
mNextId(1),
19+
mSchedule()
20+
{
21+
mSchedule.resize(max + 1);
22+
}
23+
1724
PrioritizedTxScheduler::~PrioritizedTxScheduler() {}
1825

1926
uint32_t PrioritizedTxScheduler::add(std::shared_ptr<Transmission> tx)
@@ -88,9 +95,9 @@ uint64_t PrioritizedTxScheduler::computeNextTimeCadence(uint64_t currentTime,
8895
}
8996
}
9097

91-
std::shared_ptr<const Transmission> PrioritizedTxScheduler::popNext(uint64_t time)
98+
PrioritizedTxScheduler::ScheduleItem PrioritizedTxScheduler::peekNext(uint64_t time)
9299
{
93-
std::shared_ptr<Transmission> item = nullptr;
100+
ScheduleItem scheduleItem;
94101

95102
// Find a priority list with item ready to be popped
96103
std::vector<std::list<std::shared_ptr<Transmission>>>::iterator scheduleIter = mSchedule.begin();
@@ -148,18 +155,38 @@ std::shared_ptr<const Transmission> PrioritizedTxScheduler::popNext(uint64_t tim
148155

149156
if (found)
150157
{
151-
// Pop it!
152-
item = (*itemIter);
153-
scheduleIter->erase(itemIter);
154-
155-
// Reschedule this if auto repeat settings are valid
156-
if (item != nullptr
157-
&& item->autoRepeatUs > 0
158-
&& (item->autoRepeatEndTimeUs == 0 || time <= item->autoRepeatEndTimeUs))
159-
{
160-
item->nextTxTimeUs = computeNextTimeCadence(time, item->autoRepeatUs, item->nextTxTimeUs);
161-
add(item);
162-
}
158+
scheduleItem.mScheduleIter = scheduleIter;
159+
scheduleItem.mItemIter = itemIter;
160+
scheduleItem.mTime = time;
161+
scheduleItem.mIsValid = true;
162+
}
163+
}
164+
165+
return scheduleItem;
166+
}
167+
168+
std::shared_ptr<Transmission> PrioritizedTxScheduler::popItem(ScheduleItem& scheduleItem)
169+
{
170+
std::shared_ptr<Transmission> item = nullptr;
171+
172+
if (scheduleItem.mIsValid)
173+
{
174+
// Save the transmission
175+
item = scheduleItem.getTx();
176+
177+
// Pop it!
178+
scheduleItem.mScheduleIter->erase(scheduleItem.mItemIter);
179+
scheduleItem.mIsValid = false;
180+
181+
// Reschedule this if auto repeat settings are valid
182+
if (item != nullptr
183+
&& item->autoRepeatUs > 0
184+
&& (item->autoRepeatEndTimeUs == 0 || scheduleItem.mTime <= item->autoRepeatEndTimeUs))
185+
{
186+
item->nextTxTimeUs = computeNextTimeCadence(scheduleItem.mTime,
187+
item->autoRepeatUs,
188+
item->nextTxTimeUs);
189+
add(item);
163190
}
164191
}
165192

src/coreLib/PrioritizedTxScheduler.hpp

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,38 @@ class PrioritizedTxScheduler
2323
PRIORITY_COUNT
2424
};
2525

26+
//! Points to a schedule item within the current schedule
27+
class ScheduleItem
28+
{
29+
//! Only the PrioritizedTxScheduler may modify private elements here
30+
friend PrioritizedTxScheduler;
31+
32+
public:
33+
//! Constructor
34+
ScheduleItem() : mIsValid(false), mTime(0) {}
35+
36+
//! @returns the transmission for this schedule item
37+
std::shared_ptr<Transmission> getTx() {return mIsValid ? *mItemIter : nullptr;}
38+
39+
private:
40+
//! Set to true iff iterators are valid
41+
bool mIsValid;
42+
//! The schedule group
43+
std::vector<std::list<std::shared_ptr<Transmission>>>::iterator mScheduleIter;
44+
//! The item within the schedule group
45+
std::list<std::shared_ptr<Transmission>>::iterator mItemIter;
46+
//! The time at which this item was peeked
47+
uint64_t mTime;
48+
};
49+
2650
public:
2751
//! Default constructor
2852
PrioritizedTxScheduler();
2953

54+
//! Constructor with custom priority list
55+
//! @param[in] max The maximum accepted priority
56+
PrioritizedTxScheduler(uint32_t max);
57+
3058
//! Virtual destructor
3159
virtual ~PrioritizedTxScheduler();
3260

@@ -49,11 +77,15 @@ class PrioritizedTxScheduler
4977
uint32_t autoRepeatUs=0,
5078
uint64_t autoRepeatEndTimeUs=0);
5179

52-
//! Pops the next scheduled packet, given the current time
80+
//! Peeks the next scheduled packet, given the current time
5381
//! @param[in] time The current time
5482
//! @returns nullptr if no scheduled packet is available for the given time
55-
//! @returns the next sceduled packet for the given current time
56-
std::shared_ptr<const Transmission> popNext(uint64_t time);
83+
//! @returns the next scheduled item for the given current time
84+
ScheduleItem peekNext(uint64_t time);
85+
86+
//! Pops a schedule item that was retrieved using peekNext
87+
//! @param[in,out] scheduleItem The schedule item to pop and invalidate
88+
std::shared_ptr<Transmission> popItem(ScheduleItem& scheduleItem);
5789

5890
//! Cancels scheduled transmission by transmission ID
5991
//! @param[in] transmissionId The transmission ID of the transmissions to cancel

src/coreLib/TransmissionTimeliner.cpp

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
#include <assert.h>
33

44
TransmissionTimeliner::TransmissionTimeliner(MapleBusInterface& bus, std::shared_ptr<PrioritizedTxScheduler> schedule):
5-
mBus(bus), mSchedule(schedule), mCurrentTx(nullptr), mNextTx(nullptr)
5+
mBus(bus), mSchedule(schedule), mCurrentTx(nullptr)
66
{}
77

88
TransmissionTimeliner::ReadStatus TransmissionTimeliner::readTask(uint64_t currentTimeUs)
@@ -34,20 +34,22 @@ std::shared_ptr<const Transmission> TransmissionTimeliner::writeTask(uint64_t cu
3434
{
3535
std::shared_ptr<const Transmission> txSent = nullptr;
3636

37-
// Get next transmission
38-
if (mNextTx == nullptr && !mBus.isBusy())
37+
if (!mBus.isBusy())
3938
{
40-
mNextTx = mSchedule->popNext(currentTimeUs);
41-
}
42-
43-
// Transmit
44-
if (mNextTx != nullptr)
45-
{
46-
assert(mNextTx->packet->isValid());
47-
if (mBus.write(*mNextTx->packet, mNextTx->expectResponse))
39+
PrioritizedTxScheduler::ScheduleItem item = mSchedule->peekNext(currentTimeUs);
40+
txSent = item.getTx();
41+
if (txSent != nullptr)
4842
{
49-
mCurrentTx = txSent = mNextTx;
50-
mNextTx = nullptr;
43+
assert(txSent->packet->isValid());
44+
if (mBus.write(*txSent->packet, txSent->expectResponse))
45+
{
46+
mCurrentTx = txSent;
47+
mSchedule->popItem(item);
48+
}
49+
else
50+
{
51+
txSent = nullptr;
52+
}
5153
}
5254
}
5355

src/coreLib/TransmissionTimeliner.hpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,4 @@ class TransmissionTimeliner
4747
std::shared_ptr<PrioritizedTxScheduler> mSchedule;
4848
//! The currently sending transmission
4949
std::shared_ptr<const Transmission> mCurrentTx;
50-
//! Recently popped transmission that is waiting to be sent
51-
std::shared_ptr<const Transmission> mNextTx;
5250
};

src/coreLib/parsers/MaplePassthroughCommandParser.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,24 +16,24 @@ class EchoTransmitter : public Transmitter
1616
{
1717
if (writeFailed)
1818
{
19-
printf("%lu: failed write\n", tx->transmissionId);
19+
printf("%lu: failed write\n", (long unsigned int)tx->transmissionId);
2020
}
2121
else
2222
{
23-
printf("%lu: failed read\n", tx->transmissionId);
23+
printf("%lu: failed read\n", (long unsigned int)tx->transmissionId);
2424
}
2525
}
2626

2727
virtual void txComplete(std::shared_ptr<const MaplePacket> packet,
2828
std::shared_ptr<const Transmission> tx) final
2929
{
30-
printf("%lu: complete {", tx->transmissionId);
31-
printf("%08lX", packet->frameWord);
30+
printf("%lu: complete {", (long unsigned int)tx->transmissionId);
31+
printf("%08lX", (long unsigned int)packet->frameWord);
3232
for (std::vector<uint32_t>::const_iterator iter = packet->payload.begin();
3333
iter != packet->payload.end();
3434
++iter)
3535
{
36-
printf(" %08lX", *iter);
36+
printf(" %08lX", (long unsigned int)*iter);
3737
}
3838
printf("}\n");
3939
}
@@ -126,10 +126,10 @@ void MaplePassthroughCommandParser::submit(const char* chars, uint32_t len)
126126
packet,
127127
true);
128128
std::vector<uint32_t>::iterator iter = words.begin();
129-
printf("%lu: added {%08lX", id, *iter++);
129+
printf("%lu: added {%08lX", (long unsigned int)id, (long unsigned int)*iter++);
130130
for(; iter < words.end(); ++iter)
131131
{
132-
printf(" %08lX", *iter);
132+
printf(" %08lX", (long unsigned int)*iter);
133133
}
134134
printf("}\n");
135135
}

src/test/MainNodeTests.cpp

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ class MainNodeTest : public ::testing::Test
116116
mScreenData(mMutex),
117117
mPlayerData{0, mDreamcastControllerObserver, mScreenData, mClock, mUsbFileSystem},
118118
mMapleBus(),
119-
mPrioritizedTxScheduler(std::make_shared<PrioritizedTxScheduler>(DreamcastMainNode::MAX_PRIORITY)),
119+
mPrioritizedTxScheduler(std::make_shared<PrioritizedTxScheduler>(PrioritizedTxScheduler::PRIORITY_COUNT - 1)),
120120
mDreamcastMainNode(mMapleBus, mPlayerData, mPrioritizedTxScheduler)
121121
{}
122122

@@ -265,9 +265,9 @@ TEST_F(MainNodeTest, peripheralDisconnect)
265265
// The task will process events, and it will return read failure
266266
MapleBusInterface::Status status;
267267
status.phase = MapleBusInterface::Phase::READ_FAILED;
268-
EXPECT_CALL(mMapleBus, processEvents(1000000))
269-
.Times(1)
270-
.WillOnce(Return(status));
268+
EXPECT_CALL(mMapleBus, processEvents(_))
269+
.Times(3)
270+
.WillRepeatedly(Return(status));
271271
// All sub node's task functions will be called with the current time
272272
EXPECT_CALL(*mDreamcastMainNode.mMockedSubNodes[0], mainPeripheralDisconnected()).Times(1);
273273
EXPECT_CALL(*mDreamcastMainNode.mMockedSubNodes[1], mainPeripheralDisconnected()).Times(1);
@@ -280,9 +280,25 @@ TEST_F(MainNodeTest, peripheralDisconnect)
280280
EXPECT_CALL(*mDreamcastMainNode.mMockedSubNodes[2], task(1000000)).Times(1);
281281
EXPECT_CALL(*mDreamcastMainNode.mMockedSubNodes[3], task(1000000)).Times(1);
282282
EXPECT_CALL(*mDreamcastMainNode.mMockedSubNodes[4], task(1000000)).Times(1);
283+
EXPECT_CALL(*mDreamcastMainNode.mMockedSubNodes[0], task(1000001)).Times(1);
284+
EXPECT_CALL(*mDreamcastMainNode.mMockedSubNodes[1], task(1000001)).Times(1);
285+
EXPECT_CALL(*mDreamcastMainNode.mMockedSubNodes[2], task(1000001)).Times(1);
286+
EXPECT_CALL(*mDreamcastMainNode.mMockedSubNodes[3], task(1000001)).Times(1);
287+
EXPECT_CALL(*mDreamcastMainNode.mMockedSubNodes[4], task(1000001)).Times(1);
288+
EXPECT_CALL(*mDreamcastMainNode.mMockedSubNodes[0], task(1000002)).Times(1);
289+
EXPECT_CALL(*mDreamcastMainNode.mMockedSubNodes[1], task(1000002)).Times(1);
290+
EXPECT_CALL(*mDreamcastMainNode.mMockedSubNodes[2], task(1000002)).Times(1);
291+
EXPECT_CALL(*mDreamcastMainNode.mMockedSubNodes[3], task(1000002)).Times(1);
292+
EXPECT_CALL(*mDreamcastMainNode.mMockedSubNodes[4], task(1000002)).Times(1);
293+
// The peripheral will get to run task twice before it disconnects on the 3rd failure
294+
EXPECT_CALL(*mockedDreamcastPeripheral, task(1000000)).Times(1);
295+
EXPECT_CALL(*mockedDreamcastPeripheral, task(1000001)).Times(1);
283296

284297
// --- TEST EXECUTION ---
285298
mDreamcastMainNode.task(1000000);
299+
mDreamcastMainNode.task(1000001);
300+
// Disconnection happens on 3rd failure
301+
mDreamcastMainNode.task(1000002);
286302

287303
// --- EXPECTATIONS ---
288304
// All peripherals removed

0 commit comments

Comments
 (0)