mirror of
https://github.com/DCC-EX/CommandStation-EX.git
synced 2024-11-26 17:46:14 +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"
|
||||
|
||||
/* 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
|
||||
* to transmit and receive DCC data on the programming track.
|
||||
*
|
||||
* Important... DCCWaveform.h contains hardware specific confioguration settings
|
||||
* that you will need to check.
|
||||
*
|
||||
* Notes: the waveform generator sends reset packets on progTrack when it has nothing better to do, this means that
|
||||
* 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.
|
||||
*
|
||||
|
||||
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.
|
||||
|
||||
Once soem CVs have been listed, it then drops into JMRI input moce so you can play.
|
||||
|
||||
Important... Config.h contains hardware specific confioguration settings
|
||||
that you will need to check.
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
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() {
|
||||
Serial.begin(115200);
|
||||
|
@ -40,4 +40,3 @@ void loop() {
|
|||
// This line passes input on Serial to the JMRIparser
|
||||
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 <TimerThree.h>
|
||||
#include "Hardware.h"
|
||||
#include "DCCWaveform.h"
|
||||
#include "DIAG.h"
|
||||
DCCWaveform DCCWaveform::mainTrack(MAIN_POWER_PIN,MAIN_SIGNAL_PIN,MAIN_SENSE_PIN,PREAMBLE_BITS_MAIN,true);
|
||||
DCCWaveform DCCWaveform::progTrack(PROG_POWER_PIN,PROG_SIGNAL_PIN,PROG_SENSE_PIN,PREAMBLE_BITS_PROG,false);
|
||||
DCCWaveform DCCWaveform::mainTrack(PREAMBLE_BITS_MAIN, true);
|
||||
DCCWaveform DCCWaveform::progTrack(PREAMBLE_BITS_PROG, false);
|
||||
|
||||
void DCCWaveform::begin() {
|
||||
|
||||
Timer3.initialize(58);
|
||||
Timer3.disablePwm(MAIN_SIGNAL_PIN);
|
||||
Timer3.disablePwm(PROG_SIGNAL_PIN);
|
||||
Timer3.attachInterrupt(interruptHandler);
|
||||
Hardware::init();
|
||||
Hardware::setCallback(58, interruptHandler);
|
||||
mainTrack.beginTrack();
|
||||
progTrack.beginTrack();
|
||||
}
|
||||
|
@ -46,11 +43,8 @@ void DCCWaveform::interruptHandler() {
|
|||
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
|
||||
powerPin=Arduino_to_GPIO_pin(powerPinNo);
|
||||
directionPin=Arduino_to_GPIO_pin(directionPinNo);
|
||||
sensePin=sensePinNo;
|
||||
isMainTrack = isMain;
|
||||
packetPending = false;
|
||||
memcpy(transmitPacket, idlePacket, sizeof(idlePacket));
|
||||
|
@ -62,18 +56,7 @@ DCCWaveform::DCCWaveform(byte powerPinNo, byte directionPinNo, byte sensePinNo,
|
|||
|
||||
}
|
||||
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);
|
||||
DIAG(F("\nTrack started sensePin=%d\n"),sensePin);
|
||||
}
|
||||
|
||||
POWERMODE DCCWaveform::getPowerMode() {
|
||||
|
@ -82,7 +65,7 @@ DCCWaveform::DCCWaveform(byte powerPinNo, byte directionPinNo, byte sensePinNo,
|
|||
|
||||
void DCCWaveform::setPowerMode(POWERMODE mode) {
|
||||
powerMode = mode;
|
||||
digitalWrite2f(powerPin, mode==POWERMODE::ON ? HIGH:LOW);
|
||||
Hardware::setPower(isMainTrack, mode == POWERMODE::ON);
|
||||
if (mode == POWERMODE::ON) delay(200);
|
||||
}
|
||||
|
||||
|
@ -98,11 +81,11 @@ void DCCWaveform::checkPowerOverload() {
|
|||
break;
|
||||
case POWERMODE::ON:
|
||||
// Check current
|
||||
current=analogRead(sensePin);
|
||||
current = Hardware::getCurrentMilliamps(isMainTrack);
|
||||
if (current < POWER_SAMPLE_MAX) delay = POWER_SAMPLE_ON_WAIT;
|
||||
else {
|
||||
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;
|
||||
}
|
||||
break;
|
||||
|
@ -128,20 +111,20 @@ bool DCCWaveform::interrupt1() {
|
|||
// otherwise can cause hangs in main loop waiting for the pendingBuffer.
|
||||
switch (state) {
|
||||
case 0: // start of bit transmission
|
||||
digitalWrite2f(directionPin, HIGH);
|
||||
Hardware::setSignal(isMainTrack, HIGH);
|
||||
checkRailcom();
|
||||
state = 1;
|
||||
return true; // must call interrupt2 to set currentBit
|
||||
|
||||
case 1: // 58us after case 0
|
||||
if (currentBit) {
|
||||
digitalWrite2f(directionPin, LOW);
|
||||
Hardware::setSignal(isMainTrack, LOW);
|
||||
state = 0;
|
||||
}
|
||||
else state = 2;
|
||||
break;
|
||||
case 2: // 116us after case 0
|
||||
digitalWrite2f(directionPin, LOW);
|
||||
Hardware::setSignal(isMainTrack, LOW);
|
||||
state = 3;
|
||||
break;
|
||||
case 3: // finished sending zero bit
|
||||
|
@ -202,10 +185,7 @@ void DCCWaveform::checkRailcom() {
|
|||
if (isMainTrack && RAILCOM_CUTOUT) {
|
||||
byte preamble = PREAMBLE_BITS_MAIN - remainingPreambles;
|
||||
if (preamble == RAILCOM_PREAMBLES_BEFORE_CUTOUT) {
|
||||
digitalWrite2f(railcomBrakePin,HIGH);
|
||||
}
|
||||
else if (preamble== RAILCOM_PREAMBLES_BEFORE_CUTOUT+RAILCOM_PREAMBLES_SKIPPED_IN_CUTOUT) {
|
||||
digitalWrite2f(railcomBrakePin,LOW);
|
||||
// TODO Railcom::startCutout();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -243,7 +223,7 @@ bool DCCWaveform::getAck()
|
|||
// Monitor looking for a reading high enough to be an ack
|
||||
while (result == false && timeout > millis()) {
|
||||
upsamples++;
|
||||
int current=analogRead(sensePin);
|
||||
int current = Hardware::getCurrentMilliamps(isMainTrack);
|
||||
maxCurrent = max(maxCurrent, current);
|
||||
result = current > ACK_MIN_PULSE;
|
||||
}
|
||||
|
@ -251,7 +231,7 @@ bool DCCWaveform::getAck()
|
|||
// Monitor current until ack signal dies back
|
||||
if (result) while ( true) {
|
||||
downsamples++;
|
||||
int current=analogRead(sensePin);
|
||||
int current = Hardware::getCurrentMilliamps(isMainTrack);
|
||||
maxCurrent = max(maxCurrent, current);
|
||||
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_ON_WAIT = 100;
|
||||
|
@ -36,14 +29,13 @@ const byte MAX_PACKET_SIZE = 12;
|
|||
|
||||
|
||||
enum class POWERMODE { OFF, ON, OVERLOAD };
|
||||
const byte idleMessage[] = {0xFF, 0x00};
|
||||
const byte resetMessage[] = {0x00, 0x00};
|
||||
|
||||
const byte idlePacket[] = {0xFF, 0x00, 0xFF};
|
||||
const byte resetPacket[] = {0x00, 0x00, 0x00};
|
||||
|
||||
class DCCWaveform {
|
||||
public:
|
||||
DCCWaveform(byte powerPinNo, byte directionPinNo, byte sensePinNo, byte preambleBits, bool isMain);
|
||||
DCCWaveform( byte preambleBits, bool isMain);
|
||||
static void begin();
|
||||
static void loop();
|
||||
static DCCWaveform mainTrack;
|
||||
|
@ -83,15 +75,8 @@ class DCCWaveform {
|
|||
byte pendingLength;
|
||||
byte pendingRepeats;
|
||||
|
||||
// Hardware fast pins
|
||||
GPIO_pin_t directionPin;
|
||||
GPIO_pin_t powerPin;
|
||||
GPIO_pin_t railcomBrakePin;
|
||||
|
||||
// current sampling
|
||||
POWERMODE powerMode;
|
||||
byte sensePin;
|
||||
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