From aacfff2e3dada1799403aa26f5cde0fe9e1dd9c2 Mon Sep 17 00:00:00 2001 From: Harald Barth Date: Mon, 25 Mar 2024 15:05:14 +0100 Subject: [PATCH] Z21 add turnout and sensor broadcasts --- CommandDistributor.cpp | 3 ++ NetworkClientUDP.h | 37 +++++++++++++++++++++++++ Z21Throttle.cpp | 63 +++++++++++++++++++++++++++++++++++++++++- Z21Throttle.h | 29 ++++++++----------- 4 files changed, 113 insertions(+), 19 deletions(-) create mode 100644 NetworkClientUDP.h diff --git a/CommandDistributor.cpp b/CommandDistributor.cpp index e7087ad..829b581 100644 --- a/CommandDistributor.cpp +++ b/CommandDistributor.cpp @@ -31,6 +31,7 @@ #include "DCC.h" #include "TrackManager.h" #include "StringFormatter.h" +#include "Z21Throttle.h" // variables to hold clock time int16_t lastclocktime; @@ -149,6 +150,7 @@ void CommandDistributor::broadcastToClients(clientType type) { // Public broadcast functions below void CommandDistributor::broadcastSensor(int16_t id, bool on ) { + Z21Throttle::broadcastNotifySensor(id, on); broadcastReply(COMMAND_TYPE, F("<%c %d>\n"), on?'Q':'q', id); } @@ -156,6 +158,7 @@ void CommandDistributor::broadcastTurnout(int16_t id, bool isClosed ) { // 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 // be safe for both types. + Z21Throttle::broadcastNotifyTurnout(id, isClosed); broadcastReply(COMMAND_TYPE, F("\n"),id, !isClosed); #ifdef CD_HANDLE_RING broadcastReply(WITHROTTLE_TYPE, F("PTA%c%d\n"), isClosed?'2':'4', id); diff --git a/NetworkClientUDP.h b/NetworkClientUDP.h new file mode 100644 index 0000000..bb23617 --- /dev/null +++ b/NetworkClientUDP.h @@ -0,0 +1,37 @@ +/* + * © 2024 Harald Barth + * All rights reserved. + * + * This file is part of CommandStation-EX + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * It is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with CommandStation. If not, see . + */ +#include +#include + +class NetworkClientUDP { +public: + NetworkClientUDP() { + }; + bool ok() { + return (inUse); + }; + + bool inUse = true; + bool connected = false; + IPAddress remoteIP; + int remotePort; + + static WiFiUDP client; +}; diff --git a/Z21Throttle.cpp b/Z21Throttle.cpp index 7cc799e..29402dc 100644 --- a/Z21Throttle.cpp +++ b/Z21Throttle.cpp @@ -27,6 +27,7 @@ #include "DCCWaveform.h" #include "StringFormatter.h" #include "Turnouts.h" +#include "Sensors.h" #include "DIAG.h" #include "GITHUB_SHA.h" #include "version.h" @@ -172,6 +173,17 @@ Z21Throttle* Z21Throttle::getOrAddThrottle(int clientId) { return p; } +void Z21Throttle::broadcastNotifyTurnout(uint16_t addr, bool isClosed) { + for (Z21Throttle* wt = firstThrottle; wt != NULL ; wt = wt->nextThrottle) { + wt->notifyTurnoutInfo(addr, isClosed); + } +} +void Z21Throttle::broadcastNotifySensor(uint16_t addr, bool state) { + for (Z21Throttle* wt = firstThrottle; wt != NULL ; wt = wt->nextThrottle) { + wt->notifySensor(addr, state); + } +} + void Z21Throttle::forget( byte clientId) { for (Z21Throttle* wt=firstThrottle; wt!=NULL ; wt=wt->nextThrottle) if (wt->clientid==clientId) { @@ -405,6 +417,22 @@ void Z21Throttle::notifyLocoInfo(byte inMSB, byte inLSB) { notify(HEADER_LAN_XPRESS_NET, LAN_X_HEADER_LOCO_INFO, Z21Throttle::replyBuffer, 9, false); } +void Z21Throttle::notifyTurnoutInfo(uint16_t addr, bool isClosed) { + char c; + Z21Throttle::replyBuffer[0] = (byte)(addr >> 8); + Z21Throttle::replyBuffer[1] = (byte)(addr & 0xFF); + if (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); +} + void Z21Throttle::notifyTurnoutInfo(byte inMSB, byte inLSB) { Z21Throttle::replyBuffer[0] = inMSB; // turnout address msb Z21Throttle::replyBuffer[1] = inLSB; // turnout address lsb @@ -426,6 +454,23 @@ void Z21Throttle::notifyTurnoutInfo(byte inMSB, byte inLSB) { notify(HEADER_LAN_XPRESS_NET, LAN_X_HEADER_TURNOUT_INFO, Z21Throttle::replyBuffer, 3, false); } +void Z21Throttle::notifySensor(uint16_t addr) { + Sensor *s = Sensor::get(addr); + if (s) { + notifySensor(addr, s->active); + } +} + +void Z21Throttle::notifySensor(uint16_t addr, bool state) { + Z21Throttle::replyBuffer[0] = 0x01; // Status in first info byte + Z21Throttle::replyBuffer[1] = (byte)(addr & 0xFF); + Z21Throttle::replyBuffer[2] = (byte)(addr >> 8); + Z21Throttle::replyBuffer[3] = state; + if (Diag::Z21THROTTLE) + DIAG(F("Z21 Throttle %d : notifySensor %d 0x%x"), clientid, addr, Z21Throttle::replyBuffer[3]); + notify(HEADER_LAN_LOCONET_DETECTOR, Z21Throttle::replyBuffer, 4, false); +} + void Z21Throttle::notifyLocoMode(byte inMSB, byte inLSB) { Z21Throttle::replyBuffer[0] = inMSB; // loco address msb Z21Throttle::replyBuffer[1] = inLSB; // loco address lsb @@ -888,6 +933,23 @@ bool Z21Throttle::parse(byte *networkPacket, int len) { notifyStatus(); // big endian here, but resend the same as received, so no problem. done = true; break; + case HEADER_LAN_LOCONET_DETECTOR: + { + switch(Data[0]) { + case LAN_LOCONET_TYPE_UHL_REPORTER: + { + uint16_t addr = (Data[2] << 8) + Data[1]; + if (Diag::Z21THROTTLEVERBOSE) DIAG(F("%d LOCONET DETECTOR %d"), this->clientid, addr); + notifySensor(addr); + //done = true; + break; + } + case LAN_LOCONET_TYPE_DIGITRAX: + case LAN_LOCONET_TYPE_UHL_LISSY: + break; + } + } + break; case HEADER_LAN_GET_SERIAL_NUMBER: // XXX this has been seen, return dummy number case HEADER_LAN_GET_BROADCASTFLAGS: @@ -899,7 +961,6 @@ bool Z21Throttle::parse(byte *networkPacket, int len) { case HEADER_LAN_RAILCOM_DATACHANGED: case HEADER_LAN_RAILCOM_GETDATA: case HEADER_LAN_LOCONET_DISPATCH_ADDR: - case HEADER_LAN_LOCONET_DETECTOR: break; } diff --git a/Z21Throttle.h b/Z21Throttle.h index a1cc72e..271bf85 100644 --- a/Z21Throttle.h +++ b/Z21Throttle.h @@ -20,7 +20,7 @@ #define Z21Throttle_h //#include "CircularBuffer.hpp" -#include "WiFiClient.h" +#include "NetworkClientUDP.h" #define MAX_MTU 1460 #define UDPBYTE_SIZE 1500 @@ -48,26 +48,12 @@ struct MYLOCOZ21 { uint32_t functionToggles; }; -class NetworkClientUDP { - public: - NetworkClientUDP() { - }; - bool ok() { - return (inUse); - }; - - bool inUse = true; - bool connected = false; - IPAddress remoteIP; - int remotePort; - - static WiFiUDP client; -}; - class Z21Throttle { public: static void loop(); - static Z21Throttle* getOrAddThrottle(int clientId); + static Z21Throttle* getOrAddThrottle(int clientId); + static void broadcastNotifyTurnout(uint16_t addr, bool isClosed); + static void broadcastNotifySensor(uint16_t addr, bool state); static void markForBroadcast(int cab); static void forget(byte clientId); static void findUniqThrottle(int id, char *u); @@ -137,7 +123,10 @@ class Z21Throttle { void notifyStatus(); void notifyLocoInfo(byte inMSB, byte inLSB); + void notifyTurnoutInfo(uint16_t addr, bool isClosed); void notifyTurnoutInfo(byte inMSB, byte inLSB); + void notifySensor(uint16_t addr); + void notifySensor(uint16_t addr, bool state); void notifyLocoMode(byte inMSB, byte inLSB); void notifyFirmwareVersion(); void notifyHWInfo(); @@ -182,6 +171,10 @@ class Z21Throttle { #define LAN_GET_CONFIG 0x12 +#define LAN_LOCONET_TYPE_DIGITRAX 0x80 +#define LAN_LOCONET_TYPE_UHL_REPORTER 0x81 +#define LAN_LOCONET_TYPE_UHL_LISSY 0x82 + #define LAN_X_HEADER_GENERAL 0x21 #define LAN_X_HEADER_READ_REGISTER 0x22 #define LAN_X_HEADER_SET_STOP 0x80