diff --git a/CommandStation-EX.ino b/CommandStation-EX.ino index 551c44f..21487f9 100644 --- a/CommandStation-EX.ino +++ b/CommandStation-EX.ino @@ -29,16 +29,23 @@ int ramLowWatermark = 32767; // This figure gets overwritten dynamically in loop() #endif +#if defined(ARDUINO_ARCH_MEGAAVR) +#include +#endif + + + + //////////////////////////////////////////////////////////////// // // Enables an I2C 2x24 or 4x24 LCD Screen -#ifdef ENABLE_LCD +#if ENABLE_LCD bool lcdEnabled = false; - #if defined(LIB_TYPE_PCF8574) - LiquidCrystal_PCF8574 lcdDisplay(LCD_ADDRESS); - #elif defined(LIB_TYPE_I2C) - LiquidCrystal_I2C lcdDisplay = LiquidCrystal_I2C(LCD_ADDRESS, LCD_COLUMNS, LCD_LINES); - #endif +#if defined(LIB_TYPE_PCF8574) +LiquidCrystal_PCF8574 lcdDisplay(LCD_ADDRESS); +#elif defined(LIB_TYPE_I2C) +LiquidCrystal_I2C lcdDisplay = LiquidCrystal_I2C(LCD_ADDRESS, LCD_COLUMNS, LCD_LINES); +#endif #endif // this code is here to demonstrate use of the DCC API and other techniques @@ -109,15 +116,16 @@ DCCEXParser serialParser; void setup() { - //////////////////////////////////////////// - // - // More display stuff. Need to put this in a .h file and make - // it a class - #ifdef ENABLE_LCD +//////////////////////////////////////////// +// +// More display stuff. Need to put this in a .h file and make +// it a class +#if ENABLE_LCD Wire.begin(); // Check that we can find the LCD by its address before attempting to use it. Wire.beginTransmission(LCD_ADDRESS); - if(Wire.endTransmission() == 0) { + if (Wire.endTransmission() == 0) + { lcdEnabled = true; lcdDisplay.begin(LCD_COLUMNS, LCD_LINES); lcdDisplay.setBacklight(255); @@ -126,15 +134,15 @@ void setup() lcdDisplay.print("DCC++ EX v"); lcdDisplay.print(VERSION); lcdDisplay.setCursor(0, 1); - #if COMM_INTERFACE >= 1 +#if COMM_INTERFACE >= 1 lcdDisplay.print("IP: PENDING"); - #else +#else lcdDisplay.print("SERIAL: READY"); - #endif - #if LCD_LINES > 2 - lcdDisplay.setCursor(0, 3); - lcdDisplay.print("TRACK POWER: OFF"); - #endif +#endif +#if LCD_LINES > 2 + lcdDisplay.setCursor(0, 3); + lcdDisplay.print("TRACK POWER: OFF"); +#endif } #endif diff --git a/DCC.h b/DCC.h index 9c5be1e..1e1058b 100644 --- a/DCC.h +++ b/DCC.h @@ -24,149 +24,150 @@ typedef void (*ACK_CALLBACK)(int result); -enum ackOp { // Program opcodes for the ack Manager -BASELINE, // ensure enough resets sent before starting and obtain baseline current -W0,W1, // issue write bit (0..1) packet -WB, // issue write byte packet -VB, // Issue validate Byte packet -V0, // Issue validate bit=0 packet -V1, // issue validate bit=1 packlet -WACK, // wait for ack (or absence of ack) -ITC1, // If True Callback(1) (if prevous WACK got an ACK) -ITC0, // If True callback(0); -ITCB, // If True callback(byte) -NAKFAIL, // if false callback(-1) -FAIL, // callback(-1) -STARTMERGE, // Clear bit and byte settings ready for merge pass -MERGE, // Merge previous wack response with byte value and decrement bit number (use for readimng CV bytes) -SETBIT, // sets bit number to next prog byte -SETCV, // sets cv number to next prog byte -STASHLOCOID, // keeps current byte value for later -COMBINELOCOID, // combines current value with stashed value and returns it -ITSKIP, // skip to SKIPTARGET if ack true -SKIPTARGET=0xFF // jump to target +enum ackOp +{ // Program opcodes for the ack Manager + BASELINE, // ensure enough resets sent before starting and obtain baseline current + W0, + W1, // issue write bit (0..1) packet + WB, // issue write byte packet + VB, // Issue validate Byte packet + V0, // Issue validate bit=0 packet + V1, // issue validate bit=1 packlet + WACK, // wait for ack (or absence of ack) + ITC1, // If True Callback(1) (if prevous WACK got an ACK) + ITC0, // If True callback(0); + ITCB, // If True callback(byte) + NAKFAIL, // if false callback(-1) + FAIL, // callback(-1) + STARTMERGE, // Clear bit and byte settings ready for merge pass + MERGE, // Merge previous wack response with byte value and decrement bit number (use for readimng CV bytes) + SETBIT, // sets bit number to next prog byte + SETCV, // sets cv number to next prog byte + STASHLOCOID, // keeps current byte value for later + COMBINELOCOID, // combines current value with stashed value and returns it + ITSKIP, // skip to SKIPTARGET if ack true + SKIPTARGET = 0xFF // jump to target }; // Allocations with memory implications..! // Base system takes approx 900 bytes + 8 per loco. Turnouts, Sensors etc are dynamically created - #ifdef ARDUINO_AVR_UNO - const byte MAX_LOCOS=20; - #else - const byte MAX_LOCOS=50; - #endif +#ifdef ARDUINO_AVR_UNO +const byte MAX_LOCOS = 20; +#else +const byte MAX_LOCOS = 50; +#endif - -class DCC { - public: - - static void begin(const __FlashStringHelper* motorShieldName, MotorDriver * mainDriver, MotorDriver * progDriver, byte timerNumber=1); +class DCC +{ +public: + static void begin(const __FlashStringHelper *motorShieldName, MotorDriver *mainDriver, MotorDriver *progDriver, byte timerNumber = 1); static void loop(); // Public DCC API functions - static void setThrottle( uint16_t cab, uint8_t tSpeed, bool tDirection); + static void setThrottle(uint16_t cab, uint8_t tSpeed, bool tDirection); static uint8_t getThrottleSpeed(int cab); static bool getThrottleDirection(int cab); static void writeCVByteMain(int cab, int cv, byte bValue); static void writeCVBitMain(int cab, int cv, byte bNum, bool bValue); - static void setFunction( int cab, byte fByte, byte eByte); - static void setFn( int cab, byte functionNumber, bool on); - static int changeFn( int cab, byte functionNumber, bool pressed); - static void updateGroupflags(byte & flags, int functionNumber); - static void setAccessory(int aAdd, byte aNum, bool activate) ; - static bool writeTextPacket( byte *b, int nBytes); - static void setProgTrackSyncMain(bool on); // when true, prog track becomes driveable - - // ACKable progtrack calls bitresults callback 0,0 or -1, cv returns value or -1 - static void readCV(int cv, ACK_CALLBACK callback, bool blocking=false); - static void readCVBit(int cv, byte bitNum, ACK_CALLBACK callback, bool blocking=false); // -1 for error - static void writeCVByte(int cv, byte byteValue, ACK_CALLBACK callback, bool blocking=false) ; - static void writeCVBit(int cv, byte bitNum, bool bitValue, ACK_CALLBACK callback, bool blocking=false); - static void verifyCVByte(int cv, byte byteValue, ACK_CALLBACK callback, bool blocking=false) ; - static void verifyCVBit(int cv, byte bitNum, bool bitValue, ACK_CALLBACK callback, bool blocking=false); - - static void getLocoId(ACK_CALLBACK callback, bool blocking=false); + static void setFunction(int cab, byte fByte, byte eByte); + static void setFn(int cab, byte functionNumber, bool on); + static int changeFn(int cab, byte functionNumber, bool pressed); + static void updateGroupflags(byte &flags, int functionNumber); + static void setAccessory(int aAdd, byte aNum, bool activate); + static bool writeTextPacket(byte *b, int nBytes); + static void setProgTrackSyncMain(bool on); // when true, prog track becomes driveable + + // ACKable progtrack calls bitresults callback 0,0 or -1, cv returns value or -1 + static void readCV(int cv, ACK_CALLBACK callback, bool blocking = false); + static void readCVBit(int cv, byte bitNum, ACK_CALLBACK callback, bool blocking = false); // -1 for error + static void writeCVByte(int cv, byte byteValue, ACK_CALLBACK callback, bool blocking = false); + static void writeCVBit(int cv, byte bitNum, bool bitValue, ACK_CALLBACK callback, bool blocking = false); + static void verifyCVByte(int cv, byte byteValue, ACK_CALLBACK callback, bool blocking = false); + static void verifyCVBit(int cv, byte bitNum, bool bitValue, ACK_CALLBACK callback, bool blocking = false); + + static void getLocoId(ACK_CALLBACK callback, bool blocking = false); // Enhanced API functions - static void forgetLoco(int cab); // removes any speed reminders for this loco - static void forgetAllLocos(); // removes all speed reminders - static void displayCabList(Print * stream); + static void forgetLoco(int cab); // removes any speed reminders for this loco + static void forgetAllLocos(); // removes all speed reminders + static void displayCabList(Print *stream); - static __FlashStringHelper* getMotorShieldName(); - -private: - struct LOCO { - int loco; - byte speedCode; - byte groupFlags; - unsigned long functions; + static __FlashStringHelper *getMotorShieldName(); + +private: + struct LOCO + { + int loco; + byte speedCode; + byte groupFlags; + unsigned long functions; }; static byte loopStatus; - static void setThrottle2( uint16_t cab, uint8_t speedCode); + static void setThrottle2(uint16_t cab, uint8_t speedCode); static void updateLocoReminder(int loco, byte speedCode); - static void setFunctionInternal( int cab, byte fByte, byte eByte); + static void setFunctionInternal(int cab, byte fByte, byte eByte); static bool issueReminder(int reg); static int nextLoco; - static __FlashStringHelper* shieldName; - + static __FlashStringHelper *shieldName; + static LOCO speedTable[MAX_LOCOS]; static byte cv1(byte opcode, int cv); static byte cv2(int cv); static int lookupSpeedTable(int locoId); static void issueReminders(); static void callback(int value); - -// ACK MANAGER - static ackOp const * ackManagerProg; - static byte ackManagerByte; - static byte ackManagerBitNum; - static int ackManagerCv; - static byte ackManagerStash; + + // ACK MANAGER + static ackOp const *ackManagerProg; + static byte ackManagerByte; + static byte ackManagerBitNum; + static int ackManagerCv; + static byte ackManagerStash; static bool ackReceived; - static ACK_CALLBACK ackManagerCallback; + static ACK_CALLBACK ackManagerCallback; static void ackManagerSetup(int cv, byte bitNumOrbyteValue, ackOp const program[], ACK_CALLBACK callback, bool blocking); static void ackManagerLoop(bool blocking); static bool checkResets(bool blocking, uint8_t numResets); - static const int PROG_REPEATS=8; // repeats of programming commands (some decoders need at least 8 to be reliable) - - + static const int PROG_REPEATS = 8; // repeats of programming commands (some decoders need at least 8 to be reliable) // NMRA codes # - static const byte SET_SPEED=0x3f; + static const byte SET_SPEED = 0x3f; static const byte WRITE_BYTE_MAIN = 0xEC; static const byte WRITE_BIT_MAIN = 0xE8; static const byte WRITE_BYTE = 0x7C; - static const byte VERIFY_BYTE= 0x74; - static const byte BIT_MANIPULATE=0x78; - static const byte WRITE_BIT=0xF0; - static const byte VERIFY_BIT=0xE0; - static const byte BIT_ON=0x08; - static const byte BIT_OFF=0x00; + static const byte VERIFY_BYTE = 0x74; + static const byte BIT_MANIPULATE = 0x78; + static const byte WRITE_BIT = 0xF0; + static const byte VERIFY_BIT = 0xE0; + static const byte BIT_ON = 0x08; + static const byte BIT_OFF = 0x00; }; -#ifdef ARDUINO_AVR_MEGA // is using Mega 1280, define as Mega 2560 (pinouts and functionality are identical) - #define ARDUINO_AVR_MEGA2560 +#ifdef ARDUINO_AVR_MEGA // is using Mega 1280, define as Mega 2560 (pinouts and functionality are identical) +#define ARDUINO_AVR_MEGA2560 #endif #if defined(ARDUINO_AVR_UNO) - #define ARDUINO_TYPE "UNO" +#define ARDUINO_TYPE "UNO" #elif defined(ARDUINO_AVR_NANO) - #define ARDUINO_TYPE "NANO" +#define ARDUINO_TYPE "NANO" #elif defined(ARDUINO_AVR_MEGA2560) - #define ARDUINO_TYPE "MEGA" +#define ARDUINO_TYPE "MEGA" +#elif defined(ARDUINO_ARCH_MEGAAVR) +#define ARDUINO_TYPE "UNOWIFIR2" #else - #error CANNOT COMPILE - DCC++ EX ONLY WORKS WITH AN ARDUINO UNO, NANO 328, OR ARDUINO MEGA 1280/2560 +#error CANNOT COMPILE - DCC++ EX ONLY WORKS WITH AN ARDUINO UNO, NANO 328, OR ARDUINO MEGA 1280/2560 #endif - -#ifdef ENABLE_LCD +#if ENABLE_LCD #include - #if defined(LIB_TYPE_PCF8574) - #include - extern LiquidCrystal_PCF8574 lcdDisplay; - #elif defined(LIB_TYPE_I2C) - #include - extern LiquidCrystal_I2C lcdDisplay; - #endif +#if defined(LIB_TYPE_PCF8574) +#include +extern LiquidCrystal_PCF8574 lcdDisplay; +#elif defined(LIB_TYPE_I2C) +#include +extern LiquidCrystal_I2C lcdDisplay; +#endif extern bool lcdEnabled; #endif diff --git a/DCCEXParser.cpp b/DCCEXParser.cpp index e10e028..8b26da7 100644 --- a/DCCEXParser.cpp +++ b/DCCEXParser.cpp @@ -20,7 +20,9 @@ #include "DCCEXParser.h" #include "DCC.h" #include "DCCWaveform.h" +#if ENABLE_WIFI && (defined(ARDUINO_AVR_MEGA) || defined(ARDUINO_AVR_MEGA2560)) #include "WifiInterface.h" +#endif #include "Turnouts.h" #include "Outputs.h" #include "Sensors.h" @@ -31,524 +33,611 @@ #include "EEStore.h" #include "DIAG.h" - // These keywords are used in the <1> command. The number is what you get if you use the keyword as a parameter. // To discover new keyword numbers , use the <$ YOURKEYWORD> command -const int HASH_KEYWORD_PROG=-29718; -const int HASH_KEYWORD_MAIN=11339; -const int HASH_KEYWORD_JOIN=-30750; -const int HASH_KEYWORD_CABS=-11981; -const int HASH_KEYWORD_RAM=25982; -const int HASH_KEYWORD_CMD=9962; -const int HASH_KEYWORD_WIT=31594; -const int HASH_KEYWORD_WIFI=-5583; -const int HASH_KEYWORD_ACK=3113; -const int HASH_KEYWORD_ON=2657; -const int HASH_KEYWORD_DCC=6436; -const int HASH_KEYWORD_SLOW=-17209; - +const int HASH_KEYWORD_PROG = -29718; +const int HASH_KEYWORD_MAIN = 11339; +const int HASH_KEYWORD_JOIN = -30750; +const int HASH_KEYWORD_CABS = -11981; +const int HASH_KEYWORD_RAM = 25982; +const int HASH_KEYWORD_CMD = 9962; +const int HASH_KEYWORD_WIT = 31594; +const int HASH_KEYWORD_WIFI = -5583; +const int HASH_KEYWORD_ACK = 3113; +const int HASH_KEYWORD_ON = 2657; +const int HASH_KEYWORD_DCC = 6436; +const int HASH_KEYWORD_SLOW = -17209; int DCCEXParser::stashP[MAX_PARAMS]; bool DCCEXParser::stashBusy; - - Print * DCCEXParser::stashStream=NULL; + +Print *DCCEXParser::stashStream = NULL; // 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. +// Non-DCC things like turnouts, pins and sensors are handled in additional JMRI interface classes. DCCEXParser::DCCEXParser() {} -void DCCEXParser::flush() { - if (Diag::CMD) DIAG(F("\nBuffer flush")); - bufferLength=0; - inCommandPayload=false; +void DCCEXParser::flush() +{ + if (Diag::CMD) + DIAG(F("\nBuffer flush")); + bufferLength = 0; + inCommandPayload = false; } -void DCCEXParser::loop(Stream & stream) { - while(stream.available()) { - if (bufferLength==MAX_BUFFER) { - flush(); +void DCCEXParser::loop(Stream &stream) +{ + while (stream.available()) + { + if (bufferLength == MAX_BUFFER) + { + flush(); + } + char ch = stream.read(); + if (ch == '<') + { + inCommandPayload = true; + bufferLength = 0; + buffer[0] = '\0'; + } + else if (ch == '>') + { + buffer[bufferLength] = '\0'; + parse(&stream, buffer, false); // Parse this allowing async responses + inCommandPayload = false; + break; + } + else if (inCommandPayload) + { + buffer[bufferLength++] = ch; + } } - char ch = stream.read(); - if (ch == '<') { - inCommandPayload = true; - bufferLength=0; - buffer[0]='\0'; - } - else if (ch == '>') { - buffer[bufferLength]='\0'; - parse( & stream, buffer, false); // Parse this allowing async responses - inCommandPayload = false; - break; - } else if(inCommandPayload) { - buffer[bufferLength++]= ch; +} + +int DCCEXParser::splitValues(int result[MAX_PARAMS], const byte *cmd) +{ + byte state = 1; + byte parameterCount = 0; + int runningValue = 0; + const byte *remainingCmd = cmd + 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) + { + byte 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; + } + if (hot >= 'A' && hot <= 'Z') + { + // Since JMRI got modified to send keywords in some rare cases, we need this + // Super Kluge to turn keywords into a hash value that can be recognised later + runningValue = ((runningValue << 5) + runningValue) ^ hot; + break; + } + result[parameterCount] = runningValue * (signNegative ? -1 : 1); + parameterCount++; + state = 1; + continue; + } + remainingCmd++; } - } - } - - int DCCEXParser::splitValues( int result[MAX_PARAMS], const byte * cmd) { - byte state=1; - byte parameterCount=0; - int runningValue=0; - const byte * remainingCmd=cmd+1; // skips the opcode - bool signNegative=false; - - // clear all parameters in case not enough found - for (int i=0;i') 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; - } - if (hot>='A' && hot<='Z') { - // Since JMRI got modified to send keywords in some rare cases, we need this - // Super Kluge to turn keywords into a hash value that can be recognised later - runningValue = ((runningValue << 5) + runningValue) ^ hot; - break; - } - result[parameterCount] = runningValue * (signNegative ?-1:1); - parameterCount++; - state=1; - continue; - } - remainingCmd++; - } - return parameterCount; + return parameterCount; } -FILTER_CALLBACK DCCEXParser::filterCallback=0; -void DCCEXParser::setFilter(FILTER_CALLBACK filter) { - filterCallback=filter; +FILTER_CALLBACK DCCEXParser::filterCallback = 0; +void DCCEXParser::setFilter(FILTER_CALLBACK filter) +{ + filterCallback = filter; } - + // See documentation on DCC class for info on this section -void DCCEXParser::parse(Print * stream, byte *com, bool blocking) { - if (Diag::CMD) DIAG(F("\nPARSING:%s\n"),com); - (void) EEPROM; // tell compiler not to warn thi is unused - int p[MAX_PARAMS]; - while (com[0]=='<' || com[0]==' ') com++; // strip off any number of < or spaces - byte params=splitValues(p, com); - byte opcode=com[0]; - - if (filterCallback) filterCallback(stream,opcode,params,p); - +void DCCEXParser::parse(Print *stream, byte *com, bool blocking) +{ + if (Diag::CMD) + DIAG(F("\nPARSING:%s\n"), com); + (void)EEPROM; // tell compiler not to warn thi is unused + int p[MAX_PARAMS]; + while (com[0] == '<' || com[0] == ' ') + com++; // strip off any number of < or spaces + byte params = splitValues(p, com); + byte opcode = com[0]; + + if (filterCallback) + filterCallback(stream, opcode, params, p); + // Functions return from this switch if complete, break from switch implies error to send - switch(opcode) { - case '\0': return; // filterCallback asked us to ignore - case 't': // THROTTLE + switch (opcode) + { + case '\0': + return; // filterCallback asked us to ignore + case 't': // THROTTLE + { + int cab; + int tspeed; + int direction; + + if (params == 4) + { // + cab = p[1]; + tspeed = p[2]; + direction = p[3]; + } + else if (params == 3) + { // + cab = p[0]; + tspeed = p[1]; + direction = p[2]; + } + else + break; + + // Convert JMRI bizarre -1=emergency stop, 0-126 as speeds + // to DCC 0=stop, 1= emergency stop, 2-127 speeds + if (tspeed > 126 || tspeed < -1) + break; // invalid JMRI speed code + if (tspeed < 0) + tspeed = 1; // emergency stop DCC speed + else if (tspeed > 0) + tspeed++; // map 1-126 -> 2-127 + if (cab == 0 && tspeed > 1) + break; // ignore broadcasts of speed>1 + + if (direction < 0 || direction > 1) + break; // invalid direction code + + DCC::setThrottle(cab, tspeed, direction); + if (params == 4) + StringFormatter::send(stream, F(""), p[0], p[2], p[3]); + else + StringFormatter::send(stream, F("")); + return; + } + case 'f': // FUNCTION + if (parsef(stream, params, p)) + return; + break; + + case 'a': // ACCESSORY + if (p[2] != (p[2] & 1)) + return; + DCC::setAccessory(p[0], p[1], p[2] == 1); + return; + + case 'T': // TURNOUT + if (parseT(stream, params, p)) + return; + break; + + case 'Z': // OUTPUT + if (parseZ(stream, params, p)) + return; + break; + + case 'S': // SENSOR + if (parseS(stream, params, p)) + return; + break; + + case 'w': // WRITE CV on MAIN + DCC::writeCVByteMain(p[0], p[1], p[2]); + return; + + case 'b': // WRITE CV BIT ON MAIN + DCC::writeCVBitMain(p[0], p[1], p[2], p[3]); + return; + + case 'W': // WRITE CV ON PROG + if (!stashCallback(stream, p)) + break; + DCC::writeCVByte(p[0], p[1], callback_W, blocking); + return; + + case 'V': // VERIFY CV ON PROG + if (params == 2) + { // + if (!stashCallback(stream, p)) + break; + DCC::verifyCVByte(p[0], p[1], callback_Vbyte, blocking); + return; + } + if (params == 3) { - int cab; - int tspeed; - int direction; - - if (params==4) { // - cab=p[1]; - tspeed=p[2]; - direction=p[3]; - } - else if (params==3) { // - cab=p[0]; - tspeed=p[1]; - direction=p[2]; - } - else break; - - // Convert JMRI bizarre -1=emergency stop, 0-126 as speeds - // to DCC 0=stop, 1= emergency stop, 2-127 speeds - if (tspeed>126 || tspeed<-1) break; // invalid JMRI speed code - if (tspeed<0) tspeed=1; // emergency stop DCC speed - else if (tspeed>0) tspeed++; // map 1-126 -> 2-127 - if (cab == 0 && tspeed>1) break; // ignore broadcasts of speed>1 - - if (direction<0 || direction>1) break; // invalid direction code - - DCC::setThrottle(cab,tspeed,direction); - if (params==4) StringFormatter::send(stream,F(""), p[0], p[2],p[3]); - else StringFormatter::send(stream,F("")); - return; - } - case 'f': // FUNCTION - if (parsef(stream,params,p)) return; - break; - - case 'a': // ACCESSORY - if(p[2] != (p[2] & 1)) return; - DCC::setAccessory(p[0],p[1],p[2]==1); - return; - - case 'T': // TURNOUT - if (parseT(stream,params,p)) return; - break; - - case 'Z': // OUTPUT - if (parseZ(stream,params,p)) return; - break; - - case 'S': // SENSOR - if (parseS(stream,params,p)) return; - break; - - case 'w': // WRITE CV on MAIN - DCC::writeCVByteMain(p[0],p[1],p[2]); - return; - - case 'b': // WRITE CV BIT ON MAIN - DCC::writeCVBitMain(p[0],p[1],p[2],p[3]); - return; - - case 'W': // WRITE CV ON PROG - if (!stashCallback(stream,p)) break; - DCC::writeCVByte(p[0],p[1],callback_W,blocking); - return; - - case 'V': // VERIFY CV ON PROG - if (params==2) { // - if (!stashCallback(stream,p)) break; - DCC::verifyCVByte(p[0],p[1],callback_Vbyte,blocking); - return; - } - if (params==3) { - if (!stashCallback(stream,p)) break; - DCC::verifyCVBit(p[0],p[1],p[2],callback_Vbit,blocking); - return; + if (!stashCallback(stream, p)) + break; + DCC::verifyCVBit(p[0], p[1], p[2], callback_Vbit, blocking); + return; } break; - - case 'B': // WRITE CV BIT ON PROG - if (!stashCallback(stream,p)) break; - DCC::writeCVBit(p[0],p[1],p[2],callback_B,blocking); + + case 'B': // WRITE CV BIT ON PROG + if (!stashCallback(stream, p)) + break; + DCC::writeCVBit(p[0], p[1], p[2], callback_B, blocking); return; - - - case 'R': // READ CV ON PROG - if (params==3) { // - if (!stashCallback(stream,p)) break; - DCC::readCV(p[0],callback_R,blocking); - return; + + case 'R': // READ CV ON PROG + if (params == 3) + { // + if (!stashCallback(stream, p)) + break; + DCC::readCV(p[0], callback_R, blocking); + return; } - if (params==0) { // New read loco id - if (!stashCallback(stream,p)) break; - DCC::getLocoId(callback_Rloco,blocking); - return; + if (params == 0) + { // New read loco id + if (!stashCallback(stream, p)) + break; + DCC::getLocoId(callback_Rloco, blocking); + return; } break; - - case '1': // POWERON <1 [MAIN|PROG]> - case '0': // POWEROFF <0 [MAIN | PROG] > - if (params>1) break; + + case '1': // POWERON <1 [MAIN|PROG]> + case '0': // POWEROFF <0 [MAIN | PROG] > + if (params > 1) + break; { - POWERMODE mode= opcode=='1'?POWERMODE::ON:POWERMODE::OFF; - DCC::setProgTrackSyncMain(false); // Only <1 JOIN> will set this on, all others set it off - if (params==0) { - DCCWaveform::mainTrack.setPowerMode(mode); - DCCWaveform::progTrack.setPowerMode(mode); - StringFormatter::send(stream,F(""),opcode); - return; - } - switch (p[0]) { - case HASH_KEYWORD_MAIN: - DCCWaveform::mainTrack.setPowerMode(mode); - StringFormatter::send(stream,F(""),opcode); - return; - - case HASH_KEYWORD_PROG: - DCCWaveform::progTrack.setPowerMode(mode); - StringFormatter::send(stream,F(""),opcode); - return; - case HASH_KEYWORD_JOIN: - DCCWaveform::mainTrack.setPowerMode(mode); - DCCWaveform::progTrack.setPowerMode(mode); - if (mode==POWERMODE::ON) { - DCC::setProgTrackSyncMain(true); - StringFormatter::send(stream,F(""),opcode); - } - else StringFormatter::send(stream,F("")); - return; - - } - break; - } - return; - - case 'c': // READ CURRENT - StringFormatter::send(stream,F(""), DCCWaveform::mainTrack.getLastCurrent()); - return; + POWERMODE mode = opcode == '1' ? POWERMODE::ON : POWERMODE::OFF; + DCC::setProgTrackSyncMain(false); // Only <1 JOIN> will set this on, all others set it off + if (params == 0) + { + DCCWaveform::mainTrack.setPowerMode(mode); + DCCWaveform::progTrack.setPowerMode(mode); + StringFormatter::send(stream, F(""), opcode); + return; + } + switch (p[0]) + { + case HASH_KEYWORD_MAIN: + DCCWaveform::mainTrack.setPowerMode(mode); + StringFormatter::send(stream, F(""), opcode); + return; - case 'Q': // SENSORS - 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); + case HASH_KEYWORD_PROG: + DCCWaveform::progTrack.setPowerMode(mode); + StringFormatter::send(stream, F(""), opcode); + return; + case HASH_KEYWORD_JOIN: + DCCWaveform::mainTrack.setPowerMode(mode); + DCCWaveform::progTrack.setPowerMode(mode); + if (mode == POWERMODE::ON) + { + DCC::setProgTrackSyncMain(true); + StringFormatter::send(stream, F(""), opcode); + } + else + StringFormatter::send(stream, F("")); + return; + } + break; } return; - case 's': // - StringFormatter::send(stream,F(""),DCCWaveform::mainTrack.getPowerMode()==POWERMODE::ON ); - StringFormatter::send(stream,F(""), F(VERSION), F(ARDUINO_TYPE), DCC::getMotorShieldName(), F(GITHUB_SHA)); - // TODO Send stats of speed reminders table - // TODO send status of turnouts etc etc + case 'c': // READ CURRENT + StringFormatter::send(stream, F(""), DCCWaveform::mainTrack.getLastCurrent()); return; - case 'E': // STORE EPROM + case 'Q': // SENSORS + 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(""), F(VERSION), F(ARDUINO_TYPE), DCC::getMotorShieldName(), 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); + StringFormatter::send(stream, F(""), EEStore::eeStore->data.nTurnouts, EEStore::eeStore->data.nSensors, EEStore::eeStore->data.nOutputs); return; - case 'e': // CLEAR EPROM + 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; + case ' ': // < > + StringFormatter::send(stream, F("\n")); return; - case '#': // NUMBER OF LOCOSLOTS <#> - StringFormatter::send(stream,F("<# %d>"), MAX_LOCOS); - 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 + DIAG(F("\nOpcode=%c params=%d\n"), opcode, params); + for (int i = 0; i < params; i++) + DIAG(F("p[%d]=%d (0x%x)\n"), i, p[i], p[i]); break; - - } // end of opcode switch + + } // end of opcode switch // Any fallout here sends an - StringFormatter::send(stream, F("")); + 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; +bool DCCEXParser::parseZ(Print *stream, int params, int p[]) +{ - case 3: // - Output::create(p[0],p[1],p[2],1); - return true; + switch (params) + { - 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); + 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]); } - (void)stream;// NO RESPONSE - return true; -} + 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; - } + 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::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::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; } -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; +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; + } +} - 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; +//=================================== +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; +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_RAM: // + StringFormatter::send(stream, F("\nFree memory=%d\n"), freeMemory()); + break; - case HASH_KEYWORD_ACK: // - Diag::ACK=onOff; - return true; + case HASH_KEYWORD_ACK: // + Diag::ACK = onOff; + return true; - case HASH_KEYWORD_CMD: // - Diag::CMD=onOff; - return true; + case HASH_KEYWORD_CMD: // + Diag::CMD = onOff; + return true; - case HASH_KEYWORD_WIFI: // - Diag::WIFI=onOff; - return true; + case HASH_KEYWORD_WIFI: // + Diag::WIFI = onOff; + return true; - case HASH_KEYWORD_WIT: // - Diag::WITHROTTLE=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; - } + 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; +// 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_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_W(int result) +{ + StringFormatter::send(stashStream, F(""), stashP[2], stashP[3], stashP[0], result == 1 ? stashP[1] : -1); + stashBusy = false; } -void DCCEXParser::callback_R(int result) { - StringFormatter::send(stashStream,F(""),stashP[1],stashP[2],stashP[0],result); - 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_Rloco(int result) { - StringFormatter::send(stashStream,F(""),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; } - diff --git a/MemStream.h b/MemStream.h index 444864f..61ef6bb 100644 --- a/MemStream.h +++ b/MemStream.h @@ -24,34 +24,43 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define MemStream_h #include +#if defined(ARDUINO_ARCH_MEGAAVR) +#include +#else #include +#endif + #include class MemStream : public Stream { private: - uint8_t * _buffer; - const uint16_t _len; - bool _buffer_overflow; - uint16_t _pos_read; - uint16_t _pos_write; - bool _allowWrite; - + uint8_t *_buffer; + const uint16_t _len; + bool _buffer_overflow; + uint16_t _pos_read; + uint16_t _pos_write; + bool _allowWrite; public: // public methods - MemStream(uint8_t *buffer, const uint16_t len, uint16_t content_len = 0, bool allowWrite=true); + MemStream(uint8_t *buffer, const uint16_t len, uint16_t content_len = 0, bool allowWrite = true); ~MemStream() {} operator const uint8_t *() const { return _buffer; } - operator const char *() const { return (const char*)_buffer; } + operator const char *() const { return (const char *)_buffer; } uint16_t current_length() const { return _pos_write; } bool listen() { return true; } void end() {} bool isListening() { return true; } - bool overflow() { bool ret = _buffer_overflow; _buffer_overflow = false; return ret; } + bool overflow() + { + bool ret = _buffer_overflow; + _buffer_overflow = false; + return ret; + } int peek(); virtual size_t write(uint8_t byte); diff --git a/MotorDrivers.h b/MotorDrivers.h index c81bc37..79bcd4f 100644 --- a/MotorDrivers.h +++ b/MotorDrivers.h @@ -1,5 +1,8 @@ #ifndef MotorDrivers_h #define MotorDrivers_h +#if defined(ARDUINO_ARCH_MEGAAVR) +#include +#endif // *** PLEASE NOTE *** THIS FILE IS **NOT** INTENDED TO BE EDITED WHEN CONFIGURING A SYSTEM. // It will be overwritten if the library is updated. @@ -8,36 +11,35 @@ // A configuration defined by macro here can be used in your sketch. // A custom hardware setup will require your sketch to create MotorDriver instances // similar to those defined here, WITHOUT editing this file. - const byte UNUSED_PIN = 255; // MotorDriver(byte power_pin, byte signal_pin, byte signal_pin2, byte brake_pin, byte current_pin, // float senseFactor, unsigned int tripMilliamps, byte faultPin); - + // Arduino standard Motor Shield -#define STANDARD_MOTOR_SHIELD F("STANDARD_MOTOR_SHIELD"), \ - new MotorDriver(3 , 12, UNUSED_PIN, UNUSED_PIN, A0, 2.99, 2000, UNUSED_PIN), \ - new MotorDriver(11, 13, UNUSED_PIN, UNUSED_PIN, A1, 2.99, 250 , UNUSED_PIN) +#define STANDARD_MOTOR_SHIELD F("STANDARD_MOTOR_SHIELD"), \ + new MotorDriver(3, 12, UNUSED_PIN, UNUSED_PIN, A0, 2.99, 2000, UNUSED_PIN), \ + new MotorDriver(11, 13, UNUSED_PIN, UNUSED_PIN, A1, 2.99, TRIP_CURRENT_PROG, UNUSED_PIN) // Pololu Motor Shield -#define POLOLU_MOTOR_SHIELD F("POLOLU_MOTOR_SHIELD"), \ - new MotorDriver(4, 7, UNUSED_PIN, 9 , A0, 18, 2000, 12), \ - new MotorDriver(2, 8, UNUSED_PIN, 10, A1, 18, 250 , UNUSED_PIN) +#define POLOLU_MOTOR_SHIELD F("POLOLU_MOTOR_SHIELD"), \ + new MotorDriver(4, 7, UNUSED_PIN, 9, A0, 18, 2000, 12), \ + new MotorDriver(2, 8, UNUSED_PIN, 10, A1, 18, TRIP_CURRENT_PROG, UNUSED_PIN) -// Firebox Mk1 -#define FIREBOX_MK1 F("FIREBOX_MK1"), \ - new MotorDriver(3, 6, 7, UNUSED_PIN, A5, 9.766, 5500, UNUSED_PIN), \ - new MotorDriver(4, 8, 9, UNUSED_PIN, A1, 5.00, 250 , UNUSED_PIN) +// Firebox Mk1 +#define FIREBOX_MK1 F("FIREBOX_MK1"), \ + new MotorDriver(3, 6, 7, UNUSED_PIN, A5, 9.766, 5500, UNUSED_PIN), \ + new MotorDriver(4, 8, 9, UNUSED_PIN, A1, 5.00, TRIP_CURRENT_PROG, UNUSED_PIN) -// Firebox Mk1S -#define FIREBOX_MK1S F("FIREBOX_MK1A"), \ - new MotorDriver(24, 21, 22, 25, 23, 9.766, 5500, UNUSED_PIN), \ - new MotorDriver(30, 27, 28, 31, 29, 5.00, 250 , UNUSED_PIN) +// Firebox Mk1S +#define FIREBOX_MK1S F("FIREBOX_MK1A"), \ + new MotorDriver(24, 21, 22, 25, 23, 9.766, 5500, UNUSED_PIN), \ + new MotorDriver(30, 27, 28, 31, 29, 5.00, TRIP_CURRENT_PROG, UNUSED_PIN) // FunduMoto Motor Shield -#define FUNDUMOTO_SHIELD F("FUNDUMOTO_SHIELD"), \ - new MotorDriver(10 , 12, UNUSED_PIN, 9, A0, 2.99, 2000, UNUSED_PIN), \ - new MotorDriver(11, 13, UNUSED_PIN, UNUSED_PIN, A1, 2.99, 250 , UNUSED_PIN) +#define FUNDUMOTO_SHIELD F("FUNDUMOTO_SHIELD"), \ + new MotorDriver(10, 12, UNUSED_PIN, 9, A0, 2.99, 2000, UNUSED_PIN), \ + new MotorDriver(11, 13, UNUSED_PIN, UNUSED_PIN, A1, 2.99, TRIP_CURRENT_PROG, UNUSED_PIN) #endif diff --git a/Timer.cpp b/Timer.cpp index 1430e9c..3a73401 100644 --- a/Timer.cpp +++ b/Timer.cpp @@ -85,10 +85,15 @@ ISR(TIMER2_OVF_vect) #include "ATMEGA4809/Timer.h" -Timer TimerA(0); +Timer TimerA(1); +Timer TimerB(2); -ISR(TCA0_OVF_vect) { +ISR(TIMER1_OVF_vect) { TimerA.isrCallback(); } +ISR(TIMER2_OVF_vect) { + TimerB.isrCallback(); +} + #endif diff --git a/WifiInterface.cpp b/WifiInterface.cpp index 06fa11b..9ea5738 100644 --- a/WifiInterface.cpp +++ b/WifiInterface.cpp @@ -22,6 +22,8 @@ #include "DIAG.h" #include "StringFormatter.h" #include "WiThrottle.h" + + const char PROGMEM READY_SEARCH[] = "\r\nready\r\n"; const char PROGMEM OK_SEARCH[] = "\r\nOK\r\n"; const char PROGMEM END_DETAIL_SEARCH[] = "@ 1000"; diff --git a/WifiInterface.h b/WifiInterface.h index 10941fa..003ef2d 100644 --- a/WifiInterface.h +++ b/WifiInterface.h @@ -21,37 +21,39 @@ #define WifiInterface_h #include "DCCEXParser.h" #include "MemStream.h" + #include #include -typedef void (*HTTP_CALLBACK)(Print * stream, byte * cmd); +typedef void (*HTTP_CALLBACK)(Print *stream, byte *cmd); -class WifiInterface { +class WifiInterface +{ - public: - static bool setup(Stream & setupStream, const __FlashStringHelper* SSSid, const __FlashStringHelper* password, - const __FlashStringHelper* hostname, int port); - static void loop(); - static void ATCommand(const byte * command); - static void setHTTPCallback(HTTP_CALLBACK callback); - - private: - static Stream * wifiStream; - static DCCEXParser parser; - static bool setup2( const __FlashStringHelper* SSSid, const __FlashStringHelper* password, - const __FlashStringHelper* hostname, int port); - static bool checkForOK(const unsigned int timeout, const char* waitfor, bool echo, bool escapeEcho=true); - static bool isHTTP(); - static HTTP_CALLBACK httpCallback; - static bool connected; - static bool closeAfter; - static byte loopstate; - static int datalength; - static int connectionId; - static unsigned long loopTimeoutStart; - static const byte MAX_WIFI_BUFFER=250; - static byte buffer[MAX_WIFI_BUFFER+1]; - static MemStream streamer; +public: + static bool setup(Stream &setupStream, const __FlashStringHelper *SSSid, const __FlashStringHelper *password, + const __FlashStringHelper *hostname, int port); + static void loop(); + static void ATCommand(const byte *command); + static void setHTTPCallback(HTTP_CALLBACK callback); + +private: + static Stream *wifiStream; + static DCCEXParser parser; + static bool setup2(const __FlashStringHelper *SSSid, const __FlashStringHelper *password, + const __FlashStringHelper *hostname, int port); + static bool checkForOK(const unsigned int timeout, const char *waitfor, bool echo, bool escapeEcho = true); + static bool isHTTP(); + static HTTP_CALLBACK httpCallback; + static bool connected; + static bool closeAfter; + static byte loopstate; + static int datalength; + static int connectionId; + static unsigned long loopTimeoutStart; + static const byte MAX_WIFI_BUFFER = 250; + static byte buffer[MAX_WIFI_BUFFER + 1]; + static MemStream streamer; }; #endif