1
0
mirror of https://github.com/DCC-EX/CommandStation-EX.git synced 2024-11-26 17:46:14 +01:00

Revisions to support Teensy 3.x and Teensy 4.x

This commit is contained in:
Mike S 2021-03-25 13:16:12 -04:00
parent 76c2b5ae91
commit 8141311e66
10 changed files with 147 additions and 77 deletions

12
DCC.cpp
View File

@ -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);
}

16
DCC.h
View File

@ -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

View File

@ -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 <t [REGISTER] CAB SPEED DIRECTION>
{
int cab;
int tspeed;
int direction;
int16_t cab;
int16_t tspeed;
int16_t direction;
if (params == 4)
{ // <t REGISTER CAB SPEED DIRECTION>
@ -561,7 +558,7 @@ void DCCEXParser::parse(Print *stream, byte *com, RingStream * ringStream)
StringFormatter::send(stream, F("<X>"));
}
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;

View File

@ -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);
};

View File

@ -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__)

View File

@ -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:
};

View File

@ -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() {

View File

@ -31,8 +31,12 @@
#include "DCCEXParser.h"
#include <Arduino.h>
#include <avr/pgmspace.h>
#include <Ethernet.h>
#include "RingStream.h"
#if defined (ARDUINO_TEENSY41)
#include <NativeEthernet.h> //TEENSY Ethernet Treiber
#include <NativeEthernetUdp.h>
#else
#include "Ethernet.h"
#endif#include "RingStream.h"
/**
* @brief Network Configuration

View File

@ -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:

View File

@ -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