1
0
mirror of https://github.com/DCC-EX/CommandStation-EX.git synced 2025-04-15 09:50:11 +02:00

Automatic value checks

This commit is contained in:
Asbelos 2025-04-06 13:14:52 +01:00
parent 502ba7a653
commit 1bcc2678c2
2 changed files with 72 additions and 57 deletions

View File

@ -115,11 +115,7 @@ The REPLY( format, ...) macro sends a formatted string to the stream.
These macros are included into the DCCEXParser::execute function so
stream, ringStream and other DCCEXParser variables are available in context. */
// helper macro to check track letter
#define CHECKTRACK CHECK(track>='A' && track<='H', Invalid track A..H)
#define CHECKCV(cv) CHECK(cv>0 && cv<=255, Invalid cv 1..255)
#define CHECKCVVALUE(value) CHECK(value>=0 && value<=255, Invalid cv value 0..255)
ZZBEGIN
ZZ(#) // Request number of simultaneously supported locos
@ -127,7 +123,6 @@ ZZ(#) // Request number of simultaneously supported locos
ZZ(!) // Emergency stop all locos
DCC::estopAll();
ZZ(t,loco) // Request loco status
CHECK(loco>0)
CommandDistributor::broadcastLoco(DCC::lookupSpeedTable(loco,false));
ZZ(t,loco,tspeed,direction) // Set throttle speed(0..127) and direction (0=reverse, 1=fwd)
CHECK(setThrottle(loco,tspeed,direction))
@ -468,9 +463,7 @@ ZZ(1,JOIN) // JOIN prog track to MAIN and power
TrackManager::setJoin(true); TrackManager::setTrackPower(TRACK_MODE_MAIN|TRACK_MODE_PROG, POWERMODE::ON);
#endif
ZZ(1,track) // Power on given track
CHECKTRACK
TrackManager::setTrackPower(POWERMODE::ON, (byte)track-'A');
ZZ(0) // Power off all tracks
TrackManager::setJoin(false);
TrackManager::setTrackPower(TRACK_ALL, POWERMODE::OFF);
@ -483,7 +476,6 @@ ZZ(0,PROG) // Power off PROG track
// todo move to TrackManager Prog track boost mode will not outlive prog track off
TrackManager::setTrackPower(TRACK_MODE_PROG, POWERMODE::OFF);
ZZ(0,track) // Power off given track
CHECKTRACK
TrackManager::setJoin(false);
TrackManager::setTrackPower(POWERMODE::OFF, (byte)track-'a');
@ -504,16 +496,13 @@ ZZ(A,address,value) // Send DCC extended accessory (Aspect) command
DCC::setExtendedAccessory(address,value);
ZZ(w,loco,cv,value) // POM write cv on main track
CHECKCV(cv) CHECKCVVALUE(value)
DCC::writeCVByteMain(loco,cv,value);
ZZ(r,loco,cv) // POM read cv on main track
CHECKCV(cv)
CHECK(DCCWaveform::isRailcom(),Railcom not active)
EXPECT_CALLBACK
DCC::readCVByteMain(loco,cv,callback_r);
ZZ(b,loco,cv,bit,value) // POM write cv bit on main track
CHECKCV(cv) CHECK(value==0 || value==1) CHECK(bit>=0 && bit<=7,Invalid bit 0..7)
DCC::writeCVBitMain(loco,cv,bit,value);
ZZ(b,loco,cv,bit,bitvalue) // POM write cv bit on main track
DCC::writeCVBitMain(loco,cv,bit,bitvalue);
ZZ(m,LINEAR) // Set Momentum algorithm to linear acceleration
DCC::linearAcceleration=true;
@ -526,35 +515,26 @@ ZZ(m,loco,accelerating,braking) // set momentum for loco
// todo reorder for more sensible doco.
ZZ(W,cv,value,ignore1,ignore2) // (Deprecated) Write cv value on PROG track
CHECKCV(cv) CHECKCVVALUE(value)
EXPECT_CALLBACK DCC::writeCVByte(cv,value, callback_W);
ZZ(W,cab) // Write loco address on PROG track
EXPECT_CALLBACK DCC::setLocoId(cab,callback_Wloco);
ZZ(W,CONSIST,cab,REVERSE) // Write consist address and reverse flag on PROG track
EXPECT_CALLBACK DCC::setConsistId(cab,true,callback_Wconsist);
ZZ(W,CONSIST,cab) // write consist address on PROG track
EXPECT_CALLBACK DCC::setConsistId(cab,false,callback_Wconsist);
ZZ(W,loco) // Write loco address on PROG track
EXPECT_CALLBACK DCC::setLocoId(loco,callback_Wloco);
ZZ(W,CONSIST,loco,REVERSE) // Write consist address and reverse flag on PROG track
EXPECT_CALLBACK DCC::setConsistId(loco,true,callback_Wconsist);
ZZ(W,CONSIST,loco) // write consist address on PROG track
EXPECT_CALLBACK DCC::setConsistId(loco,false,callback_Wconsist);
ZZ(W,cv,value) // Write cv value on PROG track
CHECKCV(cv) CHECKCVVALUE(value)
EXPECT_CALLBACK DCC::writeCVByte(cv,value, callback_W);
ZZ(W,cv,value,bit) // Write cv bit on prog track
CHECKCV(cv) CHECK(value==0 || value==1) CHECK(bit>=0 && bit<=7,Invalid bit 0..7)
EXPECT_CALLBACK DCC::writeCVBit(cv,value,bit,callback_W);
ZZ(W,cv,bitvalue,bit) // Write cv bit on prog track
EXPECT_CALLBACK DCC::writeCVBit(cv,bitvalue,bit,callback_W);
ZZ(V,cv,value) // Fast read cv with expected value
CHECKCV(cv) CHECKCVVALUE(value)
EXPECT_CALLBACK DCC::verifyCVByte(cv,value, callback_Vbyte);
ZZ(V,cv,bit,value) // Fast read bit with expected value
CHECKCV(cv) CHECK(value==0 || value==1) CHECK(bit>=0 && bit<=7,Invalid bit 0..7)
EXPECT_CALLBACK DCC::verifyCVBit(cv,bit,value,callback_Vbit);
ZZ(B,cv,bit,value) // Write cv bit
CHECKCV(cv) CHECK(value==0 || value==1) CHECK(bit>=0 && bit<=7,Invalid bit 0..7)
EXPECT_CALLBACK DCC::writeCVBit(cv,bit,value,callback_B);
ZZ(R,cv,ignore1,ignore2) // (Deprecated) read cv
CHECKCV(cv)
ZZ(V,cv,bit,bitvalue) // Fast read bit with expected value
EXPECT_CALLBACK DCC::verifyCVBit(cv,bit,bitvalue,callback_Vbit);
ZZ(B,cv,bit,bitvalue) // Write cv bit
EXPECT_CALLBACK DCC::writeCVBit(cv,bit,bitvalue,callback_B);
ZZ(R,cv,ignore1,ignore2) // (Deprecated) read cv value on PROG track
EXPECT_CALLBACK DCC::readCV(cv,callback_R);
ZZ(R,cv) // Read cv
CHECKCV(cv)
EXPECT_CALLBACK DCC::verifyCVByte(cv, 0, callback_Vbyte);
ZZ(R) // Read driveable loco id (may be long, short or consist)
EXPECT_CALLBACK DCC::getLocoId(callback_Rloco);
@ -568,10 +548,10 @@ ZZ(-) // Clear loco state and reminder table
DCC::forgetAllLocos();
ZZ(-,loco) // remove loco state amnd reminders
DCC::forgetLoco(loco);
ZZ(F,loco,DCCFREQ,value) // Set DC frequencey for loco
CHECK(value>=0 && value<=3) DCC::setDCFreq(loco,value);
ZZ(F,loco,function,value) // Set loco function ON/OFF
CHECK(value==0 || value==1) DCC::setFn(loco,function,value);
ZZ(F,loco,DCCFREQ,freqvalue) // Set DC frequencey for loco
CHECK(freqvalue>=0 && freqvalue<=3) DCC::setDCFreq(loco,freqvalue);
ZZ(F,loco,function,fvalue) // Set loco function ON/OFF
CHECK(fvalue==0 || fvalue==1) DCC::setFn(loco,function,fvalue);
// ZZ(M,ignore,d0,d1,d2,d3,d4,d5) // Send up to 5 byte DCC packet on MAIN track (all d values in hex)
ZZ_nodoc(M,ignore,d0,d1,d2,d3,d4,d5) byte packet[]={(byte)d0,(byte)d1,(byte)d2,(byte)d3,(byte)d4,(byte)d5}; DCCWaveform::mainTrack.schedulePacket(packet,sizeof(packet),3);
@ -620,34 +600,34 @@ ZZ(J,P,id) // list turntable positions
ZZ(=) // list track manager states
TrackManager::list(stream);
ZZ(=,track,MAIN) // Set track to MAIN
CHECKTRACK CHECK(TrackManager::setTrackMode(track,TRACK_MODE_MAIN))
CHECK(TrackManager::setTrackMode(track,TRACK_MODE_MAIN))
ZZ(=,track,MAIN_INV) // Set track to MAIN inverted polatity
CHECKTRACK CHECK(TrackManager::setTrackMode(track,TRACK_MODE_MAIN_INV))
CHECK(TrackManager::setTrackMode(track,TRACK_MODE_MAIN_INV))
ZZ(=,track,MAIN_AUTO) // Set track to MAIN with auto reversing
CHECKTRACK CHECK(TrackManager::setTrackMode(track,TRACK_MODE_MAIN_AUTO))
CHECK(TrackManager::setTrackMode(track,TRACK_MODE_MAIN_AUTO))
ZZ(=,track,PROG) // Set track to PROG
CHECKTRACK CHECK(TrackManager::setTrackMode(track,TRACK_MODE_PROG))
CHECK(TrackManager::setTrackMode(track,TRACK_MODE_PROG))
ZZ(=,track,OFF) // Set track power OFF
CHECKTRACK CHECK(TrackManager::setTrackMode(track,TRACK_MODE_NONE))
CHECK(TrackManager::setTrackMode(track,TRACK_MODE_NONE))
ZZ(=,track,NONE) // Set track no output
CHECKTRACK CHECK(TrackManager::setTrackMode(track,TRACK_MODE_NONE))
CHECK(TrackManager::setTrackMode(track,TRACK_MODE_NONE))
ZZ(=,track,EXT) // Set track to use external sync
CHECKTRACK CHECK(TrackManager::setTrackMode(track,TRACK_MODE_EXT))
CHECK(TrackManager::setTrackMode(track,TRACK_MODE_EXT))
#ifdef BOOSTER_INPUT
ZZ_nodoc(=,track,BOOST) CHECKTRACK CHECK(TrackManager::setTrackMode(track,TRACK_MODE_BOOST))
ZZ_nodoc(=,track,BOOST_INV) CHECKTRACK CHECK(TrackManager::setTrackMode(track,TRACK_MODE_BOOST_INV))
ZZ_nodoc(=,track,BOOST_AUTO) CHECKTRACK) CHECK(TrackManager::setTrackMode(track,TRACK_MODE_BOOST_AUTO))
ZZ_nodoc(=,track,BOOST) CHECK(TrackManager::setTrackMode(track,TRACK_MODE_BOOST))
ZZ_nodoc(=,track,BOOST_INV) CHECK(TrackManager::setTrackMode(track,TRACK_MODE_BOOST_INV))
ZZ_nodoc(=,track,BOOST_AUTO) CHECK(TrackManager::setTrackMode(track,TRACK_MODE_BOOST_AUTO))
#endif
ZZ(=,track,AUTO) // Update track to auto reverse
CHECKTRACK CHECK(TrackManager::orTrackMode(track, TRACK_MODIFIER_AUTO))
CHECK(TrackManager::orTrackMode(track, TRACK_MODIFIER_AUTO))
ZZ(=,track,INV) // Update track to inverse polarity
CHECKTRACK CHECK(TrackManager::orTrackMode(track, TRACK_MODIFIER_INV))
CHECK(TrackManager::orTrackMode(track, TRACK_MODIFIER_INV))
ZZ(=,track,DC,locoid) // Set track to DC
CHECKTRACK CHECK(TrackManager::setTrackMode(track, TRACK_MODE_DC, locoid))
CHECK(TrackManager::setTrackMode(track, TRACK_MODE_DC, locoid))
ZZ(=,track,DC_INV,locoid) // Set track to DC with inverted polarity
CHECKTRACK CHECK(TrackManager::setTrackMode(track, TRACK_MODE_DC_INV, locoid))
CHECK(TrackManager::setTrackMode(track, TRACK_MODE_DC_INV, locoid))
ZZ(=,track,DCX,locoid) // Set track to DC with inverted polarity
CHECKTRACK CHECK(TrackManager::setTrackMode(track, TRACK_MODE_DC_INV, locoid))
CHECK(TrackManager::setTrackMode(track, TRACK_MODE_DC_INV, locoid))
ZZEND

View File

@ -24,14 +24,49 @@
#define Z8(op,_1,_2,_3,_4,_5,_6,_7) ZPREP(op,7) ZZZ(0,_1) ZZZ(1,_2) ZZZ(2,_3) ZZZ(3,_4) ZZZ(4,_5) ZZZ(5,_6) ZZZ(6,_7)
#define ZRIP(count) CONCAT(Z,count)
#define ZZ(...) ZRIP(FOR_EACH_NARG(__VA_ARGS__))(__VA_ARGS__) DCCEXParser::matchedCommandFormat = F( #__VA_ARGS__);
#define ZC1(op)
#define ZC2(op,_1) ZZCHK(0,_1)
#define ZC3(op,_1,_2) ZZCHK(0,_1) ZZCHK(1,_2)
#define ZC4(op,_1,_2,_3) ZZCHK(0,_1) ZZCHK(1,_2) ZZCHK(2,_3)
#define ZC5(op,_1,_2,_3,_4) ZZCHK(0,_1) ZZCHK(1,_2) ZZCHK(2,_3) ZZCHK(3,_4)
#define ZC6(op,_1,_2,_3,_4,_5) ZZCHK(0,_1) ZZCHK(1,_2) ZZCHK(2,_3) ZZCHK(3,_4) ZZCHK(4,_5)
#define ZC7(op,_1,_2,_3,_4,_5,_6) ZZCHK(0,_1) ZZCHK(1,_2) ZZCHK(2,_3) ZZCHK(3,_4) ZZCHK(4,_5) ZZCHK(5,_6)
#define ZC8(op,_1,_2,_3,_4,_5,_6,_7) ZZCHK(0,_1) ZZCHK(1,_2) ZZCHK(2,_3) ZZCHK(3,_4) ZZCHK(4,_5) ZZCHK(5,_6) ZZCHK(6,_7)
#define ZCRIP(count) CONCAT(ZC,count)
#define ZZ(...) \
ZRIP(FOR_EACH_NARG(__VA_ARGS__))(__VA_ARGS__) \
DCCEXParser::matchedCommandFormat = F( #__VA_ARGS__); \
ZCRIP(FOR_EACH_NARG(__VA_ARGS__))(__VA_ARGS__)
#define ZZBEGIN if (false) {
#define ZZEND return true; } return false;
//#define CHECK(x) if (!(x)) { DCCEXParser::checkFailedFormat=F(#x); return false;}
#define CHECK(x,...) if (!(x)) { DCCEXParser::checkFailedFormat=#__VA_ARGS__[0]?F(#__VA_ARGS__):F(#x); return false;}
#define REPLY(format,...) StringFormatter::send(stream,F(format), ##__VA_ARGS__);
#define EXPECT_CALLBACK CHECK(stashCallback(stream, p, ringStream))
// helper macro to hide command from documentation extractor
#define ZZ_nodoc ZZ
#define ZCHECK(_checkname,_index,_pname,_min,_max) \
if (CONCAT(#_pname,_hk) == CONCAT(#_checkname,_hk) \
&& (p[_index]<_min || p[_index]>_max)) CHECK(false,_checkname _min .. _max)
// Automatic range checks based on name of inserted parameter
#define ZZCHK(_index,_pname)\
ZCHECK(loco,_index,_pname,0,10239) \
ZCHECK(track,_index,_pname,'A','H') \
ZCHECK(cv,_index,_pname,1,255) \
ZCHECK(value,_index,_pname,0,255) \
ZCHECK(bit,_index,_pname,0,7) \
ZCHECK(bitvalue,_index,_pname,0,1) \
ZCHECK(crapvalue,_index,_pname,99,100) \