mirror of
https://github.com/DCC-EX/CommandStation-EX.git
synced 2024-11-23 08:06:13 +01:00
Restructure to support multiple input streams
Preparation for Wifi without adding any Wifi specifics.
This commit is contained in:
parent
4d80152ad0
commit
aebc35b183
|
@ -17,6 +17,9 @@ void myCallback(int result) {
|
|||
DIAG(F("\n getting Loco Id callback result=%d"),result);
|
||||
}
|
||||
|
||||
DCCEXParser serialParser(Serial);;
|
||||
DCCEXParser wifiParser(Serial1);
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
DCC::begin();
|
||||
|
@ -31,5 +34,6 @@ void loop() {
|
|||
DCC::loop(); // required to keep locos running and check powwer
|
||||
|
||||
// This line passes input on Serial to the DCCEXParser
|
||||
StringParser::loop(Serial, DCCEXParser::parse);
|
||||
serialParser.loop();
|
||||
wifiParser.loop();
|
||||
}
|
||||
|
|
127
DCCEXParser.cpp
127
DCCEXParser.cpp
|
@ -1,4 +1,4 @@
|
|||
#include "StringParser.h"
|
||||
#include "StringFormatter.h"
|
||||
#include "DCCEXParser.h"
|
||||
#include "DCC.h"
|
||||
#include "DCCWaveform.h"
|
||||
|
@ -10,19 +10,92 @@
|
|||
|
||||
const char VERSION[]="99.666";
|
||||
|
||||
// This is a JMRI command parser
|
||||
int DCCEXParser::stashP[MAX_PARAMS];
|
||||
bool DCCEXParser::stashBusy;
|
||||
Stream & DCCEXParser::stashStream=Serial; // keep compiler happy but ovevride in constructor
|
||||
|
||||
|
||||
DCCEXParser::DCCEXParser(Stream & myStream) {
|
||||
stream=myStream;
|
||||
}
|
||||
|
||||
// This is a JMRI command parser, one instance per incoming stream
|
||||
// It doesnt know how the string got here, nor how it gets back.
|
||||
// It knows nothing about hardware or tracks... it just parses strings and
|
||||
// calls the corresponding DCC api.
|
||||
// Non-DCC things like turnouts, pins and sensors are handled in additional JMRI interface classes.
|
||||
|
||||
void DCCEXParser::loop() {
|
||||
while(stream.available()) {
|
||||
if (bufferLength==MAX_BUFFER) {
|
||||
bufferLength=0;
|
||||
inCommandPayload=false;
|
||||
}
|
||||
char ch = stream.read();
|
||||
if (ch == '<') {
|
||||
inCommandPayload = true;
|
||||
bufferLength=0;
|
||||
buffer[0]='\0';
|
||||
}
|
||||
else if (ch == '>') {
|
||||
buffer[bufferLength]='\0';
|
||||
parse(buffer);
|
||||
inCommandPayload = false;
|
||||
break;
|
||||
} else if(inCommandPayload) {
|
||||
buffer[bufferLength++]= ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int DCCEXParser::splitValues( int result[MAX_PARAMS]) {
|
||||
byte state=1;
|
||||
byte parameterCount=0;
|
||||
int runningValue=0;
|
||||
const char * remainingCmd=buffer+1; // skips the opcode
|
||||
bool signNegative=false;
|
||||
|
||||
// clear all parameters in case not enough found
|
||||
for (int i=0;i<MAX_PARAMS;i++) result[i]=0;
|
||||
|
||||
while(parameterCount<MAX_PARAMS) {
|
||||
char hot=*remainingCmd;
|
||||
|
||||
switch (state) {
|
||||
|
||||
case 1: // skipping spaces before a param
|
||||
if (hot==' ') break;
|
||||
if (hot == '\0' || hot=='>') return parameterCount;
|
||||
state=2;
|
||||
continue;
|
||||
|
||||
case 2: // checking sign
|
||||
signNegative=false;
|
||||
runningValue=0;
|
||||
state=3;
|
||||
if (hot!='-') continue;
|
||||
signNegative=true;
|
||||
break;
|
||||
case 3: // building a parameter
|
||||
if (hot>='0' && hot<='9') {
|
||||
runningValue=10*runningValue+(hot-'0');
|
||||
break;
|
||||
}
|
||||
result[parameterCount] = runningValue * (signNegative ?-1:1);
|
||||
parameterCount++;
|
||||
state=1;
|
||||
continue;
|
||||
}
|
||||
remainingCmd++;
|
||||
}
|
||||
return parameterCount;
|
||||
}
|
||||
|
||||
// See documentation on DCC class for info on this section
|
||||
void DCCEXParser::parse(Stream & stream,const char *com) {
|
||||
void DCCEXParser::parse(const char *com) {
|
||||
(void) EEPROM; // tell compiler not to warn thi is unused
|
||||
int p[MAX_PARAMS];
|
||||
int params=StringParser::parse(com+1,p,MAX_PARAMS);
|
||||
int params=splitValues(p);
|
||||
|
||||
|
||||
// Functions return from this switch if complete, break from switch implies error <X> to send
|
||||
|
@ -30,7 +103,7 @@ void DCCEXParser::parse(Stream & stream,const char *com) {
|
|||
|
||||
case 't': // THROTTLE <t REGISTER CAB SPEED DIRECTION>
|
||||
DCC::setThrottle(p[1],p[2],p[3]);
|
||||
StringParser::send(stream,F("<T %d %d %d>"), p[0], p[2],p[3]);
|
||||
StringFormatter::send(stream,F("<T %d %d %d>"), p[0], p[2],p[3]);
|
||||
return;
|
||||
|
||||
case 'f': // FUNCTION <f CAB BYTE1 [BYTE2]>
|
||||
|
@ -44,15 +117,15 @@ void DCCEXParser::parse(Stream & stream,const char *com) {
|
|||
return;
|
||||
|
||||
case 'T': // TURNOUT <T ...>
|
||||
if (parseT(stream,params,p)) return;
|
||||
if (parseT(params,p)) return;
|
||||
break;
|
||||
|
||||
case 'Z': // OUTPUT <Z ...>
|
||||
if (parseZ(stream,params,p)) return;
|
||||
if (parseZ(params,p)) return;
|
||||
break;
|
||||
|
||||
case 'S': // SENSOR <S ...>
|
||||
if (parseS(stream,params,p)) return;
|
||||
if (parseS(params,p)) return;
|
||||
break;
|
||||
|
||||
case 'w': // WRITE CV on MAIN <w CAB CV VALUE>
|
||||
|
@ -81,17 +154,17 @@ void DCCEXParser::parse(Stream & stream,const char *com) {
|
|||
case '1': // POWERON <1>
|
||||
DCCWaveform::mainTrack.setPowerMode(POWERMODE::ON);
|
||||
DCCWaveform::progTrack.setPowerMode(POWERMODE::ON);
|
||||
StringParser::send(stream,F("<p1>"));
|
||||
StringFormatter::send(stream,F("<p1>"));
|
||||
return;
|
||||
|
||||
case '0': // POWEROFF <0>
|
||||
DCCWaveform::mainTrack.setPowerMode(POWERMODE::OFF);
|
||||
DCCWaveform::progTrack.setPowerMode(POWERMODE::OFF);
|
||||
StringParser::send(stream,F("<p0>"));
|
||||
StringFormatter::send(stream,F("<p0>"));
|
||||
return;
|
||||
|
||||
case 'c': // READ CURRENT <c>
|
||||
StringParser::send(stream,F("<a %d>"), DCCWaveform::mainTrack.getLastCurrent());
|
||||
StringFormatter::send(stream,F("<a %d>"), DCCWaveform::mainTrack.getLastCurrent());
|
||||
return;
|
||||
|
||||
case 'Q': // SENSORS <Q>
|
||||
|
@ -99,7 +172,7 @@ void DCCEXParser::parse(Stream & stream,const char *com) {
|
|||
break;
|
||||
|
||||
case 's': // <s>
|
||||
StringParser::send(stream,F("<iDCC-Asbelos BASE STATION FOR ARDUINO / %s: V-%s %s/%s\n>"), BOARD_NAME, VERSION, __DATE__, __TIME__ );
|
||||
StringFormatter::send(stream,F("<iDCC-Asbelos BASE STATION FOR ARDUINO / %s: V-%s %s/%s\n>"), BOARD_NAME, VERSION, __DATE__, __TIME__ );
|
||||
// TODO send power status
|
||||
// TODO Send stats of speed reminders table
|
||||
// TODO send status of turnouts etc etc
|
||||
|
@ -107,16 +180,16 @@ void DCCEXParser::parse(Stream & stream,const char *com) {
|
|||
|
||||
case 'E': // STORE EPROM <E>
|
||||
EEStore::store();
|
||||
StringParser::send(stream,F("<e %d %d %d>"), EEStore::eeStore->data.nTurnouts, EEStore::eeStore->data.nSensors, EEStore::eeStore->data.nOutputs);
|
||||
StringFormatter::send(stream,F("<e %d %d %d>"), EEStore::eeStore->data.nTurnouts, EEStore::eeStore->data.nSensors, EEStore::eeStore->data.nOutputs);
|
||||
return;
|
||||
|
||||
case 'e': // CLEAR EPROM <e>
|
||||
EEStore::clear();
|
||||
StringParser::send(stream, F("<O>"));
|
||||
StringFormatter::send(stream, F("<O>"));
|
||||
return;
|
||||
|
||||
case ' ': // < >
|
||||
StringParser::send(stream,F("\n"));
|
||||
StringFormatter::send(stream,F("\n"));
|
||||
return;
|
||||
|
||||
default: //anything else will drop out to <X>
|
||||
|
@ -125,10 +198,10 @@ void DCCEXParser::parse(Stream & stream,const char *com) {
|
|||
} // end of opcode switch
|
||||
|
||||
// Any fallout here sends an <X>
|
||||
StringParser::send(stream, F("<X>"));
|
||||
StringFormatter::send(stream, F("<X>"));
|
||||
}
|
||||
|
||||
bool DCCEXParser::parseZ(Stream & stream, int params, int p[]){
|
||||
bool DCCEXParser::parseZ( int params, int p[]){
|
||||
|
||||
|
||||
switch (params) {
|
||||
|
@ -138,7 +211,7 @@ bool DCCEXParser::parseZ(Stream & stream, int params, int p[]){
|
|||
Output * o=Output::get(p[0]);
|
||||
if(o==NULL) return false;
|
||||
o->activate(p[1]);
|
||||
StringParser::send(stream,F("<Y %d %d>"), p[0],p[1]);
|
||||
StringFormatter::send(stream,F("<Y %d %d>"), p[0],p[1]);
|
||||
}
|
||||
return true;
|
||||
|
||||
|
@ -159,14 +232,14 @@ bool DCCEXParser::parseZ(Stream & stream, int params, int p[]){
|
|||
|
||||
|
||||
//===================================
|
||||
bool DCCEXParser::parseT(Stream & stream, int params, int p[]) {
|
||||
bool DCCEXParser::parseT( int params, int p[]) {
|
||||
switch(params){
|
||||
case 0: // <T>
|
||||
return (Turnout::showAll(stream)); break;
|
||||
|
||||
case 1: // <T id>
|
||||
if (!Turnout::remove(p[0])) return false;
|
||||
StringParser::send(stream,F("<O>"));
|
||||
StringFormatter::send(stream,F("<O>"));
|
||||
return true;
|
||||
|
||||
case 2: // <T id 0|1>
|
||||
|
@ -176,7 +249,7 @@ bool DCCEXParser::parseT(Stream & stream, int params, int p[]) {
|
|||
|
||||
case 3: // <T id addr subaddr>
|
||||
if (!Turnout::create(p[0],p[1],p[2])) return false;
|
||||
StringParser::send(stream,F("<O>"));
|
||||
StringFormatter::send(stream,F("<O>"));
|
||||
return true;
|
||||
|
||||
default:
|
||||
|
@ -184,7 +257,7 @@ bool DCCEXParser::parseT(Stream & stream, int params, int p[]) {
|
|||
}
|
||||
}
|
||||
|
||||
bool DCCEXParser::parseS(Stream & stream, int params, int p[]) {
|
||||
bool DCCEXParser::parseS( int params, int p[]) {
|
||||
|
||||
switch(params){
|
||||
|
||||
|
@ -206,10 +279,8 @@ bool DCCEXParser::parseS(Stream & stream, int params, int p[]) {
|
|||
return false;
|
||||
}
|
||||
|
||||
int DCCEXParser::stashP[MAX_PARAMS];
|
||||
bool DCCEXParser::stashBusy=false;
|
||||
Stream & DCCEXParser::stashStream=Serial; // only to keep compiler happy
|
||||
|
||||
// CALLBACKS must be static
|
||||
bool DCCEXParser::stashCallback(Stream & stream, int p[MAX_PARAMS]) {
|
||||
if (stashBusy) return false;
|
||||
stashBusy=true;
|
||||
|
@ -218,16 +289,16 @@ bool DCCEXParser::stashCallback(Stream & stream, int p[MAX_PARAMS]) {
|
|||
return true;
|
||||
}
|
||||
void DCCEXParser::callback_W(int result) {
|
||||
StringParser::send(stashStream,F("<r%d|%d|%d %d>"), stashP[2], stashP[3],stashP[0],result==1?stashP[1]:-1);
|
||||
StringFormatter::send(stashStream,F("<r%d|%d|%d %d>"), stashP[2], stashP[3],stashP[0],result==1?stashP[1]:-1);
|
||||
stashBusy=false;
|
||||
}
|
||||
|
||||
void DCCEXParser::callback_B(int result) {
|
||||
StringParser::send(stashStream,F("<r%d|%d|%d %d %d>"), stashP[3],stashP[4], stashP[0],stashP[1],result==1?stashP[2]:-1);
|
||||
StringFormatter::send(stashStream,F("<r%d|%d|%d %d %d>"), stashP[3],stashP[4], stashP[0],stashP[1],result==1?stashP[2]:-1);
|
||||
stashBusy=false;
|
||||
}
|
||||
void DCCEXParser::callback_R(int result) {
|
||||
StringParser::send(stashStream,F("<r%d|%d|%d %d>"),stashP[1],stashP[2],stashP[0],result);
|
||||
StringFormatter::send(stashStream,F("<r%d|%d|%d %d>"),stashP[1],stashP[2],stashP[0],result);
|
||||
stashBusy=false;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,19 +2,28 @@
|
|||
#define DCCEXParser_h
|
||||
struct DCCEXParser
|
||||
{
|
||||
static void parse(Stream & stream,const char * command);
|
||||
|
||||
DCCEXParser(Stream & myStream);
|
||||
void loop();
|
||||
private:
|
||||
|
||||
static const int MAX_PARAMS=10; // longest command sent in
|
||||
static const int MAX_BUFFER=50; // longest command sent in
|
||||
|
||||
Stream & stream;
|
||||
byte bufferLength=0;
|
||||
bool inCommandPayload=false;
|
||||
char buffer[MAX_BUFFER];
|
||||
void parse(const char * command);
|
||||
int splitValues( int result[MAX_PARAMS]);
|
||||
|
||||
bool parseT(int params, int p[]);
|
||||
bool parseZ(int params, int p[]);
|
||||
bool parseS( int params, int p[]);
|
||||
|
||||
static bool parseT(Stream & stream, int params, int p[]);
|
||||
static bool parseZ(Stream & stream, int params, int p[]);
|
||||
static bool parseS(Stream & stream, int params, int p[]);
|
||||
|
||||
static int stashP[MAX_PARAMS];
|
||||
static bool stashBusy;
|
||||
static Stream & stashStream;
|
||||
static int stashP[MAX_PARAMS];
|
||||
static bool stashCallback(Stream & stream, int p[MAX_PARAMS]);
|
||||
static void callback_W(int result);
|
||||
static void callback_B(int result);
|
||||
|
|
4
DIAG.h
4
DIAG.h
|
@ -1,9 +1,9 @@
|
|||
#ifndef DIAG_h
|
||||
#define DIAG_h
|
||||
|
||||
#include "StringParser.h"
|
||||
#include "StringFormatter.h"
|
||||
#ifndef DIAG_ENABLED
|
||||
#define DIAG_ENABLED true
|
||||
#endif
|
||||
#define DIAG if (DIAG_ENABLED) StringParser::print
|
||||
#define DIAG if (DIAG_ENABLED) StringFormatter::print
|
||||
#endif
|
||||
|
|
|
@ -65,7 +65,7 @@ the state of any outputs being monitored or controlled by a separate interface o
|
|||
|
||||
#include "Outputs.h"
|
||||
#include "EEStore.h"
|
||||
#include "StringParser.h"
|
||||
#include "StringFormatter.h"
|
||||
void Output::activate(int s){
|
||||
data.oStatus=(s>0); // if s>0, set status to active, else inactive
|
||||
digitalWrite(data.pin,data.oStatus ^ bitRead(data.iFlag,0)); // set state of output pin to HIGH or LOW depending on whether bit zero of iFlag is set to 0 (ACTIVE=HIGH) or 1 (ACTIVE=LOW)
|
||||
|
@ -106,14 +106,14 @@ bool Output::showAll(Stream & stream){
|
|||
bool gotone=false;
|
||||
for(Output * tt=firstOutput;tt!=NULL;tt=tt->nextOutput){
|
||||
gotone=true;
|
||||
StringParser::send(stream,F("<Y %d %d %d %d>"), tt->data.id, tt->data.pin, tt->data.iFlag, tt->data.oStatus);
|
||||
StringFormatter::send(stream,F("<Y %d %d %d %d>"), tt->data.id, tt->data.pin, tt->data.iFlag, tt->data.oStatus);
|
||||
}
|
||||
return gotone;
|
||||
}
|
||||
|
||||
void Output::show(Stream & stream){
|
||||
for(Output * tt=firstOutput;tt!=NULL;tt=tt->nextOutput){
|
||||
StringParser::send(stream,F("<Y %d %d>"), tt->data.id, tt->data.oStatus);
|
||||
StringFormatter::send(stream,F("<Y %d %d>"), tt->data.id, tt->data.oStatus);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
10
Sensors.cpp
10
Sensors.cpp
|
@ -50,7 +50,7 @@ decide to ignore the <q ID> return and only react to <Q ID> triggers.
|
|||
|
||||
#include "Sensors.h"
|
||||
#include "EEStore.h"
|
||||
#include "StringParser.h"
|
||||
#include "StringFormatter.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
@ -62,10 +62,10 @@ void Sensor::check(Stream & stream){
|
|||
|
||||
if(!tt->active && tt->signal<0.5){
|
||||
tt->active=true;
|
||||
StringParser::send(stream,F("<Q %d>"), tt->data.snum);
|
||||
StringFormatter::send(stream,F("<Q %d>"), tt->data.snum);
|
||||
} else if(tt->active && tt->signal>0.9){
|
||||
tt->active=false;
|
||||
StringParser::send(stream,F("<q %d>"), tt->data.snum);
|
||||
StringFormatter::send(stream,F("<q %d>"), tt->data.snum);
|
||||
}
|
||||
} // loop over all sensors
|
||||
|
||||
|
@ -131,7 +131,7 @@ bool Sensor::remove(int n){
|
|||
|
||||
void Sensor::show(Stream & stream){
|
||||
for(Sensor * tt=firstSensor;tt!=NULL;tt=tt->nextSensor){
|
||||
StringParser::send(stream, F("<Q %d %d %d>"), tt->data.snum, tt->data.pin, tt->data.pullUp);
|
||||
StringFormatter::send(stream, F("<Q %d %d %d>"), tt->data.snum, tt->data.pin, tt->data.pullUp);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -139,7 +139,7 @@ void Sensor::show(Stream & stream){
|
|||
|
||||
void Sensor::status(Stream & stream){
|
||||
for(Sensor * tt=firstSensor;tt!=NULL;tt=tt->nextSensor){
|
||||
StringParser::send(stream,F("<%s %d>"), tt->active?"Q":"q", tt->data.snum);
|
||||
StringFormatter::send(stream,F("<%s %d>"), tt->active?"Q":"q", tt->data.snum);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
40
StringFormatter.cpp
Normal file
40
StringFormatter.cpp
Normal file
|
@ -0,0 +1,40 @@
|
|||
#include "StringFormatter.h"
|
||||
#include <stdarg.h>
|
||||
|
||||
|
||||
void StringFormatter::print( const __FlashStringHelper* input...) {
|
||||
va_list args;
|
||||
va_start(args, input);
|
||||
send(Serial,input,args);
|
||||
}
|
||||
|
||||
void StringFormatter::send(Stream & stream, const __FlashStringHelper* input...) {
|
||||
va_list args;
|
||||
va_start(args, input);
|
||||
send(stream,input,args);
|
||||
}
|
||||
|
||||
void StringFormatter::send(Stream & stream,const __FlashStringHelper* format, va_list args) {
|
||||
|
||||
// thanks to Jan Turoň https://arduino.stackexchange.com/questions/56517/formatting-strings-in-arduino-for-output
|
||||
|
||||
char* flash=(char*)format;
|
||||
for(int i=0; ; ++i) {
|
||||
char c=pgm_read_byte_near(flash+i);
|
||||
if (c=='\0') return;
|
||||
if(c!='%') { stream.print(c); continue; }
|
||||
i++;
|
||||
c=pgm_read_byte_near(flash+i);
|
||||
switch(c) {
|
||||
case '%': stream.write('%'); break;
|
||||
case 's': stream.print(va_arg(args, char*)); break;
|
||||
case 'd': stream.print(va_arg(args, int), DEC); break;
|
||||
case 'b': stream.print(va_arg(args, int), BIN); break;
|
||||
case 'o': stream.print(va_arg(args, int), OCT); break;
|
||||
case 'x': stream.print(va_arg(args, int), HEX); break;
|
||||
case 'c': stream.write(va_arg(args, int)); break;
|
||||
case 'f': stream.print(va_arg(args, double), 2); break;
|
||||
}
|
||||
}
|
||||
va_end(args);
|
||||
}
|
|
@ -1,19 +1,15 @@
|
|||
#ifndef StringParser_h
|
||||
#define StringParser_h
|
||||
#ifndef StringFormatter_h
|
||||
#define StringFormatter_h
|
||||
#include <Arduino.h>
|
||||
class StringParser
|
||||
class StringFormatter
|
||||
{
|
||||
public:
|
||||
static void loop(Stream & stream, void (*callback)(Stream & stream, const char * data) );
|
||||
static int parse(const char * com, int result[], byte maxResults);
|
||||
static void print( const __FlashStringHelper* input...);
|
||||
static void send(Stream & serial, const __FlashStringHelper* input...);
|
||||
private:
|
||||
static void send(Stream & serial, const __FlashStringHelper* input,va_list args);
|
||||
|
||||
static byte bufferLength;
|
||||
static bool inCommandPayload;
|
||||
static const byte MAX_BUFFER=100;
|
||||
static char buffer[MAX_BUFFER];
|
||||
|
||||
};
|
||||
#endif
|
109
StringParser.cpp
109
StringParser.cpp
|
@ -1,109 +0,0 @@
|
|||
#include "StringParser.h"
|
||||
#include <stdarg.h>
|
||||
|
||||
byte StringParser::bufferLength=0;
|
||||
bool StringParser::inCommandPayload=false;
|
||||
char StringParser::buffer[MAX_BUFFER];
|
||||
|
||||
void StringParser::loop(Stream & stream, void (*callback)(Stream & stream, const char * data) ) {
|
||||
while(stream.available()) {
|
||||
if (bufferLength==MAX_BUFFER) {
|
||||
bufferLength=0;
|
||||
inCommandPayload=false;
|
||||
}
|
||||
char ch = stream.read();
|
||||
if (ch == '<') {
|
||||
inCommandPayload = true;
|
||||
bufferLength=0;
|
||||
buffer[0]='\0';
|
||||
}
|
||||
else if (ch == '>') {
|
||||
buffer[bufferLength]='\0';
|
||||
(*callback)(Serial, buffer);
|
||||
inCommandPayload = false;
|
||||
} else if(inCommandPayload) {
|
||||
buffer[bufferLength++]= ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
int StringParser::parse(const char * com, int result[], byte maxResults) {
|
||||
byte state=1;
|
||||
byte parameterCount=0;
|
||||
int runningValue=0;
|
||||
const char * remainingCmd=com; // skips the opcode
|
||||
bool signNegative=false;
|
||||
|
||||
// clear all parameters in case not enough found
|
||||
for (int i=0;i<maxResults;i++) result[i]=0;
|
||||
|
||||
while(parameterCount<maxResults) {
|
||||
char hot=*remainingCmd;
|
||||
|
||||
switch (state) {
|
||||
|
||||
case 1: // skipping spaces before a param
|
||||
if (hot==' ') break;
|
||||
if (hot == '\0' || hot=='>') return parameterCount;
|
||||
state=2;
|
||||
continue;
|
||||
|
||||
case 2: // checking sign
|
||||
signNegative=false;
|
||||
runningValue=0;
|
||||
state=3;
|
||||
if (hot!='-') continue;
|
||||
signNegative=true;
|
||||
break;
|
||||
case 3: // building a parameter
|
||||
if (hot>='0' && hot<='9') {
|
||||
runningValue=10*runningValue+(hot-'0');
|
||||
break;
|
||||
}
|
||||
result[parameterCount] = runningValue * (signNegative ?-1:1);
|
||||
parameterCount++;
|
||||
state=1;
|
||||
continue;
|
||||
}
|
||||
remainingCmd++;
|
||||
}
|
||||
return parameterCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void StringParser::print( const __FlashStringHelper* input...) {
|
||||
va_list args;
|
||||
va_start(args, input);
|
||||
send(Serial,input,args);
|
||||
}
|
||||
|
||||
void StringParser::send(Stream & stream, const __FlashStringHelper* input...) {
|
||||
va_list args;
|
||||
va_start(args, input);
|
||||
send(stream,input,args);
|
||||
}
|
||||
|
||||
void StringParser::send(Stream & stream,const __FlashStringHelper* format, va_list args) {
|
||||
|
||||
|
||||
// thanks to Jan Turoň https://arduino.stackexchange.com/questions/56517/formatting-strings-in-arduino-for-output
|
||||
|
||||
char* flash=(char*)format;
|
||||
for(int i=0; ; ++i) {
|
||||
char c=pgm_read_byte_near(flash+i);
|
||||
if (c=='\0') return;
|
||||
if(c!='%') { stream.print(c); continue; }
|
||||
i++;
|
||||
c=pgm_read_byte_near(flash+i);
|
||||
switch(c) {
|
||||
case '%': stream.print('%'); break;
|
||||
case 's': stream.print(va_arg(args, char*)); break;
|
||||
case 'd': stream.print(va_arg(args, int), DEC); break;
|
||||
case 'b': stream.print(va_arg(args, int), BIN); break;
|
||||
case 'o': stream.print(va_arg(args, int), OCT); break;
|
||||
case 'x': stream.print(va_arg(args, int), HEX); break;
|
||||
case 'f': stream.print(va_arg(args, double), 2); break;
|
||||
}
|
||||
}
|
||||
va_end(args);
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
#include "Turnouts.h"
|
||||
#include "EEStore.h"
|
||||
#include "StringParser.h"
|
||||
#include "StringFormatter.h"
|
||||
|
||||
bool Turnout::activate(int n,bool state){
|
||||
Turnout * tt=get(n);
|
||||
|
@ -43,7 +43,7 @@ bool Turnout::remove(int n){
|
|||
void Turnout::show(Stream & stream, int n){
|
||||
for(Turnout *tt=firstTurnout;tt!=NULL;tt=tt->nextTurnout){
|
||||
if (tt->data.id==n) {
|
||||
StringParser::send(stream,F("<H %d %d>"), tt->data.id, tt->data.tStatus);
|
||||
StringFormatter::send(stream,F("<H %d %d>"), tt->data.id, tt->data.tStatus);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ void Turnout::show(Stream & stream, int n){
|
|||
bool Turnout::showAll(Stream & stream){
|
||||
bool gotOne=false;
|
||||
for(Turnout * tt=firstTurnout;tt!=NULL;tt=tt->nextTurnout){
|
||||
StringParser::send(stream,F("<H %d %d %d %d>"), tt->data.id, tt->data.address, tt->data.subAddress, tt->data.tStatus);
|
||||
StringFormatter::send(stream,F("<H %d %d %d %d>"), tt->data.id, tt->data.address, tt->data.subAddress, tt->data.tStatus);
|
||||
gotOne=true;
|
||||
}
|
||||
return gotOne;
|
||||
|
|
Loading…
Reference in New Issue
Block a user