mirror of
https://github.com/DCC-EX/CommandStation-EX.git
synced 2025-04-14 09:20:12 +02:00
STASH upgrade
This commit is contained in:
parent
5d18c910fa
commit
6d8ca67a2b
@ -119,6 +119,7 @@ Once a new OPCODE is decided upon, update this list.
|
|||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include "KeywordHasher.h"
|
#include "KeywordHasher.h"
|
||||||
#include "CamParser.h"
|
#include "CamParser.h"
|
||||||
|
#include "Stash.h"
|
||||||
#ifdef ARDUINO_ARCH_ESP32
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
#include "WifiESP32.h"
|
#include "WifiESP32.h"
|
||||||
#endif
|
#endif
|
||||||
@ -777,7 +778,7 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream)
|
|||||||
|
|
||||||
case 'J' : // throttle info access
|
case 'J' : // throttle info access
|
||||||
{
|
{
|
||||||
if ((params<1) | (params>3)) break; // <J>
|
if (params<1) break; // <J>
|
||||||
//if ((params<1) | (params>2)) break; // <J>
|
//if ((params<1) | (params>2)) break; // <J>
|
||||||
int16_t id=(params==2)?p[1]:0;
|
int16_t id=(params==2)?p[1]:0;
|
||||||
switch(p[0]) {
|
switch(p[0]) {
|
||||||
@ -801,7 +802,7 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
case "L"_hk: // <JL display row> track state and mA value on display
|
case "L"_hk: // <JL display row> track state and mA value on display
|
||||||
if (params<3) break;
|
if (params!=3) break;
|
||||||
TrackManager::reportCurrentLCD(p[1], p[2]); // Track power status
|
TrackManager::reportCurrentLCD(p[1], p[2]); // Track power status
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -810,11 +811,10 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream)
|
|||||||
StringFormatter::send(stream, F("<jA>\n"));
|
StringFormatter::send(stream, F("<jA>\n"));
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case "M"_hk: // <JM> intercepted by EXRAIL
|
case "M"_hk: // <JM> Stash management
|
||||||
if (params>1) break; // invalid cant do
|
if (parseJM(stream, params, p))
|
||||||
// <JM> requests stash size so say none.
|
return;
|
||||||
StringFormatter::send(stream,F("<jM 0>\n"));
|
break;
|
||||||
return;
|
|
||||||
|
|
||||||
case "R"_hk: // <JR> returns rosters
|
case "R"_hk: // <JR> returns rosters
|
||||||
StringFormatter::send(stream, F("<jR"));
|
StringFormatter::send(stream, F("<jR"));
|
||||||
@ -1405,6 +1405,40 @@ bool DCCEXParser::parseI(Print *stream, int16_t params, int16_t p[])
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
bool DCCEXParser::parseJM(Print *stream, int16_t params, int16_t p[]) {
|
||||||
|
switch (params) {
|
||||||
|
case 1: // <JM> list all stashed automations
|
||||||
|
Stash::list(stream);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 2: // <JM id> get stash value
|
||||||
|
Stash::list(stream, p[1]);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 3: //
|
||||||
|
if (p[1]=="CLEAR"_hk) {
|
||||||
|
if (p[2]=="ALL"_hk) { // <JM CLEAR ALL>
|
||||||
|
Stash::clearAll();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Stash::clear(p[2]); // <JM CLEAR id>
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Stash::set(p[1], p[2]); // <JM id loco>
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 4: // <JM CLEAR ANY id>
|
||||||
|
if (p[1]=="CLEAR"_hk && p[2]=="ANY"_hk) {
|
||||||
|
// <JM CLEAR ANY id>
|
||||||
|
Stash::clearAny(p[3]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// CALLBACKS must be static
|
// CALLBACKS must be static
|
||||||
bool DCCEXParser::stashCallback(Print *stream, int16_t p[MAX_COMMAND_PARAMS], RingStream * ringStream)
|
bool DCCEXParser::stashCallback(Print *stream, int16_t p[MAX_COMMAND_PARAMS], RingStream * ringStream)
|
||||||
{
|
{
|
||||||
|
@ -52,6 +52,7 @@ struct DCCEXParser
|
|||||||
static bool parsef(Print * stream, int16_t params, int16_t p[]);
|
static bool parsef(Print * stream, int16_t params, int16_t p[]);
|
||||||
static bool parseC(Print * stream, int16_t params, int16_t p[]);
|
static bool parseC(Print * stream, int16_t params, int16_t p[]);
|
||||||
static bool parseD(Print * stream, int16_t params, int16_t p[]);
|
static bool parseD(Print * stream, int16_t params, int16_t p[]);
|
||||||
|
static bool parseJM(Print * stream, int16_t params, int16_t p[]);
|
||||||
#ifndef IO_NO_HAL
|
#ifndef IO_NO_HAL
|
||||||
static bool parseI(Print * stream, int16_t params, int16_t p[]);
|
static bool parseI(Print * stream, int16_t params, int16_t p[]);
|
||||||
#endif
|
#endif
|
||||||
|
56
EXRAIL2.cpp
56
EXRAIL2.cpp
@ -57,6 +57,7 @@
|
|||||||
#include "Turntables.h"
|
#include "Turntables.h"
|
||||||
#include "IODevice.h"
|
#include "IODevice.h"
|
||||||
#include "EXRAILSensor.h"
|
#include "EXRAILSensor.h"
|
||||||
|
#include "Stash.h"
|
||||||
|
|
||||||
|
|
||||||
// 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.
|
||||||
@ -92,8 +93,7 @@ LookList * RMFT2::onBlockEnterLookup=NULL;
|
|||||||
LookList * RMFT2::onBlockExitLookup=NULL;
|
LookList * RMFT2::onBlockExitLookup=NULL;
|
||||||
byte * RMFT2::routeStateArray=nullptr;
|
byte * RMFT2::routeStateArray=nullptr;
|
||||||
const FSH * * RMFT2::routeCaptionArray=nullptr;
|
const FSH * * RMFT2::routeCaptionArray=nullptr;
|
||||||
int16_t * RMFT2::stashArray=nullptr;
|
|
||||||
int16_t RMFT2::maxStashId=0;
|
|
||||||
|
|
||||||
// getOperand instance version, uses progCounter from instance.
|
// getOperand instance version, uses progCounter from instance.
|
||||||
uint16_t RMFT2::getOperand(byte n) {
|
uint16_t RMFT2::getOperand(byte n) {
|
||||||
@ -258,13 +258,7 @@ LookList* RMFT2::LookListLoader(OPCODE op1, OPCODE op2, OPCODE op3) {
|
|||||||
IODevice::configureInput((VPIN)pin,true);
|
IODevice::configureInput((VPIN)pin,true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OPCODE_STASH:
|
|
||||||
case OPCODE_CLEAR_STASH:
|
|
||||||
case OPCODE_PICKUP_STASH: {
|
|
||||||
maxStashId=max(maxStashId,((int16_t)operand));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case OPCODE_ATGTE:
|
case OPCODE_ATGTE:
|
||||||
case OPCODE_ATLT:
|
case OPCODE_ATLT:
|
||||||
case OPCODE_IFGTE:
|
case OPCODE_IFGTE:
|
||||||
@ -352,13 +346,7 @@ LookList* RMFT2::LookListLoader(OPCODE op1, OPCODE op2, OPCODE op3) {
|
|||||||
}
|
}
|
||||||
SKIPOP; // include ENDROUTES opcode
|
SKIPOP; // include ENDROUTES opcode
|
||||||
|
|
||||||
if (compileFeatures & FEATURE_STASH) {
|
DIAG(F("EXRAIL %db, fl=%d"),progCounter,MAX_FLAGS);
|
||||||
// create the stash array from the highest id found
|
|
||||||
if (maxStashId>0) stashArray=(int16_t*)calloc(maxStashId+1, sizeof(int16_t));
|
|
||||||
//TODO check EEPROM and fetch stashArray
|
|
||||||
}
|
|
||||||
|
|
||||||
DIAG(F("EXRAIL %db, fl=%d, stash=%d"),progCounter,MAX_FLAGS, maxStashId);
|
|
||||||
|
|
||||||
// Removed for 4.2.31 new RMFT2(0); // add the startup route
|
// Removed for 4.2.31 new RMFT2(0); // add the startup route
|
||||||
diag=saved_diag;
|
diag=saved_diag;
|
||||||
@ -815,6 +803,10 @@ void RMFT2::loop2() {
|
|||||||
case OPCODE_IFCLOSED:
|
case OPCODE_IFCLOSED:
|
||||||
skipIf=Turnout::isThrown(operand);
|
skipIf=Turnout::isThrown(operand);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case OPCODE_IFSTASH:
|
||||||
|
skipIf=Stash::get(operand)==0;
|
||||||
|
break;
|
||||||
|
|
||||||
#ifndef IO_NO_HAL
|
#ifndef IO_NO_HAL
|
||||||
case OPCODE_IFTTPOSITION: // do block if turntable at this position
|
case OPCODE_IFTTPOSITION: // do block if turntable at this position
|
||||||
@ -1067,30 +1059,32 @@ void RMFT2::loop2() {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case OPCODE_STASH:
|
case OPCODE_STASH:
|
||||||
if (compileFeatures & FEATURE_STASH)
|
Stash::set(operand,invert? -loco : loco);
|
||||||
stashArray[operand] = invert? -loco : loco;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPCODE_CLEAR_STASH:
|
case OPCODE_CLEAR_STASH:
|
||||||
if (compileFeatures & FEATURE_STASH)
|
Stash::clear(operand);
|
||||||
stashArray[operand] = 0;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPCODE_CLEAR_ALL_STASH:
|
case OPCODE_CLEAR_ALL_STASH:
|
||||||
if (compileFeatures & FEATURE_STASH)
|
Stash::clearAll();
|
||||||
for (int i=0;i<=maxStashId;i++) stashArray[operand]=0;
|
break;
|
||||||
|
|
||||||
|
case OPCODE_CLEAR_ANY_STASH:
|
||||||
|
if (loco) Stash::clearAny(loco);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPCODE_PICKUP_STASH:
|
case OPCODE_PICKUP_STASH:
|
||||||
if (compileFeatures & FEATURE_STASH) {
|
{
|
||||||
int16_t x=stashArray[operand];
|
auto x=Stash::get(operand);
|
||||||
if (x>=0) {
|
if (x>=0) {
|
||||||
loco=x;
|
loco=x;
|
||||||
invert=false;
|
invert=false;
|
||||||
break;
|
}
|
||||||
}
|
else {
|
||||||
loco=-x;
|
loco=-x;
|
||||||
invert=true;
|
invert=true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -77,6 +77,7 @@ enum OPCODE : byte {OPCODE_THROW,OPCODE_CLOSE,OPCODE_TOGGLE_TURNOUT,
|
|||||||
OPCODE_ROUTE_ACTIVE,OPCODE_ROUTE_INACTIVE,OPCODE_ROUTE_HIDDEN,
|
OPCODE_ROUTE_ACTIVE,OPCODE_ROUTE_INACTIVE,OPCODE_ROUTE_HIDDEN,
|
||||||
OPCODE_ROUTE_DISABLED,
|
OPCODE_ROUTE_DISABLED,
|
||||||
OPCODE_STASH,OPCODE_CLEAR_STASH,OPCODE_CLEAR_ALL_STASH,OPCODE_PICKUP_STASH,
|
OPCODE_STASH,OPCODE_CLEAR_STASH,OPCODE_CLEAR_ALL_STASH,OPCODE_PICKUP_STASH,
|
||||||
|
OPCODE_CLEAR_ANY_STASH,
|
||||||
OPCODE_ONBUTTON,OPCODE_ONSENSOR,
|
OPCODE_ONBUTTON,OPCODE_ONSENSOR,
|
||||||
OPCODE_NEOPIXEL,
|
OPCODE_NEOPIXEL,
|
||||||
OPCODE_ONBLOCKENTER,OPCODE_ONBLOCKEXIT,
|
OPCODE_ONBLOCKENTER,OPCODE_ONBLOCKEXIT,
|
||||||
@ -93,7 +94,8 @@ enum OPCODE : byte {OPCODE_THROW,OPCODE_CLOSE,OPCODE_TOGGLE_TURNOUT,
|
|||||||
OPCODE_IFCLOSED,OPCODE_IFTHROWN,
|
OPCODE_IFCLOSED,OPCODE_IFTHROWN,
|
||||||
OPCODE_IFRE,
|
OPCODE_IFRE,
|
||||||
OPCODE_IFLOCO,
|
OPCODE_IFLOCO,
|
||||||
OPCODE_IFTTPOSITION
|
OPCODE_IFTTPOSITION,
|
||||||
|
OPCODE_IFSTASH,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Ensure thrunge_lcd is put last as there may be more than one display,
|
// Ensure thrunge_lcd is put last as there may be more than one display,
|
||||||
@ -137,7 +139,7 @@ enum SignalType {
|
|||||||
static const byte FEATURE_LCC = 0x40;
|
static const byte FEATURE_LCC = 0x40;
|
||||||
static const byte FEATURE_ROSTER= 0x20;
|
static const byte FEATURE_ROSTER= 0x20;
|
||||||
static const byte FEATURE_ROUTESTATE= 0x10;
|
static const byte FEATURE_ROUTESTATE= 0x10;
|
||||||
static const byte FEATURE_STASH = 0x08;
|
// spare = 0x08;
|
||||||
static const byte FEATURE_BLINK = 0x04;
|
static const byte FEATURE_BLINK = 0x04;
|
||||||
static const byte FEATURE_SENSOR = 0x02;
|
static const byte FEATURE_SENSOR = 0x02;
|
||||||
static const byte FEATURE_BLOCK = 0x01;
|
static const byte FEATURE_BLOCK = 0x01;
|
||||||
|
@ -46,6 +46,7 @@
|
|||||||
#undef CALL
|
#undef CALL
|
||||||
#undef CLEAR_STASH
|
#undef CLEAR_STASH
|
||||||
#undef CLEAR_ALL_STASH
|
#undef CLEAR_ALL_STASH
|
||||||
|
#undef CLEAR_ANY_STASH
|
||||||
#undef CLOSE
|
#undef CLOSE
|
||||||
#undef CONFIGURE_SERVO
|
#undef CONFIGURE_SERVO
|
||||||
#undef DCC_SIGNAL
|
#undef DCC_SIGNAL
|
||||||
@ -88,6 +89,7 @@
|
|||||||
#undef IFRANDOM
|
#undef IFRANDOM
|
||||||
#undef IFRED
|
#undef IFRED
|
||||||
#undef IFRESERVE
|
#undef IFRESERVE
|
||||||
|
#undef IFSTASH
|
||||||
#undef IFTHROWN
|
#undef IFTHROWN
|
||||||
#undef IFTIMEOUT
|
#undef IFTIMEOUT
|
||||||
#undef IFTTPOSITION
|
#undef IFTTPOSITION
|
||||||
@ -338,6 +340,11 @@
|
|||||||
* @brief Clears all stashed loco values
|
* @brief Clears all stashed loco values
|
||||||
*/
|
*/
|
||||||
#define CLEAR_ALL_STASH
|
#define CLEAR_ALL_STASH
|
||||||
|
/**
|
||||||
|
* @def CLEAR_ANY_STASH
|
||||||
|
* @brief Clears loco value from all stash entries
|
||||||
|
*/
|
||||||
|
#define CLEAR_ANY_STASH
|
||||||
/**
|
/**
|
||||||
* @def CLOSE(turnout_id)
|
* @def CLOSE(turnout_id)
|
||||||
* @brief Close turnout by id
|
* @brief Close turnout by id
|
||||||
@ -602,6 +609,13 @@
|
|||||||
* @param signal_id
|
* @param signal_id
|
||||||
*/
|
*/
|
||||||
#define IFRED(signal_id)
|
#define IFRED(signal_id)
|
||||||
|
/**
|
||||||
|
* @def IFSTASH(stash_id)
|
||||||
|
* @brief Checks if given stash entry has a non zero value
|
||||||
|
* @see IF
|
||||||
|
* @param stash_id
|
||||||
|
*/
|
||||||
|
#define IFSTASH(stash_id)
|
||||||
/**
|
/**
|
||||||
* @def IFTHROWN(turnout_id)
|
* @def IFTHROWN(turnout_id)
|
||||||
* @brief Checks if given turnout is in THROWN state
|
* @brief Checks if given turnout is in THROWN state
|
||||||
|
@ -181,36 +181,7 @@ void RMFT2::ComandFilter(Print * stream, byte & opcode, byte & paramCount, int16
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "M"_hk:
|
|
||||||
// NOTE: we only need to handle valid calls here because
|
|
||||||
// DCCEXParser has to have code to handle the <J<> cases where
|
|
||||||
// exrail isnt involved anyway.
|
|
||||||
// This entire code block is compiled out if STASH macros not used
|
|
||||||
if (!(compileFeatures & FEATURE_STASH)) return;
|
|
||||||
if (paramCount==1) { // <JM>
|
|
||||||
StringFormatter::send(stream,F("<jM %d>\n"),maxStashId);
|
|
||||||
opcode=0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (paramCount==2) { // <JM id>
|
|
||||||
if (p[1]<=0 || p[1]>maxStashId) break;
|
|
||||||
StringFormatter::send(stream,F("<jM %d %d>\n"),
|
|
||||||
p[1],stashArray[p[1]]);
|
|
||||||
opcode=0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (paramCount==3) { // <JM id cab>
|
|
||||||
if (p[1]<=0 || p[1]>maxStashId) break;
|
|
||||||
stashArray[p[1]]=p[2];
|
|
||||||
opcode=0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'K': // <K blockid loco> Block enter
|
case 'K': // <K blockid loco> Block enter
|
||||||
case 'k': // <k blockid loco> Block exit
|
case 'k': // <k blockid loco> Block exit
|
||||||
@ -223,6 +194,7 @@ void RMFT2::ComandFilter(Print * stream, byte & opcode, byte & paramCount, int16
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool RMFT2::parseSlash(Print * stream, byte & paramCount, int16_t p[]) {
|
bool RMFT2::parseSlash(Print * stream, byte & paramCount, int16_t p[]) {
|
||||||
|
|
||||||
@ -268,15 +240,6 @@ bool RMFT2::parseSlash(Print * stream, byte & paramCount, int16_t p[]) {
|
|||||||
slot.id);
|
slot.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (compileFeatures & FEATURE_STASH) {
|
|
||||||
for (int i=1;i<=maxStashId;i++) {
|
|
||||||
if (stashArray[i])
|
|
||||||
StringFormatter::send(stream,F("\nSTASH[%d] Loco=%d"),
|
|
||||||
i, stashArray[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
StringFormatter::send(stream,F(" *>\n"));
|
StringFormatter::send(stream,F(" *>\n"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -136,11 +136,11 @@ constexpr bool unsafePin(const int16_t value, const uint16_t pos=0 ) {
|
|||||||
|
|
||||||
// check duplicate sequences
|
// check duplicate sequences
|
||||||
#undef SEQUENCE
|
#undef SEQUENCE
|
||||||
#define SEQUENCE(id) static_assert(seqCount(id)==1,"\n\nUSER ERROR: Duplicate ROUTE/AUTOMATION/SEQUENCE(" #id")\n");
|
#define SEQUENCE(id) static_assert(seqCount(id)==1,"\n\nUSER ERROR: Duplicate ROUTE/AUTOMATION/SEQUENCE(" #id ")\n");
|
||||||
#undef AUTOMATION
|
#undef AUTOMATION
|
||||||
#define AUTOMATION(id,description) static_assert(seqCount(id)==1,"\n\nUSER ERROR: Duplicate ROUTE/AUTOMATION/SEQUENCE(" #id")\n");
|
#define AUTOMATION(id,description) static_assert(seqCount(id)==1,"\n\nUSER ERROR: Duplicate ROUTE/AUTOMATION/SEQUENCE(" #id ")\n");
|
||||||
#undef ROUTE
|
#undef ROUTE
|
||||||
#define ROUTE(id,description) static_assert(seqCount(id)==1,"\n\nUSER ERROR: Duplicate ROUTE/AUTOMATION/SEQUENCE(" #id")\n");
|
#define ROUTE(id,description) static_assert(seqCount(id)==1,"\n\nUSER ERROR: Duplicate ROUTE/AUTOMATION/SEQUENCE(" #id ")\n");
|
||||||
|
|
||||||
// check dangerous pins
|
// check dangerous pins
|
||||||
#define _PIN_RESERVED_ "\n\nUSER ERROR: Pin is used by Motor Shield or other critical function.\n"
|
#define _PIN_RESERVED_ "\n\nUSER ERROR: Pin is used by Motor Shield or other critical function.\n"
|
||||||
|
@ -154,14 +154,6 @@ bool exrailHalSetup() {
|
|||||||
#undef ROUTE_CAPTION
|
#undef ROUTE_CAPTION
|
||||||
#define ROUTE_CAPTION(id,caption) | FEATURE_ROUTESTATE
|
#define ROUTE_CAPTION(id,caption) | FEATURE_ROUTESTATE
|
||||||
|
|
||||||
#undef CLEAR_STASH
|
|
||||||
#define CLEAR_STASH(id) | FEATURE_STASH
|
|
||||||
#undef CLEAR_ALL_STASH
|
|
||||||
#define CLEAR_ALL_STASH | FEATURE_STASH
|
|
||||||
#undef PICKUP_STASH
|
|
||||||
#define PICKUP_STASH(id) | FEATURE_STASH
|
|
||||||
#undef STASH
|
|
||||||
#define STASH(id) | FEATURE_STASH
|
|
||||||
#undef BLINK
|
#undef BLINK
|
||||||
#define BLINK(vpin,onDuty,offDuty) | FEATURE_BLINK
|
#define BLINK(vpin,onDuty,offDuty) | FEATURE_BLINK
|
||||||
#undef ONBUTTON
|
#undef ONBUTTON
|
||||||
@ -435,6 +427,7 @@ int RMFT2::onLCCLookup[RMFT2::countLCCLookup];
|
|||||||
#define CALL(route) OPCODE_CALL,V(route),
|
#define CALL(route) OPCODE_CALL,V(route),
|
||||||
#define CLEAR_STASH(id) OPCODE_CLEAR_STASH,V(id),
|
#define CLEAR_STASH(id) OPCODE_CLEAR_STASH,V(id),
|
||||||
#define CLEAR_ALL_STASH OPCODE_CLEAR_ALL_STASH,V(0),
|
#define CLEAR_ALL_STASH OPCODE_CLEAR_ALL_STASH,V(0),
|
||||||
|
#define CLEAR_ANY_STASH OPCODE_CLEAR_ANY_STASH,V(0),
|
||||||
#define CLOSE(id) OPCODE_CLOSE,V(id),
|
#define CLOSE(id) OPCODE_CLOSE,V(id),
|
||||||
#define CONFIGURE_SERVO(vpin,pos1,pos2,profile)
|
#define CONFIGURE_SERVO(vpin,pos1,pos2,profile)
|
||||||
#ifndef IO_NO_HAL
|
#ifndef IO_NO_HAL
|
||||||
@ -481,6 +474,7 @@ int RMFT2::onLCCLookup[RMFT2::countLCCLookup];
|
|||||||
#define IFRANDOM(percent) OPCODE_IFRANDOM,V(percent),
|
#define IFRANDOM(percent) OPCODE_IFRANDOM,V(percent),
|
||||||
#define IFRED(signal_id) OPCODE_IFRED,V(signal_id),
|
#define IFRED(signal_id) OPCODE_IFRED,V(signal_id),
|
||||||
#define IFRESERVE(block) OPCODE_IFRESERVE,V(block),
|
#define IFRESERVE(block) OPCODE_IFRESERVE,V(block),
|
||||||
|
#define IFSTASH(stash_id) OPCODE_IFSTASH,V(stash_id),
|
||||||
#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,
|
||||||
#ifndef IO_NO_HAL
|
#ifndef IO_NO_HAL
|
||||||
|
21
Release_Notes/Stash.md
Normal file
21
Release_Notes/Stash.md
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# The STASH feature of exrail.
|
||||||
|
|
||||||
|
STASH is used for scenarios where it is helpful to relate a loco id to where it is parked. For example a fiddle yard may have 10 tracks and it's much easier for the operator to select a train to depart by using the track number, or pressing a button relating to that track, rather than by knowing the loco id which may be difficult to see.
|
||||||
|
|
||||||
|
Automated yard parking can use the stash to determine which tracks are empty without the need for block occupancy detectors.
|
||||||
|
|
||||||
|
Note that a negative locoid may be stashed to indicate that the loco will operate with inverted direction. For example a loco facing backwards, with the INVERT_DRECTION state may be stashed by exrail and the invert state will be restored along with the loco id when using the PICKUP_STASH. CLEAR_ANY_STASH will clear all references to the loco regardless of direction.
|
||||||
|
|
||||||
|
The following Stash commands are available:
|
||||||
|
| EXRAIL command | Serial protocol | function |
|
||||||
|
| -------------- | --------------- | -------- |
|
||||||
|
| STASH(s) | `<JM s locoid>` | Save the current loco id in the stash array element s. |
|
||||||
|
| CLEAR_STASH(s) | `<JM s 0>` | Sets stash array element s to zero. |
|
||||||
|
| CLEAR_ALL_STASH | `<JM CLEAR ALL>` | sets all stash entries to zero |
|
||||||
|
| CLEAR_ANY_STASH | `<JM CLEAR ANY locoid>` | removes current loco from all stash elements |
|
||||||
|
| PICKUP_STASH(s) | N/A | sets current loco to stash element s |
|
||||||
|
| IFSTASH(s) | N/A | True if stash element s is not zero |
|
||||||
|
| N/A | `<JM>` | query all stashes (returns `<jM s loco>` where loco is not zero)
|
||||||
|
| N/A | `<JM stash>` | Query loco in stash (returns `<jM s loco>`)
|
||||||
|
|
||||||
|
|
89
Stash.cpp
Normal file
89
Stash.cpp
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
* © 2024 Chris Harlow
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This file is part of DCC-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 "Stash.h"
|
||||||
|
#include "StringFormatter.h"
|
||||||
|
|
||||||
|
Stash::Stash(int16_t stash_id, int16_t loco_id) {
|
||||||
|
this->stashId = stash_id;
|
||||||
|
this->locoId = loco_id;
|
||||||
|
this->next = first;
|
||||||
|
first = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Stash::clearAll() {
|
||||||
|
for (auto s=first;s;s=s->next) {
|
||||||
|
s->locoId = 0;
|
||||||
|
s->stashId =0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Stash::clearAny(int16_t loco_id) {
|
||||||
|
auto lid=abs(loco_id);
|
||||||
|
for (auto s=first;s;s=s->next)
|
||||||
|
if (abs(s->locoId) == lid) {
|
||||||
|
s->locoId = 0;
|
||||||
|
s->stashId =0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Stash::clear(int16_t stash_id) {
|
||||||
|
set(stash_id,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t Stash::get(int16_t stash_id) {
|
||||||
|
for (auto s=first;s;s=s->next)
|
||||||
|
if (s->stashId == stash_id) return s->locoId;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Stash::set(int16_t stash_id, int16_t loco_id) {
|
||||||
|
// replace any existing stash
|
||||||
|
for (auto s=first;s;s=s->next)
|
||||||
|
if (s->stashId == stash_id) {
|
||||||
|
s->locoId=loco_id;
|
||||||
|
if (loco_id==0) s->stashId=0; // recycle
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (loco_id==0) return; // no need to create a zero entry.
|
||||||
|
|
||||||
|
// replace any empty stash
|
||||||
|
for (auto s=first;s;s=s->next)
|
||||||
|
if (s->locoId == 0) {
|
||||||
|
s->locoId=loco_id;
|
||||||
|
s->stashId=stash_id;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// create a new stash
|
||||||
|
new Stash(stash_id, loco_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Stash::list(Print * stream, int16_t stash_id) {
|
||||||
|
bool sent=false;
|
||||||
|
for (auto s=first;s;s=s->next)
|
||||||
|
if ((s->locoId) && (stash_id==0 || s->stashId==stash_id)) {
|
||||||
|
StringFormatter::send(stream,F("<jM %d %d>\n"),
|
||||||
|
s->stashId,s->locoId);
|
||||||
|
sent=true;
|
||||||
|
}
|
||||||
|
if (!sent) StringFormatter::send(stream,F("<jM %d 0>\n"),
|
||||||
|
stash_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
Stash* Stash::first=nullptr;
|
39
Stash.h
Normal file
39
Stash.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* © 2024 Chris Harlow
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This file is part of DCC-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 Stash_h
|
||||||
|
#define Stash_h
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
class Stash {
|
||||||
|
public:
|
||||||
|
static void clear(int16_t stash_id);
|
||||||
|
static void clearAll();
|
||||||
|
static void clearAny(int16_t loco_id);
|
||||||
|
static int16_t get(int16_t stash_id);
|
||||||
|
static void set(int16_t stash_id, int16_t loco_id);
|
||||||
|
static void list(Print * stream, int16_t stash_id=0); // id0 = LIST ALL
|
||||||
|
private:
|
||||||
|
Stash(int16_t stash_id, int16_t loco_id);
|
||||||
|
static Stash* first;
|
||||||
|
Stash* next;
|
||||||
|
int16_t stashId;
|
||||||
|
int16_t locoId;
|
||||||
|
};
|
||||||
|
#endif
|
@ -3,7 +3,11 @@
|
|||||||
|
|
||||||
#include "StringFormatter.h"
|
#include "StringFormatter.h"
|
||||||
|
|
||||||
#define VERSION "5.5.17"
|
#define VERSION "5.5.18"
|
||||||
|
// 5.5.18 - New STASH internals
|
||||||
|
// - EXRAIL IFSTASH/CLEAR_ANY_STASH
|
||||||
|
// - <JM CLEAR ANY id> to clear any stash with loco id
|
||||||
|
// - See Release_Notes/Stash.md
|
||||||
// 5.5.17 - Extensive new compile time checking in exrail scripts (duplicate sequences etc), no function change
|
// 5.5.17 - Extensive new compile time checking in exrail scripts (duplicate sequences etc), no function change
|
||||||
// 5.5.16 - DOXYGEN comments in EXRAIL2MacroReset.h
|
// 5.5.16 - DOXYGEN comments in EXRAIL2MacroReset.h
|
||||||
// 5.5.15 - Support for F429ZI/F329ZI
|
// 5.5.15 - Support for F429ZI/F329ZI
|
||||||
|
Loading…
Reference in New Issue
Block a user