mirror of
https://github.com/DCC-EX/CommandStation-EX.git
synced 2024-11-22 23:56:13 +01:00
Assorted bits (#138)
* LCN * Prevent deprecated compiler warning * Implement huge function numbers * new commands <! [cab]> forget locos. <9> ESTOP ALL. <D RESET> reboot arduino * Waveform accuracy msg * Drop post-write verify * UNUSED_PIN current measure and callback -2 for cv actions. * Correct diags * ESTOP a forget loco * ESTOP loco on forget * Avoid compiler warning * current sensor offset * Restore <1 JOIN> after prog track operation * <!> ESTOP <-> FORGET * Auto current offset detection * manage current offset and diagnostics * neater msg at startup * Add startup message to LCN master * DCC::setJoinRelayPin Co-authored-by: Asbelos <asbelos@btinternet.com>
This commit is contained in:
parent
f556cc5e1c
commit
d7b2cf3d76
|
@ -95,6 +95,11 @@ void setup()
|
|||
#undef SETUP
|
||||
#endif
|
||||
|
||||
#if defined(LCN_SERIAL)
|
||||
LCN_SERIAL.begin(115200);
|
||||
LCN::init(LCN_SERIAL);
|
||||
#endif
|
||||
|
||||
LCD(1,F("Ready"));
|
||||
}
|
||||
|
||||
|
@ -121,6 +126,10 @@ void loop()
|
|||
RMFT::loop();
|
||||
#endif
|
||||
|
||||
#if defined(LCN_SERIAL)
|
||||
LCN::loop();
|
||||
#endif
|
||||
|
||||
LCDDisplay::loop(); // ignored if LCD not in use
|
||||
|
||||
// Report any decrease in memory (will automatically trigger on first call)
|
||||
|
|
55
DCC.cpp
55
DCC.cpp
|
@ -47,16 +47,10 @@ const byte FN_GROUP_5=0x10;
|
|||
FSH* DCC::shieldName=NULL;
|
||||
byte DCC::joinRelay=UNUSED_PIN;
|
||||
|
||||
void DCC::begin(const FSH * motorShieldName, MotorDriver * mainDriver, MotorDriver* progDriver,
|
||||
byte joinRelayPin) {
|
||||
void DCC::begin(const FSH * motorShieldName, MotorDriver * mainDriver, MotorDriver* progDriver) {
|
||||
shieldName=(FSH *)motorShieldName;
|
||||
DIAG(F("<iDCC-EX V-%S / %S / %S G-%S>\n"), F(VERSION), F(ARDUINO_TYPE), shieldName, F(GITHUB_SHA));
|
||||
|
||||
joinRelay=joinRelayPin;
|
||||
if (joinRelay!=UNUSED_PIN) {
|
||||
pinMode(joinRelay,OUTPUT);
|
||||
digitalWrite(joinRelay,LOW); // high is relay disengaged
|
||||
}
|
||||
// Load stuff from EEprom
|
||||
(void)EEPROM; // tell compiler not to warn this is unused
|
||||
EEStore::init();
|
||||
|
@ -64,6 +58,14 @@ void DCC::begin(const FSH * motorShieldName, MotorDriver * mainDriver, MotorDriv
|
|||
DCCWaveform::begin(mainDriver,progDriver);
|
||||
}
|
||||
|
||||
void DCC::setJoinRelayPin(byte joinRelayPin) {
|
||||
joinRelay=joinRelayPin;
|
||||
if (joinRelay!=UNUSED_PIN) {
|
||||
pinMode(joinRelay,OUTPUT);
|
||||
digitalWrite(joinRelay,LOW); // LOW is relay disengaged
|
||||
}
|
||||
}
|
||||
|
||||
void DCC::setThrottle( uint16_t cab, uint8_t tSpeed, bool tDirection) {
|
||||
byte speedCode = (tSpeed & 0x7F) + tDirection * 128;
|
||||
setThrottle2(cab, speedCode);
|
||||
|
@ -114,7 +116,28 @@ bool DCC::getThrottleDirection(int cab) {
|
|||
|
||||
// Set function to value on or off
|
||||
void DCC::setFn( int cab, byte functionNumber, bool on) {
|
||||
if (cab<=0 || functionNumber>28) return;
|
||||
if (cab<=0 ) return;
|
||||
|
||||
if (functionNumber>28) {
|
||||
//non reminding advanced binary bit set
|
||||
byte b[5];
|
||||
byte nB = 0;
|
||||
if (cab > 127)
|
||||
b[nB++] = highByte(cab) | 0xC0; // convert train number into a two-byte address
|
||||
b[nB++] = lowByte(cab);
|
||||
if (functionNumber <= 127) {
|
||||
b[nB++] = 0b11011101; // Binary State Control Instruction short form
|
||||
b[nB++] = functionNumber | (on ? 0x80 : 0);
|
||||
}
|
||||
else {
|
||||
b[nB++] = 0b11000000; // Binary State Control Instruction long form
|
||||
b[nB++] = (functionNumber & 0x7F) | (on ? 0x80 : 0); // low order bits and state flag
|
||||
b[nB++] = functionNumber >>8 ; // high order bits
|
||||
}
|
||||
DCCWaveform::mainTrack.schedulePacket(b, nB, 4);
|
||||
return;
|
||||
}
|
||||
|
||||
int reg = lookupSpeedTable(cab);
|
||||
if (reg<0) return;
|
||||
|
||||
|
@ -293,7 +316,8 @@ const ackOp FLASH READ_BIT_PROG[] = {
|
|||
const ackOp FLASH WRITE_BYTE_PROG[] = {
|
||||
BASELINE,
|
||||
WB,WACK, // Write
|
||||
VB,WACK, // validate byte
|
||||
// VB,WACK, // validate byte, unnecessary after write gave ACK.
|
||||
// Also, in some cases, like decoder reset, the value read back is not the same as written.
|
||||
ITC1, // if ok callback (1)
|
||||
FAIL // callback (-1)
|
||||
};
|
||||
|
@ -499,10 +523,13 @@ void DCC::setLocoId(int id,ACK_CALLBACK callback) {
|
|||
}
|
||||
|
||||
void DCC::forgetLoco(int cab) { // removes any speed reminders for this loco
|
||||
setThrottle2(cab,1); // ESTOP this loco if still on track
|
||||
int reg=lookupSpeedTable(cab);
|
||||
if (reg>=0) speedTable[reg].loco=0;
|
||||
setThrottle2(cab,1); // ESTOP if this loco still on track
|
||||
}
|
||||
void DCC::forgetAllLocos() { // removes all speed reminders
|
||||
setThrottle2(0,1); // ESTOP all locos still on track
|
||||
for (int i=0;i<MAX_LOCOS;i++) speedTable[i].loco=0;
|
||||
}
|
||||
|
||||
|
@ -634,6 +661,7 @@ int DCC::ackManagerWord;
|
|||
int DCC::ackManagerCv;
|
||||
byte DCC::ackManagerBitNum;
|
||||
bool DCC::ackReceived;
|
||||
bool DCC::ackManagerRejoin;
|
||||
|
||||
ACK_CALLBACK DCC::ackManagerCallback;
|
||||
|
||||
|
@ -667,6 +695,11 @@ void DCC::ackManagerLoop() {
|
|||
// (typically waiting for a reset counter or ACK waiting, or when all finished.)
|
||||
switch (opcode) {
|
||||
case BASELINE:
|
||||
ackManagerRejoin=DCCWaveform::progTrackSyncMain;
|
||||
if (!DCCWaveform::progTrack.canMeasureCurrent()) {
|
||||
callback(-2);
|
||||
return;
|
||||
}
|
||||
setProgTrackSyncMain(false);
|
||||
if (DCCWaveform::progTrack.getPowerMode() == POWERMODE::OFF) {
|
||||
if (Diag::ACK) DIAG(F("\nAuto Prog power on"));
|
||||
|
@ -833,6 +866,10 @@ void DCC::callback(int value) {
|
|||
if (Diag::ACK) DIAG(F("\nAuto Prog power off"));
|
||||
DCCWaveform::progTrack.doAutoPowerOff();
|
||||
}
|
||||
|
||||
// Restore <1 JOIN> to state before BASELINE
|
||||
setProgTrackSyncMain(ackManagerRejoin);
|
||||
|
||||
if (Diag::ACK) DIAG(F("\nCallback(%d)\n"),value);
|
||||
(ackManagerCallback)( value);
|
||||
}
|
||||
|
|
5
DCC.h
5
DCC.h
|
@ -65,8 +65,8 @@ const byte MAX_LOCOS = 50;
|
|||
class DCC
|
||||
{
|
||||
public:
|
||||
static void begin(const FSH * motorShieldName, MotorDriver *mainDriver, MotorDriver *progDriver,
|
||||
byte joinRelayPin=UNUSED_PIN);
|
||||
static void begin(const FSH * motorShieldName, MotorDriver *mainDriver, MotorDriver *progDriver);
|
||||
static void setJoinRelayPin(byte joinRelayPin);
|
||||
static void loop();
|
||||
|
||||
// Public DCC API functions
|
||||
|
@ -135,6 +135,7 @@ private:
|
|||
static int ackManagerWord;
|
||||
static byte ackManagerStash;
|
||||
static bool ackReceived;
|
||||
static bool ackManagerRejoin;
|
||||
static ACK_CALLBACK ackManagerCallback;
|
||||
static void ackManagerSetup(int cv, byte bitNumOrbyteValue, ackOp const program[], ACK_CALLBACK callback);
|
||||
static void ackManagerSetup(int wordval, ackOp const program[], ACK_CALLBACK callback);
|
||||
|
|
1
DCCEX.h
1
DCCEX.h
|
@ -14,6 +14,7 @@
|
|||
#include "EthernetInterface.h"
|
||||
#endif
|
||||
#include "LCD_Implementation.h"
|
||||
#include "LCN.h"
|
||||
#include "freeMemory.h"
|
||||
|
||||
#if __has_include ( "myAutomation.h")
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include "EEStore.h"
|
||||
#include "DIAG.h"
|
||||
#include <avr/wdt.h>
|
||||
|
||||
// These keywords are used in the <1> command. The number is what you get if you use the keyword as a parameter.
|
||||
// To discover new keyword numbers , use the <$ YOURKEYWORD> command
|
||||
|
@ -51,6 +52,9 @@ const int HASH_KEYWORD_LIMIT = 27413;
|
|||
const int HASH_KEYWORD_ETHERNET = -30767;
|
||||
const int HASH_KEYWORD_MAX = 16244;
|
||||
const int HASH_KEYWORD_MIN = 15978;
|
||||
const int HASH_KEYWORD_LCN = 15137;
|
||||
const int HASH_KEYWORD_RESET = 26133;
|
||||
|
||||
|
||||
int DCCEXParser::stashP[MAX_COMMAND_PARAMS];
|
||||
bool DCCEXParser::stashBusy;
|
||||
|
@ -477,6 +481,10 @@ void DCCEXParser::parse(Print *stream, byte *com, RingStream * ringStream)
|
|||
}
|
||||
return;
|
||||
|
||||
case '!': // ESTOP ALL <!>
|
||||
DCC::setThrottle(0,1,1); // this broadcasts speed 1(estop) and sets all reminders to speed 1.
|
||||
return;
|
||||
|
||||
case 'c': // SEND METER RESPONSES <c>
|
||||
// <c MeterName value C/V unit min max res warn>
|
||||
StringFormatter::send(stream, F("<c CurrentMAIN %d C Milli 0 %d 1 %d>"), DCCWaveform::mainTrack.getCurrentmA(),
|
||||
|
@ -520,6 +528,12 @@ void DCCEXParser::parse(Print *stream, byte *com, RingStream * ringStream)
|
|||
StringFormatter::send(stream, F("<# %d>"), MAX_LOCOS);
|
||||
return;
|
||||
|
||||
case '-': // Forget Loco <- [cab]>
|
||||
if (params > 1 || p[0]<0) break;
|
||||
if (p[0]==0) DCC::forgetAllLocos();
|
||||
else DCC::forgetLoco(p[0]);
|
||||
return;
|
||||
|
||||
case 'F': // New command to call the new Loco Function API <F cab func 1|0>
|
||||
if (Diag::CMD)
|
||||
DIAG(F("Setting loco %d F%d %S"), p[0], p[1], p[2] ? F("ON") : F("OFF"));
|
||||
|
@ -757,9 +771,20 @@ bool DCCEXParser::parseD(Print *stream, int params, int p[])
|
|||
Diag::WITHROTTLE = onOff;
|
||||
return true;
|
||||
|
||||
case HASH_KEYWORD_LCN: // <D LCN ON/OFF>
|
||||
Diag::LCN = onOff;
|
||||
return true;
|
||||
|
||||
case HASH_KEYWORD_PROGBOOST:
|
||||
DCC::setProgTrackBoost(true);
|
||||
return true;
|
||||
return true;
|
||||
|
||||
case HASH_KEYWORD_RESET:
|
||||
{
|
||||
wdt_enable( WDTO_15MS); // set Arduino watchdog timer for 15ms
|
||||
delay(50); // wait for the prescaller time to expire
|
||||
break; // and <X> if we didnt restart
|
||||
}
|
||||
|
||||
case HASH_KEYWORD_EEPROM: // <D EEPROM NumEntries>
|
||||
if (params >= 2)
|
||||
|
|
|
@ -46,9 +46,9 @@ void DCCWaveform::begin(MotorDriver * mainDriver, MotorDriver * progDriver) {
|
|||
// Only use PWM if both pins are PWM capable. Otherwise JOIN does not work
|
||||
MotorDriver::usePWM= mainDriver->isPWMCapable() && progDriver->isPWMCapable();
|
||||
if (MotorDriver::usePWM)
|
||||
DIAG(F("\nWaveform using PWM pins for accuracy."));
|
||||
DIAG(F("\nSignal pin config: high accuracy waveform"));
|
||||
else
|
||||
DIAG(F("\nWaveform accuracy limited by signal pin configuration."));
|
||||
DIAG(F("\nSignal pin config: normal accuracy waveform"));
|
||||
DCCTimer::begin(DCCWaveform::interruptHandler);
|
||||
}
|
||||
|
||||
|
|
|
@ -94,6 +94,9 @@ class DCCWaveform {
|
|||
autoPowerOff=false;
|
||||
}
|
||||
};
|
||||
inline bool canMeasureCurrent() {
|
||||
return motorDriver->canMeasureCurrent();
|
||||
};
|
||||
inline void setAckLimit(int mA) {
|
||||
ackLimitmA = mA;
|
||||
}
|
||||
|
|
74
LCN.cpp
Normal file
74
LCN.cpp
Normal file
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* © 2021, Chris Harlow. All rights reserved.
|
||||
*
|
||||
* This file is part of DCC-EX CommandStation-EX
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "LCN.h"
|
||||
#include "DIAG.h"
|
||||
#include "Turnouts.h"
|
||||
#include "Sensors.h"
|
||||
|
||||
int LCN::id = 0;
|
||||
Stream * LCN::stream=NULL;
|
||||
bool LCN::firstLoop=true;
|
||||
|
||||
void LCN::init(Stream & lcnstream) {
|
||||
stream=&lcnstream;
|
||||
DIAG(F("\nLCN connection setup\n"));
|
||||
}
|
||||
|
||||
|
||||
// Inbound LCN traffic is postfix notation... nnnX where nnn is an id, X is the opcode
|
||||
void LCN::loop() {
|
||||
if (!stream) return;
|
||||
if (firstLoop) {
|
||||
firstLoop=false;
|
||||
stream->println('X');
|
||||
return;
|
||||
}
|
||||
|
||||
while (stream->available()) {
|
||||
int ch = stream->read();
|
||||
if (ch >= 0 && ch <= '9') { // accumulate id value
|
||||
id = 10 * id + ch - '0';
|
||||
}
|
||||
else if (ch == 't' || ch == 'T') { // Turnout opcodes
|
||||
if (Diag::LCN) DIAG(F("\nLCN IN %d%c\n"),id,(char)ch);
|
||||
Turnout * tt = Turnout::get(id);
|
||||
if (!tt) Turnout::create(id, LCN_TURNOUT_ADDRESS, 0);
|
||||
if (ch == 't') tt->data.tStatus |= STATUS_ACTIVE;
|
||||
else tt->data.tStatus &= ~STATUS_ACTIVE;
|
||||
Turnout::turnoutlistHash++; // signals ED update of turnout data
|
||||
id = 0;
|
||||
}
|
||||
else if (ch == 'S' || ch == 's') {
|
||||
if (Diag::LCN) DIAG(F("\nLCN IN %d%c\n"),id,(char)ch);
|
||||
Sensor * ss = Sensor::get(id);
|
||||
if (!ss) ss = Sensor::create(id, 255,0); // impossible pin
|
||||
ss->active = ch == 'S';
|
||||
id = 0;
|
||||
}
|
||||
else id = 0; // ignore any other garbage from LCN
|
||||
}
|
||||
}
|
||||
|
||||
void LCN::send(char opcode, int id, bool state) {
|
||||
if (stream) {
|
||||
StringFormatter::send(stream,F("%c/%d/%d"), opcode, id , state);
|
||||
if (Diag::LCN) DIAG(F("\nLCN OUT %c/%d/%d\n"), opcode, id , state);
|
||||
}
|
||||
}
|
16
LCN.h
Normal file
16
LCN.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
#ifndef LCN_h
|
||||
#define LCN_h
|
||||
#include <Arduino.h>
|
||||
|
||||
class LCN {
|
||||
public:
|
||||
static void init(Stream & lcnstream);
|
||||
static void loop();
|
||||
static void send(char opcode, int id, bool state);
|
||||
private :
|
||||
static bool firstLoop;
|
||||
static Stream * stream;
|
||||
static int id;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -67,9 +67,9 @@
|
|||
#define LCD_BACKLIGHT 0x08
|
||||
#define LCD_NOBACKLIGHT 0x00
|
||||
|
||||
#define En B00000100 // Enable bit
|
||||
#define Rw B00000010 // Read/Write bit
|
||||
#define Rs B00000001 // Register select bit
|
||||
#define En 0b00000100 // Enable bit
|
||||
#define Rw 0b00000010 // Read/Write bit
|
||||
#define Rs 0b00000001 // Register select bit
|
||||
|
||||
class LiquidCrystal_I2C : public Print {
|
||||
public:
|
||||
|
|
|
@ -58,7 +58,10 @@ MotorDriver::MotorDriver(byte power_pin, byte signal_pin, byte signal_pin2, int8
|
|||
else brakePin=UNUSED_PIN;
|
||||
|
||||
currentPin=current_pin;
|
||||
pinMode(currentPin, INPUT);
|
||||
if (currentPin!=UNUSED_PIN) {
|
||||
pinMode(currentPin, INPUT);
|
||||
senseOffset=analogRead(currentPin); // value of sensor at zero current
|
||||
}
|
||||
|
||||
faultPin=fault_pin;
|
||||
if (faultPin != UNUSED_PIN) {
|
||||
|
@ -69,6 +72,12 @@ MotorDriver::MotorDriver(byte power_pin, byte signal_pin, byte signal_pin2, int8
|
|||
senseFactor=sense_factor;
|
||||
tripMilliamps=trip_milliamps;
|
||||
rawCurrentTripValue=(int)(trip_milliamps / sense_factor);
|
||||
|
||||
if (currentPin==UNUSED_PIN)
|
||||
DIAG(F("\nMotorDriver ** WARNING ** No current or short detection\n"));
|
||||
else
|
||||
DIAG(F("\nMotorDriver currentPin=A%d, senseOffset=%d, rawCurentTripValue(relative to offset)=%d\n"),
|
||||
currentPin-A0, senseOffset,rawCurrentTripValue);
|
||||
}
|
||||
|
||||
bool MotorDriver::isPWMCapable() {
|
||||
|
@ -117,14 +126,24 @@ void MotorDriver::setSignal( bool high) {
|
|||
}
|
||||
}
|
||||
|
||||
bool MotorDriver::canMeasureCurrent() {
|
||||
return currentPin!=UNUSED_PIN;
|
||||
}
|
||||
/*
|
||||
* Return the current reading as pin reading 0 to 1023. If the fault
|
||||
* pin is activated return a negative current to show active fault pin.
|
||||
* As there is no -0, ceat a little and return -1 in that case.
|
||||
* As there is no -0, create a little and return -1 in that case.
|
||||
*
|
||||
* senseOffset handles the case where a shield returns values above or below
|
||||
* a central value depending on direction.
|
||||
*/
|
||||
int MotorDriver::getCurrentRaw() {
|
||||
int current = analogRead(currentPin);
|
||||
if (faultPin != UNUSED_PIN && isLOW(fastFaultPin) && isHIGH(fastPowerPin))
|
||||
if (currentPin==UNUSED_PIN) return 0;
|
||||
|
||||
int current = analogRead(currentPin)-senseOffset;
|
||||
if (current<0) current=0-current;
|
||||
|
||||
if ((faultPin != UNUSED_PIN) && isLOW(fastFaultPin) && isHIGH(fastPowerPin))
|
||||
return (current == 0 ? -1 : -current);
|
||||
return current;
|
||||
// IMPORTANT: This function can be called in Interrupt() time within the 56uS timer
|
||||
|
@ -140,7 +159,8 @@ int MotorDriver::mA2raw( unsigned int mA) {
|
|||
}
|
||||
|
||||
void MotorDriver::getFastPin(const FSH* type,int pin, bool input, FASTPIN & result) {
|
||||
DIAG(F("\nMotorDriver %S Pin=%d,"),type,pin);
|
||||
// DIAG(F("\nMotorDriver %S Pin=%d,"),type,pin);
|
||||
(void) type; // avoid compiler warning if diag not used above.
|
||||
uint8_t port = digitalPinToPort(pin);
|
||||
if (input)
|
||||
result.inout = portInputRegister(port);
|
||||
|
@ -148,5 +168,5 @@ void MotorDriver::getFastPin(const FSH* type,int pin, bool input, FASTPIN & res
|
|||
result.inout = portOutputRegister(port);
|
||||
result.maskHIGH = digitalPinToBitMask(pin);
|
||||
result.maskLOW = ~result.maskHIGH;
|
||||
DIAG(F(" port=0x%x, inoutpin=0x%x, isinput=%d, mask=0x%x\n"),port, result.inout,input,result.maskHIGH);
|
||||
// DIAG(F(" port=0x%x, inoutpin=0x%x, isinput=%d, mask=0x%x\n"),port, result.inout,input,result.maskHIGH);
|
||||
}
|
||||
|
|
|
@ -34,7 +34,8 @@ struct FASTPIN {
|
|||
|
||||
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);
|
||||
MotorDriver(byte power_pin, byte signal_pin, byte signal_pin2, int8_t brake_pin,
|
||||
byte current_pin, float senseFactor, unsigned int tripMilliamps, byte faultPin);
|
||||
virtual void setPower( bool on);
|
||||
virtual void setSignal( bool high);
|
||||
virtual void setBrake( bool on);
|
||||
|
@ -45,6 +46,7 @@ class MotorDriver {
|
|||
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() {
|
||||
|
@ -61,6 +63,7 @@ class MotorDriver {
|
|||
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;
|
||||
};
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
// If the brakePin is negative that means the sense
|
||||
// of the brake pin on the motor bridge is inverted
|
||||
// (HIGH == release brake)
|
||||
|
||||
//
|
||||
// Arduino standard Motor Shield
|
||||
#define STANDARD_MOTOR_SHIELD F("STANDARD_MOTOR_SHIELD"), \
|
||||
new MotorDriver(3, 12, UNUSED_PIN, UNUSED_PIN, A0, 2.99, 2000, UNUSED_PIN), \
|
||||
|
|
|
@ -34,6 +34,7 @@ bool Diag::CMD=false;
|
|||
bool Diag::WIFI=false;
|
||||
bool Diag::WITHROTTLE=false;
|
||||
bool Diag::ETHERNET=false;
|
||||
bool Diag::LCN=false;
|
||||
|
||||
|
||||
void StringFormatter::diag( const FSH* input...) {
|
||||
|
|
|
@ -33,6 +33,7 @@ class Diag {
|
|||
static bool WIFI;
|
||||
static bool WITHROTTLE;
|
||||
static bool ETHERNET;
|
||||
static bool LCN;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -55,6 +55,11 @@ void Turnout::activate(bool state) {
|
|||
#ifdef EESTOREDEBUG
|
||||
DIAG(F("\nTurnout::activate(%d)\n"),state);
|
||||
#endif
|
||||
if (data.address==LCN_TURNOUT_ADDRESS) {
|
||||
// A LCN turnout is transmitted to the LCN master.
|
||||
LCN::send('T',data.id,state);
|
||||
return; // The tStatus will be updated by a message from the LCN master, later.
|
||||
}
|
||||
if (state)
|
||||
data.tStatus|=STATUS_ACTIVE;
|
||||
else
|
||||
|
|
|
@ -21,11 +21,12 @@
|
|||
|
||||
#include <Arduino.h>
|
||||
#include "DCC.h"
|
||||
#include "LCN.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
|
||||
|
||||
const int LCN_TURNOUT_ADDRESS=-1; // spoof dcc address -1 indicates a LCN turnout
|
||||
struct TurnoutData {
|
||||
int id;
|
||||
uint8_t tStatus; // has STATUS_ACTIVE, STATUS_PWM, STATUS_PWMPIN
|
||||
|
|
Loading…
Reference in New Issue
Block a user