1
0
mirror of https://github.com/DCC-EX/CommandStation-EX.git synced 2025-03-13 17:43:08 +01:00

Fixes the main loop over all interfaces

This commit is contained in:
Gregor Baues 2020-10-27 09:52:06 +01:00
parent 1b624cdfdb
commit 0144ff7ee4
7 changed files with 119 additions and 60 deletions

View File

@ -102,9 +102,7 @@ void loop()
// (3) Start Loop NetworkInterface
// wifi.loop();
eth1.loop();
eth2.loop();
NetworkInterface::loop();
// (3) End Loop NetworkInterface

View File

@ -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.

View File

@ -23,12 +23,54 @@
#include "EthernetSetup.h"
#include "WifiSetup.h"
Transport<WiFiServer, WiFiClient, WiFiUDP>* wifiTransport;
Transport<EthernetServer, EthernetClient, EthernetUDP>* ethernetTransport;
Transport<WiFiServer, WiFiClient, WiFiUDP> *wifiTransport;
Transport<EthernetServer, EthernetClient, EthernetUDP> *ethernetTransport;
DCCNetwork _dccNet;
void DCCNetwork::loop()
{
for (byte i = 0; i < _tCounter; i++)
{
Transport<EthernetServer, EthernetClient, EthernetUDP> *e;
Transport<WiFiServer, WiFiClient, WiFiUDP> *w;
switch (_t[i])
{
case ETHERNET:
{
e = (Transport<EthernetServer, EthernetClient, EthernetUDP> *)transports[i];
e->loop();
break;
}
case WIFI:
{
w = (Transport<WiFiServer, WiFiClient, WiFiUDP> *)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<WiFiServer, WiFiClient, WiFiUDP>;
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<EthernetServer, EthernetClient, EthernetUDP>;
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(){}
NetworkInterface::NetworkInterface() {}
NetworkInterface::~NetworkInterface() {}

View File

@ -20,13 +20,13 @@
#include <Arduino.h>
// #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();

View File

@ -62,8 +62,9 @@ void Transport<S, C, U>::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);
}
}

View File

@ -27,7 +27,7 @@
#include "NetworkInterface.h"
#include "TransportProcessor.h"
template <class S, class C, class U> class Transport
template <class S, class C, class U> 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() {

View File

@ -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);