mirror of
https://github.com/DCC-EX/CommandStation-EX.git
synced 2024-12-23 12:51:24 +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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
if (params==4 || params==5) { // <z [-]vpin r g b [count]>
|
||||
uint16_t colourcode=((p[1] & 0x1F)<<11) |
|
||||
((p[2] & 0x1F)<<6) |
|
||||
((p[3] & 0x1F)<<1);
|
||||
if (setON) colourcode |= 0x0001;
|
||||
// driver treats count 0 as 1
|
||||
for (auto pix=vpin;pix<=vpin+p[4];pix++) IODevice::writeAnalogue(pix,colourcode,0,0);
|
||||
if (params==4 || params==5) { // <z [-]vpin r g b [count]>
|
||||
auto count=p[4]?p[4]:1;
|
||||
if (p[1]<0 || p[1]>0xFF) break;
|
||||
if (p[2]<0 || p[2]>0xFF) break;
|
||||
if (p[3]<0 || p[3]>0xFF) break;
|
||||
// strange parameter mangling... see IO_NeoPixel.h NeoPixel::_writeAnalogue
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
20
EXRAIL2.cpp
20
EXRAIL2.cpp
@ -998,8 +998,14 @@ void RMFT2::loop2() {
|
||||
}
|
||||
break;
|
||||
|
||||
case OPCODE_NEOPIXEL: // OPCODE_NEOPIXEL,V(vpin),OPCODE_PAD,V(rgbcolour)
|
||||
IODevice::writeAnalogue(operand,getOperand(1));
|
||||
case OPCODE_NEOPIXEL:
|
||||
// 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;
|
||||
|
||||
#ifndef IO_NO_HAL
|
||||
@ -1199,11 +1205,11 @@ int16_t RMFT2::getSignalSlot(int16_t id) {
|
||||
}
|
||||
|
||||
if (sigtype== NEOPIXEL_SIGNAL_FLAG) {
|
||||
// redpin,amberpin,greenpin are the 3 rgbs
|
||||
VPIN colour=redpin;
|
||||
if (rag==SIGNAL_AMBER) colour=amberpin;
|
||||
if (rag==SIGNAL_GREEN) colour=greenpin;
|
||||
IODevice::writeAnalogue(sigid, colour);
|
||||
// redpin,amberpin,greenpin are the 3 RG values but with no blue permitted. . (code limitation hack)
|
||||
int colour_RG=redpin;
|
||||
if (rag==SIGNAL_AMBER) colour_RG=amberpin;
|
||||
if (rag==SIGNAL_GREEN) colour_RG=greenpin;
|
||||
IODevice::writeAnalogue(sigid, colour_RG,true,0);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -272,8 +272,7 @@
|
||||
#define LCN(msg)
|
||||
#define MESSAGE(msg)
|
||||
#define MOVETT(id,steps,activity)
|
||||
#define NEOPIXEL(id,colour)
|
||||
#define NEOPIXEL_OFF(id,colour)
|
||||
#define NEOPIXEL(id,r,g,b,count...)
|
||||
#define NEOPIXEL_SIGNAL(sigid,redcolour,ambercolour,greencolour)
|
||||
#define ACON(eventid)
|
||||
#define ACOF(eventid)
|
||||
|
@ -71,8 +71,8 @@
|
||||
//const byte TRACK_POWER_0=0, TRACK_POWER_OFF=0;
|
||||
//const byte TRACK_POWER_1=1, TRACK_POWER_ON=1;
|
||||
|
||||
// NEOPIXEL RGB generator
|
||||
#define NeoRGB(red,green,blue) (((red & 0x1F)<<11) | ((green & 0x1F)<<6) | ((blue & 0x1F)<<1) )
|
||||
// NEOPIXEL RG generator for NEOPIXEL_SIGNAL
|
||||
#define NeoRG(red,green) ((red & 0xff)<<8) | (green & 0xff)
|
||||
|
||||
// Pass 1 Implements aliases
|
||||
#include "EXRAIL2MacroReset.h"
|
||||
@ -435,7 +435,7 @@ const FSH * RMFT2::getRosterFunctions(int16_t id) {
|
||||
#undef DCCX_SIGNAL
|
||||
#define DCCX_SIGNAL(id,redAspect,amberAspect,greenAspect) id | RMFT2::DCCX_SIGNAL_FLAG,redAspect,amberAspect,greenAspect,
|
||||
#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
|
||||
#define VIRTUAL_SIGNAL(id) id,0,0,0,
|
||||
|
||||
@ -558,8 +558,11 @@ int RMFT2::onLCCLookup[RMFT2::countLCCLookup];
|
||||
#define LCN(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 NEOPIXEL(id,colour) OPCODE_NEOPIXEL,V(id),OPCODE_PAD,V(colour| NEOPIXEL_FLAG_ON),
|
||||
#define NEOPIXEL_OFF(id,colour) OPCODE_NEOPIXEL,V(id),OPCODE_PAD,V(colour& ^NEOPIXEL_FLAG_ON),
|
||||
#define NEOPIXEL(id,r,g,b,count...) OPCODE_NEOPIXEL,V(id),\
|
||||
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 ONACTIVATE(addr,subaddr) OPCODE_ONACTIVATE,V(addr<<2|subaddr),
|
||||
#define ONACTIVATEL(linear) OPCODE_ONACTIVATE,V(linear+3),
|
||||
|
106
IO_NeoPixel.h
106
IO_NeoPixel.h
@ -133,7 +133,6 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
static const uint16_t NEOPIXEL_ON_FLAG=0x0001;
|
||||
|
||||
static const byte SEESAW_NEOPIXEL_BASE=0x0E;
|
||||
static const byte SEESAW_NEOPIXEL_STATUS = 0x00;
|
||||
@ -152,20 +151,35 @@ private:
|
||||
_firstVpin = firstVpin;
|
||||
_nPins=nPins;
|
||||
_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);
|
||||
_greenOffset=4+(mode >> 2 & 0x03);
|
||||
_blueOffset=4+(mode & 0x03);
|
||||
if (4+(mode >>6 & 0x03) == _redOffset) _bytesPerPixel=3;
|
||||
else _bytesPerPixel=4; // string has a white byte.
|
||||
|
||||
_kHz800=(mode & NEO_KHZ400)==0;
|
||||
_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);
|
||||
}
|
||||
|
||||
void _begin() {
|
||||
|
||||
// Initialise Neopixel device
|
||||
I2CManager.begin();
|
||||
if (!I2CManager.exists(_I2CAddress)) {
|
||||
@ -198,45 +212,41 @@ private:
|
||||
_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
|
||||
int _read(VPIN vpin) override {
|
||||
if (_deviceState == DEVSTATE_FAILED) return 0;
|
||||
auto pin=vpin-_firstVpin;
|
||||
return pixelBuffer[pin] & NEOPIXEL_ON_FLAG;
|
||||
return isPixelOn(vpin-_firstVpin);
|
||||
}
|
||||
|
||||
// Write digital value. Sets pixel on or off
|
||||
void _write(VPIN vpin, int value) override {
|
||||
if (_deviceState == DEVSTATE_FAILED) return;
|
||||
auto pin=vpin-_firstVpin;
|
||||
auto pixel=vpin-_firstVpin;
|
||||
if (value) {
|
||||
if (pixelBuffer[pin] & NEOPIXEL_ON_FLAG) return;
|
||||
pixelBuffer[pin] |= NEOPIXEL_ON_FLAG;
|
||||
if (isPixelOn(pixel)) return;
|
||||
setPixelOn(pixel);
|
||||
}
|
||||
else { // set off
|
||||
if (!(pixelBuffer[pin] & NEOPIXEL_ON_FLAG)) return;
|
||||
pixelBuffer[pin] &= (~NEOPIXEL_ON_FLAG);
|
||||
if (!isPixelOn(pixel)) return;
|
||||
setPixelOff(pixel);
|
||||
}
|
||||
transmit(pin);
|
||||
transmit(pixel);
|
||||
}
|
||||
|
||||
// Write analogue (integer) value
|
||||
void _writeAnalogue(VPIN vpin, int colour, uint8_t ignore1, uint16_t ignore2) override {
|
||||
(void) ignore1;
|
||||
(void) ignore2;
|
||||
// Write analogue value.
|
||||
// The convoluted parameter mashing here is to allow passing the RGB and on/off
|
||||
// information through the generic HAL _writeAnalog interface which was originally
|
||||
// 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;
|
||||
auto newColour=(uint16_t)colour;
|
||||
auto pin=vpin-_firstVpin;
|
||||
if (pixelBuffer[pin]==newColour) return;
|
||||
pixelBuffer[pin]=newColour;
|
||||
transmit(pin);
|
||||
RGB newColour={(byte)((colour_RG>>8) & 0xFF), (byte)(colour_RG & 0xFF), (byte)(colour_B & 0xFF)};
|
||||
auto pixel=vpin-_firstVpin;
|
||||
if (pixelBuffer[pixel]==newColour && isPixelOn(pixel)==(bool)onoff) return; // no change
|
||||
|
||||
if (onoff) setPixelOn(pixel); else setPixelOff(pixel);
|
||||
pixelBuffer[pixel]=newColour;
|
||||
transmit(pixel);
|
||||
}
|
||||
|
||||
// Display device information and status.
|
||||
@ -247,6 +257,12 @@ private:
|
||||
_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
|
||||
void reportError(uint8_t status, bool fail=true) {
|
||||
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};
|
||||
uint16_t offset= pin * _bytesPerPixel;
|
||||
uint16_t offset= pixel * _bytesPerPixel;
|
||||
buffer[2]=(byte)(offset>>8);
|
||||
buffer[3]=(byte)(offset & 0xFF);
|
||||
auto colour=pixelBuffer[pin];
|
||||
if (colour & NEOPIXEL_ON_FLAG) {
|
||||
buffer[_redOffset]=(colour>>11 & 0x1F) <<_brightness;
|
||||
buffer[_greenOffset]=(colour>>6 & 0x1F) <<_brightness;
|
||||
buffer[_blueOffset]=(colour>>1 & 0x1F) <<_brightness;
|
||||
} // else leave buffer black
|
||||
|
||||
if (isPixelOn(pixel)) {
|
||||
auto colour=pixelBuffer[pixel];
|
||||
buffer[_redOffset]=colour.red;
|
||||
buffer[_greenOffset]=colour.green;
|
||||
buffer[_blueOffset]=colour.blue;
|
||||
} // else leave buffer black (in buffer preset to zeros above)
|
||||
|
||||
// Transmit pixel to driver
|
||||
I2CManager.write(_I2CAddress,buffer,4 +_bytesPerPixel);
|
||||
_showPendimg=true;
|
||||
|
||||
}
|
||||
uint16_t* pixelBuffer = nullptr;
|
||||
byte _brightness;
|
||||
struct RGB {
|
||||
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 _redOffset;
|
||||
byte _greenOffset;
|
||||
byte _blueOffset;
|
||||
bool _showPendimg;
|
||||
bool _kHz800;
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user