/*
* © 2020, Chris Harlow. All rights reserved.
*
* This file is part of Asbelos DCC API
*
* This is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* It is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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
#include "defines.h"
#include "FSH.h"
#include "DIAG.h"
#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
#endif
#if defined(__IMXRT1062__) || defined(ESP_FAMILY)
typedef uint32_t PORTTYPE;
struct FASTPIN {
volatile uint32_t *inout;
uint32_t maskHIGH;
uint32_t maskLOW;
};
#else
typedef uint8_t PORTTYPE;
struct FASTPIN {
volatile uint8_t *inout;
uint8_t maskHIGH;
uint8_t maskLOW;
};
#endif
#define setHIGH(fastpin) *fastpin.inout |= fastpin.maskHIGH
#define setLOW(fastpin) *fastpin.inout &= fastpin.maskLOW
#define isHIGH(fastpin) (*fastpin.inout & fastpin.maskHIGH)
#define isLOW(fastpin) (!isHIGH(fastpin))
typedef byte driverType;
const driverType TYPE_UNKNOWN=0;
const driverType TIMER_MAIN=1;
const driverType TIMER_PROG=2;
const driverType RMT_MAIN=4;
const driverType RMT_PROG=16;
const driverType DC_ENA=32;
const driverType DC_BRAKE=64;
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,
driverType t=TYPE_UNKNOWN);
void setPower( bool on);
void setSignal( bool high);
void setBrake( bool on);
int getCurrentRaw();
unsigned int raw2mA( int raw);
int mA2raw( unsigned int mA);
inline int getRawCurrentTripValue() {
return rawCurrentTripValue;
}
bool isPWMCapable();
bool canMeasureCurrent();
static bool usePWM;
static bool commonFaultPin; // This is a stupid motor shield which has only a common fault pin for both outputs
inline byte getFaultPin() {
return faultPin;
}
#if defined(ARDUINO_ARCH_ESP32)
void loop();
inline driverType type() { return dtype; };
inline void setType(driverType t) { dtype = t; };
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) {
getFastPin(type, pin, 0, result);
}
byte powerPin, signalPin, signalPin2, currentPin, faultPin, brakePin;
FASTPIN fastPowerPin,fastSignalPin, fastSignalPin2, fastBrakePin,fastFaultPin;
bool dualSignal; // true to use signalPin2
bool invertBrake; // brake pin passed as negative means pin is inverted
float senseFactor;
int senseOffset;
unsigned int tripMilliamps;
int rawCurrentTripValue;
#if defined(ARDUINO_TEENSY40) || defined(ARDUINO_TEENSY41)
static bool disableInterrupts() {
uint32_t primask;
__asm__ volatile("mrs %0, primask\n" : "=r" (primask)::);
__disable_irq();
return (primask == 0) ? true : false;
}
static void enableInterrupts(bool doit) {
if (doit) __enable_irq();
}
#endif
#if defined(ARDUINO_ARCH_ESP32)
RMTChannel* rmtChannel;
std::queue outQueue;
driverType dtype;
#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);
static MotorDriverContainer mDC;
inline void add(MotorDriver *m) {
mD.push_back(m);
DIAG(F("Container: mDType=%d count=%d"),m->type(), mD.size());
};
// void SetCapability(byte n, byte cap, char [] name);
inline FSH *getMotorShieldName() { return shieldName; };
inline void diag() {
if (mD.empty()) {
DIAG(F("Container empty"));
return;
}
for(const auto& d: mD)
DIAG(F("Container: mDType=%d count=%d"),d->type(), mD.size());
};
inline MotorDriver *mainTrack() {
std::vector v = getDriverType(TIMER_MAIN);
if(v.empty()) return NULL;
return v.front();
};
inline MotorDriver *progTrack() {
std::vector v = getDriverType(TIMER_PROG);
if(v.empty()) return NULL;
return v.front();
};
void loop();
std::vector getDriverType(driverType t);
private:
std::vectormD;
FSH *shieldName;
};
#endif