From c711be798079883a5d215c9cbec0573033f1c7c0 Mon Sep 17 00:00:00 2001 From: Harald Barth Date: Mon, 22 Nov 2021 23:26:04 +0100 Subject: [PATCH] DCCTrack::schedulePacket allows multiple different motordrivers side by side --- DCC.cpp | 30 +++++++++++++++--------- DCCEXParser.cpp | 3 ++- DCCPacket.h | 12 ++++++++++ DCCRMT.cpp | 20 ++++++++++++---- DCCRMT.h | 4 +++- DCCTrack.cpp | 38 ++++++++++++++++++++++++++++++ DCCTrack.h | 20 ++++++++++++++++ DCCWaveform.cpp | 24 ++++++++++--------- DCCWaveform.h | 10 ++++---- GITHUB_SHA.h | 2 +- IO_GPIOBase.h | 6 ++++- IO_MCP23008.h | 6 ----- MotorDriver.cpp | 61 +++++++++++++++++++++++++++++++++++++++---------- MotorDriver.h | 31 +++++++++++++++++++++++-- 14 files changed, 211 insertions(+), 56 deletions(-) create mode 100644 DCCPacket.h create mode 100644 DCCTrack.cpp create mode 100644 DCCTrack.h diff --git a/DCC.cpp b/DCC.cpp index 4d30b98..fe0fbb4 100644 --- a/DCC.cpp +++ b/DCC.cpp @@ -20,6 +20,7 @@ #include "DIAG.h" #include "DCC.h" #include "DCCWaveform.h" +#include "DCCTrack.h" #include "EEStore.h" #include "GITHUB_SHA.h" #include "version.h" @@ -62,7 +63,13 @@ void DCC::begin() { (void)EEPROM; // tell compiler not to warn this is unused EEStore::init(); - DCCWaveform::begin(mDC.mainTrack(),mDC.progTrack()); + DCCWaveform::begin(mDC.mainTrack(),mDC.progTrack()); + DCCTrack::mainTrack.addDriver(mDC.mainTrack()); + DCCTrack::progTrack.addDriver(mDC.progTrack()); + + MotorDriver *md; + mDC.add(2, md = new MotorDriver(16, 21, UNUSED_PIN, UNUSED_PIN, UNUSED_PIN, 2.00, 2000, UNUSED_PIN, RMT_MAIN)); + DCCTrack::mainTrack.addDriver(md); } void DCC::setJoinRelayPin(byte joinRelayPin) { @@ -118,7 +125,7 @@ void DCC::setThrottle2( uint16_t cab, byte speedCode) { } - DCCWaveform::mainTrack.schedulePacket(b, nB, 0); + DCCTrack::mainTrack.schedulePacket(b, nB, 0); } void DCC::setFunctionInternal(int cab, byte byte1, byte byte2) { @@ -132,7 +139,7 @@ void DCC::setFunctionInternal(int cab, byte byte1, byte byte2) { if (byte1!=0) b[nB++] = byte1; b[nB++] = byte2; - DCCWaveform::mainTrack.schedulePacket(b, nB, 0); + DCCTrack::mainTrack.schedulePacket(b, nB, 0); } uint8_t DCC::getThrottleSpeed(int cab) { @@ -167,7 +174,7 @@ void DCC::setFn( int cab, int16_t functionNumber, bool on) { b[nB++] = (functionNumber & 0x7F) | (on ? 0x80 : 0); // low order bits and state flag b[nB++] = functionNumber >>7 ; // high order bits } - DCCWaveform::mainTrack.schedulePacket(b, nB, 4); + DCCTrack::mainTrack.schedulePacket(b, nB, 3); return; } @@ -254,7 +261,7 @@ void DCC::setAccessory(int address, byte number, bool activate) { b[0] = address % 64 + 128; // first byte is of the form 10AAAAAA, where AAAAAA represent 6 least signifcant bits of accessory address b[1] = ((((address / 64) % 8) << 4) + (number % 4 << 1) + activate % 2) ^ 0xF8; // second byte is of the form 1AAACDDD, where C should be 1, and the least significant D represent activate/deactivate - DCCWaveform::mainTrack.schedulePacket(b, 2, 4); // Repeat the packet four times + DCCTrack::mainTrack.schedulePacket(b, 2, 3); // Repeat the packet four times (3 2 1 0) } // @@ -272,7 +279,7 @@ void DCC::writeCVByteMain(int cab, int cv, byte bValue) { b[nB++] = cv2(cv); b[nB++] = bValue; - DCCWaveform::mainTrack.schedulePacket(b, nB, 4); + DCCTrack::mainTrack.schedulePacket(b, nB, 3); } // @@ -293,7 +300,7 @@ void DCC::writeCVBitMain(int cab, int cv, byte bNum, bool bValue) { b[nB++] = cv2(cv); b[nB++] = WRITE_BIT | (bValue ? BIT_ON : BIT_OFF) | bNum; - DCCWaveform::mainTrack.schedulePacket(b, nB, 4); + DCCTrack::mainTrack.schedulePacket(b, nB, 3); } void DCC::setProgTrackSyncMain(bool on) { @@ -571,6 +578,7 @@ byte DCC::loopStatus=0; void DCC::loop() { DCCWaveform::loop(ackManagerProg!=NULL); // power overload checks + mDC.loop(); ackManagerLoop(); // maintain prog track ack manager issueReminders(); } @@ -771,7 +779,7 @@ void DCC::ackManagerLoop() { if (Diag::ACK) DIAG(F("W%d cv=%d bit=%d"),opcode==W1, ackManagerCv,ackManagerBitNum); byte instruction = WRITE_BIT | (opcode==W1 ? BIT_ON : BIT_OFF) | ackManagerBitNum; byte message[] = {cv1(BIT_MANIPULATE, ackManagerCv), cv2(ackManagerCv), instruction }; - DCCWaveform::progTrack.schedulePacket(message, sizeof(message), PROG_REPEATS); + DCCTrack::progTrack.schedulePacket(message, sizeof(message), PROG_REPEATS); DCCWaveform::progTrack.setAckPending(); callbackState=AFTER_WRITE; } @@ -782,7 +790,7 @@ void DCC::ackManagerLoop() { if (checkResets( RESET_MIN)) return; if (Diag::ACK) DIAG(F("WB cv=%d value=%d"),ackManagerCv,ackManagerByte); byte message[] = {cv1(WRITE_BYTE, ackManagerCv), cv2(ackManagerCv), ackManagerByte}; - DCCWaveform::progTrack.schedulePacket(message, sizeof(message), PROG_REPEATS); + DCCTrack::progTrack.schedulePacket(message, sizeof(message), PROG_REPEATS); DCCWaveform::progTrack.setAckPending(); callbackState=AFTER_WRITE; } @@ -793,7 +801,7 @@ void DCC::ackManagerLoop() { if (checkResets( RESET_MIN)) return; if (Diag::ACK) DIAG(F("VB cv=%d value=%d"),ackManagerCv,ackManagerByte); byte message[] = { cv1(VERIFY_BYTE, ackManagerCv), cv2(ackManagerCv), ackManagerByte}; - DCCWaveform::progTrack.schedulePacket(message, sizeof(message), PROG_REPEATS); + DCCTrack::progTrack.schedulePacket(message, sizeof(message), PROG_REPEATS); DCCWaveform::progTrack.setAckPending(); } break; @@ -805,7 +813,7 @@ void DCC::ackManagerLoop() { if (Diag::ACK) DIAG(F("V%d cv=%d bit=%d"),opcode==V1, ackManagerCv,ackManagerBitNum); byte instruction = VERIFY_BIT | (opcode==V0?BIT_OFF:BIT_ON) | ackManagerBitNum; byte message[] = {cv1(BIT_MANIPULATE, ackManagerCv), cv2(ackManagerCv), instruction }; - DCCWaveform::progTrack.schedulePacket(message, sizeof(message), PROG_REPEATS); + DCCTrack::progTrack.schedulePacket(message, sizeof(message), PROG_REPEATS); DCCWaveform::progTrack.setAckPending(); } break; diff --git a/DCCEXParser.cpp b/DCCEXParser.cpp index 0757c29..7a8ed3b 100644 --- a/DCCEXParser.cpp +++ b/DCCEXParser.cpp @@ -22,6 +22,7 @@ #include "StringFormatter.h" #include "DCCEXParser.h" #include "DCCWaveform.h" +#include "DCCTrack.h" #include "Turnouts.h" #include "Outputs.h" #include "Sensors.h" @@ -413,7 +414,7 @@ void DCCEXParser::parse(Print *stream, byte *com, RingStream * ringStream) packet[i]=(byte)p[i+1]; if (Diag::CMD) DIAG(F("packet[%d]=%d (0x%x)"), i, packet[i], packet[i]); } - (opcode=='M'?DCCWaveform::mainTrack:DCCWaveform::progTrack).schedulePacket(packet,params,3); + (opcode=='M'?DCCTrack::mainTrack:DCCTrack::progTrack).schedulePacket(packet,params,3); } return; diff --git a/DCCPacket.h b/DCCPacket.h new file mode 100644 index 0000000..261cff3 --- /dev/null +++ b/DCCPacket.h @@ -0,0 +1,12 @@ +#pragma once + +const byte MAX_PACKET_SIZE = 5; // NMRA standard extended packets, payload size WITHOUT checksum. + +class dccPacket { + public: + byte data[MAX_PACKET_SIZE+1]; // space for checksum if needed + byte length : 4; // future proof up to 15 + byte repeat : 4; // hopefully 15 enough for ever + //byte priority : 2; // 0 repeats; 1 mobile function ; 2 accessory ; 3 mobile speed +}; + diff --git a/DCCRMT.cpp b/DCCRMT.cpp index 108bac9..95d0e9a 100644 --- a/DCCRMT.cpp +++ b/DCCRMT.cpp @@ -131,15 +131,25 @@ void RMTChannel::RMTprefill() { const byte transmitMask[] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}; -bool RMTChannel::RMTfillData(const byte buffer[], byte byteCount, byte repeatCount=1) { +//bool RMTChannel::RMTfillData(const byte buffer[], byte byteCount, byte repeatCount=0) { +bool RMTChannel::RMTfillData(dccPacket packet) { + // dataReady: Signals to then interrupt routine. It is set when + // we have data in the channel buffer which can be copied out + // to the HW. dataRepeat on the other hand signals back to + // the caller of this function if the data has been sent enough + // times (0 to 3 means 1 to 4 times in total). if (dataReady == true || dataRepeat > 0) // we have still old work to do return false; - if (DATA_LEN(byteCount) > maxDataLen) // this would overun our allocated memory for data - return false; // something very broken, can not convert packet + if (DATA_LEN(packet.length) > maxDataLen) { // this would overun our allocated memory for data + DIAG(F("Can not convert DCC bytes # %d to DCC bits %d, buffer too small"), packet.length, maxDataLen); + return false; // something very broken, can not convert packet + } + byte *buffer = packet.data; + // convert bytes to RMT stream of "bits" byte bitcounter = 0; - for(byte n=0; n #if defined(ARDUINO_ARCH_ESP32) +#include "DCCPacket.h" #include "driver/rmt.h" #include "soc/rmt_reg.h" #include "soc/rmt_struct.h" @@ -34,7 +35,8 @@ class RMTChannel { RMTChannel(byte pin, byte ch, byte plen); void IRAM_ATTR RMTinterrupt(); void RMTprefill(); - bool RMTfillData(const byte buffer[], byte byteCount, byte repeatCount); + bool RMTfillData(dccPacket packet); + //bool RMTfillData(const byte buffer[], byte byteCount, byte repeatCount); static RMTChannel mainRMTChannel; static RMTChannel progRMTChannel; diff --git a/DCCTrack.cpp b/DCCTrack.cpp new file mode 100644 index 0000000..e0896d0 --- /dev/null +++ b/DCCTrack.cpp @@ -0,0 +1,38 @@ + +#include "defines.h" +#include "DCCTrack.h" +#include "DIAG.h" + +DCCTrack::DCCTrack(DCCWaveform *w) { + waveform = w; +} + +void DCCTrack::schedulePacket(const byte buffer[], byte byteCount, byte repeats) { + dccPacket packet; + + // add checksum now, makes stuff easier later + byte checksum = 0; + for (byte b = 0; b < byteCount; b++) { + checksum ^= buffer[b]; + packet.data[b] = buffer[b]; + } + packet.data[byteCount] = checksum; + packet.length = byteCount + 1; + packet.repeat = repeats; + schedulePacket(packet); +}; + +void DCCTrack::schedulePacket(dccPacket packet) { + bool once=true; + for (const auto& driver: mD) { + if (driver->type() == RMT_MAIN || driver->type() == RMT_PROG) { + //DIAG(F("DCCTrack::schedulePacket RMT l=%d d=%x"),packet.length, packet.data[0]); + driver->schedulePacket(packet); + } + if (driver->type() == TIMERINTERRUPT && waveform && once) { + //DIAG(F("DCCTrack::schedulePacket WAVE l=%d d=%x"),packet.length, packet.data[0]); + waveform->schedulePacket(packet); + once=false; + } + } +} diff --git a/DCCTrack.h b/DCCTrack.h new file mode 100644 index 0000000..86ce98d --- /dev/null +++ b/DCCTrack.h @@ -0,0 +1,20 @@ + +#pragma once +#include +#include "DCCPacket.h" +#include "DCCWaveform.h" + +class DCCTrack { + public: + DCCTrack(DCCWaveform *w); + void schedulePacket(const byte buffer[], byte byteCount, byte repeats); + void schedulePacket(dccPacket packet); + inline void addDriver(MotorDriver *m) { mD.push_back(m); }; + static DCCTrack mainTrack; + static DCCTrack progTrack; + private: + DCCWaveform *waveform; + std::vectormD; +}; + + diff --git a/DCCWaveform.cpp b/DCCWaveform.cpp index 1cf3011..85bf40b 100644 --- a/DCCWaveform.cpp +++ b/DCCWaveform.cpp @@ -22,6 +22,7 @@ #include "defines.h" #include "DCCWaveform.h" +#include "DCCTrack.h" #include "DCCTimer.h" #include "DIAG.h" #include "freeMemory.h" @@ -29,6 +30,9 @@ DCCWaveform DCCWaveform::mainTrack(PREAMBLE_BITS_MAIN, true); DCCWaveform DCCWaveform::progTrack(PREAMBLE_BITS_PROG, false); +DCCTrack DCCTrack::mainTrack(&DCCWaveform::mainTrack); +DCCTrack DCCTrack::progTrack(&DCCWaveform::progTrack); + bool DCCWaveform::progTrackSyncMain=false; bool DCCWaveform::progTrackBoosted=false; int DCCWaveform::progTripValue=0; @@ -38,8 +42,6 @@ uint8_t DCCWaveform::trailingEdgeCounter=0; void DCCWaveform::begin(MotorDriver * mainDriver, MotorDriver * progDriver) { - mainTrack.rmtPin = new RMTChannel(21, 0, PREAMBLE_BITS_MAIN); - mainTrack.motorDriver=mainDriver; progTrack.motorDriver=progDriver; progTripValue = progDriver->mA2raw(TRIP_CURRENT_PROG); // need only calculate once hence static @@ -62,11 +64,11 @@ volatile bool ackflag = 0; void IRAM_ATTR DCCWaveform::loop(bool ackManagerActive) { - if (mainTrack.packetPendingRMT) { - mainTrack.rmtPin->RMTfillData(mainTrack.pendingPacket, mainTrack.pendingLength, mainTrack.pendingRepeats); - mainTrack.packetPendingRMT=false; + //if (mainTrack.packetPendingRMT) { + // mainTrack.rmtPin->RMTfillData(mainTrack.pendingPacket, mainTrack.pendingLength, mainTrack.pendingRepeats); + // mainTrack.packetPendingRMT=false; // sentResetsSincePacket = 0 // later when progtrack - } + //} #ifdef SLOW_ANALOG_READ if (ackflag) { @@ -305,17 +307,17 @@ void IRAM_ATTR DCCWaveform::interrupt2() { // Wait until there is no packet pending, then make this pending void DCCWaveform::schedulePacket(const byte buffer[], byte byteCount, byte repeats) { - if (byteCount > MAX_PACKET_SIZE) return; // allow for chksum + if (byteCount > MAX_PACKET_SIZE+1) return; // has chksum while (packetPending); portENTER_CRITICAL(&timerMux); - byte checksum = 0; + //byte checksum = 0; for (byte b = 0; b < byteCount; b++) { - checksum ^= buffer[b]; + //checksum ^= buffer[b]; pendingPacket[b] = buffer[b]; } // buffer is MAX_PACKET_SIZE but pendingPacket is one bigger - pendingPacket[byteCount] = checksum; - pendingLength = byteCount + 1; + //pendingPacket[byteCount] = checksum; + pendingLength = byteCount /*+ 1*/; pendingRepeats = repeats; packetPending = true; packetPendingRMT = true; diff --git a/DCCWaveform.h b/DCCWaveform.h index ef8773a..4f61fa4 100644 --- a/DCCWaveform.h +++ b/DCCWaveform.h @@ -28,10 +28,8 @@ const int POWER_SAMPLE_ON_WAIT = 100; const int POWER_SAMPLE_OFF_WAIT = 1000; const int POWER_SAMPLE_OVERLOAD_WAIT = 20; -// Number of preamble bits. -const int PREAMBLE_BITS_MAIN = 16; -const int PREAMBLE_BITS_PROG = 22; -const byte MAX_PACKET_SIZE = 5; // NMRA standard extended packets, payload size WITHOUT checksum. +//const byte MAX_PACKET_SIZE = 5; // NMRA standard extended packets, payload size WITHOUT checksum. +#include "DCCPacket.h" // The WAVE_STATE enum is deliberately numbered because a change of order would be catastrophic // to the transform array. @@ -81,6 +79,9 @@ class DCCWaveform { } return tripmA; } + inline void schedulePacket(dccPacket packet) { + schedulePacket(packet.data, packet.length, packet.repeat); + }; void schedulePacket(const byte buffer[], byte byteCount, byte repeats); volatile bool packetPending; volatile bool packetPendingRMT; @@ -124,7 +125,6 @@ class DCCWaveform { bool isMainTrack; MotorDriver* motorDriver; - RMTChannel* rmtPin; // Transmission controller byte transmitPacket[MAX_PACKET_SIZE+1]; // +1 for checksum byte transmitLength; diff --git a/GITHUB_SHA.h b/GITHUB_SHA.h index 4fe3dd6..fba9fe3 100644 --- a/GITHUB_SHA.h +++ b/GITHUB_SHA.h @@ -1 +1 @@ -#define GITHUB_SHA "ESP32-motordriver-2021121-22:55" +#define GITHUB_SHA "ESP32-motordriver-2021122-23:21" diff --git a/IO_GPIOBase.h b/IO_GPIOBase.h index 4269a70..3bc75af 100644 --- a/IO_GPIOBase.h +++ b/IO_GPIOBase.h @@ -69,6 +69,10 @@ protected: I2CRB requestBlock; FSH *_deviceName; +#if defined(ARDUINO_ARCH_ESP32) + // workaround: Has somehow no min function for all types + static inline T min(T a, int b) { return a < b ? a : b; }; +#endif }; // Because class GPIOBase is a template, the implementation (below) must be contained within the same @@ -246,4 +250,4 @@ int GPIOBase::_read(VPIN vpin) { return (_portInputState & mask) ? 0 : 1; // Invert state (5v=0, 0v=1) } -#endif \ No newline at end of file +#endif diff --git a/IO_MCP23008.h b/IO_MCP23008.h index 1b8471e..fa19d01 100644 --- a/IO_MCP23008.h +++ b/IO_MCP23008.h @@ -22,12 +22,6 @@ #include "IO_GPIOBase.h" -#if defined(ARDUINO_ARCH_ESP32) // min seems to be missing from that package -#ifndef min -#define min(a,b) ((a)<(b)?(a):(b)) -#endif -#endif - class MCP23008 : public GPIOBase { public: static void create(VPIN firstVpin, uint8_t nPins, uint8_t I2CAddress, int interruptPin=-1) { diff --git a/MotorDriver.cpp b/MotorDriver.cpp index 2675249..cb8e55d 100644 --- a/MotorDriver.cpp +++ b/MotorDriver.cpp @@ -31,22 +31,33 @@ bool MotorDriver::usePWM=false; bool MotorDriver::commonFaultPin=false; MotorDriver::MotorDriver(byte power_pin, byte signal_pin, byte signal_pin2, int8_t brake_pin, - byte current_pin, float sense_factor, unsigned int trip_milliamps, byte fault_pin) { + byte current_pin, float sense_factor, unsigned int trip_milliamps, byte fault_pin, + driverType dt) { + dtype = dt; powerPin=power_pin; getFastPin(F("POWER"),powerPin,fastPowerPin); pinMode(powerPin, OUTPUT); - - signalPin=signal_pin; - getFastPin(F("SIG"),signalPin,fastSignalPin); - pinMode(signalPin, OUTPUT); - - signalPin2=signal_pin2; - if (signalPin2!=UNUSED_PIN) { - dualSignal=true; - getFastPin(F("SIG2"),signalPin2,fastSignalPin2); - pinMode(signalPin2, OUTPUT); + + if (dtype == RMT_MAIN) { + signalPin=signal_pin; +#if defined(ARDUINO_ARCH_ESP32) + rmtChannel = new RMTChannel(signalPin, 0, PREAMBLE_BITS_MAIN); +#endif + dualSignal=false; + } else if (dtype == TIMERINTERRUPT) { + signalPin=signal_pin; + getFastPin(F("SIG"),signalPin,fastSignalPin); + pinMode(signalPin, OUTPUT); + + signalPin2=signal_pin2; + if (signalPin2!=UNUSED_PIN) { + dualSignal=true; + getFastPin(F("SIG2"),signalPin2,fastSignalPin2); + pinMode(signalPin2, OUTPUT); + } else { + dualSignal=false; + } } - else dualSignal=false; brakePin=brake_pin; if (brake_pin!=UNUSED_PIN){ @@ -197,6 +208,21 @@ void MotorDriver::getFastPin(const FSH* type,int pin, bool input, FASTPIN & res // DIAG(F(" port=0x%x, inoutpin=0x%x, isinput=%d, mask=0x%x"),port, result.inout,input,result.maskHIGH); } +bool MotorDriver::schedulePacket(dccPacket packet) { + if(!rmtChannel) return true; // fake success if functionality is not there + + outQueue.push(packet); + if (outQueue.size() > 10) { + DIAG(F("Warning: outQueue > 10")); + } + return true; +} + +void MotorDriver::loop() { + if (rmtChannel && !outQueue.empty() && rmtChannel->RMTfillData(outQueue.front())) + outQueue.pop(); +} + MotorDriverContainer::MotorDriverContainer(const FSH * motorShieldName, MotorDriver *m0, MotorDriver *m1, @@ -217,4 +243,15 @@ MotorDriverContainer::MotorDriverContainer(const FSH * motorShieldName, shieldName = (FSH *)motorShieldName; } +void MotorDriverContainer::loop() { + static byte i = 0; + + // loops over MotorDrivers which have loop tasks + if (mD[i]) + if (mD[i]->type() == RMT_MAIN || mD[i]->type() == RMT_PROG) + mD[i]->loop(); + i++; + if(i > 7) i=0; +} + MotorDriverContainer mDC(MOTOR_SHIELD_TYPE); diff --git a/MotorDriver.h b/MotorDriver.h index a4a389d..77f645a 100644 --- a/MotorDriver.h +++ b/MotorDriver.h @@ -16,12 +16,20 @@ * You should have received a copy of the GNU General Public License * along with CommandStation. If not, see . */ + #ifndef MotorDriver_h #define MotorDriver_h #include "defines.h" #include "FSH.h" -// Virtualised Motor shield 1-track hardware Interface +#if defined(ARDUINO_ARCH_ESP32) +#include +#include "DCCRMT.h" +#endif + +// Number of preamble bits (moved here so MotorDriver and Waveform know) +const int PREAMBLE_BITS_MAIN = 16; +const int PREAMBLE_BITS_PROG = 22; #ifndef UNUSED_PIN // sync define with the one in MotorDrivers.h #define UNUSED_PIN 127 // inside int8_t @@ -48,10 +56,13 @@ struct FASTPIN { #define isHIGH(fastpin) (*fastpin.inout & fastpin.maskHIGH) #define isLOW(fastpin) (!isHIGH(fastpin)) +enum driverType { TIMERINTERRUPT, RMT_MAIN, RMT_PROG, DC_ENA, DC_BRAKE }; + class MotorDriver { public: MotorDriver(byte power_pin, byte signal_pin, byte signal_pin2, int8_t brake_pin, - byte current_pin, float senseFactor, unsigned int tripMilliamps, byte faultPin); + byte current_pin, float senseFactor, unsigned int tripMilliamps, byte faultPin, + driverType t=TIMERINTERRUPT); void setPower( bool on); void setSignal( bool high); void setBrake( bool on); @@ -68,6 +79,12 @@ class MotorDriver { inline byte getFaultPin() { return faultPin; } +#if defined(ARDUINO_ARCH_ESP32) + void loop(); + inline driverType type() { return dtype; }; + bool schedulePacket(dccPacket packet); +#endif + private: void getFastPin(const FSH* type,int pin, bool input, FASTPIN & result); void getFastPin(const FSH* type,int pin, FASTPIN & result) { @@ -92,6 +109,11 @@ class MotorDriver { if (doit) __enable_irq(); } #endif +#if defined(ARDUINO_ARCH_ESP32) + RMTChannel* rmtChannel; + std::queue outQueue; + driverType dtype; +#endif }; class MotorDriverContainer { @@ -105,10 +127,15 @@ public: MotorDriver *m5=NULL, MotorDriver *m6=NULL, MotorDriver *m7=NULL); + inline void add(byte n, MotorDriver *m) { + if (n>8) return; + mD[n] = m; + }; // void SetCapability(byte n, byte cap, char [] name); inline FSH *getMotorShieldName() { return shieldName; }; inline MotorDriver *mainTrack() { return mD[0]; }; //start fixed inline MotorDriver *progTrack() { return mD[1]; }; + void loop(); private: MotorDriver *mD[8];