1
0
mirror of https://github.com/DCC-EX/CommandStation-EX.git synced 2024-11-23 08:06:13 +01:00

RAG Ifs and cmds

This commit is contained in:
Asbelos 2022-04-17 09:58:32 +01:00
parent 766fdc43ac
commit 45f690eb4d
4 changed files with 123 additions and 59 deletions

View File

@ -64,6 +64,9 @@ const int16_t HASH_KEYWORD_RESUME=27609;
const int16_t HASH_KEYWORD_KILL=5218;
const int16_t HASH_KEYWORD_ALL=3457;
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.
// 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);
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:
return false;
}
@ -517,6 +532,9 @@ bool RMFT2::skipIfBlock() {
case OPCODE_IFRESERVE:
case OPCODE_IFTHROWN:
case OPCODE_IFTIMEOUT:
case OPCODE_IFRED:
case OPCODE_IFAMBER:
case OPCODE_IFGREEN:
nest++;
break;
case OPCODE_ENDIF:
@ -553,6 +571,10 @@ void RMFT2::loop2() {
byte opcode = GET_OPCODE;
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);
// Attention: Returning from this switch leaves the program counter unchanged.
// This is used for unfinished waits for timers or sensors.
@ -639,7 +661,7 @@ void RMFT2::loop2() {
return;
case OPCODE_IFTIMEOUT: // do next operand if timeout flag set
if (!timeoutFlag) if (!skipIfBlock()) return;
skipIf=!timeoutFlag;
break;
case OPCODE_AFTER: // waits for sensor to hit and then remain off for 0.5 seconds. (must come after an AT operation)
@ -691,40 +713,52 @@ void RMFT2::loop2() {
break;
case OPCODE_IF: // do next operand if sensor set
if (!readSensor(operand)) if (!skipIfBlock()) return;
skipIf=!readSensor(operand);
break;
case OPCODE_ELSE: // skip to matching ENDIF
if (!skipIfBlock()) return;
skipIf=true;
break;
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;
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;
case OPCODE_IFNOT: // do next operand if sensor not set
if (readSensor(operand)) if (!skipIfBlock()) return;
skipIf=readSensor(operand);
break;
case OPCODE_IFRANDOM: // do block on random percentage
if ((int16_t)random(100)>=operand) if (!skipIfBlock()) return;
skipIf=(int16_t)random(100)>=operand;
break;
case OPCODE_IFRESERVE: // do block if we successfully RERSERVE
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;
case OPCODE_IFTHROWN:
if (Turnout::isClosed(operand)) if (!skipIfBlock()) return;
skipIf=Turnout::isClosed(operand);
break;
case OPCODE_IFCLOSED:
if (!Turnout::isClosed(operand)) if (!skipIfBlock()) return;
skipIf=Turnout::isThrown(operand);
break;
case OPCODE_ENDIF:
@ -747,15 +781,15 @@ void RMFT2::loop2() {
break;
case OPCODE_RED:
doSignal(operand,true,false,false);
doSignal(operand,SIGNAL_RED);
break;
case OPCODE_AMBER:
doSignal(operand,false,true,false);
doSignal(operand,SIGNAL_AMBER);
break;
case OPCODE_GREEN:
doSignal(operand,false,false,true);
doSignal(operand,SIGNAL_GREEN);
break;
case OPCODE_FON:
@ -924,6 +958,8 @@ void RMFT2::loop2() {
kill(F("INVOP"),operand);
}
// 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;
}
@ -951,22 +987,32 @@ void RMFT2::kill(const FSH * reason, int operand) {
delete this;
}
/* static */ void RMFT2::doSignal(VPIN id,bool red, bool amber, bool green) {
//if (diag) DIAG(F(" dosignal %d"),id);
int16_t RMFT2::getSignalSlot(VPIN id) {
for (int sigpos=0;;sigpos+=4) {
//if (diag) DIAG(F("red=%d"),redpin);
VPIN sigid=GETFLASHW(RMFT2::SignalDefinitions+sigpos);
if (sigid==0) { // end of signal list
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
// for a LED signal it will be same as redpin
// 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
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
int16_t sigpos=sigslot*4;
VPIN sigid=GETFLASHW(RMFT2::SignalDefinitions+sigpos);
VPIN redpin=GETFLASHW(RMFT2::SignalDefinitions+sigpos+1);
VPIN amberpin=GETFLASHW(RMFT2::SignalDefinitions+sigpos+2);
VPIN greenpin=GETFLASHW(RMFT2::SignalDefinitions+sigpos+3);
@ -975,27 +1021,30 @@ void RMFT2::kill(const FSH * reason, int operand) {
if (sigid & SERVO_SIGNAL_FLAG) {
// A servo signal, the pin numbers are actually servo positions
// 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);
return;
}
// LED or similar 3 pin signal
// If amberpin is zero, synthesise amber from red+green
if (amber && (amberpin==0)) {
red=true;
green=true;
}
const byte SIMAMBER=0x00;
if (rag==SIGNAL_AMBER && (amberpin==0)) rag=SIMAMBER; // special case this func only
// Manage invert (HIGH on) pins
bool aHigh=sigid & ACTIVE_HIGH_SIGNAL_FLAG;
// set the three pins
if (redpin) IODevice::write(redpin,red^aHigh);
if (amberpin) IODevice::write(amberpin,amber^aHigh);
if (greenpin) IODevice::write(greenpin,green^aHigh);
if (redpin) IODevice::write(redpin,(rag==SIGNAL_RED || rag==SIMAMBER)^aHigh);
if (amberpin) IODevice::write(amberpin,(rag==SIGNAL_AMBER)^aHigh);
if (greenpin) IODevice::write(greenpin,(rag==SIGNAL_GREEN || rag==SIMAMBER)^aHigh);
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) {

View File

@ -51,6 +51,7 @@ enum OPCODE : byte {OPCODE_THROW,OPCODE_CLOSE,
OPCODE_PRINT,OPCODE_DCCACTIVATE,
OPCODE_ONACTIVATE,OPCODE_ONDEACTIVATE,OPCODE_IFGTE,OPCODE_IFLT,
OPCODE_ROSTER,OPCODE_KILLALL,
OPCODE_IFRED,OPCODE_IFAMBER,OPCODE_IFGREEN,
OPCODE_ROUTE,OPCODE_AUTOMATION,OPCODE_SEQUENCE,OPCODE_ENDTASK,OPCODE_ENDEXRAIL
};
@ -61,7 +62,10 @@ enum OPCODE : byte {OPCODE_THROW,OPCODE_CLOSE,
static const byte LATCH_FLAG = 0x40;
static const byte TASK_FLAG = 0x20;
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;
@ -112,7 +116,9 @@ private:
static void setFlag(VPIN id,byte onMask, byte OffMask=0);
static bool getFlag(VPIN id,byte mask);
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 RMFT2 * loopTask;
static RMFT2 * pausingTask;

View File

@ -59,11 +59,14 @@
#undef FWD
#undef GREEN
#undef IF
#undef IFAMBER
#undef IFCLOSED
#undef IFGREEN
#undef IFGTE
#undef IFLT
#undef IFNOT
#undef IFRANDOM
#undef IFRED
#undef IFRESERVE
#undef IFTHROWN
#undef IFTIMEOUT
@ -158,11 +161,14 @@
#define FWD(speed)
#define GREEN(signal_id)
#define IF(sensor_id)
#define IFAMBER(signal_id)
#define IFCLOSED(turnout_id)
#define IFGREEN(signal_id)
#define IFGTE(sensor_id,value)
#define IFLT(sensor_id,value)
#define IFNOT(sensor_id)
#define IFRANDOM(percent)
#define IFRED(signal_id)
#define IFTHROWN(turnout_id)
#define IFRESERVE(block)
#define IFTIMEOUT

View File

@ -235,11 +235,14 @@ const FLASH int16_t RMFT2::SignalDefinitions[] = {
#define FWD(speed) OPCODE_FWD,V(speed),
#define GREEN(signal_id) OPCODE_GREEN,V(signal_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 IFGREEN(signal_id) OPCODE_IFGREEN,V(signal_id),
#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 IFNOT(sensor_id) OPCODE_IFNOT,V(sensor_id),
#define IFRANDOM(percent) OPCODE_IFRANDOM,V(percent),
#define IFRED(signal_id) OPCODE_IFRED,V(signal_id),
#define IFRESERVE(block) OPCODE_IFRESERVE,V(block),
#define IFTHROWN(turnout_id) OPCODE_IFTHROWN,V(turnout_id),
#define IFTIMEOUT OPCODE_IFTIMEOUT,0,0,