LedRing/src/main.cpp

346 lines
8.2 KiB
C++

#include <Arduino.h>
#include <Adafruit_NeoPixel.h>
#include <Encoder.h>
#include "pin_map.hpp"
#include "Button.hpp"
/* Types and Constants */
/* ---------------------------------------------------------------------------------------------- */
/* State machine */
#define FOREACH_MODE(MODE) \
MODE(ControlOff) \
MODE(LightOn) \
MODE(SetColor) \
MODE(SetSaturation) \
MODE(SetBrightness) \
MODE(Shift) \
#define GENERATE_MODE_ENUM(ENUM) ENUM,
enum class Mode_e {FOREACH_MODE(GENERATE_MODE_ENUM)};
Mode_e& operator++(Mode_e& mode)
{
if (mode == Mode_e::Shift) {
return mode = Mode_e::ControlOff;
}
return mode = static_cast<Mode_e>(static_cast<int>(mode) + 1);
}
#ifdef DEBUG
#define GENERATE_MODE_STRING(STRING) #STRING,
char static const * mode_str[] = {FOREACH_MODE(GENERATE_MODE_STRING)};
#endif /*DEBUG*/
/* Leds */
uint16_t static const LedCount{24};
uint8_t static const ColorSaturation{128};
uint8_t static const ColorArray[3][3] =
{{ColorSaturation, 0, 0}, {0, ColorSaturation, 0}, {0, 0, ColorSaturation}};
/* Led ring state */
typedef struct {
uint16_t ledOnCounter;
uint16_t ledOnShift;
uint16_t hue;
uint8_t saturation;
uint8_t brightness;
} LedRingState_t;
/* Button */
int const AnalogButtonVRef{970};
/* Global variables */
/* ---------------------------------------------------------------------------------------------- */
/* State machine */
Mode_e currentMode{Mode_e::ControlOff};
/* Led ring state */
LedRingState_t ledRingState {
.ledOnCounter = 1,
.ledOnShift = 0,
.hue = 0,
.saturation = 255,
.brightness = 16,
};
/* IO Objects */
Adafruit_NeoPixel ledRing{LedCount, LedPin, NEO_GRB + NEO_KHZ800};
Encoder encoder{EncoderPinA, EncoderPinB};
AnalogButton button{AnalogButtonPin, AnalogButtonVRef};
/* debug Serial definition */
#ifdef DEBUG
#ifdef ARDUINO_AVR_ATTINYX5
#include <SoftwareSerial.h>
SoftwareSerial debugSerial{RxPin, TxPin}; // RX, TX
#endif /*ARDUINO_AVR_ATTINYX5*/
#ifdef ARDUINO_AVR_UNO
#include <HardwareSerial.h>
HardwareSerial &debugSerial = Serial;
#endif /*ARDUINO_AVR_UNO*/
#endif /*DEBUG*/
/* Private function declarations */
/* ---------------------------------------------------------------------------------------------- */
/* State machine */
#define GENERATE_MODE_EXEC_DECLARTION(MODE) void MODE ## _execute (int shift);
FOREACH_MODE(GENERATE_MODE_EXEC_DECLARTION)
/* Encoder */
int get_encoder_shift(void);
void refresh_led_ring(void);
void analog_button_calibration(void);
/* Function definitions */
/* ---------------------------------------------------------------------------------------------- */
void setup()
{
#ifdef DEBUG
debugSerial.begin(9600);
while(!debugSerial.available());
debugSerial.println("Init ... ");
#endif /*DEBUG*/
analog_button_calibration();
ledRing.begin();
ledRing.setBrightness(50);
ledRing.show();
get_encoder_shift();
#ifdef DEBUG
debugSerial.println(mode_str[static_cast<int>(currentMode)]);
#endif /*DEBUG*/
}
void loop() {
int shift{get_encoder_shift()};
if (button.is_button_pressed()) {
while(button.is_button_pressed()){
delay(150);
}
++currentMode;
#ifdef DEBUG
debugSerial.println(mode_str[static_cast<int>(currentMode)]);
#endif /*DEBUG*/
}
if (shift != 0) {
switch (currentMode) {
case Mode_e::ControlOff:
ControlOff_execute(shift);
break;
case Mode_e::LightOn:
LightOn_execute(shift);
break;
case Mode_e::SetColor:
SetColor_execute(shift);
break;
case Mode_e::SetBrightness:
SetBrightness_execute(shift);
break;
case Mode_e::SetSaturation:
SetSaturation_execute(shift);
break;
case Mode_e::Shift:
Shift_execute(shift);
break;
default:
break;
}
}
if (currentMode != Mode_e::ControlOff && shift != 0) {
refresh_led_ring();
}
}
void ControlOff_execute (int shift) {
}
void LightOn_execute (int shift) {
uint16_t & ledOnCounter = ledRingState.ledOnCounter;
if (shift > 0) {
++ledOnCounter;
if (ledOnCounter > LedCount) {
ledOnCounter = 0;
}
} else {
--ledOnCounter;
if (ledOnCounter == UINT16_MAX) {
ledOnCounter = LedCount;
}
}
#if defined(DEBUG) && defined(ARDUINO_AVR_UNO)
if (shift != 0) {
debugSerial.print(__func__);
debugSerial.print(" : shift=");
debugSerial.print(shift, DEC);
debugSerial.print(", ledOnCounter=");
debugSerial.println(ledOnCounter, DEC);
}
#endif /*defined(DEBUG) && defined(ARDUINO_AVR_UNO)*/
}
void SetColor_execute (int shift) {
uint16_t & hue = ledRingState.hue;
hue += (shift << 8);
#if defined(DEBUG) && defined(ARDUINO_AVR_UNO)
if (shift != 0) {
debugSerial.print(__func__);
debugSerial.print(" : shift=");
debugSerial.print(shift, DEC);
debugSerial.print(", hue=");
debugSerial.println(hue, DEC);
}
#endif /*defined(DEBUG) && defined(ARDUINO_AVR_UNO)*/
}
void SetBrightness_execute (int shift) {
uint8_t & brightness = ledRingState.brightness;
brightness += (shift << 2);
#if defined(DEBUG) && defined(ARDUINO_AVR_UNO)
if (shift != 0) {
debugSerial.print(__func__);
debugSerial.print(" : shift=");
debugSerial.print(shift, DEC);
debugSerial.print(", brightness=");
debugSerial.println(brightness, DEC);
}
#endif /*defined(DEBUG) && defined(ARDUINO_AVR_UNO)*/
}
void Shift_execute (int shift) {
uint16_t & ledOnShift = ledRingState.ledOnShift;
if (shift > 0) {
++ledOnShift;
if (ledOnShift == LedCount) {
ledOnShift = 0;
}
} else {
--ledOnShift;
if (ledOnShift == UINT16_MAX) {
ledOnShift = LedCount - 1;
}
}
#if defined(DEBUG) && defined(ARDUINO_AVR_UNO)
if (shift != 0) {
debugSerial.print(__func__);
debugSerial.print(" : shift=");
debugSerial.print(shift, DEC);
debugSerial.print(", ledOnShift=");
debugSerial.println(ledOnShift, DEC);
}
#endif /*defined(DEBUG) && defined(ARDUINO_AVR_UNO)*/
}
void SetSaturation_execute (int shift) {
uint8_t & saturation = ledRingState.saturation;
saturation += (shift << 2);
#if defined(DEBUG) && defined(ARDUINO_AVR_UNO)
if (shift != 0) {
debugSerial.print(__func__);
debugSerial.print(" : shift=");
debugSerial.print(shift, DEC);
debugSerial.print(", saturation=");
debugSerial.println(saturation, DEC);
}
#endif /*defined(DEBUG) && defined(ARDUINO_AVR_UNO)*/
}
int get_encoder_shift(void) {
int32_t static _previousValue{encoder.read()};
int32_t currentValue{encoder.read()};
int32_t diff{currentValue - _previousValue};
if (diff <= -4) {
_previousValue = currentValue;
return diff >> 2;
} else if (diff >= 4) {
_previousValue = currentValue;
return diff >> 2;
} else {
return 0;
}
}
void refresh_led_ring(void) {
ledRing.fill(0);
for (size_t i = 0; i < ledRingState.ledOnCounter; ++i) {
unsigned int ledId = i + ledRingState.ledOnShift;
if (ledId >= LedCount) {
ledId -= LedCount;
}
ledRing.setPixelColor(ledId, Adafruit_NeoPixel::ColorHSV
(ledRingState.hue, ledRingState.saturation, ledRingState.brightness));
}
ledRing.show();
}
void analog_button_calibration(void) {
int hRef;
do {
hRef = analogRead(AnalogButtonPin);
delay(300);
#ifdef DEBUG
debugSerial.println(hRef);
#endif /*DEBUG*/
} while (hRef < 1000);
int lRef = analogRead(AnalogButtonPin);
while (hRef - lRef < 50) {
#ifdef DEBUG
debugSerial.println(lRef);
#endif /*DEBUG*/
lRef = analogRead(AnalogButtonPin);
delay(300);
}
#ifdef DEBUG
debugSerial.println(lRef);
#endif /*DEBUG*/
button = AnalogButton{AnalogButtonPin, lRef + 10};
while(analogRead(AnalogButtonPin) < lRef + 10){
delay(150);
}
}