mirror of
https://github.com/DCC-EX/CommandStation-EX.git
synced 2024-11-23 16:16:13 +01:00
Compare commits
6 Commits
784088b0df
...
7e4093f03f
Author | SHA1 | Date | |
---|---|---|---|
|
7e4093f03f | ||
|
7ee4188d88 | ||
|
5742b71ec6 | ||
|
8705c8c33f | ||
|
e4904e4080 | ||
|
59b0e8383d |
16
DCC.cpp
16
DCC.cpp
|
@ -278,6 +278,22 @@ void DCC::setAccessory(int address, byte port, bool gate, byte onoff /*= 2*/) {
|
|||
}
|
||||
}
|
||||
|
||||
void DCC::setExtendedAccessory(int16_t address, int16_t value, byte repeats) {
|
||||
|
||||
// format is 10AAAAAA, 0AAA0AA1, 000XXXXX
|
||||
if (address != (address & 0x7F)) return;
|
||||
if (value != (value & 0x1F)) return;
|
||||
|
||||
byte b[3];
|
||||
b[0]= 0x80 | ((address & 0x7FF)>>5);
|
||||
b[1]= 0x01 | ((address & 0x1c)<<2) | (address & 0x03)<<1;
|
||||
b[2]=value & 0x1F;
|
||||
DCCWaveform::mainTrack.schedulePacket(b, sizeof(b), repeats); // Repeat on packet three times
|
||||
#if defined(EXRAIL_ACTIVE)
|
||||
// TODO RMFT2::activateExtendedEvent(address,value);
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
// writeCVByteMain: Write a byte with PoM on main. This writes
|
||||
// the 5 byte sized packet to implement this DCC function
|
||||
|
|
1
DCC.h
1
DCC.h
|
@ -71,6 +71,7 @@ public:
|
|||
static uint32_t getFunctionMap(int cab);
|
||||
static void updateGroupflags(byte &flags, int16_t functionNumber);
|
||||
static void setAccessory(int address, byte port, bool gate, byte onoff = 2);
|
||||
static void setExtendedAccessory(int16_t address, int16_t value, byte repeats=3);
|
||||
static bool writeTextPacket(byte *b, int nBytes);
|
||||
|
||||
// ACKable progtrack calls bitresults callback 0,0 or -1, cv returns value or -1
|
||||
|
|
|
@ -45,7 +45,7 @@ Once a new OPCODE is decided upon, update this list.
|
|||
0, Track power off
|
||||
1, Track power on
|
||||
a, DCC accessory control
|
||||
A,
|
||||
A, DCC extended accessory control
|
||||
b, Write CV bit on main
|
||||
B, Write CV bit
|
||||
c, Request current command
|
||||
|
@ -385,6 +385,18 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream)
|
|||
}
|
||||
return;
|
||||
|
||||
case 'A': // EXTENDED ACCESSORY <A address value>
|
||||
{
|
||||
// Note: if this happens to match a defined EXRAIL
|
||||
// DCCX_SIGNAL, then EXRAIL will have intercepted
|
||||
// this command alrerady.
|
||||
if (params!=2) break;
|
||||
if (p[0] != (p[0] & 0x7F)) break;
|
||||
if (p[1] != (p[1] & 0x1F)) break;
|
||||
DCC::setExtendedAccessory(p[0],p[1]);
|
||||
}
|
||||
return;
|
||||
|
||||
case 'T': // TURNOUT <T ...>
|
||||
if (parseT(stream, params, p))
|
||||
return;
|
||||
|
|
52
EXRAIL2.cpp
52
EXRAIL2.cpp
|
@ -800,6 +800,14 @@ void RMFT2::loop2() {
|
|||
DCC::setAccessory(addr,subaddr,active);
|
||||
break;
|
||||
}
|
||||
case OPCODE_ASPECT: {
|
||||
// operand is address<<5 | value
|
||||
int16_t address=operand>>5;
|
||||
byte aspect=operand & 0x1f;
|
||||
if (!signalAspectEvent(address,aspect))
|
||||
DCC::setExtendedAccessory(address,aspect);
|
||||
break;
|
||||
}
|
||||
|
||||
case OPCODE_FOLLOW:
|
||||
progCounter=routeLookup->find(operand);
|
||||
|
@ -1061,7 +1069,7 @@ int16_t RMFT2::getSignalSlot(int16_t id) {
|
|||
if (diag) DIAG(F(" doSignal %d %x"),id,rag);
|
||||
|
||||
// Schedule any event handler for this signal change.
|
||||
// Thjis will work even without a signal definition.
|
||||
// This will work even without a signal definition.
|
||||
if (rag==SIGNAL_RED) onRedLookup->handleEvent(F("RED"),id);
|
||||
else if (rag==SIGNAL_GREEN) onGreenLookup->handleEvent(F("GREEN"),id);
|
||||
else onAmberLookup->handleEvent(F("AMBER"),id);
|
||||
|
@ -1098,6 +1106,16 @@ int16_t RMFT2::getSignalSlot(int16_t id) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (sigtype== DCCX_SIGNAL_FLAG) {
|
||||
// redpin,amberpin,greenpin are the 3 aspects
|
||||
byte value=redpin;
|
||||
if (rag==SIGNAL_AMBER) value=amberpin;
|
||||
if (rag==SIGNAL_GREEN) value=greenpin;
|
||||
DCC::setExtendedAccessory(sigid & SIGNAL_ID_MASK,value);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// LED or similar 3 pin signal, (all pins zero would be a virtual signal)
|
||||
// If amberpin is zero, synthesise amber from red+green
|
||||
const byte SIMAMBER=0x00;
|
||||
|
@ -1131,6 +1149,38 @@ int16_t RMFT2::getSignalSlot(int16_t id) {
|
|||
return (flags[sigslot] & SIGNAL_MASK) == rag;
|
||||
}
|
||||
|
||||
|
||||
// signalAspectEvent returns true if the aspect is destined
|
||||
// for a defined DCCX_SIGNAL which will handle all the RAG flags
|
||||
// and ON* handlers.
|
||||
// Otherwise false so the parser should send the command directly
|
||||
bool RMFT2::signalAspectEvent(int16_t address, byte aspect ) {
|
||||
if (!(compileFeatures & FEATURE_SIGNAL)) return false;
|
||||
int16_t sigslot=getSignalSlot(address);
|
||||
if (sigslot<0) return false; // this is not a defined signal
|
||||
int16_t sigpos=sigslot*8;
|
||||
VPIN sigid=GETHIGHFLASHW(RMFT2::SignalDefinitions,sigpos);
|
||||
VPIN sigtype=sigid & ~SIGNAL_ID_MASK;
|
||||
if (sigtype!=DCCX_SIGNAL_FLAG) return false; // not a DCCX signal
|
||||
// Turn an aspect change into a RED/AMBER/GREEN setting
|
||||
if (aspect==GETHIGHFLASHW(RMFT2::SignalDefinitions,sigpos+2)) {
|
||||
doSignal(sigid,SIGNAL_RED);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (aspect==GETHIGHFLASHW(RMFT2::SignalDefinitions,sigpos+4)) {
|
||||
doSignal(sigid,SIGNAL_AMBER);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (aspect==GETHIGHFLASHW(RMFT2::SignalDefinitions,sigpos+6)) {
|
||||
doSignal(sigid,SIGNAL_GREEN);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false; // aspect is not a defined one
|
||||
}
|
||||
|
||||
void RMFT2::turnoutEvent(int16_t turnoutId, bool closed) {
|
||||
// Hunt for an ONTHROW/ONCLOSE for this turnout
|
||||
if (closed) onCloseLookup->handleEvent(F("CLOSE"),turnoutId);
|
||||
|
|
|
@ -54,7 +54,7 @@ enum OPCODE : byte {OPCODE_THROW,OPCODE_CLOSE,
|
|||
OPCODE_START,OPCODE_SETLOCO,OPCODE_SENDLOCO,OPCODE_FORGET,
|
||||
OPCODE_PAUSE, OPCODE_RESUME,OPCODE_POWEROFF,OPCODE_POWERON,
|
||||
OPCODE_ONCLOSE, OPCODE_ONTHROW, OPCODE_SERVOTURNOUT, OPCODE_PINTURNOUT,
|
||||
OPCODE_PRINT,OPCODE_DCCACTIVATE,
|
||||
OPCODE_PRINT,OPCODE_DCCACTIVATE,OPCODE_ASPECT,
|
||||
OPCODE_ONACTIVATE,OPCODE_ONDEACTIVATE,
|
||||
OPCODE_ROSTER,OPCODE_KILLALL,
|
||||
OPCODE_ROUTE,OPCODE_AUTOMATION,OPCODE_SEQUENCE,
|
||||
|
@ -155,9 +155,11 @@ class LookList {
|
|||
static void clockEvent(int16_t clocktime, bool change);
|
||||
static void rotateEvent(int16_t id, bool change);
|
||||
static void powerEvent(int16_t track, bool overload);
|
||||
static bool signalAspectEvent(int16_t address, byte aspect );
|
||||
static const int16_t SERVO_SIGNAL_FLAG=0x4000;
|
||||
static const int16_t ACTIVE_HIGH_SIGNAL_FLAG=0x2000;
|
||||
static const int16_t DCC_SIGNAL_FLAG=0x1000;
|
||||
static const int16_t DCCX_SIGNAL_FLAG=0x3000;
|
||||
static const int16_t SIGNAL_ID_MASK=0x0FFF;
|
||||
// Throttle Info Access functions built by exrail macros
|
||||
static const byte rosterNameCount;
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#undef ALIAS
|
||||
#undef AMBER
|
||||
#undef ANOUT
|
||||
#undef ASPECT
|
||||
#undef AT
|
||||
#undef ATGTE
|
||||
#undef ATLT
|
||||
|
@ -44,6 +45,7 @@
|
|||
#undef CLOSE
|
||||
#undef CONFIGURE_SERVO
|
||||
#undef DCC_SIGNAL
|
||||
#undef DCCX_SIGNAL
|
||||
#undef DCC_TURNTABLE
|
||||
#undef DEACTIVATE
|
||||
#undef DEACTIVATEL
|
||||
|
@ -186,6 +188,7 @@
|
|||
#define AMBER(signal_id)
|
||||
#define ANOUT(vpin,value,param1,param2)
|
||||
#define AT(sensor_id)
|
||||
#define ASPECT(address,value)
|
||||
#define ATGTE(sensor_id,value)
|
||||
#define ATLT(sensor_id,value)
|
||||
#define ATTIMEOUT(sensor_id,timeout_ms)
|
||||
|
@ -198,6 +201,7 @@
|
|||
#define CLOSE(id)
|
||||
#define CONFIGURE_SERVO(vpin,pos1,pos2,profile)
|
||||
#define DCC_SIGNAL(id,add,subaddr)
|
||||
#define DCCX_SIGNAL(id,redAspect,amberAspect,greenAspect)
|
||||
#define DCC_TURNTABLE(id,home,description)
|
||||
#define DEACTIVATE(addr,subaddr)
|
||||
#define DEACTIVATEL(addr)
|
||||
|
|
|
@ -51,6 +51,14 @@ void RMFT2::ComandFilter(Print * stream, byte & opcode, byte & paramCount, int16
|
|||
opcode=0;
|
||||
break;
|
||||
|
||||
case 'A': // <A address aspect>
|
||||
if (paramCount!=2) break;
|
||||
// Ask exrail if this is just changing the aspect on a
|
||||
// predefined DCCX_SIGNAL. Because this will handle all
|
||||
// the IFRED and ONRED type issues at the same time.
|
||||
if (signalAspectEvent(p[0],p[1])) opcode=0; // all done
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
// This entire code block is compiled out if LLC macros not used
|
||||
if (!(compileFeatures & FEATURE_LCC)) return;
|
||||
|
|
|
@ -117,6 +117,9 @@ static_assert(!hasdup(compileTimeSequenceList[0],1),"Duplicate SEQUENCE/ROUTE/AU
|
|||
// - check range on LATCH/UNLATCH
|
||||
// This pass generates no runtime data or code
|
||||
#include "EXRAIL2MacroReset.h"
|
||||
#undef ASPECT
|
||||
#define ASPECT(address,value) static_assert((address & 0x7ff)== address, "invalid Address"); \
|
||||
static_assert((value & 0x1F)== value, "Invalid value");
|
||||
#undef CALL
|
||||
#define CALL(id) static_assert(hasseq(id),"Sequence not found");
|
||||
#undef FOLLOW
|
||||
|
@ -169,6 +172,8 @@ bool exrailHalSetup() {
|
|||
#define SERVO_SIGNAL(vpin,redval,amberval,greenval) | FEATURE_SIGNAL
|
||||
#undef DCC_SIGNAL
|
||||
#define DCC_SIGNAL(id,addr,subaddr) | FEATURE_SIGNAL
|
||||
#undef DCCX_SIGNAL
|
||||
#define DCCX_SIGNAL(id,redAspect,amberAspect,greenAspect) | FEATURE_SIGNAL
|
||||
#undef VIRTUAL_SIGNAL
|
||||
#define VIRTUAL_SIGNAL(id) | FEATURE_SIGNAL
|
||||
|
||||
|
@ -398,6 +403,8 @@ const FSH * RMFT2::getRosterFunctions(int16_t id) {
|
|||
#define SERVO_SIGNAL(vpin,redval,amberval,greenval) vpin | RMFT2::SERVO_SIGNAL_FLAG,redval,amberval,greenval,
|
||||
#undef DCC_SIGNAL
|
||||
#define DCC_SIGNAL(id,addr,subaddr) id | RMFT2::DCC_SIGNAL_FLAG,addr,subaddr,0,
|
||||
#undef DCCX_SIGNAL
|
||||
#define DCCX_SIGNAL(id,redAspect,amberAspect,greenAspect) id | RMFT2::DCCX_SIGNAL_FLAG,redAspect,amberAspect,greenAspect,
|
||||
#undef VIRTUAL_SIGNAL
|
||||
#define VIRTUAL_SIGNAL(id) id,0,0,0,
|
||||
|
||||
|
@ -432,6 +439,7 @@ int RMFT2::onLCCLookup[RMFT2::countLCCLookup];
|
|||
#define ALIAS(name,value...)
|
||||
#define AMBER(signal_id) OPCODE_AMBER,V(signal_id),
|
||||
#define ANOUT(vpin,value,param1,param2) OPCODE_SERVO,V(vpin),OPCODE_PAD,V(value),OPCODE_PAD,V(param1),OPCODE_PAD,V(param2),
|
||||
#define ASPECT(address,value) OPCODE_ASPECT,V((address<<5) | (value & 0x1F)),
|
||||
#define AT(sensor_id) OPCODE_AT,V(sensor_id),
|
||||
#define ATGTE(sensor_id,value) OPCODE_ATGTE,V(sensor_id),OPCODE_PAD,V(value),
|
||||
#define ATLT(sensor_id,value) OPCODE_ATLT,V(sensor_id),OPCODE_PAD,V(value),
|
||||
|
@ -453,6 +461,7 @@ int RMFT2::onLCCLookup[RMFT2::countLCCLookup];
|
|||
#define DELAYMINS(mindelay) OPCODE_DELAYMINS,V(mindelay),
|
||||
#define DELAYRANDOM(mindelay,maxdelay) DELAY(mindelay) OPCODE_RANDWAIT,V((maxdelay-mindelay)/100L),
|
||||
#define DCC_SIGNAL(id,add,subaddr)
|
||||
#define DCCX_SIGNAL(id,redAspect,amberAspect,greenAspect)
|
||||
#define DONE OPCODE_ENDTASK,0,0,
|
||||
#define DRIVE(analogpin) OPCODE_DRIVE,V(analogpin),
|
||||
#define ELSE OPCODE_ELSE,0,0,
|
||||
|
|
|
@ -3,7 +3,11 @@
|
|||
|
||||
#include "StringFormatter.h"
|
||||
|
||||
#define VERSION "5.2.33"
|
||||
#define VERSION "5.2.34"
|
||||
// 5.2.34 - <A address aspect> Command fopr DCC Extended Accessories
|
||||
// - Exrail ASPECT(address,aspect) for above.
|
||||
// - EXRAIL DCCX_SIGNAL(Address,redAspect,amberAspect,greenAspect)
|
||||
// - Exrail intercept <A ...> for DCC Signals.
|
||||
// 5.2.33 - Exrail CONFIGURE_SERVO(vpin,pos1,pos2,profile)
|
||||
// 5.2.32 - Railcom Cutout (Initial trial Mega2560 only)
|
||||
// 5.2.31 - Exrail JMRI_SENSOR(vpin [,count]) creates <S> types.
|
||||
|
|
Loading…
Reference in New Issue
Block a user