diff --git a/EXRAIL2.cpp b/EXRAIL2.cpp index 0e17ea9..c01189c 100644 --- a/EXRAIL2.cpp +++ b/EXRAIL2.cpp @@ -52,6 +52,7 @@ #include "Turnouts.h" #include "CommandDistributor.h" #include "TrackManager.h" +#include "Turntables.h" // Command parsing keywords const int16_t HASH_KEYWORD_EXRAIL=15435; @@ -94,6 +95,7 @@ LookList * RMFT2::onAmberLookup=NULL; LookList * RMFT2::onGreenLookup=NULL; LookList * RMFT2::onChangeLookup=NULL; LookList * RMFT2::onClockLookup=NULL; +LookList * RMFT2::onRotateLookup=NULL; #define GET_OPCODE GETHIGHFLASH(RMFT2::RouteCode,progCounter) #define SKIPOP progCounter+=3 @@ -175,6 +177,7 @@ LookList* RMFT2::LookListLoader(OPCODE op1, OPCODE op2, OPCODE op3) { onGreenLookup=LookListLoader(OPCODE_ONGREEN); onChangeLookup=LookListLoader(OPCODE_ONCHANGE); onClockLookup=LookListLoader(OPCODE_ONTIME); + onRotateLookup=LookListLoader(OPCODE_ONROTATE); // Second pass startup, define any turnouts or servos, set signals red @@ -238,6 +241,32 @@ LookList* RMFT2::LookListLoader(OPCODE op1, OPCODE op2, OPCODE op3) { setTurnoutHiddenState(VpinTurnout::create(id,pin)); break; } + + case OPCODE_DCCTURNTABLE: { + VPIN id=operand; + setTurntableHiddenState(DCCTurntable::create(id)); + Turntable *tto=Turntable::get(id); + tto->addPosition(0); + break; + } + + case OPCODE_EXTTTURNTABLE: { + VPIN id=operand; + VPIN pin=getOperand(progCounter,1); + int home=getOperand(progCounter,2); + setTurntableHiddenState(EXTTTurntable::create(id,pin)); + Turntable *tto=Turntable::get(id); + tto->addPosition(home); + break; + } + + case OPCODE_TTADDPOSITION: { + VPIN id=operand; + int value=getOperand(progCounter,1); + Turntable *tto=Turntable::get(id); + tto->addPosition(value); + break; + } case OPCODE_AUTOSTART: // automatically create a task from here at startup. @@ -263,6 +292,10 @@ void RMFT2::setTurnoutHiddenState(Turnout * t) { t->setHidden(GETFLASH(getTurnoutDescription(t->getId()))==0x01); } +void RMFT2::setTurntableHiddenState(Turntable * tto) { + tto->setHidden(GETFLASH(getTurntableDescription(tto->getId()))==0x01); +} + char RMFT2::getRouteType(int16_t id) { for (int16_t i=0;;i+=2) { int16_t rid= GETHIGHFLASHW(routeIdList,i); @@ -598,6 +631,13 @@ void RMFT2::loop2() { case OPCODE_CLOSE: Turnout::setClosed(operand, true); break; + + case OPCODE_ROTATE: + uint8_t activity; + activity=getOperand(2); + if (!activity) activity=0; + Turntable::setPosition(operand,getOperand(1),activity); + break; case OPCODE_REV: forward = false; @@ -788,6 +828,10 @@ void RMFT2::loop2() { case OPCODE_IFCLOSED: skipIf=Turnout::isThrown(operand); break; + + case OPCODE_IFTTPOSITION: // do block if turntable at this position + skipIf=Turntable::getPosition(operand)!=(int)getOperand(1); + break; case OPCODE_ENDIF: break; @@ -986,6 +1030,10 @@ void RMFT2::loop2() { case OPCODE_ONGREEN: case OPCODE_ONCHANGE: case OPCODE_ONTIME: + case OPCODE_DCCTURNTABLE: // Turntable definition ignored at runtime + case OPCODE_EXTTTURNTABLE: // Turntable definition ignored at runtime + case OPCODE_TTADDPOSITION: // Turntable position definition ignored at runtime + case OPCODE_ONROTATE: break; @@ -1130,6 +1178,11 @@ void RMFT2::changeEvent(int16_t vpin, bool change) { if (change) handleEvent(F("CHANGE"),onChangeLookup,vpin); } +void RMFT2::rotateEvent(int16_t turntableId, bool change) { + // Hunt or an ONROTATE for this turntable + if (change) handleEvent(F("ROTATE"),onRotateLookup,turntableId); +} + void RMFT2::clockEvent(int16_t clocktime, bool change) { // Hunt for an ONTIME for this time if (Diag::CMD) diff --git a/EXRAIL2.h b/EXRAIL2.h index 4d106e6..96bc7db 100644 --- a/EXRAIL2.h +++ b/EXRAIL2.h @@ -25,6 +25,7 @@ #include "FSH.h" #include "IODevice.h" #include "Turnouts.h" +#include "Turntables.h" // The following are the operation codes (or instructions) for a kind of virtual machine. // Each instruction is normally 3 bytes long with an operation code followed by a parameter. @@ -62,6 +63,8 @@ enum OPCODE : byte {OPCODE_THROW,OPCODE_CLOSE, OPCODE_ONCHANGE, OPCODE_ONCLOCKTIME, OPCODE_ONTIME, + OPCODE_TTADDPOSITION,OPCODE_DCCTURNTABLE,OPCODE_EXTTTURNTABLE, + OPCODE_ONROTATE,OPCODE_ROTATE,OPCODE_IFTTPOSITION, // OPcodes below this point are skip-nesting IF operations // placed here so that they may be skipped as a group @@ -130,6 +133,7 @@ class LookList { static void activateEvent(int16_t addr, bool active); static void changeEvent(int16_t id, bool change); static void clockEvent(int16_t clocktime, bool change); + static void rotateEvent(int16_t id, bool change); static const int16_t SERVO_SIGNAL_FLAG=0x4000; static const int16_t ACTIVE_HIGH_SIGNAL_FLAG=0x2000; static const int16_t DCC_SIGNAL_FLAG=0x1000; @@ -144,6 +148,8 @@ class LookList { static const FSH * getTurnoutDescription(int16_t id); static const FSH * getRosterName(int16_t id); static const FSH * getRosterFunctions(int16_t id); + static const FSH * getTurntableDescription(int16_t id); + // static const FSH * getTurntablePositionDescription(int16_t id, uint8_t position); private: static void ComandFilter(Print * stream, byte & opcode, byte & paramCount, int16_t p[]); @@ -156,6 +162,7 @@ private: static bool isSignal(int16_t id,char rag); static int16_t getSignalSlot(int16_t id); static void setTurnoutHiddenState(Turnout * t); + static void setTurntableHiddenState(Turntable * tto); static LookList* LookListLoader(OPCODE op1, OPCODE op2=OPCODE_ENDEXRAIL,OPCODE op3=OPCODE_ENDEXRAIL); static void handleEvent(const FSH* reason,LookList* handlers, int16_t id); @@ -188,6 +195,7 @@ private: static LookList * onGreenLookup; static LookList * onChangeLookup; static LookList * onClockLookup; + static LookList * onRotateLookup; // Local variables - exist for each instance/task RMFT2 *next; // loop chain diff --git a/EXRAIL2MacroReset.h b/EXRAIL2MacroReset.h index 588a417..7c690b7 100644 --- a/EXRAIL2MacroReset.h +++ b/EXRAIL2MacroReset.h @@ -40,6 +40,7 @@ #undef CALL #undef CLOSE #undef DCC_SIGNAL +#undef DCC_TURNTABLE #undef DEACTIVATE #undef DEACTIVATEL #undef DELAY @@ -51,8 +52,9 @@ #undef ENDEXRAIL #undef ENDIF #undef ENDTASK -#undef ESTOP -#undef EXRAIL +#undef ESTOP +#undef EXRAIL +#undef EXTT_TURNTABLE #undef FADE #undef FOFF #undef FOLLOW @@ -75,6 +77,7 @@ #undef IFRESERVE #undef IFTHROWN #undef IFTIMEOUT +#undef IFTTPOSITION #undef IFRE #undef INVERT_DIRECTION #undef JOIN @@ -95,6 +98,7 @@ #undef ONCLOCKMINS #undef ONGREEN #undef ONRED +#undef ONROTATE #undef ONTHROW #undef ONCHANGE #undef PARSE @@ -113,7 +117,8 @@ #undef RESUME #undef RETURN #undef REV -#undef ROSTER +#undef ROSTER +#undef ROTATE #undef ROUTE #undef SENDLOCO #undef SEQUENCE @@ -136,7 +141,8 @@ #undef SPEED #undef START #undef STOP -#undef THROW +#undef THROW +#undef TT_ADDPOSITION #undef TURNOUT #undef TURNOUTL #undef UNJOIN @@ -165,6 +171,7 @@ #define CALL(route) #define CLOSE(id) #define DCC_SIGNAL(id,add,subaddr) +#define DCC_TURNTABLE(id,description) #define DEACTIVATE(addr,subaddr) #define DEACTIVATEL(addr) #define DELAY(mindelay) @@ -177,7 +184,8 @@ #define ENDIF #define ENDTASK #define ESTOP -#define EXRAIL +#define EXRAIL +#define EXTT_TURNTABLE(id,vpin,home,description) #define FADE(pin,value,ms) #define FOFF(func) #define FOLLOW(route) @@ -200,6 +208,7 @@ #define IFTHROWN(turnout_id) #define IFRESERVE(block) #define IFTIMEOUT +#define IFTTPOSITION(turntable_id,position) #define IFRE(sensor_id,value) #define INVERT_DIRECTION #define JOIN @@ -219,7 +228,8 @@ #define ONDEACTIVATEL(linear) #define ONCLOSE(turnout_id) #define ONGREEN(signal_id) -#define ONRED(signal_id) +#define ONRED(signal_id) +#define ONROTATE(turntable_id) #define ONTHROW(turnout_id) #define ONCHANGE(sensor_id) #define PAUSE @@ -238,8 +248,9 @@ #define RESUME #define RETURN #define REV(speed) -#define ROUTE(id,description) +#define ROTATE(turntable_id,position,activity) #define ROSTER(cab,name,funcmap...) +#define ROUTE(id,description) #define SENDLOCO(cab,route) #define SEQUENCE(id) #define SERIAL(msg) @@ -261,7 +272,8 @@ #define SPEED(speed) #define START(route) #define STOP -#define THROW(id) +#define THROW(id) +#define TT_ADDPOSITION(turntable_id,value,description) #define TURNOUT(id,addr,subaddr,description...) #define TURNOUTL(id,addr,description...) #define UNJOIN diff --git a/EXRAILMacros.h b/EXRAILMacros.h index 66b0111..fc8dbca 100644 --- a/EXRAILMacros.h +++ b/EXRAILMacros.h @@ -187,6 +187,30 @@ const FSH * RMFT2::getTurnoutDescription(int16_t turnoutid) { return NULL; } +// Pass to get turntable descriptions (optional) +#include "EXRAIL2MacroReset.h" +#undef DCC_TURNTABLE +#define DCC_TURNTABLE(id,description...) O_DESC(id,description) +#undef EXTT_TURNTABLE +#define EXTT_TURNTABLE(id,vpin,home,description...) O_DESC(id,description) + +const FSH * RMFT2::getTurntableDescription(int16_t turntableId) { + switch (turntableId) { + #include "myAutomation.h" + default:break; + } + return NULL; +} + +// Pass to get turntable position descriptions (optional) +// #include "EXRAIL2MacroReset.h" +// #undef TT_ADDPOSITION +// #define TT_ADDPOSITION(turntable_id,value,description...) 0_DESC(id,description) + +// const FSH * RMFT2::getTurntablePositionDescription(int16_t turntableId, uint8_t positionId) { + +// } + // Pass 6: Roster IDs (count) #include "EXRAIL2MacroReset.h" #undef ROSTER @@ -268,6 +292,7 @@ const HIGHFLASH int16_t RMFT2::SignalDefinitions[] = { #define BROADCAST(msg) PRINT(msg) #define CALL(route) OPCODE_CALL,V(route), #define CLOSE(id) OPCODE_CLOSE,V(id), +#define DCC_TURNTABLE(id,description...) OPCODE_DCCTURNTABLE,V(id), #define DEACTIVATE(addr,subaddr) OPCODE_DCCACTIVATE,V(addr<<3 | subaddr<<1), #define DEACTIVATEL(addr) OPCODE_DCCACTIVATE,V((addr+3)<<1), #define DELAY(ms) ms<30000?OPCODE_DELAYMS:OPCODE_DELAY,V(ms/(ms<30000?1L:100L)), @@ -281,7 +306,8 @@ const HIGHFLASH int16_t RMFT2::SignalDefinitions[] = { #define ENDIF OPCODE_ENDIF,0,0, #define ENDTASK OPCODE_ENDTASK,0,0, #define ESTOP OPCODE_SPEED,V(1), -#define EXRAIL +#define EXRAIL +#define EXTT_TURNTABLE(id,vpin,home,description...) OPCODE_EXTTTURNTABLE,V(id),OPCODE_PAD,V(vpin),OPCODE_PAD,V(home), #define FADE(pin,value,ms) OPCODE_SERVO,V(pin),OPCODE_PAD,V(value),OPCODE_PAD,V(PCA9685::ProfileType::UseDuration|PCA9685::NoPowerOff),OPCODE_PAD,V(ms/100L), #define FOFF(func) OPCODE_FOFF,V(func), #define FOLLOW(route) OPCODE_FOLLOW,V(route), @@ -304,6 +330,7 @@ const HIGHFLASH int16_t RMFT2::SignalDefinitions[] = { #define IFRESERVE(block) OPCODE_IFRESERVE,V(block), #define IFTHROWN(turnout_id) OPCODE_IFTHROWN,V(turnout_id), #define IFTIMEOUT OPCODE_IFTIMEOUT,0,0, +#define IFTTPOSITION(id,position) OPCODE_IFTTPOSITION,V(id),OPCODE_PAD,V(position), #define IFRE(sensor_id,value) OPCODE_IFRE,V(sensor_id),OPCODE_PAD,V(value), #define INVERT_DIRECTION OPCODE_INVERT_DIRECTION,0,0, #define JOIN OPCODE_JOIN,0,0, @@ -324,6 +351,7 @@ const HIGHFLASH int16_t RMFT2::SignalDefinitions[] = { #define ONDEACTIVATEL(linear) OPCODE_ONDEACTIVATE,V(linear+3), #define ONGREEN(signal_id) OPCODE_ONGREEN,V(signal_id), #define ONRED(signal_id) OPCODE_ONRED,V(signal_id), +#define ONROTATE(id) OPCODE_ONROTATE,V(id), #define ONTHROW(turnout_id) OPCODE_ONTHROW,V(turnout_id), #define ONCHANGE(sensor_id) OPCODE_ONCHANGE,V(sensor_id), #define PAUSE OPCODE_PAUSE,0,0, @@ -343,6 +371,7 @@ const HIGHFLASH int16_t RMFT2::SignalDefinitions[] = { #define RETURN OPCODE_RETURN,0,0, #define REV(speed) OPCODE_REV,V(speed), #define ROSTER(cabid,name,funcmap...) +#define ROTATE(id,position,activity) OPCODE_ROTATE,V(id),OPCODE_PAD,V(position),OPCODE_PAD,V(activity), #define ROUTE(id, description) OPCODE_ROUTE, V(id), #define SENDLOCO(cab,route) OPCODE_SENDLOCO,V(cab),OPCODE_PAD,V(route), #define SEQUENCE(id) OPCODE_SEQUENCE, V(id), @@ -366,6 +395,7 @@ const HIGHFLASH int16_t RMFT2::SignalDefinitions[] = { #define START(route) OPCODE_START,V(route), #define STOP OPCODE_SPEED,V(0), #define THROW(id) OPCODE_THROW,V(id), +#define TT_ADDPOSITION(id,value,description...) OPCODE_TTADDPOSITION,V(id),OPCODE_PAD,V(value), #define TURNOUT(id,addr,subaddr,description...) OPCODE_TURNOUT,V(id),OPCODE_PAD,V(addr),OPCODE_PAD,V(subaddr), #define TURNOUTL(id,addr,description...) TURNOUT(id,(addr-1)/4+1,(addr-1)%4, description) #define UNJOIN OPCODE_UNJOIN,0,0, diff --git a/Turntables.cpp b/Turntables.cpp index 3e33d2b..dcf50a0 100644 --- a/Turntables.cpp +++ b/Turntables.cpp @@ -108,6 +108,13 @@ Turntable *Turntable::getByVpin(VPIN vpin) { return nullptr; } +// Get the current position for turntable with the specified ID +uint8_t Turntable::getPosition(uint16_t id) { + Turntable *tto = get(id); + if (!tto) return false; + return tto->getPosition(); +} + // Broadcast position changes bool Turntable::setPositionStateOnly(uint16_t id, uint8_t position, bool moving) { Turntable *tto = get(id); @@ -234,7 +241,10 @@ DCCTurntable::DCCTurntable(uint16_t id) : Turntable(id, TURNTABLE_DCC) {} int16_t value = getPositionValue(position); if (position == 0 || !value) return false; // Return false if it's not a valid position // Set position via device driver - // DCC activate function here + int16_t addr=value>>3; + int16_t subaddr=(value>>1) & 0x03; + bool active=value & 0x01; + DCC::setAccessory(addr, subaddr, active); #else (void)position; #endif diff --git a/Turntables.h b/Turntables.h index e318724..b95c9c0 100644 --- a/Turntables.h +++ b/Turntables.h @@ -172,6 +172,7 @@ public: inline static bool exists(uint16_t id) { return get(id) != 0; } static bool setPosition(uint16_t id, uint8_t position, uint8_t activity=0); static bool setPositionStateOnly(uint16_t id, uint8_t position, bool moving); + static uint8_t getPosition(uint16_t id); inline static Turntable *first() { return _firstTurntable; } static bool printAll(Print *stream) { bool gotOne = false;