258 lines
9.2 KiB
C++
258 lines
9.2 KiB
C++
/*********************************************************************************
|
|
* MIT License
|
|
*
|
|
* Copyright (c) 2020-2022 Gregg E. Berman
|
|
*
|
|
* https://github.com/HomeSpan/HomeSpan
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
* copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*
|
|
********************************************************************************/
|
|
|
|
////////////////////////////////////////////
|
|
// Addressable LEDs //
|
|
////////////////////////////////////////////
|
|
|
|
#pragma once
|
|
|
|
#include "RFControl.h"
|
|
#include "PwmPin.h"
|
|
#include "Blinker.h"
|
|
|
|
////////////////////////////////////////////
|
|
// Single-Wire RGB/RGBW NeoPixels //
|
|
////////////////////////////////////////////
|
|
|
|
class Pixel : public Blinkable {
|
|
|
|
public:
|
|
struct Color {
|
|
union{
|
|
struct {
|
|
uint8_t white:8;
|
|
uint8_t blue:8;
|
|
uint8_t red:8;
|
|
uint8_t green:8;
|
|
};
|
|
uint32_t val;
|
|
};
|
|
|
|
Color RGB(uint8_t r, uint8_t g, uint8_t b, uint8_t w=0){ // returns Color based on provided RGB(W) values where r/g/b/w=[0-255]
|
|
this->red=r;
|
|
this->green=g;
|
|
this->blue=b;
|
|
this->white=w;
|
|
return(*this);
|
|
}
|
|
|
|
Color HSV(float h, float s, float v, double w=0){ // returns Color based on provided HSV(W) values where h=[0,360] and s/v/w=[0,100]
|
|
float r,g,b;
|
|
LedPin::HSVtoRGB(h,s/100.0,v/100.0,&r,&g,&b);
|
|
this->red=r*255;
|
|
this->green=g*255;
|
|
this->blue=b*255;
|
|
this->white=w*2.555;
|
|
return(*this);
|
|
}
|
|
|
|
bool operator==(const Color& color){
|
|
return(val==color.val);
|
|
}
|
|
|
|
bool operator!=(const Color& color){
|
|
return(val!=color.val);
|
|
}
|
|
|
|
Color operator+(const Color& color){
|
|
Color newColor;
|
|
newColor.white=white+color.white;
|
|
newColor.blue=blue+color.blue;
|
|
newColor.red=red+color.red;
|
|
newColor.green=green+color.green;
|
|
return(newColor);
|
|
}
|
|
|
|
Color& operator+=(const Color& color){
|
|
white+=color.white;
|
|
red+=color.red;
|
|
blue+=color.blue;
|
|
green+=color.green;
|
|
return(*this);
|
|
}
|
|
|
|
Color operator-(const Color& color){
|
|
Color newColor;
|
|
newColor.white=white-color.white;
|
|
newColor.blue=blue-color.blue;
|
|
newColor.red=red-color.red;
|
|
newColor.green=green-color.green;
|
|
return(newColor);
|
|
}
|
|
|
|
Color& operator-=(const Color& color){
|
|
white-=color.white;
|
|
red-=color.red;
|
|
blue-=color.blue;
|
|
green-=color.green;
|
|
return(*this);
|
|
}
|
|
|
|
}; // Color
|
|
|
|
private:
|
|
struct pixel_status_t {
|
|
int nPixels;
|
|
Color *color;
|
|
int iBit;
|
|
int iMem;
|
|
boolean started;
|
|
Pixel *px;
|
|
boolean multiColor;
|
|
};
|
|
|
|
RFControl *rf; // Pixel utilizes RFControl
|
|
uint32_t pattern[2]; // storage for zero-bit and one-bit pulses
|
|
uint32_t resetTime; // minimum time (in usec) between pulse trains
|
|
uint32_t txEndMask; // mask for end-of-transmission interrupt
|
|
uint32_t txThrMask; // mask for threshold interrupt
|
|
uint32_t lastBit; // 0=RGBW; 8=RGB
|
|
|
|
const int memSize=sizeof(RMTMEM.chan[0].data32)/4; // determine size (in pulses) of one channel
|
|
|
|
static void loadData(void *arg); // interrupt handler
|
|
volatile static pixel_status_t status; // storage for volatile information modified in interupt handler
|
|
|
|
public:
|
|
Pixel(int pin, boolean isRGBW=false); // creates addressable single-wire RGB (false) or RGBW (true) LED connected to pin (such as the SK68 or WS28)
|
|
void set(Color *c, int nPixels, boolean multiColor=true); // sets colors of nPixels based on array of Colors c; setting multiColor to false repeats Color in c[0] for all nPixels
|
|
void set(Color c, int nPixels=1){set(&c,nPixels,false);} // sets color of nPixels to be equal to specific Color c
|
|
|
|
static Color RGB(uint8_t r, uint8_t g, uint8_t b, uint8_t w=0){return(Color().RGB(r,g,b,w));} // an alternative method for returning an RGB Color
|
|
static Color HSV(float h, float s, float v, double w=0){return(Color().HSV(h,s,v,w));} // an alternative method for returning an HSV Color
|
|
|
|
int getPin(){return(rf->getPin());} // returns pixel pin if valid, else returns -1
|
|
void setTiming(float high0, float low0, float high1, float low1, uint32_t lowReset); // changes default timings for bit pulse - note parameters are in MICROSECONDS
|
|
|
|
operator bool(){ // override boolean operator to return true/false if creation succeeded/failed
|
|
return(*rf);
|
|
}
|
|
|
|
void on() {set(RGB(255,0,0));}
|
|
void off() {set(RGB(0,0,0));}
|
|
};
|
|
|
|
////////////////////////////////////////////
|
|
// Two-Wire RGB DotStars //
|
|
////////////////////////////////////////////
|
|
|
|
class Dot {
|
|
|
|
public:
|
|
struct Color {
|
|
union{
|
|
struct {
|
|
uint8_t red:8;
|
|
uint8_t green:8;
|
|
uint8_t blue:8;
|
|
uint8_t drive:5;
|
|
uint8_t flags:3;
|
|
};
|
|
uint32_t val;
|
|
};
|
|
|
|
Color RGB(uint8_t r, uint8_t g, uint8_t b, uint8_t driveLevel=31){ // returns Color based on provided RGB values where r/g/b=[0-255] and current-limiting drive level=[0,31]
|
|
this->red=r;
|
|
this->green=g;
|
|
this->blue=b;
|
|
this->drive=driveLevel;
|
|
this->flags=7;
|
|
return(*this);
|
|
}
|
|
|
|
Color HSV(float h, float s, float v, double drivePercent=100){ // returns Color based on provided HSV values where h=[0,360], s/v=[0,100], and current-limiting drive percent=[0,100]
|
|
float r,g,b;
|
|
LedPin::HSVtoRGB(h,s/100.0,v/100.0,&r,&g,&b);
|
|
this->red=r*255;
|
|
this->green=g*255;
|
|
this->blue=b*255;
|
|
this->drive=drivePercent*0.315;
|
|
this->flags=7;
|
|
return(*this);
|
|
}
|
|
|
|
bool operator==(const Color& color){
|
|
return(val==color.val);
|
|
}
|
|
|
|
bool operator!=(const Color& color){
|
|
return(val!=color.val);
|
|
}
|
|
|
|
Color operator+(const Color& color){
|
|
Color newColor;
|
|
newColor.blue=blue+color.blue;
|
|
newColor.red=red+color.red;
|
|
newColor.green=green+color.green;
|
|
return(newColor);
|
|
}
|
|
|
|
Color& operator+=(const Color& color){
|
|
red+=color.red;
|
|
blue+=color.blue;
|
|
green+=color.green;
|
|
return(*this);
|
|
}
|
|
|
|
Color operator-(const Color& color){
|
|
Color newColor;
|
|
newColor.blue=blue-color.blue;
|
|
newColor.red=red-color.red;
|
|
newColor.green=green-color.green;
|
|
return(newColor);
|
|
}
|
|
|
|
Color& operator-=(const Color& color){
|
|
red-=color.red;
|
|
blue-=color.blue;
|
|
green-=color.green;
|
|
return(*this);
|
|
}
|
|
|
|
};
|
|
|
|
private:
|
|
uint32_t dataMask;
|
|
uint32_t clockMask;
|
|
volatile uint32_t *dataSetReg;
|
|
volatile uint32_t *dataClearReg;
|
|
volatile uint32_t *clockSetReg;
|
|
volatile uint32_t *clockClearReg;
|
|
|
|
public:
|
|
Dot(uint8_t dataPin, uint8_t clockPin); // creates addressable two-wire RGB LED connected to dataPin and clockPin (such as the DotStar SK9822 or APA102)
|
|
void set(Color *c, int nPixels, boolean multiColor=true); // sets colors of nPixels based on array of Colors c; setting multiColor to false repeats Color in c[0] for all nPixels
|
|
void set(Color c, int nPixels=1){set(&c,nPixels,false);} // sets color of nPixels to be equal to specific Color c
|
|
|
|
static Color RGB(uint8_t r, uint8_t g, uint8_t b, uint8_t driveLevel=31){return(Color().RGB(r,g,b,driveLevel));} // an alternative method for returning an RGB Color
|
|
static Color HSV(float h, float s, float v, double drivePercent=100){return(Color().HSV(h,s,v,drivePercent));} // an alternative method for returning an HSV Color
|
|
|
|
};
|
|
|
|
////////////////////////////////////////////
|