diff --git a/platformio.ini b/platformio.ini index c13b695..52ab1e6 100644 --- a/platformio.ini +++ b/platformio.ini @@ -9,7 +9,7 @@ ; https://docs.platformio.org/page/projectconf.html [platformio] -default_envs = attiny85d +default_envs = attiny85_debug [env] build_flags = -Wall @@ -28,11 +28,16 @@ board_build.f_cpu = 16000000L ; board_fuses.hfuse = 0xBB ; board_fuses.efuse = 0xCC -[env:attiny85d] +[env:attiny85_debug] build_type = debug extends = env:attiny85 build_flags = -D DEBUG +[env:attiny85_init_debug] +build_type = debug +extends = env:attiny85_debug +build_flags = -D DEBUG_INIT + [env:uno] build_type = debug diff --git a/src/main.cpp b/src/main.cpp index 5095e04..d41650e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -13,41 +13,40 @@ /* State machine */ #define FOREACH_MODE(MODE) \ MODE(Init) \ + MODE(LightOnMin) \ + MODE(LightOnMax) \ + MODE(ControlOff) \ MODE(Preset) \ MODE(SetColor) \ MODE(SetSaturation) \ - MODE(SetBrightness) \ - MODE(LightOn) \ - MODE(Shift) \ - MODE(ControlOff) + MODE(SetBrightness) #define GENERATE_MODE_ENUM(ENUM) ENUM, +/* Generate Mode_e enum */ enum class Mode_e { FOREACH_MODE(GENERATE_MODE_ENUM) }; -/* cyclic increment operator for mode_e */ +/* Cyclic increment operator for Mode_e */ Mode_e &operator++(Mode_e &mode) { if (mode == Mode_e::ControlOff) { - return mode = Mode_e::Preset; + return mode = Mode_e::Init; } return mode = static_cast(static_cast(mode) + 1); } -#ifdef DEBUG +#if defined(DEBUG) +/* Generate string array from Mode_e names */ #define GENERATE_MODE_STRING(STRING) #STRING, char static const *mode_str[] = {FOREACH_MODE(GENERATE_MODE_STRING)}; -#endif /*DEBUG*/ +#endif /* defined(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 color and led count state */ typedef struct { - uint16_t ledOnCounter; - uint16_t ledOnShift; + uint16_t ledOnMin; + uint16_t ledOnMax; uint16_t hue; uint8_t saturation; uint8_t brightness; @@ -55,61 +54,17 @@ typedef struct { uint8_t const PresetMax{8}; -// https://hslpicker.com/ = {0, 40, 50, 110, 240, 280, 310, 360 for white} -uint16_t const PresetHue[PresetMax] = {0, 7282, 9102, 20025, 43691, 50972, 56434, 65535}; +// https://hslpicker.com/ = {0, 40, 50, 110, 240, 280, 310, 360 for +// white} +uint16_t const PresetHue[PresetMax] = {0, 7282, 9102, 20025, + 43691, 50972, 56434, 65535}; uint8_t const PresetLevelMax{3}; uint8_t const PresetBrightness[PresetLevelMax] = {16, 64, 127}; -// LedRingColorState_t const Preset[PresetMax] = {{ -// .ledOnCounter = LedCount, -// .ledOnShift = 0, -// .hue = 0, -// .saturation = 255, -// .brightness = 255 -// }, { -// .ledOnCounter = LedCount, -// .ledOnShift = 0, -// .hue = 28, -// .saturation = 255, -// .brightness = 255 -// }, { -// .ledOnCounter = LedCount, -// .ledOnShift = 0, -// .hue = 36, -// .saturation = 255, -// .brightness = 255 -// }, { -// .ledOnCounter = LedCount, -// .ledOnShift = 0, -// .hue = 78, -// .saturation = 255, -// .brightness = 255 -// }, { -// .ledOnCounter = LedCount, -// .ledOnShift = 0, -// .hue = 171, -// .saturation = 255, -// .brightness = 16, -// }, { -// .ledOnCounter = LedCount, -// .ledOnShift = 0, -// .hue = 199, -// .saturation = 255, -// .brightness = 16, -// }, { -// .ledOnCounter = LedCount, -// .ledOnShift = 0, -// .hue = 220, -// .saturation = 255, -// .brightness = 16, -// } -// }; - /* Preset state */ typedef struct { - bool isActive; uint8_t index; uint8_t level; } PresetState_t; @@ -128,21 +83,14 @@ int const AnalogButtonVRef{970}; /*----------------------------------------------------------------------------------------------*/ /* Led ring state */ -LedRingState_t ledRingState { - .ledRingColorState = { - .ledOnCounter = LedCount / 2, - .ledOnShift = 0, - .hue = 0, - .saturation = 255, - .brightness = 16 - }, - .presetState = { - .isActive = false, - .index = 0, - .level = 0 - }, - .currentMode = Mode_e::Init -}; +LedRingState_t ledRingState{ + .ledRingColorState = {.ledOnMin = 0, + .ledOnMax = LedCount / 2, + .hue = 0, + .saturation = 255, + .brightness = 16}, + .presetState = {.index = 0, .level = 0}, + .currentMode = Mode_e::Init}; /* IO Objects */ Adafruit_NeoPixel ledRing{LedCount, LedPin, NEO_GRB + NEO_KHZ800}; @@ -150,21 +98,21 @@ Encoder encoder{EncoderPinA, EncoderPinB}; AnalogButton button{AnalogButtonPin, AnalogButtonVRef}; /* debug Serial definition */ -#ifdef DEBUG -#ifdef ARDUINO_AVR_ATTINYX5 +#if defined(DEBUG) +#if defined(ARDUINO_AVR_ATTINYX5) #include SoftwareSerial debugSerial{RxPin, TxPin}; -#endif /*ARDUINO_AVR_ATTINYX5*/ -#ifdef ARDUINO_AVR_UNO +#endif /* defined(ARDUINO_AVR_ATTINYX5) */ +#if defined(ARDUINO_AVR_UNO) #include HardwareSerial &debugSerial = Serial; -#endif /*ARDUINO_AVR_UNO*/ -#endif /*DEBUG*/ +#endif /* defined(ARDUINO_AVR_UNO) */ +#endif /* defined(DEBUG) */ /* Private function declarations */ /*----------------------------------------------------------------------------------------------*/ -/* State machine */ +/* Generates state machine handlers for each Mode_e */ #define GENERATE_MODE_EXEC_DECLARTION(MODE) void MODE##_execute(int shift); FOREACH_MODE(GENERATE_MODE_EXEC_DECLARTION) @@ -177,12 +125,12 @@ void display_mode(Mode_e mode); void display_led_ring(void); -void refresh_led_ring(LedRingColorState_t const &ledRingColorState = ledRingState.ledRingColorState); +void refresh_led_ring(LedRingColorState_t const &ledRingColorState = + ledRingState.ledRingColorState); /* Function definitions */ /*----------------------------------------------------------------------------------------------*/ void setup() { - ledRing.begin(); ledRing.fill(Adafruit_NeoPixel::Color(45, 0, 0)); delay(300); @@ -191,20 +139,22 @@ void setup() { ledRing.fill(Adafruit_NeoPixel::Color(0, 0, 45)); delay(300); -#ifdef DEBUG +#if defined(DEBUG) debugSerial.begin(9600); +#if defined(DEBUG_INIT) while (!debugSerial.available()) ; +#endif /* defined(DEBUG_INIT) */ debugSerial.println("Init ... "); -#endif /*DEBUG*/ +#endif /* defined(DEBUG) */ analog_button_calibration(); get_encoder_shift(); -#ifdef DEBUG +#if defined(DEBUG) debugSerial.println(mode_str[static_cast(ledRingState.currentMode)]); -#endif /*DEBUG*/ +#endif /* defined(DEBUG) */ } void loop() { @@ -217,9 +167,9 @@ void loop() { } ++ledRingState.currentMode; -#ifdef DEBUG +#if defined(DEBUG) debugSerial.println(mode_str[static_cast(ledRingState.currentMode)]); -#endif /*DEBUG*/ +#endif /* defined(DEBUG) */ display_mode(ledRingState.currentMode); hasModeChanged = true; @@ -235,10 +185,6 @@ void loop() { Preset_execute(shift); break; - case Mode_e::LightOn: - LightOn_execute(shift); - break; - case Mode_e::SetColor: SetColor_execute(shift); break; @@ -251,8 +197,12 @@ void loop() { SetSaturation_execute(shift); break; - case Mode_e::Shift: - Shift_execute(shift); + case Mode_e::LightOnMin: + LightOnMin_execute(shift); + break; + + case Mode_e::LightOnMax: + LightOnMax_execute(shift); break; default: @@ -260,7 +210,8 @@ void loop() { } } - if (ledRingState.currentMode != Mode_e::ControlOff && (shift != 0 || hasModeChanged)) { + if (ledRingState.currentMode != Mode_e::ControlOff && + (shift != 0 || hasModeChanged)) { display_led_ring(); } } @@ -341,47 +292,29 @@ void SetSaturation_execute(int shift) { #endif /*defined(DEBUG) && defined(ARDUINO_AVR_UNO)*/ } /* SetSaturation_execute */ -void LightOn_execute(int shift) { - uint16_t &ledOnCounter = ledRingState.ledRingColorState.ledOnCounter; - static bool clockwise = true; - - if ((shift > 0) != !clockwise) { - ++ledOnCounter; - if (ledOnCounter > LedCount) { - ledOnCounter = LedCount; - clockwise = !clockwise; - } - } else { - --ledOnCounter; - if (ledOnCounter == UINT16_MAX) { - ledOnCounter = 0; - clockwise = !clockwise; - } - } - -#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)*/ -} /* LightOn_execute */ - -void Shift_execute(int shift) { - uint16_t &ledOnShift = ledRingState.ledRingColorState.ledOnShift; +void LightOnMin_execute(int shift) { + uint16_t &ledOnMin = ledRingState.ledRingColorState.ledOnMin; + uint16_t &ledOnMax = ledRingState.ledRingColorState.ledOnMax; if (shift > 0) { - ++ledOnShift; - if (ledOnShift == LedCount) { - ledOnShift = 0; + if (ledOnMin == ledOnMax) { + ledRingState.currentMode = Mode_e::LightOnMax; + ++ledOnMax; + } else { + ++ledOnMin; + if (ledOnMin == LedCount) { + ledOnMin = 0; + } } } else { - --ledOnShift; - if (ledOnShift == UINT16_MAX) { - ledOnShift = LedCount - 1; + if (ledOnMin == ledOnMax) { + ledRingState.currentMode = Mode_e::LightOnMax; + --ledOnMax; + } else { + --ledOnMin; + if (ledOnMin == UINT16_MAX) { + ledOnMin = LedCount - 1; + } } } @@ -390,39 +323,78 @@ void Shift_execute(int shift) { debugSerial.print(__func__); debugSerial.print(" : shift="); debugSerial.print(shift, DEC); - debugSerial.print(", ledOnShift="); - debugSerial.println(ledOnShift, DEC); + debugSerial.print(", ledOnMin="); + debugSerial.println(ledOnMin, DEC); } #endif /*defined(DEBUG) && defined(ARDUINO_AVR_UNO)*/ -} /* Shift_execute */ +} /* LightOnMin_execute */ + +void LightOnMax_execute(int shift) { + uint16_t &ledOnMin = ledRingState.ledRingColorState.ledOnMin; + uint16_t &ledOnMax = ledRingState.ledRingColorState.ledOnMax; + + if (shift > 0) { + if (ledOnMax == ledOnMin) { + ledRingState.currentMode = Mode_e::LightOnMin; + ++ledOnMin; + } else { + ++ledOnMax; + if (ledOnMax == LedCount) { + ledOnMax = 0; + } + } + } else { + if (ledOnMax == ledOnMin) { + ledRingState.currentMode = Mode_e::LightOnMin; + --ledOnMin; + } else { + --ledOnMax; + if (ledOnMax == UINT16_MAX) { + ledOnMax = LedCount - 1; + } + } + } + +#if defined(DEBUG) && defined(ARDUINO_AVR_UNO) + if (shift != 0) { + debugSerial.print(__func__); + debugSerial.print(" : shift="); + debugSerial.print(shift, DEC); + debugSerial.print(", ledOnMax="); + debugSerial.println(ledOnMax, DEC); + } +#endif /*defined(DEBUG) && defined(ARDUINO_AVR_UNO)*/ +} /* LightOnMax_execute */ /* Others functions */ void analog_button_calibration(void) { int highRef, lowRef; +#if defined(DEBUG) && false + debugSerial.print(__func__); +#endif /* defined(DEBUG) */ + do { highRef = analogRead(AnalogButtonPin); delay(300); - -#ifdef DEBUG - debugSerial.println(highRef); -#endif /*DEBUG*/ } while (highRef < 1000); +#if defined(DEBUG) && false + debugSerial.println("highRef="); + debugSerial.println(highRef); +#endif /* defined(DEBUG) */ + lowRef = analogRead(AnalogButtonPin); while (highRef - lowRef < 50) { -#ifdef DEBUG - debugSerial.println(lowRef); -#endif /*DEBUG*/ - lowRef = analogRead(AnalogButtonPin); delay(300); } -#ifdef DEBUG +#if defined(DEBUG) && false + debugSerial.println("lowRef="); debugSerial.println(lowRef); -#endif /*DEBUG*/ +#endif /* defined(DEBUG) */ button = AnalogButton{AnalogButtonPin, lowRef + 10}; } @@ -448,17 +420,12 @@ int get_encoder_shift(void) { void display_mode(Mode_e mode) { if (ledRingState.currentMode != Mode_e::ControlOff) { -#ifdef DEBUG - debugSerial.println("Display mode"); -#endif /*DEBUG*/ - for (size_t i = 0; i < 3; ++i) { ledRing.fill(0); ledRing.show(); delay(300); for (Mode_e i = Mode_e::Init; i < ledRingState.currentMode; ++i) { - ledRing.setPixelColor(int(i), Adafruit_NeoPixel::ColorHSV( - 0, 255, 16)); + ledRing.setPixelColor(int(i), Adafruit_NeoPixel::ColorHSV(0, 255, 16)); } ledRing.show(); delay(300); @@ -471,46 +438,68 @@ void display_led_ring(void) { LedRingColorState_t ledRingColorState; if (ledRingState.currentMode == Mode_e::Preset) { -#ifdef DEBUG - debugSerial.print("Preset : "); +#if defined(DEBUG) && false + debugSerial.print("Preset index,level="); debugSerial.print(preset.index); - debugSerial.print(", "); - // debugSerial.print((preset.index == (PresetMax - 1)) ? 0 : UINT8_MAX); - // debugSerial.print(", "); - debugSerial.println(preset.level); -#endif - ledRingColorState = { - .ledOnCounter = LedCount / 4, - .ledOnShift = 0, - .hue = PresetHue[preset.index], - .saturation = (preset.index == (PresetMax - 1)) ? 0 : UINT8_MAX, - .brightness = PresetBrightness[preset.level] - }; + debugSerial.print(","); + debugSerial.print(preset.level); + debugSerial.println(); +#endif /* defined(DEBUG) */ + ledRingColorState = {.ledOnMin = ledRingState.ledRingColorState.ledOnMin, + .ledOnMax = ledRingState.ledRingColorState.ledOnMax, + .hue = PresetHue[preset.index], + .saturation = + (preset.index == (PresetMax - 1)) ? 0 : UINT8_MAX, + .brightness = PresetBrightness[preset.level]}; refresh_led_ring(ledRingColorState); } else { refresh_led_ring(); } - } void refresh_led_ring(LedRingColorState_t const &ledRingColorState) { -#ifdef DEBUG - debugSerial.print("Color : "); - debugSerial.print(ledRingColorState.hue); - debugSerial.print(", "); - debugSerial.print(ledRingColorState.saturation); - debugSerial.print(", "); - debugSerial.println(ledRingColorState.brightness); -#endif + uint16_t const &ledOnMin = ledRingColorState.ledOnMin; + uint16_t const &ledOnMax = ledRingColorState.ledOnMax; + uint16_t LedOnCount = 0; + +#if defined(DEBUG) + debugSerial.print("Color hue,sat,bri="); + debugSerial.print(ledRingColorState.hue); + debugSerial.print(","); + debugSerial.print(ledRingColorState.saturation); + debugSerial.print(","); + debugSerial.println(ledRingColorState.brightness); +#endif /* defined(DEBUG) */ + + /* reset ring */ ledRing.fill(0); - for (size_t i = 0; i < ledRingColorState.ledOnCounter; ++i) { - unsigned int ledId = i + ledRingColorState.ledOnShift; + + /* compute number of led on */ + if (ledOnMin <= ledOnMax) { + LedOnCount = ledOnMax - ledOnMin; + } else { + LedOnCount = LedCount - (ledOnMax - ledOnMax); + } + +#if defined(DEBUG) + debugSerial.print("Led min,max,count="); + debugSerial.print(ledOnMin); + debugSerial.print(","); + debugSerial.print(ledOnMax); + debugSerial.print(","); + debugSerial.println(LedOnCount); +#endif /* defined(DEBUG) */ + + for (size_t i = ledRingColorState.ledOnMin; + i < ledRingColorState.ledOnMin + LedOnCount; ++i) { + unsigned int ledId = i; if (ledId >= LedCount) { ledId -= LedCount; } - ledRing.setPixelColor(ledId, Adafruit_NeoPixel::ColorHSV( - ledRingColorState.hue, ledRingColorState.saturation, - ledRingColorState.brightness)); + ledRing.setPixelColor( + ledId, Adafruit_NeoPixel::ColorHSV(ledRingColorState.hue, + ledRingColorState.saturation, + ledRingColorState.brightness)); } ledRing.show(); } \ No newline at end of file