diff --git a/EXRAIL2MacroReset.h b/EXRAIL2MacroReset.h index df4e413..28f74c1 100644 --- a/EXRAIL2MacroReset.h +++ b/EXRAIL2MacroReset.h @@ -875,7 +875,7 @@ #define ONTHROW(turnout_id) /** * @def ONCHANGE(vpin) - * @brief Toratry encoder change starts task here (This is obscurely different from ONSENSOR which will be merged in a later release.) + * @brief Rotary encoder change starts task here (This is obscurely different from ONSENSOR which will be merged in a later release.) * @param vpin */ #define ONCHANGE(vpin) diff --git a/EXRAILAsserts.h b/EXRAILAsserts.h new file mode 100644 index 0000000..dc83c18 --- /dev/null +++ b/EXRAILAsserts.h @@ -0,0 +1,164 @@ +/* + * © 2020-2025 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 . + */ + +// This file checks the myAutomation for errors by generating a list of compile time asserts. + +// Assert Pass 1 Collect sequence numbers. +#include "EXRAIL2MacroReset.h" +#undef AUTOMATION +#define AUTOMATION(id, description) id, +#undef ROUTE +#define ROUTE(id, description) id, +#undef SEQUENCE +#define SEQUENCE(id) id, +constexpr int16_t compileTimeSequenceList[]={ + #include "myAutomation.h" + 0 + }; +constexpr int16_t stuffSize=sizeof(compileTimeSequenceList)/sizeof(int16_t) - 1; + + +// Compile time function to check for sequence number duplication +constexpr int16_t seqCount(const int16_t value, const int16_t pos=0, const int16_t count=0 ) { + return pos>=stuffSize? count : + seqCount(value,pos+1,count+((compileTimeSequenceList[pos]==value)?1:0)); +} + + +// Build a compile time blacklist of pin numbers. +// Includes those defined in defaults.h for the cpu (PIN_BLACKLIST) +// and cheats in the motor shield pins from config.h (MOTOR_SHIELD_TYPE) +// for reference the MotorDriver constructor is: +// MotorDriver(byte power_pin, byte signal_pin, byte signal_pin2, int8_t brake_pin, byte current_pin, +// float senseFactor, unsigned int tripMilliamps, byte faultPin); + +// create capture macros to reinterpret MOTOR_SHIELD_TYPE from configuration +#define new +#define MotorDriver(power_pin,signal_pin,signal_pin2, \ + brake_pin,current_pin,senseFactor,tripMilliamps,faultPin) \ + power_pin,signal_pin,signal_pin2,brake_pin,current_pin,faultPin +#ifndef PIN_BLACKLIST + #define PIN_BLACKLIST UNUSED_PIN +#endif +#define MDFURKLE(stuff) MDFURKLE2(stuff) +#define MDFURKLE2(description,...) REMOVE_TRAILING_COMMA(__VA_ARGS__) +#define REMOVE_TRAILING_COMMA(...) __VA_ARGS__ + + +constexpr int16_t compileTimePinBlackList[]={ + PIN_BLACKLIST, MDFURKLE(MOTOR_SHIELD_TYPE) + }; +constexpr int16_t pbSize=sizeof(compileTimePinBlackList)/sizeof(int16_t) - 1; + + +// remove capture macros +#undef new +#undef MotorDriver + +// Compile time function to check for dangerous pins. +constexpr bool unsafePin(const int16_t value, const uint16_t pos=0 ) { + return pos>=pbSize? false : + compileTimePinBlackList[pos]==value + || unsafePin(value,pos+1); +} + + +//pass 2 apply static asserts: +// check call and follows etc for existing sequence numbers +// check sequence numbers for duplicates +// check range on LATCH/UNLATCH +// check range on RESERVE/FREE +// check range on SPEED/FWD/REV +// check range on SET/RESET (pins that are not safe to use in EXRAIL) +// +// This pass generates no runtime data or code +#include "EXRAIL2MacroReset.h" +#undef ASPECT +#define ASPECT(address,value) static_assert(address <=2044, "invalid Address"); \ + static_assert(address>=-3, "Invalid value"); + +// check references to sequences/routes/automations +#undef CALL +#define CALL(id) static_assert(seqCount(id)>0,"Sequence not found"); +#undef FOLLOW +#define FOLLOW(id) static_assert(seqCount(id)>0,"Sequence not found"); +#undef START +#define START(id) static_assert(seqCount(id)>0,"Sequence not found"); +#undef SENDLOCO +#define SENDLOCO(cab,id) static_assert(seqCount(id)>0,"Sequence not found"); +#undef ROUTE_ACTIVE +#define ROUTE_ACTIVE(id) static_assert(seqCount(id)>0,"Route not found"); +#undef ROUTE_INACTIVE +#define ROUTE_INACTIVE(id) static_assert(seqCount(id)>0,"Route not found"); +#undef ROUTE_HIDDEN +#define ROUTE_HIDDEN(id) static_assert(seqCount(id)>0,"Route not found"); +#undef ROUTE_DISABLED +#define ROUTE_DISABLED(id) static_assert(seqCount(id)>0,"Route not found"); +#undef ROUTE_CAPTION +#define ROUTE_CAPTION(id,caption) static_assert(seqCount(id)>0,"Route not found"); + + +#undef LATCH +#define LATCH(id) static_assert(id>=0 && id=0 && id=0 && id=0 && id=0 && id=0 && speed<128,"Speed out of valid range 0-127"); +#undef FWD +#define FWD(speed) static_assert(speed>=0 && speed<128,"Speed out of valid range 0-127"); +#undef REV +#define REV(speed) static_assert(speed>=0 && speed<128,"Speed out of valid range 0-127"); + +// check duplicate sequences +#undef SEQUENCE +#define SEQUENCE(id) static_assert(seqCount(id)==1,"Duplicate ROUTE/AUTOMATION/SEQUENCE " #id); +#undef AUTOMATION +#define AUTOMATION(id,description) static_assert(seqCount(id)==1,"Duplicate ROUTE/AUTOMATION/SEQUENCE " #id); +#undef ROUTE +#define ROUTE(id,description) static_assert(seqCount(id)==1,"Duplicate ROUTE/AUTOMATION/SEQUENCE " #id); + +// check dangerous pins +#undef SET +#define SET(vpin) static_assert(!unsafePin(vpin),"SET(" #vpin ") not safe to use in EXRAIL"); +#undef RESET +#define RESET(vpin) static_assert(!unsafePin(vpin),"RESET(" #vpin ") not safe to use in EXRAIL"); +#undef BLINK +#define BLINK(vpin,onDuty,offDuty) static_assert(!unsafePin(vpin),"BLINK(" #vpin ") not safe to use in EXRAIL"); +#undef SIGNAL +#define SIGNAL(redpin,amberpin,greenpin) \ + static_assert(!unsafePin(redpin),"RED " #redpin " not safe to use in EXRAIL"); \ + static_assert(amberpin==0 ||!unsafePin(amberpin),"AMBER " #amberpin " not safe to use in EXRAIL"); \ + static_assert(!unsafePin(greenpin),"GREEN " #greenpin " not safe to use in EXRAIL"); +#undef SIGNALH +#define SIGNALH(redpin,amberpin,greenpin) \ + static_assert(!unsafePin(redpin),"RED " #redpin " not safe to use in EXRAIL"); \ + static_assert(amberpin==0 ||!unsafePin(amberpin),"AMBER " #amberpin " not safe to use in EXRAIL"); \ + static_assert(!unsafePin(greenpin),"GREEN " #greenpin " not safe to use in EXRAIL"); + +// and run the assert pass. +#include "myAutomation.h" diff --git a/EXRAILMacros.h b/EXRAILMacros.h index 11ffdc1..d672c24 100644 --- a/EXRAILMacros.h +++ b/EXRAILMacros.h @@ -86,72 +86,8 @@ #define ALIAS(name,value...) const int name= #value[0] ? value+0: -__COUNTER__ ; #include "myAutomation.h" -// Pass 1d Detect sequence duplicates. -// This pass generates no runtime data or code -#include "EXRAIL2MacroReset.h" -#undef AUTOMATION -#define AUTOMATION(id, description) id, -#undef ROUTE -#define ROUTE(id, description) id, -#undef SEQUENCE -#define SEQUENCE(id) id, -constexpr int16_t compileTimeSequenceList[]={ - #include "myAutomation.h" - 0 - }; -constexpr int16_t stuffSize=sizeof(compileTimeSequenceList)/sizeof(int16_t) - 1; - - -// Compile time function to check for sequence nos. -constexpr bool hasseq(const int16_t value, const int16_t pos=0 ) { - return pos>=stuffSize? false : - compileTimeSequenceList[pos]==value - || hasseq(value,pos+1); -} - -// Compile time function to check for duplicate sequence nos. -constexpr bool hasdup(const int16_t value, const int16_t pos ) { - return pos>=stuffSize? false : - compileTimeSequenceList[pos]==value - || hasseq(value,pos+1) - || hasdup(compileTimeSequenceList[pos],pos+1); -} - - -static_assert(!hasdup(compileTimeSequenceList[0],1),"Duplicate SEQUENCE/ROUTE/AUTOMATION detected"); - -//pass 1s static asserts to -// - check call and follows etc for existing sequence numbers -// - check range on LATCH/UNLATCH -// This pass generates no runtime data or code -#include "EXRAIL2MacroReset.h" -#undef ASPECT -#define ASPECT(address,value) static_assert(address <=2044, "invalid Address"); \ - static_assert(address>=-3, "Invalid value"); -#undef CALL -#define CALL(id) static_assert(hasseq(id),"Sequence not found"); -#undef FOLLOW -#define FOLLOW(id) static_assert(hasseq(id),"Sequence not found"); -#undef START -#define START(id) static_assert(hasseq(id),"Sequence not found"); -#undef SENDLOCO -#define SENDLOCO(cab,id) static_assert(hasseq(id),"Sequence not found"); -#undef LATCH -#define LATCH(id) static_assert(id>=0 && id=0 && id=0 && id=0 && id=0 && speed<128,"Speed out of valid range 0-127"); -#undef FWD -#define FWD(speed) static_assert(speed>=0 && speed<128,"Speed out of valid range 0-127"); -#undef REV -#define REV(speed) static_assert(speed>=0 && speed<128,"Speed out of valid range 0-127"); - -#include "myAutomation.h" +// Perform compile time asserts to check the script for errors +#include "EXRAILAsserts.h" // Pass 1g Implants STEALTH_GLOBAL in correct place #include "EXRAIL2MacroReset.h" @@ -607,9 +543,7 @@ int RMFT2::onLCCLookup[RMFT2::countLCCLookup]; #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), -#ifndef DISABLE_PROG #define POM(cv,value) OPCODE_POM,V(cv),OPCODE_PAD,V(value), -#endif #define POWEROFF OPCODE_POWEROFF,0,0, #define POWERON OPCODE_POWERON,0,0, #define PRINT(msg) OPCODE_PRINT,V(__COUNTER__ - StringMacroTracker2), diff --git a/version.h b/version.h index f32c980..d90b8ce 100644 --- a/version.h +++ b/version.h @@ -3,7 +3,8 @@ #include "StringFormatter.h" -#define VERSION "5.5.16" +#define VERSION "5.5.17" +// 5.5.17 - Extensive new compile time checking in exrail scripts (duplicate sequences etc), no function change // 5.5.16 - DOXYGEN comments in EXRAIL2MacroReset.h // 5.5.15 - Support for F429ZI/F329ZI // - Own mDNS support for (wired) Ethernet