mirror of
https://github.com/DCC-EX/CommandStation-EX.git
synced 2025-04-01 19:20:12 +02:00
Merge branch 'ServoSignal' into TrackManager
This commit is contained in:
commit
9273265036
115
EXRAIL2.cpp
115
EXRAIL2.cpp
@ -64,6 +64,9 @@ const int16_t HASH_KEYWORD_RESUME=27609;
|
|||||||
const int16_t HASH_KEYWORD_KILL=5218;
|
const int16_t HASH_KEYWORD_KILL=5218;
|
||||||
const int16_t HASH_KEYWORD_ALL=3457;
|
const int16_t HASH_KEYWORD_ALL=3457;
|
||||||
const int16_t HASH_KEYWORD_ROUTES=-3702;
|
const int16_t HASH_KEYWORD_ROUTES=-3702;
|
||||||
|
const int16_t HASH_KEYWORD_RED=26099;
|
||||||
|
const int16_t HASH_KEYWORD_AMBER=18713;
|
||||||
|
const int16_t HASH_KEYWORD_GREEN=-31493;
|
||||||
|
|
||||||
// One instance of RMFT clas is used for each "thread" in the automation.
|
// One instance of RMFT clas is used for each "thread" in the automation.
|
||||||
// Each thread manages a loco on a journey through the layout, and/or may manage a scenery automation.
|
// Each thread manages a loco on a journey through the layout, and/or may manage a scenery automation.
|
||||||
@ -407,6 +410,18 @@ bool RMFT2::parseSlash(Print * stream, byte & paramCount, int16_t p[]) {
|
|||||||
setFlag(p[1], 0, LATCH_FLAG);
|
setFlag(p[1], 0, LATCH_FLAG);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
case HASH_KEYWORD_RED:
|
||||||
|
doSignal(p[1],SIGNAL_RED);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case HASH_KEYWORD_AMBER:
|
||||||
|
doSignal(p[1],SIGNAL_AMBER);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case HASH_KEYWORD_GREEN:
|
||||||
|
doSignal(p[1],SIGNAL_GREEN);
|
||||||
|
return true;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -508,24 +523,17 @@ bool RMFT2::skipIfBlock() {
|
|||||||
while (nest > 0) {
|
while (nest > 0) {
|
||||||
SKIPOP;
|
SKIPOP;
|
||||||
byte opcode = GET_OPCODE;
|
byte opcode = GET_OPCODE;
|
||||||
switch(opcode) {
|
// all other IF type commands increase the nesting level
|
||||||
|
if (opcode>IF_TYPE_OPCODES) nest++;
|
||||||
|
else switch(opcode) {
|
||||||
case OPCODE_ENDEXRAIL:
|
case OPCODE_ENDEXRAIL:
|
||||||
kill(F("missing ENDIF"), nest);
|
kill(F("missing ENDIF"), nest);
|
||||||
return false;
|
return false;
|
||||||
case OPCODE_IF:
|
|
||||||
case OPCODE_IFCLOSED:
|
|
||||||
case OPCODE_IFGTE:
|
|
||||||
case OPCODE_IFLT:
|
|
||||||
case OPCODE_IFNOT:
|
|
||||||
case OPCODE_IFRANDOM:
|
|
||||||
case OPCODE_IFRESERVE:
|
|
||||||
case OPCODE_IFTHROWN:
|
|
||||||
case OPCODE_IFTIMEOUT:
|
|
||||||
nest++;
|
|
||||||
break;
|
|
||||||
case OPCODE_ENDIF:
|
case OPCODE_ENDIF:
|
||||||
nest--;
|
nest--;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPCODE_ELSE:
|
case OPCODE_ELSE:
|
||||||
// if nest==1 then this is the ELSE for the IF we are skipping
|
// if nest==1 then this is the ELSE for the IF we are skipping
|
||||||
if (nest==1) nest=0; // cause loop exit and return after ELSE
|
if (nest==1) nest=0; // cause loop exit and return after ELSE
|
||||||
@ -557,6 +565,10 @@ void RMFT2::loop2() {
|
|||||||
|
|
||||||
byte opcode = GET_OPCODE;
|
byte opcode = GET_OPCODE;
|
||||||
int16_t operand = GET_OPERAND(0);
|
int16_t operand = GET_OPERAND(0);
|
||||||
|
|
||||||
|
// skipIf will get set to indicate a failing IF condition
|
||||||
|
bool skipIf=false;
|
||||||
|
|
||||||
// if (diag) DIAG(F("RMFT2 %d %d"),opcode,operand);
|
// if (diag) DIAG(F("RMFT2 %d %d"),opcode,operand);
|
||||||
// Attention: Returning from this switch leaves the program counter unchanged.
|
// Attention: Returning from this switch leaves the program counter unchanged.
|
||||||
// This is used for unfinished waits for timers or sensors.
|
// This is used for unfinished waits for timers or sensors.
|
||||||
@ -643,7 +655,7 @@ void RMFT2::loop2() {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
case OPCODE_IFTIMEOUT: // do next operand if timeout flag set
|
case OPCODE_IFTIMEOUT: // do next operand if timeout flag set
|
||||||
if (!timeoutFlag) if (!skipIfBlock()) return;
|
skipIf=!timeoutFlag;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPCODE_AFTER: // waits for sensor to hit and then remain off for 0.5 seconds. (must come after an AT operation)
|
case OPCODE_AFTER: // waits for sensor to hit and then remain off for 0.5 seconds. (must come after an AT operation)
|
||||||
@ -704,40 +716,52 @@ void RMFT2::loop2() {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case OPCODE_IF: // do next operand if sensor set
|
case OPCODE_IF: // do next operand if sensor set
|
||||||
if (!readSensor(operand)) if (!skipIfBlock()) return;
|
skipIf=!readSensor(operand);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPCODE_ELSE: // skip to matching ENDIF
|
case OPCODE_ELSE: // skip to matching ENDIF
|
||||||
if (!skipIfBlock()) return;
|
skipIf=true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPCODE_IFGTE: // do next operand if sensor>= value
|
case OPCODE_IFGTE: // do next operand if sensor>= value
|
||||||
if (IODevice::readAnalogue(operand)<(int)(GET_OPERAND(1))) if (!skipIfBlock()) return;
|
skipIf=IODevice::readAnalogue(operand)<(int)(GET_OPERAND(1));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPCODE_IFLT: // do next operand if sensor< value
|
case OPCODE_IFLT: // do next operand if sensor< value
|
||||||
if (IODevice::readAnalogue(operand)>=(int)(GET_OPERAND(1))) if (!skipIfBlock()) return;
|
skipIf=IODevice::readAnalogue(operand)>=(int)(GET_OPERAND(1));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPCODE_IFNOT: // do next operand if sensor not set
|
case OPCODE_IFNOT: // do next operand if sensor not set
|
||||||
if (readSensor(operand)) if (!skipIfBlock()) return;
|
skipIf=readSensor(operand);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPCODE_IFRANDOM: // do block on random percentage
|
case OPCODE_IFRANDOM: // do block on random percentage
|
||||||
if ((int16_t)random(100)>=operand) if (!skipIfBlock()) return;
|
skipIf=(int16_t)random(100)>=operand;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPCODE_IFRESERVE: // do block if we successfully RERSERVE
|
case OPCODE_IFRESERVE: // do block if we successfully RERSERVE
|
||||||
if (!getFlag(operand,SECTION_FLAG)) setFlag(operand,SECTION_FLAG);
|
if (!getFlag(operand,SECTION_FLAG)) setFlag(operand,SECTION_FLAG);
|
||||||
else if (!skipIfBlock()) return;
|
else skipIf=true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPCODE_IFRED: // do block if signal as expected
|
||||||
|
skipIf=!isSignal(operand,SIGNAL_RED);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPCODE_IFAMBER: // do block if signal as expected
|
||||||
|
skipIf=!isSignal(operand,SIGNAL_AMBER);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPCODE_IFGREEN: // do block if signal as expected
|
||||||
|
skipIf=!isSignal(operand,SIGNAL_GREEN);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPCODE_IFTHROWN:
|
case OPCODE_IFTHROWN:
|
||||||
if (Turnout::isClosed(operand)) if (!skipIfBlock()) return;
|
skipIf=Turnout::isClosed(operand);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPCODE_IFCLOSED:
|
case OPCODE_IFCLOSED:
|
||||||
if (!Turnout::isClosed(operand)) if (!skipIfBlock()) return;
|
skipIf=Turnout::isThrown(operand);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPCODE_ENDIF:
|
case OPCODE_ENDIF:
|
||||||
@ -760,15 +784,15 @@ void RMFT2::loop2() {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case OPCODE_RED:
|
case OPCODE_RED:
|
||||||
doSignal(operand,true,false,false);
|
doSignal(operand,SIGNAL_RED);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPCODE_AMBER:
|
case OPCODE_AMBER:
|
||||||
doSignal(operand,false,true,false);
|
doSignal(operand,SIGNAL_AMBER);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPCODE_GREEN:
|
case OPCODE_GREEN:
|
||||||
doSignal(operand,false,false,true);
|
doSignal(operand,SIGNAL_GREEN);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPCODE_FON:
|
case OPCODE_FON:
|
||||||
@ -936,6 +960,8 @@ void RMFT2::loop2() {
|
|||||||
kill(F("INVOP"),operand);
|
kill(F("INVOP"),operand);
|
||||||
}
|
}
|
||||||
// Falling out of the switch means move on to the next opcode
|
// Falling out of the switch means move on to the next opcode
|
||||||
|
// but if we are skipping a false IF or else
|
||||||
|
if (skipIf) if (!skipIfBlock()) return;
|
||||||
SKIPOP;
|
SKIPOP;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -963,22 +989,32 @@ void RMFT2::kill(const FSH * reason, int operand) {
|
|||||||
delete this;
|
delete this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ void RMFT2::doSignal(VPIN id,bool red, bool amber, bool green) {
|
int16_t RMFT2::getSignalSlot(VPIN id) {
|
||||||
//if (diag) DIAG(F(" dosignal %d"),id);
|
|
||||||
for (int sigpos=0;;sigpos+=4) {
|
for (int sigpos=0;;sigpos+=4) {
|
||||||
//if (diag) DIAG(F("red=%d"),redpin);
|
|
||||||
VPIN sigid=GETFLASHW(RMFT2::SignalDefinitions+sigpos);
|
VPIN sigid=GETFLASHW(RMFT2::SignalDefinitions+sigpos);
|
||||||
if (sigid==0) { // end of signal list
|
if (sigid==0) { // end of signal list
|
||||||
DIAG(F("EXRAIL Signal %d not defined"), id);
|
DIAG(F("EXRAIL Signal %d not defined"), id);
|
||||||
return; // signal not found
|
return -1;
|
||||||
}
|
}
|
||||||
// sigid is the signal id used in RED/AMBER/GREEN macro
|
// sigid is the signal id used in RED/AMBER/GREEN macro
|
||||||
// for a LED signal it will be same as redpin
|
// for a LED signal it will be same as redpin
|
||||||
// but for a servo signal it will also have SERVO_SIGNAL_FLAG set.
|
// but for a servo signal it will also have SERVO_SIGNAL_FLAG set.
|
||||||
|
|
||||||
if ((sigid & ~SERVO_SIGNAL_FLAG & ~ACTIVE_HIGH_SIGNAL_FLAG)!= id) continue; // keep looking
|
if ((sigid & ~SERVO_SIGNAL_FLAG & ~ACTIVE_HIGH_SIGNAL_FLAG)!= id) continue; // keep looking
|
||||||
|
return sigpos/4; // relative slot in signals table
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* static */ void RMFT2::doSignal(VPIN id,char rag) {
|
||||||
|
//if (diag) DIAG(F(" dosignal %d %x"),id,rag);
|
||||||
|
int16_t sigslot=getSignalSlot(id);
|
||||||
|
if (sigslot<0) return;
|
||||||
|
|
||||||
|
// keep track of signal state
|
||||||
|
setFlag(sigslot,rag,SIGNAL_MASK);
|
||||||
|
|
||||||
// Correct signal definition found, get the rag values
|
// Correct signal definition found, get the rag values
|
||||||
|
int16_t sigpos=sigslot*4;
|
||||||
|
VPIN sigid=GETFLASHW(RMFT2::SignalDefinitions+sigpos);
|
||||||
VPIN redpin=GETFLASHW(RMFT2::SignalDefinitions+sigpos+1);
|
VPIN redpin=GETFLASHW(RMFT2::SignalDefinitions+sigpos+1);
|
||||||
VPIN amberpin=GETFLASHW(RMFT2::SignalDefinitions+sigpos+2);
|
VPIN amberpin=GETFLASHW(RMFT2::SignalDefinitions+sigpos+2);
|
||||||
VPIN greenpin=GETFLASHW(RMFT2::SignalDefinitions+sigpos+3);
|
VPIN greenpin=GETFLASHW(RMFT2::SignalDefinitions+sigpos+3);
|
||||||
@ -987,27 +1023,30 @@ void RMFT2::kill(const FSH * reason, int operand) {
|
|||||||
if (sigid & SERVO_SIGNAL_FLAG) {
|
if (sigid & SERVO_SIGNAL_FLAG) {
|
||||||
// A servo signal, the pin numbers are actually servo positions
|
// A servo signal, the pin numbers are actually servo positions
|
||||||
// Note, setting a signal to a zero position has no effect.
|
// Note, setting a signal to a zero position has no effect.
|
||||||
int16_t servopos= red? redpin: (green? greenpin : amberpin);
|
int16_t servopos= rag==SIGNAL_RED? redpin: (rag==SIGNAL_GREEN? greenpin : amberpin);
|
||||||
if (servopos!=0) IODevice::writeAnalogue(id,servopos,PCA9685::Bounce);
|
if (servopos!=0) IODevice::writeAnalogue(id,servopos,PCA9685::Bounce);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// LED or similar 3 pin signal
|
// LED or similar 3 pin signal
|
||||||
// If amberpin is zero, synthesise amber from red+green
|
// If amberpin is zero, synthesise amber from red+green
|
||||||
if (amber && (amberpin==0)) {
|
const byte SIMAMBER=0x00;
|
||||||
red=true;
|
if (rag==SIGNAL_AMBER && (amberpin==0)) rag=SIMAMBER; // special case this func only
|
||||||
green=true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Manage invert (HIGH on) pins
|
// Manage invert (HIGH on) pins
|
||||||
bool aHigh=sigid & ACTIVE_HIGH_SIGNAL_FLAG;
|
bool aHigh=sigid & ACTIVE_HIGH_SIGNAL_FLAG;
|
||||||
|
|
||||||
// set the three pins
|
// set the three pins
|
||||||
if (redpin) IODevice::write(redpin,red^aHigh);
|
if (redpin) IODevice::write(redpin,(rag==SIGNAL_RED || rag==SIMAMBER)^aHigh);
|
||||||
if (amberpin) IODevice::write(amberpin,amber^aHigh);
|
if (amberpin) IODevice::write(amberpin,(rag==SIGNAL_AMBER)^aHigh);
|
||||||
if (greenpin) IODevice::write(greenpin,green^aHigh);
|
if (greenpin) IODevice::write(greenpin,(rag==SIGNAL_GREEN || rag==SIMAMBER)^aHigh);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* static */ bool RMFT2::isSignal(VPIN id,char rag) {
|
||||||
|
int16_t sigslot=getSignalSlot(id);
|
||||||
|
if (sigslot<0) return false;
|
||||||
|
return (flags[sigslot] & SIGNAL_MASK) == rag;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RMFT2::turnoutEvent(int16_t turnoutId, bool closed) {
|
void RMFT2::turnoutEvent(int16_t turnoutId, bool closed) {
|
||||||
|
33
EXRAIL2.h
33
EXRAIL2.h
@ -35,10 +35,9 @@ enum OPCODE : byte {OPCODE_THROW,OPCODE_CLOSE,
|
|||||||
OPCODE_RESERVE,OPCODE_FREE,
|
OPCODE_RESERVE,OPCODE_FREE,
|
||||||
OPCODE_AT,OPCODE_AFTER,OPCODE_AUTOSTART,
|
OPCODE_AT,OPCODE_AFTER,OPCODE_AUTOSTART,
|
||||||
OPCODE_ATGTE,OPCODE_ATLT,
|
OPCODE_ATGTE,OPCODE_ATLT,
|
||||||
OPCODE_ATTIMEOUT1,OPCODE_ATTIMEOUT2,OPCODE_IFTIMEOUT,
|
OPCODE_ATTIMEOUT1,OPCODE_ATTIMEOUT2,
|
||||||
OPCODE_LATCH,OPCODE_UNLATCH,OPCODE_SET,OPCODE_RESET,
|
OPCODE_LATCH,OPCODE_UNLATCH,OPCODE_SET,OPCODE_RESET,
|
||||||
OPCODE_IF,OPCODE_IFNOT,OPCODE_ENDIF,OPCODE_IFRANDOM,OPCODE_IFRESERVE,
|
OPCODE_ENDIF,OPCODE_ELSE,
|
||||||
OPCODE_IFCLOSED, OPCODE_IFTHROWN,OPCODE_ELSE,
|
|
||||||
OPCODE_DELAY,OPCODE_DELAYMINS,OPCODE_DELAYMS,OPCODE_RANDWAIT,
|
OPCODE_DELAY,OPCODE_DELAYMINS,OPCODE_DELAYMS,OPCODE_RANDWAIT,
|
||||||
OPCODE_FON,OPCODE_FOFF,OPCODE_XFON,OPCODE_XFOFF,
|
OPCODE_FON,OPCODE_FOFF,OPCODE_XFON,OPCODE_XFOFF,
|
||||||
OPCODE_RED,OPCODE_GREEN,OPCODE_AMBER,OPCODE_DRIVE,
|
OPCODE_RED,OPCODE_GREEN,OPCODE_AMBER,OPCODE_DRIVE,
|
||||||
@ -49,9 +48,22 @@ enum OPCODE : byte {OPCODE_THROW,OPCODE_CLOSE,
|
|||||||
OPCODE_PAUSE, OPCODE_RESUME,OPCODE_POWEROFF,OPCODE_POWERON,
|
OPCODE_PAUSE, OPCODE_RESUME,OPCODE_POWEROFF,OPCODE_POWERON,
|
||||||
OPCODE_ONCLOSE, OPCODE_ONTHROW, OPCODE_SERVOTURNOUT, OPCODE_PINTURNOUT,
|
OPCODE_ONCLOSE, OPCODE_ONTHROW, OPCODE_SERVOTURNOUT, OPCODE_PINTURNOUT,
|
||||||
OPCODE_PRINT,OPCODE_DCCACTIVATE,
|
OPCODE_PRINT,OPCODE_DCCACTIVATE,
|
||||||
OPCODE_ONACTIVATE,OPCODE_ONDEACTIVATE,OPCODE_IFGTE,OPCODE_IFLT,
|
OPCODE_ONACTIVATE,OPCODE_ONDEACTIVATE,
|
||||||
OPCODE_ROSTER,OPCODE_SET_TRACK,OPCODE_KILLALL,
|
OPCODE_ROSTER,OPCODE_KILLALL,
|
||||||
OPCODE_ROUTE,OPCODE_AUTOMATION,OPCODE_SEQUENCE,OPCODE_ENDTASK,OPCODE_ENDEXRAIL
|
OPCODE_ROUTE,OPCODE_AUTOMATION,OPCODE_SEQUENCE,
|
||||||
|
OPCODE_ENDTASK,OPCODE_ENDEXRAIL,
|
||||||
|
OPCODE_SET_TRACK,
|
||||||
|
|
||||||
|
// OPcodes below this point are skip-nesting IF operations
|
||||||
|
// placed here so that they may be skipped as a group
|
||||||
|
// see skipIfBlock()
|
||||||
|
IF_TYPE_OPCODES, // do not move this...
|
||||||
|
OPCODE_IFRED,OPCODE_IFAMBER,OPCODE_IFGREEN,
|
||||||
|
OPCODE_IFGTE,OPCODE_IFLT,
|
||||||
|
OPCODE_IFTIMEOUT,
|
||||||
|
OPCODE_IF,OPCODE_IFNOT,
|
||||||
|
OPCODE_IFRANDOM,OPCODE_IFRESERVE,
|
||||||
|
OPCODE_IFCLOSED, OPCODE_IFTHROWN
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -61,7 +73,10 @@ enum OPCODE : byte {OPCODE_THROW,OPCODE_CLOSE,
|
|||||||
static const byte LATCH_FLAG = 0x40;
|
static const byte LATCH_FLAG = 0x40;
|
||||||
static const byte TASK_FLAG = 0x20;
|
static const byte TASK_FLAG = 0x20;
|
||||||
static const byte SPARE_FLAG = 0x10;
|
static const byte SPARE_FLAG = 0x10;
|
||||||
static const byte COUNTER_MASK= 0x0F;
|
static const byte SIGNAL_MASK = 0x0C;
|
||||||
|
static const byte SIGNAL_RED = 0x08;
|
||||||
|
static const byte SIGNAL_AMBER = 0x0C;
|
||||||
|
static const byte SIGNAL_GREEN = 0x04;
|
||||||
|
|
||||||
static const byte MAX_STACK_DEPTH=4;
|
static const byte MAX_STACK_DEPTH=4;
|
||||||
|
|
||||||
@ -112,7 +127,9 @@ private:
|
|||||||
static void setFlag(VPIN id,byte onMask, byte OffMask=0);
|
static void setFlag(VPIN id,byte onMask, byte OffMask=0);
|
||||||
static bool getFlag(VPIN id,byte mask);
|
static bool getFlag(VPIN id,byte mask);
|
||||||
static int16_t progtrackLocoId;
|
static int16_t progtrackLocoId;
|
||||||
static void doSignal(VPIN id,bool red, bool amber, bool green);
|
static void doSignal(VPIN id,char rag);
|
||||||
|
static bool isSignal(VPIN id,char rag);
|
||||||
|
static int16_t getSignalSlot(VPIN id);
|
||||||
static void setTurnoutHiddenState(Turnout * t);
|
static void setTurnoutHiddenState(Turnout * t);
|
||||||
static RMFT2 * loopTask;
|
static RMFT2 * loopTask;
|
||||||
static RMFT2 * pausingTask;
|
static RMFT2 * pausingTask;
|
||||||
|
@ -59,11 +59,14 @@
|
|||||||
#undef FWD
|
#undef FWD
|
||||||
#undef GREEN
|
#undef GREEN
|
||||||
#undef IF
|
#undef IF
|
||||||
|
#undef IFAMBER
|
||||||
#undef IFCLOSED
|
#undef IFCLOSED
|
||||||
|
#undef IFGREEN
|
||||||
#undef IFGTE
|
#undef IFGTE
|
||||||
#undef IFLT
|
#undef IFLT
|
||||||
#undef IFNOT
|
#undef IFNOT
|
||||||
#undef IFRANDOM
|
#undef IFRANDOM
|
||||||
|
#undef IFRED
|
||||||
#undef IFRESERVE
|
#undef IFRESERVE
|
||||||
#undef IFTHROWN
|
#undef IFTHROWN
|
||||||
#undef IFTIMEOUT
|
#undef IFTIMEOUT
|
||||||
@ -159,11 +162,14 @@
|
|||||||
#define FWD(speed)
|
#define FWD(speed)
|
||||||
#define GREEN(signal_id)
|
#define GREEN(signal_id)
|
||||||
#define IF(sensor_id)
|
#define IF(sensor_id)
|
||||||
|
#define IFAMBER(signal_id)
|
||||||
#define IFCLOSED(turnout_id)
|
#define IFCLOSED(turnout_id)
|
||||||
|
#define IFGREEN(signal_id)
|
||||||
#define IFGTE(sensor_id,value)
|
#define IFGTE(sensor_id,value)
|
||||||
#define IFLT(sensor_id,value)
|
#define IFLT(sensor_id,value)
|
||||||
#define IFNOT(sensor_id)
|
#define IFNOT(sensor_id)
|
||||||
#define IFRANDOM(percent)
|
#define IFRANDOM(percent)
|
||||||
|
#define IFRED(signal_id)
|
||||||
#define IFTHROWN(turnout_id)
|
#define IFTHROWN(turnout_id)
|
||||||
#define IFRESERVE(block)
|
#define IFRESERVE(block)
|
||||||
#define IFTIMEOUT
|
#define IFTIMEOUT
|
||||||
|
@ -235,11 +235,14 @@ const FLASH int16_t RMFT2::SignalDefinitions[] = {
|
|||||||
#define FWD(speed) OPCODE_FWD,V(speed),
|
#define FWD(speed) OPCODE_FWD,V(speed),
|
||||||
#define GREEN(signal_id) OPCODE_GREEN,V(signal_id),
|
#define GREEN(signal_id) OPCODE_GREEN,V(signal_id),
|
||||||
#define IF(sensor_id) OPCODE_IF,V(sensor_id),
|
#define IF(sensor_id) OPCODE_IF,V(sensor_id),
|
||||||
|
#define IFAMBER(signal_id) OPCODE_IFAMBER,V(signal_id),
|
||||||
#define IFCLOSED(turnout_id) OPCODE_IFCLOSED,V(turnout_id),
|
#define IFCLOSED(turnout_id) OPCODE_IFCLOSED,V(turnout_id),
|
||||||
|
#define IFGREEN(signal_id) OPCODE_IFGREEN,V(signal_id),
|
||||||
#define IFGTE(sensor_id,value) OPCODE_IFGTE,V(sensor_id),OPCODE_PAD,V(value),
|
#define IFGTE(sensor_id,value) OPCODE_IFGTE,V(sensor_id),OPCODE_PAD,V(value),
|
||||||
#define IFLT(sensor_id,value) OPCODE_IFLT,V(sensor_id),OPCODE_PAD,V(value),
|
#define IFLT(sensor_id,value) OPCODE_IFLT,V(sensor_id),OPCODE_PAD,V(value),
|
||||||
#define IFNOT(sensor_id) OPCODE_IFNOT,V(sensor_id),
|
#define IFNOT(sensor_id) OPCODE_IFNOT,V(sensor_id),
|
||||||
#define IFRANDOM(percent) OPCODE_IFRANDOM,V(percent),
|
#define IFRANDOM(percent) OPCODE_IFRANDOM,V(percent),
|
||||||
|
#define IFRED(signal_id) OPCODE_IFRED,V(signal_id),
|
||||||
#define IFRESERVE(block) OPCODE_IFRESERVE,V(block),
|
#define IFRESERVE(block) OPCODE_IFRESERVE,V(block),
|
||||||
#define IFTHROWN(turnout_id) OPCODE_IFTHROWN,V(turnout_id),
|
#define IFTHROWN(turnout_id) OPCODE_IFTHROWN,V(turnout_id),
|
||||||
#define IFTIMEOUT OPCODE_IFTIMEOUT,0,0,
|
#define IFTIMEOUT OPCODE_IFTIMEOUT,0,0,
|
||||||
|
@ -72,7 +72,7 @@ void I2CManagerClass::I2C_sendStart() {
|
|||||||
bytesToReceive = currentRequest->readLen;
|
bytesToReceive = currentRequest->readLen;
|
||||||
|
|
||||||
// If anything to send, initiate write. Otherwise initiate read.
|
// If anything to send, initiate write. Otherwise initiate read.
|
||||||
if (operation == OPERATION_READ || ((operation == OPERATION_REQUEST) & !bytesToSend))
|
if (operation == OPERATION_READ || ((operation == OPERATION_REQUEST) && !bytesToSend))
|
||||||
TWI0.MADDR = (currentRequest->i2cAddress << 1) | 1;
|
TWI0.MADDR = (currentRequest->i2cAddress << 1) | 1;
|
||||||
else
|
else
|
||||||
TWI0.MADDR = (currentRequest->i2cAddress << 1) | 0;
|
TWI0.MADDR = (currentRequest->i2cAddress << 1) | 0;
|
||||||
|
@ -94,22 +94,24 @@ uint8_t I2CManagerClass::read(uint8_t address, uint8_t readBuffer[], uint8_t rea
|
|||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
* Function to queue a request block and initiate operations.
|
* Function to queue a request block and initiate operations.
|
||||||
*
|
*
|
||||||
* For the Wire version, this executes synchronously, but the status is
|
* For the Wire version, this executes synchronously.
|
||||||
* returned in the I2CRB as for the asynchronous version.
|
* The read/write/write_P functions return I2C_STATUS_OK always, and the
|
||||||
|
* completion status of the operation is in the request block, as for
|
||||||
|
* the non-blocking version.
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
void I2CManagerClass::queueRequest(I2CRB *req) {
|
void I2CManagerClass::queueRequest(I2CRB *req) {
|
||||||
switch (req->operation) {
|
switch (req->operation) {
|
||||||
case OPERATION_READ:
|
case OPERATION_READ:
|
||||||
req->status = read(req->i2cAddress, req->readBuffer, req->readLen, NULL, 0, req);
|
read(req->i2cAddress, req->readBuffer, req->readLen, NULL, 0, req);
|
||||||
break;
|
break;
|
||||||
case OPERATION_SEND:
|
case OPERATION_SEND:
|
||||||
req->status = write(req->i2cAddress, req->writeBuffer, req->writeLen, req);
|
write(req->i2cAddress, req->writeBuffer, req->writeLen, req);
|
||||||
break;
|
break;
|
||||||
case OPERATION_SEND_P:
|
case OPERATION_SEND_P:
|
||||||
req->status = write_P(req->i2cAddress, req->writeBuffer, req->writeLen, req);
|
write_P(req->i2cAddress, req->writeBuffer, req->writeLen, req);
|
||||||
break;
|
break;
|
||||||
case OPERATION_REQUEST:
|
case OPERATION_REQUEST:
|
||||||
req->status = read(req->i2cAddress, req->readBuffer, req->readLen, req->writeBuffer, req->writeLen, req);
|
read(req->i2cAddress, req->readBuffer, req->readLen, req->writeBuffer, req->writeLen, req);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -258,11 +258,14 @@ void WiThrottle::parse(RingStream * stream, byte * cmdx) {
|
|||||||
|
|
||||||
int WiThrottle::getInt(byte * cmd) {
|
int WiThrottle::getInt(byte * cmd) {
|
||||||
int i=0;
|
int i=0;
|
||||||
|
bool negate=cmd[0]=='-';
|
||||||
|
if (negate) cmd++;
|
||||||
while (cmd[0]>='0' && cmd[0]<='9') {
|
while (cmd[0]>='0' && cmd[0]<='9') {
|
||||||
i=i*10 + (cmd[0]-'0');
|
i=i*10 + (cmd[0]-'0');
|
||||||
cmd++;
|
cmd++;
|
||||||
}
|
}
|
||||||
return i;
|
if (negate) i=0-i;
|
||||||
|
return i ;
|
||||||
}
|
}
|
||||||
|
|
||||||
int WiThrottle::getLocoId(byte * cmd) {
|
int WiThrottle::getLocoId(byte * cmd) {
|
||||||
|
@ -12,7 +12,13 @@
|
|||||||
// Automatic ALIAS(name)
|
// Automatic ALIAS(name)
|
||||||
// Command Parser now accepts Underscore in Alias Names
|
// Command Parser now accepts Underscore in Alias Names
|
||||||
// 4.0.2 EXRAIL additions:
|
// 4.0.2 EXRAIL additions:
|
||||||
// PARSE <> commands
|
// FIX negative route ids in WIthrottle problem.
|
||||||
|
// IFRED(signal_id), IFAMBER(signal_id), IFGREEN(signal_id)
|
||||||
|
// </RED signal_id> </AMBER signal_id> </GREEN signal_id> commands
|
||||||
|
// <t cab> command to obtain current throttle settings
|
||||||
|
// JA, JR, JT commands to obtain route, roster and turnout descriptions
|
||||||
|
// HIDDEN turnouts
|
||||||
|
// PARSE <> commands in EXRAIL
|
||||||
// VIRTUAL_TURNOUT
|
// VIRTUAL_TURNOUT
|
||||||
// </KILL ALL> and KILLALL command to stop all tasks.
|
// </KILL ALL> and KILLALL command to stop all tasks.
|
||||||
// FORGET forgets the current loco in DCC reminder tables.
|
// FORGET forgets the current loco in DCC reminder tables.
|
||||||
|
Loading…
Reference in New Issue
Block a user