2020-09-26 13:01:00 +02:00
|
|
|
/*
|
|
|
|
* © 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/>.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "EthernetInterface.h"
|
|
|
|
#include "DIAG.h"
|
2020-10-30 14:00:02 +01:00
|
|
|
#include "CommandDistributor.h"
|
2020-09-26 13:01:00 +02:00
|
|
|
|
2020-10-30 14:00:02 +01:00
|
|
|
EthernetInterface * EthernetInterface::singleton=NULL;
|
|
|
|
/**
|
|
|
|
* @brief Setup Ethernet Connection
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
void EthernetInterface::setup()
|
|
|
|
{
|
|
|
|
singleton=new EthernetInterface();
|
|
|
|
if (!singleton->connected) singleton=NULL;
|
|
|
|
};
|
2020-09-26 13:01:00 +02:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
2020-10-30 14:00:02 +01:00
|
|
|
* @brief Aquire IP Address from DHCP and start server
|
2020-09-26 13:01:00 +02:00
|
|
|
*
|
|
|
|
* @return true
|
|
|
|
* @return false
|
|
|
|
*/
|
2020-10-30 14:00:02 +01:00
|
|
|
EthernetInterface::EthernetInterface()
|
2020-09-26 13:01:00 +02:00
|
|
|
{
|
2020-10-30 14:00:02 +01:00
|
|
|
byte mac[]=MAC_ADDRESS;
|
2020-09-26 13:01:00 +02:00
|
|
|
|
2020-10-30 14:00:02 +01:00
|
|
|
DIAG(F("\n+++++ Ethernet Setup "));
|
|
|
|
|
|
|
|
if (Ethernet.begin(mac) == 0)
|
2020-09-26 13:01:00 +02:00
|
|
|
{
|
2020-10-30 14:00:02 +01:00
|
|
|
DIAG(F("FAILED "));
|
|
|
|
if (Ethernet.hardwareStatus() == EthernetNoHardware) DIAG(F("shield not found"));
|
|
|
|
else if (Ethernet.linkStatus() == LinkOFF) DIAG(F("cable not connected"));
|
|
|
|
DIAG(F(" ++++++\n"));
|
|
|
|
connected=false;
|
|
|
|
return;
|
2020-09-26 13:01:00 +02:00
|
|
|
}
|
2020-10-30 14:00:02 +01:00
|
|
|
|
|
|
|
connected=true;
|
|
|
|
|
|
|
|
IPAddress ip = Ethernet.localIP(); // reassign the obtained ip address
|
2020-09-26 13:01:00 +02:00
|
|
|
|
2020-10-30 14:00:02 +01:00
|
|
|
server = new EthernetServer(LISTEN_PORT); // Ethernet Server listening on default port LISTEN_PORT
|
|
|
|
server->begin();
|
|
|
|
|
|
|
|
LCD(4,F("IP: %d.%d.%d.%d"), ip[0], ip[1], ip[2], ip[3]);
|
|
|
|
LCD(5,F("Port:%d"), LISTEN_PORT);
|
2020-09-26 13:01:00 +02:00
|
|
|
|
2020-10-30 14:00:02 +01:00
|
|
|
outboundRing=new RingStream(OUTBOUND_RING_SIZE);
|
2020-09-26 13:01:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-10-30 14:00:02 +01:00
|
|
|
* @brief Main loop for the EthernetInterface
|
2020-09-26 13:01:00 +02:00
|
|
|
*
|
|
|
|
*/
|
2020-10-30 14:00:02 +01:00
|
|
|
void EthernetInterface::loop()
|
2020-09-26 13:01:00 +02:00
|
|
|
{
|
2020-10-30 14:00:02 +01:00
|
|
|
if (!singleton) return;
|
|
|
|
|
|
|
|
switch (Ethernet.maintain())
|
2020-09-26 13:01:00 +02:00
|
|
|
{
|
2020-10-30 14:00:02 +01:00
|
|
|
case 1:
|
|
|
|
//renewed fail
|
|
|
|
DIAG(F("\nEthernet Error: renewed fail\n"));
|
|
|
|
singleton=NULL;
|
|
|
|
return;
|
2020-09-26 13:01:00 +02:00
|
|
|
|
2020-10-30 14:00:02 +01:00
|
|
|
case 3:
|
|
|
|
//rebind fail
|
|
|
|
DIAG(F("Ethernet Error: rebind fail\n"));
|
|
|
|
singleton=NULL;
|
|
|
|
return;
|
2020-09-26 13:01:00 +02:00
|
|
|
|
2020-10-30 14:00:02 +01:00
|
|
|
default:
|
|
|
|
//nothing happened
|
|
|
|
break;
|
|
|
|
}
|
2020-09-26 13:01:00 +02:00
|
|
|
|
2020-10-30 14:00:02 +01:00
|
|
|
singleton->loop2();
|
2020-09-26 13:01:00 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-10-30 14:00:02 +01:00
|
|
|
void EthernetInterface::loop2()
|
2020-09-26 13:01:00 +02:00
|
|
|
{
|
|
|
|
// get client from the server
|
2020-10-30 14:00:02 +01:00
|
|
|
EthernetClient client = server->accept();
|
2020-09-26 13:01:00 +02:00
|
|
|
|
|
|
|
// check for new client
|
|
|
|
if (client)
|
|
|
|
{
|
|
|
|
for (byte i = 0; i < MAX_SOCK_NUM; i++)
|
|
|
|
{
|
|
|
|
if (!clients[i])
|
|
|
|
{
|
|
|
|
// On accept() the EthernetServer doesn't track the client anymore
|
|
|
|
// so we store it in our client array
|
|
|
|
clients[i] = client;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// check for incoming data from all possible clients
|
2020-10-30 14:00:02 +01:00
|
|
|
for (byte socket = 0; socket < MAX_SOCK_NUM; socket++)
|
2020-09-26 13:01:00 +02:00
|
|
|
{
|
2020-10-30 14:00:02 +01:00
|
|
|
if (clients[socket]) {
|
|
|
|
|
|
|
|
// stop any clients which disconnect
|
|
|
|
if (!clients[socket].connected())
|
2020-09-26 13:01:00 +02:00
|
|
|
{
|
2020-10-30 14:00:02 +01:00
|
|
|
if (Diag::ETHERNET) DIAG(F("\nEthernet: disconnect %d \n"), socket);
|
|
|
|
clients[socket].stop();
|
|
|
|
clients[socket]=NULL;//????
|
2020-09-26 13:01:00 +02:00
|
|
|
}
|
2020-10-30 14:00:02 +01:00
|
|
|
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.
|
|
|
|
}
|
2020-09-26 13:01:00 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-30 14:00:02 +01:00
|
|
|
// 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
|
|
|
|
}
|
|
|
|
|
2020-09-26 13:01:00 +02:00
|
|
|
}
|
2020-10-30 14:00:02 +01:00
|
|
|
|