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:
parent
d3d6cc97fb
commit
e823db3d24
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
20
EXRAIL2.cpp
20
EXRAIL2.cpp
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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),
|
||||||
|
|
106
IO_NeoPixel.h
106
IO_NeoPixel.h
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user