1
0
mirror of https://github.com/DCC-EX/CommandStation-EX.git synced 2025-06-15 20:15:23 +02:00

Compare commits

...

6 Commits

Author SHA1 Message Date
Reinder Feenstra
1ef8f71166
Merge 8740af814d9d7e03e234ec6036c1725edc21e96b into 8ac61b88d444ff1e8d48e17b590ba383ed591560 2025-04-16 23:33:40 +00:00
Harald Barth
8ac61b88d4 version 5.4.8 2025-04-14 21:51:35 +02:00
Harald Barth
8aabede3ee treat all function groups equal; remove unused no reminders compile option 2025-04-14 21:27:51 +02:00
Harald Barth
839ea582a4 insert idle after speed packet only 2025-04-14 21:14:24 +02:00
Reinder Feenstra
8740af814d fix: all values except the opcode are case insensetive and threated as uppercase.
Extended accessory now uses an E instead of an A.
2025-03-29 08:45:40 +01:00
Reinder Feenstra
31f89ad4c4 Added broadcast for (extended) accessory commands.
see: https://github.com/DCC-EX/CommandStation-EX/issues/444
2025-03-28 22:47:13 +01:00
5 changed files with 27 additions and 22 deletions

View File

@ -152,6 +152,14 @@ void CommandDistributor::broadcastSensor(int16_t id, bool on ) {
broadcastReply(COMMAND_TYPE, F("<%c %d>\n"), on?'Q':'q', id); broadcastReply(COMMAND_TYPE, F("<%c %d>\n"), on?'Q':'q', id);
} }
void CommandDistributor::broadcastAccessory(int16_t address, byte port, bool gate, bool on) {
broadcastReply(COMMAND_TYPE, F("<y A %d %d %c %c>\n"), address, port, gate?'1':'0', on?'1':'0');
}
void CommandDistributor::broadcastExtendedAccessory(int16_t address, int16_t value) {
broadcastReply(COMMAND_TYPE, F("<y E %d %d>\n"), address, value);
}
void CommandDistributor::broadcastTurnout(int16_t id, bool isClosed ) { void CommandDistributor::broadcastTurnout(int16_t id, bool isClosed ) {
// For DCC++ classic compatibility, state reported to JMRI is 1 for thrown and 0 for closed; // For DCC++ classic compatibility, state reported to JMRI is 1 for thrown and 0 for closed;
// The string below contains serial and Withrottle protocols which should // The string below contains serial and Withrottle protocols which should

View File

@ -49,6 +49,8 @@ public :
static void broadcastLoco(byte slot); static void broadcastLoco(byte slot);
static void broadcastForgetLoco(int16_t loco); static void broadcastForgetLoco(int16_t loco);
static void broadcastSensor(int16_t id, bool value); static void broadcastSensor(int16_t id, bool value);
static void broadcastAccessory(int16_t address, byte port, bool gate, bool on);
static void broadcastExtendedAccessory(int16_t address, int16_t value);
static void broadcastTurnout(int16_t id, bool isClosed); static void broadcastTurnout(int16_t id, bool isClosed);
static void broadcastTurntable(int16_t id, uint8_t position, bool moving); static void broadcastTurntable(int16_t id, uint8_t position, bool moving);
static void broadcastClockTime(int16_t time, int8_t rate); static void broadcastClockTime(int16_t time, int8_t rate);

34
DCC.cpp
View File

@ -307,10 +307,12 @@ void DCC::setAccessory(int address, byte port, bool gate, byte onoff /*= 2*/) {
#if defined(EXRAIL_ACTIVE) #if defined(EXRAIL_ACTIVE)
RMFT2::activateEvent(address<<2|port,gate); RMFT2::activateEvent(address<<2|port,gate);
#endif #endif
CommandDistributor::broadcastAccessory(address, port, gate, true);
} }
if (onoff != 1) { if (onoff != 1) {
b[1] &= ~0x08; // set C to 0 b[1] &= ~0x08; // set C to 0
DCCWaveform::mainTrack.schedulePacket(b, 2, 3); // Repeat off packet three times DCCWaveform::mainTrack.schedulePacket(b, 2, 3); // Repeat off packet three times
CommandDistributor::broadcastAccessory(address, port, gate, false);
} }
} }
@ -362,6 +364,7 @@ whole range of the 11 bits sent to track.
| ((address & 0x03)<<1); // mask 2 bits, shift up 1 | ((address & 0x03)<<1); // mask 2 bits, shift up 1
b[2]=value; b[2]=value;
DCCWaveform::mainTrack.schedulePacket(b, sizeof(b), repeats); DCCWaveform::mainTrack.schedulePacket(b, sizeof(b), repeats);
CommandDistributor::broadcastExtendedAccessory(address, value);
return true; return true;
} }
@ -759,7 +762,15 @@ void DCC::issueReminders() {
if (!DCCWaveform::mainTrack.isReminderWindowOpen()) 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) {
if (loopStatus == 0 /*only needed if numLocos == 1 but we do not have a counter*/) {
// insert idle packet in the speed packet loop to fullfill the *censored*
// >5ms between packets to same decoder rule
const byte idlepacket[] = {0xFF, 0x00, 0xFF};
DCCWaveform::mainTrack.schedulePacket(idlepacket, 3, 0);
}
reg = 0; // Go to start of table
}
if (speedTable[reg].loco > 0) { if (speedTable[reg].loco > 0) {
// have found loco to remind // have found loco to remind
if (issueReminder(reg)) if (issueReminder(reg))
@ -780,40 +791,23 @@ bool DCC::issueReminder(int reg) {
break; break;
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)
#ifndef DISABLE_FUNCTION_REMINDERS
setFunctionInternal(loco,0, 128 | ((functions>>1)& 0x0F) | ((functions & 0x01)<<4),0); // 100D DDDD setFunctionInternal(loco,0, 128 | ((functions>>1)& 0x0F) | ((functions & 0x01)<<4),0); // 100D DDDD
#else
setFunctionInternal(loco,0, 128 | ((functions>>1)& 0x0F) | ((functions & 0x01)<<4),2);
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)
#ifndef DISABLE_FUNCTION_REMINDERS
setFunctionInternal(loco,0, 176 | ((functions>>5)& 0x0F),0); // 1011 DDDD setFunctionInternal(loco,0, 176 | ((functions>>5)& 0x0F),0); // 1011 DDDD
#else
setFunctionInternal(loco,0, 176 | ((functions>>5)& 0x0F),2);
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)
#ifndef DISABLE_FUNCTION_REMINDERS
setFunctionInternal(loco,0, 160 | ((functions>>9)& 0x0F),0); // 1010 DDDD setFunctionInternal(loco,0, 160 | ((functions>>9)& 0x0F),0); // 1010 DDDD
#else
setFunctionInternal(loco,0, 160 | ((functions>>9)& 0x0F),2);
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)
setFunctionInternal(loco,222, ((functions>>13)& 0xFF),2); setFunctionInternal(loco,222, ((functions>>13)& 0xFF),0);
flags&= ~FN_GROUP_4; // dont send them again
break; break;
case 5: // remind function group 5 F21-F28 case 5: // remind function group 5 F21-F28
if (flags & FN_GROUP_5) if (flags & FN_GROUP_5)
setFunctionInternal(loco,223, ((functions>>21)& 0xFF),2); setFunctionInternal(loco,223, ((functions>>21)& 0xFF),0);
flags&= ~FN_GROUP_5; // dont send them again
break; break;
} }
loopStatus++; loopStatus++;

View File

@ -92,7 +92,7 @@ Once a new OPCODE is decided upon, update this list.
W, Write CV W, Write CV
x, x,
X, Invalid command response X, Invalid command response
y, y, Accessory/extended accessory broadcast
Y, Output broadcast Y, Output broadcast
z, Direct output z, Direct output
Z, Output configuration/control Z, Output configuration/control

View File

@ -3,7 +3,8 @@
#include "StringFormatter.h" #include "StringFormatter.h"
#define VERSION "5.4.7" #define VERSION "5.4.8"
// 5.4.8 - Bugfix: Insert idle packet at end of speed reminder loop; treat all function groups equal
// 5.4.7 - Bugfix: EXRAIL fix CLEAR_ALL_STASH // 5.4.7 - Bugfix: EXRAIL fix CLEAR_ALL_STASH
// 5.4.6 - Bugfix: Do not drop further commands in same packet // 5.4.6 - Bugfix: Do not drop further commands in same packet
// 5.4.5 - ESP32: Better detection of correct IDF version // 5.4.5 - ESP32: Better detection of correct IDF version