mirror of
https://github.com/DCC-EX/CommandStation-EX.git
synced 2024-11-24 08:36:14 +01:00
Compare commits
24 Commits
600880dacd
...
73d7babb52
Author | SHA1 | Date | |
---|---|---|---|
|
73d7babb52 | ||
|
ebaf1b984e | ||
|
697f228a05 | ||
|
c8e307db7a | ||
|
a5ccb2e29e | ||
|
42e2e69f5f | ||
|
2075bc50e8 | ||
|
a16214790e | ||
|
784934024e | ||
|
b478056a9f | ||
|
ef47257d67 | ||
|
03db06f2ee | ||
|
4308739c2b | ||
|
0cfea3e1a5 | ||
|
d0df9f3c33 | ||
|
ac4af407aa | ||
|
a236a205fe | ||
|
478e9661bb | ||
|
2c1b3e0a8f | ||
|
e7c4af5d4a | ||
|
263ed18b25 | ||
|
4e1fad4832 | ||
|
29ea746062 | ||
|
e6f33cfdee |
|
@ -254,29 +254,64 @@ void CommandDistributor::broadcastPower() {
|
||||||
if (TrackManager::getPower(t, pstr))
|
if (TrackManager::getPower(t, pstr))
|
||||||
broadcastReply(COMMAND_TYPE, F("<p%s>\n"),pstr);
|
broadcastReply(COMMAND_TYPE, F("<p%s>\n"),pstr);
|
||||||
|
|
||||||
|
byte trackcount=0;
|
||||||
|
byte oncount=0;
|
||||||
|
byte offcount=0;
|
||||||
|
for(byte t=0; t<TrackManager::MAX_TRACKS; t++) {
|
||||||
|
if (TrackManager::isActive(t)) {
|
||||||
|
trackcount++;
|
||||||
|
// do not call getPower(t) unless isActive(t)!
|
||||||
|
if (TrackManager::getPower(t) == POWERMODE::ON)
|
||||||
|
oncount++;
|
||||||
|
else
|
||||||
|
offcount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//DIAG(F("t=%d on=%d off=%d"), trackcount, oncount, offcount);
|
||||||
|
|
||||||
|
char state='2';
|
||||||
|
if (oncount==0 || offcount == trackcount)
|
||||||
|
state = '0';
|
||||||
|
else if (oncount == trackcount) {
|
||||||
|
state = '1';
|
||||||
|
}
|
||||||
|
|
||||||
|
// additional info about MAIN, PROG and JOIN
|
||||||
bool main=TrackManager::getMainPower()==POWERMODE::ON;
|
bool main=TrackManager::getMainPower()==POWERMODE::ON;
|
||||||
bool prog=TrackManager::getProgPower()==POWERMODE::ON;
|
bool prog=TrackManager::getProgPower()==POWERMODE::ON;
|
||||||
bool join=TrackManager::isJoined();
|
bool join=TrackManager::isJoined();
|
||||||
|
//DIAG(F("m=%d p=%d j=%d"), main, prog, join);
|
||||||
const FSH * reason=F("");
|
const FSH * reason=F("");
|
||||||
char state='1';
|
if (join) {
|
||||||
if (main && prog && join) reason=F(" JOIN");
|
reason = F("JOIN");
|
||||||
else if (main && prog);
|
broadcastReply(COMMAND_TYPE, F("<p1 %S>\n"),reason);
|
||||||
else if (main) reason=F(" MAIN");
|
} else {
|
||||||
else if (prog) reason=F(" PROG");
|
if (main) {
|
||||||
else state='0';
|
//reason = F("MAIN");
|
||||||
broadcastReply(COMMAND_TYPE, F("<p%c%S>\n"),state,reason);
|
broadcastReply(COMMAND_TYPE, F("<p1 MAIN>\n"));
|
||||||
|
}
|
||||||
|
if (prog) {
|
||||||
|
//reason = F("PROG");
|
||||||
|
broadcastReply(COMMAND_TYPE, F("<p1 PROG>\n"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state != '2')
|
||||||
|
broadcastReply(COMMAND_TYPE, F("<p%c>\n"),state);
|
||||||
#ifdef CD_HANDLE_RING
|
#ifdef CD_HANDLE_RING
|
||||||
broadcastReply(WITHROTTLE_TYPE, F("PPA%c\n"), main?'1':'0');
|
// send '1' if all main are on, otherwise global state (which in that case is '0' or '2')
|
||||||
|
broadcastReply(WITHROTTLE_TYPE, F("PPA%c\n"), main?'1': state);
|
||||||
#endif
|
#endif
|
||||||
LCD(2,F("Power %S%S"),state=='1'?F("On"):F("Off"),reason);
|
|
||||||
|
LCD(2,F("Power %S %S"),state=='1'?F("On"): ( state=='0'? F("Off") : F("SC") ),reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandDistributor::broadcastRaw(clientType type, char * msg) {
|
void CommandDistributor::broadcastRaw(clientType type, char * msg) {
|
||||||
broadcastReply(type, F("%s"),msg);
|
broadcastReply(type, F("%s"),msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandDistributor::broadcastTrackState(const FSH* format,byte trackLetter, int16_t dcAddr) {
|
void CommandDistributor::broadcastTrackState(const FSH* format, byte trackLetter, const FSH *modename, int16_t dcAddr) {
|
||||||
broadcastReply(COMMAND_TYPE, format, trackLetter, dcAddr);
|
broadcastReply(COMMAND_TYPE, format, trackLetter, modename, dcAddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandDistributor::broadcastRouteState(uint16_t routeId, byte state ) {
|
void CommandDistributor::broadcastRouteState(uint16_t routeId, byte state ) {
|
||||||
|
@ -330,7 +365,7 @@ void CommandDistributor::setVirtualLCDSerial(Print * stream) {
|
||||||
virtualLCDSerial=stream;
|
virtualLCDSerial=stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
Print* CommandDistributor::virtualLCDSerial=nullptr;
|
Print* CommandDistributor::virtualLCDSerial=&USB_SERIAL;
|
||||||
byte CommandDistributor::virtualLCDClient=0xFF;
|
byte CommandDistributor::virtualLCDClient=0xFF;
|
||||||
byte CommandDistributor::rememberVLCDClient=0;
|
byte CommandDistributor::rememberVLCDClient=0;
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,7 @@ public :
|
||||||
static int16_t retClockTime();
|
static int16_t retClockTime();
|
||||||
static void broadcastPower();
|
static void broadcastPower();
|
||||||
static void broadcastRaw(clientType type,char * msg);
|
static void broadcastRaw(clientType type,char * msg);
|
||||||
static void broadcastTrackState(const FSH* format,byte trackLetter, int16_t dcAddr);
|
static void broadcastTrackState(const FSH* format,byte trackLetter, const FSH* modename, int16_t dcAddr);
|
||||||
template<typename... Targs> static void broadcastReply(clientType type, Targs... msg);
|
template<typename... Targs> static void broadcastReply(clientType type, Targs... msg);
|
||||||
static void forget(byte clientId);
|
static void forget(byte clientId);
|
||||||
static void broadcastRouteState(uint16_t routeId,byte state);
|
static void broadcastRouteState(uint16_t routeId,byte state);
|
||||||
|
|
|
@ -87,7 +87,7 @@ void setup()
|
||||||
|
|
||||||
DISPLAY_START (
|
DISPLAY_START (
|
||||||
// This block is still executed for DIAGS if display not in use
|
// This block is still executed for DIAGS if display not in use
|
||||||
LCD(0,F("DCC-EX v%S"),F(VERSION));
|
LCD(0,F("DCC-EX v" VERSION));
|
||||||
LCD(1,F("Lic GPLv3"));
|
LCD(1,F("Lic GPLv3"));
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -160,6 +160,7 @@ const int16_t HASH_KEYWORD_C='C';
|
||||||
const int16_t HASH_KEYWORD_G='G';
|
const int16_t HASH_KEYWORD_G='G';
|
||||||
const int16_t HASH_KEYWORD_H='H';
|
const int16_t HASH_KEYWORD_H='H';
|
||||||
const int16_t HASH_KEYWORD_I='I';
|
const int16_t HASH_KEYWORD_I='I';
|
||||||
|
const int16_t HASH_KEYWORD_M='M';
|
||||||
const int16_t HASH_KEYWORD_O='O';
|
const int16_t HASH_KEYWORD_O='O';
|
||||||
const int16_t HASH_KEYWORD_P='P';
|
const int16_t HASH_KEYWORD_P='P';
|
||||||
const int16_t HASH_KEYWORD_R='R';
|
const int16_t HASH_KEYWORD_R='R';
|
||||||
|
@ -668,7 +669,7 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream)
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
case '=': // TRACK MANAGER CONTROL <= [params]>
|
case '=': // TRACK MANAGER CONTROL <= [params]>
|
||||||
if (TrackManager::parseJ(stream, params, p))
|
if (TrackManager::parseEqualSign(stream, params, p))
|
||||||
return;
|
return;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -729,6 +730,12 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream)
|
||||||
StringFormatter::send(stream, F("<jA>\n"));
|
StringFormatter::send(stream, F("<jA>\n"));
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
case HASH_KEYWORD_M: // <JM> intercepted by EXRAIL
|
||||||
|
if (params>1) break; // invalid cant do
|
||||||
|
// <JM> requests stash size so say none.
|
||||||
|
StringFormatter::send(stream,F("<jM 0>\n"));
|
||||||
|
return;
|
||||||
|
|
||||||
case HASH_KEYWORD_R: // <JR> returns rosters
|
case HASH_KEYWORD_R: // <JR> returns rosters
|
||||||
StringFormatter::send(stream, F("<jR"));
|
StringFormatter::send(stream, F("<jR"));
|
||||||
#ifdef EXRAIL_ACTIVE
|
#ifdef EXRAIL_ACTIVE
|
||||||
|
@ -840,13 +847,14 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream)
|
||||||
case 'L': // LCC interface implemented in EXRAIL parser
|
case 'L': // LCC interface implemented in EXRAIL parser
|
||||||
break; // Will <X> if not intercepted by EXRAIL
|
break; // Will <X> if not intercepted by EXRAIL
|
||||||
|
|
||||||
|
#ifndef DISABLE_VDPY
|
||||||
case '@': // JMRI saying "give me virtual LCD msgs"
|
case '@': // JMRI saying "give me virtual LCD msgs"
|
||||||
CommandDistributor::setVirtualLCDSerial(stream);
|
CommandDistributor::setVirtualLCDSerial(stream);
|
||||||
StringFormatter::send(stream,
|
StringFormatter::send(stream,
|
||||||
F("<@ 0 0 \"DCC-EX v" VERSION "\">\n"
|
F("<@ 0 0 \"DCC-EX v" VERSION "\">\n"
|
||||||
"<@ 0 1 \"Lic GPLv3\">\n"));
|
"<@ 0 1 \"Lic GPLv3\">\n"));
|
||||||
return;
|
return;
|
||||||
|
#endif
|
||||||
default: //anything else will diagnose and drop out to <X>
|
default: //anything else will diagnose and drop out to <X>
|
||||||
if (opcode >= ' ' && opcode <= '~') {
|
if (opcode >= ' ' && opcode <= '~') {
|
||||||
DIAG(F("Opcode=%c params=%d"), opcode, params);
|
DIAG(F("Opcode=%c params=%d"), opcode, params);
|
||||||
|
@ -1057,6 +1065,7 @@ bool DCCEXParser::parseS(Print *stream, int16_t params, int16_t p[])
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DCCEXParser::parseC(Print *stream, int16_t params, int16_t p[]) {
|
bool DCCEXParser::parseC(Print *stream, int16_t params, int16_t p[]) {
|
||||||
|
(void)stream; // arg not used, maybe later?
|
||||||
if (params == 0)
|
if (params == 0)
|
||||||
return false;
|
return false;
|
||||||
switch (p[0])
|
switch (p[0])
|
||||||
|
|
|
@ -54,7 +54,9 @@
|
||||||
xxx; \
|
xxx; \
|
||||||
t->refresh();}
|
t->refresh();}
|
||||||
#else
|
#else
|
||||||
#define DISPLAY_START(xxx) {}
|
#define DISPLAY_START(xxx) { \
|
||||||
|
xxx; \
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
#endif // LCD_Implementation_h
|
#endif // LCD_Implementation_h
|
||||||
|
|
44
EXRAIL2.cpp
44
EXRAIL2.cpp
|
@ -86,6 +86,8 @@ LookList * RMFT2::onRotateLookup=NULL;
|
||||||
LookList * RMFT2::onOverloadLookup=NULL;
|
LookList * RMFT2::onOverloadLookup=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) {
|
||||||
|
@ -232,6 +234,12 @@ if (compileFeatures & FEATURE_SIGNAL) {
|
||||||
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:
|
||||||
|
@ -312,7 +320,13 @@ if (compileFeatures & FEATURE_SIGNAL) {
|
||||||
}
|
}
|
||||||
SKIPOP; // include ENDROUTES opcode
|
SKIPOP; // include ENDROUTES opcode
|
||||||
|
|
||||||
DIAG(F("EXRAIL %db, fl=%d"),progCounter,MAX_FLAGS);
|
if (compileFeatures & FEATURE_STASH) {
|
||||||
|
// 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;
|
||||||
|
@ -936,6 +950,34 @@ void RMFT2::loop2() {
|
||||||
manageRouteState(operand,4);
|
manageRouteState(operand,4);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case OPCODE_STASH:
|
||||||
|
if (compileFeatures & FEATURE_STASH)
|
||||||
|
stashArray[operand] = invert? -loco : loco;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPCODE_CLEAR_STASH:
|
||||||
|
if (compileFeatures & FEATURE_STASH)
|
||||||
|
stashArray[operand] = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPCODE_CLEAR_ALL_STASH:
|
||||||
|
if (compileFeatures & FEATURE_STASH)
|
||||||
|
for (int i=0;i<=maxStashId;i++) stashArray[operand]=0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPCODE_PICKUP_STASH:
|
||||||
|
if (compileFeatures & FEATURE_STASH) {
|
||||||
|
int16_t x=stashArray[operand];
|
||||||
|
if (x>=0) {
|
||||||
|
loco=x;
|
||||||
|
invert=false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
loco=-x;
|
||||||
|
invert=true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case OPCODE_ROUTE:
|
case OPCODE_ROUTE:
|
||||||
case OPCODE_AUTOMATION:
|
case OPCODE_AUTOMATION:
|
||||||
case OPCODE_SEQUENCE:
|
case OPCODE_SEQUENCE:
|
||||||
|
|
|
@ -70,6 +70,7 @@ enum OPCODE : byte {OPCODE_THROW,OPCODE_CLOSE,
|
||||||
OPCODE_ONOVERLOAD,
|
OPCODE_ONOVERLOAD,
|
||||||
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,
|
||||||
|
|
||||||
// OPcodes below this point are skip-nesting IF operations
|
// OPcodes below this point are skip-nesting IF operations
|
||||||
// placed here so that they may be skipped as a group
|
// placed here so that they may be skipped as a group
|
||||||
|
@ -102,6 +103,7 @@ enum thrunger: byte {
|
||||||
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;
|
||||||
|
|
||||||
|
|
||||||
// Flag bits for status of hardware and TPL
|
// Flag bits for status of hardware and TPL
|
||||||
|
@ -203,7 +205,7 @@ private:
|
||||||
uint16_t getOperand(byte n);
|
uint16_t getOperand(byte n);
|
||||||
|
|
||||||
static bool diag;
|
static bool diag;
|
||||||
static const HIGHFLASH byte RouteCode[];
|
static const HIGHFLASH3 byte RouteCode[];
|
||||||
static const HIGHFLASH int16_t SignalDefinitions[];
|
static const HIGHFLASH int16_t SignalDefinitions[];
|
||||||
static byte flags[MAX_FLAGS];
|
static byte flags[MAX_FLAGS];
|
||||||
static Print * LCCSerial;
|
static Print * LCCSerial;
|
||||||
|
@ -229,6 +231,8 @@ private:
|
||||||
static void manageRouteCaption(uint16_t id, const FSH* caption);
|
static void manageRouteCaption(uint16_t id, const FSH* caption);
|
||||||
static byte * routeStateArray;
|
static byte * routeStateArray;
|
||||||
static const FSH ** routeCaptionArray;
|
static const FSH ** routeCaptionArray;
|
||||||
|
static int16_t * stashArray;
|
||||||
|
static int16_t maxStashId;
|
||||||
|
|
||||||
// Local variables - exist for each instance/task
|
// Local variables - exist for each instance/task
|
||||||
RMFT2 *next; // loop chain
|
RMFT2 *next; // loop chain
|
||||||
|
|
|
@ -39,6 +39,8 @@
|
||||||
#undef AUTOSTART
|
#undef AUTOSTART
|
||||||
#undef BROADCAST
|
#undef BROADCAST
|
||||||
#undef CALL
|
#undef CALL
|
||||||
|
#undef CLEAR_STASH
|
||||||
|
#undef CLEAR_ALL_STASH
|
||||||
#undef CLOSE
|
#undef CLOSE
|
||||||
#undef DCC_SIGNAL
|
#undef DCC_SIGNAL
|
||||||
#undef DCC_TURNTABLE
|
#undef DCC_TURNTABLE
|
||||||
|
@ -108,6 +110,7 @@
|
||||||
#undef ONCHANGE
|
#undef ONCHANGE
|
||||||
#undef PARSE
|
#undef PARSE
|
||||||
#undef PAUSE
|
#undef PAUSE
|
||||||
|
#undef PICKUP_STASH
|
||||||
#undef PIN_TURNOUT
|
#undef PIN_TURNOUT
|
||||||
#undef PRINT
|
#undef PRINT
|
||||||
#ifndef DISABLE_PROG
|
#ifndef DISABLE_PROG
|
||||||
|
@ -152,6 +155,7 @@
|
||||||
#undef SIGNALH
|
#undef SIGNALH
|
||||||
#undef SPEED
|
#undef SPEED
|
||||||
#undef START
|
#undef START
|
||||||
|
#undef STASH
|
||||||
#undef STOP
|
#undef STOP
|
||||||
#undef THROW
|
#undef THROW
|
||||||
#undef TT_ADDPOSITION
|
#undef TT_ADDPOSITION
|
||||||
|
@ -185,6 +189,8 @@
|
||||||
#define AUTOSTART
|
#define AUTOSTART
|
||||||
#define BROADCAST(msg)
|
#define BROADCAST(msg)
|
||||||
#define CALL(route)
|
#define CALL(route)
|
||||||
|
#define CLEAR_STASH(id)
|
||||||
|
#define CLEAR_ALL_STASH(id)
|
||||||
#define CLOSE(id)
|
#define CLOSE(id)
|
||||||
#define DCC_SIGNAL(id,add,subaddr)
|
#define DCC_SIGNAL(id,add,subaddr)
|
||||||
#define DCC_TURNTABLE(id,home,description)
|
#define DCC_TURNTABLE(id,home,description)
|
||||||
|
@ -256,6 +262,7 @@
|
||||||
#define PIN_TURNOUT(id,pin,description...)
|
#define PIN_TURNOUT(id,pin,description...)
|
||||||
#define PRINT(msg)
|
#define PRINT(msg)
|
||||||
#define PARSE(msg)
|
#define PARSE(msg)
|
||||||
|
#define PICKUP_STASH(id)
|
||||||
#ifndef DISABLE_PROG
|
#ifndef DISABLE_PROG
|
||||||
#define POM(cv,value)
|
#define POM(cv,value)
|
||||||
#endif
|
#endif
|
||||||
|
@ -298,6 +305,7 @@
|
||||||
#define SIGNALH(redpin,amberpin,greenpin)
|
#define SIGNALH(redpin,amberpin,greenpin)
|
||||||
#define SPEED(speed)
|
#define SPEED(speed)
|
||||||
#define START(route)
|
#define START(route)
|
||||||
|
#define STASH(id)
|
||||||
#define STOP
|
#define STOP
|
||||||
#define THROW(id)
|
#define THROW(id)
|
||||||
#define TT_ADDPOSITION(turntable_id,position,value,angle,description...)
|
#define TT_ADDPOSITION(turntable_id,position,value,angle,description...)
|
||||||
|
|
|
@ -45,6 +45,8 @@ const int16_t HASH_KEYWORD_RED=26099;
|
||||||
const int16_t HASH_KEYWORD_AMBER=18713;
|
const int16_t HASH_KEYWORD_AMBER=18713;
|
||||||
const int16_t HASH_KEYWORD_GREEN=-31493;
|
const int16_t HASH_KEYWORD_GREEN=-31493;
|
||||||
const int16_t HASH_KEYWORD_A='A';
|
const int16_t HASH_KEYWORD_A='A';
|
||||||
|
const int16_t HASH_KEYWORD_M='M';
|
||||||
|
|
||||||
|
|
||||||
// This filter intercepts <> commands to do the following:
|
// This filter intercepts <> commands to do the following:
|
||||||
// - Implement RMFT specific commands/diagnostics
|
// - Implement RMFT specific commands/diagnostics
|
||||||
|
@ -150,6 +152,32 @@ void RMFT2::ComandFilter(Print * stream, byte & opcode, byte & paramCount, int16
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case HASH_KEYWORD_M:
|
||||||
|
// 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:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -195,6 +223,15 @@ bool RMFT2::parseSlash(Print * stream, byte & paramCount, int16_t p[]) {
|
||||||
sigid & SIGNAL_ID_MASK);
|
sigid & SIGNAL_ID_MASK);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,6 +113,15 @@ void 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
|
||||||
|
|
||||||
const byte RMFT2::compileFeatures = 0
|
const byte RMFT2::compileFeatures = 0
|
||||||
#include "myAutomation.h"
|
#include "myAutomation.h"
|
||||||
;
|
;
|
||||||
|
@ -353,6 +362,8 @@ int RMFT2::onLCCLookup[RMFT2::countLCCLookup];
|
||||||
#define AUTOSTART OPCODE_AUTOSTART,0,0,
|
#define AUTOSTART OPCODE_AUTOSTART,0,0,
|
||||||
#define BROADCAST(msg) PRINT(msg)
|
#define BROADCAST(msg) PRINT(msg)
|
||||||
#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_ALL_STASH OPCODE_CLEAR_ALL_STASH,V(0),
|
||||||
#define CLOSE(id) OPCODE_CLOSE,V(id),
|
#define CLOSE(id) OPCODE_CLOSE,V(id),
|
||||||
#ifndef IO_NO_HAL
|
#ifndef IO_NO_HAL
|
||||||
#define DCC_TURNTABLE(id,home,description...) OPCODE_DCCTURNTABLE,V(id),OPCODE_PAD,V(home),
|
#define DCC_TURNTABLE(id,home,description...) OPCODE_DCCTURNTABLE,V(id),OPCODE_PAD,V(home),
|
||||||
|
@ -435,6 +446,7 @@ int RMFT2::onLCCLookup[RMFT2::countLCCLookup];
|
||||||
#define ONTHROW(turnout_id) OPCODE_ONTHROW,V(turnout_id),
|
#define ONTHROW(turnout_id) OPCODE_ONTHROW,V(turnout_id),
|
||||||
#define ONCHANGE(sensor_id) OPCODE_ONCHANGE,V(sensor_id),
|
#define ONCHANGE(sensor_id) OPCODE_ONCHANGE,V(sensor_id),
|
||||||
#define PAUSE OPCODE_PAUSE,0,0,
|
#define PAUSE OPCODE_PAUSE,0,0,
|
||||||
|
#define PICKUP_STASH(id) OPCODE_PICKUP_STASH,V(id),
|
||||||
#define PIN_TURNOUT(id,pin,description...) OPCODE_PINTURNOUT,V(id),OPCODE_PAD,V(pin),
|
#define PIN_TURNOUT(id,pin,description...) OPCODE_PINTURNOUT,V(id),OPCODE_PAD,V(pin),
|
||||||
#ifndef DISABLE_PROG
|
#ifndef DISABLE_PROG
|
||||||
#define POM(cv,value) OPCODE_POM,V(cv),OPCODE_PAD,V(value),
|
#define POM(cv,value) OPCODE_POM,V(cv),OPCODE_PAD,V(value),
|
||||||
|
@ -482,6 +494,7 @@ int RMFT2::onLCCLookup[RMFT2::countLCCLookup];
|
||||||
#define SIGNALH(redpin,amberpin,greenpin)
|
#define SIGNALH(redpin,amberpin,greenpin)
|
||||||
#define SPEED(speed) OPCODE_SPEED,V(speed),
|
#define SPEED(speed) OPCODE_SPEED,V(speed),
|
||||||
#define START(route) OPCODE_START,V(route),
|
#define START(route) OPCODE_START,V(route),
|
||||||
|
#define STASH(id) OPCODE_STASH,V(id),
|
||||||
#define STOP OPCODE_SPEED,V(0),
|
#define STOP OPCODE_SPEED,V(0),
|
||||||
#define THROW(id) OPCODE_THROW,V(id),
|
#define THROW(id) OPCODE_THROW,V(id),
|
||||||
#ifndef IO_NO_HAL
|
#ifndef IO_NO_HAL
|
||||||
|
@ -503,7 +516,7 @@ int RMFT2::onLCCLookup[RMFT2::countLCCLookup];
|
||||||
|
|
||||||
// Build RouteCode
|
// Build RouteCode
|
||||||
const int StringMacroTracker2=__COUNTER__;
|
const int StringMacroTracker2=__COUNTER__;
|
||||||
const HIGHFLASH byte RMFT2::RouteCode[] = {
|
const HIGHFLASH3 byte RMFT2::RouteCode[] = {
|
||||||
#include "myAutomation.h"
|
#include "myAutomation.h"
|
||||||
OPCODE_ENDTASK,0,0,OPCODE_ENDEXRAIL,0,0 };
|
OPCODE_ENDTASK,0,0,OPCODE_ENDEXRAIL,0,0 };
|
||||||
|
|
||||||
|
|
3
FSH.h
3
FSH.h
|
@ -56,6 +56,7 @@ typedef __FlashStringHelper FSH;
|
||||||
#if defined(ARDUINO_AVR_MEGA) || defined(ARDUINO_AVR_MEGA2560)
|
#if defined(ARDUINO_AVR_MEGA) || defined(ARDUINO_AVR_MEGA2560)
|
||||||
// AVR_MEGA memory deliberately placed at end of link may need _far functions
|
// AVR_MEGA memory deliberately placed at end of link may need _far functions
|
||||||
#define HIGHFLASH __attribute__((section(".fini2")))
|
#define HIGHFLASH __attribute__((section(".fini2")))
|
||||||
|
#define HIGHFLASH3 __attribute__((section(".fini3")))
|
||||||
#define GETFARPTR(data) pgm_get_far_address(data)
|
#define GETFARPTR(data) pgm_get_far_address(data)
|
||||||
#define GETHIGHFLASH(data,offset) pgm_read_byte_far(GETFARPTR(data)+offset)
|
#define GETHIGHFLASH(data,offset) pgm_read_byte_far(GETFARPTR(data)+offset)
|
||||||
#define GETHIGHFLASHW(data,offset) pgm_read_word_far(GETFARPTR(data)+offset)
|
#define GETHIGHFLASHW(data,offset) pgm_read_word_far(GETFARPTR(data)+offset)
|
||||||
|
@ -63,6 +64,7 @@ typedef __FlashStringHelper FSH;
|
||||||
// AVR_UNO/NANO runtime does not support _far functions so just use _near equivalent
|
// AVR_UNO/NANO runtime does not support _far functions so just use _near equivalent
|
||||||
// as there is no progmem above 32kb anyway.
|
// as there is no progmem above 32kb anyway.
|
||||||
#define HIGHFLASH PROGMEM
|
#define HIGHFLASH PROGMEM
|
||||||
|
#define HIGHFLASH3 PROGMEM
|
||||||
#define GETFARPTR(data) ((uint32_t)(data))
|
#define GETFARPTR(data) ((uint32_t)(data))
|
||||||
#define GETHIGHFLASH(data,offset) pgm_read_byte_near(GETFARPTR(data)+(offset))
|
#define GETHIGHFLASH(data,offset) pgm_read_byte_near(GETFARPTR(data)+(offset))
|
||||||
#define GETHIGHFLASHW(data,offset) pgm_read_word_near(GETFARPTR(data)+(offset))
|
#define GETHIGHFLASHW(data,offset) pgm_read_word_near(GETFARPTR(data)+(offset))
|
||||||
|
@ -80,6 +82,7 @@ typedef __FlashStringHelper FSH;
|
||||||
typedef char FSH;
|
typedef char FSH;
|
||||||
#define FLASH
|
#define FLASH
|
||||||
#define HIGHFLASH
|
#define HIGHFLASH
|
||||||
|
#define HIGHFLASH3
|
||||||
#define GETFARPTR(data) ((uint32_t)(data))
|
#define GETFARPTR(data) ((uint32_t)(data))
|
||||||
#define GETFLASH(addr) (*(const byte *)(addr))
|
#define GETFLASH(addr) (*(const byte *)(addr))
|
||||||
#define GETHIGHFLASH(data,offset) (*(const byte *)(GETFARPTR(data)+offset))
|
#define GETHIGHFLASH(data,offset) (*(const byte *)(GETFARPTR(data)+offset))
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
#define GITHUB_SHA "devel-202311200731Z"
|
#define GITHUB_SHA "devel-202311232114Z"
|
||||||
|
|
|
@ -156,8 +156,10 @@ class MotorDriver {
|
||||||
// from outside interrupt
|
// from outside interrupt
|
||||||
void setBrake( bool on, bool interruptContext=false);
|
void setBrake( bool on, bool interruptContext=false);
|
||||||
__attribute__((always_inline)) inline void setSignal( bool high) {
|
__attribute__((always_inline)) inline void setSignal( bool high) {
|
||||||
|
#ifndef ARDUINO_ARCH_ESP32
|
||||||
if (invertPhase)
|
if (invertPhase)
|
||||||
high = !high;
|
high = !high;
|
||||||
|
#endif
|
||||||
if (trackPWM) {
|
if (trackPWM) {
|
||||||
DCCTimer::setPWM(signalPin,high);
|
DCCTimer::setPWM(signalPin,high);
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,8 +39,11 @@ void StringFormatter::diag( const FSH* input...) {
|
||||||
|
|
||||||
void StringFormatter::lcd(byte row, const FSH* input...) {
|
void StringFormatter::lcd(byte row, const FSH* input...) {
|
||||||
va_list args;
|
va_list args;
|
||||||
|
#ifndef DISABLE_VDPY
|
||||||
Print * virtualLCD=CommandDistributor::getVirtualLCDSerial(0,row);
|
Print * virtualLCD=CommandDistributor::getVirtualLCDSerial(0,row);
|
||||||
|
#else
|
||||||
|
Print * virtualLCD=NULL;
|
||||||
|
#endif
|
||||||
// Issue the LCD as a diag first
|
// Issue the LCD as a diag first
|
||||||
// Unless the same serial is asking for the virtual @ respomnse
|
// Unless the same serial is asking for the virtual @ respomnse
|
||||||
if (virtualLCD!=&USB_SERIAL) {
|
if (virtualLCD!=&USB_SERIAL) {
|
||||||
|
@ -50,13 +53,14 @@ void StringFormatter::lcd(byte row, const FSH* input...) {
|
||||||
send(&USB_SERIAL,F(" *>\n"));
|
send(&USB_SERIAL,F(" *>\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef DISABLE_VDPY
|
||||||
// send to virtual LCD collector (if any)
|
// send to virtual LCD collector (if any)
|
||||||
if (virtualLCD) {
|
if (virtualLCD) {
|
||||||
va_start(args, input);
|
va_start(args, input);
|
||||||
send2(virtualLCD,input,args);
|
send2(virtualLCD,input,args);
|
||||||
CommandDistributor::commitVirtualLCDSerial();
|
CommandDistributor::commitVirtualLCDSerial();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
DisplayInterface::setRow(row);
|
DisplayInterface::setRow(row);
|
||||||
va_start(args, input);
|
va_start(args, input);
|
||||||
send2(DisplayInterface::getDisplayHandler(),input,args);
|
send2(DisplayInterface::getDisplayHandler(),input,args);
|
||||||
|
@ -66,12 +70,14 @@ void StringFormatter::lcd2(uint8_t display, byte row, const FSH* input...) {
|
||||||
va_list args;
|
va_list args;
|
||||||
|
|
||||||
// send to virtual LCD collector (if any)
|
// send to virtual LCD collector (if any)
|
||||||
|
#ifndef DISABLE_VDPY
|
||||||
Print * virtualLCD=CommandDistributor::getVirtualLCDSerial(display,row);
|
Print * virtualLCD=CommandDistributor::getVirtualLCDSerial(display,row);
|
||||||
if (virtualLCD) {
|
if (virtualLCD) {
|
||||||
va_start(args, input);
|
va_start(args, input);
|
||||||
send2(virtualLCD,input,args);
|
send2(virtualLCD,input,args);
|
||||||
CommandDistributor::commitVirtualLCDSerial();
|
CommandDistributor::commitVirtualLCDSerial();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
DisplayInterface::setRow(display, row);
|
DisplayInterface::setRow(display, row);
|
||||||
va_start(args, input);
|
va_start(args, input);
|
||||||
|
@ -250,4 +256,3 @@ void StringFormatter::printHex(Print * stream,uint16_t value) {
|
||||||
result[4]='\0';
|
result[4]='\0';
|
||||||
stream->print(result);
|
stream->print(result);
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,6 @@ const int16_t HASH_KEYWORD_INV = 11857;
|
||||||
MotorDriver * TrackManager::track[MAX_TRACKS];
|
MotorDriver * TrackManager::track[MAX_TRACKS];
|
||||||
int16_t TrackManager::trackDCAddr[MAX_TRACKS];
|
int16_t TrackManager::trackDCAddr[MAX_TRACKS];
|
||||||
|
|
||||||
POWERMODE TrackManager::mainPowerGuess=POWERMODE::OFF;
|
|
||||||
byte TrackManager::lastTrack=0;
|
byte TrackManager::lastTrack=0;
|
||||||
bool TrackManager::progTrackSyncMain=false;
|
bool TrackManager::progTrackSyncMain=false;
|
||||||
bool TrackManager::progTrackBoosted=false;
|
bool TrackManager::progTrackBoosted=false;
|
||||||
|
@ -210,6 +209,9 @@ void TrackManager::setDCSignal(int16_t cab, byte speedbyte) {
|
||||||
bool TrackManager::setTrackMode(byte trackToSet, TRACK_MODE mode, int16_t dcAddr) {
|
bool TrackManager::setTrackMode(byte trackToSet, TRACK_MODE mode, int16_t dcAddr) {
|
||||||
if (trackToSet>lastTrack || track[trackToSet]==NULL) return false;
|
if (trackToSet>lastTrack || track[trackToSet]==NULL) return false;
|
||||||
|
|
||||||
|
// Remember track mode we came from for later
|
||||||
|
TRACK_MODE oldmode = track[trackToSet]->getMode();
|
||||||
|
|
||||||
//DIAG(F("Track=%c Mode=%d"),trackToSet+'A', mode);
|
//DIAG(F("Track=%c Mode=%d"),trackToSet+'A', mode);
|
||||||
// DC tracks require a motorDriver that can set brake!
|
// DC tracks require a motorDriver that can set brake!
|
||||||
if (mode & TRACK_MODE_DC) {
|
if (mode & TRACK_MODE_DC) {
|
||||||
|
@ -270,7 +272,6 @@ bool TrackManager::setTrackMode(byte trackToSet, TRACK_MODE mode, int16_t dcAddr
|
||||||
}
|
}
|
||||||
track[trackToSet]->setMode(mode);
|
track[trackToSet]->setMode(mode);
|
||||||
trackDCAddr[trackToSet]=dcAddr;
|
trackDCAddr[trackToSet]=dcAddr;
|
||||||
streamTrackState(NULL,trackToSet);
|
|
||||||
|
|
||||||
// When a track is switched, we must clear any side effects of its previous
|
// When a track is switched, we must clear any side effects of its previous
|
||||||
// state, otherwise trains run away or just dont move.
|
// state, otherwise trains run away or just dont move.
|
||||||
|
@ -337,10 +338,11 @@ bool TrackManager::setTrackMode(byte trackToSet, TRACK_MODE mode, int16_t dcAddr
|
||||||
applyDCSpeed(trackToSet);
|
applyDCSpeed(trackToSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Normal running tracks are set to the global power state
|
// Turn off power if we changed the mode of this track
|
||||||
track[trackToSet]->setPower(
|
if (mode != oldmode)
|
||||||
(mode & (TRACK_MODE_MAIN | TRACK_MODE_DC | TRACK_MODE_EXT | TRACK_MODE_BOOST)) ?
|
track[trackToSet]->setPower(POWERMODE::OFF);
|
||||||
mainPowerGuess : POWERMODE::OFF);
|
streamTrackState(NULL,trackToSet);
|
||||||
|
|
||||||
//DIAG(F("TrackMode=%d"),mode);
|
//DIAG(F("TrackMode=%d"),mode);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -350,7 +352,7 @@ void TrackManager::applyDCSpeed(byte t) {
|
||||||
track[t]->setDCSignal(speedByte);
|
track[t]->setDCSignal(speedByte);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TrackManager::parseJ(Print *stream, int16_t params, int16_t p[])
|
bool TrackManager::parseEqualSign(Print *stream, int16_t params, int16_t p[])
|
||||||
{
|
{
|
||||||
|
|
||||||
if (params==0) { // <=> List track assignments
|
if (params==0) { // <=> List track assignments
|
||||||
|
@ -397,46 +399,60 @@ bool TrackManager::parseJ(Print *stream, int16_t params, int16_t p[])
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TrackManager::streamTrackState(Print* stream, byte t) {
|
const FSH* TrackManager::getModeName(TRACK_MODE tm) {
|
||||||
// null stream means send to commandDistributor for broadcast
|
const FSH *modename=F("---");
|
||||||
if (track[t]==NULL) return;
|
|
||||||
auto format=F("<= %d XXX>\n");
|
|
||||||
TRACK_MODE tm = track[t]->getMode();
|
|
||||||
if (tm & TRACK_MODE_MAIN) {
|
if (tm & TRACK_MODE_MAIN) {
|
||||||
if(tm & TRACK_MODE_AUTOINV)
|
if(tm & TRACK_MODE_AUTOINV)
|
||||||
format=F("<= %c MAIN A>\n");
|
modename=F("MAIN A");
|
||||||
else if (tm & TRACK_MODE_INV)
|
else if (tm & TRACK_MODE_INV)
|
||||||
format=F("<= %c MAIN I>\n");
|
modename=F("MAIN I>\n");
|
||||||
else
|
else
|
||||||
format=F("<= %c MAIN>\n");
|
modename=F("MAIN");
|
||||||
}
|
}
|
||||||
#ifndef DISABLE_PROG
|
#ifndef DISABLE_PROG
|
||||||
else if (tm & TRACK_MODE_PROG)
|
else if (tm & TRACK_MODE_PROG)
|
||||||
format=F("<= %c PROG>\n");
|
modename=F("PROG");
|
||||||
#endif
|
#endif
|
||||||
else if (tm & TRACK_MODE_NONE)
|
else if (tm & TRACK_MODE_NONE)
|
||||||
format=F("<= %c NONE>\n");
|
modename=F("NONE");
|
||||||
else if(tm & TRACK_MODE_EXT)
|
else if(tm & TRACK_MODE_EXT)
|
||||||
format=F("<= %c EXT>\n");
|
modename=F("EXT");
|
||||||
else if(tm & TRACK_MODE_BOOST) {
|
else if(tm & TRACK_MODE_BOOST) {
|
||||||
if(tm & TRACK_MODE_AUTOINV)
|
if(tm & TRACK_MODE_AUTOINV)
|
||||||
format=F("<= %c B A>\n");
|
modename=F("B A");
|
||||||
else if (tm & TRACK_MODE_INV)
|
else if (tm & TRACK_MODE_INV)
|
||||||
format=F("<= %c B I>\n");
|
modename=F("B I");
|
||||||
else
|
else
|
||||||
format=F("<= %c B>\n");
|
modename=F("B");
|
||||||
}
|
}
|
||||||
else if (tm & TRACK_MODE_DC) {
|
else if (tm & TRACK_MODE_DC) {
|
||||||
if (tm & TRACK_MODE_INV)
|
if (tm & TRACK_MODE_INV)
|
||||||
format=F("<= %c DCX %d>\n");
|
modename=F("DCX");
|
||||||
else
|
else
|
||||||
format=F("<= %c DC %d>\n");
|
modename=F("DC");
|
||||||
}
|
}
|
||||||
|
return modename;
|
||||||
|
}
|
||||||
|
|
||||||
if (stream)
|
// null stream means send to commandDistributor for broadcast
|
||||||
StringFormatter::send(stream,format,'A'+t, trackDCAddr[t]);
|
void TrackManager::streamTrackState(Print* stream, byte t) {
|
||||||
|
const FSH *format;
|
||||||
|
|
||||||
|
if (track[t]==NULL) return;
|
||||||
|
TRACK_MODE tm = track[t]->getMode();
|
||||||
|
if (tm & TRACK_MODE_DC)
|
||||||
|
format=F("<= %c %S %d>\n");
|
||||||
else
|
else
|
||||||
CommandDistributor::broadcastTrackState(format,'A'+t, trackDCAddr[t]);
|
format=F("<= %c %S>\n");
|
||||||
|
|
||||||
|
const FSH *modename=getModeName(tm);
|
||||||
|
if (stream) { // null stream means send to commandDistributor for broadcast
|
||||||
|
StringFormatter::send(stream,format,'A'+t, modename, trackDCAddr[t]);
|
||||||
|
} else {
|
||||||
|
CommandDistributor::broadcastTrackState(format,'A'+t, modename, trackDCAddr[t]);
|
||||||
|
CommandDistributor::broadcastPower();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -497,12 +513,15 @@ void TrackManager::setTrackPower(TRACK_MODE trackmodeToMatch, POWERMODE powermod
|
||||||
void TrackManager::setTrackPower(POWERMODE powermode, byte t) {
|
void TrackManager::setTrackPower(POWERMODE powermode, byte t) {
|
||||||
MotorDriver *driver=track[t];
|
MotorDriver *driver=track[t];
|
||||||
TRACK_MODE trackmode = driver->getMode();
|
TRACK_MODE trackmode = driver->getMode();
|
||||||
if (trackmode & TRACK_MODE_DC) {
|
if (trackmode & TRACK_MODE_NONE) {
|
||||||
|
driver->setBrake(true); // Track is unused. Brake is good to have.
|
||||||
|
powermode = POWERMODE::OFF; // Track is unused. Force it to OFF
|
||||||
|
} else if (trackmode & TRACK_MODE_DC) { // includes inverted DC (called DCX)
|
||||||
if (powermode == POWERMODE::ON) {
|
if (powermode == POWERMODE::ON) {
|
||||||
driver->setBrake(true); // DC starts with brake on
|
driver->setBrake(true); // DC starts with brake on
|
||||||
applyDCSpeed(t); // speed match DCC throttles
|
applyDCSpeed(t); // speed match DCC throttles
|
||||||
}
|
}
|
||||||
} else {
|
} else /* MAIN PROG EXT BOOST */ {
|
||||||
if (powermode == POWERMODE::ON) {
|
if (powermode == POWERMODE::ON) {
|
||||||
// toggle brake before turning power on - resets overcurrent error
|
// toggle brake before turning power on - resets overcurrent error
|
||||||
// on the Pololu board if brake is wired to ^D2.
|
// on the Pololu board if brake is wired to ^D2.
|
||||||
|
@ -513,15 +532,6 @@ void TrackManager::setTrackPower(POWERMODE powermode, byte t) {
|
||||||
driver->setPower(powermode);
|
driver->setPower(powermode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TrackManager::reportPowerChange(Print* stream, byte thistrack) {
|
|
||||||
// This function is for backward JMRI compatibility only
|
|
||||||
// It reports the first track only, as main, regardless of track settings.
|
|
||||||
// <c MeterName value C/V unit min max res warn>
|
|
||||||
int maxCurrent=track[0]->raw2mA(track[0]->getRawCurrentTripValue());
|
|
||||||
StringFormatter::send(stream, F("<c CurrentMAIN %d C Milli 0 %d 1 %d>\n"),
|
|
||||||
track[0]->raw2mA(track[0]->getCurrentRaw(false)), maxCurrent, maxCurrent);
|
|
||||||
}
|
|
||||||
|
|
||||||
// returns state of the one and only prog track
|
// returns state of the one and only prog track
|
||||||
POWERMODE TrackManager::getProgPower() {
|
POWERMODE TrackManager::getProgPower() {
|
||||||
FOR_EACH_TRACK(t)
|
FOR_EACH_TRACK(t)
|
||||||
|
@ -639,18 +649,3 @@ int16_t TrackManager::returnDCAddr(byte t) {
|
||||||
return (trackDCAddr[t]);
|
return (trackDCAddr[t]);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* TrackManager::getModeName(byte Mode) {
|
|
||||||
|
|
||||||
//DIAG(F("PowerMode %d"), Mode);
|
|
||||||
|
|
||||||
switch (Mode)
|
|
||||||
{
|
|
||||||
case 1: return "NONE";
|
|
||||||
case 2: return "MAIN";
|
|
||||||
case 4: return "PROG";
|
|
||||||
case 8: return "DC";
|
|
||||||
case 16: return "DCX";
|
|
||||||
case 32: return "EXT";
|
|
||||||
default: return "----";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -73,25 +73,28 @@ class TrackManager {
|
||||||
|
|
||||||
static const int16_t MAX_TRACKS=8;
|
static const int16_t MAX_TRACKS=8;
|
||||||
static bool setTrackMode(byte track, TRACK_MODE mode, int16_t DCaddr=0);
|
static bool setTrackMode(byte track, TRACK_MODE mode, int16_t DCaddr=0);
|
||||||
static bool parseJ(Print * stream, int16_t params, int16_t p[]);
|
static bool parseEqualSign(Print * stream, int16_t params, int16_t p[]);
|
||||||
static void loop();
|
static void loop();
|
||||||
static POWERMODE getMainPower();
|
static POWERMODE getMainPower();
|
||||||
static POWERMODE getProgPower();
|
static POWERMODE getProgPower();
|
||||||
|
static inline POWERMODE getPower(byte t) { return track[t]->getPower(); }
|
||||||
static bool getPower(byte t, char s[]);
|
static bool getPower(byte t, char s[]);
|
||||||
static void setJoin(bool join);
|
static void setJoin(bool join);
|
||||||
static bool isJoined() { return progTrackSyncMain;}
|
static bool isJoined() { return progTrackSyncMain;}
|
||||||
|
static inline bool isActive (byte tr) {
|
||||||
|
if (tr > lastTrack) return false;
|
||||||
|
return track[tr]->getMode() & (TRACK_MODE_MAIN|TRACK_MODE_PROG|TRACK_MODE_DC|TRACK_MODE_BOOST|TRACK_MODE_EXT);}
|
||||||
static void setJoinRelayPin(byte joinRelayPin);
|
static void setJoinRelayPin(byte joinRelayPin);
|
||||||
static void sampleCurrent();
|
static void sampleCurrent();
|
||||||
static void reportGauges(Print* stream);
|
static void reportGauges(Print* stream);
|
||||||
static void reportCurrent(Print* stream);
|
static void reportCurrent(Print* stream);
|
||||||
static void reportPowerChange(Print* stream, byte thistrack);
|
|
||||||
static void reportObsoleteCurrent(Print* stream);
|
static void reportObsoleteCurrent(Print* stream);
|
||||||
static void streamTrackState(Print* stream, byte t);
|
static void streamTrackState(Print* stream, byte t);
|
||||||
static bool isPowerOn(byte t);
|
static bool isPowerOn(byte t);
|
||||||
static bool isProg(byte t);
|
static bool isProg(byte t);
|
||||||
static byte returnMode(byte t);
|
static byte returnMode(byte t);
|
||||||
static int16_t returnDCAddr(byte t);
|
static int16_t returnDCAddr(byte t);
|
||||||
static const char* getModeName(byte Mode);
|
static const FSH* getModeName(TRACK_MODE Mode);
|
||||||
|
|
||||||
static int16_t joinRelay;
|
static int16_t joinRelay;
|
||||||
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
|
||||||
|
@ -108,7 +111,6 @@ class TrackManager {
|
||||||
static void addTrack(byte t, MotorDriver* driver);
|
static void addTrack(byte t, MotorDriver* driver);
|
||||||
static byte lastTrack;
|
static byte lastTrack;
|
||||||
static byte nextCycleTrack;
|
static byte nextCycleTrack;
|
||||||
static POWERMODE mainPowerGuess;
|
|
||||||
static void applyDCSpeed(byte t);
|
static void applyDCSpeed(byte t);
|
||||||
|
|
||||||
static int16_t trackDCAddr[MAX_TRACKS]; // dc address if TRACK_MODE_DC
|
static int16_t trackDCAddr[MAX_TRACKS]; // dc address if TRACK_MODE_DC
|
||||||
|
|
|
@ -199,6 +199,18 @@ The configuration file for DCC-EX Command Station
|
||||||
//
|
//
|
||||||
// #define DISABLE_PROG
|
// #define DISABLE_PROG
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// DISABLE / ENABLE VDPY
|
||||||
|
//
|
||||||
|
// The Virtual display "VDPY" feature is by default enabled everywhere
|
||||||
|
// but on Uno and Nano. If you think you can fit it (for example
|
||||||
|
// having disabled some of the features above) you can enable it with
|
||||||
|
// ENABLE_VDPY. You can even disable it on all other CPUs with
|
||||||
|
// DISABLE_VDPY
|
||||||
|
//
|
||||||
|
// #define DISABLE_VDPY
|
||||||
|
// #define ENABLE_VDPY
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
// REDEFINE WHERE SHORT/LONG ADDR break is. According to NMRA the last short address
|
// REDEFINE WHERE SHORT/LONG ADDR break is. According to NMRA the last short address
|
||||||
// is 127 and the first long address is 128. There are manufacturers which have
|
// is 127 and the first long address is 128. There are manufacturers which have
|
||||||
|
|
|
@ -219,11 +219,10 @@
|
||||||
// The HAL is disabled by default on Nano and Uno platforms, because of limited flash space.
|
// The HAL is disabled by default on Nano and Uno platforms, because of limited flash space.
|
||||||
//
|
//
|
||||||
#if defined(ARDUINO_AVR_NANO) || defined(ARDUINO_AVR_UNO)
|
#if defined(ARDUINO_AVR_NANO) || defined(ARDUINO_AVR_UNO)
|
||||||
#if defined(DISABLE_DIAG) && defined(DISABLE_EEPROM) && defined(DISABLE_PROG)
|
#define IO_NO_HAL // HAL too big whatever you disable otherwise
|
||||||
#warning you have sacrificed DIAG for HAL
|
#ifndef ENABLE_VDPY
|
||||||
#else
|
#define DISABLE_VDPY
|
||||||
#define IO_NO_HAL
|
#endif
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if __has_include ( "myAutomation.h")
|
#if __has_include ( "myAutomation.h")
|
||||||
|
|
10
version.h
10
version.h
|
@ -3,7 +3,15 @@
|
||||||
|
|
||||||
#include "StringFormatter.h"
|
#include "StringFormatter.h"
|
||||||
|
|
||||||
#define VERSION "5.2.5"
|
#define VERSION "5.2.9"
|
||||||
|
// 5.2.9 - Bugfix LCD startup with no LCD, uses <@
|
||||||
|
// 5.2.9 - EXRAIL STASH feature
|
||||||
|
// 5.2.8 - Bugfix: Do not turn off all tracks on change
|
||||||
|
// give better power messages
|
||||||
|
// 5.2.7 - Bugfix: EXRAIL ling segment
|
||||||
|
// - Bugfix: Back out wrongly added const
|
||||||
|
// - Bugfix ESP32: Do not inverse DCX direction signal twice
|
||||||
|
// 5.2.6 - Trackmanager broadcast power state on track mode change
|
||||||
// 5.2.5 - Trackmanager: Do not treat TRACK_MODE_ALL as TRACK_MODE_DC
|
// 5.2.5 - Trackmanager: Do not treat TRACK_MODE_ALL as TRACK_MODE_DC
|
||||||
// 5.2.4 - LCD macro will not do diag if that duplicates @ to same target.
|
// 5.2.4 - LCD macro will not do diag if that duplicates @ to same target.
|
||||||
// - Added ROUTE_DISABLED macro in EXRAIL
|
// - Added ROUTE_DISABLED macro in EXRAIL
|
||||||
|
|
Loading…
Reference in New Issue
Block a user