mirror of
https://github.com/DCC-EX/CommandStation-EX.git
synced 2024-11-30 03:26:13 +01:00
Merge branch 'ESP88-Ash' into Temp-Ash
This commit is contained in:
commit
86d800fc3c
|
@ -63,7 +63,12 @@ void setup()
|
||||||
|
|
||||||
// Responsibility 1: Start the usb connection for diagnostics
|
// Responsibility 1: Start the usb connection for diagnostics
|
||||||
// This is normally Serial but uses SerialUSB on a SAMD processor
|
// This is normally Serial but uses SerialUSB on a SAMD processor
|
||||||
|
|
||||||
SerialManager::init();
|
SerialManager::init();
|
||||||
|
// Serial.begin(115200); // check this -- removed when resolve conflicts
|
||||||
|
#ifdef ESP_DEBUG
|
||||||
|
Serial.setDebugOutput(true);
|
||||||
|
#endif
|
||||||
|
|
||||||
DIAG(F("License GPLv3 fsf.org (c) dcc-ex.com"));
|
DIAG(F("License GPLv3 fsf.org (c) dcc-ex.com"));
|
||||||
|
|
||||||
|
@ -77,9 +82,12 @@ void setup()
|
||||||
// Start the WiFi interface on a MEGA, Uno cannot currently handle WiFi
|
// Start the WiFi interface on a MEGA, Uno cannot currently handle WiFi
|
||||||
// Start Ethernet if it exists
|
// Start Ethernet if it exists
|
||||||
#if WIFI_ON
|
#if WIFI_ON
|
||||||
|
#ifndef ESP_FAMILY
|
||||||
WifiInterface::setup(WIFI_SERIAL_LINK_SPEED, F(WIFI_SSID), F(WIFI_PASSWORD), F(WIFI_HOSTNAME), IP_PORT, WIFI_CHANNEL);
|
WifiInterface::setup(WIFI_SERIAL_LINK_SPEED, F(WIFI_SSID), F(WIFI_PASSWORD), F(WIFI_HOSTNAME), IP_PORT, WIFI_CHANNEL);
|
||||||
|
#else
|
||||||
|
WifiESP::setup(WIFI_SSID, WIFI_PASSWORD, WIFI_HOSTNAME, IP_PORT, WIFI_CHANNEL);
|
||||||
|
#endif
|
||||||
#endif // WIFI_ON
|
#endif // WIFI_ON
|
||||||
|
|
||||||
#if ETHERNET_ON
|
#if ETHERNET_ON
|
||||||
EthernetInterface::setup();
|
EthernetInterface::setup();
|
||||||
#endif // ETHERNET_ON
|
#endif // ETHERNET_ON
|
||||||
|
@ -119,14 +127,17 @@ void 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();
|
||||||
|
|
||||||
// Responsibility 2: handle any incoming commands on USB connection
|
// Responsibility 2: handle any incoming commands on USB connection
|
||||||
SerialManager::loop();
|
SerialManager::loop();
|
||||||
|
|
||||||
// Responsibility 3: Optionally handle any incoming WiFi traffic
|
// Responsibility 3: Optionally handle any incoming WiFi traffic
|
||||||
#if WIFI_ON
|
#if WIFI_ON
|
||||||
|
#ifndef ESP_FAMILY
|
||||||
WifiInterface::loop();
|
WifiInterface::loop();
|
||||||
|
#else
|
||||||
|
WifiESP::loop();
|
||||||
#endif
|
#endif
|
||||||
|
#endif //WIFI_ON
|
||||||
#if ETHERNET_ON
|
#if ETHERNET_ON
|
||||||
EthernetInterface::loop();
|
EthernetInterface::loop();
|
||||||
#endif
|
#endif
|
||||||
|
@ -146,7 +157,9 @@ void loop()
|
||||||
|
|
||||||
// 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
|
||||||
|
#ifdef ESP_FAMILY
|
||||||
|
updateMinimumFreeMemory(128);
|
||||||
|
#endif
|
||||||
int freeNow = minimumFreeMemory();
|
int freeNow = minimumFreeMemory();
|
||||||
if (freeNow < ramLowWatermark) {
|
if (freeNow < ramLowWatermark) {
|
||||||
ramLowWatermark = freeNow;
|
ramLowWatermark = freeNow;
|
||||||
|
|
26
DCC.cpp
26
DCC.cpp
|
@ -313,14 +313,14 @@ const ackOp FLASH WRITE_BIT0_PROG[] = {
|
||||||
W0,WACK,
|
W0,WACK,
|
||||||
V0, WACK, // validate bit is 0
|
V0, WACK, // validate bit is 0
|
||||||
ITC1, // if acked, callback(1)
|
ITC1, // if acked, callback(1)
|
||||||
FAIL // callback (-1)
|
CALLFAIL // callback (-1)
|
||||||
};
|
};
|
||||||
const ackOp FLASH WRITE_BIT1_PROG[] = {
|
const ackOp FLASH WRITE_BIT1_PROG[] = {
|
||||||
BASELINE,
|
BASELINE,
|
||||||
W1,WACK,
|
W1,WACK,
|
||||||
V1, WACK, // validate bit is 1
|
V1, WACK, // validate bit is 1
|
||||||
ITC1, // if acked, callback(1)
|
ITC1, // if acked, callback(1)
|
||||||
FAIL // callback (-1)
|
CALLFAIL // callback (-1)
|
||||||
};
|
};
|
||||||
|
|
||||||
const ackOp FLASH VERIFY_BIT0_PROG[] = {
|
const ackOp FLASH VERIFY_BIT0_PROG[] = {
|
||||||
|
@ -329,7 +329,7 @@ const ackOp FLASH VERIFY_BIT0_PROG[] = {
|
||||||
ITC0, // if acked, callback(0)
|
ITC0, // if acked, callback(0)
|
||||||
V1, WACK, // validate bit is 1
|
V1, WACK, // validate bit is 1
|
||||||
ITC1,
|
ITC1,
|
||||||
FAIL // callback (-1)
|
CALLFAIL // callback (-1)
|
||||||
};
|
};
|
||||||
const ackOp FLASH VERIFY_BIT1_PROG[] = {
|
const ackOp FLASH VERIFY_BIT1_PROG[] = {
|
||||||
BASELINE,
|
BASELINE,
|
||||||
|
@ -337,7 +337,7 @@ const ackOp FLASH VERIFY_BIT1_PROG[] = {
|
||||||
ITC1, // if acked, callback(1)
|
ITC1, // if acked, callback(1)
|
||||||
V0, WACK,
|
V0, WACK,
|
||||||
ITC0,
|
ITC0,
|
||||||
FAIL // callback (-1)
|
CALLFAIL // callback (-1)
|
||||||
};
|
};
|
||||||
|
|
||||||
const ackOp FLASH READ_BIT_PROG[] = {
|
const ackOp FLASH READ_BIT_PROG[] = {
|
||||||
|
@ -346,7 +346,7 @@ const ackOp FLASH READ_BIT_PROG[] = {
|
||||||
ITC1, // if acked, callback(1)
|
ITC1, // if acked, callback(1)
|
||||||
V0, WACK, // validate bit is zero
|
V0, WACK, // validate bit is zero
|
||||||
ITC0, // if acked callback 0
|
ITC0, // if acked callback 0
|
||||||
FAIL // bit not readable
|
CALLFAIL // bit not readable
|
||||||
};
|
};
|
||||||
|
|
||||||
const ackOp FLASH WRITE_BYTE_PROG[] = {
|
const ackOp FLASH WRITE_BYTE_PROG[] = {
|
||||||
|
@ -354,7 +354,7 @@ const ackOp FLASH WRITE_BYTE_PROG[] = {
|
||||||
WB,WACK,ITC1, // Write and callback(1) if ACK
|
WB,WACK,ITC1, // Write and callback(1) if ACK
|
||||||
// handle decoders that dont ack a write
|
// handle decoders that dont ack a write
|
||||||
VB,WACK,ITC1, // validate byte and callback(1) if correct
|
VB,WACK,ITC1, // validate byte and callback(1) if correct
|
||||||
FAIL // callback (-1)
|
CALLFAIL // callback (-1)
|
||||||
};
|
};
|
||||||
|
|
||||||
const ackOp FLASH VERIFY_BYTE_PROG[] = {
|
const ackOp FLASH VERIFY_BYTE_PROG[] = {
|
||||||
|
@ -379,8 +379,8 @@ const ackOp FLASH VERIFY_BYTE_PROG[] = {
|
||||||
V0, WACK, MERGE,
|
V0, WACK, MERGE,
|
||||||
V0, WACK, MERGE,
|
V0, WACK, MERGE,
|
||||||
V0, WACK, MERGE,
|
V0, WACK, MERGE,
|
||||||
VB, WACK, ITCBV, // verify merged byte and return it if acked ok - with retry report
|
VB, WACK, ITCB, // verify merged byte and return it if acked ok
|
||||||
FAIL };
|
CALLFAIL };
|
||||||
|
|
||||||
|
|
||||||
const ackOp FLASH READ_CV_PROG[] = {
|
const ackOp FLASH READ_CV_PROG[] = {
|
||||||
|
@ -403,7 +403,7 @@ const ackOp FLASH READ_CV_PROG[] = {
|
||||||
V0, WACK, MERGE,
|
V0, WACK, MERGE,
|
||||||
V0, WACK, MERGE,
|
V0, WACK, MERGE,
|
||||||
VB, WACK, ITCB, // verify merged byte and return it if acked ok
|
VB, WACK, ITCB, // verify merged byte and return it if acked ok
|
||||||
FAIL }; // verification failed
|
CALLFAIL }; // verification failed
|
||||||
|
|
||||||
|
|
||||||
const ackOp FLASH LOCO_ID_PROG[] = {
|
const ackOp FLASH LOCO_ID_PROG[] = {
|
||||||
|
@ -469,7 +469,7 @@ const ackOp FLASH LOCO_ID_PROG[] = {
|
||||||
V0, WACK, MERGE,
|
V0, WACK, MERGE,
|
||||||
V0, WACK, MERGE,
|
V0, WACK, MERGE,
|
||||||
VB, WACK, ITCB, // verify merged byte and callback
|
VB, WACK, ITCB, // verify merged byte and callback
|
||||||
FAIL
|
CALLFAIL
|
||||||
};
|
};
|
||||||
|
|
||||||
const ackOp FLASH SHORT_LOCO_ID_PROG[] = {
|
const ackOp FLASH SHORT_LOCO_ID_PROG[] = {
|
||||||
|
@ -486,7 +486,7 @@ const ackOp FLASH SHORT_LOCO_ID_PROG[] = {
|
||||||
SETBYTEL, // low byte of word
|
SETBYTEL, // low byte of word
|
||||||
WB,WACK, // some decoders don't ACK writes
|
WB,WACK, // some decoders don't ACK writes
|
||||||
VB,WACK,ITCB,
|
VB,WACK,ITCB,
|
||||||
FAIL
|
CALLFAIL
|
||||||
};
|
};
|
||||||
|
|
||||||
const ackOp FLASH LONG_LOCO_ID_PROG[] = {
|
const ackOp FLASH LONG_LOCO_ID_PROG[] = {
|
||||||
|
@ -510,7 +510,7 @@ const ackOp FLASH LONG_LOCO_ID_PROG[] = {
|
||||||
SETBYTEL, // low byte of word
|
SETBYTEL, // low byte of word
|
||||||
WB,WACK,
|
WB,WACK,
|
||||||
VB,WACK,ITC1, // callback(1) means Ok
|
VB,WACK,ITC1, // callback(1) means Ok
|
||||||
FAIL
|
CALLFAIL
|
||||||
};
|
};
|
||||||
|
|
||||||
void DCC::writeCVByte(int16_t cv, byte byteValue, ACK_CALLBACK callback) {
|
void DCC::writeCVByte(int16_t cv, byte byteValue, ACK_CALLBACK callback) {
|
||||||
|
@ -869,7 +869,7 @@ void DCC::ackManagerLoop() {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FAIL: // callback(-1)
|
case CALLFAIL: // callback(-1)
|
||||||
callback(-1);
|
callback(-1);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
4
DCC.h
4
DCC.h
|
@ -56,7 +56,7 @@ enum ackOp : byte
|
||||||
ITCBV, // If True callback(byte) - end of Verify Byte
|
ITCBV, // If True callback(byte) - end of Verify Byte
|
||||||
ITCB7, // If True callback(byte &0x7F)
|
ITCB7, // If True callback(byte &0x7F)
|
||||||
NAKFAIL, // if false callback(-1)
|
NAKFAIL, // if false callback(-1)
|
||||||
FAIL, // callback(-1)
|
CALLFAIL, // callback(-1)
|
||||||
BIV, // Set ackManagerByte to initial value for Verify retry
|
BIV, // Set ackManagerByte to initial value for Verify retry
|
||||||
STARTMERGE, // Clear bit and byte settings ready for merge pass
|
STARTMERGE, // Clear bit and byte settings ready for merge pass
|
||||||
MERGE, // Merge previous wack response with byte value and decrement bit number (use for readimng CV bytes)
|
MERGE, // Merge previous wack response with byte value and decrement bit number (use for readimng CV bytes)
|
||||||
|
@ -224,6 +224,8 @@ private:
|
||||||
#define ARDUINO_TYPE "TEENSY40"
|
#define ARDUINO_TYPE "TEENSY40"
|
||||||
#elif defined(ARDUINO_TEENSY41)
|
#elif defined(ARDUINO_TEENSY41)
|
||||||
#define ARDUINO_TYPE "TEENSY41"
|
#define ARDUINO_TYPE "TEENSY41"
|
||||||
|
#elif defined(ARDUINO_ARCH_ESP8266)
|
||||||
|
#define ARDUINO_TYPE "ESP8266"
|
||||||
#else
|
#else
|
||||||
#error CANNOT COMPILE - DCC++ EX ONLY WORKS WITH AN ARDUINO UNO, NANO 328, OR ARDUINO MEGA 1280/2560
|
#error CANNOT COMPILE - DCC++ EX ONLY WORKS WITH AN ARDUINO UNO, NANO 328, OR ARDUINO MEGA 1280/2560
|
||||||
#endif
|
#endif
|
||||||
|
|
3
DCCEX.h
3
DCCEX.h
|
@ -33,6 +33,9 @@
|
||||||
#include "SerialManager.h"
|
#include "SerialManager.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include "WifiInterface.h"
|
#include "WifiInterface.h"
|
||||||
|
#ifdef ESP_FAMILY
|
||||||
|
#include "WifiESP.h"
|
||||||
|
#endif
|
||||||
#if ETHERNET_ON == true
|
#if ETHERNET_ON == true
|
||||||
#include "EthernetInterface.h"
|
#include "EthernetInterface.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with CommandStation. If not, see <https://www.gnu.org/licenses/>.
|
* along with CommandStation. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
#include "defines.h"
|
||||||
#include "StringFormatter.h"
|
#include "StringFormatter.h"
|
||||||
#include "DCCEXParser.h"
|
#include "DCCEXParser.h"
|
||||||
#include "DCC.h"
|
#include "DCC.h"
|
||||||
|
@ -37,7 +38,9 @@
|
||||||
#include "CommandDistributor.h"
|
#include "CommandDistributor.h"
|
||||||
#include "EEStore.h"
|
#include "EEStore.h"
|
||||||
#include "DIAG.h"
|
#include "DIAG.h"
|
||||||
|
#ifndef ESP_FAMILY
|
||||||
#include <avr/wdt.h>
|
#include <avr/wdt.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
|
|
31
DCCTimer.cpp
31
DCCTimer.cpp
|
@ -49,7 +49,7 @@
|
||||||
|
|
||||||
#include "DCCTimer.h"
|
#include "DCCTimer.h"
|
||||||
const int DCC_SIGNAL_TIME=58; // this is the 58uS DCC 1-bit waveform half-cycle
|
const int DCC_SIGNAL_TIME=58; // this is the 58uS DCC 1-bit waveform half-cycle
|
||||||
const long CLOCK_CYCLES=(F_CPU / 1000000 * DCC_SIGNAL_TIME) >>1;
|
const long CLOCK_CYCLES=(F_CPU / 1000000 * DCC_SIGNAL_TIME);
|
||||||
|
|
||||||
INTERRUPT_CALLBACK interruptHandler=0;
|
INTERRUPT_CALLBACK interruptHandler=0;
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ INTERRUPT_CALLBACK interruptHandler=0;
|
||||||
ADC0.CTRLC = (ADC0.CTRLC & 0b00110000) | 0b01000011; // speed up analogRead sample time
|
ADC0.CTRLC = (ADC0.CTRLC & 0b00110000) | 0b01000011; // speed up analogRead sample time
|
||||||
TCB0.CTRLB = TCB_CNTMODE_INT_gc & ~TCB_CCMPEN_bm; // timer compare mode with output disabled
|
TCB0.CTRLB = TCB_CNTMODE_INT_gc & ~TCB_CCMPEN_bm; // timer compare mode with output disabled
|
||||||
TCB0.CTRLA = TCB_CLKSEL_CLKDIV2_gc; // 8 MHz ~ 0.125 us
|
TCB0.CTRLA = TCB_CLKSEL_CLKDIV2_gc; // 8 MHz ~ 0.125 us
|
||||||
TCB0.CCMP = CLOCK_CYCLES -1; // 1 tick less for timer reset
|
TCB0.CCMP = (CLOCK_CYCLES>>1) -1; // 1 tick less for timer reset
|
||||||
TCB0.INTFLAGS = TCB_CAPT_bm; // clear interrupt request flag
|
TCB0.INTFLAGS = TCB_CAPT_bm; // clear interrupt request flag
|
||||||
TCB0.INTCTRL = TCB_CAPT_bm; // Enable the interrupt
|
TCB0.INTCTRL = TCB_CAPT_bm; // Enable the interrupt
|
||||||
TCB0.CNT = 0;
|
TCB0.CNT = 0;
|
||||||
|
@ -151,6 +151,31 @@ void DCCTimer::read(uint8_t word, uint8_t *mac, uint8_t offset) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#elif defined(ARDUINO_ARCH_ESP8266)
|
||||||
|
|
||||||
|
void DCCTimer::begin(INTERRUPT_CALLBACK callback) {
|
||||||
|
interruptHandler=callback;
|
||||||
|
timer1_disable();
|
||||||
|
|
||||||
|
// There seem to be differnt ways to attach interrupt handler
|
||||||
|
// ETS_FRC_TIMER1_INTR_ATTACH(NULL, NULL);
|
||||||
|
// ETS_FRC_TIMER1_NMI_INTR_ATTACH(interruptHandler);
|
||||||
|
// Let us choose the one from the API
|
||||||
|
timer1_attachInterrupt(interruptHandler);
|
||||||
|
|
||||||
|
// not exactly sure of order:
|
||||||
|
timer1_enable(TIM_DIV1, TIM_EDGE, TIM_LOOP);
|
||||||
|
timer1_write(CLOCK_CYCLES);
|
||||||
|
}
|
||||||
|
// We do not support to use PWM to make the Waveform on ESP
|
||||||
|
bool IRAM_ATTR DCCTimer::isPWMPin(byte pin) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
void IRAM_ATTR DCCTimer::setPWM(byte pin, bool high) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
// Arduino nano, uno, mega etc
|
// Arduino nano, uno, mega etc
|
||||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||||
|
@ -167,7 +192,7 @@ void DCCTimer::read(uint8_t word, uint8_t *mac, uint8_t offset) {
|
||||||
noInterrupts();
|
noInterrupts();
|
||||||
ADCSRA = (ADCSRA & 0b11111000) | 0b00000100; // speed up analogRead sample time
|
ADCSRA = (ADCSRA & 0b11111000) | 0b00000100; // speed up analogRead sample time
|
||||||
TCCR1A = 0;
|
TCCR1A = 0;
|
||||||
ICR1 = CLOCK_CYCLES;
|
ICR1 = CLOCK_CYCLES>>1;
|
||||||
TCNT1 = 0;
|
TCNT1 = 0;
|
||||||
TCCR1B = _BV(WGM13) | _BV(CS10); // Mode 8, clock select 1
|
TCCR1B = _BV(WGM13) | _BV(CS10); // Mode 8, clock select 1
|
||||||
TIMSK1 = _BV(TOIE1); // Enable Software interrupt
|
TIMSK1 = _BV(TOIE1); // Enable Software interrupt
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
#include "defines.h"
|
||||||
#include "DCCWaveform.h"
|
#include "DCCWaveform.h"
|
||||||
#include "DCCTimer.h"
|
#include "DCCTimer.h"
|
||||||
#include "DIAG.h"
|
#include "DIAG.h"
|
||||||
|
@ -55,33 +56,48 @@ void DCCWaveform::begin(MotorDriver * mainDriver, MotorDriver * progDriver) {
|
||||||
DCCTimer::begin(DCCWaveform::interruptHandler);
|
DCCTimer::begin(DCCWaveform::interruptHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DCCWaveform::loop(bool ackManagerActive) {
|
#ifdef SLOW_ANALOG_READ
|
||||||
|
// Flag to hold if we need to run ack checking in loop
|
||||||
|
static bool ackflag = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void IRAM_ATTR DCCWaveform::loop(bool ackManagerActive) {
|
||||||
mainTrack.checkPowerOverload(false);
|
mainTrack.checkPowerOverload(false);
|
||||||
progTrack.checkPowerOverload(ackManagerActive);
|
progTrack.checkPowerOverload(ackManagerActive);
|
||||||
|
#ifdef SLOW_ANALOG_READ
|
||||||
|
if (ackflag) {
|
||||||
|
progTrack.checkAck();
|
||||||
|
// reset flag AFTER check is done
|
||||||
|
ackflag = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma GCC push_options
|
#pragma GCC push_options
|
||||||
#pragma GCC optimize ("-O3")
|
#pragma GCC optimize ("-O3")
|
||||||
void DCCWaveform::interruptHandler() {
|
void IRAM_ATTR DCCWaveform::interruptHandler() {
|
||||||
// call the timer edge sensitive actions for progtrack and maintrack
|
// call the timer edge sensitive actions for progtrack and maintrack
|
||||||
// member functions would be cleaner but have more overhead
|
// member functions would be cleaner but have more overhead
|
||||||
byte sigMain=signalTransform[mainTrack.state];
|
byte sigMain=signalTransform[mainTrack.state];
|
||||||
byte sigProg=progTrackSyncMain? sigMain : signalTransform[progTrack.state];
|
byte sigProg=progTrackSyncMain? sigMain : signalTransform[progTrack.state];
|
||||||
|
|
||||||
// Set the signal state for both tracks
|
// Set the signal state for both tracks
|
||||||
mainTrack.motorDriver->setSignal(sigMain);
|
mainTrack.motorDriver->setSignal(sigMain);
|
||||||
progTrack.motorDriver->setSignal(sigProg);
|
progTrack.motorDriver->setSignal(sigProg);
|
||||||
|
|
||||||
// Move on in the state engine
|
// Move on in the state engine
|
||||||
mainTrack.state=stateTransform[mainTrack.state];
|
mainTrack.state=stateTransform[mainTrack.state];
|
||||||
progTrack.state=stateTransform[progTrack.state];
|
progTrack.state=stateTransform[progTrack.state];
|
||||||
|
|
||||||
|
|
||||||
// WAVE_PENDING means we dont yet know what the next bit is
|
// WAVE_PENDING means we dont yet know what the next bit is
|
||||||
if (mainTrack.state==WAVE_PENDING) mainTrack.interrupt2();
|
if (mainTrack.state==WAVE_PENDING)
|
||||||
if (progTrack.state==WAVE_PENDING) progTrack.interrupt2();
|
mainTrack.interrupt2();
|
||||||
else if (progTrack.ackPending) progTrack.checkAck();
|
if (progTrack.state==WAVE_PENDING)
|
||||||
|
progTrack.interrupt2();
|
||||||
|
#ifdef SLOW_ANALOG_READ
|
||||||
|
else if (progTrack.ackPending && ackflag == 0) // We need AND we are not already checking
|
||||||
|
ackflag = 1;
|
||||||
|
#else
|
||||||
|
else if (progTrack.ackPending)
|
||||||
|
progTrack.checkAck();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#pragma GCC push_options
|
#pragma GCC push_options
|
||||||
|
|
||||||
|
@ -206,7 +222,7 @@ const bool DCCWaveform::signalTransform[]={
|
||||||
|
|
||||||
#pragma GCC push_options
|
#pragma GCC push_options
|
||||||
#pragma GCC optimize ("-O3")
|
#pragma GCC optimize ("-O3")
|
||||||
void DCCWaveform::interrupt2() {
|
void IRAM_ATTR DCCWaveform::interrupt2() {
|
||||||
// calculate the next bit to be sent:
|
// calculate the next bit to be sent:
|
||||||
// set state WAVE_MID_1 for a 1=bit
|
// set state WAVE_MID_1 for a 1=bit
|
||||||
// or WAVE_HIGH_0 for a 0 bit.
|
// or WAVE_HIGH_0 for a 0 bit.
|
||||||
|
@ -216,7 +232,9 @@ void DCCWaveform::interrupt2() {
|
||||||
remainingPreambles--;
|
remainingPreambles--;
|
||||||
// Update free memory diagnostic as we don't have anything else to do this time.
|
// Update free memory diagnostic as we don't have anything else to do this time.
|
||||||
// Allow for checkAck and its called functions using 22 bytes more.
|
// Allow for checkAck and its called functions using 22 bytes more.
|
||||||
|
#ifndef ESP_FAMILY
|
||||||
updateMinimumFreeMemory(22);
|
updateMinimumFreeMemory(22);
|
||||||
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,7 +335,7 @@ byte DCCWaveform::getAck() {
|
||||||
|
|
||||||
#pragma GCC push_options
|
#pragma GCC push_options
|
||||||
#pragma GCC optimize ("-O3")
|
#pragma GCC optimize ("-O3")
|
||||||
void DCCWaveform::checkAck() {
|
void IRAM_ATTR DCCWaveform::checkAck() {
|
||||||
// This function operates in interrupt() time so must be fast and can't DIAG
|
// This function operates in interrupt() time so must be fast and can't DIAG
|
||||||
if (sentResetsSincePacket > 6) { //ACK timeout
|
if (sentResetsSincePacket > 6) { //ACK timeout
|
||||||
ackCheckDuration=millis()-ackCheckStart;
|
ackCheckDuration=millis()-ackCheckStart;
|
||||||
|
|
|
@ -25,11 +25,6 @@
|
||||||
#include "DCCTimer.h"
|
#include "DCCTimer.h"
|
||||||
#include "DIAG.h"
|
#include "DIAG.h"
|
||||||
|
|
||||||
#define setHIGH(fastpin) *fastpin.inout |= fastpin.maskHIGH
|
|
||||||
#define setLOW(fastpin) *fastpin.inout &= fastpin.maskLOW
|
|
||||||
#define isHIGH(fastpin) (*fastpin.inout & fastpin.maskHIGH)
|
|
||||||
#define isLOW(fastpin) (!isHIGH(fastpin))
|
|
||||||
|
|
||||||
bool MotorDriver::usePWM=false;
|
bool MotorDriver::usePWM=false;
|
||||||
bool MotorDriver::commonFaultPin=false;
|
bool MotorDriver::commonFaultPin=false;
|
||||||
|
|
||||||
|
@ -114,7 +109,7 @@ void MotorDriver::setBrake(bool on) {
|
||||||
else setLOW(fastBrakePin);
|
else setLOW(fastBrakePin);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MotorDriver::setSignal( bool high) {
|
void IRAM_ATTR MotorDriver::setSignal( bool high) {
|
||||||
if (usePWM) {
|
if (usePWM) {
|
||||||
DCCTimer::setPWM(signalPin,high);
|
DCCTimer::setPWM(signalPin,high);
|
||||||
}
|
}
|
||||||
|
@ -181,7 +176,7 @@ int MotorDriver::mA2raw( unsigned int mA) {
|
||||||
void MotorDriver::getFastPin(const FSH* type,int pin, bool input, FASTPIN & result) {
|
void MotorDriver::getFastPin(const FSH* type,int pin, bool input, FASTPIN & result) {
|
||||||
// DIAG(F("MotorDriver %S Pin=%d,"),type,pin);
|
// DIAG(F("MotorDriver %S Pin=%d,"),type,pin);
|
||||||
(void) type; // avoid compiler warning if diag not used above.
|
(void) type; // avoid compiler warning if diag not used above.
|
||||||
uint8_t port = digitalPinToPort(pin);
|
PORTTYPE port = digitalPinToPort(pin);
|
||||||
if (input)
|
if (input)
|
||||||
result.inout = portInputRegister(port);
|
result.inout = portInputRegister(port);
|
||||||
else
|
else
|
||||||
|
|
|
@ -29,13 +29,15 @@
|
||||||
#define UNUSED_PIN 127 // inside int8_t
|
#define UNUSED_PIN 127 // inside int8_t
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__IMXRT1062__)
|
#if defined(__IMXRT1062__) || defined (ARDUINO_ARCH_ESP8266)
|
||||||
|
typedef uint32_t PORTTYPE;
|
||||||
struct FASTPIN {
|
struct FASTPIN {
|
||||||
volatile uint32_t *inout;
|
volatile uint32_t *inout;
|
||||||
uint32_t maskHIGH;
|
uint32_t maskHIGH;
|
||||||
uint32_t maskLOW;
|
uint32_t maskLOW;
|
||||||
};
|
};
|
||||||
#else
|
#else
|
||||||
|
typedef uint8_t PORTTYPE;
|
||||||
struct FASTPIN {
|
struct FASTPIN {
|
||||||
volatile uint8_t *inout;
|
volatile uint8_t *inout;
|
||||||
uint8_t maskHIGH;
|
uint8_t maskHIGH;
|
||||||
|
@ -43,12 +45,30 @@ struct FASTPIN {
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define setHIGH(fastpin) *fastpin.inout |= fastpin.maskHIGH
|
||||||
|
#define setLOW(fastpin) *fastpin.inout &= fastpin.maskLOW
|
||||||
|
#define isHIGH(fastpin) (*fastpin.inout & fastpin.maskHIGH)
|
||||||
|
#define isLOW(fastpin) (!isHIGH(fastpin))
|
||||||
|
|
||||||
class MotorDriver {
|
class MotorDriver {
|
||||||
public:
|
public:
|
||||||
MotorDriver(byte power_pin, byte signal_pin, byte signal_pin2, int8_t brake_pin,
|
MotorDriver(byte power_pin, byte signal_pin, byte signal_pin2, int8_t brake_pin,
|
||||||
byte current_pin, float senseFactor, unsigned int tripMilliamps, byte faultPin);
|
byte current_pin, float senseFactor, unsigned int tripMilliamps, byte faultPin);
|
||||||
virtual void setPower( bool on);
|
virtual void setPower( bool on);
|
||||||
virtual void setSignal( bool high);
|
void setSignal( bool high);/* {
|
||||||
|
if (usePWM) {
|
||||||
|
DCCTimer::setPWM(signalPin,high);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (high) {
|
||||||
|
setHIGH(fastSignalPin);
|
||||||
|
if (dualSignal) setLOW(fastSignalPin2);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
setLOW(fastSignalPin);
|
||||||
|
if (dualSignal) setHIGH(fastSignalPin2);
|
||||||
|
}
|
||||||
|
};*/
|
||||||
virtual void setBrake( bool on);
|
virtual void setBrake( bool on);
|
||||||
virtual int getCurrentRaw();
|
virtual int getCurrentRaw();
|
||||||
virtual unsigned int raw2mA( int raw);
|
virtual unsigned int raw2mA( int raw);
|
||||||
|
|
|
@ -46,10 +46,11 @@ size_t RingStream::write(uint8_t b) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int RingStream::read() {
|
int RingStream::read(byte advance) {
|
||||||
if ((_pos_read==_pos_write) && !_overflow) return -1; // empty
|
if ((_pos_read==_pos_write) && !_overflow) return -1; // empty
|
||||||
|
if (_pos_read == _mark) return -1;
|
||||||
byte b=_buffer[_pos_read];
|
byte b=_buffer[_pos_read];
|
||||||
_pos_read++;
|
_pos_read += advance;
|
||||||
if (_pos_read==_len) _pos_read=0;
|
if (_pos_read==_len) _pos_read=0;
|
||||||
_overflow=false;
|
_overflow=false;
|
||||||
return b;
|
return b;
|
||||||
|
@ -69,6 +70,7 @@ int RingStream::freeSpace() {
|
||||||
|
|
||||||
// mark start of message with client id (0...9)
|
// mark start of message with client id (0...9)
|
||||||
void RingStream::mark(uint8_t b) {
|
void RingStream::mark(uint8_t b) {
|
||||||
|
//DIAG(F("Mark1 len=%d count=%d pr=%d pw=%d m=%d"),_len, _count,_pos_read,_pos_write,_mark);
|
||||||
_mark=_pos_write;
|
_mark=_pos_write;
|
||||||
write(b); // client id
|
write(b); // client id
|
||||||
write((uint8_t)0); // count MSB placemarker
|
write((uint8_t)0); // count MSB placemarker
|
||||||
|
@ -82,7 +84,12 @@ uint8_t RingStream::peekTargetMark() {
|
||||||
return _buffer[_mark];
|
return _buffer[_mark];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RingStream::info() {
|
||||||
|
DIAG(F("Info len=%d count=%d pr=%d pw=%d m=%d"),_len, _count,_pos_read,_pos_write,_mark);
|
||||||
|
}
|
||||||
|
|
||||||
bool RingStream::commit() {
|
bool RingStream::commit() {
|
||||||
|
//DIAG(F("Commit1 len=%d count=%d pr=%d pw=%d m=%d"),_len, _count,_pos_read,_pos_write,_mark);
|
||||||
if (_overflow) {
|
if (_overflow) {
|
||||||
DIAG(F("RingStream(%d) commit(%d) OVERFLOW"),_len, _count);
|
DIAG(F("RingStream(%d) commit(%d) OVERFLOW"),_len, _count);
|
||||||
// just throw it away
|
// just throw it away
|
||||||
|
@ -102,6 +109,8 @@ bool RingStream::commit() {
|
||||||
_mark++;
|
_mark++;
|
||||||
if (_mark==_len) _mark=0;
|
if (_mark==_len) _mark=0;
|
||||||
_buffer[_mark]=lowByte(_count);
|
_buffer[_mark]=lowByte(_count);
|
||||||
|
_mark=_len+1;
|
||||||
|
//DIAG(F("Commit2 len=%d count=%d pr=%d pw=%d m=%d"),_len, _count,_pos_read,_pos_write,_mark);
|
||||||
return true; // commit worked
|
return true; // commit worked
|
||||||
}
|
}
|
||||||
void RingStream::flush() {
|
void RingStream::flush() {
|
||||||
|
|
|
@ -29,7 +29,8 @@ class RingStream : public Print {
|
||||||
|
|
||||||
virtual size_t write(uint8_t b);
|
virtual size_t write(uint8_t b);
|
||||||
using Print::write;
|
using Print::write;
|
||||||
int read();
|
inline int read() { return read(1); };
|
||||||
|
inline int peek() { return read(0); };
|
||||||
int count();
|
int count();
|
||||||
int freeSpace();
|
int freeSpace();
|
||||||
void mark(uint8_t b);
|
void mark(uint8_t b);
|
||||||
|
@ -37,7 +38,10 @@ class RingStream : public Print {
|
||||||
uint8_t peekTargetMark();
|
uint8_t peekTargetMark();
|
||||||
void printBuffer(Print * streamer);
|
void printBuffer(Print * streamer);
|
||||||
void flush();
|
void flush();
|
||||||
|
void info();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
int read(byte advance);
|
||||||
int _len;
|
int _len;
|
||||||
int _pos_write;
|
int _pos_write;
|
||||||
int _pos_read;
|
int _pos_read;
|
||||||
|
|
264
WifiESP.cpp
Normal file
264
WifiESP.cpp
Normal file
|
@ -0,0 +1,264 @@
|
||||||
|
/*
|
||||||
|
© 2021, Harald Barth.
|
||||||
|
|
||||||
|
This file is part of 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 "defines.h"
|
||||||
|
#ifdef ESP_FAMILY
|
||||||
|
#include <ESP8266WiFi.h>
|
||||||
|
#include <ESPAsyncTCP.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "WifiESP.h"
|
||||||
|
#include "DIAG.h"
|
||||||
|
#include "RingStream.h"
|
||||||
|
#include "CommandDistributor.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static std::vector<AsyncClient*> clients; // a list to hold all clients
|
||||||
|
static AsyncServer *server;
|
||||||
|
|
||||||
|
static RingStream *outboundRing = new RingStream(2048);
|
||||||
|
|
||||||
|
static void handleError(void* arg, AsyncClient* client, int8_t error) {
|
||||||
|
DIAG(F("connection error %s from client %s"), client->errorToString(error), client->remoteIP().toString().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handleData(void* arg, AsyncClient* client, void *data, size_t len) {
|
||||||
|
//DIAG(F("data received from client %s"), client->remoteIP().toString().c_str());
|
||||||
|
uint8_t clientId;
|
||||||
|
for (clientId=0; clientId<clients.size(); clientId++){
|
||||||
|
if (clients[clientId] == client) break;
|
||||||
|
}
|
||||||
|
if (clientId < clients.size()) {
|
||||||
|
byte cmd[len+1];
|
||||||
|
memcpy(cmd,data,len);
|
||||||
|
cmd[len]=0;
|
||||||
|
outboundRing->mark(clientId);
|
||||||
|
CommandDistributor::parse(clientId,cmd,outboundRing);
|
||||||
|
outboundRing->commit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//static AsyncClient *debugclient = NULL;
|
||||||
|
|
||||||
|
bool sendData(AsyncClient *client, char* data, size_t count) {
|
||||||
|
size_t willsend = 0;
|
||||||
|
|
||||||
|
// reply to client
|
||||||
|
if (client->canSend()) {
|
||||||
|
while (count > 0) {
|
||||||
|
if (client->connected())
|
||||||
|
willsend = client->add(data, count); // add checks for space()
|
||||||
|
else
|
||||||
|
willsend = 0;
|
||||||
|
if (willsend < count) {
|
||||||
|
DIAG(F("Willsend %d of count %d"), willsend, count);
|
||||||
|
}
|
||||||
|
if (client->connected() && client->send()) {
|
||||||
|
count = count - willsend;
|
||||||
|
data = data + willsend;
|
||||||
|
} else {
|
||||||
|
DIAG(F("Could not send promised %d"), count);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Did send all bytes we wanted
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
DIAG(F("Aborting: Busy or space=0"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void deleteClient(AsyncClient* client) {
|
||||||
|
uint8_t clientId;
|
||||||
|
for (clientId=0; clientId<clients.size(); clientId++){
|
||||||
|
if (clients[clientId] == client) break;
|
||||||
|
}
|
||||||
|
if (clientId < clients.size()) {
|
||||||
|
clients[clientId] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void handleDisconnect(void* arg, AsyncClient* client) {
|
||||||
|
DIAG(F("Client disconnected"));
|
||||||
|
deleteClient(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handleTimeOut(void* arg, AsyncClient* client, uint32_t time) {
|
||||||
|
DIAG(F("client ACK timeout ip: %s"), client->remoteIP().toString().c_str());
|
||||||
|
deleteClient(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void handleNewClient(void* arg, AsyncClient* client) {
|
||||||
|
DIAG(F("New client %s"), client->remoteIP().toString().c_str());
|
||||||
|
|
||||||
|
// add to list
|
||||||
|
clients.push_back(client);
|
||||||
|
|
||||||
|
// register events
|
||||||
|
client->onData(&handleData, NULL);
|
||||||
|
client->onError(&handleError, NULL);
|
||||||
|
client->onDisconnect(&handleDisconnect, NULL);
|
||||||
|
client->onTimeout(&handleTimeOut, NULL);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Things one _might_ want to do:
|
||||||
|
Disable soft watchdog: ESP.wdtDisable()
|
||||||
|
Enable soft watchdog: ESP.wdtEnable(X) ignores the value of X and enables it for fixed
|
||||||
|
time at least in version 3.0.2 of the esp8266 package.
|
||||||
|
|
||||||
|
Internet says:
|
||||||
|
|
||||||
|
I manage to complety disable the hardware watchdog on ESP8266 in order to run the benchmark CoreMark.
|
||||||
|
|
||||||
|
void hw_wdt_disable(){
|
||||||
|
*((volatile uint32_t*) 0x60000900) &= ~(1); // Hardware WDT OFF
|
||||||
|
}
|
||||||
|
|
||||||
|
void hw_wdt_enable(){
|
||||||
|
*((volatile uint32_t*) 0x60000900) |= 1; // Hardware WDT ON
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool WifiESP::setup(const char *SSid,
|
||||||
|
const char *password,
|
||||||
|
const char *hostname,
|
||||||
|
int port,
|
||||||
|
const byte channel) {
|
||||||
|
bool havePassword = true;
|
||||||
|
bool haveSSID = true;
|
||||||
|
bool wifiUp = false;
|
||||||
|
|
||||||
|
// We are server and should not sleep
|
||||||
|
wifi_set_sleep_type(NONE_SLEEP_T);
|
||||||
|
// connects to access point
|
||||||
|
|
||||||
|
const char *yourNetwork = "Your network ";
|
||||||
|
if (strncmp(yourNetwork, SSid, 13) == 0 || strncmp("", SSid, 13) == 0)
|
||||||
|
haveSSID = false;
|
||||||
|
if (strncmp(yourNetwork, password, 13) == 0 || strncmp("", password, 13) == 0)
|
||||||
|
havePassword = false;
|
||||||
|
|
||||||
|
if (haveSSID && havePassword) {
|
||||||
|
WiFi.mode(WIFI_STA);
|
||||||
|
WiFi.setAutoReconnect(true);
|
||||||
|
WiFi.begin(SSid, password);
|
||||||
|
while (WiFi.status() != WL_CONNECTED) {
|
||||||
|
Serial.print('.');
|
||||||
|
delay(500);
|
||||||
|
}
|
||||||
|
if (WiFi.status() == WL_CONNECTED) {
|
||||||
|
DIAG(F("Wifi STA IP %s"),WiFi.localIP().toString().c_str());
|
||||||
|
wifiUp = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!haveSSID) {
|
||||||
|
// prepare all strings
|
||||||
|
String strSSID("DCC_");
|
||||||
|
String strPass("PASS_");
|
||||||
|
String strMac = WiFi.macAddress();
|
||||||
|
strMac.remove(0,9);
|
||||||
|
strMac.replace(":","");
|
||||||
|
strMac.replace(":","");
|
||||||
|
strSSID.concat(strMac);
|
||||||
|
strPass.concat(strMac);
|
||||||
|
|
||||||
|
WiFi.mode(WIFI_AP);
|
||||||
|
if (WiFi.softAP(strSSID.c_str(),
|
||||||
|
havePassword ? password : strPass.c_str(),
|
||||||
|
channel, false, 8)) {
|
||||||
|
DIAG(F("Wifi AP SSID %s PASS %s"),strSSID.c_str(),havePassword ? password : strPass.c_str());
|
||||||
|
DIAG(F("Wifi AP IP %s"),WiFi.softAPIP().toString().c_str());
|
||||||
|
wifiUp = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!wifiUp) {
|
||||||
|
DIAG(F("Wifi all fail"));
|
||||||
|
// no idea to go on
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
server = new AsyncServer(port); // start listening on tcp port
|
||||||
|
|
||||||
|
server->onClient(&handleNewClient, server);
|
||||||
|
server->begin();
|
||||||
|
DIAG(F("Server up port %d"),port);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WifiESP::loop() {
|
||||||
|
AsyncClient *client = NULL;
|
||||||
|
// Do something with outboundRing
|
||||||
|
// call sendData
|
||||||
|
int clientId=outboundRing->peek();
|
||||||
|
if (clientId >= 0) {
|
||||||
|
if (clientId > clients.size()) {
|
||||||
|
// something is wrong with the ringbuffer position
|
||||||
|
outboundRing->info();
|
||||||
|
client = NULL;
|
||||||
|
} else {
|
||||||
|
client = clients[clientId];
|
||||||
|
}
|
||||||
|
// if (client != debugclient) {
|
||||||
|
// DIAG(F("new client pointer = %x from id %d"), client, clientId);
|
||||||
|
// debugclient = client;
|
||||||
|
// }
|
||||||
|
} else {
|
||||||
|
client = NULL;
|
||||||
|
}
|
||||||
|
if (clientId>=0 && client && client->connected() && client->canSend()) {
|
||||||
|
outboundRing->read();
|
||||||
|
int count=outboundRing->count();
|
||||||
|
//DIAG(F("Wifi reply client=%d, count=%d"), clientId,count);
|
||||||
|
{
|
||||||
|
char buffer[count+1];
|
||||||
|
for(int i=0;i<count;i++) {
|
||||||
|
int c = outboundRing->read();
|
||||||
|
if (c >= 0)
|
||||||
|
buffer[i] = (char)c;
|
||||||
|
else {
|
||||||
|
DIAG(F("Ringread fail at %d"),i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buffer[count]=0;
|
||||||
|
//DIAG(F("SEND:%s COUNT:%d"),buffer,count);
|
||||||
|
uint8_t tries = 3;
|
||||||
|
while (! sendData(client, buffer, count)) {
|
||||||
|
DIAG(F("senData fail"));
|
||||||
|
yield();
|
||||||
|
if (tries == 0) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef ESP_DEBUG
|
||||||
|
static unsigned long last = 0;
|
||||||
|
if (millis() - last > 60000) {
|
||||||
|
last = millis();
|
||||||
|
DIAG(F("+"));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
ESP.wdtFeed();
|
||||||
|
}
|
||||||
|
#endif //ESP_FAMILY
|
37
WifiESP.h
Normal file
37
WifiESP.h
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* © 2021, Harald Barth.
|
||||||
|
*
|
||||||
|
* This file is part of 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef WifiESP_h
|
||||||
|
#define WifiESP_h
|
||||||
|
|
||||||
|
#include "FSH.h"
|
||||||
|
|
||||||
|
class WifiESP
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
static bool setup(const char *wifiESSID,
|
||||||
|
const char *wifiPassword,
|
||||||
|
const char *hostname,
|
||||||
|
const int port,
|
||||||
|
const byte channel);
|
||||||
|
static void loop();
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
#endif
|
|
@ -44,7 +44,14 @@ The configuration file for DCC-EX Command Station
|
||||||
// |
|
// |
|
||||||
// +-----------------------v
|
// +-----------------------v
|
||||||
//
|
//
|
||||||
#define MOTOR_SHIELD_TYPE STANDARD_MOTOR_SHIELD
|
//#define MOTOR_SHIELD_TYPE STANDARD_MOTOR_SHIELD
|
||||||
|
|
||||||
|
#define ESP_MOTOR_SHIELD F("ESP"), \
|
||||||
|
new MotorDriver(D3, D5, UNUSED_PIN, UNUSED_PIN, UNUSED_PIN, 2.99, 2000, UNUSED_PIN),\
|
||||||
|
new MotorDriver(D2, D6, UNUSED_PIN, UNUSED_PIN, A0 , 2.99, 2000, UNUSED_PIN)
|
||||||
|
|
||||||
|
#define MOTOR_SHIELD_TYPE ESP_MOTOR_SHIELD
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// The IP port to talk to a WIFI or Ethernet shield.
|
// The IP port to talk to a WIFI or Ethernet shield.
|
||||||
|
@ -56,7 +63,7 @@ The configuration file for DCC-EX Command Station
|
||||||
// NOTE: Only supported on Arduino Mega
|
// NOTE: Only supported on Arduino Mega
|
||||||
// Set to false if you not even want it on the Arduino Mega
|
// Set to false if you not even want it on the Arduino Mega
|
||||||
//
|
//
|
||||||
#define ENABLE_WIFI true
|
//#define ENABLE_WIFI true
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
|
|
12
defines.h
12
defines.h
|
@ -35,12 +35,20 @@
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
#if defined (ARDUINO_ARCH_ESP8266)
|
||||||
|
#define ESP_FAMILY
|
||||||
|
//#define ESP_DEBUG
|
||||||
|
#define SLOW_ANALOG_READ
|
||||||
|
#endif
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// WIFI_ON: All prereqs for running with WIFI are met
|
// WIFI_ON: All prereqs for running with WIFI are met
|
||||||
// Note: WIFI_CHANNEL may not exist in early config.h files so is added here if needed.
|
// Note: WIFI_CHANNEL may not exist in early config.h files so is added here if needed.
|
||||||
|
|
||||||
#if (defined(ARDUINO_AVR_MEGA) || defined(ARDUINO_AVR_MEGA2560) || defined(ARDUINO_SAMD_ZERO) || defined(TEENSYDUINO)) || defined(ARDUINO_AVR_NANO_EVERY)
|
#if (defined(ARDUINO_AVR_MEGA) || defined(ARDUINO_AVR_MEGA2560) || defined(ARDUINO_SAMD_ZERO) || defined(TEENSYDUINO)) || defined(ARDUINO_AVR_NANO_EVERY) || defined (ESP_FAMILY))
|
||||||
#define BIG_RAM
|
#define BIG_RAM
|
||||||
#endif
|
#endif
|
||||||
#if ENABLE_WIFI
|
#if ENABLE_WIFI
|
||||||
|
@ -53,8 +61,6 @@
|
||||||
#define WIFI_WARNING
|
#define WIFI_WARNING
|
||||||
#define WIFI_ON false
|
#define WIFI_ON false
|
||||||
#endif
|
#endif
|
||||||
#else
|
|
||||||
#define WIFI_ON false
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if ENABLE_ETHERNET
|
#if ENABLE_ETHERNET
|
||||||
|
|
|
@ -28,6 +28,8 @@ extern "C" char* sbrk(int);
|
||||||
#elif defined(__AVR__)
|
#elif defined(__AVR__)
|
||||||
extern char *__brkval;
|
extern char *__brkval;
|
||||||
extern char *__malloc_heap_start;
|
extern char *__malloc_heap_start;
|
||||||
|
#elif defined(ARDUINO_ARCH_ESP8266)
|
||||||
|
// supported but nothing needed here
|
||||||
#else
|
#else
|
||||||
#error Unsupported board type
|
#error Unsupported board type
|
||||||
#endif
|
#endif
|
||||||
|
@ -35,7 +37,7 @@ extern char *__malloc_heap_start;
|
||||||
|
|
||||||
static volatile int minimum_free_memory = __INT_MAX__;
|
static volatile int minimum_free_memory = __INT_MAX__;
|
||||||
|
|
||||||
#if !defined(__IMXRT1062__)
|
#if !defined(__IMXRT1062__) && !defined(ARDUINO_ARCH_ESP8266)
|
||||||
static inline int freeMemory() {
|
static inline int freeMemory() {
|
||||||
char top;
|
char top;
|
||||||
#if defined(__arm__)
|
#if defined(__arm__)
|
||||||
|
@ -56,7 +58,18 @@ int minimumFreeMemory() {
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#elif defined(ARDUINO_ARCH_ESP8266)
|
||||||
|
// ESP8266
|
||||||
|
static inline int freeMemory() {
|
||||||
|
return ESP.getFreeHeap();
|
||||||
|
}
|
||||||
|
// Return low memory value.
|
||||||
|
int minimumFreeMemory() {
|
||||||
|
int retval = minimum_free_memory;
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
|
// All types of TEENSYs
|
||||||
#if defined(ARDUINO_TEENSY40)
|
#if defined(ARDUINO_TEENSY40)
|
||||||
static const unsigned DTCM_START = 0x20000000UL;
|
static const unsigned DTCM_START = 0x20000000UL;
|
||||||
static const unsigned OCRAM_START = 0x20200000UL;
|
static const unsigned OCRAM_START = 0x20200000UL;
|
||||||
|
@ -109,4 +122,3 @@ void updateMinimumFreeMemory(unsigned char extraBytes) {
|
||||||
if (spare < 0) spare = 0;
|
if (spare < 0) spare = 0;
|
||||||
if (spare < minimum_free_memory) minimum_free_memory = spare;
|
if (spare < minimum_free_memory) minimum_free_memory = spare;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user