mirror of
https://github.com/DCC-EX/CommandStation-EX.git
synced 2025-02-18 15:06:03 +01:00
Abstracted Hardware Interface
The hardware interface for all pins and timers is now in Hardware.cpp
This commit is contained in:
parent
28be07610a
commit
22406b44ed
25
CVReader.ino
25
CVReader.ino
@ -3,22 +3,22 @@
|
|||||||
#include "JMRIParser.h"
|
#include "JMRIParser.h"
|
||||||
|
|
||||||
/* this code is here to test the waveforwe generator and reveal the issues involved in programming track operations.
|
/* this code is here to test the waveforwe generator and reveal the issues involved in programming track operations.
|
||||||
*
|
|
||||||
* It tests the Waveform genartor and demonstrates how a DCC API function can be simply written
|
It tests the Waveform genartor and demonstrates how a DCC API function can be simply written
|
||||||
* to transmit and receive DCC data on the programming track.
|
to transmit and receive DCC data on the programming track.
|
||||||
*
|
|
||||||
* Important... DCCWaveform.h contains hardware specific confioguration settings
|
Once soem CVs have been listed, it then drops into JMRI input moce so you can play.
|
||||||
* that you will need to check.
|
|
||||||
*
|
Important... Config.h contains hardware specific confioguration settings
|
||||||
* Notes: the waveform generator sends reset packets on progTrack when it has nothing better to do, this means that
|
that you will need to check.
|
||||||
* the decoder does not step out of service mode. (The main track sends idles).
|
|
||||||
* It also means that the API functions dont have to mess with reset packets.
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const int cvnums[]={1,2,3,4,5,17,18,19,21,22,29};
|
const int cvnums[] = {1, 2, 3, 4, 5, 8, 17, 18, 19, 21, 22, 29};
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
@ -40,4 +40,3 @@ void loop() {
|
|||||||
// This line passes input on Serial to the JMRIparser
|
// This line passes input on Serial to the JMRIparser
|
||||||
StringParser::loop(Serial, JMRIParser::parse);
|
StringParser::loop(Serial, JMRIParser::parse);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
13
Config.h
Normal file
13
Config.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// This hardware configuration would normally be setup using a bunch of #ifdefs.
|
||||||
|
|
||||||
|
const byte MAIN_POWER_PIN = 3;
|
||||||
|
const byte MAIN_SIGNAL_PIN = 12;
|
||||||
|
const byte MAIN_SIGNAL_PIN_ALT = 0; // for hardware that flipflops signal pins
|
||||||
|
const byte MAIN_SENSE_PIN = A0;
|
||||||
|
const byte MAIN_SENSE_FACTOR=1; // analgRead(MAIN_SENSE_PIN) * MAIN_SENSE_FACTOR = milliamps
|
||||||
|
|
||||||
|
const byte PROG_POWER_PIN = 11;
|
||||||
|
const byte PROG_SIGNAL_PIN = 13;
|
||||||
|
const byte PROG_SIGNAL_PIN_ALT = 0; // for hardware that flipflops signal pins
|
||||||
|
const byte PROG_SENSE_PIN = A1;
|
||||||
|
const float PROG_SENSE_FACTOR=1; // analgRead(PROG_SENSE_PIN) * PROG_SENSE_FACTOR = milliamps
|
@ -1,16 +1,13 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <TimerThree.h>
|
#include "Hardware.h"
|
||||||
#include "DCCWaveform.h"
|
#include "DCCWaveform.h"
|
||||||
#include "DIAG.h"
|
#include "DIAG.h"
|
||||||
DCCWaveform DCCWaveform::mainTrack(MAIN_POWER_PIN,MAIN_SIGNAL_PIN,MAIN_SENSE_PIN,PREAMBLE_BITS_MAIN,true);
|
DCCWaveform DCCWaveform::mainTrack(PREAMBLE_BITS_MAIN, true);
|
||||||
DCCWaveform DCCWaveform::progTrack(PROG_POWER_PIN,PROG_SIGNAL_PIN,PROG_SENSE_PIN,PREAMBLE_BITS_PROG,false);
|
DCCWaveform DCCWaveform::progTrack(PREAMBLE_BITS_PROG, false);
|
||||||
|
|
||||||
void DCCWaveform::begin() {
|
void DCCWaveform::begin() {
|
||||||
|
Hardware::init();
|
||||||
Timer3.initialize(58);
|
Hardware::setCallback(58, interruptHandler);
|
||||||
Timer3.disablePwm(MAIN_SIGNAL_PIN);
|
|
||||||
Timer3.disablePwm(PROG_SIGNAL_PIN);
|
|
||||||
Timer3.attachInterrupt(interruptHandler);
|
|
||||||
mainTrack.beginTrack();
|
mainTrack.beginTrack();
|
||||||
progTrack.beginTrack();
|
progTrack.beginTrack();
|
||||||
}
|
}
|
||||||
@ -46,11 +43,8 @@ void DCCWaveform::interruptHandler() {
|
|||||||
const byte bitMask[] = {0x00, 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
|
const byte bitMask[] = {0x00, 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
|
||||||
|
|
||||||
|
|
||||||
DCCWaveform::DCCWaveform(byte powerPinNo, byte directionPinNo, byte sensePinNo, byte preambleBits, bool isMain) {
|
DCCWaveform::DCCWaveform( byte preambleBits, bool isMain) {
|
||||||
// establish appropriate pins
|
// establish appropriate pins
|
||||||
powerPin=Arduino_to_GPIO_pin(powerPinNo);
|
|
||||||
directionPin=Arduino_to_GPIO_pin(directionPinNo);
|
|
||||||
sensePin=sensePinNo;
|
|
||||||
isMainTrack = isMain;
|
isMainTrack = isMain;
|
||||||
packetPending = false;
|
packetPending = false;
|
||||||
memcpy(transmitPacket, idlePacket, sizeof(idlePacket));
|
memcpy(transmitPacket, idlePacket, sizeof(idlePacket));
|
||||||
@ -62,18 +56,7 @@ DCCWaveform::DCCWaveform(byte powerPinNo, byte directionPinNo, byte sensePinNo,
|
|||||||
|
|
||||||
}
|
}
|
||||||
void DCCWaveform::beginTrack() {
|
void DCCWaveform::beginTrack() {
|
||||||
pinMode2f(powerPin,OUTPUT);
|
|
||||||
pinMode2f(directionPin,OUTPUT);
|
|
||||||
pinMode(sensePin,INPUT);
|
|
||||||
|
|
||||||
if (isMainTrack && RAILCOM_CUTOUT) {
|
|
||||||
railcomBrakePin=Arduino_to_GPIO_pin(RAILCOM_BRAKE_PIN);
|
|
||||||
pinMode2f(railcomBrakePin, OUTPUT);
|
|
||||||
digitalWrite2f(railcomBrakePin, LOW);
|
|
||||||
}
|
|
||||||
|
|
||||||
setPowerMode(POWERMODE::ON);
|
setPowerMode(POWERMODE::ON);
|
||||||
DIAG(F("\nTrack started sensePin=%d\n"),sensePin);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
POWERMODE DCCWaveform::getPowerMode() {
|
POWERMODE DCCWaveform::getPowerMode() {
|
||||||
@ -82,7 +65,7 @@ DCCWaveform::DCCWaveform(byte powerPinNo, byte directionPinNo, byte sensePinNo,
|
|||||||
|
|
||||||
void DCCWaveform::setPowerMode(POWERMODE mode) {
|
void DCCWaveform::setPowerMode(POWERMODE mode) {
|
||||||
powerMode = mode;
|
powerMode = mode;
|
||||||
digitalWrite2f(powerPin, mode==POWERMODE::ON ? HIGH:LOW);
|
Hardware::setPower(isMainTrack, mode == POWERMODE::ON);
|
||||||
if (mode == POWERMODE::ON) delay(200);
|
if (mode == POWERMODE::ON) delay(200);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,11 +81,11 @@ void DCCWaveform::checkPowerOverload() {
|
|||||||
break;
|
break;
|
||||||
case POWERMODE::ON:
|
case POWERMODE::ON:
|
||||||
// Check current
|
// Check current
|
||||||
current=analogRead(sensePin);
|
current = Hardware::getCurrentMilliamps(isMainTrack);
|
||||||
if (current < POWER_SAMPLE_MAX) delay = POWER_SAMPLE_ON_WAIT;
|
if (current < POWER_SAMPLE_MAX) delay = POWER_SAMPLE_ON_WAIT;
|
||||||
else {
|
else {
|
||||||
setPowerMode(POWERMODE::OVERLOAD);
|
setPowerMode(POWERMODE::OVERLOAD);
|
||||||
DIAG(F("\n*** %s TRACK POWER OVERLOAD pin=%d current=%d max=%d ***\n"),isMainTrack?"MAIN":"PROG",sensePin,current,POWER_SAMPLE_MAX);
|
DIAG(F("\n*** %s TRACK POWER OVERLOAD current=%d max=%d ***\n"), isMainTrack ? "MAIN" : "PROG", current, POWER_SAMPLE_MAX);
|
||||||
delay = POWER_SAMPLE_OVERLOAD_WAIT;
|
delay = POWER_SAMPLE_OVERLOAD_WAIT;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -128,20 +111,20 @@ bool DCCWaveform::interrupt1() {
|
|||||||
// otherwise can cause hangs in main loop waiting for the pendingBuffer.
|
// otherwise can cause hangs in main loop waiting for the pendingBuffer.
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case 0: // start of bit transmission
|
case 0: // start of bit transmission
|
||||||
digitalWrite2f(directionPin, HIGH);
|
Hardware::setSignal(isMainTrack, HIGH);
|
||||||
checkRailcom();
|
checkRailcom();
|
||||||
state = 1;
|
state = 1;
|
||||||
return true; // must call interrupt2 to set currentBit
|
return true; // must call interrupt2 to set currentBit
|
||||||
|
|
||||||
case 1: // 58us after case 0
|
case 1: // 58us after case 0
|
||||||
if (currentBit) {
|
if (currentBit) {
|
||||||
digitalWrite2f(directionPin, LOW);
|
Hardware::setSignal(isMainTrack, LOW);
|
||||||
state = 0;
|
state = 0;
|
||||||
}
|
}
|
||||||
else state = 2;
|
else state = 2;
|
||||||
break;
|
break;
|
||||||
case 2: // 116us after case 0
|
case 2: // 116us after case 0
|
||||||
digitalWrite2f(directionPin, LOW);
|
Hardware::setSignal(isMainTrack, LOW);
|
||||||
state = 3;
|
state = 3;
|
||||||
break;
|
break;
|
||||||
case 3: // finished sending zero bit
|
case 3: // finished sending zero bit
|
||||||
@ -202,10 +185,7 @@ void DCCWaveform::checkRailcom() {
|
|||||||
if (isMainTrack && RAILCOM_CUTOUT) {
|
if (isMainTrack && RAILCOM_CUTOUT) {
|
||||||
byte preamble = PREAMBLE_BITS_MAIN - remainingPreambles;
|
byte preamble = PREAMBLE_BITS_MAIN - remainingPreambles;
|
||||||
if (preamble == RAILCOM_PREAMBLES_BEFORE_CUTOUT) {
|
if (preamble == RAILCOM_PREAMBLES_BEFORE_CUTOUT) {
|
||||||
digitalWrite2f(railcomBrakePin,HIGH);
|
// TODO Railcom::startCutout();
|
||||||
}
|
|
||||||
else if (preamble== RAILCOM_PREAMBLES_BEFORE_CUTOUT+RAILCOM_PREAMBLES_SKIPPED_IN_CUTOUT) {
|
|
||||||
digitalWrite2f(railcomBrakePin,LOW);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -243,7 +223,7 @@ bool DCCWaveform::getAck()
|
|||||||
// Monitor looking for a reading high enough to be an ack
|
// Monitor looking for a reading high enough to be an ack
|
||||||
while (result == false && timeout > millis()) {
|
while (result == false && timeout > millis()) {
|
||||||
upsamples++;
|
upsamples++;
|
||||||
int current=analogRead(sensePin);
|
int current = Hardware::getCurrentMilliamps(isMainTrack);
|
||||||
maxCurrent = max(maxCurrent, current);
|
maxCurrent = max(maxCurrent, current);
|
||||||
result = current > ACK_MIN_PULSE;
|
result = current > ACK_MIN_PULSE;
|
||||||
}
|
}
|
||||||
@ -251,7 +231,7 @@ bool DCCWaveform::getAck()
|
|||||||
// Monitor current until ack signal dies back
|
// Monitor current until ack signal dies back
|
||||||
if (result) while ( true) {
|
if (result) while ( true) {
|
||||||
downsamples++;
|
downsamples++;
|
||||||
int current=analogRead(sensePin);
|
int current = Hardware::getCurrentMilliamps(isMainTrack);
|
||||||
maxCurrent = max(maxCurrent, current);
|
maxCurrent = max(maxCurrent, current);
|
||||||
if (current <= ACK_MAX_NOT_PULSE) break;
|
if (current <= ACK_MAX_NOT_PULSE) break;
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,5 @@
|
|||||||
#include <DIO2.h>
|
|
||||||
// This hardware configuration would normally be setup in a .h file elsewhere
|
|
||||||
const byte MAIN_POWER_PIN = 3;
|
|
||||||
const byte MAIN_SIGNAL_PIN = 12;
|
|
||||||
const byte MAIN_SENSE_PIN = A0;
|
|
||||||
|
|
||||||
const byte PROG_POWER_PIN = 11;
|
|
||||||
const byte PROG_SIGNAL_PIN = 13;
|
|
||||||
const byte PROG_SENSE_PIN = A1;
|
|
||||||
|
|
||||||
const int POWER_SAMPLE_MAX = 300;
|
const int POWER_SAMPLE_MAX = 300;
|
||||||
const int POWER_SAMPLE_ON_WAIT = 100;
|
const int POWER_SAMPLE_ON_WAIT = 100;
|
||||||
@ -36,14 +29,13 @@ const byte MAX_PACKET_SIZE = 12;
|
|||||||
|
|
||||||
|
|
||||||
enum class POWERMODE { OFF, ON, OVERLOAD };
|
enum class POWERMODE { OFF, ON, OVERLOAD };
|
||||||
const byte idleMessage[] = {0xFF, 0x00};
|
|
||||||
const byte resetMessage[] = {0x00, 0x00};
|
|
||||||
const byte idlePacket[] = {0xFF, 0x00, 0xFF};
|
const byte idlePacket[] = {0xFF, 0x00, 0xFF};
|
||||||
const byte resetPacket[] = {0x00, 0x00, 0x00};
|
const byte resetPacket[] = {0x00, 0x00, 0x00};
|
||||||
|
|
||||||
class DCCWaveform {
|
class DCCWaveform {
|
||||||
public:
|
public:
|
||||||
DCCWaveform(byte powerPinNo, byte directionPinNo, byte sensePinNo, byte preambleBits, bool isMain);
|
DCCWaveform( byte preambleBits, bool isMain);
|
||||||
static void begin();
|
static void begin();
|
||||||
static void loop();
|
static void loop();
|
||||||
static DCCWaveform mainTrack;
|
static DCCWaveform mainTrack;
|
||||||
@ -83,15 +75,8 @@ class DCCWaveform {
|
|||||||
byte pendingLength;
|
byte pendingLength;
|
||||||
byte pendingRepeats;
|
byte pendingRepeats;
|
||||||
|
|
||||||
// Hardware fast pins
|
|
||||||
GPIO_pin_t directionPin;
|
|
||||||
GPIO_pin_t powerPin;
|
|
||||||
GPIO_pin_t railcomBrakePin;
|
|
||||||
|
|
||||||
// current sampling
|
// current sampling
|
||||||
POWERMODE powerMode;
|
POWERMODE powerMode;
|
||||||
byte sensePin;
|
|
||||||
unsigned long nextSampleDue;
|
unsigned long nextSampleDue;
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
42
Hardware.cpp
Normal file
42
Hardware.cpp
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
#include <Arduino.h>
|
||||||
|
#include <TimerThree.h>
|
||||||
|
|
||||||
|
#include "Hardware.h"
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
void Hardware::init() {
|
||||||
|
pinMode(MAIN_POWER_PIN, OUTPUT);
|
||||||
|
pinMode(MAIN_SIGNAL_PIN, OUTPUT);
|
||||||
|
if (MAIN_SIGNAL_PIN_ALT) pinMode(MAIN_SIGNAL_PIN_ALT, OUTPUT);
|
||||||
|
pinMode(MAIN_SENSE_PIN, INPUT);
|
||||||
|
|
||||||
|
pinMode(PROG_POWER_PIN, OUTPUT);
|
||||||
|
pinMode(PROG_SIGNAL_PIN, OUTPUT);
|
||||||
|
if (PROG_SIGNAL_PIN_ALT) pinMode(PROG_SIGNAL_PIN_ALT, OUTPUT);
|
||||||
|
pinMode(PROG_SENSE_PIN, INPUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hardware::setPower(bool isMainTrack, bool on) {
|
||||||
|
digitalWrite(isMainTrack ? MAIN_POWER_PIN : PROG_POWER_PIN, on ? HIGH : LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hardware::setSignal(bool isMainTrack, bool high) {
|
||||||
|
byte pin = isMainTrack ? MAIN_SIGNAL_PIN : PROG_SIGNAL_PIN;
|
||||||
|
byte pin2 = isMainTrack ? MAIN_SIGNAL_PIN_ALT : PROG_SIGNAL_PIN_ALT;
|
||||||
|
digitalWrite(pin, high ? HIGH : LOW);
|
||||||
|
if (pin2) digitalWrite(pin2, high ? LOW : HIGH);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Hardware::getCurrentMilliamps(bool isMainTrack) {
|
||||||
|
int pin = isMainTrack ? MAIN_SENSE_PIN : PROG_SENSE_PIN;
|
||||||
|
float factor = isMainTrack ? MAIN_SENSE_FACTOR : PROG_SENSE_FACTOR;
|
||||||
|
int rawCurrent = analogRead(pin);
|
||||||
|
return (int)(rawCurrent * factor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hardware::setCallback(int duration, void (*isr)()) {
|
||||||
|
Timer3.initialize(duration);
|
||||||
|
Timer3.disablePwm(TIMER3_A_PIN);
|
||||||
|
Timer3.disablePwm(TIMER3_B_PIN);
|
||||||
|
Timer3.attachInterrupt(isr);
|
||||||
|
}
|
10
Hardware.h
Normal file
10
Hardware.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
// Virtualised hardware Interface
|
||||||
|
class Hardware {
|
||||||
|
public:
|
||||||
|
static void init();
|
||||||
|
static void setPower(bool isMainTrack, bool on);
|
||||||
|
static void setSignal(bool isMainTrack, bool high);
|
||||||
|
static int getCurrentMilliamps(bool isMainTrack);
|
||||||
|
static void setCallback(int duration, void (*isr)());
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user