From 0144ff7ee4363268bc62b0b77101f7efc591c0a0 Mon Sep 17 00:00:00 2001 From: Gregor Baues Date: Tue, 27 Oct 2020 09:52:06 +0100 Subject: [PATCH] Fixes the main loop over all interfaces --- CommandStation-EX.ino | 4 +- NetworkConfig.h | 1 + NetworkInterface.cpp | 87 +++++++++++++++++++++++++++++------------- NetworkInterface.h | 41 +++++++++++++++++--- Transport.cpp | 5 ++- Transport.h | 5 ++- TransportProcessor.cpp | 36 ++++++++--------- 7 files changed, 119 insertions(+), 60 deletions(-) diff --git a/CommandStation-EX.ino b/CommandStation-EX.ino index 85328ac..d820c9e 100644 --- a/CommandStation-EX.ino +++ b/CommandStation-EX.ino @@ -102,9 +102,7 @@ void loop() // (3) Start Loop NetworkInterface - // wifi.loop(); - eth1.loop(); - eth2.loop(); +NetworkInterface::loop(); // (3) End Loop NetworkInterface diff --git a/NetworkConfig.h b/NetworkConfig.h index b813e1c..3749424 100644 --- a/NetworkConfig.h +++ b/NetworkConfig.h @@ -40,6 +40,7 @@ * @brief NetworkInterface configuration * */ +#define MAX_INTERFACES 4 // Consume too much memeory beyond in general not more than 2 should be required #define MAX_SOCK_NUM 8 // Maximum number of sockets allowed for any WizNet based EthernetShield. The W5100 only supports 4 #define MAX_WIFI_SOCK 5 // ESP8266 doesn't support more than 5 connections #define MAX_ETH_BUFFER 64 // maximum length we read in one go from a TCP packet. diff --git a/NetworkInterface.cpp b/NetworkInterface.cpp index b2243b1..4bcecc7 100644 --- a/NetworkInterface.cpp +++ b/NetworkInterface.cpp @@ -23,12 +23,54 @@ #include "EthernetSetup.h" #include "WifiSetup.h" -Transport* wifiTransport; -Transport* ethernetTransport; +Transport *wifiTransport; +Transport *ethernetTransport; + +DCCNetwork _dccNet; + +void DCCNetwork::loop() +{ + for (byte i = 0; i < _tCounter; i++) + { + + Transport *e; + Transport *w; + + switch (_t[i]) + { + case ETHERNET: + { + e = (Transport *)transports[i]; + e->loop(); + break; + } + case WIFI: + { + w = (Transport *)transports[i]; + w->loop(); + break; + } + } + } +} + +byte DCCNetwork::add(AbstractTransport *t, transportType transport) +{ + if (_tCounter != MAX_INTERFACES) + { + _t[_tCounter] = transport; + transports[_tCounter] = t; // add to array of network interfaces returns the index + 1 if added + _tCounter++; // if max intefaces is reached returns 0 for too many ... + return _tCounter; // normally a delete shall not be necessary as all is setup at the beginning and shall not change over a session + } + else + { + return 0; + } +} void NetworkInterface::setup(transportType transport, protocolType protocol, uint16_t port) { - bool ok = false; DIAG(F("\n[%s] Transport Setup In Progress ...\n"), transport ? "Ethernet" : "Wifi"); @@ -45,25 +87,29 @@ void NetworkInterface::setup(transportType transport, protocolType protocol, uin if (ok) { wifiTransport = new Transport; + wifiTransport->id = _dccNet.add(wifiTransport, transport); wifiTransport->server = wSetup.getServer(); wifiTransport->port = port; wifiTransport->protocol = protocol; wifiTransport->transport = transport; wifiTransport->maxConnections = wSetup.maxConnections; ok = wifiTransport->setup(this); - } - break; + DIAG(F("\n\nInterface [%x] bound to transport id [%d:%x]"), this, wifiTransport->id, wifiTransport); + break; + }; }; case ETHERNET: { EthernetSetup eSetup(port, protocol); ethernetTransport = new Transport; + ethernetTransport->id = _dccNet.add(ethernetTransport, transport); ethernetTransport->server = eSetup.setup(); // returns (NULL) 0 if we run over UDP; todo: error handling if something goes wrong in the init ethernetTransport->port = port; ethernetTransport->protocol = protocol; ethernetTransport->transport = transport; ethernetTransport->maxConnections = eSetup.maxConnections; // that has been determined during the ethernet/wifi setup - ok = ethernetTransport->setup(this); // start the transport i.e. setup all the client connections; We don't need the setup object anymore from here on + ok = ethernetTransport->setup(this); // start the transport i.e. setup all the client connections; We don't need the setup object anymore from here on + DIAG(F("\n\nInterface [%x] bound to transport id [%d:%x]"), this, ethernetTransport->id, ethernetTransport); break; }; default: @@ -72,7 +118,8 @@ void NetworkInterface::setup(transportType transport, protocolType protocol, uin break; } } - DIAG(F("\n\n[%s] Transport %s ..."), transport ? "Ethernet" : "Wifi", ok ? "OK" : "Failed"); + + DIAG(F("\n[%s] Transport %s ..."), transport ? "Ethernet" : "Wifi", ok ? "OK" : "Failed"); } void NetworkInterface::setup(transportType tt, protocolType pt) @@ -92,28 +139,14 @@ void NetworkInterface::setup() void NetworkInterface::loop() { - switch (t) - { - case WIFI: - { - if (wifiTransport->isConnected()){ - wifiTransport->loop(); - } - break; - } - case ETHERNET: - { - if (ethernetTransport->isConnected()) { - ethernetTransport->loop(); - } - break; - } - } + // loop over all the transports in + _dccNet.loop(); + } void NetworkInterface::setHttpCallback(HttpCallback callback) { - this->httpCallback = callback; + this->httpCallback = callback; } HttpCallback NetworkInterface::getHttpCallback() @@ -121,5 +154,5 @@ HttpCallback NetworkInterface::getHttpCallback() return this->httpCallback; } -NetworkInterface::NetworkInterface(){} -NetworkInterface::~NetworkInterface(){} \ No newline at end of file +NetworkInterface::NetworkInterface() {} +NetworkInterface::~NetworkInterface() {} \ No newline at end of file diff --git a/NetworkInterface.h b/NetworkInterface.h index cd9a75a..cb63b4c 100644 --- a/NetworkInterface.h +++ b/NetworkInterface.h @@ -20,13 +20,13 @@ #include -// #include "Transport.h" +#include "NetworkConfig.h" #include "HttpRequest.h" typedef enum protocolType { TCP, UDP, - MQTT + MQTT } protocolType; typedef enum transportType { @@ -36,15 +36,46 @@ typedef enum transportType { using HttpCallback = void(*)(ParsedRequest *req, Client *client); +/** + * @brief Abstract parent class of the templated ( Ethernet or Wifi ) class + * Instances of Transports are hold through this in an array in DCCNetwork which describes and + * actually manages the available transports. + */ +struct AbstractTransport { + void loop(){}; + virtual ~AbstractTransport(){}; +}; + +/** + * @brief Core class holding and running the instantiated Transports + * initalized through the NetworkInterface. The number of transports is + * limited by MAX_INTERFACES + * + */ +class DCCNetwork { + private: + byte _tCounter = 0; + transportType _t[MAX_INTERFACES]; + public: + AbstractTransport *transports[MAX_INTERFACES]; + + byte add(AbstractTransport* t, transportType _t); + void loop(); +}; + +/** + * @brief Main entry point and provider of callbacks. Sole responsibility is to create + * the transport endpoints and loop over them for processing + * + */ class NetworkInterface { private: - HttpCallback httpCallback; transportType t; public: - + void setHttpCallback(HttpCallback callback); HttpCallback getHttpCallback(); void setup(transportType t, protocolType p, uint16_t port); // specific port nummber @@ -52,7 +83,7 @@ public: void setup(transportType t); // defaults for protocol/port void setup(); // defaults for all as above plus CABLE (i.e. using EthernetShield ) as default - void loop(); + static void loop(); NetworkInterface(); ~NetworkInterface(); diff --git a/Transport.cpp b/Transport.cpp index 11497a3..7e99fa0 100644 --- a/Transport.cpp +++ b/Transport.cpp @@ -62,8 +62,9 @@ void Transport::connectionPool(S *server) for (int i = 0; i < Transport::maxConnections; i++) { clients[i] = server->accept(); - connections[i].client = &clients[i]; - connections[i].id = i; + connections[i].client = &clients[i]; // set the client + memset(connections[i].overflow, 0, MAX_OVERFLOW); // clear overflow buffer + connections[i].id = i; // ser the client id DIAG(F("\nConnection pool: [%d:%x]"), i, connections[i].client); } } diff --git a/Transport.h b/Transport.h index 0f4a4cc..5465c95 100644 --- a/Transport.h +++ b/Transport.h @@ -27,7 +27,7 @@ #include "NetworkInterface.h" #include "TransportProcessor.h" -template class Transport +template class Transport: public AbstractTransport { private: @@ -41,6 +41,7 @@ private: void connectionPool(S* server); // allocates the Sockets at setup time and creates the Connections public: + uint8_t id; uint16_t port; uint8_t protocol; // TCP or UDP uint8_t transport; // WIFI or ETHERNET @@ -48,7 +49,7 @@ public: U* udp; // UDP socket object uint8_t maxConnections; // number of supported connections depending on the network equipment use - bool setup(NetworkInterface* nwi); + bool setup(NetworkInterface* nwi); // we get the callbacks from the NetworkInterface void loop(); bool isConnected() { diff --git a/TransportProcessor.cpp b/TransportProcessor.cpp index e3f1e21..c2c8153 100644 --- a/TransportProcessor.cpp +++ b/TransportProcessor.cpp @@ -52,30 +52,25 @@ uint8_t diagNetworkClient = 0; void sendToDCC(Connection *c, TransportProcessor* t, bool blocking) { - char * _command = t->command; + static MemStream *streamer = new MemStream((byte *)t->command, MAX_ETH_BUFFER, MAX_ETH_BUFFER, true); - static MemStream *streamer = new MemStream((byte *)_command, MAX_ETH_BUFFER, MAX_ETH_BUFFER, true); - - DIAG(F("DCC parsing: [%e]\n"), _command); + DIAG(F("DCC parsing: [%e]\n"), t->command); // as we use buffer for recv and send we have to reset the write position streamer->setBufferContentPosition(0, 0); - ethParser.parse(streamer, (byte *)_command, true); // set to true to that the execution in DCC is sync + ethParser.parse(streamer, (byte *)t->command, true); // set to true to that the execution in DCC is sync if (streamer->available() == 0) { - if (c->client->connected()) - { - c->client->write((byte *)F("No response\n"), streamer->available()); - } + DIAG(F("No response\n")); } else { - _command[streamer->available()] = '\0'; // mark end of buffer, so it can be used as a string later - DIAG(F("Response: %s\n"), _command); + t->command[streamer->available()] = '\0'; // mark end of buffer, so it can be used as a string later + DIAG(F("Response: %s\n"), t->command); if (c->client->connected()) { - c->client->write((byte *)_command, streamer->available()); + c->client->write((byte *)t->command, streamer->available()); } } } @@ -257,17 +252,16 @@ appProtocol setAppProtocol(char a, char b, Connection *c) void processStream(Connection *c, TransportProcessor *t) { uint8_t i, j, k, l = 0; - uint8_t* _buffer = t->buffer; - char* _command = t->command; + uint8_t *_buffer = t->buffer; DIAG(F("\nBuffer: [%e]\n"), _buffer); - memset(_command, 0, MAX_JMRI_CMD); // clear out the command + memset(t->command, 0, MAX_JMRI_CMD); // clear out the command // copy overflow into the command if ((i = strlen(c->overflow)) != 0) { // DIAG(F("\nCopy overflow to command: %e"), c->overflow); - strncpy(_command, c->overflow, i); + strncpy(t->command, c->overflow, i); k = i; } // reset the overflow @@ -296,19 +290,19 @@ void processStream(Connection *c, TransportProcessor *t) } // breakup the buffer using its changed length i = 0; - k = strlen(_command); // current length of the command buffer telling us where to start copy in + k = strlen(t->command); // current length of the command buffer telling us where to start copy in l = strlen((char *)_buffer); // DIAG(F("\nCommand buffer: [%s]:[%d:%d:%d]\n"), command, i, l, k ); while (i < l) { // DIAG(F("\nl: %d k: %d , i: %d"), l, k, i); - _command[k] = _buffer[i]; + t->command[k] = _buffer[i]; if (_buffer[i] == c->delimiter) { // closing bracket need to fix if there is none before an opening bracket ? - _command[k + 1] = '\0'; + t->command[k + 1] = '\0'; - DIAG(F("Command: [%d:%e]\n"), _rseq[c->id], _command); + DIAG(F("Command: [%d:%e]\n"), _rseq[c->id], t->command); #ifdef DCCEX_ENABLED sendToDCC(c, t, true); #else @@ -394,7 +388,7 @@ void TransportProcessor::readStream(Connection *c) c->appProtocolHandler = (appProtocolCallback)echoProcessor; break; } - } + } } #ifdef DCCEX_ENABLED DIAG(F("\nReceived packet of size:[%d]\n"), count);