1
0
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:
Asbelos 2024-09-18 17:06:00 +01:00
parent 8e6fe6df21
commit 3aabb51888
6 changed files with 148 additions and 111 deletions

View File

@ -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;
} }

View File

@ -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;

View File

@ -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);
} }
} }

View File

@ -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
View File

@ -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

View File

@ -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)