mirror of
https://github.com/DCC-EX/CommandStation-EX.git
synced 2024-11-24 00:26:13 +01:00
a8bd530451
Arrrrgh!
189 lines
5.2 KiB
C++
189 lines
5.2 KiB
C++
/*
|
|
* © 2020,Gregor Baues, Chris Harlow. All rights reserved.
|
|
*
|
|
* This file is part of DCC-EX/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 <https://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
#if __has_include ( "config.h")
|
|
#include "config.h"
|
|
#else
|
|
#warning config.h not found. Using defaults from config.example.h
|
|
#include "config.example.h"
|
|
#endif
|
|
#include "defines.h"
|
|
#if ETHERNET_ON == true
|
|
#include "EthernetInterface.h"
|
|
#include "DIAG.h"
|
|
#include "CommandDistributor.h"
|
|
#include "DCCTimer.h"
|
|
|
|
EthernetInterface * EthernetInterface::singleton=NULL;
|
|
/**
|
|
* @brief Setup Ethernet Connection
|
|
*
|
|
*/
|
|
void EthernetInterface::setup()
|
|
{
|
|
singleton=new EthernetInterface();
|
|
if (!singleton->connected) singleton=NULL;
|
|
};
|
|
|
|
|
|
/**
|
|
* @brief Aquire IP Address from DHCP and start server
|
|
*
|
|
* @return true
|
|
* @return false
|
|
*/
|
|
EthernetInterface::EthernetInterface()
|
|
{
|
|
byte mac[6];
|
|
DCCTimer::getSimulatedMacAddress(mac);
|
|
DIAG(F("\n+++++ Ethernet Setup. Simulatd mac="));
|
|
for (byte i=0;i<sizeof(mac); i++) {
|
|
DIAG(F("%x:"),mac[i]);
|
|
}
|
|
DIAG(F("\n"));
|
|
|
|
connected=false;
|
|
|
|
#ifdef IP_ADDRESS
|
|
Ethernet.begin(mac, IP_ADDRESS);
|
|
#else
|
|
if (Ethernet.begin(mac) == 0)
|
|
{
|
|
DIAG(F("begin FAILED\n"));
|
|
return;
|
|
}
|
|
#endif
|
|
DIAG(F("begin OK."));
|
|
if (Ethernet.hardwareStatus() == EthernetNoHardware) {
|
|
DIAG(F("shield not found\n"));
|
|
return;
|
|
}
|
|
if (Ethernet.linkStatus() == LinkOFF) {
|
|
DIAG(F("cable not connected\n"));
|
|
return;
|
|
}
|
|
|
|
connected=true;
|
|
|
|
IPAddress ip = Ethernet.localIP(); // reassign the obtained ip address
|
|
|
|
server = new EthernetServer(IP_PORT); // Ethernet Server listening on default port IP_PORT
|
|
server->begin();
|
|
|
|
LCD(4,F("IP: %d.%d.%d.%d"), ip[0], ip[1], ip[2], ip[3]);
|
|
LCD(5,F("Port:%d"), IP_PORT);
|
|
|
|
outboundRing=new RingStream(OUTBOUND_RING_SIZE);
|
|
}
|
|
|
|
/**
|
|
* @brief Main loop for the EthernetInterface
|
|
*
|
|
*/
|
|
void EthernetInterface::loop()
|
|
{
|
|
if (!singleton) return;
|
|
|
|
switch (Ethernet.maintain())
|
|
{
|
|
case 1:
|
|
//renewed fail
|
|
DIAG(F("\nEthernet Error: renewed fail\n"));
|
|
singleton=NULL;
|
|
return;
|
|
|
|
case 3:
|
|
//rebind fail
|
|
DIAG(F("Ethernet Error: rebind fail\n"));
|
|
singleton=NULL;
|
|
return;
|
|
|
|
default:
|
|
//nothing happened
|
|
break;
|
|
}
|
|
|
|
singleton->loop2();
|
|
|
|
}
|
|
|
|
void EthernetInterface::loop2()
|
|
{
|
|
// get client from the server
|
|
EthernetClient client = server->accept();
|
|
|
|
// check for new client
|
|
if (client)
|
|
{
|
|
if (Diag::ETHERNET) DIAG(F("\nEthernet: New client "));
|
|
byte socket;
|
|
for (socket = 0; socket < MAX_SOCK_NUM; socket++)
|
|
{
|
|
if (!clients[socket])
|
|
{
|
|
// On accept() the EthernetServer doesn't track the client anymore
|
|
// so we store it in our client array
|
|
if (Diag::ETHERNET) DIAG(F("%d\n"),socket);
|
|
clients[socket] = client;
|
|
break;
|
|
}
|
|
}
|
|
if (socket==MAX_SOCK_NUM) DIAG(F("new Ethernet OVERFLOW\n"));
|
|
}
|
|
|
|
// check for incoming data from all possible clients
|
|
for (byte socket = 0; socket < MAX_SOCK_NUM; socket++)
|
|
{
|
|
if (clients[socket]) {
|
|
|
|
int available=clients[socket].available();
|
|
if (available > 0) {
|
|
if (Diag::ETHERNET) DIAG(F("\nEthernet: available socket=%d,avail=%d,count="), socket, available);
|
|
// read bytes from a client
|
|
int count = clients[socket].read(buffer, MAX_ETH_BUFFER);
|
|
buffer[count] = '\0'; // terminate the string properly
|
|
if (Diag::ETHERNET) DIAG(F("%d:%e\n"), socket,buffer);
|
|
// execute with data going directly back
|
|
outboundRing->mark(socket);
|
|
CommandDistributor::parse(socket,buffer,outboundRing);
|
|
outboundRing->commit();
|
|
return; // limit the amount of processing that takes place within 1 loop() cycle.
|
|
}
|
|
}
|
|
}
|
|
|
|
// stop any clients which disconnect
|
|
for (int socket = 0; socket<MAX_SOCK_NUM; socket++) {
|
|
if (clients[socket] && !clients[socket].connected()) {
|
|
clients[socket].stop();
|
|
if (Diag::ETHERNET) DIAG(F("\nEthernet: disconnect %d \n"), socket);
|
|
}
|
|
}
|
|
|
|
// handle at most 1 outbound transmission
|
|
int socketOut=outboundRing->read();
|
|
if (socketOut>=0) {
|
|
int count=outboundRing->count();
|
|
if (Diag::ETHERNET) DIAG(F("Ethernet reply socket=%d, count=:%d\n"), socketOut,count);
|
|
for(;count>0;count--) clients[socketOut].write(outboundRing->read());
|
|
clients[socketOut].flush(); //maybe
|
|
}
|
|
}
|
|
#endif
|