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:
parent
7c68a9de70
commit
e7e4d4fbd9
17
CVReader.ino
17
CVReader.ino
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
25
Railcom.cpp
25
Railcom.cpp
@ -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];
|
|
16
Railcom.h
16
Railcom.h
@ -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
|
|
53
Turnouts.cpp
53
Turnouts.cpp
@ -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;
|
||||||
|
19
Turnouts.h
19
Turnouts.h
@ -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
22
freeMemory.h
Normal 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
|
Loading…
Reference in New Issue
Block a user