mirror of
https://github.com/DCC-EX/CommandStation-EX.git
synced 2024-11-24 08:36:14 +01:00
Compare commits
6 Commits
72a9078172
...
3ba8cce3c0
Author | SHA1 | Date | |
---|---|---|---|
|
3ba8cce3c0 | ||
|
08f0a2b37d | ||
|
6637ea6fe7 | ||
|
a69017f8bb | ||
|
3f4099520a | ||
|
07fd4bc309 |
11
DCC.cpp
11
DCC.cpp
|
@ -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)
|
||||||
|
|
|
@ -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,29 +155,8 @@ 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!)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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() {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -3,7 +3,9 @@
|
||||||
|
|
||||||
#include "StringFormatter.h"
|
#include "StringFormatter.h"
|
||||||
|
|
||||||
#define VERSION "5.2.13"
|
#define VERSION "5.2.14"
|
||||||
|
// 5.2.14 - Reminder window DCC packet optimization
|
||||||
|
// - Optional #define DISABLE_FUNCTION_REMINDERS
|
||||||
// 5.2.13 - EXRAIL STEALTH
|
// 5.2.13 - EXRAIL STEALTH
|
||||||
// 5.2.12 - ESP32 add AP mode LCD messages with SSID/PW for
|
// 5.2.12 - ESP32 add AP mode LCD messages with SSID/PW for
|
||||||
// - STM32 change to UID_BASE constants in DCCTimerSTM32 rather than raw hex addresses for UID registers
|
// - STM32 change to UID_BASE constants in DCCTimerSTM32 rather than raw hex addresses for UID registers
|
||||||
|
|
Loading…
Reference in New Issue
Block a user