diff --git a/DCCEX.h b/DCCEX.h index 2dc8eb7..3aa7b7a 100644 --- a/DCCEX.h +++ b/DCCEX.h @@ -49,6 +49,7 @@ #include "CommandDistributor.h" #include "TrackManager.h" #include "DCCTimer.h" +#include "KeywordHasher.h" #include "EXRAIL.h" #endif diff --git a/DCCEXParser.cpp b/DCCEXParser.cpp index aefed4c..47665c5 100644 --- a/DCCEXParser.cpp +++ b/DCCEXParser.cpp @@ -116,6 +116,7 @@ Once a new OPCODE is decided upon, update this list. #include "EXRAIL2.h" #include "Turntables.h" #include "version.h" +#include "KeywordHasher.h" // This macro can't be created easily as a portable function because the // flashlist requires a far pointer for high flash access. @@ -126,57 +127,6 @@ Once a new OPCODE is decided upon, update this list. StringFormatter::send(stream,F(" %d"),value); \ } - -// These keywords are used in the <1> command. The number is what you get if you use the keyword as a parameter. -// To discover new keyword numbers , use the <$ YOURKEYWORD> command -const int16_t HASH_KEYWORD_MAIN = 11339; -const int16_t HASH_KEYWORD_CABS = -11981; -const int16_t HASH_KEYWORD_RAM = 25982; -const int16_t HASH_KEYWORD_CMD = 9962; -const int16_t HASH_KEYWORD_ACK = 3113; -const int16_t HASH_KEYWORD_ON = 2657; -const int16_t HASH_KEYWORD_DCC = 6436; -const int16_t HASH_KEYWORD_SLOW = -17209; -#ifndef DISABLE_PROG -const int16_t HASH_KEYWORD_JOIN = -30750; -const int16_t HASH_KEYWORD_PROG = -29718; -const int16_t HASH_KEYWORD_PROGBOOST = -6353; -#endif -#ifndef DISABLE_EEPROM -const int16_t HASH_KEYWORD_EEPROM = -7168; -#endif -const int16_t HASH_KEYWORD_LIMIT = 27413; -const int16_t HASH_KEYWORD_MAX = 16244; -const int16_t HASH_KEYWORD_MIN = 15978; -const int16_t HASH_KEYWORD_RESET = 26133; -const int16_t HASH_KEYWORD_RETRY = 25704; -const int16_t HASH_KEYWORD_SPEED28 = -17064; -const int16_t HASH_KEYWORD_SPEED128 = 25816; -const int16_t HASH_KEYWORD_SERVO=27709; -const int16_t HASH_KEYWORD_TT=2688; -const int16_t HASH_KEYWORD_VPIN=-415; -const int16_t HASH_KEYWORD_A='A'; -const int16_t HASH_KEYWORD_C='C'; -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_M='M'; -const int16_t HASH_KEYWORD_O='O'; -const int16_t HASH_KEYWORD_P='P'; -const int16_t HASH_KEYWORD_R='R'; -const int16_t HASH_KEYWORD_T='T'; -const int16_t HASH_KEYWORD_X='X'; -const int16_t HASH_KEYWORD_LCN = 15137; -const int16_t HASH_KEYWORD_HAL = 10853; -const int16_t HASH_KEYWORD_SHOW = -21309; -const int16_t HASH_KEYWORD_ANIN = -10424; -const int16_t HASH_KEYWORD_ANOUT = -26399; -const int16_t HASH_KEYWORD_WIFI = -5583; -const int16_t HASH_KEYWORD_ETHERNET = -30767; -const int16_t HASH_KEYWORD_WIT = 31594; -const int16_t HASH_KEYWORD_EXTT = 8573; -const int16_t HASH_KEYWORD_ADD = 3201; - int16_t DCCEXParser::stashP[MAX_COMMAND_PARAMS]; bool DCCEXParser::stashBusy; Print *DCCEXParser::stashStream = NULL; @@ -567,20 +517,20 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream) TrackManager::setTrackPower(TRACK_MODE_ALL, POWERMODE::ON); } if (params==1) { - if (p[0]==HASH_KEYWORD_MAIN) { // <1 MAIN> + if (p[0]=="MAIN"_hk) { // <1 MAIN> TrackManager::setTrackPower(TRACK_MODE_MAIN, POWERMODE::ON); } #ifndef DISABLE_PROG - else if (p[0] == HASH_KEYWORD_JOIN) { // <1 JOIN> + else if (p[0] == "JOIN"_hk) { // <1 JOIN> TrackManager::setJoin(true); TrackManager::setTrackPower(TRACK_MODE_MAIN|TRACK_MODE_PROG, POWERMODE::ON); } - else if (p[0]==HASH_KEYWORD_PROG) { // <1 PROG> + else if (p[0]=="PROG"_hk) { // <1 PROG> TrackManager::setJoin(false); TrackManager::setTrackPower(TRACK_MODE_PROG, POWERMODE::ON); } #endif - else if (p[0] >= HASH_KEYWORD_A && p[0] <= HASH_KEYWORD_H) { // <1 A-H> + else if (p[0] >= "A"_hk && p[0] <= "H"_hk) { // <1 A-H> byte t = (p[0] - 'A'); TrackManager::setTrackPower(POWERMODE::ON, t); //StringFormatter::send(stream, F("\n"), t+'A'); @@ -600,17 +550,17 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream) TrackManager::setTrackPower(TRACK_MODE_ALL, POWERMODE::OFF); } if (params==1) { - if (p[0]==HASH_KEYWORD_MAIN) { // <0 MAIN> + if (p[0]=="MAIN"_hk) { // <0 MAIN> TrackManager::setJoin(false); TrackManager::setTrackPower(TRACK_MODE_MAIN, POWERMODE::OFF); } #ifndef DISABLE_PROG - else if (p[0]==HASH_KEYWORD_PROG) { // <0 PROG> + else if (p[0]=="PROG"_hk) { // <0 PROG> TrackManager::progTrackBoosted=false; // Prog track boost mode will not outlive prog track off TrackManager::setTrackPower(TRACK_MODE_PROG, POWERMODE::OFF); } #endif - else if (p[0] >= HASH_KEYWORD_A && p[0] <= HASH_KEYWORD_H) { // <1 A-H> + else if (p[0] >= "A"_hk && p[0] <= "H"_hk) { // <1 A-H> byte t = (p[0] - 'A'); TrackManager::setJoin(false); TrackManager::setTrackPower(POWERMODE::OFF, t); @@ -704,7 +654,7 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream) //if ((params<1) | (params>2)) break; // int16_t id=(params==2)?p[1]:0; switch(p[0]) { - case HASH_KEYWORD_C: // sets time and speed + case "C"_hk: // sets time and speed if (params==1) { // returns latest time int16_t x = CommandDistributor::retClockTime(); StringFormatter::send(stream, F("\n"), x); @@ -713,28 +663,28 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream) CommandDistributor::setClockTime(p[1], p[2], 1); return; - case HASH_KEYWORD_G: // current gauge limits + case "G"_hk: // current gauge limits if (params>1) break; TrackManager::reportGauges(stream); // return; - case HASH_KEYWORD_I: // current values + case "I"_hk: // current values if (params>1) break; TrackManager::reportCurrent(stream); // return; - case HASH_KEYWORD_A: // intercepted by EXRAIL// returns automations/routes + case "A"_hk: // intercepted by EXRAIL// returns automations/routes if (params!=1) break; // StringFormatter::send(stream, F("\n")); return; - case HASH_KEYWORD_M: // intercepted by EXRAIL + case "M"_hk: // intercepted by EXRAIL if (params>1) break; // invalid cant do // requests stash size so say none. StringFormatter::send(stream,F("\n")); return; - case HASH_KEYWORD_R: // returns rosters + case "R"_hk: // returns rosters StringFormatter::send(stream, F("\n")); return; - case HASH_KEYWORD_T: // returns turnout list + case "T"_hk: // returns turnout list StringFormatter::send(stream, F(" for ( Turnout * t=Turnout::first(); t; t=t->next()) { @@ -780,7 +730,7 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream) return; // No turntables without HAL support #ifndef IO_NO_HAL - case HASH_KEYWORD_O: // for (Turntable * tto=Turntable::first(); tto; tto=tto->next()) { @@ -805,7 +755,7 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream) } } return; - case HASH_KEYWORD_P: // returns turntable position list for the turntable id + case "P"_hk: // returns turntable position list for the turntable id if (params==2) { // Turntable *tto=Turntable::get(id); if (!tto || tto->isHidden()) { @@ -972,14 +922,14 @@ bool DCCEXParser::parseT(Print *stream, int16_t params, int16_t p[]) switch (p[1]) { // Turnout messages use 1=throw, 0=close. case 0: - case HASH_KEYWORD_C: + case "C"_hk: state = true; break; case 1: - case HASH_KEYWORD_T: + case "T"_hk: state= false; break; - case HASH_KEYWORD_X: + case "X"_hk: { Turnout *tt = Turnout::get(p[0]); if (tt) { @@ -996,14 +946,14 @@ bool DCCEXParser::parseT(Print *stream, int16_t params, int16_t p[]) } default: // Anything else is some kind of turnout create function. - if (params == 6 && p[1] == HASH_KEYWORD_SERVO) { // + if (params == 6 && p[1] == "SERVO"_hk) { // if (!ServoTurnout::create(p[0], (VPIN)p[2], (uint16_t)p[3], (uint16_t)p[4], (uint8_t)p[5])) return false; } else - if (params == 3 && p[1] == HASH_KEYWORD_VPIN) { // + if (params == 3 && p[1] == "VPIN"_hk) { // if (!VpinTurnout::create(p[0], p[2])) return false; } else - if (params >= 3 && p[1] == HASH_KEYWORD_DCC) { + if (params >= 3 && p[1] == "DCC"_hk) { // 0<=addr<=511, 0<=subadd<=3 (like command). if (params==4 && p[2]>=0 && p[2]<512 && p[3]>=0 && p[3]<4) { // if (!DCCTurnout::create(p[0], p[2], p[3])) return false; @@ -1069,41 +1019,41 @@ bool DCCEXParser::parseC(Print *stream, int16_t params, int16_t p[]) { switch (p[0]) { #ifndef DISABLE_PROG - case HASH_KEYWORD_PROGBOOST: + case "PROGBOOST"_hk: TrackManager::progTrackBoosted=true; return true; #endif - case HASH_KEYWORD_RESET: + case "RESET"_hk: DCCTimer::reset(); break; // and if we didnt restart - case HASH_KEYWORD_SPEED28: + case "SPEED28"_hk: DCC::setGlobalSpeedsteps(28); DIAG(F("28 Speedsteps")); return true; - case HASH_KEYWORD_SPEED128: + case "SPEED128"_hk: DCC::setGlobalSpeedsteps(128); DIAG(F("128 Speedsteps")); return true; #ifndef DISABLE_PROG - case HASH_KEYWORD_ACK: // + case "ACK"_hk: // if (params >= 3) { - if (p[1] == HASH_KEYWORD_LIMIT) { + if (p[1] == "LIMIT"_hk) { DCCACK::setAckLimit(p[2]); LCD(1, F("Ack Limit=%dmA"), p[2]); // - } else if (p[1] == HASH_KEYWORD_MIN) { + } else if (p[1] == "MIN"_hk) { DCCACK::setMinAckPulseDuration(p[2]); LCD(0, F("Ack Min=%uus"), p[2]); // - } else if (p[1] == HASH_KEYWORD_MAX) { + } else if (p[1] == "MAX"_hk) { DCCACK::setMaxAckPulseDuration(p[2]); LCD(0, F("Ack Max=%uus"), p[2]); // - } else if (p[1] == HASH_KEYWORD_RETRY) { + } else if (p[1] == "RETRY"_hk) { if (p[2] >255) p[2]=3; LCD(0, F("Ack Retry=%d Sum=%d"), p[2], DCCACK::setAckRetry(p[2])); // } } else { - bool onOff = (params > 0) && (p[1] == 1 || p[1] == HASH_KEYWORD_ON); // dont care if other stuff or missing... just means off + bool onOff = (params > 0) && (p[1] == 1 || p[1] == "ON"_hk); // dont care if other stuff or missing... just means off DIAG(F("Ack diag %S"), onOff ? F("on") : F("off")); Diag::ACK = onOff; @@ -1121,64 +1071,64 @@ bool DCCEXParser::parseD(Print *stream, int16_t params, int16_t p[]) { if (params == 0) return false; - bool onOff = (params > 0) && (p[1] == 1 || p[1] == HASH_KEYWORD_ON); // dont care if other stuff or missing... just means off + bool onOff = (params > 0) && (p[1] == 1 || p[1] == "ON"_hk); // dont care if other stuff or missing... just means off switch (p[0]) { - case HASH_KEYWORD_CABS: // + case "CABS"_hk: // DCC::displayCabList(stream); return true; - case HASH_KEYWORD_RAM: // + case "RAM"_hk: // DIAG(F("Free memory=%d"), DCCTimer::getMinimumFreeMemory()); return true; - case HASH_KEYWORD_CMD: // + case "CMD"_hk: // Diag::CMD = onOff; return true; #ifdef HAS_ENOUGH_MEMORY - case HASH_KEYWORD_WIFI: // + case "WIFI"_hk: // Diag::WIFI = onOff; return true; - case HASH_KEYWORD_ETHERNET: // + case "ETHERNET"_hk: // Diag::ETHERNET = onOff; return true; - case HASH_KEYWORD_WIT: // + case "WIT"_hk: // Diag::WITHROTTLE = onOff; return true; - case HASH_KEYWORD_LCN: // + case "LCN"_hk: // Diag::LCN = onOff; return true; #endif #ifndef DISABLE_EEPROM - case HASH_KEYWORD_EEPROM: // + case "EEPROM"_hk: // if (params >= 2) EEStore::dump(p[1]); return true; #endif - case HASH_KEYWORD_SERVO: // + case "SERVO"_hk: // - case HASH_KEYWORD_ANOUT: // + case "ANOUT"_hk: // IODevice::writeAnalogue(p[1], p[2], params>3 ? p[3] : 0); break; - case HASH_KEYWORD_ANIN: // Display analogue input value + case "ANIN"_hk: // Display analogue input value DIAG(F("VPIN=%u value=%d"), p[1], IODevice::readAnalogue(p[1])); break; #if !defined(IO_NO_HAL) - case HASH_KEYWORD_HAL: - if (p[1] == HASH_KEYWORD_SHOW) + case "HAL"_hk: + if (p[1] == "SHOW"_hk) IODevice::DumpAll(); - else if (p[1] == HASH_KEYWORD_RESET) + else if (p[1] == "RESET"_hk) IODevice::reset(); break; #endif - case HASH_KEYWORD_TT: // + case "TT"_hk: // IODevice::writeAnalogue(p[1], p[2], params>3 ? p[3] : 0); break; @@ -1232,7 +1182,7 @@ bool DCCEXParser::parseI(Print *stream, int16_t params, int16_t p[]) case 3: // | - rotate to position for EX-Turntable or create DCC turntable { Turntable *tto = Turntable::get(p[0]); - if (p[1] == HASH_KEYWORD_DCC) { + if (p[1] == "DCC"_hk) { if (tto || p[2] < 0 || p[2] > 3600) return false; if (!DCCTurntable::create(p[0])) return false; Turntable *tto = Turntable::get(p[0]); @@ -1249,7 +1199,7 @@ bool DCCEXParser::parseI(Print *stream, int16_t params, int16_t p[]) case 4: // create an EXTT turntable { Turntable *tto = Turntable::get(p[0]); - if (p[1] == HASH_KEYWORD_EXTT) { + if (p[1] == "EXTT"_hk) { if (tto || p[3] < 0 || p[3] > 3600) return false; if (!EXTTTurntable::create(p[0], (VPIN)p[2])) return false; Turntable *tto = Turntable::get(p[0]); @@ -1264,7 +1214,7 @@ bool DCCEXParser::parseI(Print *stream, int16_t params, int16_t p[]) case 5: // add a position { Turntable *tto = Turntable::get(p[0]); - if (p[1] == HASH_KEYWORD_ADD) { + if (p[1] == "ADD"_hk) { // tto must exist, no more than 48 positions, angle 0 - 3600 if (!tto || p[2] > 48 || p[4] < 0 || p[4] > 3600) return false; tto->addPosition(p[2], p[3], p[4]); diff --git a/EXRAIL2Parser.cpp b/EXRAIL2Parser.cpp index d231342..99f0c37 100644 --- a/EXRAIL2Parser.cpp +++ b/EXRAIL2Parser.cpp @@ -28,25 +28,7 @@ #include "defines.h" #include "EXRAIL2.h" #include "DCC.h" -// Command parsing keywords -const int16_t HASH_KEYWORD_EXRAIL=15435; -const int16_t HASH_KEYWORD_ON = 2657; -const int16_t HASH_KEYWORD_START=23232; -const int16_t HASH_KEYWORD_RESERVE=11392; -const int16_t HASH_KEYWORD_FREE=-23052; -const int16_t HASH_KEYWORD_LATCH=1618; -const int16_t HASH_KEYWORD_UNLATCH=1353; -const int16_t HASH_KEYWORD_PAUSE=-4142; -const int16_t HASH_KEYWORD_RESUME=27609; -const int16_t HASH_KEYWORD_KILL=5218; -const int16_t HASH_KEYWORD_ALL=3457; -const int16_t HASH_KEYWORD_ROUTES=-3702; -const int16_t HASH_KEYWORD_RED=26099; -const int16_t HASH_KEYWORD_AMBER=18713; -const int16_t HASH_KEYWORD_GREEN=-31493; -const int16_t HASH_KEYWORD_A='A'; -const int16_t HASH_KEYWORD_M='M'; - +#include "KeywordHasher.h" // This filter intercepts <> commands to do the following: // - Implement RMFT specific commands/diagnostics @@ -58,8 +40,8 @@ void RMFT2::ComandFilter(Print * stream, byte & opcode, byte & paramCount, int16 switch(opcode) { case 'D': - if (p[0]==HASH_KEYWORD_EXRAIL) { // - diag = paramCount==2 && (p[1]==HASH_KEYWORD_ON || p[1]==1); + if (p[0]=="EXRAIL"_hk) { // + diag = paramCount==2 && (p[1]=="ON"_hk || p[1]==1); opcode=0; } break; @@ -125,7 +107,7 @@ void RMFT2::ComandFilter(Print * stream, byte & opcode, byte & paramCount, int16 case 'J': // throttle info commands if (paramCount<1) return; switch(p[0]) { - case HASH_KEYWORD_A: // returns automations/routes + case "A"_hk: // returns automations/routes if (paramCount==1) {// StringFormatter::send(stream, F("stream(stream); @@ -152,7 +134,7 @@ void RMFT2::ComandFilter(Print * stream, byte & opcode, byte & paramCount, int16 return; } break; - case HASH_KEYWORD_M: + case "M"_hk: // NOTE: we only need to handle valid calls here because // DCCEXParser has to have code to handle the cases where // exrail isnt involved anyway. @@ -236,13 +218,13 @@ bool RMFT2::parseSlash(Print * stream, byte & paramCount, int16_t p[]) { return true; } switch (p[0]) { - case HASH_KEYWORD_PAUSE: // + case "PAUSE"_hk: // if (paramCount!=1) return false; DCC::setThrottle(0,1,true); // pause all locos on the track pausingTask=(RMFT2 *)1; // Impossible task address return true; - case HASH_KEYWORD_RESUME: // + case "RESUME"_hk: // if (paramCount!=1) return false; pausingTask=NULL; { @@ -256,7 +238,7 @@ bool RMFT2::parseSlash(Print * stream, byte & paramCount, int16_t p[]) { return true; - case HASH_KEYWORD_START: // + case "START"_hk: // if (paramCount<2 || paramCount>3) return false; { int route=(paramCount==2) ? p[1] : p[2]; @@ -273,7 +255,7 @@ bool RMFT2::parseSlash(Print * stream, byte & paramCount, int16_t p[]) { } // check KILL ALL here, otherwise the next validation confuses ALL with a flag - if (p[0]==HASH_KEYWORD_KILL && p[1]==HASH_KEYWORD_ALL) { + if (p[0]=="KILL"_hk && p[1]=="ALL"_hk) { while (loopTask) loopTask->kill(F("KILL ALL")); // destructor changes loopTask return true; } @@ -282,7 +264,7 @@ bool RMFT2::parseSlash(Print * stream, byte & paramCount, int16_t p[]) { if (paramCount!=2 ) return false; switch (p[0]) { - case HASH_KEYWORD_KILL: // Kill taskid|ALL + case "KILL"_hk: // Kill taskid|ALL { if ( p[1]<0 || p[1]>=MAX_FLAGS) return false; RMFT2 * task=loopTask; @@ -297,27 +279,27 @@ bool RMFT2::parseSlash(Print * stream, byte & paramCount, int16_t p[]) { } return false; - case HASH_KEYWORD_RESERVE: // force reserve a section + case "RESERVE"_hk: // force reserve a section return setFlag(p[1],SECTION_FLAG); - case HASH_KEYWORD_FREE: // force free a section + case "FREE"_hk: // force free a section return setFlag(p[1],0,SECTION_FLAG); - case HASH_KEYWORD_LATCH: + case "LATCH"_hk: return setFlag(p[1], LATCH_FLAG); - case HASH_KEYWORD_UNLATCH: + case "UNLATCH"_hk: return setFlag(p[1], 0, LATCH_FLAG); - case HASH_KEYWORD_RED: + case "RED"_hk: doSignal(p[1],SIGNAL_RED); return true; - case HASH_KEYWORD_AMBER: + case "AMBER"_hk: doSignal(p[1],SIGNAL_AMBER); return true; - case HASH_KEYWORD_GREEN: + case "GREEN"_hk: doSignal(p[1],SIGNAL_GREEN); return true; diff --git a/KeywordHasher.h b/KeywordHasher.h new file mode 100644 index 0000000..d30f566 --- /dev/null +++ b/KeywordHasher.h @@ -0,0 +1,57 @@ +/* + * © 2024 Vincent Hamp and Chris Harlow + * All rights reserved. + * + * This file is part of CommandStation-EX + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * It is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with CommandStation. If not, see . + */ + + +/* Reader be aware: + This function implements the _hk data type so that a string keyword + is hashed to the same value as the DCCEXParser uses to hash incoming + keywords. + Thus "MAIN"_hk generates exactly the same run time vakue + as const int16_t HASH_KEYWORD_MAIN=11339 +*/ +#ifndef KeywordHAsher_h +#define KeywordHasher_h + +#include +constexpr uint16_t CompiletimeKeywordHasher(const char * sv, uint16_t running=0) { + return (*sv==0) ? running : CompiletimeKeywordHasher(sv+1, + (*sv >= '0' && *sv <= '9') + ? (10*running+*sv-'0') // Numeric hash + : ((running << 5) + running) ^ *sv + ); // +} + +constexpr int16_t operator""_hk(const char * keyword, size_t len) +{ + return (int16_t) CompiletimeKeywordHasher(keyword,len*0); +} + +/* Some historical values for testing: +const int16_t HASH_KEYWORD_MAIN = 11339; +const int16_t HASH_KEYWORD_SLOW = -17209; +const int16_t HASH_KEYWORD_SPEED28 = -17064; +const int16_t HASH_KEYWORD_SPEED128 = 25816; +*/ + +static_assert("MAIN"_hk == 11339); +static_assert("SLOW"_hk == -17209); +static_assert("SPEED28"_hk == -17064); +static_assert("SPEED128"_hk == 25816); +#endif \ No newline at end of file diff --git a/TrackManager.cpp b/TrackManager.cpp index 4a501a1..da96832 100644 --- a/TrackManager.cpp +++ b/TrackManager.cpp @@ -28,6 +28,7 @@ #include "DIAG.h" #include "CommandDistributor.h" #include "DCCEXParser.h" +#include "KeywordHasher.h" // Virtualised Motor shield multi-track hardware Interface #define FOR_EACH_TRACK(t) for (byte t=0;t<=lastTrack;t++) @@ -35,21 +36,6 @@ FOR_EACH_TRACK(t) \ if (track[t]->getMode()==findmode) \ track[t]->function; -#ifndef DISABLE_PROG -const int16_t HASH_KEYWORD_PROG = -29718; -#endif -const int16_t HASH_KEYWORD_MAIN = 11339; -const int16_t HASH_KEYWORD_OFF = 22479; -const int16_t HASH_KEYWORD_NONE = -26550; -const int16_t HASH_KEYWORD_DC = 2183; -const int16_t HASH_KEYWORD_DCX = 6463; // DC reversed polarity -const int16_t HASH_KEYWORD_EXT = 8201; // External DCC signal -const int16_t HASH_KEYWORD_A = 65; // parser makes single chars the ascii. -const int16_t HASH_KEYWORD_AUTO = -5457; -#ifdef BOOSTER_INPUT -const int16_t HASH_KEYWORD_BOOST = 11269; -#endif -const int16_t HASH_KEYWORD_INV = 11857; MotorDriver * TrackManager::track[MAX_TRACKS]; int16_t TrackManager::trackDCAddr[MAX_TRACKS]; @@ -362,38 +348,38 @@ bool TrackManager::parseEqualSign(Print *stream, int16_t params, int16_t p[]) } - p[0]-=HASH_KEYWORD_A; // convert A... to 0.... + p[0]-="A"_hk; // convert A... to 0.... if (params>1 && (p[0]<0 || p[0]>=MAX_TRACKS)) return false; - if (params==2 && p[1]==HASH_KEYWORD_MAIN) // <= id MAIN> + if (params==2 && p[1]=="MAIN"_hk) // <= id MAIN> return setTrackMode(p[0],TRACK_MODE_MAIN); #ifndef DISABLE_PROG - if (params==2 && p[1]==HASH_KEYWORD_PROG) // <= id PROG> + if (params==2 && p[1]=="PROG"_hk) // <= id PROG> return setTrackMode(p[0],TRACK_MODE_PROG); #endif - if (params==2 && (p[1]==HASH_KEYWORD_OFF || p[1]==HASH_KEYWORD_NONE)) // <= id OFF> <= id NONE> + if (params==2 && (p[1]=="OFF"_hk || p[1]=="NONE"_hk)) // <= id OFF> <= id NONE> return setTrackMode(p[0],TRACK_MODE_NONE); - if (params==2 && p[1]==HASH_KEYWORD_EXT) // <= id EXT> + if (params==2 && p[1]=="EXT"_hk) // <= id EXT> return setTrackMode(p[0],TRACK_MODE_EXT); #ifdef BOOSTER_INPUT - if (params==2 && p[1]==HASH_KEYWORD_BOOST) // <= id BOOST> + if (params==2 && p[1]=="BOOST"_hk) // <= id BOOST> return setTrackMode(p[0],TRACK_MODE_BOOST); #endif - if (params==2 && p[1]==HASH_KEYWORD_AUTO) // <= id AUTO> + if (params==2 && p[1]=="AUTO"_hk) // <= id AUTO> return setTrackMode(p[0], track[p[0]]->getMode() | TRACK_MODE_AUTOINV); - if (params==2 && p[1]==HASH_KEYWORD_INV) // <= id AUTO> + if (params==2 && p[1]=="INV"_hk) // <= id AUTO> return setTrackMode(p[0], track[p[0]]->getMode() | TRACK_MODE_INV); - if (params==3 && p[1]==HASH_KEYWORD_DC && p[2]>0) // <= id DC cab> + if (params==3 && p[1]=="DC"_hk && p[2]>0) // <= id DC cab> return setTrackMode(p[0],TRACK_MODE_DC,p[2]); - if (params==3 && p[1]==HASH_KEYWORD_DCX && p[2]>0) // <= id DCX cab> + if (params==3 && p[1]=="DCX"_hk && p[2]>0) // <= id DCX cab> return setTrackMode(p[0],TRACK_MODE_DC|TRACK_MODE_INV,p[2]); return false; diff --git a/version.h b/version.h index 3c33933..d849eae 100644 --- a/version.h +++ b/version.h @@ -3,7 +3,8 @@ #include "StringFormatter.h" -#define VERSION "5.2.22" +#define VERSION "5.2.23" +// 5.2.23 - KeywordHasher _hk (no functional change) // 5.2.22 - Bugfixes: Empty turnout descriptions ok; negative route numbers valid. // 5.2.21 - Add STARTUP_DELAY config option to delay CS bootup // 5.2.20 - Check return of Ethernet.begin()