mirror of
https://github.com/DCC-EX/CommandStation-EX.git
synced 2024-11-23 16:16:13 +01:00
restructure UDP packet receive
This commit is contained in:
parent
fb22bcd99d
commit
800972a57c
595
Z21Throttle.cpp
595
Z21Throttle.cpp
|
@ -1,8 +1,9 @@
|
||||||
/*
|
/*
|
||||||
* © 2023 Thierry Paris / Locoduino
|
* © 2023 Thierry Paris / Locoduino
|
||||||
|
* © 2023 Harald Barth
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is part of CommandStation-EX-Labox
|
* This file is part of CommandStation-EX
|
||||||
*
|
*
|
||||||
* This is free software: you can redistribute it and/or modify
|
* This is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -61,79 +62,61 @@ void Z21Throttle::setup(IPAddress ip, int port) {
|
||||||
NetworkClientUDP::client.flush();
|
NetworkClientUDP::client.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
int readUdpPacket() {
|
|
||||||
byte udp[UDPBYTE_SIZE];
|
|
||||||
memset(udp, 0, UDPBYTE_SIZE);
|
|
||||||
int len = NetworkClientUDP::client.read(udp, UDPBYTE_SIZE);
|
|
||||||
if (len > 0) {
|
|
||||||
for (int clientId = 0; clientId < clientsUDP.size(); clientId++) {
|
|
||||||
if (clientsUDP[clientId].inUse)
|
|
||||||
if (clientsUDP[clientId].remoteIP == NetworkClientUDP::client.remoteIP() && clientsUDP[clientId].remotePort == NetworkClientUDP::client.remotePort()) {
|
|
||||||
clientsUDP[clientId].pudpBuffer->PushBytes(udp, len);
|
|
||||||
return clientId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Z21Throttle::loop() {
|
void Z21Throttle::loop() {
|
||||||
int clientId = 0;
|
int clientId = 0;
|
||||||
|
byte networkPacket[MAX_MTU] = {0};
|
||||||
|
|
||||||
// loop over all clients and remove inactive
|
int len = NetworkClientUDP::client.parsePacket();
|
||||||
for (clientId = 0; clientId < clientsUDP.size(); clientId++) {
|
if (len > MAX_MTU) {
|
||||||
// check if client is there and alive
|
DIAG(F("ERROR: len > MAX_MTU"));
|
||||||
if (clientsUDP[clientId].inUse && !clientsUDP[clientId].connected) {
|
return;
|
||||||
if (Diag::Z21THROTTLE) DIAG(F("Remove UDP client %d"), clientId);
|
}
|
||||||
clientsUDP[clientId].inUse = false;
|
IPAddress remoteIP = NetworkClientUDP::client.remoteIP();
|
||||||
printClientsUDP();
|
int remotePort = NetworkClientUDP::client.remotePort();
|
||||||
}
|
if (len > 0) {
|
||||||
|
for (clientId = 0; clientId < clientsUDP.size(); clientId++) {
|
||||||
|
if (clientsUDP[clientId].inUse) {
|
||||||
|
if (clientsUDP[clientId].remoteIP == remoteIP
|
||||||
|
&& clientsUDP[clientId].remotePort == remotePort) {
|
||||||
|
//if (Diag::Z21THROTTLEVERBOSE) DIAG(F("UDP client %d : %s Already connected"), clientId, clientsUDP[clientId].remoteIP.toString().c_str());
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int len = NetworkClientUDP::client.parsePacket();
|
if (clientId >= clientsUDP.size()) { // not found, let's create it
|
||||||
if (len > 0) {
|
NetworkClientUDP nc;
|
||||||
int clientId = 0;
|
nc.remoteIP = NetworkClientUDP::client.remoteIP();
|
||||||
for (; clientId < clientsUDP.size(); clientId++) {
|
nc.remotePort = NetworkClientUDP::client.remotePort();
|
||||||
if (clientsUDP[clientId].inUse) {
|
nc.connected = true;
|
||||||
if (clientsUDP[clientId].remoteIP == NetworkClientUDP::client.remoteIP() && clientsUDP[clientId].remotePort == NetworkClientUDP::client.remotePort()) {
|
nc.inUse = true;
|
||||||
//if (Diag::Z21THROTTLEVERBOSE) DIAG(F("UDP client %d : %s Already connected"), clientId, clientsUDP[clientId].remoteIP.toString().c_str());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (clientId >= clientsUDP.size()) {
|
clientsUDP.push_back(nc);
|
||||||
NetworkClientUDP nc;
|
if (Diag::Z21THROTTLE) DIAG(F("New UDP client %d, %s"), clientId, nc.remoteIP.toString().c_str());
|
||||||
nc.remoteIP = NetworkClientUDP::client.remoteIP();
|
printClientsUDP();
|
||||||
nc.remotePort = NetworkClientUDP::client.remotePort();
|
#ifdef USE_HMI
|
||||||
nc.connected = true;
|
if (hmi::CurrentInterface != NULL) hmi::CurrentInterface->NewClient(clientId, nc.remoteIP, 0);
|
||||||
nc.inUse = true;
|
#endif
|
||||||
|
// Fleischmann/Roco Android app starts with Power on !
|
||||||
|
// XXX this is the wrong place to do this
|
||||||
|
TrackManager::setMainPower(POWERMODE::ON);
|
||||||
|
}
|
||||||
|
|
||||||
clientsUDP.push_back(nc);
|
// now clientId is on "current client", either new or old
|
||||||
if (Diag::Z21THROTTLE) DIAG(F("New UDP client %d, %s"), clientId, nc.remoteIP.toString().c_str());
|
|
||||||
printClientsUDP();
|
|
||||||
#ifdef USE_HMI
|
|
||||||
if (hmi::CurrentInterface != NULL) hmi::CurrentInterface->NewClient(clientId, nc.remoteIP, 0);
|
|
||||||
#endif
|
|
||||||
// Fleischmann/Roco Android app starts with Power on !
|
|
||||||
TrackManager::setMainPower(POWERMODE::ON);
|
|
||||||
}
|
|
||||||
|
|
||||||
clientId = readUdpPacket();
|
int l = NetworkClientUDP::client.read(networkPacket, len);
|
||||||
|
if (l != len) {
|
||||||
|
DIAG(F(" l %d = len %d"), l, len);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (clientId >= 0) {
|
Z21Throttle* pThrottle = getOrAddThrottle(clientId);
|
||||||
if (clientsUDP[clientId].ok()) {
|
if (pThrottle != NULL)
|
||||||
Z21Throttle* pThrottle = getOrAddThrottle(clientId);
|
pThrottle->parse(networkPacket, len);
|
||||||
|
}
|
||||||
if (pThrottle != NULL)
|
|
||||||
pThrottle->parse();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Print the list of assigned locomotives. */
|
// Print the list of assigned locomotives
|
||||||
void Z21Throttle::printLocomotives(bool addTab) {
|
void Z21Throttle::printLocomotives(bool addTab) {
|
||||||
if (!Diag::Z21THROTTLE)
|
if (!Diag::Z21THROTTLE)
|
||||||
return;
|
return;
|
||||||
|
@ -144,7 +127,7 @@ void Z21Throttle::printLocomotives(bool addTab) {
|
||||||
DIAG(F("%s %d : cab %d on throttle %c"), addTab ? " ":"", loco, myLocos[loco].cab, myLocos[loco].throttle);
|
DIAG(F("%s %d : cab %d on throttle %c"), addTab ? " ":"", loco, myLocos[loco].cab, myLocos[loco].throttle);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Print the list of assigned locomotives. */
|
// Print the list of UDP clients
|
||||||
void printClientsUDP() {
|
void printClientsUDP() {
|
||||||
if (!Diag::Z21THROTTLE) return;
|
if (!Diag::Z21THROTTLE) return;
|
||||||
|
|
||||||
|
@ -156,7 +139,7 @@ void printClientsUDP() {
|
||||||
DIAG(F(" %d unused"), clientId);
|
DIAG(F(" %d unused"), clientId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Print the list of assigned locomotives. */
|
// Print the list of throttles
|
||||||
void Z21Throttle::printThrottles(bool inPrintLocomotives) {
|
void Z21Throttle::printThrottles(bool inPrintLocomotives) {
|
||||||
if (!Diag::Z21THROTTLE) return;
|
if (!Diag::Z21THROTTLE) return;
|
||||||
|
|
||||||
|
@ -215,10 +198,10 @@ bool Z21Throttle::areYouUsingThrottle(int cab) {
|
||||||
// One instance of Z21Throttle per connected client, so we know what the locos are
|
// One instance of Z21Throttle per connected client, so we know what the locos are
|
||||||
|
|
||||||
Z21Throttle::Z21Throttle(int inClientId) {
|
Z21Throttle::Z21Throttle(int inClientId) {
|
||||||
|
clientid = inClientId;
|
||||||
if (Diag::Z21THROTTLE) DIAG(F("New Z21Throttle for client UDP %d"), clientid);
|
if (Diag::Z21THROTTLE) DIAG(F("New Z21Throttle for client UDP %d"), clientid);
|
||||||
nextThrottle=firstThrottle;
|
nextThrottle=firstThrottle;
|
||||||
firstThrottle= this;
|
firstThrottle= this;
|
||||||
clientid = inClientId;
|
|
||||||
initSent=false; // prevent sending heartbeats before connection completed
|
initSent=false; // prevent sending heartbeats before connection completed
|
||||||
turnoutListHash = -1; // make sure turnout list is sent once
|
turnoutListHash = -1; // make sure turnout list is sent once
|
||||||
exRailSent=false;
|
exRailSent=false;
|
||||||
|
@ -617,230 +600,274 @@ void Z21Throttle::cvReadPom(byte inDB1, byte inDB2, byte inDB3, byte inDB4) {
|
||||||
DCC::readCV(cvAddress, ptr);
|
DCC::readCV(cvAddress, ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Z21Throttle::parse() {
|
void diagPacket(byte *networkPacket, int len) {
|
||||||
bool done = false;
|
DIAG(F("len=%d 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x"),
|
||||||
byte DB[100];
|
len,
|
||||||
CircularBuffer* pBuffer = clientsUDP[this->clientid].pudpBuffer;
|
networkPacket[0],
|
||||||
|
networkPacket[1],
|
||||||
|
networkPacket[2],
|
||||||
|
networkPacket[3],
|
||||||
|
networkPacket[4],
|
||||||
|
networkPacket[5],
|
||||||
|
networkPacket[6],
|
||||||
|
networkPacket[7],
|
||||||
|
networkPacket[8],
|
||||||
|
networkPacket[9],
|
||||||
|
networkPacket[10],
|
||||||
|
networkPacket[11],
|
||||||
|
networkPacket[12],
|
||||||
|
networkPacket[13],
|
||||||
|
networkPacket[14]);
|
||||||
|
}
|
||||||
|
#define GETINT16(BUF) (int16_t((unsigned char)(*(BUF+1)) << 8 | (unsigned char)(*BUF)));
|
||||||
|
bool Z21Throttle::parse(byte *networkPacket, int len) {
|
||||||
|
|
||||||
if (pBuffer == NULL)
|
bool done = false;
|
||||||
return false;
|
byte *DB;
|
||||||
if (pBuffer->isEmpty())
|
byte *p = networkPacket;
|
||||||
return false;
|
int l = len;
|
||||||
|
|
||||||
int lengthData = pBuffer->GetInt16() - 4; // length of the data = total length - length of length (!) - length of header
|
while (l > 0) {
|
||||||
int header = pBuffer->GetInt16();
|
|
||||||
byte Xheader = 0;
|
|
||||||
byte DB0 = 0;
|
|
||||||
int nbLocos = CountLocos();
|
|
||||||
|
|
||||||
if (lengthData > 0) {
|
int lengthData = GETINT16(p);
|
||||||
pBuffer->GetBytes(DB, lengthData);
|
l -= lengthData;
|
||||||
if (Diag::Z21THROTTLEDATA && DB[1] != LAN_X_DB0_GET_STATUS) DIAG(F("%d <- len:%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 (p == networkPacket && lengthData != len) {
|
||||||
this->clientid, lengthData, header,
|
diagPacket(networkPacket, len);
|
||||||
(lengthData > 0)?DB[0]:0,
|
}
|
||||||
(lengthData > 1)?DB[1]:0,
|
if (l < 0) {
|
||||||
(lengthData > 2)?DB[2]:0,
|
DIAG(F("ERROR: Xbus data exceeds UDP packet size: l < 0 pos=%d, l=%d"), p-networkPacket, l);
|
||||||
(lengthData > 3)?DB[3]:0,
|
diagPacket(networkPacket, len);
|
||||||
(lengthData > 4)?DB[4]:0,
|
return false;
|
||||||
(lengthData > 5)?DB[5]:0,
|
}
|
||||||
(lengthData > 6)?DB[6]:0,
|
if (l > 0 && lengthData < 4) {
|
||||||
(lengthData > 7)?DB[7]:0,
|
DIAG(F("WARNING: Xbus data does not fill UDP packet size: l > 0 pos=%d, l=%d"), p-networkPacket, l);
|
||||||
(lengthData > 8)?DB[8]:0,
|
diagPacket(networkPacket, len);
|
||||||
(lengthData > 9)?DB[9]:0);
|
return true;
|
||||||
|
}
|
||||||
|
// length of the data = total length - length of length (!) - length of header
|
||||||
|
lengthData -= 4;
|
||||||
|
if (lengthData < 0) {
|
||||||
|
DIAG(F("ERROR: lengthData < 0 SHOULD NOT GET HERE"));
|
||||||
|
diagPacket(networkPacket, len);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
p += 2;
|
||||||
|
int header = GETINT16(p);
|
||||||
|
byte Xheader = 0;
|
||||||
|
p += 2;
|
||||||
|
DB = p;
|
||||||
|
byte DB0 = 0;
|
||||||
|
int nbLocos = CountLocos();
|
||||||
|
// set p for next round
|
||||||
|
p += lengthData;
|
||||||
|
if (Diag::Z21THROTTLEDATA && DB[1] != LAN_X_DB0_GET_STATUS)
|
||||||
|
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"),
|
||||||
|
this->clientid, lengthData, header,
|
||||||
|
(lengthData > 0)?DB[0]:0,
|
||||||
|
(lengthData > 1)?DB[1]:0,
|
||||||
|
(lengthData > 2)?DB[2]:0,
|
||||||
|
(lengthData > 3)?DB[3]:0,
|
||||||
|
(lengthData > 4)?DB[4]:0,
|
||||||
|
(lengthData > 5)?DB[5]:0,
|
||||||
|
(lengthData > 6)?DB[6]:0,
|
||||||
|
(lengthData > 7)?DB[7]:0,
|
||||||
|
(lengthData > 8)?DB[8]:0,
|
||||||
|
(lengthData > 9)?DB[9]:0);
|
||||||
|
if (l > 0 && Diag::Z21THROTTLEDATA) DIAG(F("next packet follows"));
|
||||||
|
|
||||||
|
switch (header) {
|
||||||
|
case HEADER_LAN_XPRESS_NET:
|
||||||
|
Xheader = DB[0];
|
||||||
|
switch (Xheader) {
|
||||||
|
case LAN_X_HEADER_GENERAL:
|
||||||
|
DB0 = DB[1];
|
||||||
|
switch (DB0) {
|
||||||
|
case LAN_X_DB0_GET_VERSION:
|
||||||
|
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d GET_VERSION"), this->clientid);
|
||||||
|
break;
|
||||||
|
case LAN_X_DB0_GET_STATUS:
|
||||||
|
if (false && Diag::Z21THROTTLEVERBOSE) DIAG(F("%d GET_STATUS "), this->clientid);
|
||||||
|
notifyStatus();
|
||||||
|
done = true;
|
||||||
|
break;
|
||||||
|
case LAN_X_DB0_SET_TRACK_POWER_OFF:
|
||||||
|
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d POWER_OFF"), this->clientid);
|
||||||
|
//
|
||||||
|
// TODO Pass through a text message to avoid multi thread locks...
|
||||||
|
//
|
||||||
|
TrackManager::setMainPower(POWERMODE::OFF);
|
||||||
|
done = true;
|
||||||
|
break;
|
||||||
|
case LAN_X_DB0_SET_TRACK_POWER_ON:
|
||||||
|
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d POWER_ON"), this->clientid);
|
||||||
|
//
|
||||||
|
// TODO Pass through a text message to avoid multi thread locks...
|
||||||
|
//
|
||||||
|
TrackManager::setMainPower(POWERMODE::ON);
|
||||||
|
done = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
switch (header) {
|
case LAN_X_HEADER_SET_STOP:
|
||||||
case HEADER_LAN_XPRESS_NET:
|
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d EMERGENCY_STOP"), this->clientid);
|
||||||
Xheader = DB[0];
|
//
|
||||||
switch (Xheader) {
|
// TODO Pass through a text message to avoid multi thread locks...
|
||||||
case LAN_X_HEADER_GENERAL:
|
//
|
||||||
DB0 = DB[1];
|
//Emergency Stop (speed code 1)
|
||||||
switch (DB0) {
|
// setThrottle will cause a broadcast so notification will be sent
|
||||||
case LAN_X_DB0_GET_VERSION:
|
LOOPLOCOS('*', 0) { DCC::setThrottle(myLocos[loco].cab, 1, DCC::getThrottleDirection(myLocos[loco].cab)); }
|
||||||
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d GET_VERSION"), this->clientid);
|
done = true;
|
||||||
break;
|
break;
|
||||||
case LAN_X_DB0_GET_STATUS:
|
case LAN_X_HEADER_SET_LOCO:
|
||||||
if (false && Diag::Z21THROTTLEVERBOSE) DIAG(F("%d GET_STATUS "), this->clientid);
|
DB0 = DB[1];
|
||||||
notifyStatus();
|
switch (DB0) {
|
||||||
done = true;
|
case LAN_X_DB0_LOCO_DCC14:
|
||||||
break;
|
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d LOCO DCC 14 SPEED"), this->clientid);
|
||||||
case LAN_X_DB0_SET_TRACK_POWER_OFF:
|
setSpeed(14, DB[2], DB[3], DB[4]);
|
||||||
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d POWER_OFF"), this->clientid);
|
done = true;
|
||||||
//
|
break;
|
||||||
// TODO Pass through a text message to avoid multi thread locks...
|
case LAN_X_DB0_LOCO_DCC28:
|
||||||
//
|
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d LOCO DCC 28 SPEED"), this->clientid);
|
||||||
TrackManager::setMainPower(POWERMODE::OFF);
|
setSpeed(28, DB[2], DB[3], DB[4]);
|
||||||
done = true;
|
done = true;
|
||||||
break;
|
break;
|
||||||
case LAN_X_DB0_SET_TRACK_POWER_ON:
|
case LAN_X_DB0_LOCO_DCC128:
|
||||||
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d POWER_ON"), this->clientid);
|
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d LOCO DCC 128 SPEED"), this->clientid);
|
||||||
//
|
setSpeed(128, DB[2], DB[3], DB[4]);
|
||||||
// TODO Pass through a text message to avoid multi thread locks...
|
done = true;
|
||||||
//
|
break;
|
||||||
TrackManager::setMainPower(POWERMODE::ON);
|
case LAN_X_DB0_SET_LOCO_FUNCTION:
|
||||||
done = true;
|
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d LOCO DCC FUNCTION"), this->clientid);
|
||||||
break;
|
setFunction(DB[2], DB[3], DB[4]);
|
||||||
}
|
if (Diag::Z21THROTTLE) {
|
||||||
break;
|
// Debug capacity to print data...
|
||||||
case LAN_X_HEADER_SET_STOP:
|
byte function = DB[4];
|
||||||
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d EMERGENCY_STOP"), this->clientid);
|
bitClear(function, 6);
|
||||||
//
|
bitClear(function, 7);
|
||||||
// TODO Pass through a text message to avoid multi thread locks...
|
if (function == 12) { // why not ?
|
||||||
//
|
printClientsUDP();
|
||||||
//Emergency Stop (speed code 1)
|
printThrottles(true);
|
||||||
// setThrottle will cause a broadcast so notification will be sent
|
}
|
||||||
LOOPLOCOS('*', 0) { DCC::setThrottle(myLocos[loco].cab, 1, DCC::getThrottleDirection(myLocos[loco].cab)); }
|
}
|
||||||
done = true;
|
done = true;
|
||||||
break;
|
break;
|
||||||
case LAN_X_HEADER_SET_LOCO:
|
|
||||||
DB0 = DB[1];
|
|
||||||
switch (DB0) {
|
|
||||||
case LAN_X_DB0_LOCO_DCC14:
|
|
||||||
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d LOCO DCC 14 SPEED"), this->clientid);
|
|
||||||
setSpeed(14, DB[2], DB[3], DB[4]);
|
|
||||||
done = true;
|
|
||||||
break;
|
|
||||||
case LAN_X_DB0_LOCO_DCC28:
|
|
||||||
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d LOCO DCC 28 SPEED"), this->clientid);
|
|
||||||
setSpeed(28, DB[2], DB[3], DB[4]);
|
|
||||||
done = true;
|
|
||||||
break;
|
|
||||||
case LAN_X_DB0_LOCO_DCC128:
|
|
||||||
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d LOCO DCC 128 SPEED"), this->clientid);
|
|
||||||
setSpeed(128, DB[2], DB[3], DB[4]);
|
|
||||||
done = true;
|
|
||||||
break;
|
|
||||||
case LAN_X_DB0_SET_LOCO_FUNCTION:
|
|
||||||
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d LOCO DCC FUNCTION"), this->clientid);
|
|
||||||
setFunction(DB[2], DB[3], DB[4]);
|
|
||||||
if (Diag::Z21THROTTLE) {
|
|
||||||
// Debug capacity to print data...
|
|
||||||
byte function = DB[4];
|
|
||||||
bitClear(function, 6);
|
|
||||||
bitClear(function, 7);
|
|
||||||
if (function == 12) { // why not ?
|
|
||||||
printClientsUDP();
|
|
||||||
printThrottles(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
done = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case LAN_X_HEADER_GET_LOCO_INFO:
|
|
||||||
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d LOCO INFO: "), this->clientid);
|
|
||||||
notifyLocoInfo(DB[2], DB[3]);
|
|
||||||
done = true;
|
|
||||||
|
|
||||||
break;
|
|
||||||
case LAN_X_HEADER_GET_TURNOUT_INFO:
|
|
||||||
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d TURNOUT INFO "), this->clientid);
|
|
||||||
notifyTurnoutInfo(DB[1], DB[2]);
|
|
||||||
done = true;
|
|
||||||
|
|
||||||
break;
|
|
||||||
case LAN_X_HEADER_GET_FIRMWARE_VERSION:
|
|
||||||
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d FIRMWARE VERSION "), this->clientid);
|
|
||||||
notifyFirmwareVersion();
|
|
||||||
done = true;
|
|
||||||
break;
|
|
||||||
case LAN_X_HEADER_CV_READ:
|
|
||||||
if (TrackManager::getProgDriver() != NULL) {
|
|
||||||
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d CV READ PROG "), this->clientid);
|
|
||||||
// DB0 should be 0x11
|
|
||||||
cvReadProg(DB[2], DB[3]);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
//
|
|
||||||
// TODO Dont work today...
|
|
||||||
//
|
|
||||||
|
|
||||||
// If no prog track, read on the main track !
|
|
||||||
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d CV READ MAIN "), this->clientid);
|
|
||||||
// DB0 should be 0x11
|
|
||||||
cvReadMain(DB[2], DB[3]);
|
|
||||||
}
|
|
||||||
done = true;
|
|
||||||
break;
|
|
||||||
case LAN_X_HEADER_CV_POM:
|
|
||||||
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d CV READ POM"), this->clientid);
|
|
||||||
// DB0 should be 0x11
|
|
||||||
cvReadPom(DB[2], DB[3], DB[4], DB[5]);
|
|
||||||
done = true;
|
|
||||||
break;
|
|
||||||
case LAN_X_HEADER_CV_WRITE:
|
|
||||||
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d CV WRITE "), this->clientid);
|
|
||||||
notifyFirmwareVersion();
|
|
||||||
done = true;
|
|
||||||
break;
|
|
||||||
case LAN_X_HEADER_SET_TURNOUT:
|
|
||||||
case 0x22:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HEADER_LAN_SET_BROADCASTFLAGS:
|
|
||||||
this->broadcastFlags = CircularBuffer::GetInt32(DB, 0);
|
|
||||||
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_RBUS) ? "RBUS " : "" ,
|
|
||||||
(this->broadcastFlags & BROADCAST_RAILCOM) ? "RAILCOM " : "" ,
|
|
||||||
(this->broadcastFlags & BROADCAST_SYSTEM) ? "SYSTEM " : "" ,
|
|
||||||
(this->broadcastFlags & BROADCAST_BASE_LOCOINFO) ? "LOCOINFO " : "" ,
|
|
||||||
(this->broadcastFlags & BROADCAST_LOCONET) ? "LOCONET " : "" ,
|
|
||||||
(this->broadcastFlags & BROADCAST_LOCONET_LOCO) ? "LOCONET_LOCO " : "" ,
|
|
||||||
(this->broadcastFlags & BROADCAST_LOCONET_SWITCH) ? "LOCONET_SWITCH " : "" ,
|
|
||||||
(this->broadcastFlags & BROADCAST_LOCONET_DETECTOR) ? "LOCONET_DETECTOR " : "" ,
|
|
||||||
(this->broadcastFlags & BROADCAST_RAILCOM_AUTO) ? "RAILCOM_AUTO " : "" ,
|
|
||||||
(this->broadcastFlags & BROADCAST_CAN) ? "CAN" : "" );
|
|
||||||
done = true;
|
|
||||||
break;
|
|
||||||
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.
|
|
||||||
done = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HEADER_LAN_SET_LOCOMODE:
|
|
||||||
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d SET LOCOMODE"), this->clientid);
|
|
||||||
done = true;
|
|
||||||
break;
|
|
||||||
case HEADER_LAN_GET_HWINFO:
|
|
||||||
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d GET HWINFO"), this->clientid);
|
|
||||||
notifyHWInfo(); // big endian here, but resend the same as received, so no problem.
|
|
||||||
done = true;
|
|
||||||
break;
|
|
||||||
case HEADER_LAN_LOGOFF:
|
|
||||||
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d LOGOFF"), this->clientid);
|
|
||||||
this->clientid = -1;
|
|
||||||
done = true;
|
|
||||||
break;
|
|
||||||
case HEADER_LAN_SYSTEMSTATE_GETDATA:
|
|
||||||
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d SYSTEMSTATE GETDATA"), this->clientid);
|
|
||||||
notifyStatus(); // big endian here, but resend the same as received, so no problem.
|
|
||||||
done = true;
|
|
||||||
break;
|
|
||||||
case HEADER_LAN_GET_SERIAL_NUMBER:
|
|
||||||
case HEADER_LAN_GET_BROADCASTFLAGS:
|
|
||||||
case HEADER_LAN_GET_TURNOUTMODE:
|
|
||||||
case HEADER_LAN_SET_TURNOUTMODE:
|
|
||||||
case HEADER_LAN_RMBUS_DATACHANGED:
|
|
||||||
case HEADER_LAN_RMBUS_GETDATA:
|
|
||||||
case HEADER_LAN_RMBUS_PROGRAMMODULE:
|
|
||||||
case HEADER_LAN_RAILCOM_DATACHANGED:
|
|
||||||
case HEADER_LAN_RAILCOM_GETDATA:
|
|
||||||
case HEADER_LAN_LOCONET_DISPATCH_ADDR:
|
|
||||||
case HEADER_LAN_LOCONET_DETECTOR:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case LAN_X_HEADER_GET_LOCO_INFO:
|
||||||
|
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d LOCO INFO: "), this->clientid);
|
||||||
|
notifyLocoInfo(DB[2], DB[3]);
|
||||||
|
done = true;
|
||||||
|
|
||||||
if (!done) {
|
break;
|
||||||
if (Diag::Z21THROTTLE) DIAG(F("Z21 Throttle %d : not treated : header:%x Xheader:%x DB0:%x"), this->clientid, header, Xheader, DB0);
|
case LAN_X_HEADER_GET_TURNOUT_INFO:
|
||||||
|
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d TURNOUT INFO "), this->clientid);
|
||||||
|
notifyTurnoutInfo(DB[1], DB[2]);
|
||||||
|
done = true;
|
||||||
|
|
||||||
|
break;
|
||||||
|
case LAN_X_HEADER_GET_FIRMWARE_VERSION:
|
||||||
|
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d FIRMWARE VERSION "), this->clientid);
|
||||||
|
notifyFirmwareVersion();
|
||||||
|
done = true;
|
||||||
|
break;
|
||||||
|
case LAN_X_HEADER_CV_READ:
|
||||||
|
if (TrackManager::getProgDriver() != NULL) {
|
||||||
|
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d CV READ PROG "), this->clientid);
|
||||||
|
// DB0 should be 0x11
|
||||||
|
cvReadProg(DB[2], DB[3]);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int newNbLocos = CountLocos();
|
//
|
||||||
if (nbLocos != newNbLocos)
|
// TODO Dont work today...
|
||||||
printLocomotives();
|
//
|
||||||
|
|
||||||
|
// If no prog track, read on the main track !
|
||||||
|
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d CV READ MAIN "), this->clientid);
|
||||||
|
// DB0 should be 0x11
|
||||||
|
cvReadMain(DB[2], DB[3]);
|
||||||
}
|
}
|
||||||
return true;
|
done = true;
|
||||||
|
break;
|
||||||
|
case LAN_X_HEADER_CV_POM:
|
||||||
|
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d CV READ POM"), this->clientid);
|
||||||
|
// DB0 should be 0x11
|
||||||
|
cvReadPom(DB[2], DB[3], DB[4], DB[5]);
|
||||||
|
done = true;
|
||||||
|
break;
|
||||||
|
case LAN_X_HEADER_CV_WRITE:
|
||||||
|
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d CV WRITE "), this->clientid);
|
||||||
|
notifyFirmwareVersion();
|
||||||
|
done = true;
|
||||||
|
break;
|
||||||
|
case LAN_X_HEADER_SET_TURNOUT:
|
||||||
|
case 0x22:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HEADER_LAN_SET_BROADCASTFLAGS:
|
||||||
|
this->broadcastFlags = int32_t(DB[3] << 24 | DB[2] << 16 | DB[1] << 8 | DB[0]);
|
||||||
|
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_RBUS) ? "RBUS " : "" ,
|
||||||
|
(this->broadcastFlags & BROADCAST_RAILCOM) ? "RAILCOM " : "" ,
|
||||||
|
(this->broadcastFlags & BROADCAST_SYSTEM) ? "SYSTEM " : "" ,
|
||||||
|
(this->broadcastFlags & BROADCAST_BASE_LOCOINFO) ? "LOCOINFO " : "" ,
|
||||||
|
(this->broadcastFlags & BROADCAST_LOCONET) ? "LOCONET " : "" ,
|
||||||
|
(this->broadcastFlags & BROADCAST_LOCONET_LOCO) ? "LOCONET_LOCO " : "" ,
|
||||||
|
(this->broadcastFlags & BROADCAST_LOCONET_SWITCH) ? "LOCONET_SWITCH " : "" ,
|
||||||
|
(this->broadcastFlags & BROADCAST_LOCONET_DETECTOR) ? "LOCONET_DETECTOR " : "" ,
|
||||||
|
(this->broadcastFlags & BROADCAST_RAILCOM_AUTO) ? "RAILCOM_AUTO " : "" ,
|
||||||
|
(this->broadcastFlags & BROADCAST_CAN) ? "CAN" : "" );
|
||||||
|
done = true;
|
||||||
|
break;
|
||||||
|
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.
|
||||||
|
done = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HEADER_LAN_SET_LOCOMODE:
|
||||||
|
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d SET LOCOMODE"), this->clientid);
|
||||||
|
done = true;
|
||||||
|
break;
|
||||||
|
case HEADER_LAN_GET_HWINFO:
|
||||||
|
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d GET HWINFO"), this->clientid);
|
||||||
|
notifyHWInfo(); // big endian here, but resend the same as received, so no problem.
|
||||||
|
done = true;
|
||||||
|
break;
|
||||||
|
case HEADER_LAN_LOGOFF:
|
||||||
|
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d LOGOFF"), this->clientid);
|
||||||
|
this->clientid = -1;
|
||||||
|
done = true;
|
||||||
|
break;
|
||||||
|
case HEADER_LAN_SYSTEMSTATE_GETDATA:
|
||||||
|
if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d SYSTEMSTATE GETDATA"), this->clientid);
|
||||||
|
notifyStatus(); // big endian here, but resend the same as received, so no problem.
|
||||||
|
done = true;
|
||||||
|
break;
|
||||||
|
case HEADER_LAN_GET_SERIAL_NUMBER:
|
||||||
|
case HEADER_LAN_GET_BROADCASTFLAGS:
|
||||||
|
case HEADER_LAN_GET_TURNOUTMODE:
|
||||||
|
case HEADER_LAN_SET_TURNOUTMODE:
|
||||||
|
case HEADER_LAN_RMBUS_DATACHANGED:
|
||||||
|
case HEADER_LAN_RMBUS_GETDATA:
|
||||||
|
case HEADER_LAN_RMBUS_PROGRAMMODULE:
|
||||||
|
case HEADER_LAN_RAILCOM_DATACHANGED:
|
||||||
|
case HEADER_LAN_RAILCOM_GETDATA:
|
||||||
|
case HEADER_LAN_LOCONET_DISPATCH_ADDR:
|
||||||
|
case HEADER_LAN_LOCONET_DETECTOR:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!done) {
|
||||||
|
if (Diag::Z21THROTTLE) DIAG(F("Z21 Throttle %d : not treated : header:%x Xheader:%x DB0:%x"), this->clientid, header, Xheader, DB0);
|
||||||
|
} else {
|
||||||
|
int newNbLocos = CountLocos();
|
||||||
|
if (nbLocos != newNbLocos)
|
||||||
|
printLocomotives();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if we get here, we did parse one or several xbus packets inside USB packets
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* © 2023 Thierry Paris / Locoduino
|
* © 2023 Thierry Paris / Locoduino
|
||||||
|
* © 2023 Harald Barth
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This is free software: you can redistribute it and/or modify
|
* This is free software: you can redistribute it and/or modify
|
||||||
|
@ -18,9 +19,10 @@
|
||||||
#ifndef Z21Throttle_h
|
#ifndef Z21Throttle_h
|
||||||
#define Z21Throttle_h
|
#define Z21Throttle_h
|
||||||
|
|
||||||
#include "CircularBuffer.hpp"
|
//#include "CircularBuffer.hpp"
|
||||||
#include "WiFiClient.h"
|
#include "WiFiClient.h"
|
||||||
|
|
||||||
|
#define MAX_MTU 1460
|
||||||
#define UDPBYTE_SIZE 1500
|
#define UDPBYTE_SIZE 1500
|
||||||
#define UDP_BUFFERSIZE 2048
|
#define UDP_BUFFERSIZE 2048
|
||||||
|
|
||||||
|
@ -49,8 +51,6 @@ struct MYLOCOZ21 {
|
||||||
class NetworkClientUDP {
|
class NetworkClientUDP {
|
||||||
public:
|
public:
|
||||||
NetworkClientUDP() {
|
NetworkClientUDP() {
|
||||||
this->pudpBuffer = new CircularBuffer(UDP_BUFFERSIZE);
|
|
||||||
this->pudpBuffer->begin(true);
|
|
||||||
};
|
};
|
||||||
bool ok() {
|
bool ok() {
|
||||||
return (inUse);
|
return (inUse);
|
||||||
|
@ -58,7 +58,6 @@ class NetworkClientUDP {
|
||||||
|
|
||||||
bool inUse = true;
|
bool inUse = true;
|
||||||
bool connected = false;
|
bool connected = false;
|
||||||
CircularBuffer *pudpBuffer = NULL;
|
|
||||||
IPAddress remoteIP;
|
IPAddress remoteIP;
|
||||||
int remotePort;
|
int remotePort;
|
||||||
|
|
||||||
|
@ -77,7 +76,7 @@ class Z21Throttle {
|
||||||
void notifyCvNACK(int inCvAddress);
|
void notifyCvNACK(int inCvAddress);
|
||||||
void notifyCvRead(int inCvAddress, int inValue);
|
void notifyCvRead(int inCvAddress, int inValue);
|
||||||
|
|
||||||
bool parse();
|
bool parse(byte *networkPacket, int len);
|
||||||
|
|
||||||
static Z21Throttle *readWriteThrottle; // NULL if no throttle is reading or writing a CV...
|
static Z21Throttle *readWriteThrottle; // NULL if no throttle is reading or writing a CV...
|
||||||
static int cvAddress;
|
static int cvAddress;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user