mirror of
https://github.com/DCC-EX/CommandStation-EX.git
synced 2024-11-30 03:26:13 +01:00
Apparently working Nucleo
This commit is contained in:
parent
5a2b008367
commit
9cdabb0acf
|
@ -97,7 +97,7 @@ void CommandDistributor::parse(byte clientId,byte * buffer, RingStream * stream
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandDistributor::forget(byte clientId) {
|
void CommandDistributor::forget(byte clientId) {
|
||||||
// keep for later if (clients[clientId]==WITHROTTLE_TYPE) WiThrottle::forget(clientId);
|
if (clients[clientId]==WITHROTTLE_TYPE) WiThrottle::forget(clientId);
|
||||||
clients[clientId]=NONE_TYPE;
|
clients[clientId]=NONE_TYPE;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -124,52 +124,69 @@ void setup()
|
||||||
#endif
|
#endif
|
||||||
LCD(3, F("Ready"));
|
LCD(3, F("Ready"));
|
||||||
CommandDistributor::broadcastPower();
|
CommandDistributor::broadcastPower();
|
||||||
|
Diag::WIFI=true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop()
|
void loop()
|
||||||
{
|
{
|
||||||
|
static bool XX=true;
|
||||||
|
if (XX) DIAG(F("loop 1"));
|
||||||
// The main sketch has responsibilities during loop()
|
// The main sketch has responsibilities during loop()
|
||||||
|
|
||||||
// Responsibility 1: Handle DCC background processes
|
// Responsibility 1: Handle DCC background processes
|
||||||
// (loco reminders and power checks)
|
// (loco reminders and power checks)
|
||||||
DCC::loop();
|
DCC::loop();
|
||||||
|
if (XX) DIAG(F("loop 2"));
|
||||||
// Responsibility 2: handle any incoming commands on USB connection
|
// Responsibility 2: handle any incoming commands on USB connection
|
||||||
SerialManager::loop();
|
SerialManager::loop();
|
||||||
|
if (XX) DIAG(F("loop 3"));
|
||||||
// Responsibility 3: Optionally handle any incoming WiFi traffic
|
// Responsibility 3: Optionally handle any incoming WiFi traffic
|
||||||
#ifndef ARDUINO_ARCH_ESP32
|
#ifndef ARDUINO_ARCH_ESP32
|
||||||
#if WIFI_ON
|
#if WIFI_ON
|
||||||
|
if (XX) DIAG(F("loop 4"));
|
||||||
WifiInterface::loop();
|
WifiInterface::loop();
|
||||||
#endif //WIFI_ON
|
#endif //WIFI_ON
|
||||||
#else //ARDUINO_ARCH_ESP32
|
#else //ARDUINO_ARCH_ESP32
|
||||||
#ifndef WIFI_TASK_ON_CORE0
|
#ifndef WIFI_TASK_ON_CORE0
|
||||||
|
if (XX) DIAG(F("loop 5"));
|
||||||
WifiESP::loop();
|
WifiESP::loop();
|
||||||
#endif
|
#endif
|
||||||
#endif //ARDUINO_ARCH_ESP32
|
#endif //ARDUINO_ARCH_ESP32
|
||||||
#if ETHERNET_ON
|
#if ETHERNET_ON
|
||||||
|
if (XX) DIAG(F("loop 6"));
|
||||||
EthernetInterface::loop();
|
EthernetInterface::loop();
|
||||||
#endif
|
#endif
|
||||||
|
if (XX) DIAG(F("loop 7"));
|
||||||
|
|
||||||
RMFT::loop(); // ignored if no automation
|
RMFT::loop(); // ignored if no automation
|
||||||
|
if (XX) DIAG(F("loop 8"));
|
||||||
|
|
||||||
#if defined(LCN_SERIAL)
|
#if defined(LCN_SERIAL)
|
||||||
LCN::loop();
|
LCN::loop();
|
||||||
|
if (XX) DIAG(F("loop 9"));
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
LCDDisplay::loop(); // ignored if LCD not in use
|
LCDDisplay::loop(); // ignored if LCD not in use
|
||||||
|
if (XX) DIAG(F("loop A"));
|
||||||
|
|
||||||
// Handle/update IO devices.
|
// Handle/update IO devices.
|
||||||
IODevice::loop();
|
IODevice::loop();
|
||||||
|
if (XX) DIAG(F("loop B"));
|
||||||
|
|
||||||
Sensor::checkAll(); // Update and print changes
|
Sensor::checkAll(); // Update and print changes
|
||||||
|
if (XX) DIAG(F("loop C"));
|
||||||
|
|
||||||
// Report any decrease in memory (will automatically trigger on first call)
|
// Report any decrease in memory (will automatically trigger on first call)
|
||||||
static int ramLowWatermark = __INT_MAX__; // replaced on first loop
|
static int ramLowWatermark = __INT_MAX__; // replaced on first loop
|
||||||
|
|
||||||
int freeNow = DCCTimer::getMinimumFreeMemory();
|
int freeNow = DCCTimer::getMinimumFreeMemory();
|
||||||
|
if (XX) DIAG(F("loop D"));
|
||||||
|
|
||||||
if (freeNow < ramLowWatermark) {
|
if (freeNow < ramLowWatermark) {
|
||||||
ramLowWatermark = freeNow;
|
ramLowWatermark = freeNow;
|
||||||
LCD(3,F("Free RAM=%5db"), ramLowWatermark);
|
LCD(3,F("Free RAM=%5db"), ramLowWatermark);
|
||||||
}
|
}
|
||||||
|
if (XX) DIAG(F("loop E"));
|
||||||
|
XX=false;
|
||||||
}
|
}
|
||||||
|
|
28
EXRAIL2.cpp
28
EXRAIL2.cpp
|
@ -95,23 +95,6 @@ LookList * RMFT2::onGreenLookup=NULL;
|
||||||
#define GET_OPCODE GETHIGHFLASH(RMFT2::RouteCode,progCounter)
|
#define GET_OPCODE GETHIGHFLASH(RMFT2::RouteCode,progCounter)
|
||||||
#define SKIPOP progCounter+=3
|
#define SKIPOP progCounter+=3
|
||||||
|
|
||||||
// RouteCodeFar is a far pointer to flash on anything other than a uno/nano where it is just a near pointer to flash
|
|
||||||
uint32_t RMFT2::RouteCodeFar;
|
|
||||||
|
|
||||||
uint16_t RMFT2::getOperand2(uint32_t farAddr) {
|
|
||||||
#if defined(ARDUINO_AVR_MEGA) || defined(ARDUINO_AVR_MEGA2560)
|
|
||||||
// AVR_MEGA memory uses far pointers
|
|
||||||
return pgm_read_word_far(farAddr);
|
|
||||||
#elif defined(ARDUINO_ARCH_AVR)
|
|
||||||
// UNO/NANO have no far memory
|
|
||||||
return pgm_read_word_near(farAddr);
|
|
||||||
#else
|
|
||||||
// other cpus dont care but may be averse to reading an int16_tr at an odd byte boundary.
|
|
||||||
const byte * op=(const byte *)farAddr;
|
|
||||||
return *op | (*(op+1) << 8);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// getOperand instance version, uses progCounter from instance.
|
// getOperand instance version, uses progCounter from instance.
|
||||||
uint16_t RMFT2::getOperand(byte n) {
|
uint16_t RMFT2::getOperand(byte n) {
|
||||||
return getOperand(progCounter,n);
|
return getOperand(progCounter,n);
|
||||||
|
@ -119,7 +102,13 @@ uint16_t RMFT2::getOperand(byte n) {
|
||||||
|
|
||||||
// getOperand static version, must be provided prog counter from loop etc.
|
// getOperand static version, must be provided prog counter from loop etc.
|
||||||
uint16_t RMFT2::getOperand(int progCounter,byte n) {
|
uint16_t RMFT2::getOperand(int progCounter,byte n) {
|
||||||
return getOperand2(RouteCodeFar+progCounter+1+(n*3));
|
int offset=progCounter+1+(n*3);
|
||||||
|
if (offset&1) {
|
||||||
|
byte lsb=GETHIGHFLASH(RouteCode,offset);
|
||||||
|
byte msb=GETHIGHFLASH(RouteCode,offset+1);
|
||||||
|
return msb<<8|lsb;
|
||||||
|
}
|
||||||
|
return GETHIGHFLASHW(RouteCode,offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
LookList::LookList(int16_t size) {
|
LookList::LookList(int16_t size) {
|
||||||
|
@ -168,8 +157,7 @@ LookList* RMFT2::LookListLoader(OPCODE op1, OPCODE op2, OPCODE op3) {
|
||||||
|
|
||||||
/* static */ void RMFT2::begin() {
|
/* static */ void RMFT2::begin() {
|
||||||
|
|
||||||
RouteCodeFar=GETFARPTR(RMFT2::RouteCode);
|
DIAG(F("EXRAIL RoutCode at =%P"),RouteCode);
|
||||||
DIAG(F("EXRAIL RouteAddr=%l"),RouteCodeFar);
|
|
||||||
|
|
||||||
bool saved_diag=diag;
|
bool saved_diag=diag;
|
||||||
diag=true;
|
diag=true;
|
||||||
|
|
|
@ -143,7 +143,6 @@ private:
|
||||||
OPCODE op2=OPCODE_ENDEXRAIL,OPCODE op3=OPCODE_ENDEXRAIL);
|
OPCODE op2=OPCODE_ENDEXRAIL,OPCODE op3=OPCODE_ENDEXRAIL);
|
||||||
static void handleEvent(const FSH* reason,LookList* handlers, int16_t id);
|
static void handleEvent(const FSH* reason,LookList* handlers, int16_t id);
|
||||||
static uint16_t getOperand(int progCounter,byte n);
|
static uint16_t getOperand(int progCounter,byte n);
|
||||||
static uint16_t getOperand2(uint32_t farAddr);
|
|
||||||
static RMFT2 * loopTask;
|
static RMFT2 * loopTask;
|
||||||
static RMFT2 * pausingTask;
|
static RMFT2 * pausingTask;
|
||||||
void delayMe(long millisecs);
|
void delayMe(long millisecs);
|
||||||
|
@ -170,8 +169,6 @@ private:
|
||||||
static LookList * onRedLookup;
|
static LookList * onRedLookup;
|
||||||
static LookList * onAmberLookup;
|
static LookList * onAmberLookup;
|
||||||
static LookList * onGreenLookup;
|
static LookList * onGreenLookup;
|
||||||
// RouteCodeFar is a far pointer to RouteCode flash on anything other than a uno/nano where it is just a near pointer to flash
|
|
||||||
static uint32_t RouteCodeFar;
|
|
||||||
|
|
||||||
// Local variables - exist for each instance/task
|
// Local variables - exist for each instance/task
|
||||||
RMFT2 *next; // loop chain
|
RMFT2 *next; // loop chain
|
||||||
|
|
|
@ -65,6 +65,13 @@ int RingStream::availableForWrite() {
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t RingStream::printFlash(const FSH * flashBuffer) {
|
size_t RingStream::printFlash(const FSH * flashBuffer) {
|
||||||
|
// This function does not work on a 32 bit processor where the runtime
|
||||||
|
// sometimes misrepresents the pointer size in uintptr_t.
|
||||||
|
// In any case its not really necessary in a 32 bit processor because
|
||||||
|
// we have adequate ram.
|
||||||
|
if (sizeof(void*)>2) return print(flashBuffer);
|
||||||
|
|
||||||
|
|
||||||
// We are about to add a PROGMEM string to the buffer.
|
// We are about to add a PROGMEM string to the buffer.
|
||||||
// To save RAM we can insert a marker and the
|
// To save RAM we can insert a marker and the
|
||||||
// progmem address into the buffer instead.
|
// progmem address into the buffer instead.
|
||||||
|
@ -107,8 +114,11 @@ int RingStream::read() {
|
||||||
if ((_pos_read==_pos_write) && !_overflow) return -1; // empty
|
if ((_pos_read==_pos_write) && !_overflow) return -1; // empty
|
||||||
byte b=readRawByte();
|
byte b=readRawByte();
|
||||||
if (b!=FLASH_INSERT_MARKER) return b;
|
if (b!=FLASH_INSERT_MARKER) return b;
|
||||||
#ifndef ARDUINO_ARCH_ESP32
|
|
||||||
// Detected a flash insert
|
// Detected a flash insert
|
||||||
|
if (sizeof(void*)>2) {
|
||||||
|
DIAG(F("Detected invalid flash insert marker at pos %d"),_pos_read);
|
||||||
|
return '?';
|
||||||
|
}
|
||||||
// read address bytes LSB first (size depends on CPU)
|
// read address bytes LSB first (size depends on CPU)
|
||||||
uintptr_t iFlash=0;
|
uintptr_t iFlash=0;
|
||||||
for (byte f=0; f<sizeof(iFlash); f++) {
|
for (byte f=0; f<sizeof(iFlash); f++) {
|
||||||
|
@ -120,10 +130,6 @@ int RingStream::read() {
|
||||||
_flashInsert=reinterpret_cast<char * >( iFlash);
|
_flashInsert=reinterpret_cast<char * >( iFlash);
|
||||||
// and try again... so will read the first byte of the insert.
|
// and try again... so will read the first byte of the insert.
|
||||||
return read();
|
return read();
|
||||||
#else
|
|
||||||
DIAG(F("Detected flash insert marker at pos %d but there should not be one"),_pos_read);
|
|
||||||
return '\0';
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
byte RingStream::readRawByte() {
|
byte RingStream::readRawByte() {
|
||||||
|
|
|
@ -27,7 +27,7 @@ class RingStream : public Print {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
RingStream( const uint16_t len);
|
RingStream( const uint16_t len);
|
||||||
static const int THIS_IS_A_RINGSTREAM=77;
|
static const int THIS_IS_A_RINGSTREAM=777;
|
||||||
virtual size_t write(uint8_t b);
|
virtual size_t write(uint8_t b);
|
||||||
|
|
||||||
// This availableForWrite function is subverted from its original intention so that a caller
|
// This availableForWrite function is subverted from its original intention so that a caller
|
||||||
|
|
|
@ -102,7 +102,9 @@ void SerialManager::loop() {
|
||||||
|
|
||||||
void SerialManager::loop2() {
|
void SerialManager::loop2() {
|
||||||
while (serial->available()) {
|
while (serial->available()) {
|
||||||
char ch = serial->read();
|
int intch=serial->read();
|
||||||
|
if (intch<0) break;
|
||||||
|
char ch = (char)intch;
|
||||||
if (ch == '<') {
|
if (ch == '<') {
|
||||||
inCommandPayload = true;
|
inCommandPayload = true;
|
||||||
bufferLength = 0;
|
bufferLength = 0;
|
||||||
|
|
|
@ -91,9 +91,6 @@ void StringFormatter::send2(Print * stream,const FSH* format, va_list args) {
|
||||||
{
|
{
|
||||||
const FSH* flash= (const FSH*)va_arg(args, char*);
|
const FSH* flash= (const FSH*)va_arg(args, char*);
|
||||||
|
|
||||||
#ifndef ARDUINO_ARCH_ESP32
|
|
||||||
// On ESP32 the reading flashstring from rinstream code
|
|
||||||
// crashes, so don't use the flashstream hack on ESP32
|
|
||||||
#if WIFI_ON | ETHERNET_ON
|
#if WIFI_ON | ETHERNET_ON
|
||||||
// RingStream has special logic to handle flash strings
|
// RingStream has special logic to handle flash strings
|
||||||
// but is not implemented unless wifi or ethernet are enabled.
|
// but is not implemented unless wifi or ethernet are enabled.
|
||||||
|
@ -101,11 +98,11 @@ void StringFormatter::send2(Print * stream,const FSH* format, va_list args) {
|
||||||
if (stream->availableForWrite()==RingStream::THIS_IS_A_RINGSTREAM)
|
if (stream->availableForWrite()==RingStream::THIS_IS_A_RINGSTREAM)
|
||||||
((RingStream *)stream)->printFlash(flash);
|
((RingStream *)stream)->printFlash(flash);
|
||||||
else
|
else
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
stream->print(flash);
|
stream->print(flash);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 'P': stream->print((uint32_t)va_arg(args, void*), HEX); break;
|
||||||
case 'd': printPadded(stream,va_arg(args, int), formatWidth, formatLeft); break;
|
case 'd': printPadded(stream,va_arg(args, int), formatWidth, formatLeft); break;
|
||||||
case 'u': printPadded(stream,va_arg(args, unsigned int), formatWidth, formatLeft); break;
|
case 'u': printPadded(stream,va_arg(args, unsigned int), formatWidth, formatLeft); break;
|
||||||
case 'l': printPadded(stream,va_arg(args, long), formatWidth, formatLeft); break;
|
case 'l': printPadded(stream,va_arg(args, long), formatWidth, formatLeft); break;
|
||||||
|
@ -169,7 +166,7 @@ void StringFormatter::printEscape(Print * stream, char c) {
|
||||||
case '\0': stream->print(F("\\0")); return;
|
case '\0': stream->print(F("\\0")); return;
|
||||||
case '\t': stream->print(F("\\t")); break;
|
case '\t': stream->print(F("\\t")); break;
|
||||||
case '\\': stream->print(F("\\\\")); break;
|
case '\\': stream->print(F("\\\\")); break;
|
||||||
default: stream->print(c);
|
default: stream->write(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
319
WiThrottle.cpp
319
WiThrottle.cpp
|
@ -63,69 +63,6 @@
|
||||||
|
|
||||||
WiThrottle * WiThrottle::firstThrottle=NULL;
|
WiThrottle * WiThrottle::firstThrottle=NULL;
|
||||||
|
|
||||||
static uint8_t xstrncmp(const char *s1, const char *s2, uint8_t n) {
|
|
||||||
if (n == 0)
|
|
||||||
return 0;
|
|
||||||
do {
|
|
||||||
if (*s1 != *s2++)
|
|
||||||
return 1;
|
|
||||||
if (*s1++ == 0)
|
|
||||||
break;
|
|
||||||
} while (--n != 0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WiThrottle::findUniqThrottle(int id, char *u) {
|
|
||||||
WiThrottle *wtmyid = NULL;
|
|
||||||
WiThrottle *wtmyuniq = NULL;
|
|
||||||
|
|
||||||
// search 1, look for clientid match
|
|
||||||
for (WiThrottle* wt=firstThrottle; wt!=NULL ; wt=wt->nextThrottle){
|
|
||||||
if (wt->clientid == id) {
|
|
||||||
if (xstrncmp(u, wt->uniq, 16) == 0) // should be most common case
|
|
||||||
return;
|
|
||||||
wtmyid = wt;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// search 2, look for string match
|
|
||||||
for (WiThrottle* wt=firstThrottle; wt!=NULL ; wt=wt->nextThrottle){
|
|
||||||
if (xstrncmp(u, wt->uniq, 16) == 0) {
|
|
||||||
wtmyuniq = wt;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// analyse result of the two for loops:
|
|
||||||
if (wtmyid == NULL) { // should not happen
|
|
||||||
DIAG(F("Did not find my own wiThrottle handle"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// wtmyuniq == wtmyid has already returned in for loop 1
|
|
||||||
if (wtmyuniq == NULL) { // register uniq in the found id
|
|
||||||
strncpy(wtmyid->uniq, u, 16);
|
|
||||||
wtmyid->uniq[16] = '\0';
|
|
||||||
if (Diag::WITHROTTLE) DIAG(F("Client %d registered as %s"),wtmyid->clientid, wtmyid->uniq);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// if we get here wtmyid and wtmyuniq point on objects but differnet ones
|
|
||||||
// so we need to do the copy (all other options covered above)
|
|
||||||
for(int n=0; n < MAX_MY_LOCO; n++)
|
|
||||||
wtmyid->myLocos[n] = wtmyuniq->myLocos[n];
|
|
||||||
wtmyid->heartBeatEnable = wtmyuniq->heartBeatEnable;
|
|
||||||
wtmyid->heartBeat = wtmyuniq->heartBeat;
|
|
||||||
wtmyid->initSent = wtmyuniq->initSent;
|
|
||||||
wtmyid->exRailSent = wtmyuniq->exRailSent;
|
|
||||||
wtmyid->mostRecentCab = wtmyuniq->mostRecentCab;
|
|
||||||
wtmyid->turnoutListHash = wtmyuniq->turnoutListHash;
|
|
||||||
wtmyid->lastPowerState = wtmyuniq->lastPowerState;
|
|
||||||
strncpy(wtmyid->uniq, u, 16);
|
|
||||||
wtmyid->uniq[16] = '\0';
|
|
||||||
if (Diag::WITHROTTLE)
|
|
||||||
DIAG(F("New client %d replaces old client %d as %s"), wtmyid->clientid, wtmyuniq->clientid, wtmyid->uniq);
|
|
||||||
forget(wtmyuniq->clientid); // do not use wtmyid after this
|
|
||||||
}
|
|
||||||
|
|
||||||
WiThrottle* WiThrottle::getThrottle( int wifiClient) {
|
WiThrottle* WiThrottle::getThrottle( int wifiClient) {
|
||||||
for (WiThrottle* wt=firstThrottle; wt!=NULL ; wt=wt->nextThrottle)
|
for (WiThrottle* wt=firstThrottle; wt!=NULL ; wt=wt->nextThrottle)
|
||||||
if (wt->clientid==wifiClient) return wt;
|
if (wt->clientid==wifiClient) return wt;
|
||||||
|
@ -135,6 +72,7 @@ WiThrottle* WiThrottle::getThrottle( int wifiClient) {
|
||||||
void WiThrottle::forget( byte clientId) {
|
void WiThrottle::forget( byte clientId) {
|
||||||
for (WiThrottle* wt=firstThrottle; wt!=NULL ; wt=wt->nextThrottle)
|
for (WiThrottle* wt=firstThrottle; wt!=NULL ; wt=wt->nextThrottle)
|
||||||
if (wt->clientid==clientId) {
|
if (wt->clientid==clientId) {
|
||||||
|
DIAG(F("Withrottle client %d dropped"),clientId);
|
||||||
delete wt;
|
delete wt;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -159,10 +97,7 @@ WiThrottle::WiThrottle( int wificlientid) {
|
||||||
nextThrottle=firstThrottle;
|
nextThrottle=firstThrottle;
|
||||||
firstThrottle= this;
|
firstThrottle= this;
|
||||||
clientid=wificlientid;
|
clientid=wificlientid;
|
||||||
initSent=false; // prevent sending heartbeats before connection completed
|
|
||||||
heartBeatEnable=false; // until client turns it on
|
heartBeatEnable=false; // until client turns it on
|
||||||
turnoutListHash = -1; // make sure turnout list is sent once
|
|
||||||
exRailSent=false;
|
|
||||||
mostRecentCab=0;
|
mostRecentCab=0;
|
||||||
for (int loco=0;loco<MAX_MY_LOCO; loco++) myLocos[loco].throttle='\0';
|
for (int loco=0;loco<MAX_MY_LOCO; loco++) myLocos[loco].throttle='\0';
|
||||||
}
|
}
|
||||||
|
@ -188,53 +123,18 @@ void WiThrottle::parse(RingStream * stream, byte * cmdx) {
|
||||||
heartBeat=millis();
|
heartBeat=millis();
|
||||||
if (Diag::WITHROTTLE) DIAG(F("%l WiThrottle(%d)<-[%e]"),millis(),clientid,cmd);
|
if (Diag::WITHROTTLE) DIAG(F("%l WiThrottle(%d)<-[%e]"),millis(),clientid,cmd);
|
||||||
|
|
||||||
if (initSent) {
|
// On first few commands, send turnout, roster and routes
|
||||||
// Send turnout list if changed since last sent (will replace list on client)
|
|
||||||
if (turnoutListHash != Turnout::turnoutlistHash) {
|
|
||||||
StringFormatter::send(stream,F("PTL"));
|
|
||||||
for(Turnout *tt=Turnout::first();tt!=NULL;tt=tt->next()){
|
|
||||||
if (tt->isHidden()) continue;
|
|
||||||
int id=tt->getId();
|
|
||||||
const FSH * tdesc=NULL;
|
|
||||||
#ifdef EXRAIL_ACTIVE
|
|
||||||
tdesc=RMFT2::getTurnoutDescription(id);
|
|
||||||
#endif
|
|
||||||
char tchar=Turnout::isClosed(id)?'2':'4';
|
|
||||||
if (tdesc==NULL) // turnout with no description
|
|
||||||
StringFormatter::send(stream,F("]\\[%d}|{T%d}|{T%c"), id,id,tchar);
|
|
||||||
else
|
|
||||||
StringFormatter::send(stream,F("]\\[%d}|{%S}|{%c"), id,tdesc,tchar);
|
|
||||||
}
|
|
||||||
StringFormatter::send(stream,F("\n"));
|
|
||||||
turnoutListHash = Turnout::turnoutlistHash; // keep a copy of hash for later comparison
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (!exRailSent) {
|
if (!turnoutsSent) sendTurnouts(stream);
|
||||||
// Send EX-RAIL routes list if not already sent (but not at same time as turnouts above)
|
else if(!rosterSent) sendRoster(stream);
|
||||||
exRailSent=true;
|
else if (!routesSent) sendRoutes(stream);
|
||||||
#ifdef EXRAIL_ACTIVE
|
else if (!heartrateSent) {
|
||||||
StringFormatter::send(stream,F("PRT]\\[Routes}|{Route]\\[Set}|{2]\\[Handoff}|{4\nPRL"));
|
heartrateSent=true;
|
||||||
// first pass automations
|
|
||||||
for (int ix=0;;ix+=2) {
|
|
||||||
int16_t id =GETHIGHFLASHW(RMFT2::automationIdList,ix);
|
|
||||||
if (id==0) break;
|
|
||||||
const FSH * desc=RMFT2::getRouteDescription(id);
|
|
||||||
StringFormatter::send(stream,F("]\\[A%d}|{%S}|{4"),id,desc);
|
|
||||||
}
|
|
||||||
// second pass routes.
|
|
||||||
for (int ix=0;;ix+=2) {
|
|
||||||
int16_t id=GETHIGHFLASHW(RMFT2::routeIdList,ix);
|
|
||||||
if (id==0) break;
|
|
||||||
const FSH * desc=RMFT2::getRouteDescription(id);
|
|
||||||
StringFormatter::send(stream,F("]\\[R%d}|{%S}|{2"),id,desc);
|
|
||||||
}
|
|
||||||
StringFormatter::send(stream,F("\n"));
|
|
||||||
#endif
|
|
||||||
// allow heartbeat to slow down once all metadata sent
|
// allow heartbeat to slow down once all metadata sent
|
||||||
StringFormatter::send(stream,F("*%d\n"),HEARTBEAT_SECONDS);
|
StringFormatter::send(stream,F("*%d\n"),HEARTBEAT_SECONDS);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
while (cmd[0]) {
|
while (cmd[0]) {
|
||||||
switch (cmd[0]) {
|
switch (cmd[0]) {
|
||||||
case '*': // heartbeat control
|
case '*': // heartbeat control
|
||||||
|
@ -287,32 +187,20 @@ void WiThrottle::parse(RingStream * stream, byte * cmdx) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'N': // Heartbeat (2), only send if connection completed by 'HU' message
|
case 'N': // Heartbeat (2), only send if connection completed by 'HU' message
|
||||||
StringFormatter::send(stream, F("*%d\n"), initSent ? HEARTBEAT_SECONDS : HEARTBEAT_SECONDS/2); // return timeout value
|
StringFormatter::send(stream, F("*%d\n"), heartrateSent ? HEARTBEAT_SECONDS : HEARTBEAT_SECONDS/2); // return timeout value
|
||||||
break;
|
break;
|
||||||
case 'M': // multithrottle
|
case 'M': // multithrottle
|
||||||
multithrottle(stream, cmd);
|
multithrottle(stream, cmd);
|
||||||
break;
|
break;
|
||||||
case 'H': // send initial connection info after receiving "HU" message
|
case 'H': // send initial connection info after receiving "HU" message
|
||||||
if (cmd[1] == 'U') {
|
if (cmd[1] == 'U') {
|
||||||
WiThrottle::findUniqThrottle(clientid, (char *)cmd+2);
|
StringFormatter::send(stream,F("VN2.0\nHTDCC-EX\nRL0\n"));
|
||||||
StringFormatter::send(stream,F("VN2.0\nHTDCC-EX\nRL0\n"));
|
|
||||||
StringFormatter::send(stream,F("HtDCC-EX v%S, %S, %S, %S\n"), F(VERSION), F(ARDUINO_TYPE), DCC::getMotorShieldName(), F(GITHUB_SHA));
|
StringFormatter::send(stream,F("HtDCC-EX v%S, %S, %S, %S\n"), F(VERSION), F(ARDUINO_TYPE), DCC::getMotorShieldName(), F(GITHUB_SHA));
|
||||||
StringFormatter::send(stream,F("PTT]\\[Turnouts}|{Turnout]\\[THROW}|{2]\\[CLOSE}|{4\n"));
|
StringFormatter::send(stream,F("PTT]\\[Turnouts}|{Turnout]\\[THROW}|{2]\\[CLOSE}|{4\n"));
|
||||||
StringFormatter::send(stream,F("PPA%x\n"),TrackManager::getMainPower()==POWERMODE::ON);
|
StringFormatter::send(stream,F("PPA%x\n"),TrackManager::getMainPower()==POWERMODE::ON);
|
||||||
#ifdef EXRAIL_ACTIVE
|
|
||||||
StringFormatter::send(stream,F("RL%d"), RMFT2::rosterNameCount);
|
|
||||||
for (int16_t r=0;r<RMFT2::rosterNameCount;r++) {
|
|
||||||
int16_t cabid=GETHIGHFLASHW(RMFT2::rosterIdList,r*2);
|
|
||||||
StringFormatter::send(stream,F("]\\[%S}|{%d}|{%c"),
|
|
||||||
RMFT2::getRosterName(cabid),cabid,cabid<128?'S':'L');
|
|
||||||
}
|
|
||||||
stream->write('\n'); // end roster
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
// set heartbeat to 5 seconds because we need to sync the metadata (1 second is too short!)
|
// set heartbeat to 5 seconds because we need to sync the metadata (1 second is too short!)
|
||||||
StringFormatter::send(stream,F("*%d\n"), HEARTBEAT_SECONDS/2);
|
StringFormatter::send(stream,F("*%d\n"), HEARTBEAT_SECONDS/2);
|
||||||
initSent = true;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'Q': //
|
case 'Q': //
|
||||||
|
@ -321,7 +209,7 @@ void WiThrottle::parse(RingStream * stream, byte * cmdx) {
|
||||||
StringFormatter::send(stream, F("M%c-%c%d<;>\n"), myLocos[loco].throttle, LorS(myLocos[loco].cab), myLocos[loco].cab);
|
StringFormatter::send(stream, F("M%c-%c%d<;>\n"), myLocos[loco].throttle, LorS(myLocos[loco].cab), myLocos[loco].cab);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (Diag::WITHROTTLE) DIAG(F("%l WiThrottle(%d) Quit"),millis(),clientid);
|
if (Diag::WITHROTTLE) DIAG(F("WiThrottle(%d) Quit"),clientid);
|
||||||
delete this;
|
delete this;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -382,65 +270,17 @@ void WiThrottle::multithrottle(RingStream * stream, byte * cmd){
|
||||||
}
|
}
|
||||||
//use first empty "slot" on this client's list, will be added to DCC registration list
|
//use first empty "slot" on this client's list, will be added to DCC registration list
|
||||||
for (int loco=0;loco<MAX_MY_LOCO;loco++) {
|
for (int loco=0;loco<MAX_MY_LOCO;loco++) {
|
||||||
if (myLocos[loco].throttle=='\0') {
|
if (myLocos[loco].throttle=='\0' || myLocos[loco].cab == locoid) {
|
||||||
myLocos[loco].throttle=throttleChar;
|
myLocos[loco].throttle=throttleChar;
|
||||||
myLocos[loco].cab=locoid;
|
myLocos[loco].cab=locoid;
|
||||||
myLocos[loco].functionMap=DCC::getFunctionMap(locoid);
|
myLocos[loco].functionMap=DCC::getFunctionMap(locoid);
|
||||||
myLocos[loco].broadcastPending=true; // means speed/dir will be sent later
|
myLocos[loco].broadcastPending=true; // means speed/dir will be sent later
|
||||||
mostRecentCab=locoid;
|
mostRecentCab=locoid;
|
||||||
StringFormatter::send(stream, F("M%c+%c%d<;>\n"), throttleChar, cmd[3] ,locoid); //tell client to add loco
|
StringFormatter::send(stream, F("M%c+%c%d<;>\n"), throttleChar, cmd[3] ,locoid); //tell client to add loco
|
||||||
int fkeys=29;
|
sendFunctions(stream,loco);
|
||||||
myLocos[loco].functionToggles=1<<2; // F2 (HORN) is a non-toggle
|
//speed and direction will be published at next broadcast cycle
|
||||||
|
StringFormatter::send(stream, F("M%cA%c%d<;>s1\n"), throttleChar, cmd[3], locoid); //default speed step 128
|
||||||
#ifdef EXRAIL_ACTIVE
|
return;
|
||||||
const char * functionNames=(char *) RMFT2::getRosterFunctions(locoid);
|
|
||||||
if (!functionNames) {
|
|
||||||
// no roster, use presets as above
|
|
||||||
}
|
|
||||||
else if (GETFLASH(functionNames)=='\0') {
|
|
||||||
// "" = Roster but no functions given
|
|
||||||
fkeys=0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// we have function names...
|
|
||||||
// scan names list emitting names, counting functions and
|
|
||||||
// flagging non-toggling things like horn.
|
|
||||||
myLocos[loco].functionToggles =0;
|
|
||||||
StringFormatter::send(stream, F("M%cL%c%d<;>]\\["), throttleChar,cmd[3],locoid);
|
|
||||||
fkeys=0;
|
|
||||||
bool firstchar=true;
|
|
||||||
for (int fx=0;;fx++) {
|
|
||||||
char c=GETFLASH(functionNames+fx);
|
|
||||||
if (c=='\0') {
|
|
||||||
fkeys++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (c=='/') {
|
|
||||||
fkeys++;
|
|
||||||
StringFormatter::send(stream,F("]\\["));
|
|
||||||
firstchar=true;
|
|
||||||
}
|
|
||||||
else if (firstchar && c=='*') {
|
|
||||||
myLocos[loco].functionToggles |= 1UL<<fkeys;
|
|
||||||
firstchar=false;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
firstchar=false;
|
|
||||||
stream->write(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
StringFormatter::send(stream,F("\n"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for(int fKey=0; fKey<fkeys; fKey++) {
|
|
||||||
int fstate=DCC::getFn(locoid,fKey);
|
|
||||||
if (fstate>=0) StringFormatter::send(stream,F("M%cA%c%d<;>F%d%d\n"),throttleChar,cmd[3],locoid,fstate,fKey);
|
|
||||||
}
|
|
||||||
//speed and direction will be published at next broadcast cycle
|
|
||||||
StringFormatter::send(stream, F("M%cA%c%d<;>s1\n"), throttleChar, cmd[3], locoid); //default speed step 128
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StringFormatter::send(stream, F("HMMax locos (%d) exceeded, %d not added!\n"), MAX_MY_LOCO ,locoid);
|
StringFormatter::send(stream, F("HMMax locos (%d) exceeded, %d not added!\n"), MAX_MY_LOCO ,locoid);
|
||||||
|
@ -544,8 +384,6 @@ void WiThrottle::loop(RingStream * stream) {
|
||||||
// for each WiThrottle, check the heartbeat and broadcast needed
|
// for each WiThrottle, check the heartbeat and broadcast needed
|
||||||
for (WiThrottle* wt=firstThrottle; wt!=NULL ; wt=wt->nextThrottle)
|
for (WiThrottle* wt=firstThrottle; wt!=NULL ; wt=wt->nextThrottle)
|
||||||
wt->checkHeartbeat(stream);
|
wt->checkHeartbeat(stream);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WiThrottle::checkHeartbeat(RingStream * stream) {
|
void WiThrottle::checkHeartbeat(RingStream * stream) {
|
||||||
|
@ -559,8 +397,8 @@ void WiThrottle::checkHeartbeat(RingStream * stream) {
|
||||||
heartBeat=millis(); // We have just stopped everyting, we don't need to do that again at next loop.
|
heartBeat=millis(); // We have just stopped everyting, we don't need to do that again at next loop.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//haba no, not necessary the only throttle and it may come back
|
// if it does come back, the throttle should re-acquire
|
||||||
//delete this;
|
delete this;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -660,5 +498,110 @@ void WiThrottle::getLocoCallback(int16_t locoid) {
|
||||||
DIAG(F("LocoCallback commit success"));
|
DIAG(F("LocoCallback commit success"));
|
||||||
stashStream->commit();
|
stashStream->commit();
|
||||||
CommandDistributor::broadcastPower();
|
CommandDistributor::broadcastPower();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WiThrottle::sendTurnouts(Print* stream) {
|
||||||
|
turnoutsSent=true;
|
||||||
|
StringFormatter::send(stream,F("PTL"));
|
||||||
|
for(Turnout *tt=Turnout::first();tt!=NULL;tt=tt->next()){
|
||||||
|
if (tt->isHidden()) continue;
|
||||||
|
int id=tt->getId();
|
||||||
|
const FSH * tdesc=NULL;
|
||||||
|
#ifdef EXRAIL_ACTIVE
|
||||||
|
tdesc=RMFT2::getTurnoutDescription(id);
|
||||||
|
#endif
|
||||||
|
char tchar=Turnout::isClosed(id)?'2':'4';
|
||||||
|
if (tdesc==NULL) // turnout with no description
|
||||||
|
StringFormatter::send(stream,F("]\\[%d}|{T%d}|{T%c"), id,id,tchar);
|
||||||
|
else
|
||||||
|
StringFormatter::send(stream,F("]\\[%d}|{%S}|{%c"), id,tdesc,tchar);
|
||||||
|
}
|
||||||
|
StringFormatter::send(stream,F("\n"));
|
||||||
|
}
|
||||||
|
void WiThrottle::sendRoster(Print* stream) {
|
||||||
|
rosterSent=true;
|
||||||
|
#ifdef EXRAIL_ACTIVE
|
||||||
|
StringFormatter::send(stream,F("RL%d"), RMFT2::rosterNameCount);
|
||||||
|
for (int16_t r=0;r<RMFT2::rosterNameCount;r++) {
|
||||||
|
int16_t cabid=GETHIGHFLASHW(RMFT2::rosterIdList,r*2);
|
||||||
|
StringFormatter::send(stream,F("]\\[%S}|{%d}|{%c"),
|
||||||
|
RMFT2::getRosterName(cabid),cabid,cabid<128?'S':'L');
|
||||||
|
}
|
||||||
|
StringFormatter::send(stream,F("\n"));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
void WiThrottle::sendRoutes(Print* stream) {
|
||||||
|
routesSent=true;
|
||||||
|
#ifdef EXRAIL_ACTIVE
|
||||||
|
StringFormatter::send(stream,F("PRT]\\[Routes}|{Route]\\[Set}|{2]\\[Handoff}|{4\nPRL"));
|
||||||
|
// first pass automations
|
||||||
|
for (int ix=0;;ix+=2) {
|
||||||
|
int16_t id =GETHIGHFLASHW(RMFT2::automationIdList,ix);
|
||||||
|
if (id==0) break;
|
||||||
|
const FSH * desc=RMFT2::getRouteDescription(id);
|
||||||
|
StringFormatter::send(stream,F("]\\[A%d}|{%S}|{4"),id,desc);
|
||||||
|
}
|
||||||
|
// second pass routes.
|
||||||
|
for (int ix=0;;ix+=2) {
|
||||||
|
int16_t id=GETHIGHFLASHW(RMFT2::routeIdList,ix);
|
||||||
|
if (id==0) break;
|
||||||
|
const FSH * desc=RMFT2::getRouteDescription(id);
|
||||||
|
StringFormatter::send(stream,F("]\\[R%d}|{%S}|{2"),id,desc);
|
||||||
|
}
|
||||||
|
StringFormatter::send(stream,F("\n"));
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void WiThrottle::sendFunctions(Print* stream, byte loco) {
|
||||||
|
int16_t locoid=myLocos[loco].cab;
|
||||||
|
int fkeys=29;
|
||||||
|
myLocos[loco].functionToggles=1<<2; // F2 (HORN) is a non-toggle
|
||||||
|
|
||||||
|
#ifdef EXRAIL_ACTIVE
|
||||||
|
const char * functionNames=(char *) RMFT2::getRosterFunctions(locoid);
|
||||||
|
if (!functionNames) {
|
||||||
|
// no roster, use non-exrail presets as above
|
||||||
|
}
|
||||||
|
else if (GETFLASH(functionNames)=='\0') {
|
||||||
|
// "" = Roster but no functions given
|
||||||
|
fkeys=0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// we have function names...
|
||||||
|
// scan names list emitting names, counting functions and
|
||||||
|
// flagging non-toggling things like horn.
|
||||||
|
myLocos[loco].functionToggles =0;
|
||||||
|
StringFormatter::send(stream, F("M%cL%c%d<;>]\\["), myLocos[loco].throttle,LorS(locoid),locoid);
|
||||||
|
fkeys=0;
|
||||||
|
bool firstchar=true;
|
||||||
|
for (int fx=0;;fx++) {
|
||||||
|
char c=GETFLASH(functionNames+fx);
|
||||||
|
if (c=='\0') {
|
||||||
|
fkeys++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (c=='/') {
|
||||||
|
fkeys++;
|
||||||
|
StringFormatter::send(stream,F("]\\["));
|
||||||
|
firstchar=true;
|
||||||
|
}
|
||||||
|
else if (firstchar && c=='*') {
|
||||||
|
myLocos[loco].functionToggles |= 1UL<<fkeys;
|
||||||
|
firstchar=false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
firstchar=false;
|
||||||
|
stream->write(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
StringFormatter::send(stream,F("\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for(int fKey=0; fKey<fkeys; fKey++) {
|
||||||
|
int fstate=DCC::getFn(locoid,fKey);
|
||||||
|
if (fstate>=0) StringFormatter::send(stream,F("M%cA%c%d<;>F%d%d\n"),myLocos[loco].throttle,LorS(locoid),locoid,fstate,fKey);
|
||||||
|
}
|
||||||
}
|
}
|
11
WiThrottle.h
11
WiThrottle.h
|
@ -61,10 +61,11 @@ class WiThrottle {
|
||||||
MYLOCO myLocos[MAX_MY_LOCO];
|
MYLOCO myLocos[MAX_MY_LOCO];
|
||||||
bool heartBeatEnable;
|
bool heartBeatEnable;
|
||||||
unsigned long heartBeat;
|
unsigned long heartBeat;
|
||||||
bool initSent; // valid connection established
|
bool turnoutsSent=false;
|
||||||
bool exRailSent; // valid connection established
|
bool rosterSent=false;
|
||||||
|
bool routesSent=false;
|
||||||
|
bool heartrateSent=false;
|
||||||
uint16_t mostRecentCab;
|
uint16_t mostRecentCab;
|
||||||
int turnoutListHash; // used to check for changes to turnout list
|
|
||||||
bool lastPowerState; // last power state sent to this client
|
bool lastPowerState; // last power state sent to this client
|
||||||
|
|
||||||
int DCCToWiTSpeed(int DCCSpeed);
|
int DCCToWiTSpeed(int DCCSpeed);
|
||||||
|
@ -74,6 +75,10 @@ class WiThrottle {
|
||||||
void accessory(RingStream *, byte* cmd);
|
void accessory(RingStream *, byte* cmd);
|
||||||
void checkHeartbeat(RingStream * stream);
|
void checkHeartbeat(RingStream * stream);
|
||||||
void markForBroadcast2(int cab);
|
void markForBroadcast2(int cab);
|
||||||
|
void sendTurnouts(Print * stream);
|
||||||
|
void sendRoster(Print * stream);
|
||||||
|
void sendRoutes(Print * stream);
|
||||||
|
void sendFunctions(Print* stream, byte loco);
|
||||||
// callback stuff to support prog track acquire
|
// callback stuff to support prog track acquire
|
||||||
static RingStream * stashStream;
|
static RingStream * stashStream;
|
||||||
static WiThrottle * stashInstance;
|
static WiThrottle * stashInstance;
|
||||||
|
|
|
@ -31,6 +31,7 @@ WifiInboundHandler * WifiInboundHandler::singleton;
|
||||||
|
|
||||||
void WifiInboundHandler::setup(Stream * ESStream) {
|
void WifiInboundHandler::setup(Stream * ESStream) {
|
||||||
singleton=new WifiInboundHandler(ESStream);
|
singleton=new WifiInboundHandler(ESStream);
|
||||||
|
// DIAG(F("WifiInbound Setup2 %P %P"), ESStream,singleton);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WifiInboundHandler::loop() {
|
void WifiInboundHandler::loop() {
|
||||||
|
@ -44,6 +45,7 @@ WifiInboundHandler::WifiInboundHandler(Stream * ESStream) {
|
||||||
inboundRing=new RingStream(INBOUND_RING);
|
inboundRing=new RingStream(INBOUND_RING);
|
||||||
outboundRing=new RingStream(OUTBOUND_RING);
|
outboundRing=new RingStream(OUTBOUND_RING);
|
||||||
pendingCipsend=false;
|
pendingCipsend=false;
|
||||||
|
// DIAG(F("WifiInbound setup1 %P"), wifiStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -51,11 +53,19 @@ WifiInboundHandler::WifiInboundHandler(Stream * ESStream) {
|
||||||
// +IPD,x,lll:data is stored in streamer[x]
|
// +IPD,x,lll:data is stored in streamer[x]
|
||||||
// Other input returns
|
// Other input returns
|
||||||
void WifiInboundHandler::loop1() {
|
void WifiInboundHandler::loop1() {
|
||||||
|
static bool XX=true;
|
||||||
|
if (XX) DIAG(F("Wifi 1"));
|
||||||
|
|
||||||
// First handle all inbound traffic events because they will block the sending
|
// First handle all inbound traffic events because they will block the sending
|
||||||
if (loop2()!=INBOUND_IDLE) return;
|
if (loop2()!=INBOUND_IDLE) {
|
||||||
|
if (XX) DIAG(F("Wifi 2"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (XX) DIAG(F("Wifi 3"));
|
||||||
|
|
||||||
WiThrottle::loop(outboundRing);
|
WiThrottle::loop(outboundRing);
|
||||||
|
if (XX) DIAG(F("Wifi 4"));
|
||||||
|
XX=false;
|
||||||
// if nothing is already CIPSEND pending, we can CIPSEND one reply
|
// if nothing is already CIPSEND pending, we can CIPSEND one reply
|
||||||
if (clientPendingCIPSEND<0) {
|
if (clientPendingCIPSEND<0) {
|
||||||
clientPendingCIPSEND=outboundRing->read();
|
clientPendingCIPSEND=outboundRing->read();
|
||||||
|
@ -66,14 +76,13 @@ void WifiInboundHandler::loop1() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (pendingCipsend) {
|
if (pendingCipsend && millis()-lastCIPSEND > CIPSENDgap) {
|
||||||
if (Diag::WIFI) DIAG( F("WiFi: [[CIPSEND=%d,%d]]"), clientPendingCIPSEND, currentReplySize);
|
if (Diag::WIFI) DIAG( F("WiFi: [[CIPSEND=%d,%d]]"), clientPendingCIPSEND, currentReplySize);
|
||||||
StringFormatter::send(wifiStream, F("AT+CIPSEND=%d,%d\r\n"), clientPendingCIPSEND, currentReplySize);
|
StringFormatter::send(wifiStream, F("AT+CIPSEND=%d,%d\r\n"), clientPendingCIPSEND, currentReplySize);
|
||||||
pendingCipsend=false;
|
pendingCipsend=false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// if something waiting to execute, we can call it
|
// if something waiting to execute, we can call it
|
||||||
int clientId=inboundRing->read();
|
int clientId=inboundRing->read();
|
||||||
if (clientId>=0) {
|
if (clientId>=0) {
|
||||||
|
@ -83,7 +92,6 @@ void WifiInboundHandler::loop1() {
|
||||||
for (int i=0;i<count;i++) cmd[i]=inboundRing->read();
|
for (int i=0;i<count;i++) cmd[i]=inboundRing->read();
|
||||||
cmd[count]=0;
|
cmd[count]=0;
|
||||||
if (Diag::WIFI) DIAG(F("%e"),cmd);
|
if (Diag::WIFI) DIAG(F("%e"),cmd);
|
||||||
|
|
||||||
CommandDistributor::parse(clientId,cmd,outboundRing);
|
CommandDistributor::parse(clientId,cmd,outboundRing);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -91,16 +99,17 @@ void WifiInboundHandler::loop1() {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// This is a Finite State Automation (FSA) handling the inbound bytes from an ES AT command processor
|
// This is a Finite State Automation (FSA) handling the inbound bytes from an ES AT command processor
|
||||||
|
|
||||||
WifiInboundHandler::INBOUND_STATE WifiInboundHandler::loop2() {
|
WifiInboundHandler::INBOUND_STATE WifiInboundHandler::loop2() {
|
||||||
while (wifiStream->available()) {
|
while (wifiStream->available()>=0) {
|
||||||
char ch = wifiStream->read();
|
int chint = wifiStream->read();
|
||||||
|
if (chint<0) break;
|
||||||
|
byte ch=(char)chint;
|
||||||
// echo the char to the diagnostic stream in escaped format
|
// echo the char to the diagnostic stream in escaped format
|
||||||
if (Diag::WIFI) {
|
if (Diag::WIFI) {
|
||||||
// DIAG(F(" %d/"), loopState);
|
StringFormatter::printEscape((char)ch); // DIAG in disguise
|
||||||
StringFormatter::printEscape(ch); // DIAG in disguise
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (loopState) {
|
switch (loopState) {
|
||||||
|
@ -131,11 +140,13 @@ WifiInboundHandler::INBOUND_STATE WifiInboundHandler::loop2() {
|
||||||
|
|
||||||
if (ch=='S') { // SEND OK probably
|
if (ch=='S') { // SEND OK probably
|
||||||
loopState=SKIPTOEND;
|
loopState=SKIPTOEND;
|
||||||
|
lastCIPSEND=0; // no need to wait next time
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ch=='b') { // This is a busy indicator... probabaly must restart a CIPSEND
|
if (ch=='b') { // This is a busy indicator... probabaly must restart a CIPSEND
|
||||||
pendingCipsend=(clientPendingCIPSEND>=0);
|
pendingCipsend=(clientPendingCIPSEND>=0);
|
||||||
|
if (pendingCipsend) lastCIPSEND=millis(); // forces a gap to next CIPSEND
|
||||||
loopState=SKIPTOEND;
|
loopState=SKIPTOEND;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,6 +69,7 @@ class WifiInboundHandler {
|
||||||
|
|
||||||
static const int INBOUND_RING = 512;
|
static const int INBOUND_RING = 512;
|
||||||
static const int OUTBOUND_RING = 2048;
|
static const int OUTBOUND_RING = 2048;
|
||||||
|
static const int CIPSENDgap=100; // millis() between retries of cipsend.
|
||||||
|
|
||||||
RingStream * inboundRing;
|
RingStream * inboundRing;
|
||||||
RingStream * outboundRing;
|
RingStream * outboundRing;
|
||||||
|
@ -79,5 +80,7 @@ class WifiInboundHandler {
|
||||||
int clientPendingCIPSEND=-1;
|
int clientPendingCIPSEND=-1;
|
||||||
int currentReplySize;
|
int currentReplySize;
|
||||||
bool pendingCipsend;
|
bool pendingCipsend;
|
||||||
|
uint32_t lastCIPSEND=0; // millis() of previous cipsend
|
||||||
|
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue
Block a user