Sensor::checkAll();
for(Sensor * tt=Sensor::firstSensor;tt!=NULL;tt=tt->nextSensor){
StringFormatter::send(stream,F("<%c %d>"), tt->active?'Q':'q', tt->data.snum);
}
return;
case 's': //
StringFormatter::send(stream,F(""),DCCWaveform::mainTrack.getPowerMode()==POWERMODE::ON );
StringFormatter::send(stream,F(""), VERSION, F(ARDUINO_TYPE), F(MOTOR_BOARD_TYPE), F(GITHUB_SHA));
// TODO Send stats of speed reminders table
// TODO send status of turnouts etc etc
return;
case 'E': // STORE EPROM
EEStore::store();
StringFormatter::send(stream,F(""), EEStore::eeStore->data.nTurnouts, EEStore::eeStore->data.nSensors, EEStore::eeStore->data.nOutputs);
return;
case 'e': // CLEAR EPROM
EEStore::clear();
StringFormatter::send(stream, F(""));
return;
case ' ': // < >
StringFormatter::send(stream,F("\n"));
return;
case 'D': // < >
if (parseD(stream,params,p)) return;
return;
case '#': // NUMBER OF LOCOSLOTS <#>
StringFormatter::send(stream,F("<# %d>"), MAX_LOCOS);
return;
case 'F': // New command to call the new Loco Function API
if (Diag::CMD) DIAG(F("Setting loco %d F%d %S"),p[0],p[1],p[2]?F("ON"):F("OFF"));
DCC::setFn(p[0],p[1],p[2]==1);
return;
case '+' : // Complex Wifi interface command (not usual parse)
WifiInterface::ATCommand(com);
return;
default: //anything else will diagnose and drop out to
DIAG(F("\nOpcode=%c params=%d\n"),opcode,params);
for (int i=0;i
StringFormatter::send(stream, F(""));
}
bool DCCEXParser::parseZ( Print * stream,int params, int p[]){
switch (params) {
case 2: //
{
Output * o=Output::get(p[0]);
if(o==NULL) return false;
o->activate(p[1]);
StringFormatter::send(stream,F(""), p[0],p[1]);
}
return true;
case 3: //
Output::create(p[0],p[1],p[2],1);
return true;
case 1: //
return Output::remove(p[0]);
case 0: //
{
bool gotone=false;
for(Output * tt=Output::firstOutput;tt!=NULL;tt=tt->nextOutput){
gotone=true;
StringFormatter::send(stream,F(""), tt->data.id, tt->data.pin, tt->data.iFlag, tt->data.oStatus);
}
return gotone;
}
default:
return false;
}
}
//===================================
bool DCCEXParser::parsef(Print * stream, int params, int p[]) {
// JMRI sends this info in DCC message format but it's not exactly
// convenient for other processing
if (params==2) {
byte groupcode=p[1] & 0xE0;
if (groupcode == 0x80) {
byte normalized= (p[1]<<1 & 0x1e ) | (p[1]>>4 & 0x01);
funcmap(p[0],normalized,0,4);
}
else if (groupcode == 0xC0) {
funcmap(p[0],p[1],5,8);
}
else if (groupcode == 0xA0) {
funcmap(p[0],p[1],9,12);
}
}
if (params==3) {
if (p[1]==222) funcmap(p[0],p[2],13,20);
else if (p[1]==223) funcmap(p[0],p[2],21,28);
}
(void)stream;// NO RESPONSE
return true;
}
void DCCEXParser::funcmap(int cab, byte value, byte fstart, byte fstop) {
for (int i=fstart;i<=fstop;i++) {
DCC::setFn(cab, i, value & 1);
value>>=1;
}
}
//===================================
bool DCCEXParser::parseT(Print * stream, int params, int p[]) {
switch(params){
case 0: // show all turnouts
{
bool gotOne=false;
for(Turnout *tt=Turnout::firstTurnout;tt!=NULL;tt=tt->nextTurnout){
gotOne=true;
StringFormatter::send(stream,F(""), tt->data.id, tt->data.tStatus & STATUS_ACTIVE);
}
return gotOne; // will if none found
}
case 1: // delete turnout
if (!Turnout::remove(p[0])) return false;
StringFormatter::send(stream,F(""));
return true;
case 2: // activate turnout
{
Turnout* tt=Turnout::get(p[0]);
if (!tt) return false;
tt->activate(p[1]);
StringFormatter::send(stream,F(""), tt->data.id, tt->data.tStatus & STATUS_ACTIVE);
}
return true;
case 3: // define turnout
if (!Turnout::create(p[0],p[1],p[2])) return false;
StringFormatter::send(stream,F(""));
return true;
default:
return false; // will
}
}
bool DCCEXParser::parseS( Print * stream,int params, int p[]) {
switch(params){
case 3: // create sensor. pullUp indicator (0=LOW/1=HIGH)
Sensor::create(p[0],p[1],p[2]);
return true;
case 1: // S id> remove sensor
if (Sensor::remove(p[0])) return true;
break;
case 0: // lit sensor states
for(Sensor * tt=Sensor::firstSensor;tt!=NULL;tt=tt->nextSensor){
StringFormatter::send(stream, F(""), tt->data.snum, tt->data.pin, tt->data.pullUp);
}
return true;
default: // invalid number of arguments
break;
}
return false;
}
bool DCCEXParser::parseD( Print * stream,int params, int 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
switch(p[0]){
case HASH_KEYWORD_CABS: //
DCC::displayCabList(stream);
return true;
case HASH_KEYWORD_RAM: //
StringFormatter::send(stream,F("\nFree memory=%d\n"),freeMemory());
break;
case HASH_KEYWORD_ACK: //
Diag::ACK=onOff;
return true;
case HASH_KEYWORD_CMD: //
Diag::CMD=onOff;
return true;
case HASH_KEYWORD_WIFI: //
Diag::WIFI=onOff;
return true;
case HASH_KEYWORD_WIT: //
Diag::WITHROTTLE=onOff;
return true;
case HASH_KEYWORD_DCC:
DCCWaveform::setDiagnosticSlowWave(params>=1 && p[1]==HASH_KEYWORD_SLOW);
return true;
default: // invalid/unknown
break;
}
return false;
}
// CALLBACKS must be static
bool DCCEXParser::stashCallback(Print * stream,int p[MAX_PARAMS]) {
if (stashBusy || asyncBanned) return false;
stashBusy=true;
stashStream=stream;
memcpy(stashP,p,MAX_PARAMS*sizeof(p[0]));
return true;
}
void DCCEXParser::callback_W(int result) {
StringFormatter::send(stashStream,F(""), stashP[2], stashP[3],stashP[0],result==1?stashP[1]:-1);
stashBusy=false;
}
void DCCEXParser::callback_B(int result) {
StringFormatter::send(stashStream,F(""), stashP[3],stashP[4], stashP[0],stashP[1],result==1?stashP[2]:-1);
stashBusy=false;
}
void DCCEXParser::callback_Vbit(int result) {
StringFormatter::send(stashStream,F(""), stashP[0], stashP[1],result);
stashBusy=false;
}
void DCCEXParser::callback_Vbyte(int result) {
StringFormatter::send(stashStream,F(""), stashP[0],result);
stashBusy=false;
}
void DCCEXParser::callback_R(int result) {
StringFormatter::send(stashStream,F(""),stashP[1],stashP[2],stashP[0],result);
stashBusy=false;
}
void DCCEXParser::callback_Rloco(int result) {
StringFormatter::send(stashStream,F(""),result);
stashBusy=false;
}