mirror of
https://github.com/DCC-EX/CommandStation-EX.git
synced 2024-11-27 01:56:14 +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);
|
DIAG(F("\n getting Loco Id callback result=%d"),result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DCCEXParser serialParser(Serial);;
|
||||||
|
DCCEXParser wifiParser(Serial1);
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
DCC::begin();
|
DCC::begin();
|
||||||
|
@ -31,5 +34,6 @@ void loop() {
|
||||||
DCC::loop(); // required to keep locos running and check powwer
|
DCC::loop(); // required to keep locos running and check powwer
|
||||||
|
|
||||||
// This line passes input on Serial to the DCCEXParser
|
// 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 "DCCEXParser.h"
|
||||||
#include "DCC.h"
|
#include "DCC.h"
|
||||||
#include "DCCWaveform.h"
|
#include "DCCWaveform.h"
|
||||||
|
@ -10,19 +10,92 @@
|
||||||
|
|
||||||
const char VERSION[]="99.666";
|
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 doesnt know how the string got here, nor how it gets back.
|
||||||
// It knows nothing about hardware or tracks... it just parses strings and
|
// It knows nothing about hardware or tracks... it just parses strings and
|
||||||
// calls the corresponding DCC api.
|
// calls the corresponding DCC api.
|
||||||
// Non-DCC things like turnouts, pins and sensors are handled in additional JMRI interface classes.
|
// 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
|
// 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
|
(void) EEPROM; // tell compiler not to warn thi is unused
|
||||||
int p[MAX_PARAMS];
|
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
|
// 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>
|
case 't': // THROTTLE <t REGISTER CAB SPEED DIRECTION>
|
||||||
DCC::setThrottle(p[1],p[2],p[3]);
|
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;
|
return;
|
||||||
|
|
||||||
case 'f': // FUNCTION <f CAB BYTE1 [BYTE2]>
|
case 'f': // FUNCTION <f CAB BYTE1 [BYTE2]>
|
||||||
|
@ -44,15 +117,15 @@ void DCCEXParser::parse(Stream & stream,const char *com) {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 'T': // TURNOUT <T ...>
|
case 'T': // TURNOUT <T ...>
|
||||||
if (parseT(stream,params,p)) return;
|
if (parseT(params,p)) return;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'Z': // OUTPUT <Z ...>
|
case 'Z': // OUTPUT <Z ...>
|
||||||
if (parseZ(stream,params,p)) return;
|
if (parseZ(params,p)) return;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'S': // SENSOR <S ...>
|
case 'S': // SENSOR <S ...>
|
||||||
if (parseS(stream,params,p)) return;
|
if (parseS(params,p)) return;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'w': // WRITE CV on MAIN <w CAB CV VALUE>
|
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>
|
case '1': // POWERON <1>
|
||||||
DCCWaveform::mainTrack.setPowerMode(POWERMODE::ON);
|
DCCWaveform::mainTrack.setPowerMode(POWERMODE::ON);
|
||||||
DCCWaveform::progTrack.setPowerMode(POWERMODE::ON);
|
DCCWaveform::progTrack.setPowerMode(POWERMODE::ON);
|
||||||
StringParser::send(stream,F("<p1>"));
|
StringFormatter::send(stream,F("<p1>"));
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case '0': // POWEROFF <0>
|
case '0': // POWEROFF <0>
|
||||||
DCCWaveform::mainTrack.setPowerMode(POWERMODE::OFF);
|
DCCWaveform::mainTrack.setPowerMode(POWERMODE::OFF);
|
||||||
DCCWaveform::progTrack.setPowerMode(POWERMODE::OFF);
|
DCCWaveform::progTrack.setPowerMode(POWERMODE::OFF);
|
||||||
StringParser::send(stream,F("<p0>"));
|
StringFormatter::send(stream,F("<p0>"));
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 'c': // READ CURRENT <c>
|
case 'c': // READ CURRENT <c>
|
||||||
StringParser::send(stream,F("<a %d>"), DCCWaveform::mainTrack.getLastCurrent());
|
StringFormatter::send(stream,F("<a %d>"), DCCWaveform::mainTrack.getLastCurrent());
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 'Q': // SENSORS <Q>
|
case 'Q': // SENSORS <Q>
|
||||||
|
@ -99,7 +172,7 @@ void DCCEXParser::parse(Stream & stream,const char *com) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 's': // <s>
|
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 power status
|
||||||
// TODO Send stats of speed reminders table
|
// TODO Send stats of speed reminders table
|
||||||
// TODO send status of turnouts etc etc
|
// TODO send status of turnouts etc etc
|
||||||
|
@ -107,16 +180,16 @@ void DCCEXParser::parse(Stream & stream,const char *com) {
|
||||||
|
|
||||||
case 'E': // STORE EPROM <E>
|
case 'E': // STORE EPROM <E>
|
||||||
EEStore::store();
|
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;
|
return;
|
||||||
|
|
||||||
case 'e': // CLEAR EPROM <e>
|
case 'e': // CLEAR EPROM <e>
|
||||||
EEStore::clear();
|
EEStore::clear();
|
||||||
StringParser::send(stream, F("<O>"));
|
StringFormatter::send(stream, F("<O>"));
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case ' ': // < >
|
case ' ': // < >
|
||||||
StringParser::send(stream,F("\n"));
|
StringFormatter::send(stream,F("\n"));
|
||||||
return;
|
return;
|
||||||
|
|
||||||
default: //anything else will drop out to <X>
|
default: //anything else will drop out to <X>
|
||||||
|
@ -125,10 +198,10 @@ void DCCEXParser::parse(Stream & stream,const char *com) {
|
||||||
} // end of opcode switch
|
} // end of opcode switch
|
||||||
|
|
||||||
// Any fallout here sends an <X>
|
// 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) {
|
switch (params) {
|
||||||
|
@ -138,7 +211,7 @@ bool DCCEXParser::parseZ(Stream & stream, int params, int p[]){
|
||||||
Output * o=Output::get(p[0]);
|
Output * o=Output::get(p[0]);
|
||||||
if(o==NULL) return false;
|
if(o==NULL) return false;
|
||||||
o->activate(p[1]);
|
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;
|
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){
|
switch(params){
|
||||||
case 0: // <T>
|
case 0: // <T>
|
||||||
return (Turnout::showAll(stream)); break;
|
return (Turnout::showAll(stream)); break;
|
||||||
|
|
||||||
case 1: // <T id>
|
case 1: // <T id>
|
||||||
if (!Turnout::remove(p[0])) return false;
|
if (!Turnout::remove(p[0])) return false;
|
||||||
StringParser::send(stream,F("<O>"));
|
StringFormatter::send(stream,F("<O>"));
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case 2: // <T id 0|1>
|
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>
|
case 3: // <T id addr subaddr>
|
||||||
if (!Turnout::create(p[0],p[1],p[2])) return false;
|
if (!Turnout::create(p[0],p[1],p[2])) return false;
|
||||||
StringParser::send(stream,F("<O>"));
|
StringFormatter::send(stream,F("<O>"));
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
default:
|
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){
|
switch(params){
|
||||||
|
|
||||||
|
@ -206,10 +279,8 @@ bool DCCEXParser::parseS(Stream & stream, int params, int p[]) {
|
||||||
return false;
|
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]) {
|
bool DCCEXParser::stashCallback(Stream & stream, int p[MAX_PARAMS]) {
|
||||||
if (stashBusy) return false;
|
if (stashBusy) return false;
|
||||||
stashBusy=true;
|
stashBusy=true;
|
||||||
|
@ -218,16 +289,16 @@ bool DCCEXParser::stashCallback(Stream & stream, int p[MAX_PARAMS]) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
void DCCEXParser::callback_W(int result) {
|
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;
|
stashBusy=false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DCCEXParser::callback_B(int result) {
|
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;
|
stashBusy=false;
|
||||||
}
|
}
|
||||||
void DCCEXParser::callback_R(int result) {
|
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;
|
stashBusy=false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,19 +2,28 @@
|
||||||
#define DCCEXParser_h
|
#define DCCEXParser_h
|
||||||
struct DCCEXParser
|
struct DCCEXParser
|
||||||
{
|
{
|
||||||
static void parse(Stream & stream,const char * command);
|
DCCEXParser(Stream & myStream);
|
||||||
|
void loop();
|
||||||
private:
|
private:
|
||||||
|
|
||||||
static const int MAX_PARAMS=10; // longest command sent in
|
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 bool stashBusy;
|
||||||
static Stream & stashStream;
|
static Stream & stashStream;
|
||||||
|
static int stashP[MAX_PARAMS];
|
||||||
static bool stashCallback(Stream & stream, int p[MAX_PARAMS]);
|
static bool stashCallback(Stream & stream, int p[MAX_PARAMS]);
|
||||||
static void callback_W(int result);
|
static void callback_W(int result);
|
||||||
static void callback_B(int result);
|
static void callback_B(int result);
|
||||||
|
|
4
DIAG.h
4
DIAG.h
|
@ -1,9 +1,9 @@
|
||||||
#ifndef DIAG_h
|
#ifndef DIAG_h
|
||||||
#define DIAG_h
|
#define DIAG_h
|
||||||
|
|
||||||
#include "StringParser.h"
|
#include "StringFormatter.h"
|
||||||
#ifndef DIAG_ENABLED
|
#ifndef DIAG_ENABLED
|
||||||
#define DIAG_ENABLED true
|
#define DIAG_ENABLED true
|
||||||
#endif
|
#endif
|
||||||
#define DIAG if (DIAG_ENABLED) StringParser::print
|
#define DIAG if (DIAG_ENABLED) StringFormatter::print
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -65,7 +65,7 @@ the state of any outputs being monitored or controlled by a separate interface o
|
||||||
|
|
||||||
#include "Outputs.h"
|
#include "Outputs.h"
|
||||||
#include "EEStore.h"
|
#include "EEStore.h"
|
||||||
#include "StringParser.h"
|
#include "StringFormatter.h"
|
||||||
void Output::activate(int s){
|
void Output::activate(int s){
|
||||||
data.oStatus=(s>0); // if s>0, set status to active, else inactive
|
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)
|
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;
|
bool gotone=false;
|
||||||
for(Output * tt=firstOutput;tt!=NULL;tt=tt->nextOutput){
|
for(Output * tt=firstOutput;tt!=NULL;tt=tt->nextOutput){
|
||||||
gotone=true;
|
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;
|
return gotone;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Output::show(Stream & stream){
|
void Output::show(Stream & stream){
|
||||||
for(Output * tt=firstOutput;tt!=NULL;tt=tt->nextOutput){
|
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 "Sensors.h"
|
||||||
#include "EEStore.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){
|
if(!tt->active && tt->signal<0.5){
|
||||||
tt->active=true;
|
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){
|
} else if(tt->active && tt->signal>0.9){
|
||||||
tt->active=false;
|
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
|
} // loop over all sensors
|
||||||
|
|
||||||
|
@ -131,7 +131,7 @@ bool Sensor::remove(int n){
|
||||||
|
|
||||||
void Sensor::show(Stream & stream){
|
void Sensor::show(Stream & stream){
|
||||||
for(Sensor * tt=firstSensor;tt!=NULL;tt=tt->nextSensor){
|
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){
|
void Sensor::status(Stream & stream){
|
||||||
for(Sensor * tt=firstSensor;tt!=NULL;tt=tt->nextSensor){
|
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
|
#ifndef StringFormatter_h
|
||||||
#define StringParser_h
|
#define StringFormatter_h
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
class StringParser
|
class StringFormatter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static void loop(Stream & stream, void (*callback)(Stream & stream, const char * data) );
|
|
||||||
static int parse(const char * com, int result[], byte maxResults);
|
static int parse(const char * com, int result[], byte maxResults);
|
||||||
static void print( const __FlashStringHelper* input...);
|
static void print( const __FlashStringHelper* input...);
|
||||||
static void send(Stream & serial, const __FlashStringHelper* input...);
|
static void send(Stream & serial, const __FlashStringHelper* input...);
|
||||||
private:
|
private:
|
||||||
static void send(Stream & serial, const __FlashStringHelper* input,va_list args);
|
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
|
#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 "Turnouts.h"
|
||||||
#include "EEStore.h"
|
#include "EEStore.h"
|
||||||
#include "StringParser.h"
|
#include "StringFormatter.h"
|
||||||
|
|
||||||
bool Turnout::activate(int n,bool state){
|
bool Turnout::activate(int n,bool state){
|
||||||
Turnout * tt=get(n);
|
Turnout * tt=get(n);
|
||||||
|
@ -43,7 +43,7 @@ bool Turnout::remove(int n){
|
||||||
void Turnout::show(Stream & stream, int n){
|
void Turnout::show(Stream & stream, int n){
|
||||||
for(Turnout *tt=firstTurnout;tt!=NULL;tt=tt->nextTurnout){
|
for(Turnout *tt=firstTurnout;tt!=NULL;tt=tt->nextTurnout){
|
||||||
if (tt->data.id==n) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,7 @@ void Turnout::show(Stream & stream, int n){
|
||||||
bool Turnout::showAll(Stream & stream){
|
bool Turnout::showAll(Stream & stream){
|
||||||
bool gotOne=false;
|
bool gotOne=false;
|
||||||
for(Turnout * tt=firstTurnout;tt!=NULL;tt=tt->nextTurnout){
|
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;
|
gotOne=true;
|
||||||
}
|
}
|
||||||
return gotOne;
|
return gotOne;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user