1
0
mirror of https://github.com/DCC-EX/CommandStation-EX.git synced 2024-12-24 13:21:23 +01:00

Merge branch 'devel_reminders' into devel

This commit is contained in:
Asbelos 2023-11-30 19:54:20 +00:00
commit 6637ea6fe7
3 changed files with 60 additions and 32 deletions

11
DCC.cpp
View File

@ -595,7 +595,7 @@ void DCC::loop() {
void DCC::issueReminders() { void DCC::issueReminders() {
// if the main track transmitter still has a pending packet, skip this time around. // if the main track transmitter still has a pending packet, skip this time around.
if ( DCCWaveform::mainTrack.getPacketPending()) return; if (!DCCWaveform::mainTrack.isReminderWindowOpen()) return;
// Move to next loco slot. If occupied, send a reminder. // Move to next loco slot. If occupied, send a reminder.
int reg = lastLocoReminder+1; int reg = lastLocoReminder+1;
if (reg > highestUsedReg) reg = 0; // Go to start of table if (reg > highestUsedReg) reg = 0; // Go to start of table
@ -620,14 +620,23 @@ bool DCC::issueReminder(int reg) {
case 1: // remind function group 1 (F0-F4) case 1: // remind function group 1 (F0-F4)
if (flags & FN_GROUP_1) if (flags & FN_GROUP_1)
setFunctionInternal(loco,0, 128 | ((functions>>1)& 0x0F) | ((functions & 0x01)<<4)); // 100D DDDD setFunctionInternal(loco,0, 128 | ((functions>>1)& 0x0F) | ((functions & 0x01)<<4)); // 100D DDDD
#ifdef DISABLE_FUNCTION_REMINDERS
flags&= ~FN_GROUP_1; // dont send them again
#endif
break; break;
case 2: // remind function group 2 F5-F8 case 2: // remind function group 2 F5-F8
if (flags & FN_GROUP_2) if (flags & FN_GROUP_2)
setFunctionInternal(loco,0, 176 | ((functions>>5)& 0x0F)); // 1011 DDDD setFunctionInternal(loco,0, 176 | ((functions>>5)& 0x0F)); // 1011 DDDD
#ifdef DISABLE_FUNCTION_REMINDERS
flags&= ~FN_GROUP_2; // dont send them again
#endif
break; break;
case 3: // remind function group 3 F9-F12 case 3: // remind function group 3 F9-F12
if (flags & FN_GROUP_3) if (flags & FN_GROUP_3)
setFunctionInternal(loco,0, 160 | ((functions>>9)& 0x0F)); // 1010 DDDD setFunctionInternal(loco,0, 160 | ((functions>>9)& 0x0F)); // 1010 DDDD
#ifdef DISABLE_FUNCTION_REMINDERS
flags&= ~FN_GROUP_3; // dont send them again
#endif
break; break;
case 4: // remind function group 4 F13-F20 case 4: // remind function group 4 F13-F20
if (flags & FN_GROUP_4) if (flags & FN_GROUP_4)

View File

@ -106,6 +106,7 @@ void DCCWaveform::interruptHandler() {
DCCWaveform::DCCWaveform( byte preambleBits, bool isMain) { DCCWaveform::DCCWaveform( byte preambleBits, bool isMain) {
isMainTrack = isMain; isMainTrack = isMain;
packetPending = false; packetPending = false;
reminderWindowOpen = false;
memcpy(transmitPacket, idlePacket, sizeof(idlePacket)); memcpy(transmitPacket, idlePacket, sizeof(idlePacket));
state = WAVE_START; state = WAVE_START;
// The +1 below is to allow the preamble generator to create the stop bit // The +1 below is to allow the preamble generator to create the stop bit
@ -127,9 +128,15 @@ void DCCWaveform::interrupt2() {
if (remainingPreambles > 0 ) { if (remainingPreambles > 0 ) {
state=WAVE_MID_1; // switch state to trigger LOW on next interrupt state=WAVE_MID_1; // switch state to trigger LOW on next interrupt
remainingPreambles--; remainingPreambles--;
// As we get to the end of the preambles, open the reminder window.
// This delays any reminder insertion until the last moment so
// that the reminder doesn't block a more urgent packet.
reminderWindowOpen=transmitRepeats==0 && remainingPreambles<4 && remainingPreambles>1;
if (remainingPreambles==1) promotePendingPacket();
// Update free memory diagnostic as we don't have anything else to do this time. // Update free memory diagnostic as we don't have anything else to do this time.
// Allow for checkAck and its called functions using 22 bytes more. // Allow for checkAck and its called functions using 22 bytes more.
DCCTimer::updateMinimumFreeMemoryISR(22); else DCCTimer::updateMinimumFreeMemoryISR(22);
return; return;
} }
@ -148,30 +155,9 @@ void DCCWaveform::interrupt2() {
if (bytes_sent >= transmitLength) { if (bytes_sent >= transmitLength) {
// end of transmission buffer... repeat or switch to next message // end of transmission buffer... repeat or switch to next message
bytes_sent = 0; bytes_sent = 0;
// preamble for next packet will start...
remainingPreambles = requiredPreambles; remainingPreambles = requiredPreambles;
if (transmitRepeats > 0) {
transmitRepeats--;
} }
else if (packetPending) {
// Copy pending packet to transmit packet
// a fixed length memcpy is faster than a variable length loop for these small lengths
// for (int b = 0; b < pendingLength; b++) transmitPacket[b] = pendingPacket[b];
memcpy( transmitPacket, pendingPacket, sizeof(pendingPacket));
transmitLength = pendingLength;
transmitRepeats = pendingRepeats;
packetPending = false;
clearResets();
}
else {
// Fortunately reset and idle packets are the same length
memcpy( transmitPacket, isMainTrack ? idlePacket : resetPacket, sizeof(idlePacket));
transmitLength = sizeof(idlePacket);
transmitRepeats = 0;
if (getResets() < 250) sentResetsSincePacket++; // only place to increment (private!)
}
}
} }
} }
#pragma GCC pop_options #pragma GCC pop_options
@ -193,8 +179,39 @@ void DCCWaveform::schedulePacket(const byte buffer[], byte byteCount, byte repea
packetPending = true; packetPending = true;
clearResets(); clearResets();
} }
bool DCCWaveform::getPacketPending() {
return packetPending; bool DCCWaveform::isReminderWindowOpen() {
return reminderWindowOpen && ! packetPending;
}
void DCCWaveform::promotePendingPacket() {
// fill the transmission packet from the pending packet
// Just keep going if repeating
if (transmitRepeats > 0) {
transmitRepeats--;
return;
}
if (packetPending) {
// Copy pending packet to transmit packet
// a fixed length memcpy is faster than a variable length loop for these small lengths
// for (int b = 0; b < pendingLength; b++) transmitPacket[b] = pendingPacket[b];
memcpy( transmitPacket, pendingPacket, sizeof(pendingPacket));
transmitLength = pendingLength;
transmitRepeats = pendingRepeats;
packetPending = false;
clearResets();
return;
}
// nothing to do, just send idles or resets
// Fortunately reset and idle packets are the same length
memcpy( transmitPacket, isMainTrack ? idlePacket : resetPacket, sizeof(idlePacket));
transmitLength = sizeof(idlePacket);
transmitRepeats = 0;
if (getResets() < 250) sentResetsSincePacket++; // only place to increment (private!)
} }
#endif #endif
@ -266,15 +283,15 @@ void DCCWaveform::schedulePacket(const byte buffer[], byte byteCount, byte repea
} }
} }
bool DCCWaveform::getPacketPending() { bool DCCWaveform::isReminderWindowOpen() {
if(isMainTrack) { if(isMainTrack) {
if (rmtMainChannel == NULL) if (rmtMainChannel == NULL)
return true; return false;
return rmtMainChannel->busy(); return !rmtMainChannel->busy();
} else { } else {
if (rmtProgChannel == NULL) if (rmtProgChannel == NULL)
return true; return false;
return rmtProgChannel->busy(); return !rmtProgChannel->busy();
} }
} }
void IRAM_ATTR DCCWaveform::loop() { void IRAM_ATTR DCCWaveform::loop() {

View File

@ -76,11 +76,13 @@ class DCCWaveform {
}; };
#endif #endif
void schedulePacket(const byte buffer[], byte byteCount, byte repeats); void schedulePacket(const byte buffer[], byte byteCount, byte repeats);
bool getPacketPending(); bool isReminderWindowOpen();
void promotePendingPacket();
private: private:
#ifndef ARDUINO_ARCH_ESP32 #ifndef ARDUINO_ARCH_ESP32
volatile bool packetPending; volatile bool packetPending;
volatile bool reminderWindowOpen;
volatile byte sentResetsSincePacket; volatile byte sentResetsSincePacket;
#else #else
volatile uint32_t resetPacketBase; volatile uint32_t resetPacketBase;