mirror of
https://github.com/DCC-EX/CommandStation-EX.git
synced 2024-11-23 08:06:13 +01:00
Improved <D> commands
<D ACK 1|0> <D WIFI 1|0> <D WIT 1|0> <D CMD 1|0> <D CABS> <D RAM>
This commit is contained in:
parent
6bfa315443
commit
39d9defec6
44
DCC.cpp
44
DCC.cpp
|
@ -43,7 +43,6 @@ const byte FN_GROUP_5=0x10;
|
||||||
|
|
||||||
|
|
||||||
void DCC::begin(MotorDriver * mainDriver, MotorDriver* progDriver, byte timerNumber) {
|
void DCC::begin(MotorDriver * mainDriver, MotorDriver* progDriver, byte timerNumber) {
|
||||||
debugMode=false;
|
|
||||||
DCCWaveform::begin(mainDriver,progDriver, timerNumber);
|
DCCWaveform::begin(mainDriver,progDriver, timerNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -352,10 +351,6 @@ void DCC::forgetAllLocos() { // removes all speed reminders
|
||||||
for (int i=0;i<MAX_LOCOS;i++) speedTable[i].loco=0;
|
for (int i=0;i<MAX_LOCOS;i++) speedTable[i].loco=0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DCC::setDebug(bool on) {
|
|
||||||
debugMode=on;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte DCC::loopStatus=0;
|
byte DCC::loopStatus=0;
|
||||||
|
|
||||||
void DCC::loop() {
|
void DCC::loop() {
|
||||||
|
@ -483,7 +478,6 @@ byte DCC::ackManagerStash;
|
||||||
int DCC::ackManagerCv;
|
int DCC::ackManagerCv;
|
||||||
byte DCC::ackManagerBitNum;
|
byte DCC::ackManagerBitNum;
|
||||||
bool DCC::ackReceived;
|
bool DCC::ackReceived;
|
||||||
bool DCC::debugMode=false;
|
|
||||||
|
|
||||||
ACK_CALLBACK DCC::ackManagerCallback;
|
ACK_CALLBACK DCC::ackManagerCallback;
|
||||||
|
|
||||||
|
@ -525,37 +519,37 @@ void DCC::ackManagerLoop(bool blocking) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (checkResets(blocking, DCCWaveform::progTrack.autoPowerOff ? 20 : 3)) return;
|
if (checkResets(blocking, DCCWaveform::progTrack.autoPowerOff ? 20 : 3)) return;
|
||||||
DCCWaveform::progTrack.setAckBaseline(debugMode);
|
DCCWaveform::progTrack.setAckBaseline();
|
||||||
break;
|
break;
|
||||||
case W0: // write 0 bit
|
case W0: // write 0 bit
|
||||||
case W1: // write 1 bit
|
case W1: // write 1 bit
|
||||||
{
|
{
|
||||||
if (checkResets(blocking, RESET_MIN)) return;
|
if (checkResets(blocking, RESET_MIN)) return;
|
||||||
if (debugMode) DIAG(F("\nW%d cv=%d bit=%d"),opcode==W1, ackManagerCv,ackManagerBitNum);
|
if (Diag::ACK) DIAG(F("\nW%d cv=%d bit=%d"),opcode==W1, ackManagerCv,ackManagerBitNum);
|
||||||
byte instruction = WRITE_BIT | (opcode==W1 ? BIT_ON : BIT_OFF) | ackManagerBitNum;
|
byte instruction = WRITE_BIT | (opcode==W1 ? BIT_ON : BIT_OFF) | ackManagerBitNum;
|
||||||
byte message[] = {cv1(BIT_MANIPULATE, ackManagerCv), cv2(ackManagerCv), instruction };
|
byte message[] = {cv1(BIT_MANIPULATE, ackManagerCv), cv2(ackManagerCv), instruction };
|
||||||
DCCWaveform::progTrack.schedulePacket(message, sizeof(message), PROG_REPEATS);
|
DCCWaveform::progTrack.schedulePacket(message, sizeof(message), PROG_REPEATS);
|
||||||
DCCWaveform::progTrack.setAckPending(debugMode);
|
DCCWaveform::progTrack.setAckPending();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WB: // write byte
|
case WB: // write byte
|
||||||
{
|
{
|
||||||
if (checkResets(blocking, RESET_MIN)) return;
|
if (checkResets(blocking, RESET_MIN)) return;
|
||||||
if (debugMode) DIAG(F("\nWB cv=%d value=%d"),ackManagerCv,ackManagerByte);
|
if (Diag::ACK) DIAG(F("\nWB cv=%d value=%d"),ackManagerCv,ackManagerByte);
|
||||||
byte message[] = {cv1(WRITE_BYTE, ackManagerCv), cv2(ackManagerCv), ackManagerByte};
|
byte message[] = {cv1(WRITE_BYTE, ackManagerCv), cv2(ackManagerCv), ackManagerByte};
|
||||||
DCCWaveform::progTrack.schedulePacket(message, sizeof(message), PROG_REPEATS);
|
DCCWaveform::progTrack.schedulePacket(message, sizeof(message), PROG_REPEATS);
|
||||||
DCCWaveform::progTrack.setAckPending(debugMode);
|
DCCWaveform::progTrack.setAckPending();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VB: // Issue validate Byte packet
|
case VB: // Issue validate Byte packet
|
||||||
{
|
{
|
||||||
if (checkResets(blocking, RESET_MIN)) return;
|
if (checkResets(blocking, RESET_MIN)) return;
|
||||||
if (debugMode) DIAG(F("\nVB cv=%d value=%d"),ackManagerCv,ackManagerByte);
|
if (Diag::ACK) DIAG(F("\nVB cv=%d value=%d"),ackManagerCv,ackManagerByte);
|
||||||
byte message[] = { cv1(VERIFY_BYTE, ackManagerCv), cv2(ackManagerCv), ackManagerByte};
|
byte message[] = { cv1(VERIFY_BYTE, ackManagerCv), cv2(ackManagerCv), ackManagerByte};
|
||||||
DCCWaveform::progTrack.schedulePacket(message, sizeof(message), PROG_REPEATS);
|
DCCWaveform::progTrack.schedulePacket(message, sizeof(message), PROG_REPEATS);
|
||||||
DCCWaveform::progTrack.setAckPending(debugMode);
|
DCCWaveform::progTrack.setAckPending();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -563,11 +557,11 @@ void DCC::ackManagerLoop(bool blocking) {
|
||||||
case V1: // Issue validate bit=0 or bit=1 packet
|
case V1: // Issue validate bit=0 or bit=1 packet
|
||||||
{
|
{
|
||||||
if (checkResets(blocking, RESET_MIN)) return;
|
if (checkResets(blocking, RESET_MIN)) return;
|
||||||
if (debugMode) DIAG(F("\nV%d cv=%d bit=%d"),opcode==V1, ackManagerCv,ackManagerBitNum);
|
if (Diag::ACK) DIAG(F("\nV%d cv=%d bit=%d"),opcode==V1, ackManagerCv,ackManagerBitNum);
|
||||||
byte instruction = VERIFY_BIT | (opcode==V0?BIT_OFF:BIT_ON) | ackManagerBitNum;
|
byte instruction = VERIFY_BIT | (opcode==V0?BIT_OFF:BIT_ON) | ackManagerBitNum;
|
||||||
byte message[] = {cv1(BIT_MANIPULATE, ackManagerCv), cv2(ackManagerCv), instruction };
|
byte message[] = {cv1(BIT_MANIPULATE, ackManagerCv), cv2(ackManagerCv), instruction };
|
||||||
DCCWaveform::progTrack.schedulePacket(message, sizeof(message), PROG_REPEATS);
|
DCCWaveform::progTrack.schedulePacket(message, sizeof(message), PROG_REPEATS);
|
||||||
DCCWaveform::progTrack.setAckPending(debugMode);
|
DCCWaveform::progTrack.setAckPending();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -575,10 +569,10 @@ void DCC::ackManagerLoop(bool blocking) {
|
||||||
{
|
{
|
||||||
byte ackState=2; // keep polling
|
byte ackState=2; // keep polling
|
||||||
if (blocking) {
|
if (blocking) {
|
||||||
while(ackState==2) ackState=DCCWaveform::progTrack.getAck(debugMode);
|
while(ackState==2) ackState=DCCWaveform::progTrack.getAck();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ackState=DCCWaveform::progTrack.getAck(debugMode);
|
ackState=DCCWaveform::progTrack.getAck();
|
||||||
if (ackState==2) return; // keep polling
|
if (ackState==2) return; // keep polling
|
||||||
}
|
}
|
||||||
ackReceived=ackState==1;
|
ackReceived=ackState==1;
|
||||||
|
@ -672,6 +666,20 @@ void DCC::ackManagerLoop(bool blocking) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void DCC::callback(int value) {
|
void DCC::callback(int value) {
|
||||||
if (debugMode) DIAG(F("\nCallback(%d)\n"),value);
|
if (Diag::ACK) DIAG(F("\nCallback(%d)\n"),value);
|
||||||
(ackManagerCallback)( value);
|
(ackManagerCallback)( value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DCC::displayCabList(Print * stream) {
|
||||||
|
|
||||||
|
int used=0;
|
||||||
|
for (int reg = 0; reg < MAX_LOCOS; reg++) {
|
||||||
|
if (speedTable[reg].loco>0) {
|
||||||
|
used ++;
|
||||||
|
StringFormatter::send(stream,F("\ncab=%d, speed=%d, dir=%c "),
|
||||||
|
speedTable[reg].loco, speedTable[reg].speedCode & 0x7f,(speedTable[reg].speedCode & 0x80) ? 'F':'R');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
StringFormatter::send(stream,F("\nUsed=%d, max=%d\n"),used,MAX_LOCOS);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
4
DCC.h
4
DCC.h
|
@ -74,7 +74,6 @@ class DCC {
|
||||||
static void updateGroupflags(byte & flags, int functionNumber);
|
static void updateGroupflags(byte & flags, int functionNumber);
|
||||||
static void setAccessory(int aAdd, byte aNum, bool activate) ;
|
static void setAccessory(int aAdd, byte aNum, bool activate) ;
|
||||||
static bool writeTextPacket( byte *b, int nBytes);
|
static bool writeTextPacket( byte *b, int nBytes);
|
||||||
static void setDebug(bool on);
|
|
||||||
static void setProgTrackSyncMain(bool on); // when true, prog track becomes driveable
|
static void setProgTrackSyncMain(bool on); // when true, prog track becomes driveable
|
||||||
|
|
||||||
// ACKable progtrack calls bitresults callback 0,0 or -1, cv returns value or -1
|
// ACKable progtrack calls bitresults callback 0,0 or -1, cv returns value or -1
|
||||||
|
@ -88,7 +87,7 @@ class DCC {
|
||||||
// Enhanced API functions
|
// Enhanced API functions
|
||||||
static void forgetLoco(int cab); // removes any speed reminders for this loco
|
static void forgetLoco(int cab); // removes any speed reminders for this loco
|
||||||
static void forgetAllLocos(); // removes all speed reminders
|
static void forgetAllLocos(); // removes all speed reminders
|
||||||
|
static void displayCabList(Print * stream);
|
||||||
private:
|
private:
|
||||||
struct LOCO {
|
struct LOCO {
|
||||||
int loco;
|
int loco;
|
||||||
|
@ -108,7 +107,6 @@ private:
|
||||||
static int lookupSpeedTable(int locoId);
|
static int lookupSpeedTable(int locoId);
|
||||||
static void issueReminders();
|
static void issueReminders();
|
||||||
static void callback(int value);
|
static void callback(int value);
|
||||||
static bool debugMode;
|
|
||||||
|
|
||||||
// ACK MANAGER
|
// ACK MANAGER
|
||||||
static ackOp const * ackManagerProg;
|
static ackOp const * ackManagerProg;
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "Turnouts.h"
|
#include "Turnouts.h"
|
||||||
#include "Outputs.h"
|
#include "Outputs.h"
|
||||||
#include "Sensors.h"
|
#include "Sensors.h"
|
||||||
|
#include "freeMemory.h"
|
||||||
|
|
||||||
#include "EEStore.h"
|
#include "EEStore.h"
|
||||||
#include "DIAG.h"
|
#include "DIAG.h"
|
||||||
|
@ -35,6 +36,14 @@ const char VERSION[] PROGMEM ="0.1.9";
|
||||||
const int HASH_KEYWORD_PROG=-29718;
|
const int HASH_KEYWORD_PROG=-29718;
|
||||||
const int HASH_KEYWORD_MAIN=11339;
|
const int HASH_KEYWORD_MAIN=11339;
|
||||||
const int HASH_KEYWORD_JOIN=-30750;
|
const int HASH_KEYWORD_JOIN=-30750;
|
||||||
|
const int HASH_KEYWORD_CABS=-11981;
|
||||||
|
const int HASH_KEYWORD_RAM=25982;
|
||||||
|
const int HASH_KEYWORD_CMD=9962;
|
||||||
|
const int HASH_KEYWORD_WIT=31594;
|
||||||
|
const int HASH_KEYWORD_WIFI=-5583;
|
||||||
|
const int HASH_KEYWORD_ACK=3113;
|
||||||
|
const int HASH_KEYWORD_ON=2657;
|
||||||
|
const int HASH_KEYWORD_OFF=22479;
|
||||||
|
|
||||||
|
|
||||||
int DCCEXParser::stashP[MAX_PARAMS];
|
int DCCEXParser::stashP[MAX_PARAMS];
|
||||||
|
@ -50,7 +59,7 @@ bool DCCEXParser::stashBusy;
|
||||||
|
|
||||||
DCCEXParser::DCCEXParser() {}
|
DCCEXParser::DCCEXParser() {}
|
||||||
void DCCEXParser::flush() {
|
void DCCEXParser::flush() {
|
||||||
DIAG(F("\nBuffer flush"));
|
if (Diag::CMD) DIAG(F("\nBuffer flush"));
|
||||||
bufferLength=0;
|
bufferLength=0;
|
||||||
inCommandPayload=false;
|
inCommandPayload=false;
|
||||||
}
|
}
|
||||||
|
@ -133,7 +142,7 @@ void DCCEXParser::setFilter(FILTER_CALLBACK filter) {
|
||||||
|
|
||||||
// See documentation on DCC class for info on this section
|
// See documentation on DCC class for info on this section
|
||||||
void DCCEXParser::parse(Print * stream, byte *com, bool blocking) {
|
void DCCEXParser::parse(Print * stream, byte *com, bool blocking) {
|
||||||
DIAG(F("\nPARSING:%s\n"),com);
|
if (Diag::CMD) DIAG(F("\nPARSING:%s\n"),com);
|
||||||
(void) EEPROM; // tell compiler not to warn thi is unused
|
(void) EEPROM; // tell compiler not to warn thi is unused
|
||||||
int p[MAX_PARAMS];
|
int p[MAX_PARAMS];
|
||||||
while (com[0]=='<' || com[0]==' ') com++; // strip off any number of < or spaces
|
while (com[0]=='<' || com[0]==' ') com++; // strip off any number of < or spaces
|
||||||
|
@ -145,22 +154,35 @@ void DCCEXParser::parse(Print * stream, byte *com, bool blocking) {
|
||||||
// Functions return from this switch if complete, break from switch implies error <X> to send
|
// Functions return from this switch if complete, break from switch implies error <X> to send
|
||||||
switch(opcode) {
|
switch(opcode) {
|
||||||
case '\0': return; // filterCallback asked us to ignore
|
case '\0': return; // filterCallback asked us to ignore
|
||||||
case 't': // THROTTLE <t REGISTER CAB SPEED DIRECTION>
|
case 't': // THROTTLE <t [REGISTER] CAB SPEED DIRECTION>
|
||||||
{
|
{
|
||||||
if (params!=4) break;
|
int cab;
|
||||||
|
int tspeed;
|
||||||
|
int direction;
|
||||||
|
|
||||||
|
if (params==4) { // <t REGISTER CAB SPEED DIRECTION>
|
||||||
|
cab=p[1];
|
||||||
|
tspeed=p[2];
|
||||||
|
direction=p[3];
|
||||||
|
}
|
||||||
|
else if (params==3) { // <t CAB SPEED DIRECTION>
|
||||||
|
cab=p[0];
|
||||||
|
tspeed=p[1];
|
||||||
|
direction=p[2];
|
||||||
|
}
|
||||||
|
else break;
|
||||||
|
|
||||||
// Convert JMRI bizarre -1=emergency stop, 0-126 as speeds
|
// Convert JMRI bizarre -1=emergency stop, 0-126 as speeds
|
||||||
// to DCC 0=stop, 1= emergency stop, 2-127 speeds
|
// to DCC 0=stop, 1= emergency stop, 2-127 speeds
|
||||||
int tspeed=p[2];
|
|
||||||
if (tspeed>126 || tspeed<-1) break; // invalid JMRI speed code
|
if (tspeed>126 || tspeed<-1) break; // invalid JMRI speed code
|
||||||
if (tspeed<0) tspeed=1; // emergency stop DCC speed
|
if (tspeed<0) tspeed=1; // emergency stop DCC speed
|
||||||
else if (tspeed>0) tspeed++; // map 1-126 -> 2-127
|
else if (tspeed>0) tspeed++; // map 1-126 -> 2-127
|
||||||
if (p[1] == 0 && tspeed>1) break; // ignore broadcasts of speed>1
|
if (cab == 0 && tspeed>1) break; // ignore broadcasts of speed>1
|
||||||
|
|
||||||
if (p[3]<0 || p[3]>1) break; // invalid direction code
|
if (direction<0 || direction>1) break; // invalid direction code
|
||||||
|
|
||||||
DCC::setThrottle(p[1],tspeed,p[3]);
|
DCC::setThrottle(cab,tspeed,direction);
|
||||||
StringFormatter::send(stream,F("<T %d %d %d>"), p[0], p[2],p[3]);
|
if (params==4) StringFormatter::send(stream,F("<T %d %d %d>"), p[0], p[2],p[3]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case 'f': // FUNCTION <f CAB BYTE1 [BYTE2]>
|
case 'f': // FUNCTION <f CAB BYTE1 [BYTE2]>
|
||||||
|
@ -240,7 +262,6 @@ void DCCEXParser::parse(Print * stream, byte *com, bool blocking) {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
}
|
}
|
||||||
DIAG(F("\nUnexpected keyword hash=%d\n"),p[0]);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -278,8 +299,7 @@ void DCCEXParser::parse(Print * stream, byte *com, bool blocking) {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 'D': // < >
|
case 'D': // < >
|
||||||
DCC::setDebug(p[0]==1);
|
if (parseD(stream,params,p)) return;
|
||||||
DIAG(F("\nDCC DEBUG MODE %d"),p[0]==1);
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case '#': // NUMBER OF LOCOSLOTS <#>
|
case '#': // NUMBER OF LOCOSLOTS <#>
|
||||||
|
@ -287,7 +307,7 @@ void DCCEXParser::parse(Print * stream, byte *com, bool blocking) {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 'F': // New command to call the new Loco Function API <F cab func 1|0>
|
case 'F': // New command to call the new Loco Function API <F cab func 1|0>
|
||||||
DIAG(F("Setting loco %d F%d %S"),p[0],p[1],p[2]?F("ON"):F("OFF"));
|
if (Diag::CMD) DIAG(F("Setting loco %d F%d %S"),p[0],p[1],p[2]?F("ON"):F("OFF"));
|
||||||
DCC::setFn(p[0],p[1],p[2]==1);
|
DCC::setFn(p[0],p[1],p[2]==1);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -433,6 +453,40 @@ bool DCCEXParser::parseS( Print * stream,int params, int p[]) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DCCEXParser::parseD( Print * stream,int params, int p[]) {
|
||||||
|
if (params==0) return false;
|
||||||
|
bool onOff=p[1]==1 || p[1]==HASH_KEYWORD_ON; // dont care if other stuff or missing... just means off
|
||||||
|
switch(p[0]){
|
||||||
|
case HASH_KEYWORD_CABS: // <D CABS>
|
||||||
|
DCC::displayCabList(stream);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case HASH_KEYWORD_RAM: // <D RAM>
|
||||||
|
StringFormatter::send(stream,F("\nFree memory=%d\n"),freeMemory());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HASH_KEYWORD_ACK: // <D ACK ON/OFF>
|
||||||
|
Diag::ACK=onOff;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case HASH_KEYWORD_CMD: // <D CMD ON/OFF>
|
||||||
|
Diag::CMD=onOff;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case HASH_KEYWORD_WIFI: // <D WIFI ON/OFF>
|
||||||
|
Diag::WIFI=onOff;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case HASH_KEYWORD_WIT: // <D WIT ON/OFF>
|
||||||
|
Diag::WITHROTTLE=onOff;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default: // invalid/unknown
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// CALLBACKS must be static
|
// CALLBACKS must be static
|
||||||
bool DCCEXParser::stashCallback(Print * stream,int p[MAX_PARAMS]) {
|
bool DCCEXParser::stashCallback(Print * stream,int p[MAX_PARAMS]) {
|
||||||
|
|
|
@ -44,6 +44,7 @@ struct DCCEXParser
|
||||||
bool parseZ(Print * stream, int params, int p[]);
|
bool parseZ(Print * stream, int params, int p[]);
|
||||||
bool parseS(Print * stream, int params, int p[]);
|
bool parseS(Print * stream, int params, int p[]);
|
||||||
bool parsef(Print * stream, int params, int p[]);
|
bool parsef(Print * stream, int params, int p[]);
|
||||||
|
bool parseD(Print * stream, int params, int p[]);
|
||||||
|
|
||||||
|
|
||||||
static bool stashBusy;
|
static bool stashBusy;
|
||||||
|
|
|
@ -41,10 +41,9 @@ void DCCWaveform::begin(MotorDriver * mainDriver, MotorDriver * progDriver, byte
|
||||||
case 2: interruptTimer= &TimerB; break;
|
case 2: interruptTimer= &TimerB; break;
|
||||||
#ifndef ARDUINO_AVR_UNO
|
#ifndef ARDUINO_AVR_UNO
|
||||||
case 3: interruptTimer= &TimerC; break;
|
case 3: interruptTimer= &TimerC; break;
|
||||||
case 4: interruptTimer= &TimerD; break;
|
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
DIAG(F("\n\n *** Invalid Timer number %d requested. Only 1..4 valid. DCC will not work.*** \n\n"), timerNumber);
|
DIAG(F("\n\n *** Invalid Timer number %d requested. Only 1..3 valid. DCC will not work.*** \n\n"), timerNumber);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
interruptTimer->initialize();
|
interruptTimer->initialize();
|
||||||
|
@ -278,15 +277,14 @@ int DCCWaveform::getLastCurrent() {
|
||||||
// Operations applicable to PROG track ONLY.
|
// Operations applicable to PROG track ONLY.
|
||||||
// (yes I know I could have subclassed the main track but...)
|
// (yes I know I could have subclassed the main track but...)
|
||||||
|
|
||||||
void DCCWaveform::setAckBaseline(bool debug) {
|
void DCCWaveform::setAckBaseline() {
|
||||||
if (isMainTrack) return;
|
if (isMainTrack) return;
|
||||||
ackThreshold=motorDriver->getCurrentRaw() + (int)(65 / motorDriver->senseFactor);
|
ackThreshold=motorDriver->getCurrentRaw() + (int)(65 / motorDriver->senseFactor);
|
||||||
if (debug) DIAG(F("\nACK-BASELINE %d/%dmA"),ackThreshold,motorDriver->convertToMilliamps(ackThreshold));
|
if (Diag::ACK) DIAG(F("\nACK-BASELINE %d/%dmA"),ackThreshold,motorDriver->convertToMilliamps(ackThreshold));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DCCWaveform::setAckPending(bool debug) {
|
void DCCWaveform::setAckPending() {
|
||||||
if (isMainTrack) return;
|
if (isMainTrack) return;
|
||||||
(void)debug;
|
|
||||||
ackMaxCurrent=0;
|
ackMaxCurrent=0;
|
||||||
ackPulseStart=0;
|
ackPulseStart=0;
|
||||||
ackPulseDuration=0;
|
ackPulseDuration=0;
|
||||||
|
@ -295,9 +293,9 @@ void DCCWaveform::setAckPending(bool debug) {
|
||||||
ackPending=true; // interrupt routines will now take note
|
ackPending=true; // interrupt routines will now take note
|
||||||
}
|
}
|
||||||
|
|
||||||
byte DCCWaveform::getAck(bool debug) {
|
byte DCCWaveform::getAck() {
|
||||||
if (ackPending) return (2); // still waiting
|
if (ackPending) return (2); // still waiting
|
||||||
if (debug) DIAG(F("\nACK-%S after %dmS max=%d/%dmA pulse=%duS"),ackDetected?F("OK"):F("FAIL"), ackCheckDuration,
|
if (Diag::ACK) DIAG(F("\nACK-%S after %dmS max=%d/%dmA pulse=%duS"),ackDetected?F("OK"):F("FAIL"), ackCheckDuration,
|
||||||
ackMaxCurrent,motorDriver->convertToMilliamps(ackMaxCurrent), ackPulseDuration);
|
ackMaxCurrent,motorDriver->convertToMilliamps(ackMaxCurrent), ackPulseDuration);
|
||||||
if (ackDetected) return (1); // Yes we had an ack
|
if (ackDetected) return (1); // Yes we had an ack
|
||||||
return(0); // pending set off but not detected means no ACK.
|
return(0); // pending set off but not detected means no ACK.
|
||||||
|
|
|
@ -62,9 +62,9 @@ class DCCWaveform {
|
||||||
volatile bool packetPending;
|
volatile bool packetPending;
|
||||||
volatile byte sentResetsSincePacket;
|
volatile byte sentResetsSincePacket;
|
||||||
volatile bool autoPowerOff=false;
|
volatile bool autoPowerOff=false;
|
||||||
void setAckBaseline(bool debug); //prog track only
|
void setAckBaseline(); //prog track only
|
||||||
void setAckPending(bool debug); //prog track only
|
void setAckPending(); //prog track only
|
||||||
byte getAck(bool debug); //prog track only 0=NACK, 1=ACK 2=keep waiting
|
byte getAck(); //prog track only 0=NACK, 1=ACK 2=keep waiting
|
||||||
static bool progTrackSyncMain; // true when prog track is a siding switched to main
|
static bool progTrackSyncMain; // true when prog track is a siding switched to main
|
||||||
inline void doAutoPowerOff() {
|
inline void doAutoPowerOff() {
|
||||||
if (autoPowerOff) {
|
if (autoPowerOff) {
|
||||||
|
|
|
@ -31,6 +31,11 @@
|
||||||
#define __FlashStringHelper char
|
#define __FlashStringHelper char
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
bool Diag::ACK=false;
|
||||||
|
bool Diag::CMD=false;
|
||||||
|
bool Diag::WIFI=false;
|
||||||
|
bool Diag::WITHROTTLE=false;
|
||||||
|
|
||||||
|
|
||||||
void StringFormatter::diag( const __FlashStringHelper* input...) {
|
void StringFormatter::diag( const __FlashStringHelper* input...) {
|
||||||
if (!diagSerial) return;
|
if (!diagSerial) return;
|
||||||
|
|
|
@ -27,6 +27,14 @@
|
||||||
#define __FlashStringHelper char
|
#define __FlashStringHelper char
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
class Diag {
|
||||||
|
public:
|
||||||
|
static bool ACK;
|
||||||
|
static bool CMD;
|
||||||
|
static bool WIFI;
|
||||||
|
static bool WITHROTTLE;
|
||||||
|
};
|
||||||
|
|
||||||
class StringFormatter
|
class StringFormatter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -74,7 +74,7 @@ bool WiThrottle::areYouUsingThrottle(int cab) {
|
||||||
// One instance of WiThrottle per connected client, so we know what the locos are
|
// One instance of WiThrottle per connected client, so we know what the locos are
|
||||||
|
|
||||||
WiThrottle::WiThrottle( int wificlientid) {
|
WiThrottle::WiThrottle( int wificlientid) {
|
||||||
DIAG(F("\nCreating new WiThrottle for client %d\n"),wificlientid);
|
if (Diag::WITHROTTLE) DIAG(F("\nCreating new WiThrottle for client %d\n"),wificlientid);
|
||||||
nextThrottle=firstThrottle;
|
nextThrottle=firstThrottle;
|
||||||
firstThrottle= this;
|
firstThrottle= this;
|
||||||
clientid=wificlientid;
|
clientid=wificlientid;
|
||||||
|
@ -110,7 +110,7 @@ void WiThrottle::parse(Print & stream, byte * cmdx) {
|
||||||
byte * cmd=local;
|
byte * cmd=local;
|
||||||
|
|
||||||
heartBeat=millis();
|
heartBeat=millis();
|
||||||
// DIAG(F("\nWiThrottle(%d)<-[%e]\n"),clientid, cmd);
|
if (Diag::WITHROTTLE) DIAG(F("\nWiThrottle(%d)<-[%e]\n"),clientid, cmd);
|
||||||
|
|
||||||
if (initSent) {
|
if (initSent) {
|
||||||
// Send power state if different than last sent
|
// Send power state if different than last sent
|
||||||
|
@ -187,7 +187,7 @@ void WiThrottle::parse(Print & 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DIAG(F("WiThrottle(%d) Quit\n"), clientid);
|
if (Diag::WITHROTTLE) DIAG(F("WiThrottle(%d) Quit\n"), clientid);
|
||||||
delete this;
|
delete this;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -345,10 +345,10 @@ void WiThrottle::loop() {
|
||||||
void WiThrottle::checkHeartbeat() {
|
void WiThrottle::checkHeartbeat() {
|
||||||
// if 2 heartbeats missed... drop connection and eStop any locos still assigned to this client
|
// if 2 heartbeats missed... drop connection and eStop any locos still assigned to this client
|
||||||
if(heartBeatEnable && (millis()-heartBeat > HEARTBEAT_TIMEOUT*2000)) {
|
if(heartBeatEnable && (millis()-heartBeat > HEARTBEAT_TIMEOUT*2000)) {
|
||||||
DIAG(F("\n\nWiThrottle(%d) hearbeat missed, dropping connection\n\n"),clientid);
|
if (Diag::WITHROTTLE) DIAG(F("\n\nWiThrottle(%d) hearbeat missed, dropping connection\n\n"),clientid);
|
||||||
LOOPLOCOS('*', -1) {
|
LOOPLOCOS('*', -1) {
|
||||||
if (myLocos[loco].throttle!='\0') {
|
if (myLocos[loco].throttle!='\0') {
|
||||||
DIAG(F(" eStopping cab %d\n"), myLocos[loco].cab);
|
if (Diag::WITHROTTLE) DIAG(F(" eStopping cab %d\n"), myLocos[loco].cab);
|
||||||
DCC::setThrottle(myLocos[loco].cab, 1, DCC::getThrottleDirection(myLocos[loco].cab)); // speed 1 is eStop
|
DCC::setThrottle(myLocos[loco].cab, 1, DCC::getThrottleDirection(myLocos[loco].cab)); // speed 1 is eStop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -231,7 +231,7 @@ void WifiInterface::loop() {
|
||||||
int ch = wifiStream->read();
|
int ch = wifiStream->read();
|
||||||
|
|
||||||
// echo the char to the diagnostic stream in escaped format
|
// echo the char to the diagnostic stream in escaped format
|
||||||
StringFormatter::printEscape(ch); // DIAG in disguise
|
if (Diag::WIFI) StringFormatter::printEscape(ch); // DIAG in disguise
|
||||||
|
|
||||||
switch (loopstate) {
|
switch (loopstate) {
|
||||||
case 0: // looking for +IPD
|
case 0: // looking for +IPD
|
||||||
|
@ -272,7 +272,7 @@ void WifiInterface::loop() {
|
||||||
|
|
||||||
case 10: // Waiting for > so we can send reply
|
case 10: // Waiting for > so we can send reply
|
||||||
if (millis() - loopTimeoutStart > LOOP_TIMEOUT) {
|
if (millis() - loopTimeoutStart > LOOP_TIMEOUT) {
|
||||||
DIAG(F("\nWifi TIMEOUT on wait for > prompt or ERROR\n"));
|
if (Diag::WIFI) DIAG(F("\nWifi TIMEOUT on wait for > prompt or ERROR\n"));
|
||||||
loopstate = 0; // go back to +IPD
|
loopstate = 0; // go back to +IPD
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -290,12 +290,12 @@ void WifiInterface::loop() {
|
||||||
break;
|
break;
|
||||||
case 11: // Waiting for SEND OK or ERROR to complete so we can closeAfter
|
case 11: // Waiting for SEND OK or ERROR to complete so we can closeAfter
|
||||||
if (millis() - loopTimeoutStart > LOOP_TIMEOUT) {
|
if (millis() - loopTimeoutStart > LOOP_TIMEOUT) {
|
||||||
DIAG(F("\nWifi TIMEOUT on wait for SEND OK or ERROR\n"));
|
if (Diag::WIFI) DIAG(F("\nWifi TIMEOUT on wait for SEND OK or ERROR\n"));
|
||||||
loopstate = 0; // go back to +IPD
|
loopstate = 0; // go back to +IPD
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (ch == 'K') { // assume its in SEND OK
|
if (ch == 'K') { // assume its in SEND OK
|
||||||
DIAG(F("\n Wifi AT+CIPCLOSE=%d\r\n"), connectionId);
|
if (Diag::WIFI) DIAG(F("\n Wifi AT+CIPCLOSE=%d\r\n"), connectionId);
|
||||||
StringFormatter::send(wifiStream, F("AT+CIPCLOSE=%d\r\n"), connectionId);
|
StringFormatter::send(wifiStream, F("AT+CIPCLOSE=%d\r\n"), connectionId);
|
||||||
loopstate = 0; // wait for +IPD
|
loopstate = 0; // wait for +IPD
|
||||||
}
|
}
|
||||||
|
@ -303,12 +303,12 @@ void WifiInterface::loop() {
|
||||||
|
|
||||||
case 12: // Waiting for OK after send busy
|
case 12: // Waiting for OK after send busy
|
||||||
if (ch == '+') { // Uh-oh IPD problem
|
if (ch == '+') { // Uh-oh IPD problem
|
||||||
DIAG(F("\n\n Wifi ASYNC CLASH - LOST REPLY\n"));
|
if (Diag::WIFI) DIAG(F("\n\n Wifi ASYNC CLASH - LOST REPLY\n"));
|
||||||
connectionId = 0;
|
connectionId = 0;
|
||||||
loopstate = 1;
|
loopstate = 1;
|
||||||
}
|
}
|
||||||
if (ch == 'K') { // assume its in SEND OK
|
if (ch == 'K') { // assume its in SEND OK
|
||||||
DIAG(F("\n\n Wifi BUSY RETRYING.. AT+CIPSEND=%d,%d\r\n"), connectionId, streamer.available());
|
if (Diag::WIFI) DIAG(F("\n\n Wifi BUSY RETRYING.. AT+CIPSEND=%d,%d\r\n"), connectionId, streamer.available());
|
||||||
StringFormatter::send(wifiStream, F("AT+CIPSEND=%d,%d\r\n"), connectionId, streamer.available());
|
StringFormatter::send(wifiStream, F("AT+CIPSEND=%d,%d\r\n"), connectionId, streamer.available());
|
||||||
loopTimeoutStart = millis();
|
loopTimeoutStart = millis();
|
||||||
loopstate = 10; // non-blocking loop waits for > before sending
|
loopstate = 10; // non-blocking loop waits for > before sending
|
||||||
|
@ -321,7 +321,7 @@ void WifiInterface::loop() {
|
||||||
|
|
||||||
// AT this point we have read an incoming message into the buffer
|
// AT this point we have read an incoming message into the buffer
|
||||||
|
|
||||||
DIAG(F("\n%l Wifi(%d)<-[%e]\n"), millis(),connectionId, buffer);
|
if (Diag::WIFI) DIAG(F("\n%l Wifi(%d)<-[%e]\n"), millis(),connectionId, buffer);
|
||||||
streamer.setBufferContentPosition(0, 0); // reset write position to start of buffer
|
streamer.setBufferContentPosition(0, 0); // reset write position to start of buffer
|
||||||
// SIDE EFFECT WARNING:::
|
// SIDE EFFECT WARNING:::
|
||||||
// We know that parser will read the entire buffer before starting to write to it.
|
// We know that parser will read the entire buffer before starting to write to it.
|
||||||
|
@ -345,7 +345,7 @@ void WifiInterface::loop() {
|
||||||
if (streamer.available() == 0) {
|
if (streamer.available() == 0) {
|
||||||
// No reply
|
// No reply
|
||||||
if (closeAfter) {
|
if (closeAfter) {
|
||||||
DIAG(F("AT+CIPCLOSE=%d\r\n"), connectionId);
|
if (Diag::WIFI) DIAG(F("AT+CIPCLOSE=%d\r\n"), connectionId);
|
||||||
StringFormatter::send(wifiStream, F("AT+CIPCLOSE=%d\r\n"), connectionId);
|
StringFormatter::send(wifiStream, F("AT+CIPCLOSE=%d\r\n"), connectionId);
|
||||||
}
|
}
|
||||||
loopstate = 0; // go back to waiting for +IPD
|
loopstate = 0; // go back to waiting for +IPD
|
||||||
|
@ -353,8 +353,8 @@ void WifiInterface::loop() {
|
||||||
}
|
}
|
||||||
// prepare to send reply
|
// prepare to send reply
|
||||||
buffer[streamer.available()]='\0'; // mark end of buffer, so it can be used as a string later
|
buffer[streamer.available()]='\0'; // mark end of buffer, so it can be used as a string later
|
||||||
DIAG(F("%l WiFi(%d)->[%e] l(%d)\n"), millis(), connectionId, buffer, streamer.available());
|
if (Diag::WIFI) DIAG(F("%l WiFi(%d)->[%e] l(%d)\n"), millis(), connectionId, buffer, streamer.available());
|
||||||
DIAG(F("AT+CIPSEND=%d,%d\r\n"), connectionId, streamer.available());
|
if (Diag::WIFI) DIAG(F("AT+CIPSEND=%d,%d\r\n"), connectionId, streamer.available());
|
||||||
StringFormatter::send(wifiStream, F("AT+CIPSEND=%d,%d\r\n"), connectionId, streamer.available());
|
StringFormatter::send(wifiStream, F("AT+CIPSEND=%d,%d\r\n"), connectionId, streamer.available());
|
||||||
loopTimeoutStart = millis();
|
loopTimeoutStart = millis();
|
||||||
loopstate = 10; // non-blocking loop waits for > before sending
|
loopstate = 10; // non-blocking loop waits for > before sending
|
||||||
|
|
Loading…
Reference in New Issue
Block a user