From 8141311e6672c28d82a922e82ac61cd2692053b3 Mon Sep 17 00:00:00 2001 From: Mike S Date: Thu, 25 Mar 2021 13:16:12 -0400 Subject: [PATCH] Revisions to support Teensy 3.x and Teensy 4.x --- DCC.cpp | 12 ++++---- DCC.h | 16 +++++----- DCCEXParser.cpp | 75 ++++++++++++++++++++++----------------------- DCCEXParser.h | 38 +++++++++++------------ DCCTimer.cpp | 57 ++++++++++++++++++++++++++++++++-- DCCTimer.h | 4 +++ DCCWaveform.cpp | 2 ++ EthernetInterface.h | 8 +++-- MotorDriver.h | 8 +++++ defines.h | 4 +-- 10 files changed, 147 insertions(+), 77 deletions(-) diff --git a/DCC.cpp b/DCC.cpp index 241103b..f8c9c92 100644 --- a/DCC.cpp +++ b/DCC.cpp @@ -480,31 +480,31 @@ const ackOp FLASH LONG_LOCO_ID_PROG[] = { FAIL }; -void DCC::writeCVByte(int cv, byte byteValue, ACK_CALLBACK callback) { +void DCC::writeCVByte(int16_t cv, byte byteValue, ACK_CALLBACK callback) { ackManagerSetup(cv, byteValue, WRITE_BYTE_PROG, callback); } -void DCC::writeCVBit(int cv, byte bitNum, bool bitValue, ACK_CALLBACK callback) { +void DCC::writeCVBit(int16_t cv, byte bitNum, bool bitValue, ACK_CALLBACK callback) { if (bitNum >= 8) callback(-1); else ackManagerSetup(cv, bitNum, bitValue?WRITE_BIT1_PROG:WRITE_BIT0_PROG, callback); } -void DCC::verifyCVByte(int cv, byte byteValue, ACK_CALLBACK callback) { +void DCC::verifyCVByte(int16_t cv, byte byteValue, ACK_CALLBACK callback) { ackManagerSetup(cv, byteValue, VERIFY_BYTE_PROG, callback); } -void DCC::verifyCVBit(int cv, byte bitNum, bool bitValue, ACK_CALLBACK callback) { +void DCC::verifyCVBit(int16_t cv, byte bitNum, bool bitValue, ACK_CALLBACK callback) { if (bitNum >= 8) callback(-1); else ackManagerSetup(cv, bitNum, bitValue?VERIFY_BIT1_PROG:VERIFY_BIT0_PROG, callback); } -void DCC::readCVBit(int cv, byte bitNum, ACK_CALLBACK callback) { +void DCC::readCVBit(int16_t cv, byte bitNum, ACK_CALLBACK callback) { if (bitNum >= 8) callback(-1); else ackManagerSetup(cv, bitNum,READ_BIT_PROG, callback); } -void DCC::readCV(int cv, ACK_CALLBACK callback) { +void DCC::readCV(int16_t cv, ACK_CALLBACK callback) { ackManagerSetup(cv, 0,READ_CV_PROG, callback); } diff --git a/DCC.h b/DCC.h index aa4451f..a224fb9 100644 --- a/DCC.h +++ b/DCC.h @@ -23,7 +23,7 @@ #include "MotorDrivers.h" #include "FSH.h" -typedef void (*ACK_CALLBACK)(int result); +typedef void (*ACK_CALLBACK)(int16_t result); enum ackOp : byte { // Program opcodes for the ack Manager @@ -86,12 +86,12 @@ public: static void setProgTrackBoost(bool on); // when true, special prog track current limit does not apply // ACKable progtrack calls bitresults callback 0,0 or -1, cv returns value or -1 - static void readCV(int cv, ACK_CALLBACK callback); - static void readCVBit(int cv, byte bitNum, ACK_CALLBACK callback); // -1 for error - static void writeCVByte(int cv, byte byteValue, ACK_CALLBACK callback); - static void writeCVBit(int cv, byte bitNum, bool bitValue, ACK_CALLBACK callback); - static void verifyCVByte(int cv, byte byteValue, ACK_CALLBACK callback); - static void verifyCVBit(int cv, byte bitNum, bool bitValue, ACK_CALLBACK callback); + static void readCV(int16_t cv, ACK_CALLBACK callback); + static void readCVBit(int16_t cv, byte bitNum, ACK_CALLBACK callback); // -1 for error + static void writeCVByte(int16_t cv, byte byteValue, ACK_CALLBACK callback); + static void writeCVBit(int16_t cv, byte bitNum, bool bitValue, ACK_CALLBACK callback); + static void verifyCVByte(int16_t cv, byte byteValue, ACK_CALLBACK callback); + static void verifyCVBit(int16_t cv, byte bitNum, bool bitValue, ACK_CALLBACK callback); static void getLocoId(ACK_CALLBACK callback); static void setLocoId(int id,ACK_CALLBACK callback); @@ -168,6 +168,8 @@ private: #define ARDUINO_TYPE "MEGA" #elif defined(ARDUINO_ARCH_MEGAAVR) #define ARDUINO_TYPE "MEGAAVR" +#elif defined(TEENSYDUINO) +#define ARDUINO_TYPE "TEENSY" #else #error CANNOT COMPILE - DCC++ EX ONLY WORKS WITH AN ARDUINO UNO, NANO 328, OR ARDUINO MEGA 1280/2560 #endif diff --git a/DCCEXParser.cpp b/DCCEXParser.cpp index 9b174bc..2b75479 100644 --- a/DCCEXParser.cpp +++ b/DCCEXParser.cpp @@ -34,29 +34,26 @@ // 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_PROGBOOST = -6353; -const int HASH_KEYWORD_EEPROM = -7168; -const int HASH_KEYWORD_LIMIT = 27413; -const int HASH_KEYWORD_ETHERNET = -30767; -const int HASH_KEYWORD_MAX = 16244; -const int HASH_KEYWORD_MIN = 15978; -const int HASH_KEYWORD_LCN = 15137; -const int HASH_KEYWORD_RESET = 26133; +const int16_t HASH_KEYWORD_PROG = -29718; +const int16_t HASH_KEYWORD_MAIN = 11339; +const int16_t HASH_KEYWORD_JOIN = -30750; +const int16_t HASH_KEYWORD_CABS = -11981; +const int16_t HASH_KEYWORD_RAM = 25982; +const int16_t HASH_KEYWORD_CMD = 9962; +const int16_t HASH_KEYWORD_WIT = 31594; +const int16_t HASH_KEYWORD_WIFI = -5583; +const int16_t HASH_KEYWORD_ACK = 3113; +const int16_t HASH_KEYWORD_ON = 2657; +const int16_t HASH_KEYWORD_DCC = 6436; +const int16_t HASH_KEYWORD_SLOW = -17209; +const int16_t HASH_KEYWORD_PROGBOOST = -6353; +const int16_t HASH_KEYWORD_EEPROM = -7168; +const int16_t HASH_KEYWORD_LIMIT = 27413; +const int16_t HASH_KEYWORD_ETHERNET = -30767; +const int16_t HASH_KEYWORD_MAX = 16244; +const int16_t HASH_KEYWORD_MIN = 15978; - -int DCCEXParser::stashP[MAX_COMMAND_PARAMS]; +int16_t DCCEXParser::stashP[MAX_COMMAND_PARAMS]; bool DCCEXParser::stashBusy; Print *DCCEXParser::stashStream = NULL; @@ -108,16 +105,16 @@ void DCCEXParser::loop(Stream &stream) Sensor::checkAll(&stream); // Update and print changes } -int DCCEXParser::splitValues(int result[MAX_COMMAND_PARAMS], const byte *cmd) +int16_t DCCEXParser::splitValues(int16_t result[MAX_COMMAND_PARAMS], const byte *cmd) { byte state = 1; byte parameterCount = 0; - int runningValue = 0; + int16_t 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_COMMAND_PARAMS; i++) + for (int16_t i = 0; i < MAX_COMMAND_PARAMS; i++) result[i] = 0; while (parameterCount < MAX_COMMAND_PARAMS) @@ -167,15 +164,15 @@ int DCCEXParser::splitValues(int result[MAX_COMMAND_PARAMS], const byte *cmd) return parameterCount; } -int DCCEXParser::splitHexValues(int result[MAX_COMMAND_PARAMS], const byte *cmd) +int16_t DCCEXParser::splitHexValues(int16_t result[MAX_COMMAND_PARAMS], const byte *cmd) { byte state = 1; byte parameterCount = 0; - int runningValue = 0; + int16_t runningValue = 0; const byte *remainingCmd = cmd + 1; // skips the opcode // clear all parameters in case not enough found - for (int i = 0; i < MAX_COMMAND_PARAMS; i++) + for (int16_t i = 0; i < MAX_COMMAND_PARAMS; i++) result[i] = 0; while (parameterCount < MAX_COMMAND_PARAMS) @@ -257,7 +254,7 @@ void DCCEXParser::parse(Print *stream, byte *com, RingStream * ringStream) (void)EEPROM; // tell compiler not to warn this is unused if (Diag::CMD) DIAG(F("PARSING:%s"), com); - int p[MAX_COMMAND_PARAMS]; + int16_t p[MAX_COMMAND_PARAMS]; while (com[0] == '<' || com[0] == ' ') com++; // strip off any number of < or spaces byte params = splitValues(p, com); @@ -275,9 +272,9 @@ void DCCEXParser::parse(Print *stream, byte *com, RingStream * ringStream) return; // filterCallback asked us to ignore case 't': // THROTTLE { - int cab; - int tspeed; - int direction; + int16_t cab; + int16_t tspeed; + int16_t direction; if (params == 4) { // @@ -561,7 +558,7 @@ void DCCEXParser::parse(Print *stream, byte *com, RingStream * ringStream) StringFormatter::send(stream, F("")); } -bool DCCEXParser::parseZ(Print *stream, int params, int p[]) +bool DCCEXParser::parseZ(Print *stream, int16_t params, int16_t p[]) { switch (params) @@ -605,7 +602,7 @@ bool DCCEXParser::parseZ(Print *stream, int params, int p[]) } //=================================== -bool DCCEXParser::parsef(Print *stream, int params, int p[]) +bool DCCEXParser::parsef(Print *stream, int16_t params, int16_t p[]) { // JMRI sends this info in DCC message format but it's not exactly // convenient for other processing @@ -637,9 +634,9 @@ bool DCCEXParser::parsef(Print *stream, int params, int p[]) return true; } -void DCCEXParser::funcmap(int cab, byte value, byte fstart, byte fstop) +void DCCEXParser::funcmap(int16_t cab, byte value, byte fstart, byte fstop) { - for (int i = fstart; i <= fstop; i++) + for (int16_t i = fstart; i <= fstop; i++) { DCC::setFn(cab, i, value & 1); value >>= 1; @@ -647,7 +644,7 @@ void DCCEXParser::funcmap(int cab, byte value, byte fstart, byte fstop) } //=================================== -bool DCCEXParser::parseT(Print *stream, int params, int p[]) +bool DCCEXParser::parseT(Print *stream, int16_t params, int16_t p[]) { switch (params) { @@ -690,7 +687,7 @@ bool DCCEXParser::parseT(Print *stream, int params, int p[]) } } -bool DCCEXParser::parseS(Print *stream, int params, int p[]) +bool DCCEXParser::parseS(Print *stream, int16_t params, int16_t p[]) { switch (params) @@ -722,7 +719,7 @@ bool DCCEXParser::parseS(Print *stream, int params, int p[]) return false; } -bool DCCEXParser::parseD(Print *stream, int params, int p[]) +bool DCCEXParser::parseD(Print *stream, int16_t params, int16_t p[]) { if (params == 0) return false; diff --git a/DCCEXParser.h b/DCCEXParser.h index 499218a..6953562 100644 --- a/DCCEXParser.h +++ b/DCCEXParser.h @@ -22,7 +22,7 @@ #include "FSH.h" #include "RingStream.h" -typedef void (*FILTER_CALLBACK)(Print * stream, byte & opcode, byte & paramCount, int p[]); +typedef void (*FILTER_CALLBACK)(Print * stream, byte & opcode, byte & paramCount, int16_t p[]); typedef void (*AT_COMMAND_CALLBACK)(const byte * command); struct DCCEXParser @@ -39,18 +39,18 @@ struct DCCEXParser private: - static const int MAX_BUFFER=50; // longest command sent in + static const int16_t MAX_BUFFER=50; // longest command sent in byte bufferLength=0; bool inCommandPayload=false; byte buffer[MAX_BUFFER+2]; - int splitValues( int result[MAX_COMMAND_PARAMS], const byte * command); - int splitHexValues( int result[MAX_COMMAND_PARAMS], const byte * command); + int16_t splitValues( int16_t result[MAX_COMMAND_PARAMS], const byte * command); + int16_t splitHexValues( int16_t result[MAX_COMMAND_PARAMS], const byte * command); - bool parseT(Print * stream, int params, int p[]); - bool parseZ(Print * stream, int params, int p[]); - bool parseS(Print * stream, int params, int p[]); - bool parsef(Print * stream, int params, int p[]); - bool parseD(Print * stream, int params, int p[]); + bool parseT(Print * stream, int16_t params, int16_t p[]); + bool parseZ(Print * stream, int16_t params, int16_t p[]); + bool parseS(Print * stream, int16_t params, int16_t p[]); + bool parsef(Print * stream, int16_t params, int16_t p[]); + bool parseD(Print * stream, int16_t params, int16_t p[]); static Print * getAsyncReplyStream(); static void commitAsyncReplyStream(); @@ -60,19 +60,19 @@ struct DCCEXParser static Print * stashStream; static RingStream * stashRingStream; - static int stashP[MAX_COMMAND_PARAMS]; - bool stashCallback(Print * stream, int p[MAX_COMMAND_PARAMS], RingStream * ringStream); - static void callback_W(int result); - static void callback_B(int result); - static void callback_R(int result); - static void callback_Rloco(int result); - static void callback_Wloco(int result); - static void callback_Vbit(int result); - static void callback_Vbyte(int result); + static int16_t stashP[MAX_COMMAND_PARAMS]; + bool stashCallback(Print * stream, int16_t p[MAX_COMMAND_PARAMS], RingStream * ringStream); + static void callback_W(int16_t result); + static void callback_B(int16_t result); + static void callback_R(int16_t result); + static void callback_Rloco(int16_t result); + static void callback_Wloco(int16_t result); + static void callback_Vbit(int16_t result); + static void callback_Vbyte(int16_t result); static FILTER_CALLBACK filterCallback; static FILTER_CALLBACK filterRMFTCallback; static AT_COMMAND_CALLBACK atCommandCallback; - static void funcmap(int cab, byte value, byte fstart, byte fstop); + static void funcmap(int16_t cab, byte value, byte fstart, byte fstop); }; diff --git a/DCCTimer.cpp b/DCCTimer.cpp index 622b798..eb592c7 100644 --- a/DCCTimer.cpp +++ b/DCCTimer.cpp @@ -81,10 +81,63 @@ INTERRUPT_CALLBACK interruptHandler=0; void DCCTimer::getSimulatedMacAddress(byte mac[6]) { memcpy(mac,(void *) &SIGROW.SERNUM0,6); // serial number - mac[0] &= 0xFE; - mac[0] |= 0x02; } +#elif defined(TEENSYDUINO) + IntervalTimer myDCCTimer; + + void DCCTimer::begin(INTERRUPT_CALLBACK callback) { + interruptHandler=callback; + + myDCCTimer.begin(interruptHandler, DCC_SIGNAL_TIME); + + } + + bool DCCTimer::isPWMPin(byte pin) { + //Teensy: digitalPinHasPWM, todo + return false; // TODO what are the relevant pins? + } + + void DCCTimer::setPWM(byte pin, bool high) { + // TODO what are the relevant pins? + } + + void DCCTimer::getSimulatedMacAddress(byte mac[6]) { +#if defined(__IMXRT1062__) //Teensy 4.0 and Teensy 4.1 + uint32_t m1 = HW_OCOTP_MAC1; + uint32_t m2 = HW_OCOTP_MAC0; + mac[0] = m1 >> 8; + mac[1] = m1 >> 0; + mac[2] = m2 >> 24; + mac[3] = m2 >> 16; + mac[4] = m2 >> 8; + mac[5] = m2 >> 0; +#else + read_mac(mac); +#endif +} + +#if !defined(__IMXRT1062__) +void DCCTimer::read_mac(byte mac[6]) { + read(0xe,mac,0); + read(0xf,mac,3); +} + +// http://forum.pjrc.com/threads/91-teensy-3-MAC-address +void DCCTimer::read(uint8_t word, uint8_t *mac, uint8_t offset) { + FTFL_FCCOB0 = 0x41; // Selects the READONCE command + FTFL_FCCOB1 = word; // read the given word of read once area + + // launch command and wait until complete + FTFL_FSTAT = FTFL_FSTAT_CCIF; + while(!(FTFL_FSTAT & FTFL_FSTAT_CCIF)); + + *(mac+offset) = FTFL_FCCOB5; // collect only the top three bytes, + *(mac+offset+1) = FTFL_FCCOB6; // in the right orientation (big endian). + *(mac+offset+2) = FTFL_FCCOB7; // Skip FTFL_FCCOB4 as it's always 0. +} +#endif + #else // Arduino nano, uno, mega etc #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) diff --git a/DCCTimer.h b/DCCTimer.h index dfe9ef2..0c3274c 100644 --- a/DCCTimer.h +++ b/DCCTimer.h @@ -10,6 +10,10 @@ class DCCTimer { static void getSimulatedMacAddress(byte mac[6]); static bool isPWMPin(byte pin); static void setPWM(byte pin, bool high); +#if (defined(TEENSYDUINO) && !defined(__IMXRT1062__)) + static void read_mac(byte mac[6]); + static void read(uint8_t word, uint8_t *mac, uint8_t offset); +#endif private: }; diff --git a/DCCWaveform.cpp b/DCCWaveform.cpp index 8d695e5..c87f768 100644 --- a/DCCWaveform.cpp +++ b/DCCWaveform.cpp @@ -53,8 +53,10 @@ void DCCWaveform::begin(MotorDriver * mainDriver, MotorDriver * progDriver) { } void DCCWaveform::loop(bool ackManagerActive) { + noInterrupts(); mainTrack.checkPowerOverload(false); progTrack.checkPowerOverload(ackManagerActive); + interrupts(); } void DCCWaveform::interruptHandler() { diff --git a/EthernetInterface.h b/EthernetInterface.h index 87bb8b6..df6504d 100644 --- a/EthernetInterface.h +++ b/EthernetInterface.h @@ -31,8 +31,12 @@ #include "DCCEXParser.h" #include #include -#include -#include "RingStream.h" +#if defined (ARDUINO_TEENSY41) + #include //TEENSY Ethernet Treiber + #include +#else + #include "Ethernet.h" +#endif#include "RingStream.h" /** * @brief Network Configuration diff --git a/MotorDriver.h b/MotorDriver.h index 2af1b58..f659918 100644 --- a/MotorDriver.h +++ b/MotorDriver.h @@ -26,11 +26,19 @@ #define UNUSED_PIN 127 // inside int8_t #endif +#if defined(__IMXRT1062__) +struct FASTPIN { + volatile uint32_t *inout; + uint32_t maskHIGH; + uint32_t maskLOW; +}; +#else struct FASTPIN { volatile uint8_t *inout; uint8_t maskHIGH; uint8_t maskLOW; }; +#endif class MotorDriver { public: diff --git a/defines.h b/defines.h index 5c08f01..c3454c1 100644 --- a/defines.h +++ b/defines.h @@ -23,7 +23,7 @@ // WIFI_ON: All prereqs for running with WIFI are met // Note: WIFI_CHANNEL may not exist in early config.h files so is added here if needed. -#if ENABLE_WIFI && (defined(ARDUINO_AVR_MEGA) || defined(ARDUINO_AVR_MEGA2560) || defined(ARDUINO_SAMD_ZERO)) +#if ENABLE_WIFI && (defined(ARDUINO_AVR_MEGA) || defined(ARDUINO_AVR_MEGA2560) || defined(ARDUINO_SAMD_ZERO)) || defined(Teensyduino) #define WIFI_ON true #ifndef WIFI_CHANNEL #define WIFI_CHANNEL 1 @@ -32,7 +32,7 @@ #define WIFI_ON false #endif -#if ENABLE_ETHERNET && (defined(ARDUINO_AVR_MEGA) || defined(ARDUINO_AVR_MEGA2560) || defined(ARDUINO_SAMD_ZERO)) +#if ENABLE_ETHERNET && (defined(ARDUINO_AVR_MEGA) || defined(ARDUINO_AVR_MEGA2560) || defined(ARDUINO_SAMD_ZERO)) || defined(Teensyduino) #define ETHERNET_ON true #else #define ETHERNET_ON false