1
0
mirror of https://github.com/DCC-EX/CommandStation-EX.git synced 2024-12-24 13:21:23 +01:00

Drop railcom and prepare for servo turnouts

This commit is contained in:
Asbelos 2020-06-23 17:43:50 +01:00
parent 7c68a9de70
commit e7e4d4fbd9
10 changed files with 87 additions and 90 deletions

View File

@ -44,10 +44,15 @@ void myCallback(int result) {
} }
// Create a serkial command parser... This is OPTIONAL if you don't need to handle JMRI type commands // Create a serial command parser... This is OPTIONAL if you don't need to handle JMRI type commands
// from the Serial port. // from the Serial port.
DCCEXParser serialParser; DCCEXParser serialParser;
// Try monitoring the memory
#include "freeMemory.h"
int minMemory;
void setup() { void setup() {
Serial.begin(SERIAL_BAUD_RATE); Serial.begin(SERIAL_BAUD_RATE);
DCC::begin(); DCC::begin();
@ -59,6 +64,9 @@ void setup() {
// Optionally tell parser to use my example filter // Optionally tell parser to use my example filter
DCCEXParser::setFilter(myFilter); DCCEXParser::setFilter(myFilter);
malloc(1);
minMemory=freeMemory();
DIAG(F("\nFree memory=%d"),minMemory);
DIAG(F("\nReady for JMRI commands\n")); DIAG(F("\nReady for JMRI commands\n"));
} }
@ -71,4 +79,11 @@ void loop() {
// This line passes input on Wifi to another DCCEXParser // This line passes input on Wifi to another DCCEXParser
if (WIFI_PORT>0) WifiInterface::loop(); if (WIFI_PORT>0) WifiInterface::loop();
// Report any decrease in memory
int freeNow=freeMemory();
if (freeNow<minMemory) {
minMemory=freeNow;
DIAG(F("\nFree memory=%d"),minMemory);
}
} }

View File

@ -2,7 +2,7 @@
#include "Hardware.h" #include "Hardware.h"
#include "DCCWaveform.h" #include "DCCWaveform.h"
#include "DIAG.h" #include "DIAG.h"
#include "Railcom.h"
DCCWaveform DCCWaveform::mainTrack(PREAMBLE_BITS_MAIN, true); DCCWaveform DCCWaveform::mainTrack(PREAMBLE_BITS_MAIN, true);
DCCWaveform DCCWaveform::progTrack(PREAMBLE_BITS_PROG, false); DCCWaveform DCCWaveform::progTrack(PREAMBLE_BITS_PROG, false);
@ -116,7 +116,6 @@ bool DCCWaveform::interrupt1() {
switch (state) { switch (state) {
case 0: // start of bit transmission case 0: // start of bit transmission
Hardware::setSignal(isMainTrack, HIGH); Hardware::setSignal(isMainTrack, HIGH);
checkRailcom();
state = 1; state = 1;
return true; // must call interrupt2 to set currentBit return true; // must call interrupt2 to set currentBit
@ -190,14 +189,7 @@ void DCCWaveform::interrupt2() {
} }
} }
void DCCWaveform::checkRailcom() {
if (isMainTrack && RAILCOM_CUTOUT) {
byte preamble = PREAMBLE_BITS_MAIN - remainingPreambles;
if (preamble == RAILCOM_PREAMBLES_BEFORE_CUTOUT) {
Railcom::startCutout();
}
}
}
// Wait until there is no packet pending, then make this pending // Wait until there is no packet pending, then make this pending
void DCCWaveform::schedulePacket(const byte buffer[], byte byteCount, byte repeats) { void DCCWaveform::schedulePacket(const byte buffer[], byte byteCount, byte repeats) {

View File

@ -16,10 +16,6 @@ const int ACK_MIN_PULSE = 60 ; // current above baseline which a pulse is re
const int PREAMBLE_BITS_MAIN = 20; const int PREAMBLE_BITS_MAIN = 20;
const int PREAMBLE_BITS_PROG = 22; const int PREAMBLE_BITS_PROG = 22;
// Railcom settings
const bool RAILCOM_CUTOUT = true;
const byte RAILCOM_PREAMBLES_BEFORE_CUTOUT = 1; // how far into the preamble do we cutout
const byte MAX_PACKET_SIZE = 12; const byte MAX_PACKET_SIZE = 12;
@ -68,7 +64,6 @@ class DCCWaveform {
byte bits_sent; // 0-8 (yes 9 bits) sent for current byte byte bits_sent; // 0-8 (yes 9 bits) sent for current byte
byte bytes_sent; // number of bytes sent from transmitPacket byte bytes_sent; // number of bytes sent from transmitPacket
byte state; // wave generator state machine byte state; // wave generator state machine
void checkRailcom();
byte pendingPacket[MAX_PACKET_SIZE]; byte pendingPacket[MAX_PACKET_SIZE];
byte pendingLength; byte pendingLength;

View File

@ -52,6 +52,11 @@ void Hardware::setCallback(int duration, void (*isr)()) {
Timer1.attachInterrupt(isr); Timer1.attachInterrupt(isr);
} }
void Hardware::setServo(byte pin, int angle) {
// TBD
}
// Railcom support functions, not yet implemented // Railcom support functions, not yet implemented
void Hardware::setSingleCallback(int duration, void (*isr)()) { void Hardware::setSingleCallback(int duration, void (*isr)()) {
// Timer2.initialize(duration); // Timer2.initialize(duration);

View File

@ -11,5 +11,6 @@ class Hardware {
static void setCallback(int duration, void (*isr)()); static void setCallback(int duration, void (*isr)());
static void setSingleCallback(int duration, void (*isr)()); static void setSingleCallback(int duration, void (*isr)());
static void resetSingleCallback(int duration); static void resetSingleCallback(int duration);
static void setServo(byte pin, int angle);
}; };
#endif #endif

View File

@ -1,25 +0,0 @@
#include "Railcom.h"
#include "Hardware.h"
void Railcom::startCutout() {
return;
/*** todo when ready ***
interruptState=0;
Hardware::setSingleCallback(RAILCOM_T0,interrupt);
*************/
}
void Railcom::interrupt() {
/*** TODO when ready .. railcom state machine
switch (interruptState) {
case 0: //
Hardware::setPower(true,false);
state=1;
nextInterrupt=RAILCOM_T1;
break;
}
**********************/
}
byte Railcom::interruptState;
byte Railcom::bitsReceived;
byte Railcom::buffer[MAX_BUFFER];

View File

@ -1,16 +0,0 @@
#ifndef Railcom_h
#define Railcom_h
#include <Arduino.h>
class Railcom {
public:
static void startCutout();
static void interrupt();
private:
static byte interruptState;
static byte bitsReceived;
static const byte MAX_BUFFER=20;
static byte buffer[MAX_BUFFER];
};
#endif

View File

@ -1,7 +1,7 @@
#include "Turnouts.h" #include "Turnouts.h"
#include "EEStore.h" #include "EEStore.h"
#include "StringFormatter.h" #include "StringFormatter.h"
#include "Hardware.h"
bool Turnout::activate(int n,bool state){ bool Turnout::activate(int n,bool state){
Turnout * tt=get(n); Turnout * tt=get(n);
if (tt==NULL) return false; if (tt==NULL) return false;
@ -12,8 +12,10 @@
// activate is virtual here so that it can be overridden by a non-DCC turnout mechanism // activate is virtual here so that it can be overridden by a non-DCC turnout mechanism
void Turnout::activate(bool state) { void Turnout::activate(bool state) {
data.tStatus=state; if (state) data.tStatus|=STATUS_ACTIVE;
DCC::setAccessory(data.address,data.subAddress, data.tStatus); else data.tStatus &= ~STATUS_ACTIVE;
if (data.tStatus & STATUS_PWM) Hardware::setServo(data.tStatus & STATUS_PWMPIN, (data.inactiveAngle+state?data.moveAngle:0));
else DCC::setAccessory(data.address,data.subAddress, state);
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -46,7 +48,7 @@ bool Turnout::remove(int n){
void Turnout::show(Print & stream, int n){ void Turnout::show(Print & stream, int n){
for(Turnout *tt=firstTurnout;tt!=NULL;tt=tt->nextTurnout){ for(Turnout *tt=firstTurnout;tt!=NULL;tt=tt->nextTurnout){
if (tt->data.id==n) { if (tt->data.id==n) {
StringFormatter::send(stream,F("<H %d %d>"), tt->data.id, tt->data.tStatus); StringFormatter::send(stream,F("<H %d %d>"), tt->data.id, tt->data.tStatus & STATUS_ACTIVE);
return; return;
} }
} }
@ -70,9 +72,9 @@ void Turnout::load(){
for(int i=0;i<EEStore::eeStore->data.nTurnouts;i++){ for(int i=0;i<EEStore::eeStore->data.nTurnouts;i++){
EEPROM.get(EEStore::pointer(),data); EEPROM.get(EEStore::pointer(),data);
tt=create(data.id,data.address,data.subAddress); if (data.tStatus & STATUS_PWM) tt=create(data.id,data.tStatus & STATUS_PWMPIN, data.inactiveAngle,data.moveAngle);
else tt=create(data.id,data.address,data.subAddress);
tt->data.tStatus=data.tStatus; tt->data.tStatus=data.tStatus;
tt->num=EEStore::pointer();
EEStore::advance(sizeof(tt->data)); EEStore::advance(sizeof(tt->data));
} }
} }
@ -86,7 +88,6 @@ void Turnout::store(){
EEStore::eeStore->data.nTurnouts=0; EEStore::eeStore->data.nTurnouts=0;
while(tt!=NULL){ while(tt!=NULL){
tt->num=EEStore::pointer();
EEPROM.put(EEStore::pointer(),tt->data); EEPROM.put(EEStore::pointer(),tt->data);
EEStore::advance(sizeof(tt->data)); EEStore::advance(sizeof(tt->data));
tt=tt->nextTurnout; tt=tt->nextTurnout;
@ -97,29 +98,31 @@ void Turnout::store(){
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
Turnout *Turnout::create(int id, int add, int subAdd){ Turnout *Turnout::create(int id, int add, int subAdd){
Turnout *tt; Turnout *tt=create(id);
if(firstTurnout==NULL){
firstTurnout=(Turnout *)calloc(1,sizeof(Turnout));
tt=firstTurnout;
} else if((tt=get(id))==NULL){
tt=firstTurnout;
while(tt->nextTurnout!=NULL)
tt=tt->nextTurnout;
tt->nextTurnout=(Turnout *)calloc(1,sizeof(Turnout));
tt=tt->nextTurnout;
}
if (tt==NULL) return(tt);
tt->data.id=id;
tt->data.address=add; tt->data.address=add;
tt->data.subAddress=subAdd; tt->data.subAddress=subAdd;
tt->data.tStatus=0; tt->data.tStatus=0;
return(tt); return(tt);
} }
/////////////////////////////////////////////////////////////////////////////// Turnout *Turnout::create(int id, byte pin, int activeAngle, int inactiveAngle){
Turnout *tt=create(id);
tt->data.tStatus= STATUS_PWM | (pin & STATUS_PWMPIN);
tt->data.inactiveAngle=inactiveAngle;
tt->data.moveAngle=activeAngle-inactiveAngle;
return(tt);
}
Turnout *Turnout::create(int id){
Turnout *tt=get(id);
if (tt==NULL) {
tt=(Turnout *)calloc(1,sizeof(Turnout));
tt->nextTurnout=firstTurnout;
firstTurnout=tt;
tt->data.id=id;
}
return tt;
}
///////////////////////////////////////////////////////////////////////////////
Turnout *Turnout::firstTurnout=NULL; Turnout *Turnout::firstTurnout=NULL;

View File

@ -4,24 +4,29 @@
#include <Arduino.h> #include <Arduino.h>
#include "DCC.h" #include "DCC.h"
const byte STATUS_ACTIVE=0x80; // Flag as activated
const byte STATUS_PWM=0x40; // Flag as a PWM turnout
const byte STATUS_PWMPIN=0x3F; // PWM pin 0-63
struct TurnoutData { struct TurnoutData {
uint8_t tStatus; int id;
uint8_t subAddress; uint8_t tStatus; // has STATUS_ACTIVE, STATUS_PWM, STATUS_PWMPIN
int id; union {uint8_t subAddress; char moveAngle;}; //DCC sub addrerss or PWM difference from inactiveAngle
int address; union {int address; int inactiveAngle;}; // DCC address or PWM servo angle
}; };
struct Turnout{ struct Turnout{
static Turnout *firstTurnout; static Turnout *firstTurnout;
int num; TurnoutData data;
struct TurnoutData data;
Turnout *nextTurnout; Turnout *nextTurnout;
static bool activate(int n, bool state); static bool activate(int n, bool state);
static Turnout* get(int); static Turnout* get(int);
static bool remove(int); static bool remove(int);
static void load(); static void load();
static void store(); static void store();
static Turnout *create(int, int, int); static Turnout *create(int id , int address , int subAddress);
static Turnout *create(int id , byte pin , int activeAngle, int inactiveAngle);
static Turnout *create(int id);
static void show(Print & stream, int n); static void show(Print & stream, int n);
static bool showAll(Print & stream); static bool showAll(Print & stream);
virtual void activate(bool state); virtual void activate(bool state);

22
freeMemory.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef freeMemory_h
#define freeMemory_h
// thanks go to https://github.com/mpflaga/Arduino-MemoryFree
#ifdef __arm__
// should use uinstd.h to define sbrk but Due causes a conflict
extern "C" char* sbrk(int incr);
#else // __ARM__
extern char *__brkval;
#endif // __arm__
int freeMemory() {
char top;
#ifdef __arm__
return &top - reinterpret_cast<char*>(sbrk(0));
#elif defined(CORE_TEENSY) || (ARDUINO > 103 && ARDUINO != 151)
return &top - __brkval;
#else // __arm__
return __brkval ? &top - __brkval : &top - __malloc_heap_start;
#endif // __arm__
}
#endif