mirror of
https://github.com/DCC-EX/CommandStation-EX.git
synced 2024-11-25 00:56:13 +01:00
Compare commits
1 Commits
90c2a77007
...
1b069aa941
Author | SHA1 | Date | |
---|---|---|---|
|
1b069aa941 |
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -13,5 +13,3 @@ myFilter.cpp
|
||||||
my*.h
|
my*.h
|
||||||
!my*.example.h
|
!my*.example.h
|
||||||
compile_commands.json
|
compile_commands.json
|
||||||
newcode.txt.old
|
|
||||||
UserAddin.txt
|
|
||||||
|
|
|
@ -162,7 +162,7 @@ void CommandDistributor::broadcastTurnout(int16_t id, bool isClosed ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandDistributor::broadcastTurntable(int16_t id, uint8_t position, bool moving) {
|
void CommandDistributor::broadcastTurntable(int16_t id, uint8_t position, bool moving) {
|
||||||
broadcastReply(COMMAND_TYPE, F("<I %d %d %d>\n"), id, position, moving);
|
broadcastReply(COMMAND_TYPE, F("<i %d %d %d>\n"), id, position, moving);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandDistributor::broadcastClockTime(int16_t time, int8_t rate) {
|
void CommandDistributor::broadcastClockTime(int16_t time, int8_t rate) {
|
||||||
|
|
|
@ -60,14 +60,14 @@ Once a new OPCODE is decided upon, update this list.
|
||||||
G,
|
G,
|
||||||
h,
|
h,
|
||||||
H, Turnout state broadcast
|
H, Turnout state broadcast
|
||||||
i, Server details string
|
i, Reserved for future use - Turntable object broadcast
|
||||||
I, Turntable object command, control, and broadcast
|
I, Reserved for future use - Turntable object command and control
|
||||||
j, Throttle responses
|
j, Throttle responses
|
||||||
J, Throttle queries
|
J, Throttle queries
|
||||||
k, Reserved for future use - Potentially Railcom
|
k, Reserved for future use - Potentially Railcom
|
||||||
K, Reserved for future use - Potentially Railcom
|
K, Reserved for future use - Potentially Railcom
|
||||||
l, Loco speedbyte/function map broadcast
|
l, Loco speedbyte/function map broadcast
|
||||||
L, Reserved for LCC interface (implemented in EXRAIL)
|
L,
|
||||||
m,
|
m,
|
||||||
M, Write DCC packet
|
M, Write DCC packet
|
||||||
n,
|
n,
|
||||||
|
@ -122,7 +122,7 @@ Once a new OPCODE is decided upon, update this list.
|
||||||
for (int16_t i=0;;i+=sizeof(flashList[0])) { \
|
for (int16_t i=0;;i+=sizeof(flashList[0])) { \
|
||||||
int16_t value=GETHIGHFLASHW(flashList,i); \
|
int16_t value=GETHIGHFLASHW(flashList,i); \
|
||||||
if (value==INT16_MAX) break; \
|
if (value==INT16_MAX) break; \
|
||||||
StringFormatter::send(stream,F(" %d"),value); \
|
if (value != 0) StringFormatter::send(stream,F(" %d"),value); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -157,7 +157,6 @@ const int16_t HASH_KEYWORD_VPIN=-415;
|
||||||
const int16_t HASH_KEYWORD_A='A';
|
const int16_t HASH_KEYWORD_A='A';
|
||||||
const int16_t HASH_KEYWORD_C='C';
|
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_I='I';
|
const int16_t HASH_KEYWORD_I='I';
|
||||||
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';
|
||||||
|
@ -556,8 +555,6 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream)
|
||||||
bool main=false;
|
bool main=false;
|
||||||
bool prog=false;
|
bool prog=false;
|
||||||
bool join=false;
|
bool join=false;
|
||||||
bool singletrack=false;
|
|
||||||
//byte t=0;
|
|
||||||
if (params > 1) break;
|
if (params > 1) break;
|
||||||
if (params==0) { // All
|
if (params==0) { // All
|
||||||
main=true;
|
main=true;
|
||||||
|
@ -577,52 +574,20 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream)
|
||||||
prog=true;
|
prog=true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
//else if (p[0] >= 'A' && p[0] <= 'H') { // <1 A-H>
|
|
||||||
else if (p[0] >= HASH_KEYWORD_A && p[0] <= HASH_KEYWORD_H) { // <1 A-H>
|
|
||||||
byte t = (p[0] - 'A');
|
|
||||||
//DIAG(F("Processing track - %d "), t);
|
|
||||||
if (TrackManager::isProg(t)) {
|
|
||||||
main = false;
|
|
||||||
prog = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
main=true;
|
|
||||||
prog=false;
|
|
||||||
}
|
|
||||||
singletrack=true;
|
|
||||||
if (main) TrackManager::setTrackPower(false, false, POWERMODE::ON, t);
|
|
||||||
if (prog) TrackManager::setTrackPower(true, false, POWERMODE::ON, t);
|
|
||||||
|
|
||||||
StringFormatter::send(stream, F("<1 %c>\n"), t+'A');
|
|
||||||
//CommandDistributor::broadcastPower();
|
|
||||||
//TrackManager::streamTrackState(NULL,t);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
else break; // will reply <X>
|
else break; // will reply <X>
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!singletrack) {
|
|
||||||
TrackManager::setJoin(join);
|
TrackManager::setJoin(join);
|
||||||
if (join) TrackManager::setJoinPower(POWERMODE::ON);
|
|
||||||
else {
|
|
||||||
if (main) TrackManager::setMainPower(POWERMODE::ON);
|
if (main) TrackManager::setMainPower(POWERMODE::ON);
|
||||||
if (prog) TrackManager::setProgPower(POWERMODE::ON);
|
if (prog) TrackManager::setProgPower(POWERMODE::ON);
|
||||||
}
|
|
||||||
CommandDistributor::broadcastPower();
|
CommandDistributor::broadcastPower();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
case '0': // POWEROFF <0 [MAIN | PROG] >
|
case '0': // POWEROFF <0 [MAIN | PROG] >
|
||||||
{
|
{
|
||||||
bool main=false;
|
bool main=false;
|
||||||
bool prog=false;
|
bool prog=false;
|
||||||
bool singletrack=false;
|
|
||||||
//byte t=0;
|
|
||||||
if (params > 1) break;
|
if (params > 1) break;
|
||||||
if (params==0) { // All
|
if (params==0) { // All
|
||||||
main=true;
|
main=true;
|
||||||
|
@ -637,47 +602,19 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream)
|
||||||
prog=true;
|
prog=true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
//else if (p[0] >= 'A' && p[0] <= 'H') { // <1 A-H>
|
|
||||||
else if (p[0] >= HASH_KEYWORD_A && p[0] <= HASH_KEYWORD_H) { // <1 A-H>
|
|
||||||
byte t = (p[0] - 'A');
|
|
||||||
//DIAG(F("Processing track - %d "), t);
|
|
||||||
if (TrackManager::isProg(t)) {
|
|
||||||
main = false;
|
|
||||||
prog = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
main=true;
|
|
||||||
prog=false;
|
|
||||||
}
|
|
||||||
singletrack=true;
|
|
||||||
TrackManager::setJoin(false);
|
|
||||||
if (main) TrackManager::setTrackPower(false, false, POWERMODE::OFF, t);
|
|
||||||
if (prog) {
|
|
||||||
TrackManager::progTrackBoosted=false; // Prog track boost mode will not outlive prog track off
|
|
||||||
TrackManager::setTrackPower(true, false, POWERMODE::OFF, t);
|
|
||||||
}
|
|
||||||
StringFormatter::send(stream, F("<0 %c>\n"), t+'A');
|
|
||||||
//CommandDistributor::broadcastPower();
|
|
||||||
//TrackManager::streamTrackState(NULL, t);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
else break; // will reply <X>
|
else break; // will reply <X>
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!singletrack) {
|
|
||||||
TrackManager::setJoin(false);
|
TrackManager::setJoin(false);
|
||||||
|
|
||||||
if (main) TrackManager::setMainPower(POWERMODE::OFF);
|
if (main) TrackManager::setMainPower(POWERMODE::OFF);
|
||||||
if (prog) {
|
if (prog) {
|
||||||
TrackManager::progTrackBoosted=false; // Prog track boost mode will not outlive prog track off
|
TrackManager::progTrackBoosted=false; // Prog track boost mode will not outlive prog track off
|
||||||
TrackManager::setProgPower(POWERMODE::OFF);
|
TrackManager::setProgPower(POWERMODE::OFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
CommandDistributor::broadcastPower();
|
CommandDistributor::broadcastPower();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
case '!': // ESTOP ALL <!>
|
case '!': // ESTOP ALL <!>
|
||||||
DCC::setThrottle(0,1,1); // this broadcasts speed 1(estop) and sets all reminders to speed 1.
|
DCC::setThrottle(0,1,1); // this broadcasts speed 1(estop) and sets all reminders to speed 1.
|
||||||
|
@ -805,14 +742,10 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream)
|
||||||
SENDFLASHLIST(stream,RMFT2::rosterIdList)
|
SENDFLASHLIST(stream,RMFT2::rosterIdList)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
auto rosterName= RMFT2::getRosterName(id);
|
const FSH * functionNames= RMFT2::getRosterFunctions(id);
|
||||||
if (!rosterName) rosterName=F("");
|
|
||||||
|
|
||||||
auto functionNames= RMFT2::getRosterFunctions(id);
|
|
||||||
if (!functionNames) functionNames=RMFT2::getRosterFunctions(0);
|
|
||||||
if (!functionNames) functionNames=F("");
|
|
||||||
StringFormatter::send(stream,F(" %d \"%S\" \"%S\""),
|
StringFormatter::send(stream,F(" %d \"%S\" \"%S\""),
|
||||||
id, rosterName, functionNames);
|
id, RMFT2::getRosterName(id),
|
||||||
|
functionNames == NULL ? RMFT2::getRosterFunctions(0) : functionNames);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
StringFormatter::send(stream, F(">\n"));
|
StringFormatter::send(stream, F(">\n"));
|
||||||
|
@ -906,9 +839,6 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream)
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
case 'L': // LCC interface implemented in EXRAIL parser
|
|
||||||
break; // Will <X> if not intercepted by EXRAIL
|
|
||||||
|
|
||||||
default: //anything else will diagnose and drop out to <X>
|
default: //anything else will diagnose and drop out to <X>
|
||||||
DIAG(F("Opcode=%c params=%d"), opcode, params);
|
DIAG(F("Opcode=%c params=%d"), opcode, params);
|
||||||
for (int i = 0; i < params; i++)
|
for (int i = 0; i < params; i++)
|
||||||
|
@ -1251,7 +1181,7 @@ bool DCCEXParser::parseI(Print *stream, int16_t params, int16_t p[])
|
||||||
if (tto) {
|
if (tto) {
|
||||||
bool type = tto->isEXTT();
|
bool type = tto->isEXTT();
|
||||||
uint8_t position = tto->getPosition();
|
uint8_t position = tto->getPosition();
|
||||||
StringFormatter::send(stream, F("<I %d %d>\n"), type, position);
|
StringFormatter::send(stream, F("<i %d %d>\n"), type, position);
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1277,7 +1207,7 @@ bool DCCEXParser::parseI(Print *stream, int16_t params, int16_t p[])
|
||||||
if (!DCCTurntable::create(p[0])) return false;
|
if (!DCCTurntable::create(p[0])) return false;
|
||||||
Turntable *tto = Turntable::get(p[0]);
|
Turntable *tto = Turntable::get(p[0]);
|
||||||
tto->addPosition(0, 0, p[2]);
|
tto->addPosition(0, 0, p[2]);
|
||||||
StringFormatter::send(stream, F("<I>\n"));
|
StringFormatter::send(stream, F("<i>\n"));
|
||||||
} else {
|
} else {
|
||||||
if (!tto) return false;
|
if (!tto) return false;
|
||||||
if (!tto->isEXTT()) return false;
|
if (!tto->isEXTT()) return false;
|
||||||
|
@ -1294,7 +1224,7 @@ bool DCCEXParser::parseI(Print *stream, int16_t params, int16_t p[])
|
||||||
if (!EXTTTurntable::create(p[0], (VPIN)p[2])) return false;
|
if (!EXTTTurntable::create(p[0], (VPIN)p[2])) return false;
|
||||||
Turntable *tto = Turntable::get(p[0]);
|
Turntable *tto = Turntable::get(p[0]);
|
||||||
tto->addPosition(0, 0, p[3]);
|
tto->addPosition(0, 0, p[3]);
|
||||||
StringFormatter::send(stream, F("<I>\n"));
|
StringFormatter::send(stream, F("<i>\n"));
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1308,7 +1238,7 @@ bool DCCEXParser::parseI(Print *stream, int16_t params, int16_t p[])
|
||||||
// tto must exist, no more than 48 positions, angle 0 - 3600
|
// tto must exist, no more than 48 positions, angle 0 - 3600
|
||||||
if (!tto || p[2] > 48 || p[4] < 0 || p[4] > 3600) return false;
|
if (!tto || p[2] > 48 || p[4] < 0 || p[4] > 3600) return false;
|
||||||
tto->addPosition(p[2], p[3], p[4]);
|
tto->addPosition(p[2], p[3], p[4]);
|
||||||
StringFormatter::send(stream, F("<I>\n"));
|
StringFormatter::send(stream, F("<i>\n"));
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
104
EXRAIL2.cpp
104
EXRAIL2.cpp
|
@ -85,7 +85,7 @@ RMFT2 * RMFT2::pausingTask=NULL; // Task causing a PAUSE.
|
||||||
// when pausingTask is set, that is the ONLY task that gets any service,
|
// when pausingTask is set, that is the ONLY task that gets any service,
|
||||||
// and all others will have their locos stopped, then resumed after the pausing task resumes.
|
// and all others will have their locos stopped, then resumed after the pausing task resumes.
|
||||||
byte RMFT2::flags[MAX_FLAGS];
|
byte RMFT2::flags[MAX_FLAGS];
|
||||||
Print * RMFT2::LCCSerial=0;
|
|
||||||
LookList * RMFT2::sequenceLookup=NULL;
|
LookList * RMFT2::sequenceLookup=NULL;
|
||||||
LookList * RMFT2::onThrowLookup=NULL;
|
LookList * RMFT2::onThrowLookup=NULL;
|
||||||
LookList * RMFT2::onCloseLookup=NULL;
|
LookList * RMFT2::onCloseLookup=NULL;
|
||||||
|
@ -176,26 +176,23 @@ LookList* RMFT2::LookListLoader(OPCODE op1, OPCODE op2, OPCODE op3) {
|
||||||
onCloseLookup=LookListLoader(OPCODE_ONCLOSE);
|
onCloseLookup=LookListLoader(OPCODE_ONCLOSE);
|
||||||
onActivateLookup=LookListLoader(OPCODE_ONACTIVATE);
|
onActivateLookup=LookListLoader(OPCODE_ONACTIVATE);
|
||||||
onDeactivateLookup=LookListLoader(OPCODE_ONDEACTIVATE);
|
onDeactivateLookup=LookListLoader(OPCODE_ONDEACTIVATE);
|
||||||
|
onRedLookup=LookListLoader(OPCODE_ONRED);
|
||||||
|
onAmberLookup=LookListLoader(OPCODE_ONAMBER);
|
||||||
|
onGreenLookup=LookListLoader(OPCODE_ONGREEN);
|
||||||
onChangeLookup=LookListLoader(OPCODE_ONCHANGE);
|
onChangeLookup=LookListLoader(OPCODE_ONCHANGE);
|
||||||
onClockLookup=LookListLoader(OPCODE_ONTIME);
|
onClockLookup=LookListLoader(OPCODE_ONTIME);
|
||||||
#ifndef IO_NO_HAL
|
#ifndef IO_NO_HAL
|
||||||
onRotateLookup=LookListLoader(OPCODE_ONROTATE);
|
onRotateLookup=LookListLoader(OPCODE_ONROTATE);
|
||||||
#endif
|
#endif
|
||||||
onOverloadLookup=LookListLoader(OPCODE_ONOVERLOAD);
|
onOverloadLookup=LookListLoader(OPCODE_ONOVERLOAD);
|
||||||
// onLCCLookup is not the same so not loaded here.
|
|
||||||
|
|
||||||
// Second pass startup, define any turnouts or servos, set signals red
|
// Second pass startup, define any turnouts or servos, set signals red
|
||||||
// add sequences onRoutines to the lookups
|
// add sequences onRoutines to the lookups
|
||||||
if (compileFeatures & FEATURE_SIGNAL) {
|
|
||||||
onRedLookup=LookListLoader(OPCODE_ONRED);
|
|
||||||
onAmberLookup=LookListLoader(OPCODE_ONAMBER);
|
|
||||||
onGreenLookup=LookListLoader(OPCODE_ONGREEN);
|
|
||||||
for (int sigslot=0;;sigslot++) {
|
for (int sigslot=0;;sigslot++) {
|
||||||
VPIN sigid=GETHIGHFLASHW(RMFT2::SignalDefinitions,sigslot*8);
|
VPIN sigid=GETHIGHFLASHW(RMFT2::SignalDefinitions,sigslot*8);
|
||||||
if (sigid==0) break; // end of signal list
|
if (sigid==0) break; // end of signal list
|
||||||
doSignal(sigid & SIGNAL_ID_MASK, SIGNAL_RED);
|
doSignal(sigid & SIGNAL_ID_MASK, SIGNAL_RED);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
int progCounter;
|
int progCounter;
|
||||||
for (progCounter=0;; SKIPOP){
|
for (progCounter=0;; SKIPOP){
|
||||||
|
@ -346,65 +343,13 @@ void RMFT2::ComandFilter(Print * stream, byte & opcode, byte & paramCount, int16
|
||||||
reject=!parseSlash(stream,paramCount,p);
|
reject=!parseSlash(stream,paramCount,p);
|
||||||
opcode=0;
|
opcode=0;
|
||||||
break;
|
break;
|
||||||
case 'L':
|
|
||||||
if (compileFeatures & FEATURE_LCC) {
|
|
||||||
// This entire code block is compiled out if LLC macros not used
|
|
||||||
if (paramCount==0) { //<L> LCC adapter introducing self
|
|
||||||
LCCSerial=stream; // now we know where to send events we raise
|
|
||||||
|
|
||||||
// loop through all possible sent events
|
|
||||||
for (int progCounter=0;; SKIPOP) {
|
|
||||||
byte opcode=GET_OPCODE;
|
|
||||||
if (opcode==OPCODE_ENDEXRAIL) break;
|
|
||||||
if (opcode==OPCODE_LCC) StringFormatter::send(stream,F("<LS x%h>\n"),getOperand(progCounter,0));
|
|
||||||
if (opcode==OPCODE_LCCX) { // long form LCC
|
|
||||||
StringFormatter::send(stream,F("<LS x%h%h%h%h>\n"),
|
|
||||||
getOperand(progCounter,1),
|
|
||||||
getOperand(progCounter,2),
|
|
||||||
getOperand(progCounter,3),
|
|
||||||
getOperand(progCounter,0)
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
|
|
||||||
// we stream the hex events we wish to listen to
|
|
||||||
// and at the same time build the event index looku.
|
|
||||||
|
|
||||||
|
|
||||||
int eventIndex=0;
|
|
||||||
for (int progCounter=0;; SKIPOP) {
|
|
||||||
byte opcode=GET_OPCODE;
|
|
||||||
if (opcode==OPCODE_ENDEXRAIL) break;
|
|
||||||
if (opcode==OPCODE_ONLCC) {
|
|
||||||
onLCCLookup[eventIndex]=progCounter; // TODO skip...
|
|
||||||
StringFormatter::send(stream,F("<LL %d x%h%h%h:%h>\n"),
|
|
||||||
eventIndex,
|
|
||||||
getOperand(progCounter,1),
|
|
||||||
getOperand(progCounter,2),
|
|
||||||
getOperand(progCounter,3),
|
|
||||||
getOperand(progCounter,0)
|
|
||||||
);
|
|
||||||
eventIndex++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
StringFormatter::send(stream,F("<LR>\n")); // Ready to rumble
|
|
||||||
opcode=0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (paramCount==1) { // <L eventid> LCC event arrived from adapter
|
|
||||||
int16_t eventid=p[0];
|
|
||||||
reject=eventid<0 || eventid>=countLCCLookup;
|
|
||||||
if (!reject) startNonRecursiveTask(F("LCC"),eventid,onLCCLookup[eventid]);
|
|
||||||
opcode=0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default: // other commands pass through
|
default: // other commands pass through
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (reject) {
|
if (reject) {
|
||||||
opcode=0;
|
opcode=0;
|
||||||
StringFormatter::send(stream,F("<X>\n"));
|
StringFormatter::send(stream,F("<X>"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -432,8 +377,6 @@ bool RMFT2::parseSlash(Print * stream, byte & paramCount, int16_t p[]) {
|
||||||
if (flag & LATCH_FLAG) StringFormatter::send(stream,F(" LATCHED"));
|
if (flag & LATCH_FLAG) StringFormatter::send(stream,F(" LATCHED"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (compileFeatures & FEATURE_SIGNAL) {
|
|
||||||
// do the signals
|
// do the signals
|
||||||
// flags[n] represents the state of the nth signal in the table
|
// flags[n] represents the state of the nth signal in the table
|
||||||
for (int sigslot=0;;sigslot++) {
|
for (int sigslot=0;;sigslot++) {
|
||||||
|
@ -444,7 +387,7 @@ bool RMFT2::parseSlash(Print * stream, byte & paramCount, int16_t p[]) {
|
||||||
(flag == SIGNAL_RED)? F("RED") : (flag==SIGNAL_GREEN) ? F("GREEN") : F("AMBER"),
|
(flag == SIGNAL_RED)? F("RED") : (flag==SIGNAL_GREEN) ? F("GREEN") : F("AMBER"),
|
||||||
sigid & SIGNAL_ID_MASK);
|
sigid & SIGNAL_ID_MASK);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
StringFormatter::send(stream,F(" *>\n"));
|
StringFormatter::send(stream,F(" *>\n"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -838,20 +781,6 @@ void RMFT2::loop2() {
|
||||||
CommandDistributor::broadcastPower();
|
CommandDistributor::broadcastPower();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPCODE_SET_POWER:
|
|
||||||
// operand is TRACK_POWER , trackid
|
|
||||||
//byte thistrack=getOperand(1);
|
|
||||||
switch (operand) {
|
|
||||||
case TRACK_POWER_0:
|
|
||||||
TrackManager::setTrackPower(TrackManager::isProg(getOperand(1)), false, POWERMODE::OFF, getOperand(1));
|
|
||||||
break;
|
|
||||||
case TRACK_POWER_1:
|
|
||||||
TrackManager::setTrackPower(TrackManager::isProg(getOperand(1)), false, POWERMODE::ON, getOperand(1));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OPCODE_SET_TRACK:
|
case OPCODE_SET_TRACK:
|
||||||
// operand is trackmode<<8 | track id
|
// operand is trackmode<<8 | track id
|
||||||
// If DC/DCX use my loco for DC address
|
// If DC/DCX use my loco for DC address
|
||||||
|
@ -1092,20 +1021,6 @@ void RMFT2::loop2() {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPCODE_LCC: // short form LCC
|
|
||||||
if ((compileFeatures & FEATURE_LCC) && LCCSerial)
|
|
||||||
StringFormatter::send(LCCSerial,F("<L x%h>"),(uint16_t)operand);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OPCODE_LCCX: // long form LCC
|
|
||||||
if ((compileFeatures & FEATURE_LCC) && LCCSerial)
|
|
||||||
StringFormatter::send(LCCSerial,F("<L x%h%h%h%h>\n"),
|
|
||||||
getOperand(progCounter,1),
|
|
||||||
getOperand(progCounter,2),
|
|
||||||
getOperand(progCounter,3),
|
|
||||||
getOperand(progCounter,0)
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OPCODE_SERVO: // OPCODE_SERVO,V(vpin),OPCODE_PAD,V(position),OPCODE_PAD,V(profile),OPCODE_PAD,V(duration)
|
case OPCODE_SERVO: // OPCODE_SERVO,V(vpin),OPCODE_PAD,V(position),OPCODE_PAD,V(profile),OPCODE_PAD,V(duration)
|
||||||
IODevice::writeAnalogue(operand,getOperand(1),getOperand(2),getOperand(3));
|
IODevice::writeAnalogue(operand,getOperand(1),getOperand(2),getOperand(3));
|
||||||
|
@ -1143,7 +1058,6 @@ void RMFT2::loop2() {
|
||||||
case OPCODE_SERVOTURNOUT: // Turnout definition ignored at runtime
|
case OPCODE_SERVOTURNOUT: // Turnout definition ignored at runtime
|
||||||
case OPCODE_PINTURNOUT: // Turnout definition ignored at runtime
|
case OPCODE_PINTURNOUT: // Turnout definition ignored at runtime
|
||||||
case OPCODE_ONCLOSE: // Turnout event catchers ignored here
|
case OPCODE_ONCLOSE: // Turnout event catchers ignored here
|
||||||
case OPCODE_ONLCC: // LCC event catchers ignored here
|
|
||||||
case OPCODE_ONTHROW:
|
case OPCODE_ONTHROW:
|
||||||
case OPCODE_ONACTIVATE: // Activate event catchers ignored here
|
case OPCODE_ONACTIVATE: // Activate event catchers ignored here
|
||||||
case OPCODE_ONDEACTIVATE:
|
case OPCODE_ONDEACTIVATE:
|
||||||
|
@ -1213,7 +1127,6 @@ int16_t RMFT2::getSignalSlot(int16_t id) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ void RMFT2::doSignal(int16_t id,char rag) {
|
/* static */ void RMFT2::doSignal(int16_t id,char rag) {
|
||||||
if (!(compileFeatures & FEATURE_SIGNAL)) return; // dont compile code below
|
|
||||||
if (diag) DIAG(F(" doSignal %d %x"),id,rag);
|
if (diag) DIAG(F(" doSignal %d %x"),id,rag);
|
||||||
|
|
||||||
// Schedule any event handler for this signal change.
|
// Schedule any event handler for this signal change.
|
||||||
|
@ -1281,7 +1194,6 @@ int16_t RMFT2::getSignalSlot(int16_t id) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ bool RMFT2::isSignal(int16_t id,char rag) {
|
/* static */ bool RMFT2::isSignal(int16_t id,char rag) {
|
||||||
if (!(compileFeatures & FEATURE_SIGNAL)) return false;
|
|
||||||
int16_t sigslot=getSignalSlot(id);
|
int16_t sigslot=getSignalSlot(id);
|
||||||
if (sigslot<0) return false;
|
if (sigslot<0) return false;
|
||||||
return (flags[sigslot] & SIGNAL_MASK) == rag;
|
return (flags[sigslot] & SIGNAL_MASK) == rag;
|
||||||
|
@ -1334,10 +1246,8 @@ void RMFT2::powerEvent(int16_t track, bool overload) {
|
||||||
|
|
||||||
void RMFT2::handleEvent(const FSH* reason,LookList* handlers, int16_t id) {
|
void RMFT2::handleEvent(const FSH* reason,LookList* handlers, int16_t id) {
|
||||||
int pc= handlers->find(id);
|
int pc= handlers->find(id);
|
||||||
if (pc>=0) startNonRecursiveTask(reason,id,pc);
|
if (pc<0) return;
|
||||||
}
|
|
||||||
|
|
||||||
void RMFT2::startNonRecursiveTask(const FSH* reason, int16_t id,int pc) {
|
|
||||||
// Check we dont already have a task running this handler
|
// Check we dont already have a task running this handler
|
||||||
RMFT2 * task=loopTask;
|
RMFT2 * task=loopTask;
|
||||||
while(task) {
|
while(task) {
|
||||||
|
|
20
EXRAIL2.h
20
EXRAIL2.h
|
@ -59,14 +59,15 @@ enum OPCODE : byte {OPCODE_THROW,OPCODE_CLOSE,
|
||||||
OPCODE_ROSTER,OPCODE_KILLALL,
|
OPCODE_ROSTER,OPCODE_KILLALL,
|
||||||
OPCODE_ROUTE,OPCODE_AUTOMATION,OPCODE_SEQUENCE,
|
OPCODE_ROUTE,OPCODE_AUTOMATION,OPCODE_SEQUENCE,
|
||||||
OPCODE_ENDTASK,OPCODE_ENDEXRAIL,
|
OPCODE_ENDTASK,OPCODE_ENDEXRAIL,
|
||||||
OPCODE_SET_TRACK,OPCODE_SET_POWER,
|
OPCODE_SET_TRACK,
|
||||||
OPCODE_ONRED,OPCODE_ONAMBER,OPCODE_ONGREEN,
|
OPCODE_ONRED,OPCODE_ONAMBER,OPCODE_ONGREEN,
|
||||||
OPCODE_ONCHANGE,
|
OPCODE_ONCHANGE,
|
||||||
OPCODE_ONCLOCKTIME,
|
OPCODE_ONCLOCKTIME,
|
||||||
OPCODE_ONTIME,
|
OPCODE_ONTIME,
|
||||||
|
#ifndef IO_NO_HAL
|
||||||
OPCODE_TTADDPOSITION,OPCODE_DCCTURNTABLE,OPCODE_EXTTTURNTABLE,
|
OPCODE_TTADDPOSITION,OPCODE_DCCTURNTABLE,OPCODE_EXTTTURNTABLE,
|
||||||
OPCODE_ONROTATE,OPCODE_ROTATE,OPCODE_WAITFORTT,
|
OPCODE_ONROTATE,OPCODE_ROTATE,OPCODE_IFTTPOSITION,OPCODE_WAITFORTT,
|
||||||
OPCODE_LCC,OPCODE_LCCX,OPCODE_ONLCC,
|
#endif
|
||||||
OPCODE_ONOVERLOAD,
|
OPCODE_ONOVERLOAD,
|
||||||
|
|
||||||
// OPcodes below this point are skip-nesting IF operations
|
// OPcodes below this point are skip-nesting IF operations
|
||||||
|
@ -80,8 +81,7 @@ enum OPCODE : byte {OPCODE_THROW,OPCODE_CLOSE,
|
||||||
OPCODE_IFRANDOM,OPCODE_IFRESERVE,
|
OPCODE_IFRANDOM,OPCODE_IFRESERVE,
|
||||||
OPCODE_IFCLOSED,OPCODE_IFTHROWN,
|
OPCODE_IFCLOSED,OPCODE_IFTHROWN,
|
||||||
OPCODE_IFRE,
|
OPCODE_IFRE,
|
||||||
OPCODE_IFLOCO,
|
OPCODE_IFLOCO
|
||||||
OPCODE_IFTTPOSITION
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 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,
|
||||||
|
@ -95,10 +95,6 @@ enum thrunger: byte {
|
||||||
thrunge_lcd, // Must be last!!
|
thrunge_lcd, // Must be last!!
|
||||||
};
|
};
|
||||||
|
|
||||||
// Flag bits for compile time features.
|
|
||||||
static const byte FEATURE_SIGNAL= 0x80;
|
|
||||||
static const byte FEATURE_LCC = 0x40;
|
|
||||||
static const byte FEATURE_ROSTER= 0x20;
|
|
||||||
|
|
||||||
|
|
||||||
// Flag bits for status of hardware and TPL
|
// Flag bits for status of hardware and TPL
|
||||||
|
@ -178,7 +174,6 @@ private:
|
||||||
OPCODE op2=OPCODE_ENDEXRAIL,OPCODE op3=OPCODE_ENDEXRAIL);
|
OPCODE op2=OPCODE_ENDEXRAIL,OPCODE op3=OPCODE_ENDEXRAIL);
|
||||||
static void handleEvent(const FSH* reason,LookList* handlers, int16_t id);
|
static void handleEvent(const FSH* reason,LookList* handlers, int16_t id);
|
||||||
static uint16_t getOperand(int progCounter,byte n);
|
static uint16_t getOperand(int progCounter,byte n);
|
||||||
static void startNonRecursiveTask(const FSH* reason, int16_t id,int pc);
|
|
||||||
static RMFT2 * loopTask;
|
static RMFT2 * loopTask;
|
||||||
static RMFT2 * pausingTask;
|
static RMFT2 * pausingTask;
|
||||||
void delayMe(long millisecs);
|
void delayMe(long millisecs);
|
||||||
|
@ -197,7 +192,6 @@ private:
|
||||||
static const HIGHFLASH byte RouteCode[];
|
static const HIGHFLASH 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 LookList * sequenceLookup;
|
static LookList * sequenceLookup;
|
||||||
static LookList * onThrowLookup;
|
static LookList * onThrowLookup;
|
||||||
static LookList * onCloseLookup;
|
static LookList * onCloseLookup;
|
||||||
|
@ -213,10 +207,6 @@ private:
|
||||||
#endif
|
#endif
|
||||||
static LookList * onOverloadLookup;
|
static LookList * onOverloadLookup;
|
||||||
|
|
||||||
static const int countLCCLookup;
|
|
||||||
static int onLCCLookup[];
|
|
||||||
static const byte compileFeatures;
|
|
||||||
|
|
||||||
// Local variables - exist for each instance/task
|
// Local variables - exist for each instance/task
|
||||||
RMFT2 *next; // loop chain
|
RMFT2 *next; // loop chain
|
||||||
int progCounter; // Byte offset of next route opcode in ROUTES table
|
int progCounter; // Byte offset of next route opcode in ROUTES table
|
||||||
|
|
|
@ -86,8 +86,6 @@
|
||||||
#undef LATCH
|
#undef LATCH
|
||||||
#undef LCD
|
#undef LCD
|
||||||
#undef SCREEN
|
#undef SCREEN
|
||||||
#undef LCC
|
|
||||||
#undef LCCX
|
|
||||||
#undef LCN
|
#undef LCN
|
||||||
#undef MOVETT
|
#undef MOVETT
|
||||||
#undef ONACTIVATE
|
#undef ONACTIVATE
|
||||||
|
@ -96,7 +94,6 @@
|
||||||
#undef ONDEACTIVATE
|
#undef ONDEACTIVATE
|
||||||
#undef ONDEACTIVATEL
|
#undef ONDEACTIVATEL
|
||||||
#undef ONCLOSE
|
#undef ONCLOSE
|
||||||
#undef ONLCC
|
|
||||||
#undef ONTIME
|
#undef ONTIME
|
||||||
#undef ONCLOCKTIME
|
#undef ONCLOCKTIME
|
||||||
#undef ONCLOCKMINS
|
#undef ONCLOCKMINS
|
||||||
|
@ -141,7 +138,6 @@
|
||||||
#undef SERVO_SIGNAL
|
#undef SERVO_SIGNAL
|
||||||
#undef SET
|
#undef SET
|
||||||
#undef SET_TRACK
|
#undef SET_TRACK
|
||||||
#undef SET_POWER
|
|
||||||
#undef SETLOCO
|
#undef SETLOCO
|
||||||
#undef SIGNAL
|
#undef SIGNAL
|
||||||
#undef SIGNALH
|
#undef SIGNALH
|
||||||
|
@ -196,7 +192,7 @@
|
||||||
#define ENDTASK
|
#define ENDTASK
|
||||||
#define ESTOP
|
#define ESTOP
|
||||||
#define EXRAIL
|
#define EXRAIL
|
||||||
#define EXTT_TURNTABLE(id,vpin,home,description)
|
#define EXTT_TURNTABLE(id,vpin,i2c_address,home,description)
|
||||||
#define FADE(pin,value,ms)
|
#define FADE(pin,value,ms)
|
||||||
#define FOFF(func)
|
#define FOFF(func)
|
||||||
#define FOLLOW(route)
|
#define FOLLOW(route)
|
||||||
|
@ -225,8 +221,6 @@
|
||||||
#define JOIN
|
#define JOIN
|
||||||
#define KILLALL
|
#define KILLALL
|
||||||
#define LATCH(sensor_id)
|
#define LATCH(sensor_id)
|
||||||
#define LCC(eventid)
|
|
||||||
#define LCCX(senderid,eventid)
|
|
||||||
#define LCD(row,msg)
|
#define LCD(row,msg)
|
||||||
#define SCREEN(display,row,msg)
|
#define SCREEN(display,row,msg)
|
||||||
#define LCN(msg)
|
#define LCN(msg)
|
||||||
|
@ -241,7 +235,6 @@
|
||||||
#define ONDEACTIVATE(addr,subaddr)
|
#define ONDEACTIVATE(addr,subaddr)
|
||||||
#define ONDEACTIVATEL(linear)
|
#define ONDEACTIVATEL(linear)
|
||||||
#define ONCLOSE(turnout_id)
|
#define ONCLOSE(turnout_id)
|
||||||
#define ONLCC(sender,event)
|
|
||||||
#define ONGREEN(signal_id)
|
#define ONGREEN(signal_id)
|
||||||
#define ONRED(signal_id)
|
#define ONRED(signal_id)
|
||||||
#define ONROTATE(turntable_id)
|
#define ONROTATE(turntable_id)
|
||||||
|
@ -282,7 +275,6 @@
|
||||||
#define SERVO_TURNOUT(id,pin,activeAngle,inactiveAngle,profile,description...)
|
#define SERVO_TURNOUT(id,pin,activeAngle,inactiveAngle,profile,description...)
|
||||||
#define SET(pin)
|
#define SET(pin)
|
||||||
#define SET_TRACK(track,mode)
|
#define SET_TRACK(track,mode)
|
||||||
#define SET_POWER(track,onoff)
|
|
||||||
#define SETLOCO(loco)
|
#define SETLOCO(loco)
|
||||||
#define SIGNAL(redpin,amberpin,greenpin)
|
#define SIGNAL(redpin,amberpin,greenpin)
|
||||||
#define SIGNALH(redpin,amberpin,greenpin)
|
#define SIGNALH(redpin,amberpin,greenpin)
|
||||||
|
|
|
@ -63,11 +63,6 @@
|
||||||
// (10#mins)%100)
|
// (10#mins)%100)
|
||||||
#define STRIP_ZERO(value) 10##value%100
|
#define STRIP_ZERO(value) 10##value%100
|
||||||
|
|
||||||
// These constants help EXRAIL macros convert Track Power e.g. SET_POWER(A ON|OFF).
|
|
||||||
//const byte TRACK_POWER_0=0, TRACK_POWER_OFF=0;
|
|
||||||
//const byte TRACK_POWER_1=1, TRACK_POWER_ON=1;
|
|
||||||
|
|
||||||
|
|
||||||
// Pass 1 Implements aliases
|
// Pass 1 Implements aliases
|
||||||
#include "EXRAIL2MacroReset.h"
|
#include "EXRAIL2MacroReset.h"
|
||||||
#undef ALIAS
|
#undef ALIAS
|
||||||
|
@ -79,34 +74,12 @@
|
||||||
#include "EXRAIL2MacroReset.h"
|
#include "EXRAIL2MacroReset.h"
|
||||||
#undef HAL
|
#undef HAL
|
||||||
#define HAL(haltype,params...) haltype::create(params);
|
#define HAL(haltype,params...) haltype::create(params);
|
||||||
|
#undef EXTT_TURNTABLE
|
||||||
|
#define EXTT_TURNTABLE(id,vpin,i2c_address,home,description...) EXTurntable::create(vpin,1,i2c_address);
|
||||||
void exrailHalSetup() {
|
void exrailHalSetup() {
|
||||||
#include "myAutomation.h"
|
#include "myAutomation.h"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pass 1c detect compile time featurtes
|
|
||||||
#include "EXRAIL2MacroReset.h"
|
|
||||||
#undef SIGNAL
|
|
||||||
#define SIGNAL(redpin,amberpin,greenpin) | FEATURE_SIGNAL
|
|
||||||
#undef SIGNALH
|
|
||||||
#define SIGNALH(redpin,amberpin,greenpin) | FEATURE_SIGNAL
|
|
||||||
#undef SERVO_SIGNAL
|
|
||||||
#define SERVO_SIGNAL(vpin,redval,amberval,greenval) | FEATURE_SIGNAL
|
|
||||||
#undef DCC_SIGNAL
|
|
||||||
#define DCC_SIGNAL(id,addr,subaddr) | FEATURE_SIGNAL
|
|
||||||
#undef VIRTUAL_SIGNAL
|
|
||||||
#define VIRTUAL_SIGNAL(id) | FEATURE_SIGNAL
|
|
||||||
|
|
||||||
#undef LCC
|
|
||||||
#define LCC(eventid) | FEATURE_LCC
|
|
||||||
#undef LCCX
|
|
||||||
#define LCCX(senderid,eventid) | FEATURE_LCC
|
|
||||||
#undef ONLCC
|
|
||||||
#define ONLCC(senderid,eventid) | FEATURE_LCC
|
|
||||||
|
|
||||||
const byte RMFT2::compileFeatures = 0
|
|
||||||
#include "myAutomation.h"
|
|
||||||
;
|
|
||||||
|
|
||||||
// Pass 2 create throttle route list
|
// Pass 2 create throttle route list
|
||||||
#include "EXRAIL2MacroReset.h"
|
#include "EXRAIL2MacroReset.h"
|
||||||
#undef ROUTE
|
#undef ROUTE
|
||||||
|
@ -224,7 +197,7 @@ const FSH * RMFT2::getTurnoutDescription(int16_t turnoutid) {
|
||||||
#undef DCC_TURNTABLE
|
#undef DCC_TURNTABLE
|
||||||
#define DCC_TURNTABLE(id,home,description...) O_DESC(id,description)
|
#define DCC_TURNTABLE(id,home,description...) O_DESC(id,description)
|
||||||
#undef EXTT_TURNTABLE
|
#undef EXTT_TURNTABLE
|
||||||
#define EXTT_TURNTABLE(id,vpin,home,description...) O_DESC(id,description)
|
#define EXTT_TURNTABLE(id,vpin,i2c_address,home,description...) O_DESC(id,description)
|
||||||
|
|
||||||
const FSH * RMFT2::getTurntableDescription(int16_t turntableId) {
|
const FSH * RMFT2::getTurntableDescription(int16_t turntableId) {
|
||||||
switch (turntableId) {
|
switch (turntableId) {
|
||||||
|
@ -300,16 +273,6 @@ const HIGHFLASH int16_t RMFT2::SignalDefinitions[] = {
|
||||||
#include "myAutomation.h"
|
#include "myAutomation.h"
|
||||||
0,0,0,0 };
|
0,0,0,0 };
|
||||||
|
|
||||||
// Pass 9 ONLCC counter and lookup array
|
|
||||||
#include "EXRAIL2MacroReset.h"
|
|
||||||
#undef ONLCC
|
|
||||||
#define ONLCC(sender,event) +1
|
|
||||||
|
|
||||||
const int RMFT2::countLCCLookup=0
|
|
||||||
#include "myAutomation.h"
|
|
||||||
;
|
|
||||||
int RMFT2::onLCCLookup[RMFT2::countLCCLookup];
|
|
||||||
|
|
||||||
// Last Pass : create main routes table
|
// Last Pass : create main routes table
|
||||||
// Only undef the macros, not dummy them.
|
// Only undef the macros, not dummy them.
|
||||||
#define RMFT2_UNDEF_ONLY
|
#define RMFT2_UNDEF_ONLY
|
||||||
|
@ -354,7 +317,7 @@ int RMFT2::onLCCLookup[RMFT2::countLCCLookup];
|
||||||
#define ESTOP OPCODE_SPEED,V(1),
|
#define ESTOP OPCODE_SPEED,V(1),
|
||||||
#define EXRAIL
|
#define EXRAIL
|
||||||
#ifndef IO_NO_HAL
|
#ifndef IO_NO_HAL
|
||||||
#define EXTT_TURNTABLE(id,vpin,home,description...) OPCODE_EXTTTURNTABLE,V(id),OPCODE_PAD,V(vpin),OPCODE_PAD,V(home),
|
#define EXTT_TURNTABLE(id,vpin,i2c_address,home,description...) OPCODE_EXTTTURNTABLE,V(id),OPCODE_PAD,V(vpin),OPCODE_PAD,V(i2c_address),OPCODE_PAD,V(home),
|
||||||
#endif
|
#endif
|
||||||
#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 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 FOFF(func) OPCODE_FOFF,V(func),
|
||||||
|
@ -386,11 +349,6 @@ int RMFT2::onLCCLookup[RMFT2::countLCCLookup];
|
||||||
#define JOIN OPCODE_JOIN,0,0,
|
#define JOIN OPCODE_JOIN,0,0,
|
||||||
#define KILLALL OPCODE_KILLALL,0,0,
|
#define KILLALL OPCODE_KILLALL,0,0,
|
||||||
#define LATCH(sensor_id) OPCODE_LATCH,V(sensor_id),
|
#define LATCH(sensor_id) OPCODE_LATCH,V(sensor_id),
|
||||||
#define LCC(eventid) OPCODE_LCC,V(eventid),
|
|
||||||
#define LCCX(sender,event) OPCODE_LCCX,V(event),\
|
|
||||||
OPCODE_PAD,V((((uint64_t)sender)>>32)&0xFFFF),\
|
|
||||||
OPCODE_PAD,V((((uint64_t)sender)>>16)&0xFFFF),\
|
|
||||||
OPCODE_PAD,V((((uint64_t)sender)>>0)&0xFFFF),
|
|
||||||
#define LCD(id,msg) PRINT(msg)
|
#define LCD(id,msg) PRINT(msg)
|
||||||
#define SCREEN(display,id,msg) PRINT(msg)
|
#define SCREEN(display,id,msg) PRINT(msg)
|
||||||
#define LCN(msg) PRINT(msg)
|
#define LCN(msg) PRINT(msg)
|
||||||
|
@ -399,10 +357,6 @@ int RMFT2::onLCCLookup[RMFT2::countLCCLookup];
|
||||||
#define ONACTIVATEL(linear) OPCODE_ONACTIVATE,V(linear+3),
|
#define ONACTIVATEL(linear) OPCODE_ONACTIVATE,V(linear+3),
|
||||||
#define ONAMBER(signal_id) OPCODE_ONAMBER,V(signal_id),
|
#define ONAMBER(signal_id) OPCODE_ONAMBER,V(signal_id),
|
||||||
#define ONCLOSE(turnout_id) OPCODE_ONCLOSE,V(turnout_id),
|
#define ONCLOSE(turnout_id) OPCODE_ONCLOSE,V(turnout_id),
|
||||||
#define ONLCC(sender,event) OPCODE_ONLCC,V(event),\
|
|
||||||
OPCODE_PAD,V((((uint64_t)sender)>>32)&0xFFFF),\
|
|
||||||
OPCODE_PAD,V((((uint64_t)sender)>>16)&0xFFFF),\
|
|
||||||
OPCODE_PAD,V((((uint64_t)sender)>>0)&0xFFFF),
|
|
||||||
#define ONTIME(value) OPCODE_ONTIME,V(value),
|
#define ONTIME(value) OPCODE_ONTIME,V(value),
|
||||||
#define ONCLOCKTIME(hours,mins) OPCODE_ONTIME,V((STRIP_ZERO(hours)*60)+STRIP_ZERO(mins)),
|
#define ONCLOCKTIME(hours,mins) OPCODE_ONTIME,V((STRIP_ZERO(hours)*60)+STRIP_ZERO(mins)),
|
||||||
#define ONCLOCKMINS(mins) ONCLOCKTIME(25,mins)
|
#define ONCLOCKMINS(mins) ONCLOCKTIME(25,mins)
|
||||||
|
@ -453,7 +407,6 @@ int RMFT2::onLCCLookup[RMFT2::countLCCLookup];
|
||||||
#define SERVO_TURNOUT(id,pin,activeAngle,inactiveAngle,profile,description...) OPCODE_SERVOTURNOUT,V(id),OPCODE_PAD,V(pin),OPCODE_PAD,V(activeAngle),OPCODE_PAD,V(inactiveAngle),OPCODE_PAD,V(PCA9685::ProfileType::profile),
|
#define SERVO_TURNOUT(id,pin,activeAngle,inactiveAngle,profile,description...) OPCODE_SERVOTURNOUT,V(id),OPCODE_PAD,V(pin),OPCODE_PAD,V(activeAngle),OPCODE_PAD,V(inactiveAngle),OPCODE_PAD,V(PCA9685::ProfileType::profile),
|
||||||
#define SET(pin) OPCODE_SET,V(pin),
|
#define SET(pin) OPCODE_SET,V(pin),
|
||||||
#define SET_TRACK(track,mode) OPCODE_SET_TRACK,V(TRACK_MODE_##mode <<8 | TRACK_NUMBER_##track),
|
#define SET_TRACK(track,mode) OPCODE_SET_TRACK,V(TRACK_MODE_##mode <<8 | TRACK_NUMBER_##track),
|
||||||
#define SET_POWER(track,onoff) OPCODE_SET_POWER,V(TRACK_POWER_##onoff),OPCODE_PAD, V(TRACK_NUMBER_##track),
|
|
||||||
#define SETLOCO(loco) OPCODE_SETLOCO,V(loco),
|
#define SETLOCO(loco) OPCODE_SETLOCO,V(loco),
|
||||||
#define SIGNAL(redpin,amberpin,greenpin)
|
#define SIGNAL(redpin,amberpin,greenpin)
|
||||||
#define SIGNALH(redpin,amberpin,greenpin)
|
#define SIGNALH(redpin,amberpin,greenpin)
|
||||||
|
|
|
@ -117,7 +117,6 @@ void StringFormatter::send2(Print * stream,const FSH* format, va_list args) {
|
||||||
case 'o': stream->print(va_arg(args, int), OCT); break;
|
case 'o': stream->print(va_arg(args, int), OCT); break;
|
||||||
case 'x': stream->print((unsigned int)va_arg(args, unsigned int), HEX); break;
|
case 'x': stream->print((unsigned int)va_arg(args, unsigned int), HEX); break;
|
||||||
case 'X': stream->print((unsigned long)va_arg(args, unsigned long), HEX); break;
|
case 'X': stream->print((unsigned long)va_arg(args, unsigned long), HEX); break;
|
||||||
case 'h': printHex(stream,(unsigned int)va_arg(args, unsigned int)); break;
|
|
||||||
case 'M':
|
case 'M':
|
||||||
{ // this prints a unsigned long microseconds time in readable format
|
{ // this prints a unsigned long microseconds time in readable format
|
||||||
unsigned long time = va_arg(args, long);
|
unsigned long time = va_arg(args, long);
|
||||||
|
@ -219,15 +218,4 @@ void StringFormatter::printPadded(Print* stream, long value, byte width, bool fo
|
||||||
if (!formatLeft) stream->print(value, DEC);
|
if (!formatLeft) stream->print(value, DEC);
|
||||||
}
|
}
|
||||||
|
|
||||||
// printHex prints the full 2 byte hex with leading zeros, unlike print(value,HEX)
|
|
||||||
const char FLASH hexchars[]="0123456789ABCDEF";
|
|
||||||
void StringFormatter::printHex(Print * stream,uint16_t value) {
|
|
||||||
char result[5];
|
|
||||||
for (int i=3;i>=0;i--) {
|
|
||||||
result[i]=GETFLASH(hexchars+(value & 0x0F));
|
|
||||||
value>>=4;
|
|
||||||
}
|
|
||||||
result[4]='\0';
|
|
||||||
stream->print(result);
|
|
||||||
}
|
|
||||||
|
|
|
@ -49,7 +49,6 @@ class StringFormatter
|
||||||
static void lcd2(uint8_t display, byte row, const FSH* input...);
|
static void lcd2(uint8_t display, byte row, const FSH* input...);
|
||||||
static void printEscapes(char * input);
|
static void printEscapes(char * input);
|
||||||
static void printEscape( char c);
|
static void printEscape( char c);
|
||||||
static void printHex(Print * stream,uint16_t value);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void send2(Print * serial, const FSH* input,va_list args);
|
static void send2(Print * serial, const FSH* input,va_list args);
|
||||||
|
|
|
@ -27,7 +27,6 @@
|
||||||
#include "DCCTimer.h"
|
#include "DCCTimer.h"
|
||||||
#include "DIAG.h"
|
#include "DIAG.h"
|
||||||
#include"CommandDistributor.h"
|
#include"CommandDistributor.h"
|
||||||
#include "DCCEXParser.h"
|
|
||||||
// Virtualised Motor shield multi-track hardware Interface
|
// Virtualised Motor shield multi-track hardware Interface
|
||||||
#define FOR_EACH_TRACK(t) for (byte t=0;t<=lastTrack;t++)
|
#define FOR_EACH_TRACK(t) for (byte t=0;t<=lastTrack;t++)
|
||||||
|
|
||||||
|
@ -332,7 +331,6 @@ bool TrackManager::parseJ(Print *stream, int16_t params, int16_t p[])
|
||||||
FOR_EACH_TRACK(t)
|
FOR_EACH_TRACK(t)
|
||||||
streamTrackState(stream,t);
|
streamTrackState(stream,t);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
p[0]-=HASH_KEYWORD_A; // convert A... to 0....
|
p[0]-=HASH_KEYWORD_A; // convert A... to 0....
|
||||||
|
@ -367,36 +365,32 @@ void TrackManager::streamTrackState(Print* stream, byte t) {
|
||||||
// null stream means send to commandDistributor for broadcast
|
// null stream means send to commandDistributor for broadcast
|
||||||
if (track[t]==NULL) return;
|
if (track[t]==NULL) return;
|
||||||
auto format=F("");
|
auto format=F("");
|
||||||
bool pstate = TrackManager::isPowerOn(t);
|
|
||||||
|
|
||||||
switch(track[t]->getMode()) {
|
switch(track[t]->getMode()) {
|
||||||
case TRACK_MODE_MAIN:
|
case TRACK_MODE_MAIN:
|
||||||
if (pstate) {format=F("<= %c MAIN ON>\n");} else {format = F("<= %c MAIN OFF>\n");}
|
format=F("<= %c MAIN>\n");
|
||||||
break;
|
break;
|
||||||
#ifndef DISABLE_PROG
|
#ifndef DISABLE_PROG
|
||||||
case TRACK_MODE_PROG:
|
case TRACK_MODE_PROG:
|
||||||
if (pstate) {format=F("<= %c PROG ON>\n");} else {format=F("<= %c PROG OFF>\n");}
|
format=F("<= %c PROG>\n");
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
case TRACK_MODE_NONE:
|
case TRACK_MODE_NONE:
|
||||||
if (pstate) {format=F("<= %c NONE ON>\n");} else {format=F("<= %c NONE OFF>\n");}
|
format=F("<= %c NONE>\n");
|
||||||
break;
|
break;
|
||||||
case TRACK_MODE_EXT:
|
case TRACK_MODE_EXT:
|
||||||
if (pstate) {format=F("<= %c EXT ON>\n");} else {format=F("<= %c EXT OFF>\n");}
|
format=F("<= %c EXT>\n");
|
||||||
break;
|
break;
|
||||||
case TRACK_MODE_DC:
|
case TRACK_MODE_DC:
|
||||||
if (pstate) {format=F("<= %c DC %d ON>\n");} else {format=F("<= %c DC %d OFF>\n");}
|
format=F("<= %c DC %d>\n");
|
||||||
break;
|
break;
|
||||||
case TRACK_MODE_DCX:
|
case TRACK_MODE_DCX:
|
||||||
if (pstate) {format=F("<= %c DCX %d ON>\n");} else {format=F("<= %c DCX %d OFF>\n");}
|
format=F("<= %c DCX %d>\n");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break; // unknown, dont care
|
break; // unknown, dont care
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stream) StringFormatter::send(stream,format,'A'+t,trackDCAddr[t]);
|
if (stream) StringFormatter::send(stream,format,'A'+t,trackDCAddr[t]);
|
||||||
else CommandDistributor::broadcastTrackState(format,'A'+t,trackDCAddr[t]);
|
else CommandDistributor::broadcastTrackState(format,'A'+t,trackDCAddr[t]);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
byte TrackManager::nextCycleTrack=MAX_TRACKS;
|
byte TrackManager::nextCycleTrack=MAX_TRACKS;
|
||||||
|
@ -430,23 +424,12 @@ std::vector<MotorDriver *>TrackManager::getMainDrivers() {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void TrackManager::setPower2(bool setProg,bool setJoin, POWERMODE mode) {
|
void TrackManager::setPower2(bool setProg,POWERMODE mode) {
|
||||||
if (!setProg) mainPowerGuess=mode;
|
if (!setProg) mainPowerGuess=mode;
|
||||||
FOR_EACH_TRACK(t) {
|
FOR_EACH_TRACK(t) {
|
||||||
|
MotorDriver * driver=track[t];
|
||||||
TrackManager::setTrackPower(setProg, setJoin, mode, t);
|
if (!driver) continue;
|
||||||
|
switch (track[t]->getMode()) {
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TrackManager::setTrackPower(bool setProg, bool setJoin, POWERMODE mode, byte thistrack) {
|
|
||||||
|
|
||||||
//DIAG(F("SetTrackPower Processing Track %d"), thistrack);
|
|
||||||
MotorDriver * driver=track[thistrack];
|
|
||||||
if (!driver) return;
|
|
||||||
|
|
||||||
switch (track[thistrack]->getMode()) {
|
|
||||||
case TRACK_MODE_MAIN:
|
case TRACK_MODE_MAIN:
|
||||||
if (setProg) break;
|
if (setProg) break;
|
||||||
// toggle brake before turning power on - resets overcurrent error
|
// toggle brake before turning power on - resets overcurrent error
|
||||||
|
@ -458,14 +441,13 @@ void TrackManager::setTrackPower(bool setProg, bool setJoin, POWERMODE mode, byt
|
||||||
break;
|
break;
|
||||||
case TRACK_MODE_DC:
|
case TRACK_MODE_DC:
|
||||||
case TRACK_MODE_DCX:
|
case TRACK_MODE_DCX:
|
||||||
//DIAG(F("Processing track - %d setProg %d"), thistrack, setProg);
|
if (setProg) break;
|
||||||
if (setProg || setJoin) break;
|
|
||||||
driver->setBrake(true); // DC starts with brake on
|
driver->setBrake(true); // DC starts with brake on
|
||||||
applyDCSpeed(thistrack); // speed match DCC throttles
|
applyDCSpeed(t); // speed match DCC throttles
|
||||||
driver->setPower(mode);
|
driver->setPower(mode);
|
||||||
break;
|
break;
|
||||||
case TRACK_MODE_PROG:
|
case TRACK_MODE_PROG:
|
||||||
if (!setProg && !setJoin) break;
|
if (!setProg) break;
|
||||||
driver->setBrake(true);
|
driver->setBrake(true);
|
||||||
driver->setBrake(false);
|
driver->setBrake(false);
|
||||||
driver->setPower(mode);
|
driver->setPower(mode);
|
||||||
|
@ -478,16 +460,7 @@ void TrackManager::setTrackPower(bool setProg, bool setJoin, POWERMODE mode, byt
|
||||||
case TRACK_MODE_NONE:
|
case TRACK_MODE_NONE:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
POWERMODE TrackManager::getProgPower() {
|
POWERMODE TrackManager::getProgPower() {
|
||||||
|
@ -565,32 +538,3 @@ bool TrackManager::isPowerOn(byte t) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TrackManager::isProg(byte t) {
|
|
||||||
if (track[t]->getMode()==TRACK_MODE_PROG)
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte TrackManager::returnMode(byte t) {
|
|
||||||
return (track[t]->getMode());
|
|
||||||
}
|
|
||||||
|
|
||||||
int16_t TrackManager::returnDCAddr(byte 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 "----";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -39,10 +39,6 @@ const byte TRACK_NUMBER_5=5, TRACK_NUMBER_F=5;
|
||||||
const byte TRACK_NUMBER_6=6, TRACK_NUMBER_G=6;
|
const byte TRACK_NUMBER_6=6, TRACK_NUMBER_G=6;
|
||||||
const byte TRACK_NUMBER_7=7, TRACK_NUMBER_H=7;
|
const byte TRACK_NUMBER_7=7, TRACK_NUMBER_H=7;
|
||||||
|
|
||||||
// These constants help EXRAIL macros convert Track Power e.g. SET_POWER(A ON|OFF).
|
|
||||||
const byte TRACK_POWER_0=0, TRACK_POWER_OFF=0;
|
|
||||||
const byte TRACK_POWER_1=1, TRACK_POWER_ON=1;
|
|
||||||
|
|
||||||
class TrackManager {
|
class TrackManager {
|
||||||
public:
|
public:
|
||||||
static void Setup(const FSH * shieldName,
|
static void Setup(const FSH * shieldName,
|
||||||
|
@ -64,14 +60,10 @@ class TrackManager {
|
||||||
#ifdef ARDUINO_ARCH_ESP32
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
static std::vector<MotorDriver *>getMainDrivers();
|
static std::vector<MotorDriver *>getMainDrivers();
|
||||||
#endif
|
#endif
|
||||||
|
static void setPower2(bool progTrack,POWERMODE mode);
|
||||||
static void setPower2(bool progTrack,bool joinTrack,POWERMODE mode);
|
|
||||||
static void setPower(POWERMODE mode) {setMainPower(mode); setProgPower(mode);}
|
static void setPower(POWERMODE mode) {setMainPower(mode); setProgPower(mode);}
|
||||||
static void setMainPower(POWERMODE mode) {setPower2(false,false,mode);}
|
static void setMainPower(POWERMODE mode) {setPower2(false,mode);}
|
||||||
static void setProgPower(POWERMODE mode) {setPower2(true,false,mode);}
|
static void setProgPower(POWERMODE mode) {setPower2(true,mode);}
|
||||||
static void setJoinPower(POWERMODE mode) {setPower2(false,true,mode);}
|
|
||||||
static void setTrackPower(bool setProg, bool setJoin, POWERMODE mode, byte thistrack);
|
|
||||||
|
|
||||||
|
|
||||||
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);
|
||||||
|
@ -85,14 +77,9 @@ class TrackManager {
|
||||||
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 byte returnMode(byte t);
|
|
||||||
static int16_t returnDCAddr(byte t);
|
|
||||||
static const char* getModeName(byte 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
|
||||||
|
|
|
@ -185,7 +185,7 @@ public:
|
||||||
for (Turntable *tto = _firstTurntable; tto != 0; tto = tto->_nextTurntable)
|
for (Turntable *tto = _firstTurntable; tto != 0; tto = tto->_nextTurntable)
|
||||||
if (!tto->isHidden()) {
|
if (!tto->isHidden()) {
|
||||||
gotOne = true;
|
gotOne = true;
|
||||||
StringFormatter::send(stream, F("<I %d %d>\n"), tto->getId(), tto->getPosition());
|
StringFormatter::send(stream, F("<i %d %d>\n"), tto->getId(), tto->getPosition());
|
||||||
}
|
}
|
||||||
return gotOne;
|
return gotOne;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,6 @@
|
||||||
//#include "IO_TouchKeypad.h // Touch keypad with 16 keys
|
//#include "IO_TouchKeypad.h // Touch keypad with 16 keys
|
||||||
//#include "IO_EXTurntable.h" // Turntable-EX turntable controller
|
//#include "IO_EXTurntable.h" // Turntable-EX turntable controller
|
||||||
//#include "IO_EXFastClock.h" // FastClock driver
|
//#include "IO_EXFastClock.h" // FastClock driver
|
||||||
//#include "IO_PCA9555.h" // 16-bit I/O expander (NXP & Texas Instruments).
|
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
// The function halSetup() is invoked from CS if it exists within the build.
|
// The function halSetup() is invoked from CS if it exists within the build.
|
||||||
|
|
11
version.h
11
version.h
|
@ -3,16 +3,7 @@
|
||||||
|
|
||||||
#include "StringFormatter.h"
|
#include "StringFormatter.h"
|
||||||
|
|
||||||
#define VERSION "5.1.16"
|
#define VERSION "5.1.11"
|
||||||
// 5.1.16 - Remove I2C address from EXTT_TURNTABLE macro to work with MUX, requires separate HAL macro to create
|
|
||||||
// 5.1.15 - LCC/Adapter support and Exrail feature-compile-out.
|
|
||||||
// 5.1.14 - Fixed IFTTPOSITION
|
|
||||||
// 5.1.13 - Changed turntable broadcast from i to I due to server string conflict
|
|
||||||
// 5.1.12 - Added Power commands <0 A> & <1 A> etc. and update to <=>
|
|
||||||
// Added EXRAIL SET_POWER(track, ON/OFF)
|
|
||||||
// Fixed a problem whereby <1 MAIN> also powered on PROG track
|
|
||||||
// Added functions to TrackManager.cpp to allow UserAddin code for power display on OLED/LCD
|
|
||||||
// Added - returnMode(byte t), returnDCAddr(byte t) & getModeName(byte Mode)
|
|
||||||
// 5.1.11 - STM32F4xx revised I2C clock setup, no correctly sets clock and has fully variable frequency selection
|
// 5.1.11 - STM32F4xx revised I2C clock setup, no correctly sets clock and has fully variable frequency selection
|
||||||
// 5.1.10 - STM32F4xx DCCEXanalogWrite to handle PWM generation for TrackManager DC/DCX
|
// 5.1.10 - STM32F4xx DCCEXanalogWrite to handle PWM generation for TrackManager DC/DCX
|
||||||
// - STM32F4xx DCC 58uS timer now using non-PWM output timers where possible
|
// - STM32F4xx DCC 58uS timer now using non-PWM output timers where possible
|
||||||
|
|
Loading…
Reference in New Issue
Block a user