diff --git a/CommandStation-EX.ino b/CommandStation-EX.ino index ee7245b..872dc2b 100644 --- a/CommandStation-EX.ino +++ b/CommandStation-EX.ino @@ -85,11 +85,7 @@ void setup() #endif // ETHERNET_ON // Responsibility 3: Start the DCC engine. - // Note: this provides DCC with two motor drivers, main and prog, which handle the motor shield(s) - // Standard supported devices have pre-configured macros but custome hardware installations require - // detailed pin mappings and may also require modified subclasses of the MotorDriver to implement specialist logic. - // STANDARD_MOTOR_SHIELD, POLOLU_MOTOR_SHIELD, FIREBOX_MK1, FIREBOX_MK1S are pre defined in MotorShields.h - DCC::begin(MOTOR_SHIELD_TYPE); + DCC::begin(); // Start RMFT (ignored if no automnation) RMFT::begin(); diff --git a/DCC.cpp b/DCC.cpp index 76bb917..4d30b98 100644 --- a/DCC.cpp +++ b/DCC.cpp @@ -26,6 +26,9 @@ #include "FSH.h" #include "IODevice.h" +#include "MotorDriver.h" +extern MotorDriverContainer mDC; + // This module is responsible for converting API calls into // messages to be sent to the waveform generator. // It has no visibility of the hardware, timers, interrupts @@ -49,9 +52,8 @@ FSH* DCC::shieldName=NULL; byte DCC::joinRelay=UNUSED_PIN; byte DCC::globalSpeedsteps=128; -void DCC::begin(const FSH * motorShieldName, MotorDriver * mainDriver, MotorDriver* progDriver) { - shieldName=(FSH *)motorShieldName; - StringFormatter::send(Serial,F("\n"), F(VERSION), F(ARDUINO_TYPE), shieldName, F(GITHUB_SHA)); +void DCC::begin() { + StringFormatter::send(Serial,F("\n"), F(VERSION), F(ARDUINO_TYPE), mDC.getMotorShieldName(), F(GITHUB_SHA)); // Initialise HAL layer before reading EEprom. IODevice::begin(); @@ -60,7 +62,7 @@ void DCC::begin(const FSH * motorShieldName, MotorDriver * mainDriver, MotorDriv (void)EEPROM; // tell compiler not to warn this is unused EEStore::init(); - DCCWaveform::begin(mainDriver,progDriver); + DCCWaveform::begin(mDC.mainTrack(),mDC.progTrack()); } void DCC::setJoinRelayPin(byte joinRelayPin) { diff --git a/DCC.h b/DCC.h index cb03949..19b4e02 100644 --- a/DCC.h +++ b/DCC.h @@ -77,7 +77,7 @@ const byte MAX_LOCOS = 50; class DCC { public: - static void begin(const FSH * motorShieldName, MotorDriver *mainDriver, MotorDriver *progDriver); + static void begin(); static void setJoinRelayPin(byte joinRelayPin); static void loop(); diff --git a/DCCWaveform.cpp b/DCCWaveform.cpp index 91f0a5d..a9f09f9 100644 --- a/DCCWaveform.cpp +++ b/DCCWaveform.cpp @@ -92,8 +92,10 @@ void IRAM_ATTR DCCWaveform::interruptHandler() { byte sigMain=signalTransform[mainTrack.state]; byte sigProg=progTrackSyncMain? sigMain : signalTransform[progTrack.state]; // Set the signal state for both tracks - mainTrack.motorDriver->setSignal(sigMain); - progTrack.motorDriver->setSignal(sigProg); + if (mainTrack.motorDriver) + mainTrack.motorDriver->setSignal(sigMain); + if (progTrack.motorDriver) + progTrack.motorDriver->setSignal(sigProg); // Move on in the state engine mainTrack.state=stateTransform[mainTrack.state]; progTrack.state=stateTransform[progTrack.state]; @@ -148,12 +150,14 @@ POWERMODE DCCWaveform::getPowerMode() { void DCCWaveform::setPowerMode(POWERMODE mode) { powerMode = mode; bool ison = (mode == POWERMODE::ON); - motorDriver->setPower( ison); + if (motorDriver) + motorDriver->setPower( ison); sentResetsSincePacket=0; } void DCCWaveform::checkPowerOverload(bool ackManagerActive) { + if (!motorDriver) return; if (millis() - lastSampleTaken < sampleDelay) return; lastSampleTaken = millis(); int tripValue= motorDriver->getRawCurrentTripValue(); @@ -323,6 +327,7 @@ void DCCWaveform::schedulePacket(const byte buffer[], byte byteCount, byte repea // (yes I know I could have subclassed the main track but...) void DCCWaveform::setAckBaseline() { + if (!motorDriver) return; if (isMainTrack) return; int baseline=motorDriver->getCurrentRaw(); ackThreshold= baseline + motorDriver->mA2raw(ackLimitmA); @@ -345,6 +350,7 @@ void DCCWaveform::setAckPending() { } byte DCCWaveform::getAck() { + if (!motorDriver) return 0; if (ackPending) return (2); // still waiting if (Diag::ACK) DIAG(F("%S after %dmS max=%d/%dmA pulse=%duS samples=%d gaps=%d"),ackDetected?F("ACK"):F("NO-ACK"), ackCheckDuration, ackMaxCurrent,motorDriver->raw2mA(ackMaxCurrent), ackPulseDuration, numAckSamples, numAckGaps); @@ -355,6 +361,7 @@ byte DCCWaveform::getAck() { #pragma GCC push_options #pragma GCC optimize ("-O3") void IRAM_ATTR DCCWaveform::checkAck() { + if (!motorDriver) return; // This function operates in interrupt() time so must be fast and can't DIAG if (sentResetsSincePacket > 6) { //ACK timeout ackCheckDuration=millis()-ackCheckStart; diff --git a/MotorDriver.cpp b/MotorDriver.cpp index 11d56d8..2675249 100644 --- a/MotorDriver.cpp +++ b/MotorDriver.cpp @@ -17,6 +17,8 @@ * along with CommandStation. If not, see . */ #include +#include "config.h" +#include "defines.h" #include "MotorDriver.h" #include "DCCTimer.h" #include "DIAG.h" @@ -194,3 +196,25 @@ void MotorDriver::getFastPin(const FSH* type,int pin, bool input, FASTPIN & res result.maskLOW = ~result.maskHIGH; // DIAG(F(" port=0x%x, inoutpin=0x%x, isinput=%d, mask=0x%x"),port, result.inout,input,result.maskHIGH); } + +MotorDriverContainer::MotorDriverContainer(const FSH * motorShieldName, + MotorDriver *m0, + MotorDriver *m1, + MotorDriver *m2, + MotorDriver *m3, + MotorDriver *m4, + MotorDriver *m5, + MotorDriver *m6, + MotorDriver *m7) { + mD[0]=m0; + mD[1]=m1; + mD[2]=m2; + mD[3]=m3; + mD[4]=m4; + mD[5]=m5; + mD[6]=m6; + mD[7]=m7; + shieldName = (FSH *)motorShieldName; +} + +MotorDriverContainer mDC(MOTOR_SHIELD_TYPE); diff --git a/MotorDriver.h b/MotorDriver.h index 9193828..cd311a8 100644 --- a/MotorDriver.h +++ b/MotorDriver.h @@ -106,4 +106,25 @@ class MotorDriver { } #endif }; + +class MotorDriverContainer { +public: + MotorDriverContainer(const FSH * motorShieldName, + MotorDriver *m0=NULL, + MotorDriver *m1=NULL, + MotorDriver *m2=NULL, + MotorDriver *m3=NULL, + MotorDriver *m4=NULL, + MotorDriver *m5=NULL, + MotorDriver *m6=NULL, + MotorDriver *m7=NULL); + // 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]; }; + +private: + MotorDriver *mD[8]; + FSH *shieldName; +}; #endif