1
0
mirror of https://github.com/DCC-EX/CommandStation-EX.git synced 2024-11-22 23:56:13 +01:00

Neopixel change to 8,8,8

This commit is contained in:
Asbelos 2024-09-07 11:16:30 +01:00
parent d3d6cc97fb
commit e823db3d24
5 changed files with 99 additions and 61 deletions

View File

@ -405,16 +405,18 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream)
return; return;
} }
if (params==2) { // <o [-]vpin count> if (params==2) { // <o [-]vpin count>
for (auto pix=vpin;pix<=vpin+p[1];pix++) IODevice::write(pix,setON); for (auto pix=vpin;pix<vpin+p[1];pix++) IODevice::write(pix,setON);
return; return;
} }
if (params==4 || params==5) { // <z [-]vpin r g b [count]> if (params==4 || params==5) { // <z [-]vpin r g b [count]>
uint16_t colourcode=((p[1] & 0x1F)<<11) | auto count=p[4]?p[4]:1;
((p[2] & 0x1F)<<6) | if (p[1]<0 || p[1]>0xFF) break;
((p[3] & 0x1F)<<1); if (p[2]<0 || p[2]>0xFF) break;
if (setON) colourcode |= 0x0001; if (p[3]<0 || p[3]>0xFF) break;
// driver treats count 0 as 1 // strange parameter mangling... see IO_NeoPixel.h NeoPixel::_writeAnalogue
for (auto pix=vpin;pix<=vpin+p[4];pix++) IODevice::writeAnalogue(pix,colourcode,0,0); int colour_RG=(p[1]<<8) | p[2];
uint16_t colour_B=p[3];
for (auto pix=vpin;pix<vpin+count;pix++) IODevice::writeAnalogue(pix,colour_RG,setON,colour_B);
return; return;
} }
} }

View File

@ -998,8 +998,14 @@ void RMFT2::loop2() {
} }
break; break;
case OPCODE_NEOPIXEL: // OPCODE_NEOPIXEL,V(vpin),OPCODE_PAD,V(rgbcolour) case OPCODE_NEOPIXEL:
IODevice::writeAnalogue(operand,getOperand(1)); // OPCODE_NEOPIXEL,V([-]vpin),OPCODE_PAD,V(colour_RG),OPCODE_PAD,V(colour_B),OPCODE_PAD,V(count)
{
VPIN vpin=operand>0?operand:-operand;
auto count=getOperand(3);
for (auto pix=vpin;pix<vpin+count;pix++)
IODevice::writeAnalogue(pix,getOperand(1),operand>0,getOperand(2));
}
break; break;
#ifndef IO_NO_HAL #ifndef IO_NO_HAL
@ -1199,11 +1205,11 @@ int16_t RMFT2::getSignalSlot(int16_t id) {
} }
if (sigtype== NEOPIXEL_SIGNAL_FLAG) { if (sigtype== NEOPIXEL_SIGNAL_FLAG) {
// redpin,amberpin,greenpin are the 3 rgbs // redpin,amberpin,greenpin are the 3 RG values but with no blue permitted. . (code limitation hack)
VPIN colour=redpin; int colour_RG=redpin;
if (rag==SIGNAL_AMBER) colour=amberpin; if (rag==SIGNAL_AMBER) colour_RG=amberpin;
if (rag==SIGNAL_GREEN) colour=greenpin; if (rag==SIGNAL_GREEN) colour_RG=greenpin;
IODevice::writeAnalogue(sigid, colour); IODevice::writeAnalogue(sigid, colour_RG,true,0);
return; return;
} }

View File

@ -272,8 +272,7 @@
#define LCN(msg) #define LCN(msg)
#define MESSAGE(msg) #define MESSAGE(msg)
#define MOVETT(id,steps,activity) #define MOVETT(id,steps,activity)
#define NEOPIXEL(id,colour) #define NEOPIXEL(id,r,g,b,count...)
#define NEOPIXEL_OFF(id,colour)
#define NEOPIXEL_SIGNAL(sigid,redcolour,ambercolour,greencolour) #define NEOPIXEL_SIGNAL(sigid,redcolour,ambercolour,greencolour)
#define ACON(eventid) #define ACON(eventid)
#define ACOF(eventid) #define ACOF(eventid)

View File

@ -71,8 +71,8 @@
//const byte TRACK_POWER_0=0, TRACK_POWER_OFF=0; //const byte TRACK_POWER_0=0, TRACK_POWER_OFF=0;
//const byte TRACK_POWER_1=1, TRACK_POWER_ON=1; //const byte TRACK_POWER_1=1, TRACK_POWER_ON=1;
// NEOPIXEL RGB generator // NEOPIXEL RG generator for NEOPIXEL_SIGNAL
#define NeoRGB(red,green,blue) (((red & 0x1F)<<11) | ((green & 0x1F)<<6) | ((blue & 0x1F)<<1) ) #define NeoRG(red,green) ((red & 0xff)<<8) | (green & 0xff)
// Pass 1 Implements aliases // Pass 1 Implements aliases
#include "EXRAIL2MacroReset.h" #include "EXRAIL2MacroReset.h"
@ -435,7 +435,7 @@ const FSH * RMFT2::getRosterFunctions(int16_t id) {
#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) id | RMFT2::DCCX_SIGNAL_FLAG,redAspect,amberAspect,greenAspect,
#undef NEOPIXEL_SIGNAL #undef NEOPIXEL_SIGNAL
#define NEOPIXEL_SIGNAL(id,redcolour,ambercolour,greencolour) id | RMFT2::NEOPIXEL_SIGNAL_FLAG,redcolour | NEOPIXEL_FLAG_ON, ambercolour | NEOPIXEL_FLAG_ON, greencolour | NEOPIXEL_FLAG_ON, #define NEOPIXEL_SIGNAL(id,redcolour,ambercolour,greencolour) id | RMFT2::NEOPIXEL_SIGNAL_FLAG,redcolour, ambercolour, greencolour,
#undef VIRTUAL_SIGNAL #undef VIRTUAL_SIGNAL
#define VIRTUAL_SIGNAL(id) id,0,0,0, #define VIRTUAL_SIGNAL(id) id,0,0,0,
@ -558,8 +558,11 @@ int RMFT2::onLCCLookup[RMFT2::countLCCLookup];
#define LCN(msg) PRINT(msg) #define LCN(msg) PRINT(msg)
#define MESSAGE(msg) PRINT(msg) #define MESSAGE(msg) PRINT(msg)
#define MOVETT(id,steps,activity) OPCODE_SERVO,V(id),OPCODE_PAD,V(steps),OPCODE_PAD,V(EXTurntable::activity),OPCODE_PAD,V(0), #define MOVETT(id,steps,activity) OPCODE_SERVO,V(id),OPCODE_PAD,V(steps),OPCODE_PAD,V(EXTurntable::activity),OPCODE_PAD,V(0),
#define NEOPIXEL(id,colour) OPCODE_NEOPIXEL,V(id),OPCODE_PAD,V(colour| NEOPIXEL_FLAG_ON), #define NEOPIXEL(id,r,g,b,count...) OPCODE_NEOPIXEL,V(id),\
#define NEOPIXEL_OFF(id,colour) OPCODE_NEOPIXEL,V(id),OPCODE_PAD,V(colour& ^NEOPIXEL_FLAG_ON), OPCODE_PAD,V(((r & 0xff)<<8) | (g & 0xff)),\
OPCODE_PAD,V((b & 0xff)),\
OPCODE_PAD,V(#count[0]?(count+0):1),
#define NEOPIXEL_SIGNAL(sigid,redcolour,ambercolour,greencolour) #define NEOPIXEL_SIGNAL(sigid,redcolour,ambercolour,greencolour)
#define ONACTIVATE(addr,subaddr) OPCODE_ONACTIVATE,V(addr<<2|subaddr), #define ONACTIVATE(addr,subaddr) OPCODE_ONACTIVATE,V(addr<<2|subaddr),
#define ONACTIVATEL(linear) OPCODE_ONACTIVATE,V(linear+3), #define ONACTIVATEL(linear) OPCODE_ONACTIVATE,V(linear+3),

View File

@ -133,7 +133,6 @@ public:
} }
private: private:
static const uint16_t NEOPIXEL_ON_FLAG=0x0001;
static const byte SEESAW_NEOPIXEL_BASE=0x0E; static const byte SEESAW_NEOPIXEL_BASE=0x0E;
static const byte SEESAW_NEOPIXEL_STATUS = 0x00; static const byte SEESAW_NEOPIXEL_STATUS = 0x00;
@ -152,20 +151,35 @@ private:
_firstVpin = firstVpin; _firstVpin = firstVpin;
_nPins=nPins; _nPins=nPins;
_I2CAddress = i2cAddress; _I2CAddress = i2cAddress;
_brightness=2; // TODO 0,1,2,3
// calculate the offsets into the seesaw buffer for each colour depending
// on the pixel strip type passed in mode.
_redOffset=4+(mode >> 4 & 0x03); _redOffset=4+(mode >> 4 & 0x03);
_greenOffset=4+(mode >> 2 & 0x03); _greenOffset=4+(mode >> 2 & 0x03);
_blueOffset=4+(mode & 0x03); _blueOffset=4+(mode & 0x03);
if (4+(mode >>6 & 0x03) == _redOffset) _bytesPerPixel=3; if (4+(mode >>6 & 0x03) == _redOffset) _bytesPerPixel=3;
else _bytesPerPixel=4; // string has a white byte. else _bytesPerPixel=4; // string has a white byte.
_kHz800=(mode & NEO_KHZ400)==0; _kHz800=(mode & NEO_KHZ400)==0;
_showPendimg=false; _showPendimg=false;
// In dccex there are only 2 bytes per pixel
pixelBuffer=(uint16_t *) calloc(_nPins,sizeof(uint16_t)); // all pixels off // Each pixel requires 3 bytes RGB memory.
// Although the driver device can remember this, it cant do off/on without
// forgetting what the on colour was!
pixelBuffer=(RGB *) malloc(_nPins*sizeof(RGB));
stateBuffer=(byte *) calloc((_nPins+7)/8,sizeof(byte)); // all pixels off
if (pixelBuffer==nullptr || stateBuffer==nullptr) {
DIAG(F("NeoPixel I2C:%s not enough RAM"), _I2CAddress.toString());
return;
}
// preset all pins to white so a digital on/off will do something even if no colour set.
memset(pixelBuffer,0xFF,_nPins*sizeof(RGB));
addDevice(this); addDevice(this);
} }
void _begin() { void _begin() {
// Initialise Neopixel device // Initialise Neopixel device
I2CManager.begin(); I2CManager.begin();
if (!I2CManager.exists(_I2CAddress)) { if (!I2CManager.exists(_I2CAddress)) {
@ -198,45 +212,41 @@ private:
_showPendimg=false; _showPendimg=false;
} }
// read back pixel colour (rarely needed I suspect)
int _readAnalogue(VPIN vpin) override {
if (_deviceState == DEVSTATE_FAILED) return 0;
auto pin=vpin-_firstVpin;
return pixelBuffer[pin];
}
// read back pixel on/off // read back pixel on/off
int _read(VPIN vpin) override { int _read(VPIN vpin) override {
if (_deviceState == DEVSTATE_FAILED) return 0; if (_deviceState == DEVSTATE_FAILED) return 0;
auto pin=vpin-_firstVpin; return isPixelOn(vpin-_firstVpin);
return pixelBuffer[pin] & NEOPIXEL_ON_FLAG;
} }
// Write digital value. Sets pixel on or off // Write digital value. Sets pixel on or off
void _write(VPIN vpin, int value) override { void _write(VPIN vpin, int value) override {
if (_deviceState == DEVSTATE_FAILED) return; if (_deviceState == DEVSTATE_FAILED) return;
auto pin=vpin-_firstVpin; auto pixel=vpin-_firstVpin;
if (value) { if (value) {
if (pixelBuffer[pin] & NEOPIXEL_ON_FLAG) return; if (isPixelOn(pixel)) return;
pixelBuffer[pin] |= NEOPIXEL_ON_FLAG; setPixelOn(pixel);
} }
else { // set off else { // set off
if (!(pixelBuffer[pin] & NEOPIXEL_ON_FLAG)) return; if (!isPixelOn(pixel)) return;
pixelBuffer[pin] &= (~NEOPIXEL_ON_FLAG); setPixelOff(pixel);
} }
transmit(pin); transmit(pixel);
} }
// Write analogue (integer) value // Write analogue value.
void _writeAnalogue(VPIN vpin, int colour, uint8_t ignore1, uint16_t ignore2) override { // The convoluted parameter mashing here is to allow passing the RGB and on/off
(void) ignore1; // information through the generic HAL _writeAnalog interface which was originally
(void) ignore2; // designed for servos and short integers
void _writeAnalogue(VPIN vpin, int colour_RG, uint8_t onoff, uint16_t colour_B) override {
if (_deviceState == DEVSTATE_FAILED) return; if (_deviceState == DEVSTATE_FAILED) return;
auto newColour=(uint16_t)colour; RGB newColour={(byte)((colour_RG>>8) & 0xFF), (byte)(colour_RG & 0xFF), (byte)(colour_B & 0xFF)};
auto pin=vpin-_firstVpin; auto pixel=vpin-_firstVpin;
if (pixelBuffer[pin]==newColour) return; if (pixelBuffer[pixel]==newColour && isPixelOn(pixel)==(bool)onoff) return; // no change
pixelBuffer[pin]=newColour;
transmit(pin); if (onoff) setPixelOn(pixel); else setPixelOff(pixel);
pixelBuffer[pixel]=newColour;
transmit(pixel);
} }
// Display device information and status. // Display device information and status.
@ -247,6 +257,12 @@ private:
_deviceState == DEVSTATE_FAILED ? F("OFFLINE") : F("")); _deviceState == DEVSTATE_FAILED ? F("OFFLINE") : F(""));
} }
bool isPixelOn(int16_t pixel) {return stateBuffer[pixel/8] & (0x80>>(pixel%8));}
void setPixelOn(int16_t pixel) {stateBuffer[pixel/8] |= (0x80>>(pixel%8));}
void setPixelOff(int16_t pixel) {stateBuffer[pixel/8] &= ~(0x80>>(pixel%8));}
// Helper function for error handling // Helper function for error handling
void reportError(uint8_t status, bool fail=true) { void reportError(uint8_t status, bool fail=true) {
DIAG(F("NeoPixel I2C:%s Error:%d (%S)"), _I2CAddress.toString(), DIAG(F("NeoPixel I2C:%s Error:%d (%S)"), _I2CAddress.toString(),
@ -256,30 +272,42 @@ private:
} }
void transmit(uint16_t pin, bool show=true) { void transmit(uint16_t pixel, bool show=true) {
byte buffer[]={SEESAW_NEOPIXEL_BASE,SEESAW_NEOPIXEL_BUF,0x00,0x00,0x00,0x00,0x00}; byte buffer[]={SEESAW_NEOPIXEL_BASE,SEESAW_NEOPIXEL_BUF,0x00,0x00,0x00,0x00,0x00};
uint16_t offset= pin * _bytesPerPixel; uint16_t offset= pixel * _bytesPerPixel;
buffer[2]=(byte)(offset>>8); buffer[2]=(byte)(offset>>8);
buffer[3]=(byte)(offset & 0xFF); buffer[3]=(byte)(offset & 0xFF);
auto colour=pixelBuffer[pin];
if (colour & NEOPIXEL_ON_FLAG) { if (isPixelOn(pixel)) {
buffer[_redOffset]=(colour>>11 & 0x1F) <<_brightness; auto colour=pixelBuffer[pixel];
buffer[_greenOffset]=(colour>>6 & 0x1F) <<_brightness; buffer[_redOffset]=colour.red;
buffer[_blueOffset]=(colour>>1 & 0x1F) <<_brightness; buffer[_greenOffset]=colour.green;
} // else leave buffer black buffer[_blueOffset]=colour.blue;
} // else leave buffer black (in buffer preset to zeros above)
// Transmit pixel to driver // Transmit pixel to driver
I2CManager.write(_I2CAddress,buffer,4 +_bytesPerPixel); I2CManager.write(_I2CAddress,buffer,4 +_bytesPerPixel);
_showPendimg=true; _showPendimg=true;
} }
uint16_t* pixelBuffer = nullptr; struct RGB {
byte _brightness; byte red;
byte green;
byte blue;
bool operator==(const RGB& other) const {
return red == other.red && green == other.green && blue == other.blue;
}
};
RGB* pixelBuffer = nullptr;
byte* stateBuffer = nullptr; // 1 bit per pixel
bool _showPendimg;
// mapping of RGB onto pixel buffer for seesaw.
byte _bytesPerPixel; byte _bytesPerPixel;
byte _redOffset; byte _redOffset;
byte _greenOffset; byte _greenOffset;
byte _blueOffset; byte _blueOffset;
bool _showPendimg;
bool _kHz800; bool _kHz800;
}; };