mirror of
https://github.com/DCC-EX/CommandStation-EX.git
synced 2024-11-26 09:36:13 +01:00
Neopixel signals with blue-tint
See Release Notes file
This commit is contained in:
parent
8e6fe6df21
commit
3aabb51888
164
EXRAIL2.cpp
164
EXRAIL2.cpp
|
@ -73,6 +73,7 @@ RMFT2 * RMFT2::pausingTask=NULL; // Task causing a PAUSE.
|
||||||
byte RMFT2::flags[MAX_FLAGS];
|
byte RMFT2::flags[MAX_FLAGS];
|
||||||
Print * RMFT2::LCCSerial=0;
|
Print * RMFT2::LCCSerial=0;
|
||||||
LookList * RMFT2::routeLookup=NULL;
|
LookList * RMFT2::routeLookup=NULL;
|
||||||
|
LookList * RMFT2::signalLookup=NULL;
|
||||||
LookList * RMFT2::onThrowLookup=NULL;
|
LookList * RMFT2::onThrowLookup=NULL;
|
||||||
LookList * RMFT2::onCloseLookup=NULL;
|
LookList * RMFT2::onCloseLookup=NULL;
|
||||||
LookList * RMFT2::onActivateLookup=NULL;
|
LookList * RMFT2::onActivateLookup=NULL;
|
||||||
|
@ -207,16 +208,28 @@ LookList* RMFT2::LookListLoader(OPCODE op1, OPCODE op2, OPCODE op3) {
|
||||||
// Second pass startup, define any turnouts or servos, set signals red
|
// Second pass startup, define any turnouts or servos, set signals red
|
||||||
// add sequences onRoutines to the lookups
|
// add sequences onRoutines to the lookups
|
||||||
if (compileFeatures & FEATURE_SIGNAL) {
|
if (compileFeatures & FEATURE_SIGNAL) {
|
||||||
|
|
||||||
onRedLookup=LookListLoader(OPCODE_ONRED);
|
onRedLookup=LookListLoader(OPCODE_ONRED);
|
||||||
onAmberLookup=LookListLoader(OPCODE_ONAMBER);
|
onAmberLookup=LookListLoader(OPCODE_ONAMBER);
|
||||||
onGreenLookup=LookListLoader(OPCODE_ONGREEN);
|
onGreenLookup=LookListLoader(OPCODE_ONGREEN);
|
||||||
for (int sigslot=0;;sigslot++) {
|
// Load the signal lookup with slot numbers in the signal table
|
||||||
int16_t sighandle=GETHIGHFLASHW(RMFT2::SignalDefinitions,sigslot*8);
|
int signalCount=0;
|
||||||
if (sighandle==0) break; // end of signal list
|
for (int16_t slot=0;;slot++) {
|
||||||
VPIN sigid = sighandle & SIGNAL_ID_MASK;
|
SIGNAL_DEFINITION signal=getSignalSlot(slot);
|
||||||
doSignal(sigid, SIGNAL_RED);
|
DIAG(F("Signal s=%d id=%d t=%d"),slot,signal.id,signal.type);
|
||||||
}
|
if (signal.type==sigtypeNoMoreSignals) break;
|
||||||
}
|
if (signal.type==sigtypeContinuation) continue;
|
||||||
|
signalCount++;
|
||||||
|
}
|
||||||
|
signalLookup=new LookList(signalCount);
|
||||||
|
for (int16_t slot=0;;slot++) {
|
||||||
|
SIGNAL_DEFINITION signal=getSignalSlot(slot);
|
||||||
|
if (signal.type==sigtypeNoMoreSignals) break;
|
||||||
|
if (signal.type==sigtypeContinuation) continue;
|
||||||
|
signalLookup->add(signal.id,slot);
|
||||||
|
doSignal(signal.id, SIGNAL_RED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int progCounter;
|
int progCounter;
|
||||||
for (progCounter=0;; SKIPOP){
|
for (progCounter=0;; SKIPOP){
|
||||||
|
@ -1136,26 +1149,11 @@ void RMFT2::kill(const FSH * reason, int operand) {
|
||||||
delete this;
|
delete this;
|
||||||
}
|
}
|
||||||
|
|
||||||
int16_t RMFT2::getSignalSlot(int16_t id) {
|
|
||||||
|
|
||||||
if (id > 0) {
|
SIGNAL_DEFINITION RMFT2::getSignalSlot(int16_t slot) {
|
||||||
int sigslot = 0;
|
SIGNAL_DEFINITION signal;
|
||||||
int16_t sighandle = 0;
|
COPYHIGHFLASH(&signal,SignalDefinitions,slot*sizeof(SIGNAL_DEFINITION),sizeof(SIGNAL_DEFINITION));
|
||||||
// Trundle down the signal list until we reach the end
|
return signal;
|
||||||
while ((sighandle = GETHIGHFLASHW(RMFT2::SignalDefinitions, sigslot * 8)) != 0)
|
|
||||||
{
|
|
||||||
// sigid is the signal id used in RED/AMBER/GREEN macro
|
|
||||||
// for a LED signal it will be same as redpin
|
|
||||||
// but for a servo signal it will also have SERVO_SIGNAL_FLAG set.
|
|
||||||
VPIN sigid = sighandle & SIGNAL_ID_MASK;
|
|
||||||
if (sigid == (VPIN)id) // cast to keep compiler happy but id is positive
|
|
||||||
return sigslot; // found it
|
|
||||||
sigslot++; // keep looking
|
|
||||||
};
|
|
||||||
}
|
|
||||||
// If we got here, we did not find the signal
|
|
||||||
DIAG(F("EXRAIL Signal %d not defined"), id);
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ void RMFT2::doSignal(int16_t id,char rag) {
|
/* static */ void RMFT2::doSignal(int16_t id,char rag) {
|
||||||
|
@ -1168,90 +1166,97 @@ int16_t RMFT2::getSignalSlot(int16_t id) {
|
||||||
else if (rag==SIGNAL_GREEN) onGreenLookup->handleEvent(F("GREEN"),id);
|
else if (rag==SIGNAL_GREEN) onGreenLookup->handleEvent(F("GREEN"),id);
|
||||||
else onAmberLookup->handleEvent(F("AMBER"),id);
|
else onAmberLookup->handleEvent(F("AMBER"),id);
|
||||||
|
|
||||||
int16_t sigslot=getSignalSlot(id);
|
auto sigslot=signalLookup->find(id);
|
||||||
if (sigslot<0) return;
|
if (sigslot<0) return;
|
||||||
|
|
||||||
// keep track of signal state
|
// keep track of signal state
|
||||||
setFlag(sigslot,rag,SIGNAL_MASK);
|
setFlag(sigslot,rag,SIGNAL_MASK);
|
||||||
|
|
||||||
// Correct signal definition found, get the rag values
|
// Correct signal definition found, get the rag values
|
||||||
int16_t sigpos=sigslot*8;
|
auto signal=getSignalSlot(sigslot);
|
||||||
int16_t sighandle=GETHIGHFLASHW(RMFT2::SignalDefinitions,sigpos);
|
|
||||||
VPIN redpin=GETHIGHFLASHW(RMFT2::SignalDefinitions,sigpos+2);
|
switch (signal.type) {
|
||||||
VPIN amberpin=GETHIGHFLASHW(RMFT2::SignalDefinitions,sigpos+4);
|
case sigtypeSERVO:
|
||||||
VPIN greenpin=GETHIGHFLASHW(RMFT2::SignalDefinitions,sigpos+6);
|
{
|
||||||
//if (diag) DIAG(F("signal %d %d %d %d %d"),sigid,id,redpin,amberpin,greenpin);
|
auto servopos = rag==SIGNAL_RED? signal.redpin: (rag==SIGNAL_GREEN? signal.greenpin : signal.amberpin);
|
||||||
|
|
||||||
VPIN sigtype=sighandle & ~SIGNAL_ID_MASK;
|
|
||||||
VPIN sigid = sighandle & SIGNAL_ID_MASK;
|
|
||||||
|
|
||||||
if (sigtype == SERVO_SIGNAL_FLAG) {
|
|
||||||
// A servo signal, the pin numbers are actually servo positions
|
|
||||||
// Note, setting a signal to a zero position has no effect.
|
|
||||||
int16_t servopos= rag==SIGNAL_RED? redpin: (rag==SIGNAL_GREEN? greenpin : amberpin);
|
|
||||||
//if (diag) DIAG(F("sigA %d %d"),id,servopos);
|
//if (diag) DIAG(F("sigA %d %d"),id,servopos);
|
||||||
if (servopos!=0) IODevice::writeAnalogue(id,servopos,PCA9685::Bounce);
|
if (servopos!=0) IODevice::writeAnalogue(id,servopos,PCA9685::Bounce);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case sigtypeDCC:
|
||||||
if (sigtype== DCC_SIGNAL_FLAG) {
|
{
|
||||||
// redpin,amberpin are the DCC addr,subaddr
|
// redpin,amberpin are the DCC addr,subaddr
|
||||||
DCC::setAccessory(redpin,amberpin, rag!=SIGNAL_RED);
|
DCC::setAccessory(signal.redpin,signal.amberpin, rag!=SIGNAL_RED);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sigtype== DCCX_SIGNAL_FLAG) {
|
case sigtypeDCCX:
|
||||||
|
{
|
||||||
// redpin,amberpin,greenpin are the 3 aspects
|
// redpin,amberpin,greenpin are the 3 aspects
|
||||||
byte value=redpin;
|
auto value=signal.redpin;
|
||||||
if (rag==SIGNAL_AMBER) value=amberpin;
|
if (rag==SIGNAL_AMBER) value=signal.amberpin;
|
||||||
if (rag==SIGNAL_GREEN) value=greenpin;
|
if (rag==SIGNAL_GREEN) value=signal.greenpin;
|
||||||
DCC::setExtendedAccessory(sigid, value);
|
DCC::setExtendedAccessory(id, value);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sigtype== NEOPIXEL_SIGNAL_FLAG) {
|
case sigtypeNEOPIXEL:
|
||||||
|
{
|
||||||
// redpin,amberpin,greenpin are the 3 RG values but with no blue permitted. . (code limitation hack)
|
// redpin,amberpin,greenpin are the 3 RG values but with no blue permitted. . (code limitation hack)
|
||||||
int colour_RG=redpin;
|
auto colour_RG=signal.redpin;
|
||||||
if (rag==SIGNAL_AMBER) colour_RG=amberpin;
|
if (rag==SIGNAL_AMBER) colour_RG=signal.amberpin;
|
||||||
if (rag==SIGNAL_GREEN) colour_RG=greenpin;
|
if (rag==SIGNAL_GREEN) colour_RG=signal.greenpin;
|
||||||
IODevice::writeAnalogue(sigid, colour_RG,true,0);
|
|
||||||
|
// blue channel is in followng signal slot (a continuation)
|
||||||
|
auto signal2=getSignalSlot(sigslot+1);
|
||||||
|
auto colour_B=signal2.redpin;
|
||||||
|
if (rag==SIGNAL_AMBER) colour_B=signal2.amberpin;
|
||||||
|
if (rag==SIGNAL_GREEN) colour_B=signal2.greenpin;
|
||||||
|
IODevice::writeAnalogue(id, colour_RG,true,colour_B);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case sigtypeSIGNAL:
|
||||||
|
case sigtypeSIGNALH:
|
||||||
|
{
|
||||||
// LED or similar 3 pin signal, (all pins zero would be a virtual signal)
|
// LED or similar 3 pin signal, (all pins zero would be a virtual signal)
|
||||||
// If amberpin is zero, synthesise amber from red+green
|
// If amberpin is zero, synthesise amber from red+green
|
||||||
const byte SIMAMBER=0x00;
|
const byte SIMAMBER=0x00;
|
||||||
if (rag==SIGNAL_AMBER && (amberpin==0)) rag=SIMAMBER; // special case this func only
|
if (rag==SIGNAL_AMBER && (signal.amberpin==0)) rag=SIMAMBER; // special case this func only
|
||||||
|
|
||||||
// Manage invert (HIGH on) pins
|
// Manage invert (HIGH on) pins
|
||||||
bool aHigh=sighandle & ACTIVE_HIGH_SIGNAL_FLAG;
|
bool aHigh=signal.type==sigtypeSIGNALH;
|
||||||
|
|
||||||
// set the three pins
|
// set the three pins
|
||||||
if (redpin) {
|
if (signal.redpin) {
|
||||||
bool redval=(rag==SIGNAL_RED || rag==SIMAMBER);
|
bool redval=(rag==SIGNAL_RED || rag==SIMAMBER);
|
||||||
if (!aHigh) redval=!redval;
|
if (!aHigh) redval=!redval;
|
||||||
killBlinkOnVpin(redpin);
|
killBlinkOnVpin(signal.redpin);
|
||||||
IODevice::write(redpin,redval);
|
IODevice::write(signal.redpin,redval);
|
||||||
}
|
}
|
||||||
if (amberpin) {
|
if (signal.amberpin) {
|
||||||
bool amberval=(rag==SIGNAL_AMBER);
|
bool amberval=(rag==SIGNAL_AMBER);
|
||||||
if (!aHigh) amberval=!amberval;
|
if (!aHigh) amberval=!amberval;
|
||||||
killBlinkOnVpin(amberpin);
|
killBlinkOnVpin(signal.amberpin);
|
||||||
IODevice::write(amberpin,amberval);
|
IODevice::write(signal.amberpin,amberval);
|
||||||
}
|
}
|
||||||
if (greenpin) {
|
if (signal.greenpin) {
|
||||||
bool greenval=(rag==SIGNAL_GREEN || rag==SIMAMBER);
|
bool greenval=(rag==SIGNAL_GREEN || rag==SIMAMBER);
|
||||||
if (!aHigh) greenval=!greenval;
|
if (!aHigh) greenval=!greenval;
|
||||||
killBlinkOnVpin(greenpin);
|
killBlinkOnVpin(signal.greenpin);
|
||||||
IODevice::write(greenpin,greenval);
|
IODevice::write(signal.greenpin,greenval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case sigtypeVIRTUAL: break;
|
||||||
|
case sigtypeContinuation: break;
|
||||||
|
case sigtypeNoMoreSignals: break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ bool RMFT2::isSignal(int16_t id,char rag) {
|
/* static */ bool RMFT2::isSignal(int16_t id,char rag) {
|
||||||
if (!(compileFeatures & FEATURE_SIGNAL)) return false;
|
if (!(compileFeatures & FEATURE_SIGNAL)) return false;
|
||||||
int16_t sigslot=getSignalSlot(id);
|
int16_t sigslot=signalLookup->find(id);
|
||||||
if (sigslot<0) return false;
|
if (sigslot<0) return false;
|
||||||
return (flags[sigslot] & SIGNAL_MASK) == rag;
|
return (flags[sigslot] & SIGNAL_MASK) == rag;
|
||||||
}
|
}
|
||||||
|
@ -1263,26 +1268,23 @@ if (sigtype== NEOPIXEL_SIGNAL_FLAG) {
|
||||||
// Otherwise false so the parser should send the command directly
|
// Otherwise false so the parser should send the command directly
|
||||||
bool RMFT2::signalAspectEvent(int16_t address, byte aspect ) {
|
bool RMFT2::signalAspectEvent(int16_t address, byte aspect ) {
|
||||||
if (!(compileFeatures & FEATURE_SIGNAL)) return false;
|
if (!(compileFeatures & FEATURE_SIGNAL)) return false;
|
||||||
int16_t sigslot=getSignalSlot(address);
|
auto sigslot=signalLookup->find(address);
|
||||||
if (sigslot<0) return false; // this is not a defined signal
|
if (sigslot<0) return false; // this is not a defined signal
|
||||||
int16_t sigpos=sigslot*8;
|
auto signal=getSignalSlot(sigslot);
|
||||||
int16_t sighandle=GETHIGHFLASHW(RMFT2::SignalDefinitions,sigpos);
|
if (signal.type!=sigtypeDCCX) return false; // not a DCCX signal
|
||||||
VPIN sigtype=sighandle & ~SIGNAL_ID_MASK;
|
|
||||||
VPIN sigid = sighandle & SIGNAL_ID_MASK;
|
|
||||||
if (sigtype!=DCCX_SIGNAL_FLAG) return false; // not a DCCX signal
|
|
||||||
// Turn an aspect change into a RED/AMBER/GREEN setting
|
// Turn an aspect change into a RED/AMBER/GREEN setting
|
||||||
if (aspect==GETHIGHFLASHW(RMFT2::SignalDefinitions,sigpos+2)) {
|
if (aspect==signal.redpin) {
|
||||||
doSignal(sigid,SIGNAL_RED);
|
doSignal(address,SIGNAL_RED);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aspect==GETHIGHFLASHW(RMFT2::SignalDefinitions,sigpos+4)) {
|
if (aspect==signal.amberpin) {
|
||||||
doSignal(sigid,SIGNAL_AMBER);
|
doSignal(address,SIGNAL_AMBER);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aspect==GETHIGHFLASHW(RMFT2::SignalDefinitions,sigpos+6)) {
|
if (aspect==signal.greenpin) {
|
||||||
doSignal(sigid,SIGNAL_GREEN);
|
doSignal(address,SIGNAL_GREEN);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
34
EXRAIL2.h
34
EXRAIL2.h
|
@ -110,6 +110,23 @@ enum BlinkState: byte {
|
||||||
blink_high, // blink task running with pin high
|
blink_high, // blink task running with pin high
|
||||||
at_timeout // ATTIMEOUT timed out flag
|
at_timeout // ATTIMEOUT timed out flag
|
||||||
};
|
};
|
||||||
|
enum SignalType {
|
||||||
|
sigtypeVIRTUAL,
|
||||||
|
sigtypeSIGNAL,
|
||||||
|
sigtypeSIGNALH,
|
||||||
|
sigtypeDCC,
|
||||||
|
sigtypeDCCX,
|
||||||
|
sigtypeSERVO,
|
||||||
|
sigtypeNEOPIXEL,
|
||||||
|
sigtypeContinuation, // neopixels require a second line
|
||||||
|
sigtypeNoMoreSignals
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SIGNAL_DEFINITION {
|
||||||
|
SignalType type;
|
||||||
|
VPIN id;
|
||||||
|
VPIN redpin,amberpin,greenpin;
|
||||||
|
};
|
||||||
|
|
||||||
// Flag bits for compile time features.
|
// Flag bits for compile time features.
|
||||||
static const byte FEATURE_SIGNAL= 0x80;
|
static const byte FEATURE_SIGNAL= 0x80;
|
||||||
|
@ -171,15 +188,7 @@ class LookList {
|
||||||
static void rotateEvent(int16_t id, bool change);
|
static void rotateEvent(int16_t id, bool change);
|
||||||
static void powerEvent(int16_t track, bool overload);
|
static void powerEvent(int16_t track, bool overload);
|
||||||
static bool signalAspectEvent(int16_t address, byte aspect );
|
static bool signalAspectEvent(int16_t address, byte aspect );
|
||||||
static const int16_t SERVO_SIGNAL_FLAG=0x4000;
|
// Throttle Info Access functions built by exrail macros
|
||||||
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 NEOPIXEL_SIGNAL_FLAG=0x5000;
|
|
||||||
static const int16_t SIGNAL_ID_MASK=0x0FFF;
|
|
||||||
// Neopixel has last bit 1 for colour on, otherwise black (to allow for blinking etc with SET/RESET)
|
|
||||||
static const int16_t NEOPIXEL_FLAG_ON=0x0001;
|
|
||||||
// Throttle Info Access functions built by exrail macros
|
|
||||||
static const byte rosterNameCount;
|
static const byte rosterNameCount;
|
||||||
static const int16_t HIGHFLASH routeIdList[];
|
static const int16_t HIGHFLASH routeIdList[];
|
||||||
static const int16_t HIGHFLASH automationIdList[];
|
static const int16_t HIGHFLASH automationIdList[];
|
||||||
|
@ -193,7 +202,8 @@ class LookList {
|
||||||
static const FSH * getTurntablePositionDescription(int16_t turntableId, uint8_t positionId);
|
static const FSH * getTurntablePositionDescription(int16_t turntableId, uint8_t positionId);
|
||||||
static void startNonRecursiveTask(const FSH* reason, int16_t id,int pc);
|
static void startNonRecursiveTask(const FSH* reason, int16_t id,int pc);
|
||||||
static bool readSensor(uint16_t sensorId);
|
static bool readSensor(uint16_t sensorId);
|
||||||
static bool isSignal(int16_t id,char rag);
|
static bool isSignal(int16_t id,char rag);
|
||||||
|
static SIGNAL_DEFINITION getSignalSlot(int16_t slotno);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void ComandFilter(Print * stream, byte & opcode, byte & paramCount, int16_t p[]);
|
static void ComandFilter(Print * stream, byte & opcode, byte & paramCount, int16_t p[]);
|
||||||
|
@ -203,7 +213,6 @@ private:
|
||||||
static bool getFlag(VPIN id,byte mask);
|
static bool getFlag(VPIN id,byte mask);
|
||||||
static int16_t progtrackLocoId;
|
static int16_t progtrackLocoId;
|
||||||
static void doSignal(int16_t id,char rag);
|
static void doSignal(int16_t id,char rag);
|
||||||
static int16_t getSignalSlot(int16_t id);
|
|
||||||
static void setTurnoutHiddenState(Turnout * t);
|
static void setTurnoutHiddenState(Turnout * t);
|
||||||
#ifndef IO_NO_HAL
|
#ifndef IO_NO_HAL
|
||||||
static void setTurntableHiddenState(Turntable * tto);
|
static void setTurntableHiddenState(Turntable * tto);
|
||||||
|
@ -227,10 +236,11 @@ private:
|
||||||
|
|
||||||
static bool diag;
|
static bool diag;
|
||||||
static const HIGHFLASH3 byte RouteCode[];
|
static const HIGHFLASH3 byte RouteCode[];
|
||||||
static const HIGHFLASH int16_t SignalDefinitions[];
|
static const HIGHFLASH SIGNAL_DEFINITION SignalDefinitions[];
|
||||||
static byte flags[MAX_FLAGS];
|
static byte flags[MAX_FLAGS];
|
||||||
static Print * LCCSerial;
|
static Print * LCCSerial;
|
||||||
static LookList * routeLookup;
|
static LookList * routeLookup;
|
||||||
|
static LookList * signalLookup;
|
||||||
static LookList * onThrowLookup;
|
static LookList * onThrowLookup;
|
||||||
static LookList * onCloseLookup;
|
static LookList * onCloseLookup;
|
||||||
static LookList * onActivateLookup;
|
static LookList * onActivateLookup;
|
||||||
|
|
|
@ -252,13 +252,13 @@ bool RMFT2::parseSlash(Print * stream, byte & paramCount, int16_t p[]) {
|
||||||
// do the signals
|
// do the signals
|
||||||
// flags[n] represents the state of the nth signal in the table
|
// flags[n] represents the state of the nth signal in the table
|
||||||
for (int sigslot=0;;sigslot++) {
|
for (int sigslot=0;;sigslot++) {
|
||||||
int16_t sighandle=GETHIGHFLASHW(RMFT2::SignalDefinitions,sigslot*8);
|
SIGNAL_DEFINITION slot=getSignalSlot(sigslot);
|
||||||
if (sighandle==0) break; // end of signal list
|
if (slot.type==sigtypeNoMoreSignals) break; // end of signal list
|
||||||
VPIN sigid = sighandle & SIGNAL_ID_MASK;
|
if (slot.type==sigtypeContinuation) continue; // continueation of previous line
|
||||||
byte flag=flags[sigslot] & SIGNAL_MASK; // obtain signal flags for this id
|
byte flag=flags[sigslot] & SIGNAL_MASK; // obtain signal flags for this ids
|
||||||
StringFormatter::send(stream,F("\n%S[%d]"),
|
StringFormatter::send(stream,F("\n%S[%d]"),
|
||||||
(flag == SIGNAL_RED)? F("RED") : (flag==SIGNAL_GREEN) ? F("GREEN") : F("AMBER"),
|
(flag == SIGNAL_RED)? F("RED") : (flag==SIGNAL_GREEN) ? F("GREEN") : F("AMBER"),
|
||||||
sigid);
|
slot.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,7 @@
|
||||||
//const byte TRACK_POWER_1=1, TRACK_POWER_ON=1;
|
//const byte TRACK_POWER_1=1, TRACK_POWER_ON=1;
|
||||||
|
|
||||||
// NEOPIXEL RG generator for NEOPIXEL_SIGNAL
|
// NEOPIXEL RG generator for NEOPIXEL_SIGNAL
|
||||||
#define NeoRG(red,green) ((red & 0xff)<<8) | (green & 0xff)
|
#define NeoRGB(red,green,blue) (((uint32_t)(red & 0xff)<<16) | ((uint32_t)(green & 0xff)<<8) | (uint32_t)(blue & 0xff))
|
||||||
|
|
||||||
// Pass 1 Implements aliases
|
// Pass 1 Implements aliases
|
||||||
#include "EXRAIL2MacroReset.h"
|
#include "EXRAIL2MacroReset.h"
|
||||||
|
@ -425,23 +425,26 @@ const FSH * RMFT2::getRosterFunctions(int16_t id) {
|
||||||
// Pass 8 Signal definitions
|
// Pass 8 Signal definitions
|
||||||
#include "EXRAIL2MacroReset.h"
|
#include "EXRAIL2MacroReset.h"
|
||||||
#undef SIGNAL
|
#undef SIGNAL
|
||||||
#define SIGNAL(redpin,amberpin,greenpin) redpin,redpin,amberpin,greenpin,
|
#define SIGNAL(redpin,amberpin,greenpin) {sigtypeSIGNAL,redpin,redpin,amberpin,greenpin},
|
||||||
#undef SIGNALH
|
#undef SIGNALH
|
||||||
#define SIGNALH(redpin,amberpin,greenpin) redpin | RMFT2::ACTIVE_HIGH_SIGNAL_FLAG,redpin,amberpin,greenpin,
|
#define SIGNALH(redpin,amberpin,greenpin) {sigtypeSIGNALH,redpin,redpin,amberpin,greenpin},
|
||||||
#undef SERVO_SIGNAL
|
#undef SERVO_SIGNAL
|
||||||
#define SERVO_SIGNAL(vpin,redval,amberval,greenval) vpin | RMFT2::SERVO_SIGNAL_FLAG,redval,amberval,greenval,
|
#define SERVO_SIGNAL(vpin,redval,amberval,greenval) {sigtypeSERVO,vpin,redval,amberval,greenval},
|
||||||
#undef DCC_SIGNAL
|
#undef DCC_SIGNAL
|
||||||
#define DCC_SIGNAL(id,addr,subaddr) id | RMFT2::DCC_SIGNAL_FLAG,addr,subaddr,0,
|
#define DCC_SIGNAL(id,addr,subaddr) {sigtypeDCC,id,addr,subaddr,0},
|
||||||
#undef DCCX_SIGNAL
|
#undef DCCX_SIGNAL
|
||||||
#define DCCX_SIGNAL(id,redAspect,amberAspect,greenAspect) id | RMFT2::DCCX_SIGNAL_FLAG,redAspect,amberAspect,greenAspect,
|
#define DCCX_SIGNAL(id,redAspect,amberAspect,greenAspect) {sigtypeDCCX,id,redAspect,amberAspect,greenAspect},
|
||||||
#undef NEOPIXEL_SIGNAL
|
#undef NEOPIXEL_SIGNAL
|
||||||
#define NEOPIXEL_SIGNAL(id,redcolour,ambercolour,greencolour) id | RMFT2::NEOPIXEL_SIGNAL_FLAG,redcolour, ambercolour, greencolour,
|
#define NEOPIXEL_SIGNAL(id,redRGB,amberRGB,greenRGB) \
|
||||||
|
{sigtypeNEOPIXEL,id,((VPIN)((redRGB)>>8)), ((VPIN)((amberRGB)>>8)), ((VPIN)((greenRGB)>>8))},\
|
||||||
|
{sigtypeContinuation,id,((VPIN)((redRGB) & 0xff)), ((VPIN)((amberRGB) & 0xFF)), ((VPIN)((greenRGB) & 0xFF))},
|
||||||
#undef VIRTUAL_SIGNAL
|
#undef VIRTUAL_SIGNAL
|
||||||
#define VIRTUAL_SIGNAL(id) id,0,0,0,
|
#define VIRTUAL_SIGNAL(id) {sigtypeVIRTUAL,id,0,0,0},
|
||||||
|
|
||||||
const HIGHFLASH int16_t RMFT2::SignalDefinitions[] = {
|
const HIGHFLASH SIGNAL_DEFINITION RMFT2::SignalDefinitions[] = {
|
||||||
#include "myAutomation.h"
|
#include "myAutomation.h"
|
||||||
0,0,0,0 };
|
{sigtypeNoMoreSignals,0,0,0,0}
|
||||||
|
};
|
||||||
|
|
||||||
// Pass 9 ONLCC/ ONMERG counter and lookup array
|
// Pass 9 ONLCC/ ONMERG counter and lookup array
|
||||||
#include "EXRAIL2MacroReset.h"
|
#include "EXRAIL2MacroReset.h"
|
||||||
|
|
6
FSH.h
6
FSH.h
|
@ -60,6 +60,8 @@ typedef __FlashStringHelper FSH;
|
||||||
#define GETFARPTR(data) pgm_get_far_address(data)
|
#define GETFARPTR(data) pgm_get_far_address(data)
|
||||||
#define GETHIGHFLASH(data,offset) pgm_read_byte_far(GETFARPTR(data)+offset)
|
#define GETHIGHFLASH(data,offset) pgm_read_byte_far(GETFARPTR(data)+offset)
|
||||||
#define GETHIGHFLASHW(data,offset) pgm_read_word_far(GETFARPTR(data)+offset)
|
#define GETHIGHFLASHW(data,offset) pgm_read_word_far(GETFARPTR(data)+offset)
|
||||||
|
#define COPYHIGHFLASH(target,base,offset,length) \
|
||||||
|
memcpy_PF(target,GETFARPTR(base) + offset,length)
|
||||||
#else
|
#else
|
||||||
// AVR_UNO/NANO runtime does not support _far functions so just use _near equivalent
|
// AVR_UNO/NANO runtime does not support _far functions so just use _near equivalent
|
||||||
// as there is no progmem above 32kb anyway.
|
// as there is no progmem above 32kb anyway.
|
||||||
|
@ -68,6 +70,8 @@ typedef __FlashStringHelper FSH;
|
||||||
#define GETFARPTR(data) ((uint32_t)(data))
|
#define GETFARPTR(data) ((uint32_t)(data))
|
||||||
#define GETHIGHFLASH(data,offset) pgm_read_byte_near(GETFARPTR(data)+(offset))
|
#define GETHIGHFLASH(data,offset) pgm_read_byte_near(GETFARPTR(data)+(offset))
|
||||||
#define GETHIGHFLASHW(data,offset) pgm_read_word_near(GETFARPTR(data)+(offset))
|
#define GETHIGHFLASHW(data,offset) pgm_read_word_near(GETFARPTR(data)+(offset))
|
||||||
|
#define COPYHIGHFLASH(target,base,offset,length) \
|
||||||
|
memcpy_P(target,(byte *)base + offset,length)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
@ -87,6 +91,8 @@ typedef char FSH;
|
||||||
#define GETFLASH(addr) (*(const byte *)(addr))
|
#define GETFLASH(addr) (*(const byte *)(addr))
|
||||||
#define GETHIGHFLASH(data,offset) (*(const byte *)(GETFARPTR(data)+offset))
|
#define GETHIGHFLASH(data,offset) (*(const byte *)(GETFARPTR(data)+offset))
|
||||||
#define GETHIGHFLASHW(data,offset) (*(const uint16_t *)(GETFARPTR(data)+offset))
|
#define GETHIGHFLASHW(data,offset) (*(const uint16_t *)(GETFARPTR(data)+offset))
|
||||||
|
#define COPYHIGHFLASH(target,base,offset,length) \
|
||||||
|
memcpy(target,(byte *)&base + offset,length)
|
||||||
#define STRCPY_P strcpy
|
#define STRCPY_P strcpy
|
||||||
#define STRCMP_P strcmp
|
#define STRCMP_P strcmp
|
||||||
#define STRNCPY_P strncpy
|
#define STRNCPY_P strncpy
|
||||||
|
|
|
@ -54,8 +54,24 @@ The IO_NeoPixel.h driver supports the adafruit neopixel seesaw board. It turns e
|
||||||
For signals with 1 pixel, the NEOPIXEL_SIGNAL macro will create a signal
|
For signals with 1 pixel, the NEOPIXEL_SIGNAL macro will create a signal
|
||||||
NEOPIXEL_SIGNAL(vpin,redfx,amberfx,greenfx)
|
NEOPIXEL_SIGNAL(vpin,redfx,amberfx,greenfx)
|
||||||
|
|
||||||
*** This is experimental and may change****
|
** Changed... ****
|
||||||
In order to fit the existing signal code, the fx colours above are restricted to the red and green pixel values (ie no blue channel)
|
The fx values above can be created by the NeoRGB macro so a bright red would be NeoRGB(255,0,0) bright green NeoRGB(0,255,0) and amber something like NeoRGB(255,100,0)
|
||||||
The fx values above can be created by the NeoRG macro so a bright red would be NeoRG(255,0) bright green Ng(0,255) and amber something like NeoRG(128,128)
|
NeoRGB creates a single int32_t value so it can be used in several ways as convenient.
|
||||||
|
|
||||||
|
// create 1-lamp signal with NeoRGB colours
|
||||||
|
NEOPIXEL_SIGNAL(1000,NeoRGB(255,0,0),NeoRGB(255,100,0),NeoRGB(0,255,0))
|
||||||
|
|
||||||
|
// Create 1-lamp signal with named colours.
|
||||||
|
// This is better if you have multiple signals.
|
||||||
|
// (Note: ALIAS is not suitable due to word length defaults)
|
||||||
|
#define REDLAMP NeoRGB(255,0,0)
|
||||||
|
#define AMBERLAMP NeoRGB(255,100,0)
|
||||||
|
#define GREENLAMP NeoRGB(0,255,0)
|
||||||
|
NEOPIXEL_SIGNAL(1001,REDLAMP,AMBERLAMP,GREENLAMP)
|
||||||
|
|
||||||
|
// Create 1-lamp signal with web type RGB colours
|
||||||
|
// (Using blue for the amber signal , just testing)
|
||||||
|
NEOPIXEL_SIGNAL(1002,0xFF0000,0x0000FF,0x00FF00)
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user