mirror of
https://github.com/DCC-EX/CommandStation-EX.git
synced 2024-11-23 16:16:13 +01:00
Compare commits
9 Commits
dc78d4518e
...
dad84aed6f
Author | SHA1 | Date | |
---|---|---|---|
|
dad84aed6f | ||
|
66d59c6a8a | ||
|
814d1045ba | ||
|
bc8ab26b30 | ||
|
54e1bdb878 | ||
|
e6dde5a11c | ||
|
16362c14cc | ||
|
900aa254c6 | ||
|
d303831773 |
|
@ -209,9 +209,7 @@ int16_t CommandDistributor::retClockTime() {
|
||||||
|
|
||||||
void CommandDistributor::broadcastLoco(byte slot) {
|
void CommandDistributor::broadcastLoco(byte slot) {
|
||||||
DCC::LOCO * sp=&DCC::speedTable[slot];
|
DCC::LOCO * sp=&DCC::speedTable[slot];
|
||||||
uint32_t func = sp->functions;
|
broadcastReply(COMMAND_TYPE, F("<l %d %d %d %l>\n"), sp->loco,slot,sp->speedCode,sp->functions);
|
||||||
func = func & 0x1fffffff; // mask out bits 0-28
|
|
||||||
broadcastReply(COMMAND_TYPE, F("<l %d %d %d %l>\n"), sp->loco,slot,sp->speedCode,func);
|
|
||||||
#ifdef SABERTOOTH
|
#ifdef SABERTOOTH
|
||||||
if (Serial2 && sp->loco == SABERTOOTH) {
|
if (Serial2 && sp->loco == SABERTOOTH) {
|
||||||
static uint8_t rampingmode = 0;
|
static uint8_t rampingmode = 0;
|
||||||
|
|
9
DCC.cpp
9
DCC.cpp
|
@ -219,8 +219,9 @@ bool DCC::setFn( int cab, int16_t functionNumber, bool on) {
|
||||||
} else {
|
} else {
|
||||||
speedTable[reg].functions &= ~funcmask;
|
speedTable[reg].functions &= ~funcmask;
|
||||||
}
|
}
|
||||||
if (speedTable[reg].functions != previous && functionNumber <= 28) {
|
if (speedTable[reg].functions != previous) {
|
||||||
updateGroupflags(speedTable[reg].groupFlags, functionNumber);
|
if (functionNumber <= 28)
|
||||||
|
updateGroupflags(speedTable[reg].groupFlags, functionNumber);
|
||||||
CommandDistributor::broadcastLoco(reg);
|
CommandDistributor::broadcastLoco(reg);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -235,14 +236,14 @@ void DCC::changeFn( int cab, int16_t functionNumber) {
|
||||||
speedTable[reg].functions ^= funcmask;
|
speedTable[reg].functions ^= funcmask;
|
||||||
if (functionNumber <= 28) {
|
if (functionNumber <= 28) {
|
||||||
updateGroupflags(speedTable[reg].groupFlags, functionNumber);
|
updateGroupflags(speedTable[reg].groupFlags, functionNumber);
|
||||||
CommandDistributor::broadcastLoco(reg);
|
|
||||||
}
|
}
|
||||||
|
CommandDistributor::broadcastLoco(reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Report function state (used from withrottle protocol)
|
// Report function state (used from withrottle protocol)
|
||||||
// returns 0 false, 1 true or -1 for do not know
|
// returns 0 false, 1 true or -1 for do not know
|
||||||
int8_t DCC::getFn( int cab, int16_t functionNumber) {
|
int8_t DCC::getFn( int cab, int16_t functionNumber) {
|
||||||
if (cab<=0 || functionNumber>28)
|
if (cab<=0 || functionNumber>31)
|
||||||
return -1; // unknown
|
return -1; // unknown
|
||||||
int reg = lookupSpeedTable(cab);
|
int reg = lookupSpeedTable(cab);
|
||||||
if (reg<0)
|
if (reg<0)
|
||||||
|
|
|
@ -283,25 +283,22 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream)
|
||||||
return; // filterCallback asked us to ignore
|
return; // filterCallback asked us to ignore
|
||||||
case 't': // THROTTLE <t [REGISTER] CAB SPEED DIRECTION>
|
case 't': // THROTTLE <t [REGISTER] CAB SPEED DIRECTION>
|
||||||
{
|
{
|
||||||
if (params==1) { // <t cab> display state
|
|
||||||
|
|
||||||
int16_t slot=DCC::lookupSpeedTable(p[0],false);
|
|
||||||
if (slot>=0) {
|
|
||||||
DCC::LOCO * sp=&DCC::speedTable[slot];
|
|
||||||
StringFormatter::send(stream,F("<l %d %d %d %l>\n"),
|
|
||||||
sp->loco,slot,sp->speedCode,sp->functions);
|
|
||||||
}
|
|
||||||
else // send dummy state speed 0 fwd no functions.
|
|
||||||
StringFormatter::send(stream,F("<l %d -1 128 0>\n"),p[0]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int16_t cab;
|
int16_t cab;
|
||||||
int16_t tspeed;
|
int16_t tspeed;
|
||||||
int16_t direction;
|
int16_t direction;
|
||||||
|
|
||||||
|
if (params==1) { // <t cab> display state
|
||||||
|
int16_t slot=DCC::lookupSpeedTable(p[0],false);
|
||||||
|
if (slot>=0)
|
||||||
|
CommandDistributor::broadcastLoco(slot);
|
||||||
|
else // send dummy state speed 0 fwd no functions.
|
||||||
|
StringFormatter::send(stream,F("<l %d -1 128 0>\n"),p[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (params == 4)
|
if (params == 4)
|
||||||
{ // <t REGISTER CAB SPEED DIRECTION>
|
{ // <t REGISTER CAB SPEED DIRECTION>
|
||||||
|
// ignore register p[0]
|
||||||
cab = p[1];
|
cab = p[1];
|
||||||
tspeed = p[2];
|
tspeed = p[2];
|
||||||
direction = p[3];
|
direction = p[3];
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
#define GITHUB_SHA "devel-z21-202403110817Z"
|
#define GITHUB_SHA "devel-z21-202403241544Z"
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* © 2022-2023 Paul M. Antoine
|
* © 2022-2023 Paul M. Antoine
|
||||||
* © 2021 Fred Decker
|
* © 2021 Fred Decker
|
||||||
* © 2020-2023 Harald Barth
|
* © 2020-2024 Harald Barth
|
||||||
* (c) 2020 Chris Harlow. All rights reserved.
|
* (c) 2020 Chris Harlow. All rights reserved.
|
||||||
* (c) 2021 Fred Decker. All rights reserved.
|
* (c) 2021 Fred Decker. All rights reserved.
|
||||||
* (c) 2020 Harald Barth. All rights reserved.
|
* (c) 2020 Harald Barth. All rights reserved.
|
||||||
|
@ -57,6 +57,10 @@
|
||||||
// of the brake pin on the motor bridge is inverted
|
// of the brake pin on the motor bridge is inverted
|
||||||
// (HIGH == release brake)
|
// (HIGH == release brake)
|
||||||
|
|
||||||
|
// You can have a CS wihout any possibility to do any track signal.
|
||||||
|
// That's strange but possible.
|
||||||
|
#define NO_SHIELD F("No shield at all")
|
||||||
|
|
||||||
// Arduino STANDARD Motor Shield, used on different architectures:
|
// Arduino STANDARD Motor Shield, used on different architectures:
|
||||||
|
|
||||||
#if defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_STM32)
|
#if defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_STM32)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* © 2022 Chris Harlow
|
* © 2022 Chris Harlow
|
||||||
* © 2022,2023 Harald Barth
|
* © 2022-2024 Harald Barth
|
||||||
* © 2023 Colin Murdoch
|
* © 2023 Colin Murdoch
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
|
@ -41,7 +41,7 @@
|
||||||
MotorDriver * TrackManager::track[MAX_TRACKS];
|
MotorDriver * TrackManager::track[MAX_TRACKS];
|
||||||
int16_t TrackManager::trackDCAddr[MAX_TRACKS];
|
int16_t TrackManager::trackDCAddr[MAX_TRACKS];
|
||||||
|
|
||||||
byte TrackManager::lastTrack=0;
|
int8_t TrackManager::lastTrack=-1;
|
||||||
bool TrackManager::progTrackSyncMain=false;
|
bool TrackManager::progTrackSyncMain=false;
|
||||||
bool TrackManager::progTrackBoosted=false;
|
bool TrackManager::progTrackBoosted=false;
|
||||||
int16_t TrackManager::joinRelay=UNUSED_PIN;
|
int16_t TrackManager::joinRelay=UNUSED_PIN;
|
||||||
|
@ -499,6 +499,10 @@ void TrackManager::setTrackPower(TRACK_MODE trackmodeToMatch, POWERMODE powermod
|
||||||
// Set track power for this track, inependent of mode
|
// Set track power for this track, inependent of mode
|
||||||
void TrackManager::setTrackPower(POWERMODE powermode, byte t) {
|
void TrackManager::setTrackPower(POWERMODE powermode, byte t) {
|
||||||
MotorDriver *driver=track[t];
|
MotorDriver *driver=track[t];
|
||||||
|
if (driver == NULL) { // track is not defined at all
|
||||||
|
DIAG(F("Error: Track %c does not exist"), t+'A');
|
||||||
|
return;
|
||||||
|
}
|
||||||
TRACK_MODE trackmode = driver->getMode();
|
TRACK_MODE trackmode = driver->getMode();
|
||||||
POWERMODE oldpower = driver->getPower();
|
POWERMODE oldpower = driver->getPower();
|
||||||
if (trackmode & TRACK_MODE_NONE) {
|
if (trackmode & TRACK_MODE_NONE) {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* © 2022 Chris Harlow
|
* © 2022 Chris Harlow
|
||||||
* © 2022 Harald Barth
|
* © 2022-2024 Harald Barth
|
||||||
* © 2023 Colin Murdoch
|
* © 2023 Colin Murdoch
|
||||||
*
|
*
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
|
@ -46,7 +46,7 @@ const byte TRACK_POWER_1=1, TRACK_POWER_ON=1;
|
||||||
class TrackManager {
|
class TrackManager {
|
||||||
public:
|
public:
|
||||||
static void Setup(const FSH * shieldName,
|
static void Setup(const FSH * shieldName,
|
||||||
MotorDriver * track0,
|
MotorDriver * track0=NULL,
|
||||||
MotorDriver * track1=NULL,
|
MotorDriver * track1=NULL,
|
||||||
MotorDriver * track2=NULL,
|
MotorDriver * track2=NULL,
|
||||||
MotorDriver * track3=NULL,
|
MotorDriver * track3=NULL,
|
||||||
|
@ -108,7 +108,7 @@ class TrackManager {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void addTrack(byte t, MotorDriver* driver);
|
static void addTrack(byte t, MotorDriver* driver);
|
||||||
static byte lastTrack;
|
static int8_t lastTrack;
|
||||||
static byte nextCycleTrack;
|
static byte nextCycleTrack;
|
||||||
static void applyDCSpeed(byte t);
|
static void applyDCSpeed(byte t);
|
||||||
|
|
||||||
|
|
|
@ -571,7 +571,7 @@ void WiThrottle::sendRoutes(Print* stream) {
|
||||||
|
|
||||||
void WiThrottle::sendFunctions(Print* stream, byte loco) {
|
void WiThrottle::sendFunctions(Print* stream, byte loco) {
|
||||||
int16_t locoid=myLocos[loco].cab;
|
int16_t locoid=myLocos[loco].cab;
|
||||||
int fkeys=29;
|
int fkeys=32; // upper limit (send functions 0 to 31)
|
||||||
myLocos[loco].functionToggles=1<<2; // F2 (HORN) is a non-toggle
|
myLocos[loco].functionToggles=1<<2; // F2 (HORN) is a non-toggle
|
||||||
|
|
||||||
#ifdef EXRAIL_ACTIVE
|
#ifdef EXRAIL_ACTIVE
|
||||||
|
|
207
Z21Throttle.cpp
207
Z21Throttle.cpp
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* © 2023 Thierry Paris / Locoduino
|
* © 2023 Thierry Paris / Locoduino
|
||||||
* © 2023 Harald Barth
|
* © 2023,2024 Harald Barth
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is part of CommandStation-EX
|
* This file is part of CommandStation-EX
|
||||||
|
@ -385,50 +385,44 @@ void Z21Throttle::notifyLocoInfo(byte inMSB, byte inLSB) {
|
||||||
Z21Throttle::replyBuffer[3] = DCC::getThrottleSpeed(locoAddress); // RVVVVVVV R = forward VVVVVVV = speed
|
Z21Throttle::replyBuffer[3] = DCC::getThrottleSpeed(locoAddress); // RVVVVVVV R = forward VVVVVVV = speed
|
||||||
if (DCC::getThrottleDirection(locoAddress)) bitSet(Z21Throttle::replyBuffer[3], 7);
|
if (DCC::getThrottleDirection(locoAddress)) bitSet(Z21Throttle::replyBuffer[3], 7);
|
||||||
|
|
||||||
Z21Throttle::replyBuffer[4] = B00000000; // 0DSLFGHJ D = double traction S = Smartsearch L = F0 F = F4 G = F3 H = F2 J = F1
|
uint32_t functionMap = DCC::getFunctionMap(locoAddress);
|
||||||
if (DCC::getFn(locoAddress, 0)) bitSet(Z21Throttle::replyBuffer[4], 4);
|
|
||||||
if (DCC::getFn(locoAddress, 1)) bitSet(Z21Throttle::replyBuffer[4], 0);
|
|
||||||
if (DCC::getFn(locoAddress, 2)) bitSet(Z21Throttle::replyBuffer[4], 1);
|
|
||||||
if (DCC::getFn(locoAddress, 3)) bitSet(Z21Throttle::replyBuffer[4], 2);
|
|
||||||
if (DCC::getFn(locoAddress, 4)) bitSet(Z21Throttle::replyBuffer[4], 3);
|
|
||||||
|
|
||||||
Z21Throttle::replyBuffer[5] = B00000000; // function F5 to F12 F5 is bit0
|
// Byte 4: 0DSLFGHJ
|
||||||
if (DCC::getFn(locoAddress, 5)) bitSet(Z21Throttle::replyBuffer[5], 0);
|
// D = double traction S = Smartsearch L = F0 F = F4 G = F3 H = F2 J = F1
|
||||||
if (DCC::getFn(locoAddress, 6)) bitSet(Z21Throttle::replyBuffer[5], 1);
|
Z21Throttle::replyBuffer[4] = (functionMap >> 1) & 0xF; // function F1 to F5
|
||||||
if (DCC::getFn(locoAddress, 7)) bitSet(Z21Throttle::replyBuffer[5], 2);
|
if (functionMap & 1) // set F0 (Light)
|
||||||
if (DCC::getFn(locoAddress, 8)) bitSet(Z21Throttle::replyBuffer[5], 3);
|
Z21Throttle::replyBuffer[4] += 16;
|
||||||
if (DCC::getFn(locoAddress, 9)) bitSet(Z21Throttle::replyBuffer[5], 4);
|
functionMap >>=5; // shift out the 5 bits which are not needed any more
|
||||||
if (DCC::getFn(locoAddress, 10)) bitSet(Z21Throttle::replyBuffer[5],5);
|
|
||||||
if (DCC::getFn(locoAddress, 11)) bitSet(Z21Throttle::replyBuffer[5],6);
|
|
||||||
if (DCC::getFn(locoAddress, 12)) bitSet(Z21Throttle::replyBuffer[5],7);
|
|
||||||
|
|
||||||
Z21Throttle::replyBuffer[6] = B00000000; // function F13 to F20 F13 is bit0
|
Z21Throttle::replyBuffer[5] = functionMap & 0xFF; // function F5 to F12; F5 is bit0
|
||||||
if (DCC::getFn(locoAddress, 13)) bitSet(Z21Throttle::replyBuffer[6], 0);
|
functionMap >>=8; // shift out 8 more
|
||||||
if (DCC::getFn(locoAddress, 14)) bitSet(Z21Throttle::replyBuffer[6], 1);
|
Z21Throttle::replyBuffer[6] = functionMap & 0xFF; // function F13 to F20; F13 is bit0
|
||||||
if (DCC::getFn(locoAddress, 15)) bitSet(Z21Throttle::replyBuffer[6], 2);
|
functionMap >>=8; // shift out 8 more
|
||||||
if (DCC::getFn(locoAddress, 16)) bitSet(Z21Throttle::replyBuffer[6], 3);
|
Z21Throttle::replyBuffer[7] = functionMap & 0xFF; // function F21 to F28; F21 is bit0
|
||||||
if (DCC::getFn(locoAddress, 17)) bitSet(Z21Throttle::replyBuffer[6], 4);
|
functionMap >>=8; // shift out 8 more
|
||||||
if (DCC::getFn(locoAddress, 18)) bitSet(Z21Throttle::replyBuffer[6], 5);
|
Z21Throttle::replyBuffer[8] = functionMap & 0xFF; // function F29 to F31; F28 is bit0
|
||||||
if (DCC::getFn(locoAddress, 19)) bitSet(Z21Throttle::replyBuffer[6], 6);
|
|
||||||
if (DCC::getFn(locoAddress, 20)) bitSet(Z21Throttle::replyBuffer[6], 7);
|
|
||||||
|
|
||||||
Z21Throttle::replyBuffer[7] = B00000000; // function F21 to F28 F21 is bit0
|
notify(HEADER_LAN_XPRESS_NET, LAN_X_HEADER_LOCO_INFO, Z21Throttle::replyBuffer, 9, false);
|
||||||
if (DCC::getFn(locoAddress, 21)) bitSet(Z21Throttle::replyBuffer[7], 0);
|
|
||||||
if (DCC::getFn(locoAddress, 22)) bitSet(Z21Throttle::replyBuffer[7], 1);
|
|
||||||
if (DCC::getFn(locoAddress, 23)) bitSet(Z21Throttle::replyBuffer[7], 2);
|
|
||||||
if (DCC::getFn(locoAddress, 24)) bitSet(Z21Throttle::replyBuffer[7], 3);
|
|
||||||
if (DCC::getFn(locoAddress, 25)) bitSet(Z21Throttle::replyBuffer[7], 4);
|
|
||||||
if (DCC::getFn(locoAddress, 26)) bitSet(Z21Throttle::replyBuffer[7], 5);
|
|
||||||
if (DCC::getFn(locoAddress, 27)) bitSet(Z21Throttle::replyBuffer[7], 6);
|
|
||||||
if (DCC::getFn(locoAddress, 28)) bitSet(Z21Throttle::replyBuffer[7], 7);
|
|
||||||
|
|
||||||
notify(HEADER_LAN_XPRESS_NET, LAN_X_HEADER_LOCO_INFO, Z21Throttle::replyBuffer, 8, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Z21Throttle::notifyTurnoutInfo(byte inMSB, byte inLSB) {
|
void Z21Throttle::notifyTurnoutInfo(byte inMSB, byte inLSB) {
|
||||||
Z21Throttle::replyBuffer[0] = inMSB; // turnout address msb
|
Z21Throttle::replyBuffer[0] = inMSB; // turnout address msb
|
||||||
Z21Throttle::replyBuffer[1] = inLSB; // turnout address lsb
|
Z21Throttle::replyBuffer[1] = inLSB; // turnout address lsb
|
||||||
Z21Throttle::replyBuffer[2] = B00000000; // 000000ZZ ZZ : 00 not switched 01 pos1 10 pos2 11 invalid
|
Z21Throttle::replyBuffer[2] = B00000011; // 000000ZZ ZZ : 00 not switched 01 pos1 10 pos2 11 invalid
|
||||||
|
char c = '?';
|
||||||
|
uint16_t addr = (inMSB << 8) + inLSB + 1;
|
||||||
|
Turnout *tt = Turnout::get(addr);
|
||||||
|
if (tt) { // if the tt does not exist we fall through with replyBuffer set to invalid
|
||||||
|
if (tt->isClosed()) {
|
||||||
|
Z21Throttle::replyBuffer[2] = B00000010;
|
||||||
|
c = 'c';
|
||||||
|
} else {
|
||||||
|
Z21Throttle::replyBuffer[2] = B00000001;
|
||||||
|
c = 't';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Diag::Z21THROTTLE)
|
||||||
|
DIAG(F("Z21 Throttle %d : Turnoutinfo %d %c"), clientid, addr, c);
|
||||||
notify(HEADER_LAN_XPRESS_NET, LAN_X_HEADER_TURNOUT_INFO, Z21Throttle::replyBuffer, 3, false);
|
notify(HEADER_LAN_XPRESS_NET, LAN_X_HEADER_TURNOUT_INFO, Z21Throttle::replyBuffer, 3, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -488,6 +482,30 @@ void Z21Throttle::setSpeed(byte inNbSteps, byte inDB1, byte inDB2, byte inDB3) {
|
||||||
notifyLocoInfo(inDB1, inDB2);
|
notifyLocoInfo(inDB1, inDB2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Z21Throttle::setTurnout(byte addrMSB, byte addrLSB, byte command) {
|
||||||
|
// 1000A00P
|
||||||
|
// A=0 ... Deactivate turnout output
|
||||||
|
// A=1 ... Activate turnout output
|
||||||
|
// P=0 ... Select output 1 of the turnout
|
||||||
|
// P=1 ... Select output 2 of the turnout
|
||||||
|
// Q=0 ... Execute command immediately
|
||||||
|
// means that the client (app/mouse) does send activate and deactive
|
||||||
|
// Q=1 ... From Z21 FW V1.24: Insert turnout command into the queue of Z21
|
||||||
|
bool queue = (command & B00100000) != 0;
|
||||||
|
bool activate = (command & B00001000) != 0;
|
||||||
|
byte output = command & B00000001;
|
||||||
|
|
||||||
|
uint16_t addr = (addrMSB << 8) + addrLSB + 1;
|
||||||
|
if (Diag::Z21THROTTLE) DIAG(F("Z21 Throttle %d : turnout %d cmd 0x%x"), clientid, addr, command);
|
||||||
|
|
||||||
|
(void)queue; // We probably do not need to care (as we are a CS that maps to internal
|
||||||
|
// turnouts and not to accessory commands) about the difference.
|
||||||
|
if (activate) {
|
||||||
|
Turnout::setClosed(addr, output == 1);
|
||||||
|
} // else ignore the deactivate message
|
||||||
|
notifyTurnoutInfo(addrMSB, addrLSB); // sent for both activate and deactivate
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// TODO Pass through a text message to avoid multi thread locks...
|
// TODO Pass through a text message to avoid multi thread locks...
|
||||||
//
|
//
|
||||||
|
@ -623,7 +641,13 @@ void diagPacket(byte *networkPacket, int len) {
|
||||||
bool Z21Throttle::parse(byte *networkPacket, int len) {
|
bool Z21Throttle::parse(byte *networkPacket, int len) {
|
||||||
|
|
||||||
bool done = false;
|
bool done = false;
|
||||||
|
|
||||||
|
// same names as in Z21 LAN Protocol Specification
|
||||||
byte *DB;
|
byte *DB;
|
||||||
|
byte *Data;
|
||||||
|
byte Xheader;
|
||||||
|
int Header;
|
||||||
|
|
||||||
byte *p = networkPacket;
|
byte *p = networkPacket;
|
||||||
int l = len;
|
int l = len;
|
||||||
|
|
||||||
|
@ -636,12 +660,13 @@ bool Z21Throttle::parse(byte *networkPacket, int len) {
|
||||||
}
|
}
|
||||||
if (l < 0) {
|
if (l < 0) {
|
||||||
DIAG(F("ERROR: Xbus data exceeds UDP packet size: l < 0 pos=%d, l=%d"), p-networkPacket, l);
|
DIAG(F("ERROR: Xbus data exceeds UDP packet size: l < 0 pos=%d, l=%d"), p-networkPacket, l);
|
||||||
diagPacket(networkPacket, len);
|
diagPacket(p, len);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (l > 0 && lengthData < 4) {
|
if (l > 0 && lengthData < 4) {
|
||||||
DIAG(F("WARNING: Xbus data does not fill UDP packet size: l > 0 pos=%d, l=%d"), p-networkPacket, l);
|
DIAG(F("WARNING: Xbus data does not fill UDP packet size: l > 0 pos=%d, l=%d, lengthData=%d"),
|
||||||
diagPacket(networkPacket, len);
|
p-networkPacket, l, lengthData);
|
||||||
|
diagPacket(p, len);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// length of the data = total length - length of length (!) - length of header
|
// length of the data = total length - length of length (!) - length of header
|
||||||
|
@ -652,36 +677,36 @@ bool Z21Throttle::parse(byte *networkPacket, int len) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
p += 2;
|
p += 2;
|
||||||
int header = GETINT16(p);
|
Header = GETINT16(p);
|
||||||
byte Xheader = 0;
|
|
||||||
p += 2;
|
p += 2;
|
||||||
DB = p;
|
// now p is at start of Data, networkPacket + 4
|
||||||
byte DB0 = 0;
|
Data = p;
|
||||||
|
Xheader = Data[0];
|
||||||
|
DB = Data + 1;
|
||||||
int nbLocos = CountLocos();
|
int nbLocos = CountLocos();
|
||||||
// set p for next round
|
// set p for next round
|
||||||
p += lengthData;
|
p += lengthData;
|
||||||
if (Diag::Z21THROTTLEDATA && DB[1] != LAN_X_DB0_GET_STATUS)
|
if (l > 0 && Diag::Z21THROTTLEDATA) DIAG(F("next packet follows at pos=%d"), p-networkPacket);
|
||||||
DIAG(F("%d <- lengthData:%d header:0x%02x : 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x"),
|
if (Diag::Z21THROTTLEDATA &&
|
||||||
this->clientid, lengthData, header,
|
!((DB[0] == LAN_X_DB0_GET_STATUS) && (Xheader == LAN_X_HEADER_GENERAL)))
|
||||||
(lengthData > 0)?DB[0]:0,
|
DIAG(F("%d <- lengthData:%d Header:0x%02x : 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x"),
|
||||||
(lengthData > 1)?DB[1]:0,
|
this->clientid, lengthData, Header,
|
||||||
(lengthData > 2)?DB[2]:0,
|
(lengthData > 0)?Data[0]:0,
|
||||||
(lengthData > 3)?DB[3]:0,
|
(lengthData > 1)?Data[1]:0,
|
||||||
(lengthData > 4)?DB[4]:0,
|
(lengthData > 2)?Data[2]:0,
|
||||||
(lengthData > 5)?DB[5]:0,
|
(lengthData > 3)?Data[3]:0,
|
||||||
(lengthData > 6)?DB[6]:0,
|
(lengthData > 4)?Data[4]:0,
|
||||||
(lengthData > 7)?DB[7]:0,
|
(lengthData > 5)?Data[5]:0,
|
||||||
(lengthData > 8)?DB[8]:0,
|
(lengthData > 6)?Data[6]:0,
|
||||||
(lengthData > 9)?DB[9]:0);
|
(lengthData > 7)?Data[7]:0,
|
||||||
if (l > 0 && Diag::Z21THROTTLEDATA) DIAG(F("next packet follows"));
|
(lengthData > 8)?Data[8]:0,
|
||||||
|
(lengthData > 9)?Data[9]:0);
|
||||||
|
|
||||||
switch (header) {
|
switch (Header) {
|
||||||
case HEADER_LAN_XPRESS_NET:
|
case HEADER_LAN_XPRESS_NET:
|
||||||
Xheader = DB[0];
|
|
||||||
switch (Xheader) {
|
switch (Xheader) {
|
||||||
case LAN_X_HEADER_GENERAL:
|
case LAN_X_HEADER_GENERAL:
|
||||||
DB0 = DB[1];
|
switch (DB[0]) {
|
||||||
switch (DB0) {
|
|
||||||
case LAN_X_DB0_GET_VERSION:
|
case LAN_X_DB0_GET_VERSION:
|
||||||
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d GET_VERSION"), this->clientid);
|
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d GET_VERSION"), this->clientid);
|
||||||
break;
|
break;
|
||||||
|
@ -719,29 +744,28 @@ bool Z21Throttle::parse(byte *networkPacket, int len) {
|
||||||
done = true;
|
done = true;
|
||||||
break;
|
break;
|
||||||
case LAN_X_HEADER_SET_LOCO:
|
case LAN_X_HEADER_SET_LOCO:
|
||||||
DB0 = DB[1];
|
switch (DB[0]) {
|
||||||
switch (DB0) {
|
|
||||||
case LAN_X_DB0_LOCO_DCC14:
|
case LAN_X_DB0_LOCO_DCC14:
|
||||||
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d LOCO DCC 14 SPEED"), this->clientid);
|
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d LOCO DCC 14 SPEED"), this->clientid);
|
||||||
setSpeed(14, DB[2], DB[3], DB[4]);
|
setSpeed(14, DB[1], DB[2], DB[3]);
|
||||||
done = true;
|
done = true;
|
||||||
break;
|
break;
|
||||||
case LAN_X_DB0_LOCO_DCC28:
|
case LAN_X_DB0_LOCO_DCC28:
|
||||||
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d LOCO DCC 28 SPEED"), this->clientid);
|
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d LOCO DCC 28 SPEED"), this->clientid);
|
||||||
setSpeed(28, DB[2], DB[3], DB[4]);
|
setSpeed(28, DB[1], DB[2], DB[3]);
|
||||||
done = true;
|
done = true;
|
||||||
break;
|
break;
|
||||||
case LAN_X_DB0_LOCO_DCC128:
|
case LAN_X_DB0_LOCO_DCC128:
|
||||||
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d LOCO DCC 128 SPEED"), this->clientid);
|
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d LOCO DCC 128 SPEED"), this->clientid);
|
||||||
setSpeed(128, DB[2], DB[3], DB[4]);
|
setSpeed(128, DB[1], DB[2], DB[3]);
|
||||||
done = true;
|
done = true;
|
||||||
break;
|
break;
|
||||||
case LAN_X_DB0_SET_LOCO_FUNCTION:
|
case LAN_X_DB0_SET_LOCO_FUNCTION:
|
||||||
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d LOCO DCC FUNCTION"), this->clientid);
|
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d LOCO DCC FUNCTION"), this->clientid);
|
||||||
setFunction(DB[2], DB[3], DB[4]);
|
setFunction(DB[1], DB[2], DB[3]);
|
||||||
if (Diag::Z21THROTTLE) {
|
if (Diag::Z21THROTTLE) {
|
||||||
// Debug capacity to print data...
|
// Debug capacity to print data...
|
||||||
byte function = DB[4];
|
byte function = DB[3];
|
||||||
bitClear(function, 6);
|
bitClear(function, 6);
|
||||||
bitClear(function, 7);
|
bitClear(function, 7);
|
||||||
if (function == 12) { // why not ?
|
if (function == 12) { // why not ?
|
||||||
|
@ -754,14 +778,15 @@ bool Z21Throttle::parse(byte *networkPacket, int len) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case LAN_X_HEADER_GET_LOCO_INFO:
|
case LAN_X_HEADER_GET_LOCO_INFO:
|
||||||
|
// XXX Should we switch(DB[0]) here?
|
||||||
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d LOCO INFO: "), this->clientid);
|
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d LOCO INFO: "), this->clientid);
|
||||||
notifyLocoInfo(DB[2], DB[3]);
|
notifyLocoInfo(DB[1], DB[2]);
|
||||||
done = true;
|
done = true;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case LAN_X_HEADER_GET_TURNOUT_INFO:
|
case LAN_X_HEADER_GET_TURNOUT_INFO:
|
||||||
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d TURNOUT INFO "), this->clientid);
|
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d TURNOUT INFO "), this->clientid);
|
||||||
notifyTurnoutInfo(DB[1], DB[2]);
|
notifyTurnoutInfo(DB[0], DB[1]);
|
||||||
done = true;
|
done = true;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -774,7 +799,7 @@ bool Z21Throttle::parse(byte *networkPacket, int len) {
|
||||||
if (TrackManager::getProgDriver() != NULL) {
|
if (TrackManager::getProgDriver() != NULL) {
|
||||||
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d CV READ PROG "), this->clientid);
|
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d CV READ PROG "), this->clientid);
|
||||||
// DB0 should be 0x11
|
// DB0 should be 0x11
|
||||||
cvReadProg(DB[2], DB[3]);
|
cvReadProg(DB[1], DB[2]);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
//
|
//
|
||||||
|
@ -784,14 +809,14 @@ bool Z21Throttle::parse(byte *networkPacket, int len) {
|
||||||
// If no prog track, read on the main track !
|
// If no prog track, read on the main track !
|
||||||
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d CV READ MAIN "), this->clientid);
|
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d CV READ MAIN "), this->clientid);
|
||||||
// DB0 should be 0x11
|
// DB0 should be 0x11
|
||||||
cvReadMain(DB[2], DB[3]);
|
cvReadMain(DB[1], DB[2]);
|
||||||
}
|
}
|
||||||
done = true;
|
done = true;
|
||||||
break;
|
break;
|
||||||
case LAN_X_HEADER_CV_POM:
|
case LAN_X_HEADER_CV_POM:
|
||||||
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d CV READ POM"), this->clientid);
|
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d CV READ POM"), this->clientid);
|
||||||
// DB0 should be 0x11
|
// DB0 should be 0x11
|
||||||
cvReadPom(DB[2], DB[3], DB[4], DB[5]);
|
cvReadPom(DB[1], DB[2], DB[3], DB[4]);
|
||||||
done = true;
|
done = true;
|
||||||
break;
|
break;
|
||||||
case LAN_X_HEADER_CV_WRITE:
|
case LAN_X_HEADER_CV_WRITE:
|
||||||
|
@ -800,13 +825,18 @@ bool Z21Throttle::parse(byte *networkPacket, int len) {
|
||||||
done = true;
|
done = true;
|
||||||
break;
|
break;
|
||||||
case LAN_X_HEADER_SET_TURNOUT:
|
case LAN_X_HEADER_SET_TURNOUT:
|
||||||
case 0x22:
|
// XXX sent when operating a turnout
|
||||||
|
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d SET TURNOUT "), this->clientid);
|
||||||
|
setTurnout(DB[0], DB[1], DB[2]);
|
||||||
|
done = true;
|
||||||
|
break;
|
||||||
|
case LAN_X_HEADER_READ_REGISTER:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HEADER_LAN_SET_BROADCASTFLAGS:
|
case HEADER_LAN_SET_BROADCASTFLAGS:
|
||||||
this->broadcastFlags = int32_t(DB[3] << 24 | DB[2] << 16 | DB[1] << 8 | DB[0]);
|
this->broadcastFlags = int32_t(Data[3] << 24 | Data[2] << 16 | Data[1] << 8 | Data[0]);
|
||||||
if (Diag::Z21THROTTLEDATA) DIAG(F("BROADCAST FLAGS %d : %s %s %s %s %s %s %s %s %s %s %s"), this->clientid,
|
if (Diag::Z21THROTTLEDATA) DIAG(F("BROADCAST FLAGS %d : %s %s %s %s %s %s %s %s %s %s %s"), this->clientid,
|
||||||
(this->broadcastFlags & BROADCAST_BASE) ? "BASE " : "" ,
|
(this->broadcastFlags & BROADCAST_BASE) ? "BASE " : "" ,
|
||||||
(this->broadcastFlags & BROADCAST_RBUS) ? "RBUS " : "" ,
|
(this->broadcastFlags & BROADCAST_RBUS) ? "RBUS " : "" ,
|
||||||
|
@ -822,15 +852,27 @@ bool Z21Throttle::parse(byte *networkPacket, int len) {
|
||||||
done = true;
|
done = true;
|
||||||
break;
|
break;
|
||||||
case HEADER_LAN_GET_LOCOMODE:
|
case HEADER_LAN_GET_LOCOMODE:
|
||||||
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d GET LOCOMODE"), this->clientid);
|
{
|
||||||
notifyLocoMode(DB[0], DB[1]); // big endian here, but resend the same as received, so no problem.
|
if (Diag::Z21THROTTLEVERBOSE) {
|
||||||
|
uint16_t addr = (Data[0] << 8) + Data[1];
|
||||||
|
DIAG(F("%d GET LOCOMODE %d"), this->clientid, addr);
|
||||||
|
}
|
||||||
|
notifyLocoMode(Data[0], Data[1]); // big endian here, but resend the same as received, so no problem.
|
||||||
done = true;
|
done = true;
|
||||||
break;
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case HEADER_LAN_SET_LOCOMODE:
|
case HEADER_LAN_SET_LOCOMODE:
|
||||||
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d SET LOCOMODE"), this->clientid);
|
{
|
||||||
|
// as we currently can not change loco mode, nothing to do
|
||||||
|
if (Diag::Z21THROTTLEVERBOSE) {
|
||||||
|
uint16_t addr = (Data[0] << 8) + Data[1];
|
||||||
|
DIAG(F("%d SET LOCOMODE %d"), this->clientid, addr);
|
||||||
|
}
|
||||||
|
notifyLocoMode(Data[0], Data[1]); // big endian here, but resend the same as received, so no problem.
|
||||||
done = true;
|
done = true;
|
||||||
break;
|
}
|
||||||
|
break;
|
||||||
case HEADER_LAN_GET_HWINFO:
|
case HEADER_LAN_GET_HWINFO:
|
||||||
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d GET HWINFO"), this->clientid);
|
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d GET HWINFO"), this->clientid);
|
||||||
notifyHWInfo(); // big endian here, but resend the same as received, so no problem.
|
notifyHWInfo(); // big endian here, but resend the same as received, so no problem.
|
||||||
|
@ -847,6 +889,7 @@ bool Z21Throttle::parse(byte *networkPacket, int len) {
|
||||||
done = true;
|
done = true;
|
||||||
break;
|
break;
|
||||||
case HEADER_LAN_GET_SERIAL_NUMBER:
|
case HEADER_LAN_GET_SERIAL_NUMBER:
|
||||||
|
// XXX this has been seen, return dummy number
|
||||||
case HEADER_LAN_GET_BROADCASTFLAGS:
|
case HEADER_LAN_GET_BROADCASTFLAGS:
|
||||||
case HEADER_LAN_GET_TURNOUTMODE:
|
case HEADER_LAN_GET_TURNOUTMODE:
|
||||||
case HEADER_LAN_SET_TURNOUTMODE:
|
case HEADER_LAN_SET_TURNOUTMODE:
|
||||||
|
@ -861,7 +904,7 @@ bool Z21Throttle::parse(byte *networkPacket, int len) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!done) {
|
if (!done) {
|
||||||
if (Diag::Z21THROTTLE) DIAG(F("Z21 Throttle %d : not treated : header:%x Xheader:%x DB0:%x"), this->clientid, header, Xheader, DB0);
|
if (Diag::Z21THROTTLE) DIAG(F("Z21 Throttle %d : not treated : Header:%x Xheader:%x DB0:%x"), this->clientid, Header, Xheader, DB[0]);
|
||||||
} else {
|
} else {
|
||||||
int newNbLocos = CountLocos();
|
int newNbLocos = CountLocos();
|
||||||
if (nbLocos != newNbLocos)
|
if (nbLocos != newNbLocos)
|
||||||
|
|
|
@ -145,6 +145,7 @@ class Z21Throttle {
|
||||||
|
|
||||||
void setSpeed(byte inNbSteps, byte inDB1, byte inDB2, byte inDB3);
|
void setSpeed(byte inNbSteps, byte inDB1, byte inDB2, byte inDB3);
|
||||||
void setFunction(byte inDB1, byte inDB2, byte inDB3);
|
void setFunction(byte inDB1, byte inDB2, byte inDB3);
|
||||||
|
void setTurnout(byte addrMSB, byte addrLSB, byte command);
|
||||||
void cvReadProg(byte inDB1, byte inDB2);
|
void cvReadProg(byte inDB1, byte inDB2);
|
||||||
void cvWriteProg(byte inDB1, byte inDB2, byte inDB3);
|
void cvWriteProg(byte inDB1, byte inDB2, byte inDB3);
|
||||||
void cvReadMain(byte inDB1, byte inDB2);
|
void cvReadMain(byte inDB1, byte inDB2);
|
||||||
|
@ -182,6 +183,7 @@ class Z21Throttle {
|
||||||
#define LAN_GET_CONFIG 0x12
|
#define LAN_GET_CONFIG 0x12
|
||||||
|
|
||||||
#define LAN_X_HEADER_GENERAL 0x21
|
#define LAN_X_HEADER_GENERAL 0x21
|
||||||
|
#define LAN_X_HEADER_READ_REGISTER 0x22
|
||||||
#define LAN_X_HEADER_SET_STOP 0x80
|
#define LAN_X_HEADER_SET_STOP 0x80
|
||||||
#define LAN_X_HEADER_GET_FIRMWARE_VERSION 0xF1 //0x141 0x21 0x21 0x00
|
#define LAN_X_HEADER_GET_FIRMWARE_VERSION 0xF1 //0x141 0x21 0x21 0x00
|
||||||
#define LAN_X_HEADER_GET_LOCO_INFO 0xE3
|
#define LAN_X_HEADER_GET_LOCO_INFO 0xE3
|
||||||
|
@ -192,6 +194,7 @@ class Z21Throttle {
|
||||||
#define LAN_X_HEADER_CV_WRITE 0x24
|
#define LAN_X_HEADER_CV_WRITE 0x24
|
||||||
#define LAN_X_HEADER_CV_POM 0xE6
|
#define LAN_X_HEADER_CV_POM 0xE6
|
||||||
|
|
||||||
|
#define LAN_X_DB0_READ_REGISTER 0x11
|
||||||
#define LAN_X_DB0_GET_VERSION 0x21
|
#define LAN_X_DB0_GET_VERSION 0x21
|
||||||
#define LAN_X_DB0_GET_STATUS 0x24
|
#define LAN_X_DB0_GET_STATUS 0x24
|
||||||
#define LAN_X_DB0_SET_TRACK_POWER_OFF 0x80
|
#define LAN_X_DB0_SET_TRACK_POWER_OFF 0x80
|
||||||
|
|
|
@ -3,7 +3,14 @@
|
||||||
|
|
||||||
#include "StringFormatter.h"
|
#include "StringFormatter.h"
|
||||||
|
|
||||||
#define VERSION "5.2.38"
|
#define VERSION "5.X.Y"
|
||||||
|
// Z21: report the (unchanged) loco mode back after every attempted change
|
||||||
|
// Add turnout functionality to Z21
|
||||||
|
// Fix index of DB[] to comply with Roco documentation
|
||||||
|
// add READ_REGISTER name to Z21 parser
|
||||||
|
//
|
||||||
|
// 5.2.40 - Allow no shield
|
||||||
|
// 5.2.39 - Functions for DC frequency: Use func up to F31
|
||||||
// 5.2.38 - Exrail MESSAGE("text") to send a user message to all
|
// 5.2.38 - Exrail MESSAGE("text") to send a user message to all
|
||||||
// connected throttles (uses <m "text"> and withrottle Hmtext.
|
// connected throttles (uses <m "text"> and withrottle Hmtext.
|
||||||
// 5.2.37 - Bugfix ESP32: Use BOOSTER_INPUT define
|
// 5.2.37 - Bugfix ESP32: Use BOOSTER_INPUT define
|
||||||
|
|
Loading…
Reference in New Issue
Block a user