From 048ad061e075539972d80c1b8f5fdfc730e8f4f9 Mon Sep 17 00:00:00 2001 From: Kurt LaVacque Date: Thu, 16 Oct 2025 22:13:24 +0200 Subject: [PATCH 01/17] Refactor Helios codebase to remove obsolete files and update structure - Deleted multiple unused files including Button.cpp, Colorset.cpp, Colortypes.cpp, Helios.cpp, and others to streamline the codebase. - Updated header files to reflect changes in structure and naming conventions, transitioning from class-based to struct-based definitions for better clarity. - Modified the Makefile to accommodate changes in source file extensions and compilation settings, ensuring compatibility with the new structure. - Added new entries to .gitignore to exclude unnecessary file types. These changes enhance maintainability and clarity while adhering to the KISS principle. --- .gitignore | 1 + Helios/Button.c | 349 ++++++++++++++++++++ Helios/Button.cpp | 278 ---------------- Helios/Button.h | 180 ++++------- Helios/Colorset.c | 365 +++++++++++++++++++++ Helios/Colorset.cpp | 365 --------------------- Helios/Colorset.h | 251 +++++++-------- Helios/Colortypes.c | 453 ++++++++++++++++++++++++++ Helios/Colortypes.cpp | 432 ------------------------- Helios/Colortypes.h | 129 +++----- Helios/Helios.c | 694 ++++++++++++++++++++++++++++++++++++++++ Helios/Helios.cpp | 662 -------------------------------------- Helios/Helios.h | 112 ++----- Helios/HeliosConfig.h | 4 +- Helios/Led.c | 190 +++++++++++ Helios/Led.cpp | 147 --------- Helios/Led.h | 87 ++--- Helios/Pattern.c | 375 ++++++++++++++++++++++ Helios/Pattern.cpp | 341 -------------------- Helios/Pattern.h | 207 ++++++------ Helios/Patterns.c | 86 +++++ Helios/Patterns.cpp | 81 ----- Helios/Patterns.h | 43 ++- Helios/Random.c | 43 +++ Helios/Random.cpp | 45 --- Helios/Random.h | 32 +- Helios/Storage.c | 293 +++++++++++++++++ Helios/Storage.cpp | 236 -------------- Helios/Storage.h | 66 ++-- Helios/TimeControl.c | 197 ++++++++++++ Helios/TimeControl.cpp | 183 ----------- Helios/TimeControl.h | 60 ++-- Helios/Timer.c | 56 ++++ Helios/Timer.cpp | 59 ---- Helios/Timer.h | 40 +-- HeliosEmbedded/Makefile | 18 +- HeliosEmbedded/main.c | 21 ++ HeliosEmbedded/main.cpp | 17 - 38 files changed, 3635 insertions(+), 3563 deletions(-) create mode 100644 Helios/Button.c delete mode 100644 Helios/Button.cpp create mode 100644 Helios/Colorset.c delete mode 100644 Helios/Colorset.cpp create mode 100644 Helios/Colortypes.c delete mode 100644 Helios/Colortypes.cpp create mode 100644 Helios/Helios.c delete mode 100644 Helios/Helios.cpp create mode 100644 Helios/Led.c delete mode 100644 Helios/Led.cpp create mode 100644 Helios/Pattern.c delete mode 100644 Helios/Pattern.cpp create mode 100644 Helios/Patterns.c delete mode 100644 Helios/Patterns.cpp create mode 100644 Helios/Random.c delete mode 100644 Helios/Random.cpp create mode 100644 Helios/Storage.c delete mode 100644 Helios/Storage.cpp create mode 100644 Helios/TimeControl.c delete mode 100644 Helios/TimeControl.cpp create mode 100644 Helios/Timer.c delete mode 100644 Helios/Timer.cpp create mode 100644 HeliosEmbedded/main.c delete mode 100644 HeliosEmbedded/main.cpp diff --git a/.gitignore b/.gitignore index 055c97e4..53a0181c 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ !*.pattern !*.h !*.cpp +!*.c !*.py !*.atsln !*.componentinfo.xml diff --git a/Helios/Button.c b/Helios/Button.c new file mode 100644 index 00000000..60dea676 --- /dev/null +++ b/Helios/Button.c @@ -0,0 +1,349 @@ +#include "Button.h" +#include "TimeControl.h" +#include "HeliosConfig.h" + +#ifdef HELIOS_EMBEDDED +#include +#include +#ifdef HELIOS_ARDUINO +#include +#endif +#define BUTTON_PIN 3 +#define BUTTON_PORT 2 +#endif + +/* Forward declaration */ +void helios_wakeup(void); +void helios_terminate(void); + +#ifdef HELIOS_CLI +/* Forward declarations for CLI functions */ +static uint8_t button_process_pre_input(void); +static uint8_t button_process_post_input(void); +#endif + +/* static members of Button */ +static uint32_t m_pressTime = 0; +static uint32_t m_releaseTime = 0; +static uint32_t m_holdDuration = 0; +static uint32_t m_releaseDuration = 0; +static uint8_t m_releaseCount = 0; +static uint8_t m_buttonState = 0; +static uint8_t m_newPress = 0; +static uint8_t m_newRelease = 0; +static uint8_t m_isPressed = 0; +static uint8_t m_shortClick = 0; +static uint8_t m_longClick = 0; +static uint8_t m_holdClick = 0; + +#ifdef HELIOS_CLI +/* Note: For embedded builds, we exclude std::queue and CLI-only features. + * The CLI input queue functionality is omitted for embedded targets. */ +static uint8_t m_pinState = 0; +static uint8_t m_enableWake = 0; +/* Simple input queue for CLI - using a fixed-size circular buffer */ +#define INPUT_QUEUE_SIZE 64 +static char m_inputQueue[INPUT_QUEUE_SIZE]; +static uint32_t m_queueHead = 0; +static uint32_t m_queueTail = 0; +#endif + +uint8_t button_init(void) +{ + m_pressTime = 0; + m_releaseTime = 0; + m_holdDuration = 0; + m_releaseDuration = 0; + m_newPress = 0; + m_newRelease = 0; + m_shortClick = 0; + m_longClick = 0; + m_holdClick = 0; + m_buttonState = button_check(); + m_releaseCount = !m_buttonState; + m_isPressed = m_buttonState; +#ifdef HELIOS_CLI + m_pinState = 0; + m_enableWake = 0; + m_queueHead = 0; + m_queueTail = 0; +#endif +#ifdef HELIOS_EMBEDDED +#ifdef HELIOS_ARDUINO + pinMode(3, INPUT); +#else + /* turn off wake */ + PCMSK &= ~(1 << PCINT3); + GIMSK &= ~(1 << PCIE); +#endif +#endif + return 1; +} + +void button_enable_wake(void) +{ +#ifdef HELIOS_EMBEDDED + /* Configure INT0 to trigger on falling edge */ + PCMSK |= (1 << PCINT3); + GIMSK |= (1 << PCIE); + sei(); +#else /* HELIOS_CLI */ + m_enableWake = 0; +#endif +} + +#ifdef HELIOS_EMBEDDED +ISR(PCINT0_vect) { + PCMSK &= ~(1 << PCINT3); + GIMSK &= ~(1 << PCIE); + helios_wakeup(); +} +#endif + +uint8_t button_check(void) +{ +#ifdef HELIOS_EMBEDDED +#ifdef HELIOS_ARDUINO + return digitalRead(3) == HIGH; +#else + return (PINB & (1 << 3)) != 0; +#endif +#elif defined(HELIOS_CLI) + /* then just return the pin state as-is, the input event may have + * adjusted this value */ + return m_pinState; +#else + return 0; +#endif +} + +uint8_t button_hold_pressing(void) +{ + uint16_t holDur = (uint16_t)(button_hold_duration()); + if (holDur > HOLD_CLICK_START && holDur <= HOLD_CLICK_END && button_is_pressed()) { + return 1; + } + return 0; +} + +void button_update(void) +{ +#ifdef HELIOS_CLI + /* process any pre-input events in the queue */ + uint8_t processed_pre = button_process_pre_input(); +#endif + + uint8_t newButtonState = button_check(); + m_newPress = 0; + m_newRelease = 0; + if (newButtonState != m_buttonState) { + m_buttonState = newButtonState; + m_isPressed = m_buttonState; + if (m_isPressed) { + m_pressTime = Time_getCurtime(); + m_newPress = 1; + } else { + m_releaseTime = Time_getCurtime(); + m_newRelease = 1; + m_releaseCount++; + } + } + if (m_isPressed) { + m_holdDuration = (Time_getCurtime() >= m_pressTime) ? (uint32_t)(Time_getCurtime() - m_pressTime) : 0; + } else { + m_releaseDuration = (Time_getCurtime() >= m_releaseTime) ? (uint32_t)(Time_getCurtime() - m_releaseTime) : 0; + } + m_shortClick = (m_newRelease && (m_holdDuration <= SHORT_CLICK_THRESHOLD)); + m_longClick = (m_newRelease && (m_holdDuration > SHORT_CLICK_THRESHOLD) && (m_holdDuration < HOLD_CLICK_START)); + m_holdClick = (m_newRelease && (m_holdDuration >= HOLD_CLICK_START) && (m_holdDuration <= HOLD_CLICK_END)); + +#ifdef HELIOS_CLI + /* if there was no pre-input event this tick, process a post input event + * to ensure there is only one event per tick processed */ + if (!processed_pre) { + button_process_post_input(); + } + + if (m_enableWake) { + if (m_isPressed || m_shortClick || m_longClick) { + helios_wakeup(); + } + } +#endif +} + +uint8_t button_on_press(void) +{ + return m_newPress; +} + +uint8_t button_on_release(void) +{ + return m_newRelease; +} + +uint8_t button_is_pressed(void) +{ + return m_isPressed; +} + +uint8_t button_on_short_click(void) +{ + return m_shortClick; +} + +uint8_t button_on_long_click(void) +{ + return m_longClick; +} + +uint8_t button_on_hold_click(void) +{ + return m_holdClick; +} + +uint32_t button_press_time(void) +{ + return m_pressTime; +} + +uint32_t button_release_time(void) +{ + return m_releaseTime; +} + +uint32_t button_hold_duration(void) +{ + return m_holdDuration; +} + +uint32_t button_release_duration(void) +{ + return m_releaseDuration; +} + +uint8_t button_release_count(void) +{ + return m_releaseCount; +} + +#ifdef HELIOS_CLI +static uint8_t button_process_pre_input(void) +{ + if (m_queueHead == m_queueTail) { + return 0; + } + char command = m_inputQueue[m_queueHead]; + switch (command) { + case 'p': /* press */ + button_do_press(); + break; + case 'r': /* release */ + button_do_release(); + break; + case 't': /* toggle */ + button_do_toggle(); + break; + case 'q': /* quit */ + helios_terminate(); + break; + case 'w': /* wait */ + /* wait is pre input I guess */ + break; + default: + /* return here! do not pop the queue + * do not process post input events */ + return 0; + } + /* now pop whatever pre-input command was processed */ + m_queueHead = (m_queueHead + 1) % INPUT_QUEUE_SIZE; + return 1; +} + +static uint8_t button_process_post_input(void) +{ + if (m_queueHead == m_queueTail) { + /* probably processed the pre-input event already */ + return 0; + } + /* process input queue from the command line */ + char command = m_inputQueue[m_queueHead]; + switch (command) { + case 'c': /* click button */ + button_do_short_click(); + break; + case 'l': /* long click button */ + button_do_long_click(); + break; + default: + /* should never happen */ + return 0; + } + m_queueHead = (m_queueHead + 1) % INPUT_QUEUE_SIZE; + return 1; +} + +void button_do_short_click(void) +{ + m_newRelease = 1; + m_shortClick = 1; + m_pressTime = Time_getCurtime(); + m_holdDuration = SHORT_CLICK_THRESHOLD - 1; + m_releaseCount++; +} + +void button_do_long_click(void) +{ + m_newRelease = 1; + m_longClick = 1; + m_pressTime = Time_getCurtime(); + m_holdDuration = SHORT_CLICK_THRESHOLD + 1; + m_releaseCount++; +} + +void button_do_hold_click(void) +{ + m_newRelease = 1; + m_holdClick = 1; + m_pressTime = Time_getCurtime(); + m_holdDuration = HOLD_CLICK_START + 1; + m_releaseCount++; +} + +/* this will actually press down the button, it's your responsibility to wait + * for the appropriate number of ticks and then release the button */ +void button_do_press(void) +{ + m_pinState = 1; +} + +void button_do_release(void) +{ + m_pinState = 0; +} + +void button_do_toggle(void) +{ + m_pinState = !m_pinState; +} + +/* queue up an input event for the button */ +void button_queue_input(char input) +{ + uint32_t nextTail = (m_queueTail + 1) % INPUT_QUEUE_SIZE; + if (nextTail != m_queueHead) { + m_inputQueue[m_queueTail] = input; + m_queueTail = nextTail; + } +} + +uint32_t button_input_queue_size(void) +{ + if (m_queueTail >= m_queueHead) { + return m_queueTail - m_queueHead; + } else { + return INPUT_QUEUE_SIZE - m_queueHead + m_queueTail; + } +} +#endif + diff --git a/Helios/Button.cpp b/Helios/Button.cpp deleted file mode 100644 index b58ed095..00000000 --- a/Helios/Button.cpp +++ /dev/null @@ -1,278 +0,0 @@ -#include "Button.h" -#include "TimeControl.h" - -#ifdef HELIOS_EMBEDDED -#include -#include -#ifdef HELIOS_ARDUINO -#include -#endif -#define BUTTON_PIN 3 -#define BUTTON_PORT 2 -#endif - -#include "Helios.h" - -// static members of Button -uint32_t Button::m_pressTime = 0; -uint32_t Button::m_releaseTime = 0; -uint32_t Button::m_holdDuration = 0; -uint32_t Button::m_releaseDuration = 0; -uint8_t Button::m_releaseCount = 0; -bool Button::m_buttonState = false; -bool Button::m_newPress = false; -bool Button::m_newRelease = false; -bool Button::m_isPressed = false; -bool Button::m_shortClick = false; -bool Button::m_longClick = false; -bool Button::m_holdClick = false; - -#ifdef HELIOS_CLI -// an input queue for the button, each tick one even is processed -// out of this queue and used to produce input -std::queue Button::m_inputQueue; -// the virtual pin state -bool Button::m_pinState = false; -// whether the button is waiting to wake the device -bool Button::m_enableWake = false; -#endif - -// initialize a new button object with a pin number -bool Button::init() -{ - m_pressTime = 0; - m_releaseTime = 0; - m_holdDuration = 0; - m_releaseDuration = 0; - m_newPress = false; - m_newRelease = false; - m_shortClick = false; - m_longClick = false; - m_holdClick = false; - m_buttonState = check(); - m_releaseCount = !m_buttonState; - m_isPressed = m_buttonState; -#ifdef HELIOS_CLI - m_pinState = false; - m_enableWake = false; -#endif -#ifdef HELIOS_EMBEDDED -#ifdef HELIOS_ARDUINO - pinMode(3, INPUT); -#else - // turn off wake - PCMSK &= ~(1 << PCINT3); - GIMSK &= ~(1 << PCIE); -#endif -#endif - return true; -} - -// enable wake on press -void Button::enableWake() -{ -#ifdef HELIOS_EMBEDDED - // Configure INT0 to trigger on falling edge - PCMSK |= (1 << PCINT3); - GIMSK |= (1 << PCIE); - sei(); -#else // HELIOS_CLI - m_enableWake = false; -#endif -} - -#ifdef HELIOS_EMBEDDED -ISR(PCINT0_vect) { - PCMSK &= ~(1 << PCINT3); - GIMSK &= ~(1 << PCIE); - Helios::wakeup(); -} -#endif - -// directly poll the pin for whether it's pressed right now -bool Button::check() -{ -#ifdef HELIOS_EMBEDDED -#ifdef HELIOS_ARDUINO - return digitalRead(3) == HIGH; -#else - return (PINB & (1 << 3)) != 0; -#endif -#elif defined(HELIOS_CLI) - // then just return the pin state as-is, the input event may have - // adjusted this value - return m_pinState; -#endif -} - -// detect if the button is being held for a long hold (past long click) -bool Button::holdPressing() -{ - uint16_t holDur = (uint16_t)(Button::holdDuration()); - if (holDur > HOLD_CLICK_START && holDur <= HOLD_CLICK_END && Button::isPressed()) { - return true; - } - return false; -} - -// poll the button pin and update the state of the button object -void Button::update() -{ -#ifdef HELIOS_CLI - // process any pre-input events in the queue - bool processed_pre = processPreInput(); -#endif - - bool newButtonState = check(); - m_newPress = false; - m_newRelease = false; - if (newButtonState != m_buttonState) { - m_buttonState = newButtonState; - m_isPressed = m_buttonState; - if (m_isPressed) { - m_pressTime = Time::getCurtime(); - m_newPress = true; - } else { - m_releaseTime = Time::getCurtime(); - m_newRelease = true; - m_releaseCount++; - } - } - if (m_isPressed) { - m_holdDuration = (Time::getCurtime() >= m_pressTime) ? (uint32_t)(Time::getCurtime() - m_pressTime) : 0; - } else { - m_releaseDuration = (Time::getCurtime() >= m_releaseTime) ? (uint32_t)(Time::getCurtime() - m_releaseTime) : 0; - } - m_shortClick = (m_newRelease && (m_holdDuration <= SHORT_CLICK_THRESHOLD)); - m_longClick = (m_newRelease && (m_holdDuration > SHORT_CLICK_THRESHOLD) && (m_holdDuration < HOLD_CLICK_START)); - m_holdClick = (m_newRelease && (m_holdDuration >= HOLD_CLICK_START) && (m_holdDuration <= HOLD_CLICK_END)); - -#ifdef HELIOS_CLI - // if there was no pre-input event this tick, process a post input event - // to ensure there is only one event per tick processed - if (!processed_pre) { - processPostInput(); - } - - if (m_enableWake) { - if (m_isPressed || m_shortClick || m_longClick) { - Helios::wakeup(); - } - } -#endif -} - -#ifdef HELIOS_CLI -bool Button::processPreInput() -{ - if (!m_inputQueue.size()) { - return false; - } - char command = m_inputQueue.front(); - switch (command) { - case 'p': // press - Button::doPress(); - break; - case 'r': // release - Button::doRelease(); - break; - case 't': // toggle - Button::doToggle(); - break; - case 'q': // quit - Helios::terminate(); - break; - case 'w': // wait - // wait is pre input I guess - break; - default: - // return here! do not pop the queue - // do not process post input events - return false; - } - // now pop whatever pre-input command was processed - m_inputQueue.pop(); - return true; -} - -bool Button::processPostInput() -{ - if (!m_inputQueue.size()) { - // probably processed the pre-input event already - return false; - } - // process input queue from the command line - char command = m_inputQueue.front(); - switch (command) { - case 'c': // click button - Button::doShortClick(); - break; - case 'l': // long click button - Button::doLongClick(); - break; - default: - // should never happen - return false; - } - m_inputQueue.pop(); - return true; -} - -void Button::doShortClick() -{ - m_newRelease = true; - m_shortClick = true; - m_pressTime = Time::getCurtime(); - m_holdDuration = SHORT_CLICK_THRESHOLD - 1; - m_releaseCount++; -} - -void Button::doLongClick() -{ - m_newRelease = true; - m_longClick = true; - m_pressTime = Time::getCurtime(); - m_holdDuration = SHORT_CLICK_THRESHOLD + 1; - m_releaseCount++; -} - -void Button::doHoldClick() -{ - m_newRelease = true; - m_holdClick = true; - m_pressTime = Time::getCurtime(); - m_holdDuration = HOLD_CLICK_START + 1; - m_releaseCount++; -} - -// this will actually press down the button, it's your responsibility to wait -// for the appropriate number of ticks and then release the button -void Button::doPress() -{ - m_pinState = true; -} - -void Button::doRelease() -{ - m_pinState = false; -} - -void Button::doToggle() -{ - m_pinState = !m_pinState; -} - -// queue up an input event for the button -void Button::queueInput(char input) -{ - m_inputQueue.push(input); -} - -uint32_t Button::inputQueueSize() -{ - return m_inputQueue.size(); -} -#endif - -// global button -Button button; diff --git a/Helios/Button.h b/Helios/Button.h index 33d26ecf..aa278563 100644 --- a/Helios/Button.h +++ b/Helios/Button.h @@ -1,119 +1,77 @@ +#ifndef BUTTON_H +#define BUTTON_H + #include -#ifdef HELIOS_CLI -#include -#endif +/* Initialize button */ +uint8_t button_init(void); -class Button -{ -public: - // initialize a new button object with a pin number - static bool init(); - // directly poll the pin for whether it's pressed right now - static bool check(); - // poll the button pin and update the state of the button object - static void update(); - - // whether the button was pressed this tick - static bool onPress() { return m_newPress; } - // whether the button was released this tick - static bool onRelease() { return m_newRelease; } - // whether the button is currently pressed - static bool isPressed() { return m_isPressed; } - - // whether the button was shortclicked this tick - static bool onShortClick() { return m_shortClick; } - // whether the button was long clicked this tick - static bool onLongClick() { return m_longClick; } - // whether the button was hold clicked this tick - static bool onHoldClick() { return m_holdClick; } - - // detect if the button is being held past long click - static bool holdPressing(); - - // when the button was last pressed - static uint32_t pressTime() { return m_pressTime; } - // when the button was last released - static uint32_t releaseTime() { return m_releaseTime; } - - // how long the button is currently or was last held down (in ticks) - static uint32_t holdDuration() { return m_holdDuration; } - // how long the button is currently or was last released for (in ticks) - static uint32_t releaseDuration() { return m_releaseDuration; } - - // the number of releases - static uint8_t releaseCount() { return m_releaseCount; } - - // enable wake on press - static void enableWake(); +/* Directly poll the pin for whether it's pressed right now */ +uint8_t button_check(void); -#ifdef HELIOS_CLI - // these will 'inject' a short/long click without actually touching the - // button state, it's important that code uses 'onShortClick' or - // 'onLongClick' to capture this injected input event. Code that uses - // for example: 'button.holdDuration() >= threshold && button.onRelease()' - // will never trigger because the injected input event doesn't actually - // press the button or change the button state it just sets the 'shortClick' - // or 'longClick' values accordingly - static void doShortClick(); - static void doLongClick(); - static void doHoldClick(); - - // this will actually press down the button, it's your responsibility to wait - // for the appropriate number of ticks and then release the button - static void doPress(); - static void doRelease(); - static void doToggle(); - - // queue up an input event for the button - static void queueInput(char input); - static uint32_t inputQueueSize(); -#endif +/* Poll the button pin and update the state of the button object */ +void button_update(void); + +/* Whether the button was pressed this tick */ +uint8_t button_on_press(void); + +/* Whether the button was released this tick */ +uint8_t button_on_release(void); + +/* Whether the button is currently pressed */ +uint8_t button_is_pressed(void); + +/* Whether the button was shortclicked this tick */ +uint8_t button_on_short_click(void); + +/* Whether the button was long clicked this tick */ +uint8_t button_on_long_click(void); -private: - // ======================================== - // state data that is populated each check - - // the timestamp of when the button was pressed - static uint32_t m_pressTime; - // the timestamp of when the button was released - static uint32_t m_releaseTime; - - // the last hold duration - static uint32_t m_holdDuration; - // the last release duration - static uint32_t m_releaseDuration; - - // the number of times released, will overflow at 255 - static uint8_t m_releaseCount; - - // the active state of the button - static bool m_buttonState; - - // whether pressed this tick - static bool m_newPress; - // whether released this tick - static bool m_newRelease; - // whether currently pressed - static bool m_isPressed; - // whether a short click occurred - static bool m_shortClick; - // whether a long click occurred - static bool m_longClick; - // whether a long hold occurred - static bool m_holdClick; +/* Whether the button was hold clicked this tick */ +uint8_t button_on_hold_click(void); + +/* Detect if the button is being held past long click */ +uint8_t button_hold_pressing(void); + +/* When the button was last pressed */ +uint32_t button_press_time(void); + +/* When the button was last released */ +uint32_t button_release_time(void); + +/* How long the button is currently or was last held down (in ticks) */ +uint32_t button_hold_duration(void); + +/* How long the button is currently or was last released for (in ticks) */ +uint32_t button_release_duration(void); + +/* The number of releases */ +uint8_t button_release_count(void); + +/* Enable wake on press */ +void button_enable_wake(void); #ifdef HELIOS_CLI - // process pre or post input events from the queue - static bool processPreInput(); - static bool processPostInput(); - - // an input queue for the button, each tick one even is processed - // out of this queue and used to produce input - static std::queue m_inputQueue; - // the virtual pin state that is polled instead of a digital pin - static bool m_pinState; - // whether the button is waiting to wake the device - static bool m_enableWake; +/* These will 'inject' a short/long click without actually touching the + * button state, it's important that code uses 'button_on_short_click' or + * 'button_on_long_click' to capture this injected input event. Code that uses + * for example: 'button_hold_duration() >= threshold && button_on_release()' + * will never trigger because the injected input event doesn't actually + * press the button or change the button state it just sets the 'shortClick' + * or 'longClick' values accordingly */ +void button_do_short_click(void); +void button_do_long_click(void); +void button_do_hold_click(void); + +/* This will actually press down the button, it's your responsibility to wait + * for the appropriate number of ticks and then release the button */ +void button_do_press(void); +void button_do_release(void); +void button_do_toggle(void); + +/* Queue up an input event for the button */ +void button_queue_input(char input); +uint32_t button_input_queue_size(void); +#endif + #endif -}; diff --git a/Helios/Colorset.c b/Helios/Colorset.c new file mode 100644 index 00000000..e3779af9 --- /dev/null +++ b/Helios/Colorset.c @@ -0,0 +1,365 @@ +#include "Colorset.h" + +#include "Random.h" + +#include + +/* when no color is selected in the colorset the index is this + * then when you call colorset_get_next() for the first time it returns + * the 0th color in the colorset and after the index will be 0 */ +#define INDEX_INVALID 255 + +void colorset_init(colorset_t *set) +{ + memset((void *)set->m_palette, 0, sizeof(set->m_palette)); + set->m_numColors = 0; + set->m_curIndex = INDEX_INVALID; +} + +void colorset_init_multi(colorset_t *set, rgb_color_t c1, rgb_color_t c2, rgb_color_t c3, + rgb_color_t c4, rgb_color_t c5, rgb_color_t c6, rgb_color_t c7, rgb_color_t c8) +{ + colorset_init(set); + /* would be nice if we could do this another way */ + if (!rgb_empty(&c1)) colorset_add_color(set, c1); + if (!rgb_empty(&c2)) colorset_add_color(set, c2); + if (!rgb_empty(&c3)) colorset_add_color(set, c3); + if (!rgb_empty(&c4)) colorset_add_color(set, c4); + if (!rgb_empty(&c5)) colorset_add_color(set, c5); + if (!rgb_empty(&c6)) colorset_add_color(set, c6); + if (!rgb_empty(&c7)) colorset_add_color(set, c7); + if (!rgb_empty(&c8)) colorset_add_color(set, c8); +} + +void colorset_init_array(colorset_t *set, uint8_t numCols, const uint32_t *cols) +{ + colorset_init(set); + if (numCols > NUM_COLOR_SLOTS) { + numCols = NUM_COLOR_SLOTS; + } + uint8_t i; + for (i = 0; i < numCols; ++i) { + rgb_color_t col; + rgb_init_from_raw(&col, cols[i]); + colorset_add_color(set, col); + } +} + +void colorset_copy(colorset_t *dest, const colorset_t *src) +{ + memcpy(dest->m_palette, src->m_palette, sizeof(dest->m_palette)); + dest->m_numColors = src->m_numColors; + dest->m_curIndex = src->m_curIndex; +} + +uint8_t colorset_equals(const colorset_t *a, const colorset_t *b) +{ + /* only compare the palettes for equality */ + return (a->m_numColors == b->m_numColors) && + (memcmp(a->m_palette, b->m_palette, a->m_numColors * sizeof(rgb_color_t)) == 0); +} + +void colorset_clear(colorset_t *set) +{ + memset((void *)set->m_palette, 0, sizeof(set->m_palette)); + set->m_numColors = 0; + colorset_reset_index(set); +} + +uint32_t colorset_crc32(const colorset_t *set) +{ + uint32_t hash = 5381; + uint8_t i; + for (i = 0; i < set->m_numColors; ++i) { + hash = ((hash << 5) + hash) + rgb_raw(&set->m_palette[i]); + } + return hash; +} + +rgb_color_t colorset_get_at_index(const colorset_t *set, int index) +{ + return colorset_get(set, index); +} + +uint8_t colorset_add_color(colorset_t *set, rgb_color_t col) +{ + if (set->m_numColors >= NUM_COLOR_SLOTS) { + return 0; + } + /* insert new color and increment number of colors */ + set->m_palette[set->m_numColors] = col; + set->m_numColors++; + return 1; +} + +uint8_t colorset_add_color_hsv(colorset_t *set, uint8_t hue, uint8_t sat, uint8_t val) +{ + hsv_color_t hsv; + rgb_color_t rgb; + hsv_init3(&hsv, hue, sat, val); + rgb_init_from_hsv(&rgb, &hsv); + return colorset_add_color(set, rgb); +} + +void colorset_add_color_with_value_style(colorset_t *set, random_t *ctx, uint8_t hue, uint8_t sat, + enum colorset_value_style valStyle, uint8_t numColors, uint8_t colorPos) +{ + if (numColors == 1) { + colorset_add_color_hsv(set, hue, sat, random_next8(ctx, 16, 255)); + return; + } + switch (valStyle) { + default: + case VAL_STYLE_RANDOM: + colorset_add_color_hsv(set, hue, sat, 85 * random_next8(ctx, 1, 4)); + break; + case VAL_STYLE_LOW_FIRST_COLOR: + if (set->m_numColors == 0) { + colorset_add_color_hsv(set, hue, sat, random_next8(ctx, 0, 86)); + } else { + colorset_add_color_hsv(set, hue, sat, 85 * random_next8(ctx, 1, 4)); + } + break; + case VAL_STYLE_HIGH_FIRST_COLOR: + if (set->m_numColors == 0) { + colorset_add_color_hsv(set, hue, sat, 255); + } else { + colorset_add_color_hsv(set, hue, sat, random_next8(ctx, 0, 86)); + } + break; + case VAL_STYLE_ALTERNATING: + if (set->m_numColors % 2 == 0) { + colorset_add_color_hsv(set, hue, sat, 255); + } else { + colorset_add_color_hsv(set, hue, sat, 85); + } + break; + case VAL_STYLE_ASCENDING: + colorset_add_color_hsv(set, hue, sat, (colorPos + 1) * (255 / numColors)); + break; + case VAL_STYLE_DESCENDING: + colorset_add_color_hsv(set, hue, sat, 255 - (colorPos * (255 / numColors))); + break; + case VAL_STYLE_CONSTANT: + colorset_add_color_hsv(set, hue, sat, 255); + } +} + +void colorset_remove_color(colorset_t *set, uint8_t index) +{ + if (index >= set->m_numColors) { + return; + } + uint8_t i; + for (i = index; i < (set->m_numColors - 1); ++i) { + set->m_palette[i] = set->m_palette[i + 1]; + } + rgb_clear(&set->m_palette[--set->m_numColors]); +} + +void colorset_randomize_colors(colorset_t *set, random_t *ctx, uint8_t numColors, enum colorset_color_mode mode) +{ + /* if they specify randomly pick the color mode then roll it */ + if (mode >= COLOR_MODE_RANDOMLY_PICK) { + mode = (enum colorset_color_mode)(random_next8(ctx, 0, 255) % COLOR_MODE_COUNT); + } + colorset_clear(set); + if (!numColors) { + numColors = random_next8(ctx, mode == COLOR_MODE_MONOCHROMATIC ? 2 : 1, 9); + } + uint8_t randomizedHue = random_next8(ctx, 0, 255); + uint8_t colorGap = 0; + if (mode == COLOR_MODE_COLOR_THEORY && numColors > 1) { + colorGap = random_next8(ctx, 16, 256 / (numColors - 1)); + } + enum colorset_value_style valStyle = (enum colorset_value_style)random_next8(ctx, 0, VAL_STYLE_COUNT); + /* the doubleStyle decides if some colors are added to the set twice */ + uint8_t doubleStyle = 0; + if (numColors <= 7) { + doubleStyle = random_next8(ctx, 0, 1); + } + if (numColors <= 4) { + doubleStyle = random_next8(ctx, 0, 2); + } + uint8_t i; + for (i = 0; i < numColors; i++) { + uint8_t hueToUse; + uint8_t valueToUse = 255; + if (mode == COLOR_MODE_COLOR_THEORY) { + hueToUse = (randomizedHue + (i * colorGap)); + } else if (mode == COLOR_MODE_MONOCHROMATIC) { + hueToUse = randomizedHue; + valueToUse = 255 - (i * (256 / numColors)); + } else { /* EVENLY_SPACED */ + hueToUse = (randomizedHue + (256 / numColors) * i); + } + colorset_add_color_with_value_style(set, ctx, hueToUse, valueToUse, valStyle, numColors, i); + /* double all colors or only first color */ + if (doubleStyle == 2 || (doubleStyle == 1 && !i)) { + colorset_add_color_with_value_style(set, ctx, hueToUse, valueToUse, valStyle, numColors, i); + } + } +} + +void colorset_adjust_brightness(colorset_t *set, uint8_t fadeby) +{ + uint8_t i; + for (i = 0; i < set->m_numColors; ++i) { + rgb_adjust_brightness(&set->m_palette[i], fadeby); + } +} + +rgb_color_t colorset_get(const colorset_t *set, uint8_t index) +{ + rgb_color_t result; + if (index >= set->m_numColors) { + rgb_init3(&result, 0, 0, 0); + return result; + } + return set->m_palette[index]; +} + +void colorset_set(colorset_t *set, uint8_t index, rgb_color_t col) +{ + /* special case for 'setting' a color at the edge of the palette, + * ie adding a new color when you set an index higher than the max */ + if (index >= set->m_numColors) { + if (!colorset_add_color(set, col)) { + /* ERROR_LOGF("Failed to add new color at index %u", index); */ + } + return; + } + set->m_palette[index] = col; +} + +void colorset_skip(colorset_t *set, int32_t amount) +{ + if (!set->m_numColors) { + return; + } + /* if the colorset hasn't started yet */ + if (set->m_curIndex == INDEX_INVALID) { + set->m_curIndex = 0; + } + + /* first modulate the amount to skip to be within +/- the number of colors */ + amount %= (int32_t)set->m_numColors; + + /* max = 3 + * m_curIndex = 2 + * amount = -10 */ + set->m_curIndex = ((int32_t)set->m_curIndex + (int32_t)amount) % (int32_t)set->m_numColors; + if (set->m_curIndex > set->m_numColors) { /* must have wrapped */ + /* simply wrap it back */ + set->m_curIndex += set->m_numColors; + } +} + +rgb_color_t colorset_cur(const colorset_t *set) +{ + rgb_color_t result; + if (set->m_curIndex >= set->m_numColors) { + rgb_init3(&result, 0, 0, 0); + return result; + } + return set->m_palette[set->m_curIndex]; +} + +void colorset_set_cur_index(colorset_t *set, uint8_t index) +{ + if (!set->m_numColors) { + return; + } + if (index > (set->m_numColors - 1)) { + return; + } + set->m_curIndex = index; +} + +void colorset_reset_index(colorset_t *set) +{ + set->m_curIndex = INDEX_INVALID; +} + +uint8_t colorset_cur_index(const colorset_t *set) +{ + return set->m_curIndex; +} + +rgb_color_t colorset_get_prev(colorset_t *set) +{ + rgb_color_t result; + if (!set->m_numColors) { + rgb_init_from_raw(&result, RGB_OFF); + return result; + } + /* handle wrapping at 0 */ + if (set->m_curIndex == 0 || set->m_curIndex == INDEX_INVALID) { + set->m_curIndex = colorset_num_colors(set) - 1; + } else { + set->m_curIndex--; + } + /* return the color */ + return set->m_palette[set->m_curIndex]; +} + +rgb_color_t colorset_get_next(colorset_t *set) +{ + rgb_color_t result; + if (!set->m_numColors) { + rgb_init_from_raw(&result, RGB_OFF); + return result; + } + /* iterate current index, let it wrap at max uint8 */ + set->m_curIndex++; + /* then modulate the result within max colors */ + set->m_curIndex %= colorset_num_colors(set); + /* return the color */ + return set->m_palette[set->m_curIndex]; +} + +rgb_color_t colorset_peek(const colorset_t *set, int32_t offset) +{ + rgb_color_t result; + if (!set->m_numColors) { + rgb_init_from_raw(&result, RGB_OFF); + return result; + } + uint8_t nextIndex = 0; + /* get index of the next color */ + if (offset >= 0) { + nextIndex = (set->m_curIndex + offset) % colorset_num_colors(set); + } else { + if (offset < -1 * (int32_t)(colorset_num_colors(set))) { + rgb_init_from_raw(&result, RGB_OFF); + return result; + } + nextIndex = ((set->m_curIndex + colorset_num_colors(set)) + (int)offset) % colorset_num_colors(set); + } + /* return the color */ + return set->m_palette[nextIndex]; +} + +rgb_color_t colorset_peek_next(const colorset_t *set) +{ + return colorset_peek(set, 1); +} + +uint8_t colorset_num_colors(const colorset_t *set) +{ + return set->m_numColors; +} + +uint8_t colorset_on_start(const colorset_t *set) +{ + return (set->m_curIndex == 0); +} + +uint8_t colorset_on_end(const colorset_t *set) +{ + if (!set->m_numColors) { + return 0; + } + return (set->m_curIndex == set->m_numColors - 1); +} + diff --git a/Helios/Colorset.cpp b/Helios/Colorset.cpp deleted file mode 100644 index c3d1d6a9..00000000 --- a/Helios/Colorset.cpp +++ /dev/null @@ -1,365 +0,0 @@ -#include "Colorset.h" - -#include "Random.h" - -#include - -// when no color is selected in the colorset the index is this -// then when you call getNext() for the first time it returns -// the 0th color in the colorset and after the index will be 0 -#define INDEX_INVALID 255 - -Colorset::Colorset() : - m_palette(), - m_numColors(0), - m_curIndex(INDEX_INVALID) -{ - init(); -} - -Colorset::Colorset(RGBColor c1, RGBColor c2, RGBColor c3, RGBColor c4, - RGBColor c5, RGBColor c6, RGBColor c7, RGBColor c8) : - Colorset() -{ - init(c1, c2, c3, c4, c5, c6, c7, c8); -} - -Colorset::Colorset(uint8_t numCols, const uint32_t *cols) : - Colorset() -{ - if (numCols > NUM_COLOR_SLOTS) { - numCols = NUM_COLOR_SLOTS; - } - for (uint8_t i = 0; i < numCols; ++i) { - addColor(RGBColor(cols[i])); - } -} - -Colorset::Colorset(const Colorset &other) : - Colorset() -{ - // invoke = operator - *this = other; -} - -Colorset::~Colorset() -{ - clear(); -} - -bool Colorset::operator==(const Colorset &other) const -{ - // only compare the palettes for equality - return (m_numColors == other.m_numColors) && - (memcmp(m_palette, other.m_palette, m_numColors * sizeof(RGBColor)) == 0); -} - -bool Colorset::operator!=(const Colorset &other) const -{ - return !operator==(other); -} - -void Colorset::init(RGBColor c1, RGBColor c2, RGBColor c3, RGBColor c4, - RGBColor c5, RGBColor c6, RGBColor c7, RGBColor c8) -{ - // clear any existing colors - clear(); - // would be nice if we could do this another way - if (!c1.empty()) addColor(c1); - if (!c2.empty()) addColor(c2); - if (!c3.empty()) addColor(c3); - if (!c4.empty()) addColor(c4); - if (!c5.empty()) addColor(c5); - if (!c6.empty()) addColor(c6); - if (!c7.empty()) addColor(c7); - if (!c8.empty()) addColor(c8); -} - -void Colorset::clear() -{ - memset((void *)m_palette, 0, sizeof(m_palette)); - m_numColors = 0; - resetIndex(); -} - -bool Colorset::equals(const Colorset &set) const -{ - return operator==(set); -} - -bool Colorset::equals(const Colorset *set) const -{ - if (!set) { - return false; - } - return operator==(*set); -} - -// crc the colorset -uint32_t Colorset::crc32() const -{ - uint32_t hash = 5381; - for (uint8_t i = 0; i < m_numColors; ++i) { - hash = ((hash << 5) + hash) + m_palette[i].raw(); - } - return hash; -} - -RGBColor Colorset::operator[](int index) const -{ - return get(index); -} - -// add a single color -bool Colorset::addColor(RGBColor col) -{ - if (m_numColors >= NUM_COLOR_SLOTS) { - return false; - } - // insert new color and increment number of colors - m_palette[m_numColors] = col; - m_numColors++; - return true; -} - -bool Colorset::addColorHSV(uint8_t hue, uint8_t sat, uint8_t val) -{ - return addColor(HSVColor(hue, sat, val)); -} - -void Colorset::addColorWithValueStyle(Random &ctx, uint8_t hue, uint8_t sat, ValueStyle valStyle, uint8_t numColors, uint8_t colorPos) -{ - if (numColors == 1) { - addColorHSV(hue, sat, ctx.next8(16, 255)); - return; - } - switch (valStyle) { - default: - case VAL_STYLE_RANDOM: - addColorHSV(hue, sat, 85 * ctx.next8(1, 4)); - break; - case VAL_STYLE_LOW_FIRST_COLOR: - if (m_numColors == 0) { - addColorHSV(hue, sat, ctx.next8(0, 86)); - } else { - addColorHSV(hue, sat, 85 * ctx.next8(1, 4)); - } - break; - case VAL_STYLE_HIGH_FIRST_COLOR: - if (m_numColors == 0) { - addColorHSV(hue, sat, 255); - } else { - addColorHSV(hue, sat, ctx.next8(0, 86)); - } - break; - case VAL_STYLE_ALTERNATING: - if (m_numColors % 2 == 0) { - addColorHSV(hue, sat, 255); - } else { - addColorHSV(hue, sat, 85); - } - break; - case VAL_STYLE_ASCENDING: - addColorHSV(hue, sat, (colorPos + 1) * (255 / numColors)); - break; - case VAL_STYLE_DESCENDING: - addColorHSV(hue, sat, 255 - (colorPos * (255 / numColors))); - break; - case VAL_STYLE_CONSTANT: - addColorHSV(hue, sat, 255); - } -} - -void Colorset::removeColor(uint8_t index) -{ - if (index >= m_numColors) { - return; - } - for (uint8_t i = index; i < (m_numColors - 1); ++i) { - m_palette[i] = m_palette[i + 1]; - } - m_palette[--m_numColors].clear(); -} - -void Colorset::randomizeColors(Random &ctx, uint8_t numColors, ColorMode mode) -{ - // if they specify randomly pick the color mode then roll it - if (mode >= COLOR_MODE_RANDOMLY_PICK) { - mode = (ColorMode)(ctx.next8() % COLOR_MODE_COUNT); - } - clear(); - if (!numColors) { - numColors = ctx.next8(mode == COLOR_MODE_MONOCHROMATIC ? 2 : 1, 9); - } - uint8_t randomizedHue = ctx.next8(); - uint8_t colorGap = 0; - if (mode == COLOR_MODE_COLOR_THEORY && numColors > 1) { - colorGap = ctx.next8(16, 256 / (numColors - 1)); - } - ValueStyle valStyle = (ValueStyle)ctx.next8(0, VAL_STYLE_COUNT); - // the doubleStyle decides if some colors are added to the set twice - uint8_t doubleStyle = 0; - if (numColors <= 7) { - doubleStyle = (ctx.next8(0, 1)); - } - if (numColors <= 4) { - doubleStyle = (ctx.next8(0, 2)); - } - for (uint8_t i = 0; i < numColors; i++) { - uint8_t hueToUse; - uint8_t valueToUse = 255; - if (mode == COLOR_MODE_COLOR_THEORY) { - hueToUse = (randomizedHue + (i * colorGap)); - } else if (mode == COLOR_MODE_MONOCHROMATIC) { - hueToUse = randomizedHue; - valueToUse = 255 - (i * (256 / numColors)); - } else { // EVENLY_SPACED - hueToUse = (randomizedHue + (256 / numColors) * i); - } - addColorWithValueStyle(ctx, hueToUse, valueToUse, valStyle, numColors, i); - // double all colors or only first color - if (doubleStyle == 2 || (doubleStyle == 1 && !i)) { - addColorWithValueStyle(ctx, hueToUse, valueToUse, valStyle, numColors, i); - } - } -} - -void Colorset::adjustBrightness(uint8_t fadeby) -{ - for (uint8_t i = 0; i < m_numColors; ++i) { - m_palette[i].adjustBrightness(fadeby); - } -} - -// get a color from the colorset -RGBColor Colorset::get(uint8_t index) const -{ - if (index >= m_numColors) { - return RGBColor(0, 0, 0); - } - return m_palette[index]; -} - -// set an rgb color in a slot, or add a new color if you specify -// a slot higher than the number of colors in the colorset -void Colorset::set(uint8_t index, RGBColor col) -{ - // special case for 'setting' a color at the edge of the palette, - // ie adding a new color when you set an index higher than the max - if (index >= m_numColors) { - if (!addColor(col)) { - //ERROR_LOGF("Failed to add new color at index %u", index); - } - return; - } - m_palette[index] = col; -} - -// skip some amount of colors -void Colorset::skip(int32_t amount) -{ - if (!m_numColors) { - return; - } - // if the colorset hasn't started yet - if (m_curIndex == INDEX_INVALID) { - m_curIndex = 0; - } - - // first modulate the amount to skip to be within +/- the number of colors - amount %= (int32_t)m_numColors; - - // max = 3 - // m_curIndex = 2 - // amount = -10 - m_curIndex = ((int32_t)m_curIndex + (int32_t)amount) % (int32_t)m_numColors; - if (m_curIndex > m_numColors) { // must have wrapped - // simply wrap it back - m_curIndex += m_numColors; - } -} - -RGBColor Colorset::cur() -{ - if (m_curIndex >= m_numColors) { - return RGBColor(0, 0, 0); - } - return m_palette[m_curIndex]; -} - -void Colorset::setCurIndex(uint8_t index) -{ - if (!m_numColors) { - return; - } - if (index > (m_numColors - 1)) { - return; - } - m_curIndex = index; -} - -void Colorset::resetIndex() -{ - m_curIndex = INDEX_INVALID; -} - -RGBColor Colorset::getPrev() -{ - if (!m_numColors) { - return RGB_OFF; - } - // handle wrapping at 0 - if (m_curIndex == 0 || m_curIndex == INDEX_INVALID) { - m_curIndex = numColors() - 1; - } else { - m_curIndex--; - } - // return the color - return m_palette[m_curIndex]; -} - -RGBColor Colorset::getNext() -{ - if (!m_numColors) { - return RGB_OFF; - } - // iterate current index, let it wrap at max uint8 - m_curIndex++; - // then modulate the result within max colors - m_curIndex %= numColors(); - // return the color - return m_palette[m_curIndex]; -} - -// peek at the next color but don't iterate -RGBColor Colorset::peek(int32_t offset) const -{ - if (!m_numColors) { - return RGB_OFF; - } - uint8_t nextIndex = 0; - // get index of the next color - if (offset >= 0) { - nextIndex = (m_curIndex + offset) % numColors(); - } else { - if (offset < -1 * (int32_t)(numColors())) { - return RGB_OFF; - } - nextIndex = ((m_curIndex + numColors()) + (int)offset) % numColors(); - } - // return the color - return m_palette[nextIndex]; -} - -bool Colorset::onStart() const -{ - return (m_curIndex == 0); -} - -bool Colorset::onEnd() const -{ - if (!m_numColors) { - return false; - } - return (m_curIndex == m_numColors - 1); -} diff --git a/Helios/Colorset.h b/Helios/Colorset.h index 4c6aeafe..b8c2408a 100644 --- a/Helios/Colorset.h +++ b/Helios/Colorset.h @@ -5,139 +5,132 @@ #include "HeliosConfig.h" -class Random; +/* Forward declaration */ +typedef struct random_t random_t; +typedef struct colorset_t colorset_t; -class Colorset +enum colorset_value_style { -public: - // empty colorset - Colorset(); - // constructor for 1-8 color slots - Colorset(RGBColor c1, RGBColor c2 = RGB_OFF, RGBColor c3 = RGB_OFF, - RGBColor c4 = RGB_OFF, RGBColor c5 = RGB_OFF, RGBColor c6 = RGB_OFF, - RGBColor c7 = RGB_OFF, RGBColor c8 = RGB_OFF); - Colorset(uint8_t numCols, const uint32_t *cols); - ~Colorset(); - - // copy and assignment operators - Colorset(const Colorset &other); - - // equality operators - bool operator==(const Colorset &other) const; - bool operator!=(const Colorset &other) const; - - // initialize the colorset - void init(RGBColor c1 = RGB_OFF, RGBColor c2 = RGB_OFF, RGBColor c3 = RGB_OFF, - RGBColor c4 = RGB_OFF, RGBColor c5 = RGB_OFF, RGBColor c6 = RGB_OFF, - RGBColor c7 = RGB_OFF, RGBColor c8 = RGB_OFF); - - // clear the colorset - void clear(); - - // pointer comparison - bool equals(const Colorset &set) const; - bool equals(const Colorset *set) const; - - // crc the colorset - uint32_t crc32() const; - - // index operator to access color index - RGBColor operator[](int index) const; - - enum ValueStyle : uint8_t - { - // Random values - VAL_STYLE_RANDOM = 0, - // First color low value, the rest are random - VAL_STYLE_LOW_FIRST_COLOR, - // First color high value, the rest are low - VAL_STYLE_HIGH_FIRST_COLOR, - // Alternat between high and low value - VAL_STYLE_ALTERNATING, - // Ascending values from low to high - VAL_STYLE_ASCENDING, - // Descending values from high to low - VAL_STYLE_DESCENDING, - // Constant value - VAL_STYLE_CONSTANT, - // Total number of value styles - VAL_STYLE_COUNT - }; - - // add a single color - bool addColor(RGBColor col); - bool addColorHSV(uint8_t hue, uint8_t sat, uint8_t val); - void addColorWithValueStyle(Random &ctx, uint8_t hue, uint8_t sat, - ValueStyle valStyle, uint8_t numColors, uint8_t colorPos); - void removeColor(uint8_t index); - - // various modes of randomization types to use with randomizeColors - enum ColorMode { - // randomize with color theory - COLOR_MODE_COLOR_THEORY, - // randomize a nonochromatic set - COLOR_MODE_MONOCHROMATIC, - // randomize an evenly spaced hue set - COLOR_MODE_EVENLY_SPACED, - - // total different randomize modes above - COLOR_MODE_COUNT, - - // EXTRA OPTION: randomly pick one of the other 3 options - COLOR_MODE_RANDOMLY_PICK = COLOR_MODE_COUNT, - }; - // function to randomize the colors with various different modes of randomization - void randomizeColors(Random &ctx, uint8_t numColors, ColorMode color_mode); - - // fade all of the colors in the set - void adjustBrightness(uint8_t fadeby); - - // get a color from the colorset - RGBColor get(uint8_t index = 0) const; - - // set an rgb color in a slot, or add a new color if you specify - // a slot higher than the number of colors in the colorset - void set(uint8_t index, RGBColor col); - - // skip some amount of colors - void skip(int32_t amount = 1); - - // get current color in cycle - RGBColor cur(); - - // set the current index of the colorset - void setCurIndex(uint8_t index); - void resetIndex(); - - // the current index - uint8_t curIndex() const { return m_curIndex; } - - // get the prev color in cycle - RGBColor getPrev(); - - // get the next color in cycle - RGBColor getNext(); - - // peek at the color indexes from current but don't iterate - RGBColor peek(int32_t offset) const; - - // better wording for peek 1 ahead - RGBColor peekNext() const { return peek(1); } - - // the number of colors in the palette - uint8_t numColors() const { return m_numColors; } - - // whether the colorset is currently on the first color or last color - bool onStart() const; - bool onEnd() const; -private: - // palette of colors - RGBColor m_palette[NUM_COLOR_SLOTS]; - // the actual number of colors in the set + /* Random values */ + VAL_STYLE_RANDOM = 0, + /* First color low value, the rest are random */ + VAL_STYLE_LOW_FIRST_COLOR, + /* First color high value, the rest are low */ + VAL_STYLE_HIGH_FIRST_COLOR, + /* Alternate between high and low value */ + VAL_STYLE_ALTERNATING, + /* Ascending values from low to high */ + VAL_STYLE_ASCENDING, + /* Descending values from high to low */ + VAL_STYLE_DESCENDING, + /* Constant value */ + VAL_STYLE_CONSTANT, + /* Total number of value styles */ + VAL_STYLE_COUNT +}; + +enum colorset_color_mode +{ + /* randomize with color theory */ + COLOR_MODE_COLOR_THEORY, + /* randomize a monochromatic set */ + COLOR_MODE_MONOCHROMATIC, + /* randomize an evenly spaced hue set */ + COLOR_MODE_EVENLY_SPACED, + + /* total different randomize modes above */ + COLOR_MODE_COUNT, + + /* EXTRA OPTION: randomly pick one of the other 3 options */ + COLOR_MODE_RANDOMLY_PICK = COLOR_MODE_COUNT, +}; + +struct colorset_t +{ + /* palette of colors */ + rgb_color_t m_palette[NUM_COLOR_SLOTS]; + /* the actual number of colors in the set */ uint8_t m_numColors; - // the current index, starts at UINT8_MAX so that - // the very first call to getNext will iterate to 0 + /* the current index, starts at 255 so that + * the very first call to colorset_getNext will iterate to 0 */ uint8_t m_curIndex; }; +/* Empty colorset */ +void colorset_init(colorset_t *set); + +/* Initialize with up to 8 colors */ +void colorset_init_multi(colorset_t *set, rgb_color_t c1, rgb_color_t c2, rgb_color_t c3, + rgb_color_t c4, rgb_color_t c5, rgb_color_t c6, rgb_color_t c7, rgb_color_t c8); + +/* Initialize from array of colors */ +void colorset_init_array(colorset_t *set, uint8_t numCols, const uint32_t *cols); + +/* Copy colorset */ +void colorset_copy(colorset_t *dest, const colorset_t *src); + +/* Equality operators */ +uint8_t colorset_equals(const colorset_t *a, const colorset_t *b); + +/* Clear the colorset */ +void colorset_clear(colorset_t *set); + +/* CRC the colorset */ +uint32_t colorset_crc32(const colorset_t *set); + +/* Index operator to access color index */ +rgb_color_t colorset_get_at_index(const colorset_t *set, int index); + +/* Add a single color */ +uint8_t colorset_add_color(colorset_t *set, rgb_color_t col); +uint8_t colorset_add_color_hsv(colorset_t *set, uint8_t hue, uint8_t sat, uint8_t val); +void colorset_add_color_with_value_style(colorset_t *set, random_t *ctx, uint8_t hue, uint8_t sat, + enum colorset_value_style valStyle, uint8_t numColors, uint8_t colorPos); +void colorset_remove_color(colorset_t *set, uint8_t index); + +/* Function to randomize the colors with various different modes of randomization */ +void colorset_randomize_colors(colorset_t *set, random_t *ctx, uint8_t numColors, enum colorset_color_mode color_mode); + +/* Fade all of the colors in the set */ +void colorset_adjust_brightness(colorset_t *set, uint8_t fadeby); + +/* Get a color from the colorset */ +rgb_color_t colorset_get(const colorset_t *set, uint8_t index); + +/* Set an rgb color in a slot, or add a new color if you specify + * a slot higher than the number of colors in the colorset */ +void colorset_set(colorset_t *set, uint8_t index, rgb_color_t col); + +/* Skip some amount of colors */ +void colorset_skip(colorset_t *set, int32_t amount); + +/* Get current color in cycle */ +rgb_color_t colorset_cur(const colorset_t *set); + +/* Set the current index of the colorset */ +void colorset_set_cur_index(colorset_t *set, uint8_t index); +void colorset_reset_index(colorset_t *set); + +/* The current index */ +uint8_t colorset_cur_index(const colorset_t *set); + +/* Get the prev color in cycle */ +rgb_color_t colorset_get_prev(colorset_t *set); + +/* Get the next color in cycle */ +rgb_color_t colorset_get_next(colorset_t *set); + +/* Peek at the color indexes from current but don't iterate */ +rgb_color_t colorset_peek(const colorset_t *set, int32_t offset); + +/* Better wording for peek 1 ahead */ +rgb_color_t colorset_peek_next(const colorset_t *set); + +/* The number of colors in the palette */ +uint8_t colorset_num_colors(const colorset_t *set); + +/* Whether the colorset is currently on the first color or last color */ +uint8_t colorset_on_start(const colorset_t *set); +uint8_t colorset_on_end(const colorset_t *set); + #endif diff --git a/Helios/Colortypes.c b/Helios/Colortypes.c new file mode 100644 index 00000000..be745d7f --- /dev/null +++ b/Helios/Colortypes.c @@ -0,0 +1,453 @@ +#include "Colortypes.h" + +#if ALTERNATIVE_HSV_RGB == 1 +/* global hsv to rgb algorithm selector */ +enum hsv_to_rgb_algorithm g_hsv_rgb_alg = HSV_TO_RGB_GENERIC; +#endif + +/* ========== HSVColor functions ========== */ + +void hsv_init(hsv_color_t *hsv) +{ + hsv->hue = 0; + hsv->sat = 0; + hsv->val = 0; +} + +void hsv_init3(hsv_color_t *hsv, uint8_t hue, uint8_t sat, uint8_t val) +{ + hsv->hue = hue; + hsv->sat = sat; + hsv->val = val; +} + +void hsv_init_from_raw(hsv_color_t *hsv, uint32_t dwVal) +{ + hsv_init(hsv); + hsv_assign_from_raw(hsv, dwVal); +} + +void hsv_init_from_rgb(hsv_color_t *hsv, const rgb_color_t *rgb) +{ + hsv_assign_from_rgb(hsv, rgb); +} + +void hsv_copy(hsv_color_t *dest, const hsv_color_t *src) +{ + dest->hue = src->hue; + dest->sat = src->sat; + dest->val = src->val; +} + +void hsv_assign_from_raw(hsv_color_t *hsv, uint32_t rhs) +{ + hsv->hue = ((rhs >> 16) & 0xFF); + hsv->sat = ((rhs >> 8) & 0xFF); + hsv->val = (rhs & 0xFF); +} + +void hsv_assign_from_rgb(hsv_color_t *hsv, const rgb_color_t *rhs) +{ + /* always use generic */ + hsv_color_t temp = rgb_to_hsv_generic(rhs); + hsv_copy(hsv, &temp); +} + +uint8_t hsv_equals(const hsv_color_t *a, const hsv_color_t *b) +{ + return (hsv_raw(b) == hsv_raw(a)); +} + +uint8_t hsv_empty(const hsv_color_t *hsv) +{ + return !hsv->hue && !hsv->sat && !hsv->val; +} + +void hsv_clear(hsv_color_t *hsv) +{ + hsv->hue = 0; + hsv->sat = 0; + hsv->val = 0; +} + +uint32_t hsv_raw(const hsv_color_t *hsv) +{ + return ((uint32_t)hsv->hue << 16) | ((uint32_t)hsv->sat << 8) | (uint32_t)hsv->val; +} + +/* ========== RGBColor functions ========== */ + +void rgb_init(rgb_color_t *rgb) +{ + rgb->red = 0; + rgb->green = 0; + rgb->blue = 0; +} + +void rgb_init3(rgb_color_t *rgb, uint8_t red, uint8_t green, uint8_t blue) +{ + rgb->red = red; + rgb->green = green; + rgb->blue = blue; +} + +void rgb_init_from_raw(rgb_color_t *rgb, uint32_t dwVal) +{ + rgb_init(rgb); + rgb_assign_from_raw(rgb, dwVal); +} + +void rgb_init_from_hsv(rgb_color_t *rgb, const hsv_color_t *hsv) +{ + rgb_assign_from_hsv(rgb, hsv); +} + +void rgb_copy(rgb_color_t *dest, const rgb_color_t *src) +{ + dest->red = src->red; + dest->green = src->green; + dest->blue = src->blue; +} + +void rgb_assign_from_raw(rgb_color_t *rgb, uint32_t rhs) +{ + rgb->red = ((rhs >> 16) & 0xFF); + rgb->green = ((rhs >> 8) & 0xFF); + rgb->blue = (rhs & 0xFF); +} + +void rgb_assign_from_hsv(rgb_color_t *rgb, const hsv_color_t *rhs) +{ +#if ALTERNATIVE_HSV_RGB == 1 + rgb_color_t temp; + switch (g_hsv_rgb_alg) { + case HSV_TO_RGB_RAINBOW: + temp = hsv_to_rgb_rainbow(rhs); + break; + case HSV_TO_RGB_GENERIC: + temp = hsv_to_rgb_generic(rhs); + break; + } + rgb_copy(rgb, &temp); +#else + rgb_color_t temp = hsv_to_rgb_generic(rhs); + rgb_copy(rgb, &temp); +#endif +} + +uint8_t rgb_equals(const rgb_color_t *a, const rgb_color_t *b) +{ + return (rgb_raw(b) == rgb_raw(a)); +} + +uint8_t rgb_empty(const rgb_color_t *rgb) +{ + return !rgb->red && !rgb->green && !rgb->blue; +} + +void rgb_clear(rgb_color_t *rgb) +{ + rgb->red = 0; + rgb->green = 0; + rgb->blue = 0; +} + +/* scale down the brightness of a color by some fade amount */ +void rgb_adjust_brightness(rgb_color_t *rgb, uint8_t fadeBy) +{ + rgb->red = (((int)rgb->red) * (int)(256 - fadeBy)) >> 8; + rgb->green = (((int)rgb->green) * (int)(256 - fadeBy)) >> 8; + rgb->blue = (((int)rgb->blue) * (int)(256 - fadeBy)) >> 8; +} + +uint32_t rgb_raw(const rgb_color_t *rgb) +{ + return ((uint32_t)rgb->red << 16) | ((uint32_t)rgb->green << 8) | (uint32_t)rgb->blue; +} + +#ifdef HELIOS_CLI +/* Adjust brightness to ensure visibility on screens, without floating-point arithmetic */ +void rgb_bring_up_brightness(rgb_color_t *rgb, uint8_t min_brightness) +{ + hsv_color_t col; + hsv_init_from_rgb(&col, rgb); + if (col.val == 0) { + rgb_assign_from_hsv(rgb, &col); + return; + } + if (col.val < min_brightness) { + col.val = min_brightness; + } + rgb_assign_from_hsv(rgb, &col); +} + +/* scale a uint8 by a float value, don't use this on embedded! */ +#define FSCALE8(x, scale) (uint8_t)(((float)x * scale) > 255 ? 255 : ((float)x * scale)) + +/* return a scaled up the brightness version of the current color */ +void rgb_scale_brightness(rgb_color_t *rgb, float scale) +{ + rgb->red = FSCALE8(rgb->red, scale); + rgb->green = FSCALE8(rgb->green, scale); + rgb->blue = FSCALE8(rgb->blue, scale); +} +#endif + +/* ======================================================== + * Below are various functions for converting hsv <-> rgb */ + +#if ALTERNATIVE_HSV_RGB == 1 +#define SCALE8(i, scale) (((uint16_t)i * (uint16_t)(scale)) >> 8) +#define FIXFRAC8(N,D) (((N)*256)/(D)) + +/* Stolen from FastLED hsv to rgb full rainbow where all colours + * are given equal weight, this makes for-example yellow larger + * best to use this function as it is the legacy choice */ +rgb_color_t hsv_to_rgb_rainbow(const hsv_color_t *rhs) +{ + rgb_color_t col; + /* Yellow has a higher inherent brightness than + * any other color; 'pure' yellow is perceived to + * be 93% as bright as white. In order to make + * yellow appear the correct relative brightness, + * it has to be rendered brighter than all other + * colors. + * Level Y1 is a moderate boost, the default. + * Level Y2 is a strong boost. */ + const uint8_t Y1 = 1; + const uint8_t Y2 = 0; + + /* G2: Whether to divide all greens by two. + * Depends GREATLY on your particular LEDs */ + const uint8_t G2 = 0; + + /* Gscale: what to scale green down by. + * Depends GREATLY on your particular LEDs */ + const uint8_t Gscale = 185; + + uint8_t hue = rhs->hue; + uint8_t sat = rhs->sat; + uint8_t val = rhs->val; + + uint8_t offset = hue & 0x1F; /* 0..31 */ + + /* offset8 = offset * 8 */ + uint8_t offset8 = offset; + offset8 <<= 3; + + uint8_t third = SCALE8(offset8, (256 / 3)); /* max = 85 */ + uint8_t r, g, b; + if (!(hue & 0x80)) { + /* 0XX */ + if (!(hue & 0x40)) { + /* 00X */ + /* section 0-1 */ + if (!(hue & 0x20)) { + /* 000 */ + /* case 0: R -> O */ + r = 255 - third; + g = third; + b = 0; + } else { + /* 001 */ + /* case 1: O -> Y */ + if (Y1) { + r = 171; + g = 85 + third; + b = 0; + } + if (Y2) { + r = 170 + third; + /* uint8_t twothirds = (third << 1); */ + uint8_t twothirds = SCALE8(offset8, ((256 * 2) / 3)); /* max=170 */ + g = 85 + twothirds; + b = 0; + } + } + } else { + /* 01X */ + /* section 2-3 */ + if (!(hue & 0x20)) { + /* 010 */ + /* case 2: Y -> G */ + if (Y1) { + /* uint8_t twothirds = (third << 1); */ + uint8_t twothirds = SCALE8(offset8, ((256 * 2) / 3)); /* max=170 */ + r = 171 - twothirds; + g = 170 + third; + b = 0; + } + if (Y2) { + r = 255 - offset8; + g = 255; + b = 0; + } + } else { + /* 011 */ + /* case 3: G -> A */ + r = 0; + g = 255 - third; + b = third; + } + } + } else { + /* section 4-7 */ + /* 1XX */ + if (!(hue & 0x40)) { + /* 10X */ + if (!(hue & 0x20)) { + /* 100 */ + /* case 4: A -> B */ + r = 0; + /* uint8_t twothirds = (third << 1); */ + uint8_t twothirds = SCALE8(offset8, ((256 * 2) / 3)); /* max=170 */ + g = 171 - twothirds; /* 170? */ + b = 85 + twothirds; + } else { + /* 101 */ + /* case 5: B -> P */ + r = third; + g = 0; + b = 255 - third; + } + } else { + if (!(hue & 0x20)) { + /* 110 */ + /* case 6: P -- K */ + r = 85 + third; + g = 0; + b = 171 - third; + } else { + /* 111 */ + /* case 7: K -> R */ + r = 170 + third; + g = 0; + b = 85 - third; + } + } + } + + /* This is one of the good places to scale the green down, + * although the client can scale green down as well. */ + if (G2) g = g >> 1; + if (Gscale) g = SCALE8(g, Gscale); + + /* Scale down colors if we're desaturated at all + * and add the brightness_floor to r, g, and b. */ + if (sat != 255) { + if (sat == 0) { + r = 255; b = 255; g = 255; + } else { + if (r) r = SCALE8(r, sat) + 1; + if (g) g = SCALE8(g, sat) + 1; + if (b) b = SCALE8(b, sat) + 1; + + uint8_t desat = 255 - sat; + desat = SCALE8(desat, desat); + + uint8_t brightness_floor = desat; + r += brightness_floor; + g += brightness_floor; + b += brightness_floor; + } + } + + /* Now scale everything down if we're at value < 255. */ + if (val != 255) { + val = SCALE8(val, val); + if (val == 0) { + r = 0; g = 0; b = 0; + } else { + /* nSCALE8x3_video( r, g, b, val); */ + if (r) r = SCALE8(r, val) + 1; + if (g) g = SCALE8(g, val) + 1; + if (b) b = SCALE8(b, val) + 1; + } + } + + /* Here we have the old AVR "missing std X+n" problem again + * It turns out that fixing it winds up costing more than + * not fixing it. + * To paraphrase Dr Bronner, profile! profile! profile! */ + col.red = r; + col.green = g; + col.blue = b; + return col; +} +#endif + +/* generic hsv to rgb conversion nothing special */ +rgb_color_t hsv_to_rgb_generic(const hsv_color_t *rhs) +{ + unsigned char region, remainder, p, q, t; + rgb_color_t col; + + if (rhs->sat == 0) { + col.red = rhs->val; + col.green = rhs->val; + col.blue = rhs->val; + return col; + } + + region = rhs->hue / 43; + remainder = ((rhs->hue - (region * 43)) * 6); + + /* extraneous casts to uint16_t are to prevent overflow */ + p = (uint8_t)(((uint16_t)(rhs->val) * (255 - rhs->sat)) >> 8); + q = (uint8_t)(((uint16_t)(rhs->val) * (255 - (((uint16_t)(rhs->sat) * remainder) >> 8))) >> 8); + t = (uint8_t)(((uint16_t)(rhs->val) * (255 - (((uint16_t)(rhs->sat) * (255 - remainder)) >> 8))) >> 8); + + switch (region) { + case 0: + col.red = rhs->val; col.green = t; col.blue = p; + break; + case 1: + col.red = q; col.green = rhs->val; col.blue = p; + break; + case 2: + col.red = p; col.green = rhs->val; col.blue = t; + break; + case 3: + col.red = p; col.green = q; col.blue = rhs->val; + break; + case 4: + col.red = t; col.green = p; col.blue = rhs->val; + break; + default: + col.red = rhs->val; col.green = p; col.blue = q; + break; + } + return col; +} + +/* Convert rgb to hsv with generic fast method */ +hsv_color_t rgb_to_hsv_generic(const rgb_color_t *rhs) +{ + unsigned char rgbMin, rgbMax; + rgbMin = rhs->red < rhs->green ? (rhs->red < rhs->blue ? rhs->red : rhs->blue) : (rhs->green < rhs->blue ? rhs->green : rhs->blue); + rgbMax = rhs->red > rhs->green ? (rhs->red > rhs->blue ? rhs->red : rhs->blue) : (rhs->green > rhs->blue ? rhs->green : rhs->blue); + hsv_color_t hsv; + + hsv.val = rgbMax; + if (hsv.val == 0) { + hsv.hue = 0; + hsv.sat = 0; + return hsv; + } + + hsv.sat = 255 * (long)(rgbMax - rgbMin) / hsv.val; + if (hsv.sat == 0) { + hsv.hue = 0; + return hsv; + } + + if (rgbMax == rhs->red) { + hsv.hue = 0 + 43 * (rhs->green - rhs->blue) / (rgbMax - rgbMin); + } else if (rgbMax == rhs->green) { + hsv.hue = 85 + 43 * (rhs->blue - rhs->red) / (rgbMax - rgbMin); + } else { + hsv.hue = 171 + 43 * (rhs->red - rhs->green) / (rgbMax - rgbMin); + } + return hsv; +} + diff --git a/Helios/Colortypes.cpp b/Helios/Colortypes.cpp deleted file mode 100644 index 8039c446..00000000 --- a/Helios/Colortypes.cpp +++ /dev/null @@ -1,432 +0,0 @@ -#include "Colortypes.h" - -#if ALTERNATIVE_HSV_RGB == 1 -// global hsv to rgb algorithm selector -hsv_to_rgb_algorithm g_hsv_rgb_alg = HSV_TO_RGB_GENERIC; -#endif - -HSVColor::HSVColor() : - hue(0), - sat(0), - val(0) -{ -} - -HSVColor::HSVColor(uint8_t hue, uint8_t sat, uint8_t val) : - hue(hue), sat(sat), val(val) -{ -} - -HSVColor::HSVColor(uint32_t dwVal) : - HSVColor() -{ - *this = dwVal; -} - -// assignment from uint32_t -HSVColor &HSVColor::operator=(const uint32_t &rhs) -{ - hue = ((rhs >> 16) & 0xFF); - sat = ((rhs >> 8) & 0xFF); - val = (rhs & 0xFF); - return *this; -} - -// construction/assignment from RGB -HSVColor::HSVColor(const RGBColor &rhs) -{ - *this = rhs; -} - -HSVColor &HSVColor::operator=(const RGBColor &rhs) -{ - // always use generic - *this = rgb_to_hsv_generic(rhs); - return *this; -} - -bool HSVColor::operator==(const HSVColor &other) const -{ - return (other.raw() == raw()); -} - -bool HSVColor::operator!=(const HSVColor &other) const -{ - return (other.raw() != raw()); -} - -bool HSVColor::empty() const -{ - return !hue && !sat && !val; -} - -void HSVColor::clear() -{ - hue = 0; - sat = 0; - val = 0; -} - -// ========== -// RGBColor - -RGBColor::RGBColor() : - red(0), - green(0), - blue(0) -{ -} - -RGBColor::RGBColor(uint8_t red, uint8_t green, uint8_t blue) : - red(red), green(green), blue(blue) -{ -} - -RGBColor::RGBColor(uint32_t dwVal) : - RGBColor() -{ - *this = dwVal; -} - -// assignment from uint32_t -RGBColor &RGBColor::operator=(const uint32_t &rhs) -{ - red = ((rhs >> 16) & 0xFF); - green = ((rhs >> 8) & 0xFF); - blue = (rhs & 0xFF); - return *this; -} - -RGBColor::RGBColor(const HSVColor &rhs) -{ - *this = rhs; -} - -RGBColor &RGBColor::operator=(const HSVColor &rhs) -{ -#if ALTERNATIVE_HSV_RGB == 1 - switch (g_hsv_rgb_alg) { - case HSV_TO_RGB_RAINBOW: - *this = hsv_to_rgb_rainbow(rhs); - break; - case HSV_TO_RGB_GENERIC: - *this = hsv_to_rgb_generic(rhs); - break; - } -#else - *this = hsv_to_rgb_generic(rhs); -#endif - return *this; -} - -bool RGBColor::operator==(const RGBColor &other) const -{ - return (other.raw() == raw()); -} - -bool RGBColor::operator!=(const RGBColor &other) const -{ - return (other.raw() != raw()); -} - -bool RGBColor::empty() const -{ - return !red && !green && !blue; -} - -void RGBColor::clear() -{ - red = 0; - green = 0; - blue = 0; -} - -// scale down the brightness of a color by some fade amount -RGBColor RGBColor::adjustBrightness(uint8_t fadeBy) -{ - red = (((int)red) * (int)(256 - fadeBy)) >> 8; - green = (((int)green) * (int)(256 - fadeBy)) >> 8; - blue = (((int)blue) * (int)(256 - fadeBy)) >> 8; - return *this; -} - -#ifdef HELIOS_CLI -// Adjust brightness to ensure visibility on screens, without floating-point arithmetic and without using max function -RGBColor RGBColor::bringUpBrightness(uint8_t min_brightness) { - // Adjust each color component using FSCALE8 and ensure it doesn't drop below MIN_BRIGHTNESS - HSVColor col = *this; - if (col.val == 0) { - return col; - } - if (col.val < min_brightness) { - col.val = min_brightness; - } - return col; -} -// scale a uint8 by a float value, don't use this on embedded! -#define FSCALE8(x, scale) (uint8_t)(((float)x * scale) > 255 ? 255 : ((float)x * scale)) -// return a scaled up the brightness version of the current color -RGBColor RGBColor::scaleBrightness(float scale) -{ - // scale each color up by the given amount and return a new color - return RGBColor(FSCALE8(red, scale), FSCALE8(green, scale), FSCALE8(blue, scale)); -} -#endif -// ======================================================== -// Below are various functions for converting hsv <-> rgb - -#if ALTERNATIVE_HSV_RGB == 1 -#define SCALE8(i, scale) (((uint16_t)i * (uint16_t)(scale)) >> 8) -#define FIXFRAC8(N,D) (((N)*256)/(D)) - -// Stolen from FastLED hsv to rgb full rainbox where all colours -// are given equal weight, this makes for-example yellow larger -// best to use this function as it is the legacy choice -RGBColor hsv_to_rgb_rainbow(const HSVColor &rhs) -{ - RGBColor col; - // Yellow has a higher inherent brightness than - // any other color; 'pure' yellow is perceived to - // be 93% as bright as white. In order to make - // yellow appear the correct relative brightness, - // it has to be rendered brighter than all other - // colors. - // Level Y1 is a moderate boost, the default. - // Level Y2 is a strong boost. - const uint8_t Y1 = 1; - const uint8_t Y2 = 0; - - // G2: Whether to divide all greens by two. - // Depends GREATLY on your particular LEDs - const uint8_t G2 = 0; - - // Gscale: what to scale green down by. - // Depends GREATLY on your particular LEDs - const uint8_t Gscale = 185; - - - uint8_t hue = rhs.hue; - uint8_t sat = rhs.sat; - uint8_t val = rhs.val; - - uint8_t offset = hue & 0x1F; // 0..31 - - // offset8 = offset * 8 - uint8_t offset8 = offset; - offset8 <<= 3; - - uint8_t third = SCALE8(offset8, (256 / 3)); // max = 85 - uint8_t r, g, b; - if (!(hue & 0x80)) { - // 0XX - if (!(hue & 0x40)) { - // 00X - //section 0-1 - if (!(hue & 0x20)) { - // 000 - //case 0: // R -> O - r = 255 - third; - g = third; - b = 0; - } else { - // 001 - //case 1: // O -> Y - if (Y1) { - r = 171; - g = 85 + third; - b = 0; - } - if (Y2) { - r = 170 + third; - //uint8_t twothirds = (third << 1); - uint8_t twothirds = SCALE8(offset8, ((256 * 2) / 3)); // max=170 - g = 85 + twothirds; - b = 0; - } - } - } else { - //01X - // section 2-3 - if (!(hue & 0x20)) { - // 010 - //case 2: // Y -> G - if (Y1) { - //uint8_t twothirds = (third << 1); - uint8_t twothirds = SCALE8(offset8, ((256 * 2) / 3)); // max=170 - r = 171 - twothirds; - g = 170 + third; - b = 0; - } - if (Y2) { - r = 255 - offset8; - g = 255; - b = 0; - } - } else { - // 011 - // case 3: // G -> A - r = 0; - g = 255 - third; - b = third; - } - } - } else { - // section 4-7 - // 1XX - if (!(hue & 0x40)) { - // 10X - if (!(hue & 0x20)) { - // 100 - //case 4: // A -> B - r = 0; - //uint8_t twothirds = (third << 1); - uint8_t twothirds = SCALE8(offset8, ((256 * 2) / 3)); // max=170 - g = 171 - twothirds; //170? - b = 85 + twothirds; - } else { - // 101 - //case 5: // B -> P - r = third; - g = 0; - b = 255 - third; - } - } else { - if (!(hue & 0x20)) { - // 110 - //case 6: // P -- K - r = 85 + third; - g = 0; - b = 171 - third; - } else { - // 111 - //case 7: // K -> R - r = 170 + third; - g = 0; - b = 85 - third; - } - } - } - - // This is one of the good places to scale the green down, - // although the client can scale green down as well. - if (G2) g = g >> 1; - if (Gscale) g = SCALE8(g, Gscale); - - // Scale down colors if we're desaturated at all - // and add the brightness_floor to r, g, and b. - if (sat != 255) { - if (sat == 0) { - r = 255; b = 255; g = 255; - } else { - if (r) r = SCALE8(r, sat) + 1; - if (g) g = SCALE8(g, sat) + 1; - if (b) b = SCALE8(b, sat) + 1; - - uint8_t desat = 255 - sat; - desat = SCALE8(desat, desat); - - uint8_t brightness_floor = desat; - r += brightness_floor; - g += brightness_floor; - b += brightness_floor; - } - } - - // Now scale everything down if we're at value < 255. - if (val != 255) { - val = SCALE8(val, val); - if (val == 0) { - r = 0; g = 0; b = 0; - } else { - // nSCALE8x3_video( r, g, b, val); - if (r) r = SCALE8(r, val) + 1; - if (g) g = SCALE8(g, val) + 1; - if (b) b = SCALE8(b, val) + 1; - } - } - - // Here we have the old AVR "missing std X+n" problem again - // It turns out that fixing it winds up costing more than - // not fixing it. - // To paraphrase Dr Bronner, profile! profile! profile! - col.red = r; - col.green = g; - col.blue = b; - return col; -} -#endif - -// generic hsv to rgb conversion nothing special -RGBColor hsv_to_rgb_generic(const HSVColor &rhs) -{ - unsigned char region, remainder, p, q, t; - RGBColor col; - - if (rhs.sat == 0) { - col.red = rhs.val; - col.green = rhs.val; - col.blue = rhs.val; - return col; - } - - region = rhs.hue / 43; - remainder = ((rhs.hue - (region * 43)) * 6); - - // extraneous casts to uint16_t are to prevent overflow - p = (uint8_t)(((uint16_t)(rhs.val) * (255 - rhs.sat)) >> 8); - q = (uint8_t)(((uint16_t)(rhs.val) * (255 - (((uint16_t)(rhs.sat) * remainder) >> 8))) >> 8); - t = (uint8_t)(((uint16_t)(rhs.val) * (255 - (((uint16_t)(rhs.sat) * (255 - remainder)) >> 8))) >> 8); - - switch (region) { - case 0: - col.red = rhs.val; col.green = t; col.blue = p; - break; - case 1: - col.red = q; col.green = rhs.val; col.blue = p; - break; - case 2: - col.red = p; col.green = rhs.val; col.blue = t; - break; - case 3: - col.red = p; col.green = q; col.blue = rhs.val; - break; - case 4: - col.red = t; col.green = p; col.blue = rhs.val; - break; - default: - col.red = rhs.val; col.green = p; col.blue = q; - break; - } - return col; -} - -// Convert rgb to hsv with generic fast method -HSVColor rgb_to_hsv_generic(const RGBColor &rhs) -{ - unsigned char rgbMin, rgbMax; - rgbMin = rhs.red < rhs.green ? (rhs.red < rhs.blue ? rhs.red : rhs.blue) : (rhs.green < rhs.blue ? rhs.green : rhs.blue); - rgbMax = rhs.red > rhs.green ? (rhs.red > rhs.blue ? rhs.red : rhs.blue) : (rhs.green > rhs.blue ? rhs.green : rhs.blue); - HSVColor hsv; - - hsv.val = rgbMax; - if (hsv.val == 0) { - hsv.hue = 0; - hsv.sat = 0; - return hsv; - } - - hsv.sat = 255 * (long)(rgbMax - rgbMin) / hsv.val; - if (hsv.sat == 0) { - hsv.hue = 0; - return hsv; - } - - if (rgbMax == rhs.red) { - hsv.hue = 0 + 43 * (rhs.green - rhs.blue) / (rgbMax - rgbMin); - } else if (rgbMax == rhs.green) { - hsv.hue = 85 + 43 * (rhs.blue - rhs.red) / (rgbMax - rgbMin); - } else { - hsv.hue = 171 + 43 * (rhs.red - rhs.green) / (rgbMax - rgbMin); - } - return hsv; -} diff --git a/Helios/Colortypes.h b/Helios/Colortypes.h index 2a579de7..a10d58ee 100644 --- a/Helios/Colortypes.h +++ b/Helios/Colortypes.h @@ -7,102 +7,79 @@ #include "ColorConstants.h" #if ALTERNATIVE_HSV_RGB == 1 -enum hsv_to_rgb_algorithm : uint8_t +enum hsv_to_rgb_algorithm { HSV_TO_RGB_GENERIC, HSV_TO_RGB_RAINBOW }; -// global hsv to rgb algorithm selector, switch this to control -// all hsv to rgb conversions -extern hsv_to_rgb_algorithm g_hsv_rgb_alg; +/* global hsv to rgb algorithm selector, switch this to control + * all hsv to rgb conversions */ +extern enum hsv_to_rgb_algorithm g_hsv_rgb_alg; #endif -class ByteStream; -class RGBColor; +/* Forward declarations */ +typedef struct hsv_color_t hsv_color_t; +typedef struct rgb_color_t rgb_color_t; -class HSVColor +struct hsv_color_t { -public: - HSVColor(); - HSVColor(uint8_t hue, uint8_t sat, uint8_t val); - - // assignment from uint32_t - HSVColor(uint32_t dwVal); - HSVColor &operator=(const uint32_t &rhs); - - // construction/assignment from RGB - HSVColor(const RGBColor &rhs); - HSVColor &operator=(const RGBColor &rhs); - - // equality operators - bool operator==(const HSVColor &other) const; - bool operator!=(const HSVColor &other) const; - - bool empty() const; - void clear(); - - uint32_t raw() const { return ((uint32_t)hue << 16) | ((uint32_t)sat << 8) | (uint32_t)val; } - - // public members uint8_t hue; uint8_t sat; uint8_t val; }; -class RGBColor +struct rgb_color_t { -public: - RGBColor(); - RGBColor(uint8_t red, uint8_t green, uint8_t blue); - - // assignment from uint32_t - RGBColor(uint32_t dwVal); - RGBColor &operator=(const uint32_t &rhs); - - RGBColor(const HSVColor &rhs); - RGBColor &operator=(const HSVColor &rhs); - - // equality operators - bool operator==(const RGBColor &other) const; - bool operator!=(const RGBColor &other) const; - - bool empty() const; - void clear(); - - // scale down the brightness of a color by some fade amount - RGBColor adjustBrightness(uint8_t fadeBy); - -#ifdef HELIOS_CLI - // return a scale brightness version of the current color, this uses - // a float value to scale the r/g/b values of the color - // ex: 0.0 = black - // 0.5 = half as bright - // 1.0 = no change - // 1.5 = 50% brighter - // 2.0 = twice as bright - // 255.0 = white - RGBColor scaleBrightness(float scale); - // bring up the brightness of a color to a minimum level - RGBColor bringUpBrightness(uint8_t min_brightness); -#endif - - uint32_t raw() const { return ((uint32_t)red << 16) | ((uint32_t)green << 8) | (uint32_t)blue; } - - // public members uint8_t red; uint8_t green; uint8_t blue; }; -// Stolen from FastLED hsv to rgb full rainbox where all colours -// are given equal weight, this makes for-example yellow larger -// best to use this function as it is the legacy choice -RGBColor hsv_to_rgb_rainbow(const HSVColor &rhs); -// generic hsv to rgb conversion nothing special -RGBColor hsv_to_rgb_generic(const HSVColor &rhs); +/* HSVColor functions */ +void hsv_init(hsv_color_t *hsv); +void hsv_init3(hsv_color_t *hsv, uint8_t hue, uint8_t sat, uint8_t val); +void hsv_init_from_raw(hsv_color_t *hsv, uint32_t dwVal); +void hsv_init_from_rgb(hsv_color_t *hsv, const rgb_color_t *rgb); +void hsv_copy(hsv_color_t *dest, const hsv_color_t *src); +void hsv_assign_from_raw(hsv_color_t *hsv, uint32_t rhs); +void hsv_assign_from_rgb(hsv_color_t *hsv, const rgb_color_t *rhs); +uint8_t hsv_equals(const hsv_color_t *a, const hsv_color_t *b); +uint8_t hsv_empty(const hsv_color_t *hsv); +void hsv_clear(hsv_color_t *hsv); +uint32_t hsv_raw(const hsv_color_t *hsv); + +/* RGBColor functions */ +void rgb_init(rgb_color_t *rgb); +void rgb_init3(rgb_color_t *rgb, uint8_t red, uint8_t green, uint8_t blue); +void rgb_init_from_raw(rgb_color_t *rgb, uint32_t dwVal); +void rgb_init_from_hsv(rgb_color_t *rgb, const hsv_color_t *hsv); +void rgb_copy(rgb_color_t *dest, const rgb_color_t *src); +void rgb_assign_from_raw(rgb_color_t *rgb, uint32_t rhs); +void rgb_assign_from_hsv(rgb_color_t *rgb, const hsv_color_t *rhs); +uint8_t rgb_equals(const rgb_color_t *a, const rgb_color_t *b); +uint8_t rgb_empty(const rgb_color_t *rgb); +void rgb_clear(rgb_color_t *rgb); +void rgb_adjust_brightness(rgb_color_t *rgb, uint8_t fadeBy); +uint32_t rgb_raw(const rgb_color_t *rgb); + +#ifdef HELIOS_CLI +/* Return a scaled brightness version of the current color + * ex: 0.0 = black, 0.5 = half brightness, 1.0 = no change, + * 1.5 = 50% brighter, 2.0 = twice as bright, 255.0 = white */ +void rgb_scale_brightness(rgb_color_t *rgb, float scale); +/* Bring up the brightness of a color to a minimum level */ +void rgb_bring_up_brightness(rgb_color_t *rgb, uint8_t min_brightness); +#endif -// Convert rgb to hsv with generic fast method -HSVColor rgb_to_hsv_generic(const RGBColor &rhs); +/* Conversion functions */ +/* Stolen from FastLED hsv to rgb full rainbow where all colours + * are given equal weight, this makes for-example yellow larger + * best to use this function as it is the legacy choice */ +rgb_color_t hsv_to_rgb_rainbow(const hsv_color_t *rhs); +/* Generic hsv to rgb conversion nothing special */ +rgb_color_t hsv_to_rgb_generic(const hsv_color_t *rhs); +/* Convert rgb to hsv with generic fast method */ +hsv_color_t rgb_to_hsv_generic(const rgb_color_t *rhs); #endif diff --git a/Helios/Helios.c b/Helios/Helios.c new file mode 100644 index 00000000..68e0d822 --- /dev/null +++ b/Helios/Helios.c @@ -0,0 +1,694 @@ +#include + +#include "Helios.h" + +#include "ColorConstants.h" +#include "TimeControl.h" +#include "Storage.h" +#include "Pattern.h" +#include "Patterns.h" +#include "Random.h" +#include "Button.h" +#include "Led.h" + +#ifdef HELIOS_EMBEDDED +#include +#include +#include +#endif + +#ifdef HELIOS_CLI +#include +#endif + +#include + +/* some internal macros that shouldn't change */ +/* The number of menus in hue/sat/val selection */ +#define NUM_COLORS_PER_GROUP 4 +/* the number of color groups in the color selection menu */ +#define NUM_COLOR_GROUPS 4 +/* the number of menus in group selection */ +#define NUM_MENUS_GROUP 8 + +/* Forward declarations for internal functions */ +static uint8_t helios_init_components(void); +static void helios_handle_state(void); +static void helios_handle_state_modes(void); +static void helios_handle_off_menu(uint8_t mag, uint8_t past); +static void helios_handle_on_menu(uint8_t mag, uint8_t past); +static void helios_handle_state_color_selection(void); +static void helios_handle_state_color_group_selection(void); +static void helios_handle_state_color_variant_selection(void); +static void helios_handle_state_pat_select(void); +static void helios_handle_state_toggle_flag(enum helios_flags flag); +static void helios_handle_state_set_defaults(void); +static void helios_show_selection(rgb_color_t color); +static void helios_factory_reset(void); + +/* the slot selection returns this info for internal menu logic */ +enum helios_color_select_option { + OPTION_NONE = 0, + + SELECTED_ADD, + SELECTED_EXIT, + SELECTED_SLOT +}; + +enum helios_state { + STATE_MODES, + STATE_COLOR_GROUP_SELECTION, + STATE_COLOR_VARIANT_SELECTION, + STATE_PATTERN_SELECT, + STATE_TOGGLE_LOCK, + STATE_SET_DEFAULTS, +#ifdef HELIOS_CLI + STATE_SLEEP, +#endif +}; + +/* static members */ +static enum helios_state cur_state; +static enum helios_flags global_flags; +static uint8_t menu_selection; +static uint8_t cur_mode; +static uint8_t selected_base_group; +static uint8_t num_colors_selected; /* Track number of colors selected in current session */ +static pattern_t pat; +static uint8_t keepgoing; +static uint32_t last_mode_switch_time; +static colorset_t new_colorset; + +#ifdef HELIOS_CLI +static uint8_t sleeping; /* Only used in CLI mode */ +#endif + +volatile char helios_version[] = HELIOS_VERSION_STR; + +uint8_t helios_init(void) +{ + /* first initialize all the components of helios */ + if (!helios_init_components()) { + return 0; + } + /* then initialize the hardware for embedded helios */ +#ifdef HELIOS_EMBEDDED + /* Set PB0, PB1, PB4 as output */ + DDRB |= (1 << DDB0) | (1 << DDB1) | (1 << DDB4); + /* Timer0 Configuration for PWM */ + TCCR0A = (1 << WGM01) | (1 << WGM00) | (1 << COM0A1) | (1 << COM0B1); + /* No prescaler */ + TCCR0B = (1 << CS00); + /* Timer1 for PWM on PB4, Fast PWM, Non-inverting, No prescaler */ + TCCR1 = (1 << PWM1A) | (1 << COM1A1) | (1 << CS10); + /* Enable PWM on OC1B */ + GTCCR = (1 << PWM1B) | (1 << COM1B1); + /* Enable Timer0 overflow interrupt */ + TIMSK |= (1 << TOIE0); + /* Enable interrupts */ + sei(); +#endif + return 1; +} + +static uint8_t helios_init_components(void) +{ + /* initialize various components of Helios */ + if (!Time_init()) { + return 0; + } + if (!led_init()) { + return 0; + } + if (!storage_init()) { + return 0; + } + if (!button_init()) { + return 0; + } + /* initialize global variables */ + cur_state = STATE_MODES; + menu_selection = 0; + cur_mode = 0; + num_colors_selected = 0; + selected_base_group = 0; + keepgoing = 1; + last_mode_switch_time = 0; +#ifdef HELIOS_CLI + sleeping = 0; +#endif + helios_load_global_flags(); + helios_load_cur_mode(); + return 1; +} + +void helios_tick(void) +{ + /* sample the button and re-calculate all button globals + * the button globals should not change anywhere else */ + button_update(); + + /* handle the current state of the system, ie whatever state + * we're in we check for the appropriate input events for that + * state by checking button globals, then run the appropriate logic */ + helios_handle_state(); + + /* Update the Leds once per frame */ + led_update(); + + /* finally tick the clock forward and then sleep till the entire + * tick duration has been consumed */ + Time_tickClock(); +} + +void helios_enter_sleep(void) +{ +#ifdef HELIOS_EMBEDDED + /* clear the led colors */ + led_clear(); + /* Set all pins to input */ + DDRB = 0x00; + /* Disable pull-ups on all pins */ + PORTB = 0x00; + /* Enable wake on interrupt for the button */ + button_enable_wake(); + /* Set sleep mode to POWER DOWN mode */ + set_sleep_mode(SLEEP_MODE_PWR_DOWN); + /* enter sleep */ + sleep_mode(); + /* ... interrupt will make us wake here */ + + /* Set PB0, PB1, PB4 as output */ + DDRB |= (1 << DDB0) | (1 << DDB1) | (1 << DDB4); + /* wakeup here, re-init */ + helios_init_components(); +#else + cur_state = STATE_SLEEP; + /* enable the sleep bool */ + sleeping = 1; +#endif +} + +void helios_wakeup(void) +{ +#ifdef HELIOS_EMBEDDED + /* nothing needed here, this interrupt firing will make the mainthread resume */ +#else + /* if the button was held down then they are entering off-menus + * but if we re-initialize the button it will clear this state */ + uint8_t pressed = button_is_pressed(); + /* re-initialize some stuff */ + Time_init(); + button_init(); + /* so just re-press it */ + if (pressed) { + button_do_press(); + } + cur_state = STATE_MODES; + /* turn off the sleeping flag that only CLI has */ + sleeping = 0; +#endif +} + +void helios_load_next_mode(void) +{ + /* increment current mode and wrap around */ + cur_mode = (uint8_t)(cur_mode + 1) % NUM_MODE_SLOTS; + /* now load current mode again */ + helios_load_cur_mode(); +} + +void helios_load_cur_mode(void) +{ + /* read pattern from storage at cur mode index */ + if (!storage_read_pattern(cur_mode, &pat)) { + /* and just initialize default if it cannot be read */ + patterns_make_default(cur_mode, &pat); + /* try to write it out because storage was corrupt */ + storage_write_pattern(cur_mode, &pat); + } + /* then re-initialize the pattern */ + pattern_init_state(&pat); + /* Update the last mode switch time when loading a mode */ + last_mode_switch_time = Time_getCurtime(); +} + +void helios_save_cur_mode(void) +{ + storage_write_pattern(cur_mode, &pat); +} + +void helios_load_global_flags(void) +{ + /* read the global flags from index 0 config */ + global_flags = (enum helios_flags)storage_read_global_flags(); + cur_mode = storage_read_current_mode(); +} + +void helios_save_global_flags(void) +{ + storage_write_global_flags(global_flags); + storage_write_current_mode(cur_mode); +} + +void helios_set_mode_index(uint8_t mode_index) +{ + cur_mode = (uint8_t)mode_index % NUM_MODE_SLOTS; + /* now load current mode again */ + helios_load_cur_mode(); +} + +uint8_t helios_keep_going(void) +{ + return keepgoing; +} + +void helios_terminate(void) +{ + keepgoing = 0; +} + +void helios_set_flag(enum helios_flags flag) +{ + global_flags = (enum helios_flags)(global_flags | flag); +} + +uint8_t helios_has_flag(enum helios_flags flag) +{ + return (global_flags & flag) == flag; +} + +void helios_clear_flag(enum helios_flags flag) +{ + global_flags = (enum helios_flags)(global_flags & ~flag); +} + +void helios_toggle_flag(enum helios_flags flag) +{ + global_flags = (enum helios_flags)(global_flags ^ flag); +} + +#ifdef HELIOS_CLI +uint8_t helios_is_asleep(void) +{ + return sleeping; +} + +pattern_t *helios_cur_pattern(void) +{ + return &pat; +} +#endif + +static void helios_handle_state(void) +{ + /* check for the force sleep button hold regardless of which state we're in */ + if (button_hold_duration() > FORCE_SLEEP_TIME) { + /* when released the device will just sleep */ + if (button_on_release()) { + helios_enter_sleep(); + /* ALWAYS RETURN AFTER SLEEP! WE WILL WAKE HERE! */ + return; + } + /* but as long as it's held past the sleep time it just turns off the led */ + if (button_is_pressed()) { + led_clear(); + return; + } + } + /* otherwise just handle the state like normal */ + switch (cur_state) { + case STATE_MODES: + helios_handle_state_modes(); + break; + case STATE_COLOR_GROUP_SELECTION: + case STATE_COLOR_VARIANT_SELECTION: + helios_handle_state_color_selection(); + break; + case STATE_PATTERN_SELECT: + helios_handle_state_pat_select(); + break; + case STATE_TOGGLE_LOCK: + helios_handle_state_toggle_flag(FLAG_LOCKED); + break; + case STATE_SET_DEFAULTS: + helios_handle_state_set_defaults(); + break; +#ifdef HELIOS_CLI + case STATE_SLEEP: + /* simulate sleep in helios CLI */ + if (button_on_press() || button_on_short_click() || button_on_long_click()) { + helios_wakeup(); + } + break; +#endif + } +} + +static void helios_handle_state_modes(void) +{ + /* whether they have released the button since turning on */ + uint8_t hasReleased = (button_release_count() > 0); + + if (button_release_count() > 1 && button_on_short_click()) { + helios_enter_sleep(); + return; + } + + /* check for lock and go back to sleep */ + if (helios_has_flag(FLAG_LOCKED) && hasReleased && !button_on_release()) { + helios_enter_sleep(); + /* ALWAYS RETURN AFTER SLEEP! WE WILL WAKE HERE! */ + return; + } + + if (!helios_has_flag(FLAG_LOCKED) && hasReleased) { + /* just play the current mode */ + pattern_play(&pat); + } + /* check how long the button is held */ + uint32_t holdDur = button_hold_duration(); + /* calculate a magnitude which corresponds to how many times past the MENU_HOLD_TIME + * the user has held the button, so 0 means haven't held fully past one yet, etc */ + uint8_t magnitude = (uint8_t)(holdDur / MENU_HOLD_TIME); + /* whether the user has held the button longer than a short click */ + uint8_t heldPast = (holdDur > SHORT_CLICK_THRESHOLD); + + /* flash red briefly when locked and short clicked */ + if (helios_has_flag(FLAG_LOCKED) && holdDur < SHORT_CLICK_THRESHOLD) { + rgb_color_t red; + rgb_init_from_raw(&red, RGB_RED_BRI_LOW); + led_set_rgb(&red); + } + /* if the button is held for at least 1 second */ + if (button_is_pressed() && heldPast) { + rgb_color_t color; + /* if the button has been released before then show the on menu */ + if (hasReleased) { + switch (magnitude) { + default: + case 0: led_clear(); break; /* Turn off */ + case 1: rgb_init_from_raw(&color, RGB_TURQUOISE_BRI_LOW); led_set_rgb(&color); break; /* Color Selection */ + case 2: rgb_init_from_raw(&color, RGB_MAGENTA_BRI_LOW); led_set_rgb(&color); break; /* Pattern Selection */ + } + } else { + if (helios_has_flag(FLAG_LOCKED)) { + switch (magnitude) { + default: + case 0: led_clear(); break; + case TIME_TILL_GLOW_LOCK_UNLOCK: rgb_init_from_raw(&color, RGB_RED_BRI_LOW); led_set_rgb(&color); break; /* Exit */ + } + } else { + switch (magnitude) { + default: + case 0: led_clear(); break; /* nothing */ + case 1: rgb_init_from_raw(&color, RGB_RED_BRI_LOW); led_set_rgb(&color); break; /* Enter Glow Lock */ + case 2: rgb_init_from_raw(&color, RGB_BLUE_BRI_LOW); led_set_rgb(&color); break; /* Master Reset */ + } + } + } + } + /* if this isn't a release tick there's nothing more to do */ + if (button_on_release()) { + /* Resets the menu selection before entering new state */ + menu_selection = 0; + if (heldPast && button_release_count() == 1) { + helios_handle_off_menu(magnitude, heldPast); + return; + } + /* otherwise if we have released it then we are in the 'on' menu */ + helios_handle_on_menu(magnitude, heldPast); + } +} + +static void helios_handle_off_menu(uint8_t mag, uint8_t past) +{ + (void)past; /* unused */ + /* if still locked then handle the unlocking menu which is just if mag == 5 */ + if (helios_has_flag(FLAG_LOCKED)) { + switch (mag) { + case TIME_TILL_GLOW_LOCK_UNLOCK: /* red lock */ + cur_state = STATE_TOGGLE_LOCK; + break; + default: + /* just go back to sleep in hold-past off menu */ + helios_enter_sleep(); + /* ALWAYS RETURN AFTER SLEEP! WE WILL WAKE HERE! */ + } + /* in this case we return either way, since we're locked */ + return; + } + + /* otherwise if not locked handle the off menu */ + switch (mag) { + case 1: /* red lock */ + cur_state = STATE_TOGGLE_LOCK; + led_clear(); + return; /* RETURN HERE */ + case 2: /* blue reset defaults */ + cur_state = STATE_SET_DEFAULTS; + return; /* RETURN HERE */ + default: + /* just go back to sleep in hold-past off menu */ + helios_enter_sleep(); + /* ALWAYS RETURN AFTER SLEEP! WE WILL WAKE HERE! */ + return; + } +} + +static void helios_handle_on_menu(uint8_t mag, uint8_t past) +{ + switch (mag) { + case 0: /* off */ + /* but only if we held for more than a short click */ + if (past) { + helios_enter_sleep(); + /* ALWAYS RETURN AFTER SLEEP! WE WILL WAKE HERE! */ + return; + } + break; + case 1: /* color select */ + cur_state = STATE_COLOR_GROUP_SELECTION; + /* reset the menu selection and colors selected */ + menu_selection = 0; + num_colors_selected = 0; + /* Store original colorset before clearing */ + new_colorset = *pattern_colorset_ptr(&pat); + /* Clear existing colors in pattern */ + colorset_clear(&new_colorset); +#if ALTERNATIVE_HSV_RGB == 1 + /* use the nice hue to rgb rainbow */ + g_hsv_rgb_alg = HSV_TO_RGB_RAINBOW; +#endif + break; + case 2: /* pat select */ + cur_state = STATE_PATTERN_SELECT; + /* reset the menu selection */ + menu_selection = 0; + break; + default: /* hold past */ + break; + } +} + +struct colors_menu_data { + uint32_t colors[4]; +}; + +/* array of colors for selection */ +static const struct colors_menu_data color_menu_data[NUM_COLOR_GROUPS] = { + /* color0 color1 color2 color3 */ + /* =================================================================== */ + { {RGB_RED, RGB_CORAL_ORANGE, RGB_ORANGE, RGB_YELLOW} }, + { {RGB_LIME_GREEN, RGB_GREEN, RGB_SEAFOAM, RGB_TURQUOISE} }, + { {RGB_ICE_BLUE, RGB_LIGHT_BLUE, RGB_BLUE, RGB_ROYAL_BLUE} }, + { {RGB_PURPLE, RGB_PINK, RGB_HOT_PINK, RGB_MAGENTA} }, +}; + +static void helios_handle_state_color_selection(void) +{ + switch (cur_state) { + case STATE_COLOR_GROUP_SELECTION: + /* pick the hue group */ + helios_handle_state_color_group_selection(); + break; + case STATE_COLOR_VARIANT_SELECTION: + /* pick the hue */ + helios_handle_state_color_variant_selection(); + break; + default: + break; + } + /* get the current color */ + rgb_color_t cur = led_get(); + cur.red /= 2; + cur.green /= 2; + cur.blue /= 2; + /* show selection in all of these menus */ + helios_show_selection(cur); +} + +static void helios_handle_state_color_group_selection(void) +{ + rgb_color_t color; + + if (button_on_short_click()) { + menu_selection = (menu_selection + 1) % NUM_COLOR_GROUPS; + } + + /* Display a sample color from the selected group */ + rgb_init_from_raw(&color, color_menu_data[menu_selection].colors[0]); + led_set_rgb(&color); + + if (button_on_long_click()) { + selected_base_group = menu_selection; + cur_state = STATE_COLOR_VARIANT_SELECTION; + menu_selection = 0; + } +} + +static void helios_handle_state_color_variant_selection(void) +{ + rgb_color_t color; + + if (button_on_short_click()) { + /* If we've selected max colors, next click exits */ + if (num_colors_selected >= NUM_COLOR_SLOTS) { + /* Apply the newly built colorset */ + pattern_set_colorset(&pat, &new_colorset); + /* Save and return to normal mode */ + helios_save_cur_mode(); + cur_state = STATE_MODES; + menu_selection = 0; +#if ALTERNATIVE_HSV_RGB == 1 + g_hsv_rgb_alg = HSV_TO_RGB_GENERIC; +#endif + return; + } + + /* Cycle through colors in the group */ + menu_selection = (menu_selection + 1) % NUM_COLORS_PER_GROUP; + } + + /* Display the currently selected color */ + rgb_init_from_raw(&color, color_menu_data[selected_base_group].colors[menu_selection]); + led_set_rgb(&color); + + if (button_on_long_click()) { + /* Add the selected color to the colorset */ + rgb_init_from_raw(&color, color_menu_data[selected_base_group].colors[menu_selection]); + if (colorset_add_color(&new_colorset, color)) { + num_colors_selected++; + } + + /* If we've selected max colors, exit */ + if (num_colors_selected >= NUM_COLOR_SLOTS) { + /* Apply the newly built colorset */ + pattern_set_colorset(&pat, &new_colorset); + /* Save and return to normal mode */ + helios_save_cur_mode(); + cur_state = STATE_MODES; + menu_selection = 0; +#if ALTERNATIVE_HSV_RGB == 1 + g_hsv_rgb_alg = HSV_TO_RGB_GENERIC; +#endif + return; + } + + /* Otherwise go back to group selection for next color */ + cur_state = STATE_COLOR_GROUP_SELECTION; + menu_selection = 0; + } +} + +static void helios_handle_state_pat_select(void) +{ + rgb_color_t color; + + if (button_on_short_click()) { + menu_selection = (menu_selection + 1) % PATTERN_COUNT; + } + + /* show the menu selection */ + switch (menu_selection) { + case 0: rgb_init_from_raw(&color, RGB_RED); break; + case 1: rgb_init_from_raw(&color, RGB_GREEN); break; + case 2: rgb_init_from_raw(&color, RGB_BLUE); break; + case 3: rgb_init_from_raw(&color, RGB_YELLOW); break; + case 4: rgb_init_from_raw(&color, RGB_MAGENTA); break; + default: rgb_init_from_raw(&color, RGB_WHITE); break; + } + led_set_rgb(&color); + + if (button_on_long_click()) { + /* make the selected pattern */ + patterns_make_pattern((enum pattern_id)(PATTERN_FIRST + menu_selection), &pat); + /* reset the pattern to revert to on/off state */ + pattern_init_state(&pat); + /* save and return to normal mode */ + helios_save_cur_mode(); + cur_state = STATE_MODES; + menu_selection = 0; + } +} + +static void helios_handle_state_toggle_flag(enum helios_flags flag) +{ + rgb_color_t color; + + /* wait until button release then toggle the flag */ + if (button_on_release()) { + helios_toggle_flag(flag); + helios_save_global_flags(); + /* show feedback based on new state */ + if (helios_has_flag(flag)) { + rgb_init_from_raw(&color, RGB_GREEN); + } else { + rgb_init_from_raw(&color, RGB_RED); + } + led_hold(&color); + cur_state = STATE_MODES; + } +} + +static void helios_handle_state_set_defaults(void) +{ + rgb_color_t color; + + /* wait until button release then factory reset */ + if (button_on_release()) { + helios_factory_reset(); + /* show feedback */ + rgb_init_from_raw(&color, RGB_BLUE); + led_hold(&color); + cur_state = STATE_MODES; + } +} + +static void helios_show_selection(rgb_color_t color) +{ + uint32_t time_since_click = Time_getCurtime(); + if (button_press_time() > 0) { + time_since_click = Time_getCurtime() - button_press_time(); + } + /* flash the selection color briefly after clicking */ + if (time_since_click < 150) { + led_set_rgb(&color); + } +} + +static void helios_factory_reset(void) +{ + uint8_t slot; + /* write default patterns to all slots */ + for (slot = 0; slot < NUM_MODE_SLOTS; ++slot) { + patterns_make_default(slot, &pat); + storage_write_pattern(slot, &pat); + } + /* clear all flags */ + global_flags = FLAG_NONE; + helios_save_global_flags(); + /* reload current mode */ + helios_load_cur_mode(); +} + diff --git a/Helios/Helios.cpp b/Helios/Helios.cpp deleted file mode 100644 index c0dcc84b..00000000 --- a/Helios/Helios.cpp +++ /dev/null @@ -1,662 +0,0 @@ -#include - -#include "Helios.h" - -#include "ColorConstants.h" -#include "TimeControl.h" -#include "Storage.h" -#include "Pattern.h" -#include "Random.h" -#include "Button.h" -#include "Led.h" - -#ifdef HELIOS_EMBEDDED -#include -#include -#include -#endif - -#ifdef HELIOS_CLI -#include -#endif - -#include - -// some internal macros that shouldn't change -// The number of menus in hue/sat/val selection -#define NUM_COLORS_PER_GROUP 4 -// the number of color groups in the color selection menu -#define NUM_COLOR_GROUPS 4 -// the number of menus in group selection -#define NUM_MENUS_GROUP 8 - -Helios::State Helios::cur_state; -Helios::Flags Helios::global_flags; -uint8_t Helios::menu_selection; -uint8_t Helios::cur_mode; -uint8_t Helios::selected_base_group; -uint8_t Helios::num_colors_selected; -Pattern Helios::pat; -bool Helios::keepgoing; -uint32_t Helios::last_mode_switch_time; -Colorset Helios::new_colorset; - -#ifdef HELIOS_CLI -bool Helios::sleeping; -#endif - -volatile char helios_version[] = HELIOS_VERSION_STR; - -bool Helios::init() -{ - // first initialize all the components of helios - if (!init_components()) { - return false; - } - // then initialize the hardware for embedded helios -#ifdef HELIOS_EMBEDDED - // Set PB0, PB1, PB4 as output - DDRB |= (1 << DDB0) | (1 << DDB1) | (1 << DDB4); - // Timer0 Configuration for PWM - TCCR0A = (1 << WGM01) | (1 << WGM00) | (1 << COM0A1) | (1 << COM0B1); - // No prescaler - TCCR0B = (1 << CS00); - // Timer1 for PWM on PB4, Fast PWM, Non-inverting, No prescaler - TCCR1 = (1 << PWM1A) | (1 << COM1A1) | (1 << CS10); - // Enable PWM on OC1B - GTCCR = (1 << PWM1B) | (1 << COM1B1); - // Enable Timer0 overflow interrupt - TIMSK |= (1 << TOIE0); - // Enable interrupts - sei(); -#endif - return true; -} - -bool Helios::init_components() -{ - // initialize various components of Helios - if (!Time::init()) { - return false; - } - if (!Led::init()) { - return false; - } - if (!Storage::init()) { - return false; - } - if (!Button::init()) { - return false; - } - // initialize global variables - cur_state = STATE_MODES; - menu_selection = 0; - cur_mode = 0; - num_colors_selected = 0; - selected_base_group = 0; - keepgoing = true; - last_mode_switch_time = 0; -#ifdef HELIOS_CLI - sleeping = false; -#endif - load_global_flags(); - load_cur_mode(); - return true; -} - -void Helios::tick() -{ - // sample the button and re-calculate all button globals - // the button globals should not change anywhere else - Button::update(); - - // handle the current state of the system, ie whatever state - // we're in we check for the appropriate input events for that - // state by checking button globals, then run the appropriate logic - handle_state(); - - // Update the Leds once per frame - Led::update(); - - // finally tick the clock forward and then sleep till the entire - // tick duration has been consumed - Time::tickClock(); -} - -void Helios::enter_sleep() -{ -#ifdef HELIOS_EMBEDDED - // clear the led colors - Led::clear(); - // Set all pins to input - DDRB = 0x00; - // Disable pull-ups on all pins - PORTB = 0x00; - // Enable wake on interrupt for the button - Button::enableWake(); - // Set sleep mode to POWER DOWN mode - set_sleep_mode(SLEEP_MODE_PWR_DOWN); - // enter sleep - sleep_mode(); - // ... interrupt will make us wake here - - // Set PB0, PB1, PB4 as output - DDRB |= (1 << DDB0) | (1 << DDB1) | (1 << DDB4); - // wakeup here, re-init - init_components(); -#else - cur_state = STATE_SLEEP; - // enable the sleep bool - sleeping = true; -#endif -} - -void Helios::wakeup() -{ -#ifdef HELIOS_EMBEDDED - // nothing needed here, this interrupt firing will make the mainthread resume -#else - // if the button was held down then they are entering off-menus - // but if we re-initialize the button it will clear this state - bool pressed = Button::isPressed(); - // re-initialize some stuff - Time::init(); - Button::init(); - // so just re-press it - if (pressed) { - Button::doPress(); - } - cur_state = STATE_MODES; - // turn off the sleeping flag that only CLI has - sleeping = false; -#endif -} - -void Helios::load_next_mode() -{ - // increment current mode and wrap around - cur_mode = (uint8_t)(cur_mode + 1) % NUM_MODE_SLOTS; - // now load current mode again - load_cur_mode(); -} - -void Helios::load_cur_mode() -{ - // read pattern from storage at cur mode index - if (!Storage::read_pattern(cur_mode, pat)) { - // and just initialize default if it cannot be read - Patterns::make_default(cur_mode, pat); - // try to write it out because storage was corrupt - Storage::write_pattern(cur_mode, pat); - } - // then re-initialize the pattern - pat.init(); - // Update the last mode switch time when loading a mode - last_mode_switch_time = Time::getCurtime(); -} - -void Helios::save_cur_mode() -{ - Storage::write_pattern(cur_mode, pat); -} - -void Helios::load_global_flags() -{ - // read the global flags from index 0 config - global_flags = (Flags)Storage::read_global_flags(); - cur_mode = Storage::read_current_mode(); -} - -void Helios::save_global_flags() -{ - Storage::write_global_flags(global_flags); - Storage::write_current_mode(cur_mode); -} - -void Helios::set_mode_index(uint8_t mode_index) -{ - cur_mode = (uint8_t)mode_index % NUM_MODE_SLOTS; - // now load current mode again - load_cur_mode(); -} - -void Helios::handle_state() -{ - // check for the force sleep button hold regardless of which state we're in - if (Button::holdDuration() > FORCE_SLEEP_TIME) { - // when released the device will just sleep - if (Button::onRelease()) { - enter_sleep(); - // ALWAYS RETURN AFTER SLEEP! WE WILL WAKE HERE! - return; - } - // but as long as it's held past the sleep time it just turns off the led - if (Button::isPressed()) { - Led::clear(); - return; - } - } - // otherwise just handle the state like normal - switch (cur_state) { - case STATE_MODES: - handle_state_modes(); - break; - case STATE_COLOR_GROUP_SELECTION: - case STATE_COLOR_VARIANT_SELECTION: - handle_state_color_selection(); - break; - case STATE_PATTERN_SELECT: - handle_state_pat_select(); - break; - case STATE_TOGGLE_LOCK: - handle_state_toggle_flag(FLAG_LOCKED); - break; - case STATE_SET_DEFAULTS: - handle_state_set_defaults(); - break; -#ifdef HELIOS_CLI - case STATE_SLEEP: - // simulate sleep in helios CLI - if (Button::onPress() || Button::onShortClick() || Button::onLongClick()) { - wakeup(); - } - break; -#endif - } -} - -void Helios::handle_state_modes() -{ - // whether they have released the button since turning on - bool hasReleased = (Button::releaseCount() > 0); - - if (Button::releaseCount() > 1 && Button::onShortClick()) { - enter_sleep(); - return; - } - - // check for lock and go back to sleep - if (has_flag(FLAG_LOCKED) && hasReleased && !Button::onRelease()) { - enter_sleep(); - // ALWAYS RETURN AFTER SLEEP! WE WILL WAKE HERE! - return; - } - - if (!has_flag(FLAG_LOCKED) && hasReleased) { - // just play the current mode - pat.play(); - } - // check how long the button is held - uint32_t holdDur = Button::holdDuration(); - // calculate a magnitude which corresponds to how many times past the MENU_HOLD_TIME - // the user has held the button, so 0 means haven't held fully past one yet, etc - uint8_t magnitude = (uint8_t)(holdDur / MENU_HOLD_TIME); - // whether the user has held the button longer than a short click - bool heldPast = (holdDur > SHORT_CLICK_THRESHOLD); - - // flash red briefly when locked and short clicked - if (has_flag(FLAG_LOCKED) && holdDur < SHORT_CLICK_THRESHOLD) { - Led::set(RGB_RED_BRI_LOW); - } - // if the button is held for at least 1 second - if (Button::isPressed() && heldPast) { - // if the button has been released before then show the on menu - if (hasReleased) { - switch (magnitude) { - default: - case 0: Led::clear(); break; // Turn off - case 1: Led::set(RGB_TURQUOISE_BRI_LOW); break; // Color Selection - case 2: Led::set(RGB_MAGENTA_BRI_LOW); break; // Pattern Selection - } - } else { - if (has_flag(FLAG_LOCKED)) { - switch (magnitude) { - default: - case 0: Led::clear(); break; - case TIME_TILL_GLOW_LOCK_UNLOCK: Led::set(RGB_RED_BRI_LOW); break; // Exit - } - } else { - switch (magnitude) { - default: - case 0: Led::clear(); break; // nothing - case 1: Led::set(RGB_RED_BRI_LOW); break; // Enter Glow Lock - case 2: Led::set(RGB_BLUE_BRI_LOW); break; // Master Reset - } - } - } - } - // if this isn't a release tick there's nothing more to do - if (Button::onRelease()) { - // Resets the menu selection before entering new state - menu_selection = 0; - if (heldPast && Button::releaseCount() == 1) { - handle_off_menu(magnitude, heldPast); - return; - } - // otherwise if we have released it then we are in the 'on' menu - handle_on_menu(magnitude, heldPast); - } -} - -void Helios::handle_off_menu(uint8_t mag, bool past) -{ - // if still locked then handle the unlocking menu which is just if mag == 5 - if (has_flag(FLAG_LOCKED)) { - switch (mag) { - case TIME_TILL_GLOW_LOCK_UNLOCK: // red lock - cur_state = STATE_TOGGLE_LOCK; - break; - default: - // just go back to sleep in hold-past off menu - enter_sleep(); - // ALWAYS RETURN AFTER SLEEP! WE WILL WAKE HERE! - } - // in this case we return either way, since we're locked - return; - } - - // otherwise if not locked handle the off menu - switch (mag) { - case 1: // red lock - cur_state = STATE_TOGGLE_LOCK; - Led::clear(); - return; // RETURN HERE - case 2: // blue reset defaults - cur_state = STATE_SET_DEFAULTS; - return; //RETURN HERE - default: - // just go back to sleep in hold-past off menu - enter_sleep(); - // ALWAYS RETURN AFTER SLEEP! WE WILL WAKE HERE! - return; - } -} - -void Helios::handle_on_menu(uint8_t mag, bool past) -{ - switch (mag) { - case 0: // off - // but only if we held for more than a short click - if (past) { - enter_sleep(); - // ALWAYS RETURN AFTER SLEEP! WE WILL WAKE HERE! - return; - } - break; - case 1: // color select - cur_state = STATE_COLOR_GROUP_SELECTION; - // reset the menu selection and colors selected - menu_selection = 0; - num_colors_selected = 0; - // Store original colorset before clearing - new_colorset = pat.colorset(); - // Clear existing colors in pattern - new_colorset.clear(); -#if ALTERNATIVE_HSV_RGB == 1 - // use the nice hue to rgb rainbow - g_hsv_rgb_alg = HSV_TO_RGB_RAINBOW; -#endif - break; - case 2: // pat select - cur_state = STATE_PATTERN_SELECT; - // reset the menu selection - menu_selection = 0; - break; - default: // hold past - break; - } -} - -void Helios::handle_state_color_selection() -{ - switch (cur_state) { - case STATE_COLOR_GROUP_SELECTION: - // pick the hue group - handle_state_color_group_selection(); - break; - case STATE_COLOR_VARIANT_SELECTION: - // pick the hue - handle_state_color_variant_selection(); - break; - default: - break; - } - // get the current color - RGBColor cur = Led::get(); - cur.red /= 2; - cur.green /= 2; - cur.blue /= 2; - // show selection in all of these menus - show_selection(cur); -} - -struct ColorsMenuData { - RGBColor colors[4]; -}; - -// array of colors for selection -static const ColorsMenuData color_menu_data[NUM_COLOR_GROUPS] = { - // color0 color1 color2 color3 - // =================================================================== - { RGB_RED, RGB_CORAL_ORANGE, RGB_ORANGE, RGB_YELLOW }, - { RGB_LIME_GREEN, RGB_GREEN, RGB_SEAFOAM, RGB_TURQUOISE }, - { RGB_ICE_BLUE, RGB_LIGHT_BLUE, RGB_BLUE, RGB_ROYAL_BLUE }, - { RGB_PURPLE, RGB_PINK, RGB_HOT_PINK, RGB_MAGENTA }, -}; - -void Helios::handle_state_color_group_selection() -{ - if (Button::onShortClick()) { - menu_selection = (menu_selection + 1) % NUM_MENUS_GROUP; - } - - uint8_t color_quad = (menu_selection - 2) % NUM_COLOR_GROUPS; // Now using 4 groups - if (menu_selection > 6) { - menu_selection = 0; - } - - if (Button::onLongClick()) { - // select color - switch (menu_selection) { - case 0: // selected blank - // add blank to set - new_colorset.addColor(RGB_OFF); - num_colors_selected++; - break; - case 1: // selected white - // adds white - new_colorset.addColor(RGB_WHITE); - num_colors_selected++; - break; - default: // 2-6 (color groups) - selected_base_group = color_quad; - cur_state = STATE_COLOR_VARIANT_SELECTION; - menu_selection = 0; - return; - } - - // If we've selected enough colors, save and exit - if (num_colors_selected >= NUM_COLOR_SLOTS) { - // Restore original colorset if no colors were selected - pat.setColorset(new_colorset); - save_cur_mode(); -#if ALTERNATIVE_HSV_RGB == 1 - // restore hsv to rgb algorithm type, done color selection - g_hsv_rgb_alg = HSV_TO_RGB_GENERIC; -#endif - cur_state = STATE_MODES; - return; - } - // Otherwise reset menu selection to continue selecting colors - menu_selection = 0; - } - - // default col1/col2 to off and white for the first two options - RGBColor col1 = RGB_OFF; - RGBColor col2; - uint16_t on_dur, off_dur; - - switch (menu_selection) { - case 0: // Blank Option - col2 = RGB_WHITE_BRI_LOW; - on_dur = 1; - off_dur = 30; - break; - case 1: // White Option - col2 = RGB_WHITE; - on_dur = 9; - off_dur = 0; - break; - default: // Color options - col1 = color_menu_data[color_quad].colors[0]; - col2 = color_menu_data[color_quad].colors[2]; - on_dur = 500; - off_dur = 500; - break; - } - Led::strobe(on_dur, off_dur, col1, col2); - // show a white flash for the first two menus - if (menu_selection <= 1) { - show_selection(RGB_WHITE_BRI_LOW); - } else { - // dim the color for the quad menus - RGBColor cur = Led::get(); - cur.red /= 2; - cur.green /= 2; - cur.blue /= 2; - show_selection(RGB_WHITE_BRI_LOW); - } - - if (menu_selection == 0) { - // If the user is on the blank option (menu_selection == 0) and holding, flash red to indicate they can save with current colors - if (Button::holdPressing()) { - // flash red to indicate save action is available - Led::strobe(150, 150, RGB_RED_BRI_LOW, RGB_OFF); - } - - if (Button::onHoldClick()) { - cur_state = STATE_MODES; - if (num_colors_selected > 0) { - pat.setColorset(new_colorset); - // Save with current colors if at least one color is selected - save_cur_mode(); - } - num_colors_selected = 0; - } - } -} - -void Helios::handle_state_color_variant_selection() -{ - // handle iterating to the next option - if (Button::onShortClick()) { - menu_selection = (menu_selection + 1) % NUM_COLORS_PER_GROUP; - } - - // Get the color directly from the color menu data - RGBColor selected_color = color_menu_data[selected_base_group].colors[menu_selection]; - - // render current selection - Led::set(selected_color); - - if (Button::onLongClick()) { - // Save the color and increment counter - new_colorset.addColor(selected_color); - num_colors_selected++; - - // If we've selected enough colors, save and exit - if (num_colors_selected >= NUM_COLOR_SLOTS) { - // Restore original colorset if no colors were selected - pat.setColorset(new_colorset); - save_cur_mode(); -#if ALTERNATIVE_HSV_RGB == 1 - // restore hsv to rgb algorithm type, done color selection - g_hsv_rgb_alg = HSV_TO_RGB_GENERIC; -#endif - cur_state = STATE_MODES; - } else { - // Go back to group selection for next color - cur_state = STATE_COLOR_GROUP_SELECTION; - menu_selection = 0; - } - } -} - -void Helios::handle_state_pat_select() -{ - if (Button::onLongClick()) { - save_cur_mode(); - cur_state = STATE_MODES; - } - if (Button::onShortClick()) { - Patterns::make_pattern((PatternID)menu_selection, pat); - menu_selection = (menu_selection + 1) % PATTERN_COUNT; - pat.init(); - } - pat.play(); - show_selection(RGB_MAGENTA_BRI_LOW); -} - -void Helios::handle_state_toggle_flag(Flags flag) -{ - toggle_flag(flag); - // write out the new global flags and the current mode - save_global_flags(); - // switch back to modes - cur_state = STATE_MODES; -} - -void Helios::handle_state_set_defaults() -{ - if (Button::onShortClick()) { - menu_selection = !menu_selection; - } - // show low white for exit or red for select - if (menu_selection) { - Led::strobe(80, 20, RGB_RED_BRI_LOW, RGB_OFF); - } else { - Led::strobe(20, 10, RGB_WHITE_BRI_LOWEST, RGB_OFF); - } - // when the user long clicks a selection - if (Button::onLongClick()) { - // if the user actually selected 'yes' - if (menu_selection == 1) { - factory_reset(); - } - cur_state = STATE_MODES; - } - show_selection(RGB_WHITE_BRI_LOW); -} - -void Helios::factory_reset() -{ - for (uint8_t i = 0; i < NUM_MODE_SLOTS; ++i) { - Patterns::make_default(i, pat); - Storage::write_pattern(i, pat); - } - // Reset global brightness to default - Led::setBrightness(DEFAULT_BRIGHTNESS); - Storage::write_brightness(DEFAULT_BRIGHTNESS); - // set global flags to autoplay - global_flags = FLAG_NONE; - cur_mode = 0; - // save global flags - save_global_flags(); - // re-load current mode - load_cur_mode(); -} - - -void Helios::show_selection(RGBColor color) -{ - // only show selection while pressing the button - if (!Button::isPressed()) { - return; - } - uint16_t holdDur = (uint16_t)Button::holdDuration(); - // if the hold duration is outside the flashing range do nothing - if (holdDur < SHORT_CLICK_THRESHOLD || holdDur >= HOLD_CLICK_START) { - return; - } - Led::set(color); -} diff --git a/Helios/Helios.h b/Helios/Helios.h index 07bb3f2e..57140eee 100644 --- a/Helios/Helios.h +++ b/Helios/Helios.h @@ -1,98 +1,46 @@ +#ifndef HELIOS_H +#define HELIOS_H + #include #include "HeliosConfig.h" #include "Colorset.h" #include "Pattern.h" -class Helios -{ -public: - static bool init(); - static void tick(); - - static void enter_sleep(); - static void wakeup(); - - static bool keep_going() { return keepgoing; } - static void terminate() { keepgoing = false; } - - static void load_next_mode(); - static void load_cur_mode(); - static void save_cur_mode(); - static void load_global_flags(); - static void save_global_flags(); - static void set_mode_index(uint8_t mode_index); - -#ifdef HELIOS_CLI - static bool is_asleep() { return sleeping; } - static Pattern &cur_pattern() { return pat; } -#endif - - enum Flags : uint8_t { - FLAG_NONE = 0, - FLAG_LOCKED = (1 << 0), - }; - - // get/set global flags - static void set_flag(Flags flag) { global_flags = (Flags)(global_flags | flag); } - static bool has_flag(Flags flag) { return (global_flags & flag) == flag; } - static void clear_flag(Flags flag) { global_flags = (Flags)(global_flags & ~flag); } - static void toggle_flag(Flags flag) { global_flags = (Flags)(global_flags ^ flag); } +/* Forward declaration */ +typedef struct pattern_t pattern_t; +typedef struct colorset_t colorset_t; -private: - // initialize the various components of helios - static bool init_components(); +uint8_t helios_init(void); +void helios_tick(void); - static void handle_state(); - static void handle_state_modes(); +void helios_enter_sleep(void); +void helios_wakeup(void); - // the slot selection returns this info for internal menu logic - enum ColorSelectOption { - OPTION_NONE = 0, +uint8_t helios_keep_going(void); +void helios_terminate(void); - SELECTED_ADD, - SELECTED_EXIT, - SELECTED_SLOT - }; +void helios_load_next_mode(void); +void helios_load_cur_mode(void); +void helios_save_cur_mode(void); +void helios_load_global_flags(void); +void helios_save_global_flags(void); +void helios_set_mode_index(uint8_t mode_index); - static void handle_off_menu(uint8_t mag, bool past); - static void handle_on_menu(uint8_t mag, bool past); - static void handle_state_color_selection(); - static void handle_state_color_group_selection(); - static void handle_state_color_variant_selection(); - static void handle_state_pat_select(); - static void handle_state_toggle_flag(Flags flag); - static void handle_state_set_defaults(); - static void show_selection(RGBColor color); - static void factory_reset(); - - enum State : uint8_t { - STATE_MODES, - STATE_COLOR_GROUP_SELECTION, - STATE_COLOR_VARIANT_SELECTION, - STATE_PATTERN_SELECT, - STATE_TOGGLE_LOCK, - STATE_SET_DEFAULTS, #ifdef HELIOS_CLI - STATE_SLEEP, +uint8_t helios_is_asleep(void); +pattern_t *helios_cur_pattern(void); #endif - }; - // the current state of the system - static State cur_state; - // global flags for the entire system - static Flags global_flags; - static uint8_t menu_selection; - static uint8_t cur_mode; - // the group that was selected in color select - static uint8_t selected_base_group; - static uint8_t num_colors_selected; // Track number of colors selected in current session - static Pattern pat; - static bool keepgoing; - static uint32_t last_mode_switch_time; - static Colorset new_colorset; +enum helios_flags { + FLAG_NONE = 0, + FLAG_LOCKED = (1 << 0), +}; + +/* get/set global flags */ +void helios_set_flag(enum helios_flags flag); +uint8_t helios_has_flag(enum helios_flags flag); +void helios_clear_flag(enum helios_flags flag); +void helios_toggle_flag(enum helios_flags flag); -#ifdef HELIOS_CLI - static bool sleeping; // Only used in CLI mode #endif -}; diff --git a/Helios/HeliosConfig.h b/Helios/HeliosConfig.h index 2af799e9..4c34d665 100644 --- a/Helios/HeliosConfig.h +++ b/Helios/HeliosConfig.h @@ -127,13 +127,13 @@ // Colorset Size // // the colorset is just an array of colors but it also has a num colors val -#define COLORSET_SIZE ((sizeof(RGBColor) * NUM_COLOR_SLOTS) + 1) +#define COLORSET_SIZE ((sizeof(rgb_color_t) * NUM_COLOR_SLOTS) + 1) // Pattern Args Size // // There is currently 6 args for a pattern: on, off, gap, dash, group, blend // Each takes up 1 byte currently -#define PAT_ARGS_SIZE (sizeof(PatternArgs)) +#define PAT_ARGS_SIZE (sizeof(pattern_args_t)) // Pattern Size // diff --git a/Helios/Led.c b/Helios/Led.c new file mode 100644 index 00000000..6ca3d584 --- /dev/null +++ b/Helios/Led.c @@ -0,0 +1,190 @@ +#include + +#include "Led.h" + +#include "TimeControl.h" + +#include "HeliosConfig.h" + +#ifdef HELIOS_EMBEDDED +#ifdef HELIOS_ARDUINO +#include +#else +#include +#include +#include +#endif +#define PWM_PIN_R PB0 /* Red channel (pin 5) */ +#define PWM_PIN_G PB1 /* Green channel (pin 6) */ +#define PWM_PIN_B PB4 /* Blue channel (pin 3) */ +#endif + +#define SCALE8(i, scale) (((uint16_t)i * (uint16_t)(scale)) >> 8) + +/* Forward declaration */ +static void led_set_pwm(uint8_t pwmPin, uint8_t pwmValue, volatile uint8_t *controlRegister, + uint8_t controlBit, volatile uint8_t *compareRegister); + +/* array of led color values */ +static rgb_color_t m_ledColor; +static rgb_color_t m_realColor; +/* global brightness */ +static uint8_t m_brightness = DEFAULT_BRIGHTNESS; + +uint8_t led_init(void) +{ + /* clear the led colors */ + rgb_init_from_raw(&m_ledColor, RGB_OFF); + rgb_init_from_raw(&m_realColor, RGB_OFF); +#ifdef HELIOS_EMBEDDED +#ifdef HELIOS_ARDUINO + pinMode(0, OUTPUT); + pinMode(1, OUTPUT); + pinMode(4, OUTPUT); +#else + /* pin ctrl done in helios_init */ +#endif +#endif + return 1; +} + +void led_cleanup(void) +{ +} + +void led_set_rgb(const rgb_color_t *col) +{ + rgb_copy(&m_ledColor, col); + m_realColor.red = SCALE8(m_ledColor.red, m_brightness); + m_realColor.green = SCALE8(m_ledColor.green, m_brightness); + m_realColor.blue = SCALE8(m_ledColor.blue, m_brightness); +} + +void led_set_rgb3(uint8_t r, uint8_t g, uint8_t b) +{ + rgb_color_t col; + rgb_init3(&col, r, g, b); + led_set_rgb(&col); +} + +void led_clear(void) +{ + rgb_color_t off; + rgb_init_from_raw(&off, RGB_OFF); + led_set_rgb(&off); +} + +void led_adjust_brightness(uint8_t fadeBy) +{ + rgb_adjust_brightness(&m_ledColor, fadeBy); +} + +void led_strobe(uint16_t on_time, uint16_t off_time, const rgb_color_t *off_col, const rgb_color_t *on_col) +{ + if ((Time_getCurtime() % (on_time + off_time)) > on_time) { + led_set_rgb(off_col); + } else { + led_set_rgb(on_col); + } +} + +void led_breath(uint8_t hue, uint32_t duration, uint8_t magnitude, uint8_t sat, uint8_t val) +{ + if (!duration) { + /* don't divide by 0 */ + return; + } + /* Determine the phase in the cycle */ + uint32_t phase = Time_getCurtime() % (2 * duration); + /* Calculate hue shift */ + int32_t hueShift; + if (phase < duration) { + /* Ascending phase - from hue to hue + magnitude */ + hueShift = (phase * magnitude) / duration; + } else { + /* Descending phase - from hue + magnitude to hue */ + hueShift = ((2 * duration - phase) * magnitude) / duration; + } + /* Apply hue shift - ensure hue stays within valid range */ + uint8_t shiftedHue = hue + hueShift; + /* Apply the hsv color as a strobing hue shift */ + hsv_color_t hsv; + rgb_color_t off, on; + hsv_init3(&hsv, shiftedHue, sat, val); + rgb_init_from_raw(&off, RGB_OFF); + rgb_init_from_hsv(&on, &hsv); + led_strobe(2, 13, &off, &on); +} + +void led_hold(const rgb_color_t *col) +{ + led_set_rgb(col); + led_update(); + Time_delayMilliseconds(250); +} + +static void led_set_pwm(uint8_t pwmPin, uint8_t pwmValue, volatile uint8_t *controlRegister, + uint8_t controlBit, volatile uint8_t *compareRegister) +{ +#ifdef HELIOS_EMBEDDED + if (pwmValue == 0) { + /* digitalWrite(pin, LOW) */ + *controlRegister &= ~controlBit; /* Disable PWM */ + PORTB &= ~(1 << pwmPin); /* Set the pin low */ + } else if (pwmValue == 255) { + /* digitalWrite(pin, HIGH) */ + *controlRegister &= ~controlBit; /* Disable PWM */ + PORTB |= (1 << pwmPin); /* Set the pin high */ + } else { + /* analogWrite(pin, value) */ + *controlRegister |= controlBit; /* Enable PWM */ + *compareRegister = pwmValue; /* Set PWM duty cycle */ + } +#else + (void)pwmPin; + (void)pwmValue; + (void)controlRegister; + (void)controlBit; + (void)compareRegister; +#endif +} + +rgb_color_t led_get(void) +{ + return m_ledColor; +} + +uint8_t led_get_brightness(void) +{ + return m_brightness; +} + +void led_set_brightness(uint8_t brightness) +{ + m_brightness = brightness; +} + +void led_update(void) +{ +#ifdef HELIOS_EMBEDDED + /* write out the rgb values to analog pins */ +#ifdef HELIOS_ARDUINO + analogWrite(PWM_PIN_R, m_realColor.red); + analogWrite(PWM_PIN_G, m_realColor.green); + analogWrite(PWM_PIN_B, m_realColor.blue); +#else + /* backup SREG and turn off interrupts */ + uint8_t oldSREG = SREG; + cli(); + + /* set the PWM for R/G/B output */ + led_set_pwm(PWM_PIN_R, m_realColor.red, &TCCR0A, (1 << COM0A1), &OCR0A); + led_set_pwm(PWM_PIN_G, m_realColor.green, &TCCR0A, (1 << COM0B1), &OCR0B); + led_set_pwm(PWM_PIN_B, m_realColor.blue, >CCR, (1 << COM1B1), &OCR1B); + + /* turn interrupts back on */ + SREG = oldSREG; +#endif +#endif +} + diff --git a/Helios/Led.cpp b/Helios/Led.cpp deleted file mode 100644 index 13052f1e..00000000 --- a/Helios/Led.cpp +++ /dev/null @@ -1,147 +0,0 @@ -#include - -#include "Led.h" - -#include "TimeControl.h" - -#include "HeliosConfig.h" -#include "Helios.h" - -#ifdef HELIOS_EMBEDDED -#ifdef HELIOS_ARDUINO -#include -#else -#include -#include -#include -#endif -#define PWM_PIN_R PB0 // Red channel (pin 5) -#define PWM_PIN_G PB1 // Green channel (pin 6) -#define PWM_PIN_B PB4 // Blue channel (pin 3) -#endif - -#define SCALE8(i, scale) (((uint16_t)i * (uint16_t)(scale)) >> 8) - -// array of led color values -RGBColor Led::m_ledColor = RGB_OFF; -RGBColor Led::m_realColor = RGB_OFF; -// global brightness -uint8_t Led::m_brightness = DEFAULT_BRIGHTNESS; - -bool Led::init() -{ - // clear the led colors - m_ledColor = RGB_OFF; - m_realColor = RGB_OFF; -#ifdef HELIOS_EMBEDDED -#ifdef HELIOS_ARDUINO - pinMode(0, OUTPUT); - pinMode(1, OUTPUT); - pinMode(4, OUTPUT); -#else - // pin ctrl done in Helios::init -#endif -#endif - return true; -} - -void Led::cleanup() -{ -} - -void Led::set(RGBColor col) -{ - m_ledColor = col; - m_realColor.red = SCALE8(m_ledColor.red, m_brightness); - m_realColor.green = SCALE8(m_ledColor.green, m_brightness); - m_realColor.blue = SCALE8(m_ledColor.blue, m_brightness); -} - -void Led::set(uint8_t r, uint8_t g, uint8_t b) -{ - set(RGBColor(r, g, b)); -} - -void Led::adjustBrightness(uint8_t fadeBy) -{ - m_ledColor.adjustBrightness(fadeBy); -} - -void Led::strobe(uint16_t on_time, uint16_t off_time, RGBColor off_col, RGBColor on_col) -{ - set(((Time::getCurtime() % (on_time + off_time)) > on_time) ? off_col : on_col); -} - -void Led::breath(uint8_t hue, uint32_t duration, uint8_t magnitude, uint8_t sat, uint8_t val) -{ - if (!duration) { - // don't divide by 0 - return; - } - // Determine the phase in the cycle - uint32_t phase = Time::getCurtime() % (2 * duration); - // Calculate hue shift - int32_t hueShift; - if (phase < duration) { - // Ascending phase - from hue to hue + magnitude - hueShift = (phase * magnitude) / duration; - } else { - // Descending phase - from hue + magnitude to hue - hueShift = ((2 * duration - phase) * magnitude) / duration; - } - // Apply hue shift - ensure hue stays within valid range - uint8_t shiftedHue = hue + hueShift; - // Apply the hsv color as a strobing hue shift - strobe(2, 13, RGB_OFF, HSVColor(shiftedHue, sat, val)); -} - -void Led::hold(RGBColor col) -{ - set(col); - update(); - Time::delayMilliseconds(250); -} - -void Led::setPWM(uint8_t pwmPin, uint8_t pwmValue, volatile uint8_t &controlRegister, - uint8_t controlBit, volatile uint8_t &compareRegister) -{ -#ifdef HELIOS_EMBEDDED - if (pwmValue == 0) { - // digitalWrite(pin, LOW) - controlRegister &= ~controlBit; // Disable PWM - PORTB &= ~(1 << pwmPin); // Set the pin low - } else if (pwmValue == 255) { - // digitalWrite(pin, HIGH) - controlRegister &= ~controlBit; // Disable PWM - PORTB |= (1 << pwmPin); // Set the pin high - } else { - // analogWrite(pin, value) - controlRegister |= controlBit; // Enable PWM - compareRegister = pwmValue; // Set PWM duty cycle - } -#endif -} - -void Led::update() -{ -#ifdef HELIOS_EMBEDDED - // write out the rgb values to analog pins -#ifdef HELIOS_ARDUINO - analogWrite(PWM_PIN_R, m_realColor.red); - analogWrite(PWM_PIN_G, m_realColor.green); - analogWrite(PWM_PIN_B, m_realColor.blue); -#else - // backup SREG and turn off interrupts - uint8_t oldSREG = SREG; - cli(); - - // set the PWM for R/G/B output - setPWM(PWM_PIN_R, m_realColor.red, TCCR0A, (1 << COM0A1), OCR0A); - setPWM(PWM_PIN_G, m_realColor.green, TCCR0A, (1 << COM0B1), OCR0B); - setPWM(PWM_PIN_B, m_realColor.blue, GTCCR, (1 << COM1B1), OCR1B); - - // turn interrupts back on - SREG = oldSREG; -#endif -#endif -} diff --git a/Helios/Led.h b/Helios/Led.h index 34c5faad..e0f1bff8 100644 --- a/Helios/Led.h +++ b/Helios/Led.h @@ -5,57 +5,40 @@ #include "Colortypes.h" -class Led -{ - // private unimplemented constructor - Led(); - -public: - // opting for static class here because there should only ever be one - // Led control object and I don't like singletons - static bool init(); - static void cleanup(); - - // control individual LED, these are appropriate to use in internal pattern logic - static void set(RGBColor col); - static void set(uint8_t r, uint8_t g, uint8_t b); - - // Turn off individual LEDs, these are appropriate to use in internal pattern logic - static void clear() { set(RGB_OFF); } - - // Dim individual LEDs, these are appropriate to use in internal pattern logic - static void adjustBrightness(uint8_t fadeBy); - - // strobe between two colors with a simple on/off timing - static void strobe(uint16_t on_time, uint16_t off_time, RGBColor col1, RGBColor col2); - - // breath the hue on an index - // warning: these use hsv to rgb in realtime! - static void breath(uint8_t hue, uint32_t duration = 1000, uint8_t magnitude = 60, - uint8_t sat = 255, uint8_t val = 255); - - // a very specialized api to hold all leds on a color for 250ms - static void hold(RGBColor col); - - // get the RGBColor of an Led index - static RGBColor get() { return m_ledColor; } - - // global brightness - static uint8_t getBrightness() { return m_brightness; } - static void setBrightness(uint8_t brightness) { m_brightness = brightness; } - - // actually update the LEDs and show the changes - static void update(); - -private: - static void setPWM(uint8_t pwmPin, uint8_t pwmValue, volatile uint8_t &controlRegister, - uint8_t controlBit, volatile uint8_t &compareRegister); - - // the global brightness - static uint8_t m_brightness; - // led color - static RGBColor m_ledColor; - static RGBColor m_realColor; -}; +/* opting for static functions here because there should only ever be one + * Led control object and I don't like singletons */ + +uint8_t led_init(void); +void led_cleanup(void); + +/* control individual LED, these are appropriate to use in internal pattern logic */ +void led_set_rgb(const rgb_color_t *col); +void led_set_rgb3(uint8_t r, uint8_t g, uint8_t b); + +/* Turn off individual LEDs, these are appropriate to use in internal pattern logic */ +void led_clear(void); + +/* Dim individual LEDs, these are appropriate to use in internal pattern logic */ +void led_adjust_brightness(uint8_t fadeBy); + +/* strobe between two colors with a simple on/off timing */ +void led_strobe(uint16_t on_time, uint16_t off_time, const rgb_color_t *col1, const rgb_color_t *col2); + +/* breath the hue on an index + * warning: these use hsv to rgb in realtime! */ +void led_breath(uint8_t hue, uint32_t duration, uint8_t magnitude, uint8_t sat, uint8_t val); + +/* a very specialized api to hold all leds on a color for 250ms */ +void led_hold(const rgb_color_t *col); + +/* get the RGBColor of an Led index */ +rgb_color_t led_get(void); + +/* global brightness */ +uint8_t led_get_brightness(void); +void led_set_brightness(uint8_t brightness); + +/* actually update the LEDs and show the changes */ +void led_update(void); #endif diff --git a/Helios/Pattern.c b/Helios/Pattern.c new file mode 100644 index 00000000..d1536109 --- /dev/null +++ b/Helios/Pattern.c @@ -0,0 +1,375 @@ +#include "Pattern.h" + +#include "TimeControl.h" +#include "Colorset.h" + +#include "HeliosConfig.h" +#include "Led.h" + +#include /* for memcpy */ + +/* Forward declarations for internal functions */ +static void pattern_on_blink_on(pattern_t *pat); +static void pattern_on_blink_off(pattern_t *pat); +static void pattern_begin_gap(pattern_t *pat); +static void pattern_begin_dash(pattern_t *pat); +static void pattern_next_state(pattern_t *pat, uint8_t timing); +static void pattern_blend_blink_on(pattern_t *pat); +static void pattern_interpolate(uint8_t *current, const uint8_t next, uint8_t blend_speed); +static void pattern_tick_fade(pattern_t *pat); + +/* ================================== + * Pattern Args Functions */ + +void pattern_args_init(pattern_args_t *args, uint8_t on, uint8_t off, uint8_t gap, + uint8_t dash, uint8_t group, uint8_t blend, uint8_t fade) +{ + args->on_dur = on; + args->off_dur = off; + args->gap_dur = gap; + args->dash_dur = dash; + args->group_size = group; + args->blend_speed = blend; + args->fade_dur = fade; +} + +/* ================================== + * Pattern Functions */ + +void pattern_init(pattern_t *pat, uint8_t onDur, uint8_t offDur, uint8_t gap, + uint8_t dash, uint8_t group, uint8_t blend, uint8_t fade) +{ + pattern_args_init(&pat->m_args, onDur, offDur, gap, dash, group, blend, fade); + pat->m_patternFlags = 0; + colorset_init(&pat->m_colorset); + pat->m_groupCounter = 0; + pat->m_state = STATE_BLINK_ON; + timer_init_default(&pat->m_blinkTimer); + rgb_init(&pat->m_cur); + rgb_init(&pat->m_next); + pat->m_fadeValue = 0; + pat->m_fadeStartTime = 0; +} + +void pattern_init_with_args(pattern_t *pat, const pattern_args_t *args) +{ + pattern_init(pat, args->on_dur, args->off_dur, args->gap_dur, + args->dash_dur, args->group_size, args->blend_speed, args->fade_dur); +} + +void pattern_init_state(pattern_t *pat) +{ + colorset_reset_index(&pat->m_colorset); + + /* Reset the fade start time to the current time */ + pat->m_fadeStartTime = Time_getCurtime(); + + /* the default state to begin with */ + pat->m_state = STATE_BLINK_ON; + /* if a dash is present then always start with the dash because + * it consumes the first color in the colorset */ + if (pat->m_args.dash_dur > 0) { + pat->m_state = STATE_BEGIN_DASH; + } + /* if there's no on duration or dash duration the led is just disabled */ + if ((!pat->m_args.on_dur && !pat->m_args.dash_dur) || !colorset_num_colors(&pat->m_colorset)) { + pat->m_state = STATE_DISABLED; + } + pat->m_groupCounter = pat->m_args.group_size ? pat->m_args.group_size : (colorset_num_colors(&pat->m_colorset) - (pat->m_args.dash_dur != 0)); + + if (pat->m_args.blend_speed > 0) { + /* convert current/next colors to HSV but only if we are doing a blend */ + pat->m_cur = colorset_get_next(&pat->m_colorset); + pat->m_next = colorset_get_next(&pat->m_colorset); + } else if (pat->m_args.fade_dur) { + /* if there is a fade dur and no blend need to iterate colorset */ + colorset_get_next(&pat->m_colorset); + } + + /* Initialize the fluctuating fade value */ + pat->m_fadeValue = 0; +} + +static void pattern_tick_fade(pattern_t *pat) +{ + uint32_t now = Time_getCurtime(); + /* Calculate relative time since pattern was initialized */ + uint32_t relativeTime = now - pat->m_fadeStartTime; + uint32_t duration = pat->m_args.fade_dur * 10; + + /* only tick forward every fade_dur ticks */ + if (!relativeTime || (relativeTime % duration) != 0) { + return; + } + + /* count the number of steps based on relative time */ + uint32_t steps = relativeTime / duration; + uint32_t range = pat->m_args.off_dur; + + /* make sure the range is non-zero */ + if (range == 0) { + pat->m_fadeValue = 0; + return; + } + + uint32_t double_range = range * 2; + uint32_t step = steps % double_range; + + /* Triangle wave: up from 0 to range, then down to 0 */ + pat->m_fadeValue = (step < range) ? step : (double_range - step - 1); + + /* iterate color when at lowest point */ + if (step == 0) { + colorset_get_next(&pat->m_colorset); + } +} + +void pattern_play(pattern_t *pat) +{ + /* tick forward the fade logic each tick */ + if (pattern_is_fade(pat)) { + pattern_tick_fade(pat); + } + + /* Sometimes the pattern needs to cycle multiple states in a single frame so + * instead of using a loop or recursion I have just used a simple goto */ +replay: + + /* its kinda evolving as i go */ + switch (pat->m_state) { + case STATE_DISABLED: + return; + case STATE_BLINK_ON: + if (pat->m_args.on_dur > 0) { + pattern_on_blink_on(pat); + --pat->m_groupCounter; + /* When in ON state, use current fading on-time */ + pattern_next_state(pat, pat->m_args.on_dur + pat->m_fadeValue); + return; + } + pat->m_state = STATE_BLINK_OFF; + case STATE_BLINK_OFF: + /* the whole 'should blink off' situation is tricky because we might need + * to go back to blinking on if our colorset isn't at the end yet */ + if (pat->m_groupCounter > 0 || (!pat->m_args.gap_dur && !pat->m_args.dash_dur)) { + if (pat->m_args.off_dur > 0) { + pattern_on_blink_off(pat); + pattern_next_state(pat, pat->m_args.off_dur - pat->m_fadeValue); + return; + } + if (pat->m_groupCounter > 0 && pat->m_args.on_dur > 0) { + pat->m_state = STATE_BLINK_ON; + goto replay; + } + } + pat->m_state = STATE_BEGIN_GAP; + case STATE_BEGIN_GAP: + pat->m_groupCounter = pat->m_args.group_size ? pat->m_args.group_size : (colorset_num_colors(&pat->m_colorset) - (pat->m_args.dash_dur != 0)); + if (pat->m_args.gap_dur > 0) { + pattern_begin_gap(pat); + pattern_next_state(pat, pat->m_args.gap_dur); + return; + } + pat->m_state = STATE_BEGIN_DASH; + case STATE_BEGIN_DASH: + if (pat->m_args.dash_dur > 0) { + pattern_begin_dash(pat); + pattern_next_state(pat, pat->m_args.dash_dur); + return; + } + pat->m_state = STATE_BEGIN_GAP2; + case STATE_BEGIN_GAP2: + if (pat->m_args.dash_dur > 0 && pat->m_args.gap_dur > 0) { + pattern_begin_gap(pat); + pattern_next_state(pat, pat->m_args.gap_dur); + return; + } + pat->m_state = STATE_BLINK_ON; + goto replay; + default: + break; + } + + if (!timer_alarm(&pat->m_blinkTimer)) { + /* no alarm triggered just stay in current state, return and don't transition states */ + return; + } + + /* this just transitions the state into the next state, with some edge conditions for + * transitioning to different states under certain circumstances. Honestly this is + * a nightmare to read now and idk how to fix it */ + if (pat->m_state == STATE_IN_GAP2 || (pat->m_state == STATE_OFF && pat->m_groupCounter > 0)) { + /* this is an edge condition for when in the second gap or off in the non-last off blink + * then the state actually needs to jump backwards rather than iterate */ + pat->m_state = pat->m_args.on_dur ? STATE_BLINK_ON : (pat->m_args.dash_dur ? STATE_BEGIN_DASH : STATE_BEGIN_GAP); + } else if (pat->m_state == STATE_OFF && (!pat->m_groupCounter || colorset_num_colors(&pat->m_colorset) == 1)) { + /* this is an edge condition when the state is off but this is the last off blink in the + * group or there's literally only one color in the group then if there is more blinks + * left in the group we need to cycle back to blink on instead of to the next state */ + pat->m_state = (pat->m_groupCounter > 0) ? STATE_BLINK_ON : STATE_BEGIN_GAP; + } else { + /* this is the standard case, iterate to the next state */ + pat->m_state = (enum pattern_state)(pat->m_state + 1); + } + /* poor-mans recurse with the new state change (this transitions to a new state within the same tick) */ + goto replay; +} + +void pattern_set_args(pattern_t *pat, const pattern_args_t *args) +{ + memcpy(&pat->m_args, args, sizeof(pattern_args_t)); +} + +pattern_args_t pattern_get_args(const pattern_t *pat) +{ + return pat->m_args; +} + +pattern_args_t *pattern_args_ptr(pattern_t *pat) +{ + return &pat->m_args; +} + +static void pattern_on_blink_on(pattern_t *pat) +{ + if (pattern_is_blend(pat)) { + pattern_blend_blink_on(pat); + return; + } + + /* Check if this is a fading duration pattern */ + if (pattern_is_fade(pat)) { + rgb_color_t cur_col = colorset_cur(&pat->m_colorset); + led_set_rgb(&cur_col); + return; + } + + rgb_color_t next_col = colorset_get_next(&pat->m_colorset); + led_set_rgb(&next_col); +} + +static void pattern_on_blink_off(pattern_t *pat) +{ + (void)pat; /* unused */ + led_clear(); +} + +static void pattern_begin_gap(pattern_t *pat) +{ + (void)pat; /* unused */ + led_clear(); +} + +static void pattern_begin_dash(pattern_t *pat) +{ + rgb_color_t next_col = colorset_get_next(&pat->m_colorset); + led_set_rgb(&next_col); +} + +static void pattern_next_state(pattern_t *pat, uint8_t timing) +{ + timer_init(&pat->m_blinkTimer, timing); + pat->m_state = (enum pattern_state)(pat->m_state + 1); +} + +colorset_t pattern_get_colorset(const pattern_t *pat) +{ + return pat->m_colorset; +} + +colorset_t *pattern_colorset_ptr(pattern_t *pat) +{ + return &pat->m_colorset; +} + +void pattern_set_colorset(pattern_t *pat, const colorset_t *set) +{ + colorset_copy(&pat->m_colorset, set); + pattern_init_state(pat); +} + +void pattern_clear_colorset(pattern_t *pat) +{ + colorset_clear(&pat->m_colorset); +} + +uint8_t pattern_equals(const pattern_t *pat, const pattern_t *other) +{ + if (!other) { + return 0; + } + /* compare the colorset */ + if (!colorset_equals(&pat->m_colorset, &other->m_colorset)) { + return 0; + } + /* compare the args of each pattern for equality */ + if (memcmp(&pat->m_args, &other->m_args, sizeof(pattern_args_t)) != 0) { + return 0; + } + /* if those match then it's effectively the same + * pattern even if anything else is different */ + return 1; +} + +void pattern_update_color(pattern_t *pat, uint8_t index, const rgb_color_t *col) +{ + colorset_set(&pat->m_colorset, index, *col); + pattern_init_state(pat); +} + +uint32_t pattern_crc32(const pattern_t *pat) +{ + uint32_t hash = 5381; + uint8_t i; + for (i = 0; i < PATTERN_SIZE; ++i) { + hash = ((hash << 5) + hash) + ((uint8_t *)pat)[i]; + } + return hash; +} + +uint32_t pattern_get_flags(const pattern_t *pat) +{ + return pat->m_patternFlags; +} + +uint8_t pattern_has_flags(const pattern_t *pat, uint32_t flags) +{ + return (pat->m_patternFlags & flags) != 0; +} + +uint8_t pattern_is_blend(const pattern_t *pat) +{ + return pat->m_args.blend_speed > 0; +} + +uint8_t pattern_is_fade(const pattern_t *pat) +{ + return pat->m_args.fade_dur > 0; +} + +static void pattern_blend_blink_on(pattern_t *pat) +{ + /* if we reached the next color, then cycle the colorset + * like normal and begin playing the next color */ + if (rgb_equals(&pat->m_cur, &pat->m_next)) { + pat->m_next = colorset_get_next(&pat->m_colorset); + } + /* interpolate to the next color */ + pattern_interpolate(&pat->m_cur.red, pat->m_next.red, pat->m_args.blend_speed); + pattern_interpolate(&pat->m_cur.green, pat->m_next.green, pat->m_args.blend_speed); + pattern_interpolate(&pat->m_cur.blue, pat->m_next.blue, pat->m_args.blend_speed); + /* set the color */ + led_set_rgb(&pat->m_cur); +} + +static void pattern_interpolate(uint8_t *current, const uint8_t next, uint8_t blend_speed) +{ + if (*current < next) { + uint8_t step = (next - *current) > blend_speed ? blend_speed : (next - *current); + *current += step; + } else if (*current > next) { + uint8_t step = (*current - next) > blend_speed ? blend_speed : (*current - next); + *current -= step; + } +} + diff --git a/Helios/Pattern.cpp b/Helios/Pattern.cpp deleted file mode 100644 index 804c52d1..00000000 --- a/Helios/Pattern.cpp +++ /dev/null @@ -1,341 +0,0 @@ -#include "Pattern.h" - -//#include "../Patterns/PatternBuilder.h" -#include "TimeControl.h" -#include "Colorset.h" - -#include "HeliosConfig.h" -#include "Led.h" - -#include // for memcpy - -Pattern::Pattern(uint8_t onDur, uint8_t offDur, uint8_t gap, - uint8_t dash, uint8_t group, uint8_t blend, uint8_t fade) : - m_args(onDur, offDur, gap, dash, group, blend, fade), - m_patternFlags(0), - m_colorset(), - m_groupCounter(0), - m_state(STATE_BLINK_ON), - m_blinkTimer(), - m_cur(), - m_next(), - m_fadeValue(0), - m_fadeStartTime(0) -{ -} - -Pattern::Pattern(const PatternArgs &args) : - Pattern(args.on_dur, args.off_dur, args.gap_dur, - args.dash_dur, args.group_size, args.blend_speed, args.fade_dur) -{ -} - -Pattern::~Pattern() -{ -} - -void Pattern::init() -{ - m_colorset.resetIndex(); - - // Reset the fade start time to the current time - m_fadeStartTime = Time::getCurtime(); - - // the default state to begin with - m_state = STATE_BLINK_ON; - // if a dash is present then always start with the dash because - // it consumes the first color in the colorset - if (m_args.dash_dur > 0) { - m_state = STATE_BEGIN_DASH; - } - // if there's no on duration or dash duration the led is just disabled - if ((!m_args.on_dur && !m_args.dash_dur) || !m_colorset.numColors()) { - m_state = STATE_DISABLED; - } - m_groupCounter = m_args.group_size ? m_args.group_size : (m_colorset.numColors() - (m_args.dash_dur != 0)); - - if (m_args.blend_speed > 0) { - // convert current/next colors to HSV but only if we are doing a blend - m_cur = m_colorset.getNext(); - m_next = m_colorset.getNext(); - } else if (m_args.fade_dur) { - // if there is a fade dur and no blend need to iterate colorset - m_colorset.getNext(); - } - - // Initialize the fluctuating fade value - m_fadeValue = 0; -} - -void Pattern::tickFade() -{ - uint32_t now = Time::getCurtime(); - // Calculate relative time since pattern was initialized - uint32_t relativeTime = now - m_fadeStartTime; - uint32_t duration = m_args.fade_dur * 10; - - // only tick forward every fade_dur ticks - if (!relativeTime || (relativeTime % duration) != 0) { - return; - } - - // count the number of steps based on relative time - uint32_t steps = relativeTime / duration; - uint32_t range = m_args.off_dur; - - // make sure the range is non-zero - if (range == 0) { - m_fadeValue = 0; - return; - } - - uint32_t double_range = range * 2; - uint32_t step = steps % double_range; - - // Triangle wave: up from 0 to range, then down to 0 - m_fadeValue = (step < range) ? step : (double_range - step - 1); - - // iterate color when at lowest point - if (step == 0) { - m_colorset.getNext(); - } -} - -void Pattern::play() -{ - // tick forward the fade logic each tick - if (isFade()) { - tickFade(); - } - - // Sometimes the pattern needs to cycle multiple states in a single frame so - // instead of using a loop or recursion I have just used a simple goto -replay: - - // its kinda evolving as i go - switch (m_state) { - case STATE_DISABLED: - return; - case STATE_BLINK_ON: - if (m_args.on_dur > 0) { - onBlinkOn(); - --m_groupCounter; - // When in ON state, use current fading on-time - nextState(m_args.on_dur + m_fadeValue); - return; - } - m_state = STATE_BLINK_OFF; - case STATE_BLINK_OFF: - // the whole 'should blink off' situation is tricky because we might need - // to go back to blinking on if our colorset isn't at the end yet - if (m_groupCounter > 0 || (!m_args.gap_dur && !m_args.dash_dur)) { - if (m_args.off_dur > 0) { - onBlinkOff(); - nextState(m_args.off_dur - m_fadeValue); - return; - } - if (m_groupCounter > 0 && m_args.on_dur > 0) { - m_state = STATE_BLINK_ON; - goto replay; - } - } - m_state = STATE_BEGIN_GAP; - case STATE_BEGIN_GAP: - m_groupCounter = m_args.group_size ? m_args.group_size : (m_colorset.numColors() - (m_args.dash_dur != 0)); - if (m_args.gap_dur > 0) { - beginGap(); - nextState(m_args.gap_dur); - return; - } - m_state = STATE_BEGIN_DASH; - case STATE_BEGIN_DASH: - if (m_args.dash_dur > 0) { - beginDash(); - nextState(m_args.dash_dur); - return; - } - m_state = STATE_BEGIN_GAP2; - case STATE_BEGIN_GAP2: - if (m_args.dash_dur > 0 && m_args.gap_dur > 0) { - beginGap(); - nextState(m_args.gap_dur); - return; - } - m_state = STATE_BLINK_ON; - goto replay; - default: - break; - } - - if (!m_blinkTimer.alarm()) { - // no alarm triggered just stay in current state, return and don't transition states - PRINT_STATE(m_state); - return; - } - - // this just transitions the state into the next state, with some edge conditions for - // transitioning to different states under certain circumstances. Honestly this is - // a nightmare to read now and idk how to fix it - if (m_state == STATE_IN_GAP2 || (m_state == STATE_OFF && m_groupCounter > 0)) { - // this is an edge condition for when in the second gap or off in the non-last off blink - // then the state actually needs to jump backwards rather than iterate - m_state = m_args.on_dur ? STATE_BLINK_ON : (m_args.dash_dur ? STATE_BEGIN_DASH : STATE_BEGIN_GAP); - } else if (m_state == STATE_OFF && (!m_groupCounter || m_colorset.numColors() == 1)) { - // this is an edge condition when the state is off but this is the last off blink in the - // group or there's literally only one color in the group then if there is more blinks - // left in the group we need to cycle back to blink on instead of to the next state - m_state = (m_groupCounter > 0) ? STATE_BLINK_ON : STATE_BEGIN_GAP; - } else { - // this is the standard case, iterate to the next state - m_state = (PatternState)(m_state + 1); - } - // poor-mans recurse with the new state change (this transitions to a new state within the same tick) - goto replay; -} - -// set args -void Pattern::setArgs(const PatternArgs &args) -{ - memcpy(&m_args, &args, sizeof(PatternArgs)); -} - -void Pattern::onBlinkOn() -{ - PRINT_STATE(STATE_ON); - if (isBlend()) { - blendBlinkOn(); - return; - } - - // Check if this is a fading duration pattern - if (isFade()) { - Led::set(m_colorset.cur()); - return; - } - - - Led::set(m_colorset.getNext()); -} - -void Pattern::onBlinkOff() -{ - PRINT_STATE(STATE_OFF); - Led::clear(); -} - -void Pattern::beginGap() -{ - PRINT_STATE(STATE_IN_GAP); - Led::clear(); -} - -void Pattern::beginDash() -{ - PRINT_STATE(STATE_IN_DASH); - Led::set(m_colorset.getNext()); -} - -void Pattern::nextState(uint8_t timing) -{ - m_blinkTimer.init(timing); - m_state = (PatternState)(m_state + 1); -} - -// change the colorset -void Pattern::setColorset(const Colorset &set) -{ - m_colorset = set; - init(); -} - -void Pattern::clearColorset() -{ - m_colorset.clear(); -} - -bool Pattern::equals(const Pattern *other) -{ - if (!other) { - return false; - } - // compare the colorset - if (!m_colorset.equals(&other->m_colorset)) { - return false; - } - // compare the args of each pattern for equality - if (memcmp(&m_args, &other->m_args, sizeof(PatternArgs)) == 0) { - return false; - } - // if those match then it's effectively the same - // pattern even if anything else is different - return true; -} - -void Pattern::updateColor(uint8_t index, const RGBColor &col) -{ - m_colorset.set(index, col); - init(); -} - -uint32_t Pattern::crc32() const -{ - uint32_t hash = 5381; - for (uint8_t i = 0; i < PATTERN_SIZE; ++i) { - hash = ((hash << 5) + hash) + ((uint8_t *)this)[i]; - } - return hash; -} - -void Pattern::blendBlinkOn() -{ - // if we reached the next color, then cycle the colorset - // like normal and begin playing the next color - if (m_cur == m_next) { - m_next = m_colorset.getNext(); - } - // interpolate to the next color - interpolate(m_cur.red, m_next.red); - interpolate(m_cur.green, m_next.green); - interpolate(m_cur.blue, m_next.blue); - // set the color - Led::set(m_cur); -} - -void Pattern::interpolate(uint8_t ¤t, const uint8_t next) -{ - if (current < next) { - uint8_t step = (next - current) > m_args.blend_speed ? m_args.blend_speed : (next - current); - current += step; - } else if (current > next) { - uint8_t step = (current - next) > m_args.blend_speed ? m_args.blend_speed : (current - next); - current -= step; - } -} - -// ================================== -// Debug Code -#if DEBUG_BASIC_PATTERN == 1 -#include -void Pattern::printState(PatternState state) -{ - static uint32_t lastPrint = UINT32_MAX; - if (lastPrint == Time::getCurtime()) { - return; - } - switch (m_state) { - case STATE_DISABLED: printf("DIS "); break; - case STATE_BLINK_ON: printf("ON "); break; - case STATE_ON: printf("on "); break; - case STATE_BLINK_OFF: printf("OFF "); break; - case STATE_OFF: printf("off "); break; - case STATE_BEGIN_GAP: printf("GAP1"); break; - case STATE_IN_GAP: printf("gap1"); break; - case STATE_BEGIN_DASH: printf("DASH"); break; - case STATE_IN_DASH: printf("dash"); break; - case STATE_BEGIN_GAP2: printf("GAP2"); break; - case STATE_IN_GAP2: printf("gap2"); break; - default: printf("(%02u)", m_state); break; - } - lastPrint = Time::getCurtime(); -} -#endif diff --git a/Helios/Pattern.h b/Helios/Pattern.h index 4c2216b9..248a6bad 100644 --- a/Helios/Pattern.h +++ b/Helios/Pattern.h @@ -6,10 +6,12 @@ #include "Timer.h" #include "Patterns.h" -// for specifying things like default args -struct PatternArgs { - PatternArgs(uint8_t on = 0, uint8_t off = 0, uint8_t gap = 0, uint8_t dash = 0, uint8_t group = 0, uint8_t blend = 0, uint8_t fade = 0) : - on_dur(on), off_dur(off), gap_dur(gap), dash_dur(dash), group_size(group), blend_speed(blend), fade_dur(fade) {} +/* Forward declarations */ +typedef struct pattern_args_t pattern_args_t; +typedef struct pattern_t pattern_t; + +/* for specifying things like default args */ +struct pattern_args_t { uint8_t on_dur; uint8_t off_dur; uint8_t gap_dur; @@ -19,146 +21,117 @@ struct PatternArgs { uint8_t fade_dur; }; -class Pattern -{ -public: - // try to not set on duration to 0 - Pattern(uint8_t onDur = 1, uint8_t offDur = 0, uint8_t gap = 0, - uint8_t dash = 0, uint8_t group = 0, uint8_t blend = 0, uint8_t fade = 0); - Pattern(const PatternArgs &args); - ~Pattern(); - - // init the pattern to initial state - void init(); - - // play the pattern - void play(); - - // set/get args - void setArgs(const PatternArgs &args); - const PatternArgs getArgs() const { return m_args; } - PatternArgs getArgs() { return m_args; } - PatternArgs &args() { return m_args; } +/* Initialize pattern args with all parameters */ +void pattern_args_init(pattern_args_t *args, uint8_t on, uint8_t off, uint8_t gap, + uint8_t dash, uint8_t group, uint8_t blend, uint8_t fade); - // change the colorset - const Colorset getColorset() const { return m_colorset; } - Colorset getColorset() { return m_colorset; } - Colorset &colorset() { return m_colorset; } - void setColorset(const Colorset &set); - void clearColorset(); - - // comparison to other pattern - bool equals(const Pattern *other); +/* The various different blinking states the pattern can be in */ +enum pattern_state +{ + /* the led is disabled (there is no on or dash) */ + STATE_DISABLED, - // set a color in the colorset and re-initialize - void updateColor(uint8_t index, const RGBColor &col); + /* the pattern is blinking on the next color in the set */ + STATE_BLINK_ON, + STATE_ON, - // calculate crc of the colorset + pattern - uint32_t crc32() const; + /* the pattern is blinking off */ + STATE_BLINK_OFF, + STATE_OFF, - // get the pattern flags - uint32_t getFlags() const { return m_patternFlags; } - bool hasFlags(uint32_t flags) const { return (m_patternFlags & flags) != 0; } + /* the pattern is starting a gap after a colorset */ + STATE_BEGIN_GAP, + STATE_IN_GAP, - // whether blend speed is non 0 - bool isBlend() const { return m_args.blend_speed > 0; } + /* the pattern is beginning a dash after a colorset or gap */ + STATE_BEGIN_DASH, + STATE_IN_DASH, - // whether fade speed is non 0 - bool isFade() const { return m_args.fade_dur > 0; } + /* the pattern is starting a gap after a dash */ + STATE_BEGIN_GAP2, + STATE_IN_GAP2, +}; -protected: - // ================================== - // Pattern Parameters - PatternArgs m_args; +struct pattern_t +{ + /* ================================== + * Pattern Parameters */ + pattern_args_t m_args; - // ================================== - // Pattern Members + /* ================================== + * Pattern Members */ - // any flags the pattern has + /* any flags the pattern has */ uint8_t m_patternFlags; - // a copy of the colorset that this pattern is initialized with - Colorset m_colorset; + /* a copy of the colorset that this pattern is initialized with */ + colorset_t m_colorset; - // ================================== - // Blink Members + /* ================================== + * Blink Members */ uint8_t m_groupCounter; - // apis for blink - void onBlinkOn(); - void onBlinkOff(); - void beginGap(); - void beginDash(); - void nextState(uint8_t timing); + /* the state of the current pattern */ + enum pattern_state m_state; - // the various different blinking states the pattern can be in - enum PatternState : uint8_t - { - // the led is disabled (there is no on or dash) - STATE_DISABLED, + /* the blink timer used to measure blink timings */ + timer_t m_blinkTimer; - // the pattern is blinking on the next color in the set - STATE_BLINK_ON, - STATE_ON, + /* ================================== + * Blend Members */ - // the pattern is blinking off - STATE_BLINK_OFF, - STATE_OFF, + /* current color and target blend color */ + rgb_color_t m_cur; + rgb_color_t m_next; - // the pattern is starting a gap after a colorset - STATE_BEGIN_GAP, - STATE_IN_GAP, + /* ================================== + * Fade Members */ - // the pattern is beginning a dash after a colorset or gap - STATE_BEGIN_DASH, - STATE_IN_DASH, + /* shifting value to represent current fade */ + uint8_t m_fadeValue; - // the pattern is starting a gap after a dash - STATE_BEGIN_GAP2, - STATE_IN_GAP2, - }; + /* Add a member variable to store when the pattern was last initialized */ + uint32_t m_fadeStartTime; +}; - // the state of the current pattern - PatternState m_state; +/* try to not set on duration to 0 */ +void pattern_init(pattern_t *pat, uint8_t onDur, uint8_t offDur, uint8_t gap, + uint8_t dash, uint8_t group, uint8_t blend, uint8_t fade); +void pattern_init_with_args(pattern_t *pat, const pattern_args_t *args); - // the blink timer used to measure blink timings - Timer m_blinkTimer; +/* init the pattern to initial state */ +void pattern_init_state(pattern_t *pat); - // ================================== - // Blend Members +/* play the pattern */ +void pattern_play(pattern_t *pat); - // current color and target blend color - RGBColor m_cur; - RGBColor m_next; +/* set/get args */ +void pattern_set_args(pattern_t *pat, const pattern_args_t *args); +pattern_args_t pattern_get_args(const pattern_t *pat); +pattern_args_t *pattern_args_ptr(pattern_t *pat); - // apis for blend - void blendBlinkOn(); - void interpolate(uint8_t ¤t, const uint8_t next); +/* change the colorset */ +colorset_t pattern_get_colorset(const pattern_t *pat); +colorset_t *pattern_colorset_ptr(pattern_t *pat); +void pattern_set_colorset(pattern_t *pat, const colorset_t *set); +void pattern_clear_colorset(pattern_t *pat); - // ================================== - // Fade Members +/* comparison to other pattern */ +uint8_t pattern_equals(const pattern_t *pat, const pattern_t *other); - // shifting value to represent current fade - uint8_t m_fadeValue; +/* set a color in the colorset and re-initialize */ +void pattern_update_color(pattern_t *pat, uint8_t index, const rgb_color_t *col); - // apis for fade - void tickFade(); - - // ================================== - // Debug Code - - // if debug basic pattern is enabled -#if DEBUG_BASIC_PATTERN == 1 - // define a function for printing out state info - void printState(PatternState state); - // and define a macro that wraps it - #define PRINT_STATE(state) printState(state) -#else - // otherwise if debug is off the macro does nothing - #define PRINT_STATE(state) -#endif +/* calculate crc of the colorset + pattern */ +uint32_t pattern_crc32(const pattern_t *pat); - // Add a new member variable to store when the pattern was last initialized - uint32_t m_fadeStartTime; -}; +/* get the pattern flags */ +uint32_t pattern_get_flags(const pattern_t *pat); +uint8_t pattern_has_flags(const pattern_t *pat, uint32_t flags); + +/* whether blend speed is non 0 */ +uint8_t pattern_is_blend(const pattern_t *pat); + +/* whether fade speed is non 0 */ +uint8_t pattern_is_fade(const pattern_t *pat); #endif diff --git a/Helios/Patterns.c b/Helios/Patterns.c new file mode 100644 index 00000000..cc41885e --- /dev/null +++ b/Helios/Patterns.c @@ -0,0 +1,86 @@ +#include "Patterns.h" + +#include "Storage.h" +#include "Pattern.h" +#include "ColorConstants.h" + +/* define arrays of colors, you can reuse these if you have multiple + * modes that use the same colorset -- these demonstrate the max amount + * of colors in each set but you can absolutely list a lesser amount */ +static const uint32_t color_codes0[] = {RGB_RED, RGB_GREEN, RGB_BLUE}; /* Rainbow Flow */ + +/* Define Colorset configurations for each slot */ +struct default_colorset_t { + uint8_t num_cols; + const uint32_t *cols; +}; + +/* the array of colorset entries, make sure the number on the left reflects + * the number of colors in the array on the right */ +static const struct default_colorset_t default_colorsets[] = { + { 3, color_codes0 }, /* 0 Rainbow Flow */ +}; + +void patterns_make_default(uint8_t index, pattern_t *pat) +{ + if (index >= NUM_MODE_SLOTS) { + return; + } + pattern_args_t args; + pattern_args_init(&args, 0, 0, 0, 0, 0, 0, 0); + switch (index) { + case 0: /* Rainbow Flow */ + args.on_dur = 3; + args.off_dur = 23; + break; + } + /* assign default args */ + pattern_set_args(pat, &args); + /* build the set out of the defaults */ + colorset_t set; + colorset_init_array(&set, default_colorsets[index].num_cols, default_colorsets[index].cols); + /* assign default colorset */ + pattern_set_colorset(pat, &set); +} + +void patterns_make_pattern(enum pattern_id id, pattern_t *pat) +{ + pattern_args_t args; + pattern_args_init(&args, 0, 0, 0, 0, 0, 0, 0); + switch (id) + { + default: + + case PATTERN_STROBE: + args.on_dur = 5; + args.off_dur = 8; + break; + + case PATTERN_HYPNOSTROBE: + args.on_dur = 14; + args.off_dur = 10; + break; + + case PATTERN_STROBIE: + args.on_dur = 3; + args.off_dur = 23; + break; + + case PATTERN_RAZOR: + args.on_dur = 3; + args.off_dur = 1; + args.gap_dur = 30; /* 29 for flashing pattern circles */ + break; + + case PATTERN_DASH_DOPS: + args.on_dur = 1; + args.off_dur = 9; + args.gap_dur = 6; + args.dash_dur = 15; + break; + + } + + pattern_set_args(pat, &args); +} + diff --git a/Helios/Patterns.cpp b/Helios/Patterns.cpp deleted file mode 100644 index a4b69e02..00000000 --- a/Helios/Patterns.cpp +++ /dev/null @@ -1,81 +0,0 @@ -#include "Patterns.h" - -#include "Storage.h" -#include "Pattern.h" - -// define arrays of colors, you can reuse these if you have multiple -// modes that use the same colorset -- these demonstrate the max amount -// of colors in each set but you can absolutely list a lesser amount -static const uint32_t color_codes0[] = {RGB_RED, RGB_GREEN, RGB_BLUE}; // Rainbow Flow - -// Define Colorset configurations for each slot -struct default_colorset { - uint8_t num_cols; - const uint32_t *cols; -}; - -// the array of colorset entries, make sure the number on the left reflects -// the number of colors in the array on the right -static const default_colorset default_colorsets[] = { - { 3, color_codes0 }, // 0 Rainbow Flow -}; - -void Patterns::make_default(uint8_t index, Pattern &pat) -{ - if (index >= NUM_MODE_SLOTS) { - return; - } - PatternArgs args; - switch (index) { - case 0: // Rainbow Flow - args.on_dur = 3; - args.off_dur = 23; - break; - } - // assign default args - pat.setArgs(args); - // build the set out of the defaults - Colorset set(default_colorsets[index].num_cols, default_colorsets[index].cols); - // assign default colorset - pat.setColorset(set); -} - -void Patterns::make_pattern(PatternID id, Pattern &pat) -{ - PatternArgs args; - switch (id) - { - default: - - case PATTERN_STROBE: - args.on_dur = 5; - args.off_dur = 8; - break; - - case PATTERN_HYPNOSTROBE: - args.on_dur = 14; - args.off_dur = 10; - break; - - case PATTERN_STROBIE: - args.on_dur = 3; - args.off_dur = 23; - break; - - case PATTERN_RAZOR: - args.on_dur = 3; - args.off_dur = 1; - args.gap_dur = 30; // 29 for flashing pattern circles - break; - - case PATTERN_DASH_DOPS: - args.on_dur = 1; - args.off_dur = 9; - args.gap_dur = 6; - args.dash_dur = 15; - break; - - } - - pat.setArgs(args); -} diff --git a/Helios/Patterns.h b/Helios/Patterns.h index 9c0a63c8..5ee105e4 100644 --- a/Helios/Patterns.h +++ b/Helios/Patterns.h @@ -3,40 +3,37 @@ #include -// List of patterns that can be built, both single and multi-led patterns are found in this list. -// Within both single and multi LED pattern lists there are 'core' patterns which are associated -// with a class, and there are 'shell' patterns which are simply wrapperns around another pattern -// with different parameters passed to the constructor. There is no way to know which patterns -// are 'core' patterns, except by looking at PatternBuilder::generate to see which classes exist -enum PatternID : int8_t { - // no pattern at all, use this sparingly and default to - // PATTERN_FIRST when possible - PATTERN_NONE = (PatternID)-1, - - // first pattern of all +/* Forward declaration */ +typedef struct pattern_t pattern_t; + +/* List of patterns that can be built, both single and multi-led patterns are found in this list. + * Within both single and multi LED pattern lists there are 'core' patterns which are associated + * with a class, and there are 'shell' patterns which are simply wrappers around another pattern + * with different parameters passed to the constructor. There is no way to know which patterns + * are 'core' patterns, except by looking at patterns_make_pattern to see which classes exist */ +enum pattern_id { + /* no pattern at all, use this sparingly and default to + * PATTERN_FIRST when possible */ + PATTERN_NONE = -1, + + /* first pattern of all */ PATTERN_FIRST = 0, - // ===================================== + /* ===================================== */ - // Strobe + /* Strobe */ PATTERN_STROBE = PATTERN_FIRST, PATTERN_HYPNOSTROBE, PATTERN_STROBIE, PATTERN_RAZOR, PATTERN_DASH_DOPS, - - - // Meta pattern constants + /* Meta pattern constants */ INTERNAL_PATTERNS_END, PATTERN_LAST = (INTERNAL_PATTERNS_END - 1), - PATTERN_COUNT = (PATTERN_LAST - PATTERN_FIRST) + 1, // total number of patterns + PATTERN_COUNT = (PATTERN_LAST - PATTERN_FIRST) + 1, /* total number of patterns */ }; -class Pattern; +void patterns_make_default(uint8_t index, pattern_t *pat); +void patterns_make_pattern(enum pattern_id id, pattern_t *pat); -class Patterns { - public: - static void make_default(uint8_t index, Pattern &pat); - static void make_pattern(PatternID id, Pattern &pat); -}; #endif diff --git a/Helios/Random.c b/Helios/Random.c new file mode 100644 index 00000000..8950ba08 --- /dev/null +++ b/Helios/Random.c @@ -0,0 +1,43 @@ +#include "Random.h" + +void random_init(random_t *rng) +{ + rng->m_seed = 0; +} + +void random_init_seed(random_t *rng, uint32_t newseed) +{ + random_init(rng); + random_seed(rng, newseed); +} + +void random_seed(random_t *rng, uint32_t newseed) +{ + if (!newseed) { + rng->m_seed = 42; + } else { + rng->m_seed = newseed; + } +} + +uint16_t random_next16(random_t *rng, uint16_t minValue, uint16_t maxValue) +{ + /* walk the LCG forward to the next step */ + rng->m_seed = (rng->m_seed * 1103515245 + 12345) & 0x7FFFFFFF; + uint32_t range = maxValue - minValue; + if (range != 0xFFFFFFFF) { + /* shift the seed 16 bits to the right because the lower 16 bits + * of this LCG are apparently not uniform whatsoever, where as the + * upper 16 bits appear to be quite uniform as per tests. We don't + * really need 32bit random values so we offer max 16bits of entropy */ + return ((rng->m_seed >> 16) % (range + 1)) + minValue; + } + return (rng->m_seed >> 16); +} + +uint8_t random_next8(random_t *rng, uint8_t minValue, uint8_t maxValue) +{ + uint32_t result = random_next16(rng, minValue, maxValue); + return (uint8_t)result; +} + diff --git a/Helios/Random.cpp b/Helios/Random.cpp deleted file mode 100644 index fb10f201..00000000 --- a/Helios/Random.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include "Random.h" - -Random::Random() : - m_seed(0) -{ -} - -Random::Random(uint32_t newseed) : - Random() -{ - seed(newseed); -} - -Random::~Random() -{ -} - -void Random::seed(uint32_t newseed) -{ - if (!newseed) { - m_seed = 42; - } - m_seed = newseed; -} - -uint16_t Random::next16(uint16_t minValue, uint16_t maxValue) -{ - // walk the LCG forward to the next step - m_seed = (m_seed * 1103515245 + 12345) & 0x7FFFFFFF; - uint32_t range = maxValue - minValue; - if (range != 0xFFFFFFFF) { - // shift the seed 16 bits to the right because the lower 16 bits - // of this LCG are apparently not uniform whatsoever, where as the - // upper 16 bits appear to be quite uniform as per tests. We don't - // really need 32bit random values so we offer max 16bits of entropy - return ((m_seed >> 16) % (range + 1)) + minValue; - } - return (m_seed >> 16); -} - -uint8_t Random::next8(uint8_t minValue, uint8_t maxValue) -{ - uint32_t result = next16(minValue, maxValue); - return static_cast(result); -} diff --git a/Helios/Random.h b/Helios/Random.h index 1f556f42..f4fcbca6 100644 --- a/Helios/Random.h +++ b/Helios/Random.h @@ -1,20 +1,28 @@ -#pragma once +#ifndef RANDOM_H +#define RANDOM_H #include -class Random +typedef struct random_t random_t; + +struct random_t { -public: - Random(); - Random(uint32_t newseed); - ~Random(); + uint32_t m_seed; +}; - void seed(uint32_t newseed); +/* Initialize a random struct with default seed */ +void random_init(random_t *rng); - uint8_t next8(uint8_t minValue = 0, uint8_t maxValue = 0xFF); - uint16_t next16(uint16_t minValue = 0, uint16_t maxValue = 0xFFFF); +/* Initialize a random struct with a specific seed */ +void random_init_seed(random_t *rng, uint32_t newseed); -private: - uint32_t m_seed; -}; +/* Set the seed for the random number generator */ +void random_seed(random_t *rng, uint32_t newseed); + +/* Generate next random 8-bit value within range [minValue, maxValue] */ +uint8_t random_next8(random_t *rng, uint8_t minValue, uint8_t maxValue); + +/* Generate next random 16-bit value within range [minValue, maxValue] */ +uint16_t random_next16(random_t *rng, uint16_t minValue, uint16_t maxValue); +#endif diff --git a/Helios/Storage.c b/Helios/Storage.c new file mode 100644 index 00000000..5413c26a --- /dev/null +++ b/Helios/Storage.c @@ -0,0 +1,293 @@ +#include "Storage.h" + +#include "Colorset.h" +#include "Pattern.h" + +#ifdef HELIOS_EMBEDDED +#include +#endif + +#ifdef HELIOS_CLI +#include +#include +#include +#include +#include +#endif + +/* Forward declarations for internal functions */ +static uint8_t storage_crc_pos(uint8_t pos); +static uint8_t storage_read_crc(uint8_t pos); +static uint8_t storage_check_crc(uint8_t pos); +static void storage_write_crc(uint8_t pos); +static void storage_write_byte(uint8_t address, uint8_t data); +static uint8_t storage_read_byte(uint8_t address); + +#ifdef HELIOS_EMBEDDED +static inline uint8_t storage_internal_read(uint8_t address); +static inline void storage_internal_write(uint8_t address, uint8_t data); +#endif + +#ifdef HELIOS_CLI +/* whether storage is enabled, default enabled */ +static uint8_t m_enableStorage = 1; +#endif + +uint8_t storage_init(void) +{ +#ifdef HELIOS_CLI + if (!m_enableStorage) { + return 1; + } + /* if the storage filename doesn't exist then create it */ + if (access(STORAGE_FILENAME, O_RDWR) != 0 && errno == ENOENT) { + /* The file doesn't exist, so try creating it */ + FILE *f = fopen(STORAGE_FILENAME, "w+b"); + if (!f) { + perror("Error creating storage file for write"); + return 0; + } + /* fill the storage with 0s */ + uint32_t i; + for (i = 0; i < STORAGE_SIZE; ++i){ + uint8_t b = 0x0; + fwrite(&b, 1, sizeof(uint8_t), f); + } + fclose(f); + } +#endif + return 1; +} + +uint8_t storage_read_pattern(uint8_t slot, pattern_t *pat) +{ + uint8_t pos = slot * SLOT_SIZE; + if (!storage_check_crc(pos)) { + return 0; + } + uint8_t i; + for (i = 0; i < PATTERN_SIZE; ++i) { + ((uint8_t *)pat)[i] = storage_read_byte(pos + i); + } + return 1; +} + +void storage_write_pattern(uint8_t slot, const pattern_t *pat) +{ + uint8_t pos = slot * SLOT_SIZE; + uint8_t i; + for (i = 0; i < PATTERN_SIZE; ++i) { + uint8_t val = ((uint8_t *)pat)[i]; + uint8_t target = pos + i; + storage_write_byte(target, val); + } + storage_write_crc(pos); +} + +void storage_copy_slot(uint8_t srcSlot, uint8_t dstSlot) +{ + uint8_t src = srcSlot * SLOT_SIZE; + uint8_t dst = dstSlot * SLOT_SIZE; + uint8_t i; + for (i = 0; i < SLOT_SIZE; ++i) { + storage_write_byte(dst + i, storage_read_byte(src + i)); + } +} + +uint8_t storage_read_config(uint8_t index) +{ + return storage_read_byte(CONFIG_START_INDEX - index); +} + +void storage_write_config(uint8_t index, uint8_t val) +{ + storage_write_byte(CONFIG_START_INDEX - index, val); +} + +uint8_t storage_read_global_flags(void) +{ + return storage_read_config(STORAGE_GLOBAL_FLAG_INDEX); +} + +void storage_write_global_flags(uint8_t global_flags) +{ + storage_write_config(STORAGE_GLOBAL_FLAG_INDEX, global_flags); +} + +uint8_t storage_read_current_mode(void) +{ + return storage_read_config(STORAGE_CURRENT_MODE_INDEX); +} + +void storage_write_current_mode(uint8_t current_mode) +{ + storage_write_config(STORAGE_CURRENT_MODE_INDEX, current_mode); +} + +uint8_t storage_read_brightness(void) +{ + return storage_read_config(STORAGE_BRIGHTNESS_INDEX); +} + +void storage_write_brightness(uint8_t brightness) +{ + storage_write_config(STORAGE_BRIGHTNESS_INDEX, brightness); +} + +uint8_t storage_crc8(uint8_t pos, uint8_t size) +{ + uint8_t hash = 33; /* A non-zero initial value */ + uint8_t i; + for (i = 0; i < size; ++i) { + hash = ((hash << 5) + hash) + storage_read_byte(pos); + } + return hash; +} + +static uint8_t storage_crc_pos(uint8_t pos) +{ + /* crc the entire slot except last byte */ + return storage_crc8(pos, PATTERN_SIZE); +} + +static uint8_t storage_read_crc(uint8_t pos) +{ + /* read the last byte of the slot */ + return storage_read_byte(pos + PATTERN_SIZE); +} + +static uint8_t storage_check_crc(uint8_t pos) +{ + /* compare the last byte to the calculated crc */ + return (storage_read_crc(pos) == storage_crc_pos(pos)); +} + +static void storage_write_crc(uint8_t pos) +{ + /* compare the last byte to the calculated crc */ + storage_write_byte(pos + PATTERN_SIZE, storage_crc_pos(pos)); +} + +static void storage_write_byte(uint8_t address, uint8_t data) +{ +#ifdef HELIOS_EMBEDDED + /* reads out the byte of the eeprom first to see if it's different + * before writing out the byte -- this is faster than always writing */ + if (storage_read_byte(address) == data) { + return; + } + storage_internal_write(address, data); + /* double check that shit */ + if (storage_read_byte(address) != data) { + /* do it again because eeprom is stupid */ + storage_internal_write(address, data); + /* god forbid it doesn't write again */ + } +#else /* HELIOS_CLI */ + if (!m_enableStorage) { + return; + } + FILE *f = fopen(STORAGE_FILENAME, "r+b"); + if (!f) { + perror("Error opening storage file"); + return; + } + /* Seek to the specified address */ + if (fseek(f, address, SEEK_SET) != 0) { + perror("Error opening storage file for write"); + fclose(f); + return; + } + if (!fwrite((const void *)&data, sizeof(uint8_t), 1, f)) { + fclose(f); + return; + } + fclose(f); /* Close the file */ +#endif +} + +static uint8_t storage_read_byte(uint8_t address) +{ +#ifdef HELIOS_EMBEDDED + /* do a three way read because the attiny85 eeprom basically doesn't work */ + uint8_t b1 = storage_internal_read(address); + uint8_t b2 = storage_internal_read(address); + if (b1 == b2) { + return b2; + } + uint8_t b3 = storage_internal_read(address); + if (b3 == b1) { + return b1; + } + if (b3 == b2) { + return b2; + } + return 0; +#else + if (!m_enableStorage) { + return 0; + } + uint8_t val = 0; + if (access(STORAGE_FILENAME, O_RDONLY) != 0) { + return val; + } + FILE *f = fopen(STORAGE_FILENAME, "rb"); /* Open file for reading in binary mode */ + if (!f) { + /* this error is ok, just means no storage */ + /* perror("Error opening file for read"); */ + return val; + } + /* Seek to the specified address */ + if (fseek(f, address, SEEK_SET) != 0) { + /* error */ + perror("Failed to seek"); + fclose(f); + return val; + } + /* Read a byte of data */ + if (!fread(&val, sizeof(uint8_t), 1, f)) { + perror("Failed to read byte"); + } + fclose(f); /* Close the file */ + return val; +#endif +} + +#ifdef HELIOS_EMBEDDED +static inline void storage_internal_write(uint8_t address, uint8_t data) +{ + while (EECR & (1< -#endif - -#ifdef HELIOS_CLI -#include -#include -#include -#include -#include -#endif - -#ifdef HELIOS_CLI -// whether storage is enabled, default enabled -bool Storage::m_enableStorage = true; -#endif - -bool Storage::init() -{ -#ifdef HELIOS_CLI - if (!m_enableStorage) { - return true; - } - // if the storage filename doesn't exist then create it - if (access(STORAGE_FILENAME, O_RDWR) != 0 && errno == ENOENT) { - // The file doesn't exist, so try creating it - FILE *f = fopen(STORAGE_FILENAME, "w+b"); - if (!f) { - perror("Error creating storage file for write"); - return false; - } - // fill the storage with 0s - for (uint32_t i = 0; i < STORAGE_SIZE; ++i){ - uint8_t b = 0x0; - fwrite(&b, 1, sizeof(uint8_t), f); - } - fclose(f); - } -#endif - return true; -} - -bool Storage::read_pattern(uint8_t slot, Pattern &pat) -{ - uint8_t pos = slot * SLOT_SIZE; - if (!check_crc(pos)) { - return false; - } - for (uint8_t i = 0; i < PATTERN_SIZE; ++i) { - ((uint8_t *)&pat)[i] = read_byte(pos + i); - } - return true; -} - -void Storage::write_pattern(uint8_t slot, const Pattern &pat) -{ - uint8_t pos = slot * SLOT_SIZE; - for (uint8_t i = 0; i < PATTERN_SIZE; ++i) { - uint8_t val = ((uint8_t *)&pat)[i]; - uint8_t target = pos + i; - write_byte(target, val); - } - write_crc(pos); -} - -void Storage::copy_slot(uint8_t srcSlot, uint8_t dstSlot) -{ - uint8_t src = srcSlot * SLOT_SIZE; - uint8_t dst = dstSlot * SLOT_SIZE; - for (uint8_t i = 0; i < SLOT_SIZE; ++i) { - write_byte(dst + i, read_byte(src + i)); - } -} - -uint8_t Storage::read_config(uint8_t index) -{ - return read_byte(CONFIG_START_INDEX - index); -} - -void Storage::write_config(uint8_t index, uint8_t val) -{ - write_byte(CONFIG_START_INDEX - index, val); -} - -uint8_t Storage::crc8(uint8_t pos, uint8_t size) -{ - uint8_t hash = 33; // A non-zero initial value - for (uint8_t i = 0; i < size; ++i) { - hash = ((hash << 5) + hash) + read_byte(pos); - } - return hash; -} - -uint8_t Storage::crc_pos(uint8_t pos) -{ - // crc the entire slot except last byte - return crc8(pos, PATTERN_SIZE); -} - -uint8_t Storage::read_crc(uint8_t pos) -{ - // read the last byte of the slot - return read_byte(pos + PATTERN_SIZE); -} - -bool Storage::check_crc(uint8_t pos) -{ - // compare the last byte to the calculated crc - return (read_crc(pos) == crc_pos(pos)); -} - -void Storage::write_crc(uint8_t pos) -{ - // compare the last byte to the calculated crc - write_byte(pos + PATTERN_SIZE, crc_pos(pos)); -} - -void Storage::write_byte(uint8_t address, uint8_t data) -{ -#ifdef HELIOS_EMBEDDED - // reads out the byte of the eeprom first to see if it's different - // before writing out the byte -- this is faster than always writing - if (read_byte(address) == data) { - return; - } - internal_write(address, data); - // double check that shit - if (read_byte(address) != data) { - // do it again because eeprom is stupid - internal_write(address, data); - // god forbid it doesn't write again - } -#else // HELIOS_CLI - if (!m_enableStorage) { - return; - } - FILE *f = fopen(STORAGE_FILENAME, "r+b"); - if (!f) { - perror("Error opening storage file"); - return; - } - // Seek to the specified address - if (fseek(f, address, SEEK_SET) != 0) { - perror("Error opening storage file for write"); - fclose(f); - return; - } - if (!fwrite((const void *)&data, sizeof(uint8_t), 1, f)) { - return; - } - fclose(f); // Close the file -#endif -} - -uint8_t Storage::read_byte(uint8_t address) -{ -#ifdef HELIOS_EMBEDDED - // do a three way read because the attiny85 eeprom basically doesn't work - uint8_t b1 = internal_read(address); - uint8_t b2 = internal_read(address); - if (b1 == b2) { - return b2; - } - uint8_t b3 = internal_read(address); - if (b3 == b1) { - return b1; - } - if (b3 == b2) { - return b2; - } - return 0; -#else - if (!m_enableStorage) { - return 0; - } - uint8_t val = 0; - if (access(STORAGE_FILENAME, O_RDONLY) != 0) { - return val; - } - FILE *f = fopen(STORAGE_FILENAME, "rb"); // Open file for reading in binary mode - if (!f) { - // this error is ok, just means no storage - //perror("Error opening file for read"); - return val; - } - // Seek to the specified address - if (fseek(f, address, SEEK_SET) != 0) { - // error - perror("Failed to seek"); - fclose(f); - return val; - } - // Read a byte of data - if (!fread(&val, sizeof(uint8_t), 1, f)) { - perror("Failed to read byte"); - } - fclose(f); // Close the file - return val; -#endif -} - -#ifdef HELIOS_EMBEDDED -inline void Storage::internal_write(uint8_t address, uint8_t data) -{ - while (EECR & (1< #include "HeliosConfig.h" -// the index of the first config byte, the config bytes start at the end -// then work their way backwards (so 'config index 0' is the last byte) +/* the index of the first config byte, the config bytes start at the end + * then work their way backwards (so 'config index 0' is the last byte) */ #define CONFIG_START_INDEX (STORAGE_SIZE - 2) -// the crc of the config bytes is the very last byte in storage -// TODO: implement the global config CRC again it got removed at some point +/* the crc of the config bytes is the very last byte in storage + * TODO: implement the global config CRC again it got removed at some point */ #define CONFIG_CRC_INDEX (STORAGE_SIZE - 1) -// Storage Config Indexes relative to the CONFIG_START_INDEX +/* Storage Config Indexes relative to the CONFIG_START_INDEX */ #define STORAGE_GLOBAL_FLAG_INDEX 0 #define STORAGE_CURRENT_MODE_INDEX 1 #define STORAGE_BRIGHTNESS_INDEX 2 -class Pattern; +/* Forward declaration */ +typedef struct pattern_t pattern_t; -class Storage -{ -public: +uint8_t storage_init(void); - static bool init(); +uint8_t storage_read_pattern(uint8_t slot, pattern_t *pat); +void storage_write_pattern(uint8_t slot, const pattern_t *pat); - static bool read_pattern(uint8_t slot, Pattern &pat); - static void write_pattern(uint8_t slot, const Pattern &pat); +void storage_copy_slot(uint8_t srcSlot, uint8_t dstSlot); - static void copy_slot(uint8_t srcSlot, uint8_t dstSlot); +uint8_t storage_read_config(uint8_t index); +void storage_write_config(uint8_t index, uint8_t val); - static uint8_t read_config(uint8_t index); - static void write_config(uint8_t index, uint8_t val); +uint8_t storage_read_global_flags(void); +void storage_write_global_flags(uint8_t global_flags); - static uint8_t read_global_flags() { return read_config(STORAGE_GLOBAL_FLAG_INDEX); } - static void write_global_flags(uint8_t global_flags) { write_config(STORAGE_GLOBAL_FLAG_INDEX, global_flags); } +uint8_t storage_read_current_mode(void); +void storage_write_current_mode(uint8_t current_mode); - static uint8_t read_current_mode() { return read_config(STORAGE_CURRENT_MODE_INDEX); } - static void write_current_mode(uint8_t current_mode) { write_config(STORAGE_CURRENT_MODE_INDEX, current_mode); } +uint8_t storage_read_brightness(void); +void storage_write_brightness(uint8_t brightness); - static uint8_t read_brightness() { return read_config(STORAGE_BRIGHTNESS_INDEX); } - static void write_brightness(uint8_t brightness) { write_config(STORAGE_BRIGHTNESS_INDEX, brightness); } - - static uint8_t crc8(uint8_t pos, uint8_t size); - -#ifdef HELIOS_CLI - // toggle storage on/off - static void enableStorage(bool enabled) { m_enableStorage = enabled; } -#endif -private: - static uint8_t crc_pos(uint8_t pos); - static uint8_t read_crc(uint8_t pos); - static bool check_crc(uint8_t pos); - static void write_crc(uint8_t pos); - - static void write_byte(uint8_t address, uint8_t data); - static uint8_t read_byte(uint8_t address); - -#ifdef HELIOS_EMBEDDED - static inline uint8_t internal_read(uint8_t address); - static inline void internal_write(uint8_t address, uint8_t data); -#endif +uint8_t storage_crc8(uint8_t pos, uint8_t size); #ifdef HELIOS_CLI - // whether storage is enabled - static bool m_enableStorage; +/* toggle storage on/off */ +void storage_enable_storage(uint8_t enabled); #endif -}; #endif diff --git a/Helios/TimeControl.c b/Helios/TimeControl.c new file mode 100644 index 00000000..11033b2d --- /dev/null +++ b/Helios/TimeControl.c @@ -0,0 +1,197 @@ +#include "TimeControl.h" + +#include + +#include "Timings.h" + +#include "Led.h" + +#ifdef HELIOS_EMBEDDED +#include +#include +#ifdef HELIOS_ARDUINO +#include +#endif +#endif + +#ifdef HELIOS_CLI +#include +#include +static uint64_t start = 0; +/* convert seconds and nanoseconds to microseconds */ +#define SEC_TO_US(sec) ((sec)*1000000) +#define NS_TO_US(ns) ((ns)/1000) +#endif + +/* static members */ +static uint32_t m_curTick = 0; +/* the last frame timestamp */ +static uint32_t m_prevTime = 0; + +#ifdef HELIOS_CLI +/* whether timestep is enabled, default enabled */ +static uint8_t m_enableTimestep = 1; +#endif + +uint8_t Time_init(void) +{ + m_prevTime = Time_microseconds(); + m_curTick = 0; + return 1; +} + +void Time_cleanup(void) +{ +} + +void Time_tickClock(void) +{ + /* tick clock forward */ + m_curTick++; + +#ifdef HELIOS_CLI + if (!m_enableTimestep) { + return; + } +#endif + + /* the rest of this only runs inside vortexlib because on the duo the tick runs in the + * tcb timer callback instead of in a busy loop constantly checking microseconds() + * perform timestep */ + uint32_t elapsed_us; + uint32_t us; + do { + us = Time_microseconds(); + /* detect rollover of microsecond counter */ + if (us < m_prevTime) { + /* calculate wrapped around difference */ + elapsed_us = (uint32_t)((UINT32_MAX - m_prevTime) + us); + } else { + /* otherwise calculate regular difference */ + elapsed_us = (uint32_t)(us - m_prevTime); + } + /* if building anywhere except visual studio then we can run alternate sleep code + * because in visual studio + windows it's better to just spin and check the high + * resolution clock instead of trying to sleep for microseconds. + * 1000us per ms, divided by tickrate gives + * the number of microseconds per tick */ + } while (elapsed_us < (1000000 / TICKRATE)); + + /* store current time */ + m_prevTime = Time_microseconds(); +} + +uint32_t Time_getCurtime(void) +{ + return m_curTick; +} + +#ifdef HELIOS_EMBEDDED +volatile uint32_t timer0_overflow_count = 0; +ISR(TIMER0_OVF_vect) { + timer0_overflow_count++; /* Increment on each overflow */ +} +#endif + +uint32_t Time_microseconds(void) +{ +#ifdef HELIOS_CLI + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + uint64_t us = SEC_TO_US((uint64_t)ts.tv_sec) + NS_TO_US((uint64_t)ts.tv_nsec); + return (unsigned long)us; +#else +#ifdef HELIOS_ARDUINO + return micros(); +#else + /* The only reason that micros() is actually necessary is if Helios::tick() + * cannot be called in a 1Khz ISR. If Helios::tick() cannot be reliably called + * by an interrupt then Time::tickClock() must perform manual timestep via micros(). + * If Helios::tick() is called by an interrupt then you don't need this function and + * should always just rely on the current tick to perform operations */ + uint8_t oldSREG = SREG; + cli(); + /* multiply by 8 early to avoid floating point math or division */ + uint32_t micros = (timer0_overflow_count * (256 * 8)) + (TCNT0 * 8); + SREG = oldSREG; + /* then shift right to counteract the multiplication by 8 */ + return micros >> 6; +#endif +#endif +} + +#ifdef HELIOS_EMBEDDED +__attribute__((noinline)) +#endif +void +Time_delayMicroseconds(uint32_t us) +{ +#ifdef HELIOS_EMBEDDED +#if F_CPU >= 16000000L + /* For the ATtiny85 running at 16MHz */ + + /* The loop takes 3 cycles per iteration */ + us *= 2; /* 0.5us per iteration */ + + /* Subtract the overhead of the function call and loop setup + * Assuming approximately 5 cycles overhead */ + us -= 5; /* Simplified subtraction */ + + /* Assembly loop for delay */ + __asm__ __volatile__( + "1: sbiw %0, 1" + "\n\t" /* 2 cycles */ + "nop" + "\n\t" /* 1 cycle */ + "brne 1b" : "=w"(us) : "0"(us) /* 2 cycles */ + ); + +#elif F_CPU >= 8000000L + /* For the ATtiny85 running at 8MHz */ + + /* The loop takes 4 cycles per iteration */ + us <<= 1; /* 1us per iteration */ + + /* Subtract the overhead of the function call and loop setup + * Assuming approximately 6 cycles overhead */ + us -= 6; /* Simplified subtraction */ + + /* Assembly loop for delay */ + __asm__ __volatile__( + "1: sbiw %0, 1" + "\n\t" /* 2 cycles */ + "rjmp .+0" + "\n\t" /* 2 cycles */ + "brne 1b" : "=w"(us) : "0"(us) /* 2 cycles */ + ); +#endif + +#else + uint32_t newtime = Time_microseconds() + us; + while (Time_microseconds() < newtime) + { + /* busy loop */ + } +#endif +} + +void Time_delayMilliseconds(uint32_t ms) +{ +#ifdef HELIOS_CLI + usleep(ms * 1000); +#else + /* not very accurate */ + uint16_t i; + for (i = 0; i < ms; ++i) { + Time_delayMicroseconds(1000); + } +#endif +} + +#ifdef HELIOS_CLI +void Time_enableTimestep(uint8_t enabled) +{ + m_enableTimestep = enabled; +} +#endif + diff --git a/Helios/TimeControl.cpp b/Helios/TimeControl.cpp deleted file mode 100644 index 904be2a3..00000000 --- a/Helios/TimeControl.cpp +++ /dev/null @@ -1,183 +0,0 @@ -#include "TimeControl.h" - -#include - -#include "Timings.h" - -#include "Led.h" - -#ifdef HELIOS_EMBEDDED -#include -#include -#ifdef HELIOS_ARDUINO -#include -#endif -#endif - -#ifdef HELIOS_CLI -#include -#include -uint64_t start = 0; -// convert seconds and nanoseconds to microseconds -#define SEC_TO_US(sec) ((sec)*1000000) -#define NS_TO_US(ns) ((ns)/1000) -#endif - -// static members -uint32_t Time::m_curTick = 0; -// the last frame timestamp -uint32_t Time::m_prevTime = 0; - -#ifdef HELIOS_CLI -// whether timestep is enabled, default enabled -bool Time::m_enableTimestep = true; -#endif - -bool Time::init() -{ - m_prevTime = microseconds(); - m_curTick = 0; - return true; -} - -void Time::cleanup() -{ -} - -void Time::tickClock() -{ - // tick clock forward - m_curTick++; - -#ifdef HELIOS_CLI - if (!m_enableTimestep) { - return; - } -#endif - - // the rest of this only runs inside vortexlib because on the duo the tick runs in the - // tcb timer callback instead of in a busy loop constantly checking microseconds() - // perform timestep - uint32_t elapsed_us; - uint32_t us; - do { - us = microseconds(); - // detect rollover of microsecond counter - if (us < m_prevTime) { - // calculate wrapped around difference - elapsed_us = (uint32_t)((UINT32_MAX - m_prevTime) + us); - } else { - // otherwise calculate regular difference - elapsed_us = (uint32_t)(us - m_prevTime); - } - // if building anywhere except visual studio then we can run alternate sleep code - // because in visual studio + windows it's better to just spin and check the high - // resolution clock instead of trying to sleep for microseconds. - // 1000us per ms, divided by tickrate gives - // the number of microseconds per tick - } while (elapsed_us < (1000000 / TICKRATE)); - - // store current time - m_prevTime = microseconds(); -} - -#ifdef HELIOS_EMBEDDED -volatile uint32_t timer0_overflow_count = 0; -ISR(TIMER0_OVF_vect) { - timer0_overflow_count++; // Increment on each overflow -} -#endif - -uint32_t Time::microseconds() -{ -#ifdef HELIOS_CLI - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - uint64_t us = SEC_TO_US((uint64_t)ts.tv_sec) + NS_TO_US((uint64_t)ts.tv_nsec); - return (unsigned long)us; -#else -#ifdef HELIOS_ARDUINO - return micros(); -#else - // The only reason that micros() is actually necessary is if Helios::tick() - // cannot be called in a 1Khz ISR. If Helios::tick() cannot be reliably called - // by an interrupt then Time::tickClock() must perform manual timestep via micros(). - // If Helios::tick() is called by an interrupt then you don't need this function and - // should always just rely on the current tick to perform operations - uint8_t oldSREG = SREG; - cli(); - // multiply by 8 early to avoid floating point math or division - uint32_t micros = (timer0_overflow_count * (256 * 8)) + (TCNT0 * 8); - SREG = oldSREG; - // then shift right to counteract the multiplication by 8 - return micros >> 6; -#endif -#endif -} - -#ifdef HELIOS_EMBEDDED -__attribute__((noinline)) -#endif -void -Time::delayMicroseconds(uint32_t us) -{ -#ifdef HELIOS_EMBEDDED -#if F_CPU >= 16000000L - // For the ATtiny85 running at 16MHz - - // The loop takes 3 cycles per iteration - us *= 2; // 0.5us per iteration - - // Subtract the overhead of the function call and loop setup - // Assuming approximately 5 cycles overhead - us -= 5; // Simplified subtraction - - // Assembly loop for delay - __asm__ __volatile__( - "1: sbiw %0, 1" - "\n\t" // 2 cycles - "nop" - "\n\t" // 1 cycle - "brne 1b" : "=w"(us) : "0"(us) // 2 cycles - ); - -#elif F_CPU >= 8000000L - // For the ATtiny85 running at 8MHz - - // The loop takes 4 cycles per iteration - us <<= 1; // 1us per iteration - - // Subtract the overhead of the function call and loop setup - // Assuming approximately 6 cycles overhead - us -= 6; // Simplified subtraction - - // Assembly loop for delay - __asm__ __volatile__( - "1: sbiw %0, 1" - "\n\t" // 2 cycles - "rjmp .+0" - "\n\t" // 2 cycles - "brne 1b" : "=w"(us) : "0"(us) // 2 cycles - ); -#endif - -#else - uint32_t newtime = microseconds() + us; - while (microseconds() < newtime) - { - // busy loop - } -#endif -} - -void Time::delayMilliseconds(uint32_t ms) -{ -#ifdef HELIOS_CLI - usleep(ms * 1000); -#else - // not very accurate - for (uint16_t i = 0; i < ms; ++i) { - delayMicroseconds(1000); - } -#endif -} diff --git a/Helios/TimeControl.h b/Helios/TimeControl.h index b5f316d8..6a5a42c8 100644 --- a/Helios/TimeControl.h +++ b/Helios/TimeControl.h @@ -5,55 +5,35 @@ #include "HeliosConfig.h" -// macros to convert milliseconds and seconds to measures of ticks +/* macros to convert milliseconds and seconds to measures of ticks */ #define MS_TO_TICKS(ms) (uint32_t)(((uint32_t)(ms) * TICKRATE) / 1000) #define SEC_TO_TICKS(s) (uint32_t)((uint32_t)(s) * TICKRATE) -class Time -{ - // private unimplemented constructor - Time(); +/* Initialize time system */ +uint8_t Time_init(void); +void Time_cleanup(void); -public: - // opting for static class here because there should only ever be one - // Settings control object and I don't like singletons - static bool init(); - static void cleanup(); +/* Tick the clock forward to millis() */ +void Time_tickClock(void); - // tick the clock forward to millis() - static void tickClock(); +/* Get the current tick, offset by any active simulation (simulation only exists in vortexlib) + * Exposing this as inline or macro seems to save on space a non negligible amount, it is used a lot + * and exposing in the header probably allows the compiler to optimize away repetitive calls */ +uint32_t Time_getCurtime(void); - // get the current tick, offset by any active simulation (simulation only exists in vortexlib) - // Exposing this in the header seems to save on space a non negligible amount, it is used a lot - // and exposing in the header probably allows the compiler to optimize away repititive calls - static uint32_t getCurtime() { return m_curTick; } +/* Current microseconds since startup, only use this for things like measuring rapid data transfer timings. + * If you just need to perform regular time checks for a pattern or some logic then use Time_getCurtime() and measure + * time in ticks, use the SEC_TO_TICKS() or MS_TO_TICKS() macros to convert timings to measures of ticks for + * purpose of comparing against Time_getCurtime() */ +uint32_t Time_microseconds(void); - // Current microseconds since startup, only use this for things like measuring rapid data transfer timings. - // If you just need to perform regular time checks for a pattern or some logic then use getCurtime() and measure - // time in ticks, use the SEC_TO_TICKS() or MS_TO_TICKS() macros to convert timings to measures of ticks for - // purpose of comparing against getCurtime() - static uint32_t microseconds(); - - // delay for some number of microseconds or milliseconds, these are bad - static void delayMicroseconds(uint32_t us); - static void delayMilliseconds(uint32_t ms); - -#ifdef HELIOS_CLI - // toggle timestep on/off - static void enableTimestep(bool enabled) { m_enableTimestep = enabled; } -#endif - -private: - // global tick counter - static uint32_t m_curTick; - // the last frame timestamp - static uint32_t m_prevTime; +/* Delay for some number of microseconds or milliseconds, these are bad */ +void Time_delayMicroseconds(uint32_t us); +void Time_delayMilliseconds(uint32_t ms); #ifdef HELIOS_CLI - // whether timestep is enabled - static bool m_enableTimestep; +/* Toggle timestep on/off */ +void Time_enableTimestep(uint8_t enabled); #endif -}; #endif - diff --git a/Helios/Timer.c b/Helios/Timer.c new file mode 100644 index 00000000..45889b14 --- /dev/null +++ b/Helios/Timer.c @@ -0,0 +1,56 @@ +#include + +#include "Timer.h" + +#include "TimeControl.h" + +void timer_init_default(timer_t *timer) +{ + timer->m_alarm = 0; + timer->m_startTime = 0; +} + +void timer_init(timer_t *timer, uint8_t alarm) +{ + timer_reset(timer); + timer->m_alarm = alarm; + timer_start(timer, 0); +} + +void timer_start(timer_t *timer, uint32_t offset) +{ + /* reset the start time */ + timer->m_startTime = Time_getCurtime() + offset; +} + +void timer_reset(timer_t *timer) +{ + timer->m_alarm = 0; + timer->m_startTime = 0; +} + +uint8_t timer_alarm(timer_t *timer) +{ + if (!timer->m_alarm) { + return 0; + } + uint32_t now = Time_getCurtime(); + /* time since start (forward or backwards) */ + int32_t timeDiff = (int32_t)(int64_t)(now - timer->m_startTime); + if (timeDiff < 0) { + return 0; + } + /* if no time passed it's first alarm that is starting */ + if (timeDiff == 0) { + return 1; + } + /* if the current alarm duration is not a multiple of the current tick */ + if (timer->m_alarm && (timeDiff % timer->m_alarm) != 0) { + /* then the alarm was not hit */ + return 0; + } + /* update the start time of the timer */ + timer->m_startTime = now; + return 1; +} + diff --git a/Helios/Timer.cpp b/Helios/Timer.cpp deleted file mode 100644 index 48dd685b..00000000 --- a/Helios/Timer.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include - -#include "Timer.h" - -#include "TimeControl.h" - -Timer::Timer() : - m_alarm(0), - m_startTime(0) -{ -} - -Timer::~Timer() -{ -} - -void Timer::init(uint8_t alarm) -{ - reset(); - m_alarm = alarm; - start(); -} - -void Timer::start(uint32_t offset) -{ - // reset the start time - m_startTime = Time::getCurtime() + offset; -} - -void Timer::reset() -{ - m_alarm = 0; - m_startTime = 0; -} - -bool Timer::alarm() -{ - if (!m_alarm) { - return false; - } - uint32_t now = Time::getCurtime(); - // time since start (forward or backwards) - int32_t timeDiff = (int32_t)(int64_t)(now - m_startTime); - if (timeDiff < 0) { - return false; - } - // if no time passed it's first alarm that is starting - if (timeDiff == 0) { - return true; - } - // if the current alarm duration is not a multiple of the current tick - if (m_alarm && (timeDiff % m_alarm) != 0) { - // then the alarm was not hit - return false; - } - // update the start time of the timer - m_startTime = now; - return true; -} diff --git a/Helios/Timer.h b/Helios/Timer.h index 92a19a52..46b8394e 100644 --- a/Helios/Timer.h +++ b/Helios/Timer.h @@ -3,28 +3,30 @@ #include -class Timer +typedef struct timer_t timer_t; + +struct timer_t { -public: - Timer(); - ~Timer(); - - // init a timer with a number of alarms and optionally start it - void init(uint8_t alarm); - - // start the timer but don't change current alarm, this shifts - // the timer startTime but does not reset it's alarm state - void start(uint32_t offset = 0); - // delete all alarms from the timer and reset - void reset(); - // Will return the true if the timer hit - bool alarm(); - -private: - // the alarm + /* the alarm */ uint32_t m_alarm; - // start time in microseconds + /* start time in microseconds */ uint32_t m_startTime; }; +/* Initialize a timer struct to default values */ +void timer_init_default(timer_t *timer); + +/* Init a timer with a number of alarms and optionally start it */ +void timer_init(timer_t *timer, uint8_t alarm); + +/* Start the timer but don't change current alarm, this shifts + * the timer startTime but does not reset it's alarm state */ +void timer_start(timer_t *timer, uint32_t offset); + +/* Delete all alarms from the timer and reset */ +void timer_reset(timer_t *timer); + +/* Will return true if the timer hit */ +uint8_t timer_alarm(timer_t *timer); + #endif diff --git a/HeliosEmbedded/Makefile b/HeliosEmbedded/Makefile index d6e47a98..c89c5586 100644 --- a/HeliosEmbedded/Makefile +++ b/HeliosEmbedded/Makefile @@ -46,8 +46,8 @@ endif ### TOOLCHAIN SETUP ### ####################### -CC = ${BINDIR}avr-g++ -LD = ${BINDIR}avr-g++ +CC = ${BINDIR}avr-gcc +LD = ${BINDIR}avr-gcc OBJCOPY = ${BINDIR}avr-objcopy -v AR = ${BINDIR}avr-gcc-ar SIZE = ${BINDIR}avr-size @@ -117,15 +117,13 @@ CFLAGS = -g \ -Wall \ -flto \ -mrelax \ - -std=gnu++17 \ + -std=c11 \ -fshort-enums \ -fpack-struct \ - -fno-exceptions \ -fdata-sections \ -funsigned-char \ -ffunction-sections\ -funsigned-bitfields \ - -fno-threadsafe-statics \ -mcall-prologues \ -D__AVR_ATtiny85__ \ -mmcu=$(AVRDUDE_CHIP) \ @@ -162,15 +160,15 @@ CFLAGS+=$(INCLUDES) # Source files ifeq ($(OS),Windows_NT) # Windows SRCS = \ - $(shell find ../Helios -maxdepth 1 -type f -name '\*.cpp') main.cpp + $(shell find ../Helios -maxdepth 1 -type f -name '\*.c') main.c else # linux SRCS = \ - $(shell find ../Helios -maxdepth 1 -type f -name \*.cpp) main.cpp + $(shell find ../Helios -maxdepth 1 -type f -name \*.c) main.c endif -OBJS = $(SRCS:.cpp=.o) +OBJS = $(SRCS:.c=.o) -DFILES = $(SRCS:.cpp=.d) +DFILES = $(SRCS:.c=.d) ####################### ### BUILD TARGETS ##### @@ -198,7 +196,7 @@ $(TARGET).elf: compute_version $(OBJS) %.o: %.S $(CC) $(ASMFLAGS) -c $< -o $@ -%.o: %.cpp +%.o: %.c $(CC) $(CFLAGS) -c $< -o $@ upload: set_fuses $(TARGET).hex diff --git a/HeliosEmbedded/main.c b/HeliosEmbedded/main.c new file mode 100644 index 00000000..d537ca01 --- /dev/null +++ b/HeliosEmbedded/main.c @@ -0,0 +1,21 @@ +#include "Helios.h" +#include "Led.h" + +#include + +#if !defined(HELIOS_CLI) && !defined(HELIOS_ARDUINO) +/* this is the main thread for non-arduino embedded builds */ +int main(int argc, char *argv[]) +{ + (void)argc; /* unused */ + (void)argv; /* unused */ + + helios_init(); + /* the main thread just initializes Helios then continuously calls tick */ + while (helios_keep_going()) { + helios_tick(); + } + return 0; +} +#endif + diff --git a/HeliosEmbedded/main.cpp b/HeliosEmbedded/main.cpp deleted file mode 100644 index 391fdf1b..00000000 --- a/HeliosEmbedded/main.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "Helios.h" -#include "Led.h" - -#include - -#if !defined(HELIOS_CLI) && !defined(HELIOS_ARDUINO) -// this is the main thread for non-arduino embedded builds -int main(int argc, char *argv[]) -{ - Helios::init(); - // the main thread just initializes Helios then continuously calls tick - while (Helios::keep_going()) { - Helios::tick(); - } - return 0; -} -#endif From a6a4874b5e63a24398ff972b504802915f93e140 Mon Sep 17 00:00:00 2001 From: Kurt LaVacque Date: Thu, 16 Oct 2025 22:15:58 +0200 Subject: [PATCH 02/17] Refactor time handling in Helios codebase - Replaced all instances of Time_getCurtime(), Time_init(), and related functions with their lowercase counterparts (time_get_current_time(), time_init(), etc.) for consistency and improved readability. - Updated function calls across multiple files including Button.c, Helios.c, Led.c, Pattern.c, TimeControl.c, and Timer.c to reflect the new naming conventions. - These changes enhance code clarity and maintainability while adhering to the KISS principle. --- Helios/Button.c | 14 +++++++------- Helios/Helios.c | 12 ++++++------ Helios/Led.c | 6 +++--- Helios/Pattern.c | 4 ++-- Helios/TimeControl.c | 28 ++++++++++++++-------------- Helios/TimeControl.h | 20 ++++++++++---------- Helios/Timer.c | 4 ++-- 7 files changed, 44 insertions(+), 44 deletions(-) diff --git a/Helios/Button.c b/Helios/Button.c index 60dea676..3ea1f9f2 100644 --- a/Helios/Button.c +++ b/Helios/Button.c @@ -140,18 +140,18 @@ void button_update(void) m_buttonState = newButtonState; m_isPressed = m_buttonState; if (m_isPressed) { - m_pressTime = Time_getCurtime(); + m_pressTime = time_get_current_time(); m_newPress = 1; } else { - m_releaseTime = Time_getCurtime(); + m_releaseTime = time_get_current_time(); m_newRelease = 1; m_releaseCount++; } } if (m_isPressed) { - m_holdDuration = (Time_getCurtime() >= m_pressTime) ? (uint32_t)(Time_getCurtime() - m_pressTime) : 0; + m_holdDuration = (time_get_current_time() >= m_pressTime) ? (uint32_t)(time_get_current_time() - m_pressTime) : 0; } else { - m_releaseDuration = (Time_getCurtime() >= m_releaseTime) ? (uint32_t)(Time_getCurtime() - m_releaseTime) : 0; + m_releaseDuration = (time_get_current_time() >= m_releaseTime) ? (uint32_t)(time_get_current_time() - m_releaseTime) : 0; } m_shortClick = (m_newRelease && (m_holdDuration <= SHORT_CLICK_THRESHOLD)); m_longClick = (m_newRelease && (m_holdDuration > SHORT_CLICK_THRESHOLD) && (m_holdDuration < HOLD_CLICK_START)); @@ -287,7 +287,7 @@ void button_do_short_click(void) { m_newRelease = 1; m_shortClick = 1; - m_pressTime = Time_getCurtime(); + m_pressTime = time_get_current_time(); m_holdDuration = SHORT_CLICK_THRESHOLD - 1; m_releaseCount++; } @@ -296,7 +296,7 @@ void button_do_long_click(void) { m_newRelease = 1; m_longClick = 1; - m_pressTime = Time_getCurtime(); + m_pressTime = time_get_current_time(); m_holdDuration = SHORT_CLICK_THRESHOLD + 1; m_releaseCount++; } @@ -305,7 +305,7 @@ void button_do_hold_click(void) { m_newRelease = 1; m_holdClick = 1; - m_pressTime = Time_getCurtime(); + m_pressTime = time_get_current_time(); m_holdDuration = HOLD_CLICK_START + 1; m_releaseCount++; } diff --git a/Helios/Helios.c b/Helios/Helios.c index 68e0d822..6949709c 100644 --- a/Helios/Helios.c +++ b/Helios/Helios.c @@ -114,7 +114,7 @@ uint8_t helios_init(void) static uint8_t helios_init_components(void) { /* initialize various components of Helios */ - if (!Time_init()) { + if (!time_init()) { return 0; } if (!led_init()) { @@ -158,7 +158,7 @@ void helios_tick(void) /* finally tick the clock forward and then sleep till the entire * tick duration has been consumed */ - Time_tickClock(); + time_tick_clock(); } void helios_enter_sleep(void) @@ -198,7 +198,7 @@ void helios_wakeup(void) * but if we re-initialize the button it will clear this state */ uint8_t pressed = button_is_pressed(); /* re-initialize some stuff */ - Time_init(); + time_init(); button_init(); /* so just re-press it */ if (pressed) { @@ -230,7 +230,7 @@ void helios_load_cur_mode(void) /* then re-initialize the pattern */ pattern_init_state(&pat); /* Update the last mode switch time when loading a mode */ - last_mode_switch_time = Time_getCurtime(); + last_mode_switch_time = time_get_current_time(); } void helios_save_cur_mode(void) @@ -667,9 +667,9 @@ static void helios_handle_state_set_defaults(void) static void helios_show_selection(rgb_color_t color) { - uint32_t time_since_click = Time_getCurtime(); + uint32_t time_since_click = time_get_current_time(); if (button_press_time() > 0) { - time_since_click = Time_getCurtime() - button_press_time(); + time_since_click = time_get_current_time() - button_press_time(); } /* flash the selection color briefly after clicking */ if (time_since_click < 150) { diff --git a/Helios/Led.c b/Helios/Led.c index 6ca3d584..06ec5841 100644 --- a/Helios/Led.c +++ b/Helios/Led.c @@ -81,7 +81,7 @@ void led_adjust_brightness(uint8_t fadeBy) void led_strobe(uint16_t on_time, uint16_t off_time, const rgb_color_t *off_col, const rgb_color_t *on_col) { - if ((Time_getCurtime() % (on_time + off_time)) > on_time) { + if ((time_get_current_time() % (on_time + off_time)) > on_time) { led_set_rgb(off_col); } else { led_set_rgb(on_col); @@ -95,7 +95,7 @@ void led_breath(uint8_t hue, uint32_t duration, uint8_t magnitude, uint8_t sat, return; } /* Determine the phase in the cycle */ - uint32_t phase = Time_getCurtime() % (2 * duration); + uint32_t phase = time_get_current_time() % (2 * duration); /* Calculate hue shift */ int32_t hueShift; if (phase < duration) { @@ -120,7 +120,7 @@ void led_hold(const rgb_color_t *col) { led_set_rgb(col); led_update(); - Time_delayMilliseconds(250); + time_delay_milliseconds(250); } static void led_set_pwm(uint8_t pwmPin, uint8_t pwmValue, volatile uint8_t *controlRegister, diff --git a/Helios/Pattern.c b/Helios/Pattern.c index d1536109..8dfd4a5d 100644 --- a/Helios/Pattern.c +++ b/Helios/Pattern.c @@ -62,7 +62,7 @@ void pattern_init_state(pattern_t *pat) colorset_reset_index(&pat->m_colorset); /* Reset the fade start time to the current time */ - pat->m_fadeStartTime = Time_getCurtime(); + pat->m_fadeStartTime = time_get_current_time(); /* the default state to begin with */ pat->m_state = STATE_BLINK_ON; @@ -92,7 +92,7 @@ void pattern_init_state(pattern_t *pat) static void pattern_tick_fade(pattern_t *pat) { - uint32_t now = Time_getCurtime(); + uint32_t now = time_get_current_time(); /* Calculate relative time since pattern was initialized */ uint32_t relativeTime = now - pat->m_fadeStartTime; uint32_t duration = pat->m_args.fade_dur * 10; diff --git a/Helios/TimeControl.c b/Helios/TimeControl.c index 11033b2d..cc80e655 100644 --- a/Helios/TimeControl.c +++ b/Helios/TimeControl.c @@ -33,18 +33,18 @@ static uint32_t m_prevTime = 0; static uint8_t m_enableTimestep = 1; #endif -uint8_t Time_init(void) +uint8_t time_init(void) { - m_prevTime = Time_microseconds(); + m_prevTime = time_microseconds(); m_curTick = 0; return 1; } -void Time_cleanup(void) +void time_cleanup(void) { } -void Time_tickClock(void) +void time_tick_clock(void) { /* tick clock forward */ m_curTick++; @@ -61,7 +61,7 @@ void Time_tickClock(void) uint32_t elapsed_us; uint32_t us; do { - us = Time_microseconds(); + us = time_microseconds(); /* detect rollover of microsecond counter */ if (us < m_prevTime) { /* calculate wrapped around difference */ @@ -78,10 +78,10 @@ void Time_tickClock(void) } while (elapsed_us < (1000000 / TICKRATE)); /* store current time */ - m_prevTime = Time_microseconds(); + m_prevTime = time_microseconds(); } -uint32_t Time_getCurtime(void) +uint32_t time_get_current_time(void) { return m_curTick; } @@ -93,7 +93,7 @@ ISR(TIMER0_OVF_vect) { } #endif -uint32_t Time_microseconds(void) +uint32_t time_microseconds(void) { #ifdef HELIOS_CLI struct timespec ts; @@ -124,7 +124,7 @@ uint32_t Time_microseconds(void) __attribute__((noinline)) #endif void -Time_delayMicroseconds(uint32_t us) +time_delay_microseconds(uint32_t us) { #ifdef HELIOS_EMBEDDED #if F_CPU >= 16000000L @@ -167,15 +167,15 @@ Time_delayMicroseconds(uint32_t us) #endif #else - uint32_t newtime = Time_microseconds() + us; - while (Time_microseconds() < newtime) + uint32_t newtime = time_microseconds() + us; + while (time_microseconds() < newtime) { /* busy loop */ } #endif } -void Time_delayMilliseconds(uint32_t ms) +void time_delay_milliseconds(uint32_t ms) { #ifdef HELIOS_CLI usleep(ms * 1000); @@ -183,13 +183,13 @@ void Time_delayMilliseconds(uint32_t ms) /* not very accurate */ uint16_t i; for (i = 0; i < ms; ++i) { - Time_delayMicroseconds(1000); + time_delay_microseconds(1000); } #endif } #ifdef HELIOS_CLI -void Time_enableTimestep(uint8_t enabled) +void time_enable_timestep(uint8_t enabled) { m_enableTimestep = enabled; } diff --git a/Helios/TimeControl.h b/Helios/TimeControl.h index 6a5a42c8..b65eb8aa 100644 --- a/Helios/TimeControl.h +++ b/Helios/TimeControl.h @@ -10,30 +10,30 @@ #define SEC_TO_TICKS(s) (uint32_t)((uint32_t)(s) * TICKRATE) /* Initialize time system */ -uint8_t Time_init(void); -void Time_cleanup(void); +uint8_t time_init(void); +void time_cleanup(void); /* Tick the clock forward to millis() */ -void Time_tickClock(void); +void time_tick_clock(void); /* Get the current tick, offset by any active simulation (simulation only exists in vortexlib) * Exposing this as inline or macro seems to save on space a non negligible amount, it is used a lot * and exposing in the header probably allows the compiler to optimize away repetitive calls */ -uint32_t Time_getCurtime(void); +uint32_t time_get_current_time(void); /* Current microseconds since startup, only use this for things like measuring rapid data transfer timings. - * If you just need to perform regular time checks for a pattern or some logic then use Time_getCurtime() and measure + * If you just need to perform regular time checks for a pattern or some logic then use time_get_current_time() and measure * time in ticks, use the SEC_TO_TICKS() or MS_TO_TICKS() macros to convert timings to measures of ticks for - * purpose of comparing against Time_getCurtime() */ -uint32_t Time_microseconds(void); + * purpose of comparing against time_get_current_time() */ +uint32_t time_microseconds(void); /* Delay for some number of microseconds or milliseconds, these are bad */ -void Time_delayMicroseconds(uint32_t us); -void Time_delayMilliseconds(uint32_t ms); +void time_delay_microseconds(uint32_t us); +void time_delay_milliseconds(uint32_t ms); #ifdef HELIOS_CLI /* Toggle timestep on/off */ -void Time_enableTimestep(uint8_t enabled); +void time_enable_timestep(uint8_t enabled); #endif #endif diff --git a/Helios/Timer.c b/Helios/Timer.c index 45889b14..fd3aeb0a 100644 --- a/Helios/Timer.c +++ b/Helios/Timer.c @@ -20,7 +20,7 @@ void timer_init(timer_t *timer, uint8_t alarm) void timer_start(timer_t *timer, uint32_t offset) { /* reset the start time */ - timer->m_startTime = Time_getCurtime() + offset; + timer->m_startTime = time_get_current_time() + offset; } void timer_reset(timer_t *timer) @@ -34,7 +34,7 @@ uint8_t timer_alarm(timer_t *timer) if (!timer->m_alarm) { return 0; } - uint32_t now = Time_getCurtime(); + uint32_t now = time_get_current_time(); /* time since start (forward or backwards) */ int32_t timeDiff = (int32_t)(int64_t)(now - timer->m_startTime); if (timeDiff < 0) { From 0e520fd6a89a542df3533b0fe5fc18e5da5b41f9 Mon Sep 17 00:00:00 2001 From: Kurt LaVacque Date: Thu, 16 Oct 2025 22:31:35 +0200 Subject: [PATCH 03/17] Update .gitignore to allow .c files --- .gitignore | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 53a0181c..3dea8476 100644 --- a/.gitignore +++ b/.gitignore @@ -14,7 +14,7 @@ !*.atsln !*.componentinfo.xml !*.cppproj -!*.github/workflows/** + # Ignore object files, dependency files, and other build artifacts *.o *.d @@ -38,5 +38,3 @@ !**/Makefile - -!*.test From cc3b5a679982db1cbdad529d01c37527803eaebb Mon Sep 17 00:00:00 2001 From: Kurt LaVacque Date: Thu, 16 Oct 2025 22:49:12 +0200 Subject: [PATCH 04/17] Fix timer_t conflict and add extern C guards for CLI compatibility --- Helios/Button.h | 8 ++++ Helios/Colorset.h | 8 ++++ Helios/Colortypes.h | 8 ++++ Helios/Helios.h | 8 ++++ Helios/Led.h | 8 ++++ Helios/Pattern.h | 10 ++++- Helios/Random.h | 8 ++++ Helios/Storage.h | 8 ++++ Helios/TimeControl.h | 8 ++++ Helios/Timer.c | 10 ++--- Helios/Timer.h | 22 ++++++---- HeliosCLI/Makefile | 40 +++++++++++------- HeliosCLI/cli_main.cpp | 94 +++++++++++++++++++++++++----------------- 13 files changed, 175 insertions(+), 65 deletions(-) diff --git a/Helios/Button.h b/Helios/Button.h index aa278563..28bc2f7a 100644 --- a/Helios/Button.h +++ b/Helios/Button.h @@ -1,6 +1,10 @@ #ifndef BUTTON_H #define BUTTON_H +#ifdef __cplusplus +extern "C" { +#endif + #include /* Initialize button */ @@ -74,4 +78,8 @@ void button_queue_input(char input); uint32_t button_input_queue_size(void); #endif +#ifdef __cplusplus +} +#endif + #endif diff --git a/Helios/Colorset.h b/Helios/Colorset.h index b8c2408a..1e194158 100644 --- a/Helios/Colorset.h +++ b/Helios/Colorset.h @@ -1,6 +1,10 @@ #ifndef COLORSET_H #define COLORSET_H +#ifdef __cplusplus +extern "C" { +#endif + #include "Colortypes.h" #include "HeliosConfig.h" @@ -133,4 +137,8 @@ uint8_t colorset_num_colors(const colorset_t *set); uint8_t colorset_on_start(const colorset_t *set); uint8_t colorset_on_end(const colorset_t *set); +#ifdef __cplusplus +} +#endif + #endif diff --git a/Helios/Colortypes.h b/Helios/Colortypes.h index a10d58ee..f7b5d7f3 100644 --- a/Helios/Colortypes.h +++ b/Helios/Colortypes.h @@ -6,6 +6,10 @@ #include "HeliosConfig.h" #include "ColorConstants.h" +#ifdef __cplusplus +extern "C" { +#endif + #if ALTERNATIVE_HSV_RGB == 1 enum hsv_to_rgb_algorithm { @@ -82,4 +86,8 @@ rgb_color_t hsv_to_rgb_generic(const hsv_color_t *rhs); /* Convert rgb to hsv with generic fast method */ hsv_color_t rgb_to_hsv_generic(const rgb_color_t *rhs); +#ifdef __cplusplus +} +#endif + #endif diff --git a/Helios/Helios.h b/Helios/Helios.h index 57140eee..3af4dbb7 100644 --- a/Helios/Helios.h +++ b/Helios/Helios.h @@ -1,6 +1,10 @@ #ifndef HELIOS_H #define HELIOS_H +#ifdef __cplusplus +extern "C" { +#endif + #include #include "HeliosConfig.h" @@ -43,4 +47,8 @@ uint8_t helios_has_flag(enum helios_flags flag); void helios_clear_flag(enum helios_flags flag); void helios_toggle_flag(enum helios_flags flag); +#ifdef __cplusplus +} +#endif + #endif diff --git a/Helios/Led.h b/Helios/Led.h index e0f1bff8..cae2ca2c 100644 --- a/Helios/Led.h +++ b/Helios/Led.h @@ -1,6 +1,10 @@ #ifndef LED_CONTROL_H #define LED_CONTROL_H +#ifdef __cplusplus +extern "C" { +#endif + #include #include "Colortypes.h" @@ -41,4 +45,8 @@ void led_set_brightness(uint8_t brightness); /* actually update the LEDs and show the changes */ void led_update(void); +#ifdef __cplusplus +} +#endif + #endif diff --git a/Helios/Pattern.h b/Helios/Pattern.h index 248a6bad..68b3c8fa 100644 --- a/Helios/Pattern.h +++ b/Helios/Pattern.h @@ -1,6 +1,10 @@ #ifndef PATTERN_H #define PATTERN_H +#ifdef __cplusplus +extern "C" { +#endif + #include "Colorset.h" #include "Timer.h" @@ -74,7 +78,7 @@ struct pattern_t enum pattern_state m_state; /* the blink timer used to measure blink timings */ - timer_t m_blinkTimer; + helios_timer_t m_blinkTimer; /* ================================== * Blend Members */ @@ -134,4 +138,8 @@ uint8_t pattern_is_blend(const pattern_t *pat); /* whether fade speed is non 0 */ uint8_t pattern_is_fade(const pattern_t *pat); +#ifdef __cplusplus +} +#endif + #endif diff --git a/Helios/Random.h b/Helios/Random.h index f4fcbca6..b5bee10f 100644 --- a/Helios/Random.h +++ b/Helios/Random.h @@ -1,6 +1,10 @@ #ifndef RANDOM_H #define RANDOM_H +#ifdef __cplusplus +extern "C" { +#endif + #include typedef struct random_t random_t; @@ -25,4 +29,8 @@ uint8_t random_next8(random_t *rng, uint8_t minValue, uint8_t maxValue); /* Generate next random 16-bit value within range [minValue, maxValue] */ uint16_t random_next16(random_t *rng, uint16_t minValue, uint16_t maxValue); +#ifdef __cplusplus +} +#endif + #endif diff --git a/Helios/Storage.h b/Helios/Storage.h index fc41e44e..79a1daa4 100644 --- a/Helios/Storage.h +++ b/Helios/Storage.h @@ -1,6 +1,10 @@ #ifndef STORAGE_H #define STORAGE_H +#ifdef __cplusplus +extern "C" { +#endif + #include #include "HeliosConfig.h" @@ -45,4 +49,8 @@ uint8_t storage_crc8(uint8_t pos, uint8_t size); void storage_enable_storage(uint8_t enabled); #endif +#ifdef __cplusplus +} +#endif + #endif diff --git a/Helios/TimeControl.h b/Helios/TimeControl.h index b65eb8aa..85fd4aac 100644 --- a/Helios/TimeControl.h +++ b/Helios/TimeControl.h @@ -1,6 +1,10 @@ #ifndef TIME_CONTROL_H #define TIME_CONTROL_H +#ifdef __cplusplus +extern "C" { +#endif + #include #include "HeliosConfig.h" @@ -36,4 +40,8 @@ void time_delay_milliseconds(uint32_t ms); void time_enable_timestep(uint8_t enabled); #endif +#ifdef __cplusplus +} +#endif + #endif diff --git a/Helios/Timer.c b/Helios/Timer.c index fd3aeb0a..e18be8ae 100644 --- a/Helios/Timer.c +++ b/Helios/Timer.c @@ -4,32 +4,32 @@ #include "TimeControl.h" -void timer_init_default(timer_t *timer) +void timer_init_default(helios_timer_t *timer) { timer->m_alarm = 0; timer->m_startTime = 0; } -void timer_init(timer_t *timer, uint8_t alarm) +void timer_init(helios_timer_t *timer, uint8_t alarm) { timer_reset(timer); timer->m_alarm = alarm; timer_start(timer, 0); } -void timer_start(timer_t *timer, uint32_t offset) +void timer_start(helios_timer_t *timer, uint32_t offset) { /* reset the start time */ timer->m_startTime = time_get_current_time() + offset; } -void timer_reset(timer_t *timer) +void timer_reset(helios_timer_t *timer) { timer->m_alarm = 0; timer->m_startTime = 0; } -uint8_t timer_alarm(timer_t *timer) +uint8_t timer_alarm(helios_timer_t *timer) { if (!timer->m_alarm) { return 0; diff --git a/Helios/Timer.h b/Helios/Timer.h index 46b8394e..40997d07 100644 --- a/Helios/Timer.h +++ b/Helios/Timer.h @@ -3,9 +3,13 @@ #include -typedef struct timer_t timer_t; +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct helios_timer_t helios_timer_t; -struct timer_t +struct helios_timer_t { /* the alarm */ uint32_t m_alarm; @@ -14,19 +18,23 @@ struct timer_t }; /* Initialize a timer struct to default values */ -void timer_init_default(timer_t *timer); +void timer_init_default(helios_timer_t *timer); /* Init a timer with a number of alarms and optionally start it */ -void timer_init(timer_t *timer, uint8_t alarm); +void timer_init(helios_timer_t *timer, uint8_t alarm); /* Start the timer but don't change current alarm, this shifts * the timer startTime but does not reset it's alarm state */ -void timer_start(timer_t *timer, uint32_t offset); +void timer_start(helios_timer_t *timer, uint32_t offset); /* Delete all alarms from the timer and reset */ -void timer_reset(timer_t *timer); +void timer_reset(helios_timer_t *timer); /* Will return true if the timer hit */ -uint8_t timer_alarm(timer_t *timer); +uint8_t timer_alarm(helios_timer_t *timer); + +#ifdef __cplusplus +} +#endif #endif diff --git a/HeliosCLI/Makefile b/HeliosCLI/Makefile index a656391a..c9178d1d 100644 --- a/HeliosCLI/Makefile +++ b/HeliosCLI/Makefile @@ -5,14 +5,16 @@ .PHONY: all tests clean pngs bmps clean_storage # compiler tool definitions -CC=g++ +CXX=g++ +CC=gcc AR=ar cru MAKE=make RM=rm -rf RANLIB=ranlib -CFLAGS=-O2 -g -Wall -std=c++11 +CXXFLAGS=-O2 -g -Wall -std=c++11 +CFLAGS=-O2 -g -Wall -std=c11 # compiler defines DEFINES=\ @@ -29,9 +31,11 @@ INCLUDES=\ # only set them if they're not empty to prevent unnecessary whitespace ifneq ($(DEFINES),) CFLAGS+=$(DEFINES) + CXXFLAGS+=$(DEFINES) endif ifneq ($(INCLUDES),) CFLAGS+=$(INCLUDES) + CXXFLAGS+=$(INCLUDES) endif # local NONSTANDARD libraries to link with @@ -52,20 +56,24 @@ LIBS=\ # source files # local source files first, other sources after ifeq ($(OS),Windows_NT) - SRC = $(shell find ../Helios -type f -name \\*.cpp) \ - $(shell find . -type f -name \\*.cpp -not -path "./venv/*") + C_SRC = $(shell find ../Helios -type f -name \\*.c) + CPP_SRC = $(shell find . -type f -name \\*.cpp -not -path "./venv/*") else - SRC = $(shell find ../Helios -type f -name '*.cpp') \ - $(shell find . -type f -name '*.cpp' -not -path "./venv/*") + C_SRC = $(shell find ../Helios -type f -name '*.c') + CPP_SRC = $(shell find . -type f -name '*.cpp' -not -path "./venv/*") endif -# object files are source files with .c replaced with .o -OBJS=\ - $(SRC:.cpp=.o) \ +SRC = $(C_SRC) $(CPP_SRC) -# dependency files are source files with .c replaced with .d -DFILES=\ - $(SRC:.cpp=.d) \ +# object files are source files with .c/.cpp replaced with .o +C_OBJS = $(C_SRC:.c=.o) +CPP_OBJS = $(CPP_SRC:.cpp=.o) +OBJS = $(C_OBJS) $(CPP_OBJS) + +# dependency files +C_DFILES = $(C_SRC:.c=.d) +CPP_DFILES = $(CPP_SRC:.cpp=.d) +DFILES = $(C_DFILES) $(CPP_DFILES) # target dependencies # this includes any script generated c/h files, @@ -89,10 +97,14 @@ tests: $(TESTS) # target for vortex lib helios: compute_version $(DEPS) - $(CC) $(CFLAGS) $(DEPS) -o $@ $(LLIBS) + $(CXX) $(CXXFLAGS) $(DEPS) -o $@ $(LLIBS) -# catch-all make target to generate .o and .d files +# catch-all make target to generate .o and .d files from .cpp %.o: %.cpp + $(CXX) $(CXXFLAGS) -MMD -c $< -o $@ + +# catch-all make target to generate .o and .d files from .c +%.o: %.c $(CC) $(CFLAGS) -MMD -c $< -o $@ # catch-all for static libraries in the form of: diff --git a/HeliosCLI/cli_main.cpp b/HeliosCLI/cli_main.cpp index 0dd4386e..22d98734 100644 --- a/HeliosCLI/cli_main.cpp +++ b/HeliosCLI/cli_main.cpp @@ -22,6 +22,8 @@ #include "Colortypes.h" #include "Button.h" #include "Led.h" +#include "Patterns.h" +#include "Pattern.h" #include "color_map.h" /* @@ -53,7 +55,7 @@ bool timestep = true; bool eeprom = false; std::string eeprom_file; bool generate_bmp = false; -std::vector colorBuffer; +std::vector colorBuffer; uint32_t num_cycles = 0; float brightness_scale = 1.0f; uint8_t minumum_brightness = 75; @@ -71,7 +73,7 @@ static bool read_inputs(); static void show(); static void restore_terminal(); static void set_terminal_nonblocking(); -static bool writeBMP(const std::string& filename, const std::vector& colors); +static bool writeBMP(const std::string& filename, const std::vector& colors); static void print_usage(const char* program_name); static bool parse_eep_file(const std::string& filename, std::vector& memory); static bool parse_csv_hex(const std::string& filename, std::vector& memory); @@ -91,29 +93,30 @@ int main(int argc, char *argv[]) return 0; } // toggle timestep in the engine based on the cli input - Time::enableTimestep(timestep); + time_enable_timestep(timestep); // toggle storage in the engine based on cli input - Storage::enableStorage(storage); + storage_enable_storage(storage); // run the engine initialization - Helios::init(); + helios_init(); // set the initial mode index - Helios::set_mode_index(initial_mode_index); + helios_set_mode_index(initial_mode_index); // Set the initial pattern based on user arguments if (initial_pattern_str.length() > 0) { // convert the string arg to integer, then treat it as a PatternID - PatternID id = (PatternID)strtoul(initial_pattern_str.c_str(), NULL, 10); + pattern_id id = (pattern_id)strtoul(initial_pattern_str.c_str(), NULL, 10); // pass the current pattern to make_pattern to update it's internals - Patterns::make_pattern(id, Helios::cur_pattern()); + pattern_t* pat = helios_cur_pattern(); + patterns_make_pattern(id, pat); // re-initialize the current pattern - Helios::cur_pattern().init(); + pattern_init_state(pat); } // set initial pattern args based on user arguments if (initial_pattern_args_str.length() > 0) { // parse the list of args into an array of ints std::vector vals; std::istringstream ss(initial_pattern_args_str); - // push 6 args into the array - while (vals.size() < 6) { + // push 7 args into the array (on_dur, off_dur, gap_dur, dash_dur, group_size, blend_speed, fade_dur) + while (vals.size() < 7) { std::string arg; uint32_t val = 0; // try to parse out a number @@ -124,28 +127,40 @@ int main(int argc, char *argv[]) vals.push_back(val); } // construct pattern args from the array of values - PatternArgs args(vals[0], vals[1], vals[2], vals[3], vals[4], vals[5]); + pattern_args_t args; + pattern_args_init(&args, vals[0], vals[1], vals[2], vals[3], vals[4], vals[5], vals[6]); // set the args of the current pattern - Helios::cur_pattern().setArgs(args); + pattern_t* pat = helios_cur_pattern(); + pattern_set_args(pat, &args); } // Set the initial colorset based on user arguments if (initial_colorset_str.length() > 0) { std::stringstream ss(initial_colorset_str); std::string color; - Colorset set; + colorset_t set; + colorset_init(&set); while (getline(ss, color, ',')) { // iterate letters and lowercase them std::transform(color.begin(), color.end(), color.begin(), [](unsigned char c){ return tolower(c); }); + rgb_color_t rgb; if (color_map.count(color) > 0) { - set.addColor(color_map[color]); + uint32_t color_val = color_map[color]; + rgb.red = (color_val >> 16) & 0xFF; + rgb.green = (color_val >> 8) & 0xFF; + rgb.blue = color_val & 0xFF; } else { - set.addColor(strtoul(color.c_str(), nullptr, 16)); + uint32_t color_val = strtoul(color.c_str(), nullptr, 16); + rgb.red = (color_val >> 16) & 0xFF; + rgb.green = (color_val >> 8) & 0xFF; + rgb.blue = color_val & 0xFF; } + colorset_add_color(&set, rgb); } // update the colorset of the current pattern - Helios::cur_pattern().setColorset(set); + pattern_t* pat = helios_cur_pattern(); + pattern_set_colorset(pat, &set); // re-initialize the current pattern - Helios::cur_pattern().init(); + pattern_init_state(pat); } // just generate eeprom? if (eeprom) { @@ -155,19 +170,19 @@ int main(int argc, char *argv[]) // so that we can detect when one full cycle of the pattern has passed uint32_t cycle_count = 0; uint8_t last_index = 0; - while (Helios::keep_going()) { + while (helios_keep_going()) { // check for any inputs and read the next one read_inputs(); // if lockstep is enabled, only run logic if the // input queue isn't actually empty - if (lockstep && !Button::inputQueueSize()) { + if (lockstep && !button_input_queue_size()) { // just keep waiting for an input continue; } // run the main loop - Helios::tick(); + helios_tick(); // don't render anything if asleep, but technically it's still running... - if (Helios::is_asleep()) { + if (helios_is_asleep()) { continue; } // watch for a full cycle if it was requested by the command line @@ -175,7 +190,8 @@ int main(int argc, char *argv[]) // grab the current index of the colorset, which might be the same for // several tick in a row, so we must check whether it just changed this // tick by comparing it to the index we saved last tick - uint8_t cur_index = Helios::cur_pattern().colorset().curIndex(); + pattern_t* pat = helios_cur_pattern(); + uint8_t cur_index = pat->m_colorset.m_curIndex; if (cur_index == 0 && last_index != 0) { // only if the current index is 0 (start of colorset) and the last index was // not 0 then the colorset *just* started iterating through it's colors, so @@ -184,7 +200,7 @@ int main(int argc, char *argv[]) } // then if we run more than the chosen number of cycles just quit if (cycle_count >= num_cycles) { - Helios::terminate(); + helios_terminate(); break; } last_index = cur_index; @@ -389,7 +405,7 @@ static bool read_inputs() } for (uint32_t i = 0; i < repeatAmount; ++i) { // otherwise just queue up the command - Button::queueInput(command); + button_queue_input(command); } } return true; @@ -402,8 +418,9 @@ static void show() if (generate_bmp) { // still need to generate the BMP by recoring all the output colors // even if they have chosen the -q for quiet option - RGBColor currentColor = {Led::get().red, Led::get().green, Led::get().blue}; - RGBColor scaledColor = currentColor.scaleBrightness(brightness_scale); + rgb_color_t currentColor = led_get(); + rgb_color_t scaledColor = currentColor; + rgb_scale_brightness(&scaledColor, brightness_scale); colorBuffer.push_back(scaledColor); } return; @@ -414,8 +431,9 @@ static void show() out += "\r"; } // Get the current color and scale its brightness up - RGBColor currentColor = {Led::get().red, Led::get().green, Led::get().blue}; - RGBColor scaledColor = currentColor.scaleBrightness(brightness_scale); + rgb_color_t currentColor = led_get(); + rgb_color_t scaledColor = currentColor; + rgb_scale_brightness(&scaledColor, brightness_scale); if (output_type == OUTPUT_TYPE_COLOR) { out += "\x1B[0m["; // opening | out += "\x1B[48;2;"; // colorcode start @@ -473,7 +491,7 @@ static void set_terminal_nonblocking() atexit(restore_terminal); } -bool writeBMP(const std::string& filename, const std::vector& colors) +bool writeBMP(const std::string& filename, const std::vector& colors) { if (colors.empty()) { std::cerr << "Invalid image dimensions or empty color array." << std::endl; @@ -525,7 +543,7 @@ bool writeBMP(const std::string& filename, const std::vector& colors) // write out data for (int32_t y = height - 1; y >= 0; --y) { for (int32_t x = 0; x < width; ++x) { - const RGBColor& color = colors[y * width + x]; + const rgb_color_t& color = colors[y * width + x]; // BGR format const unsigned char pixel[3] = { color.blue, color.green, color.red }; file.write((const char *)pixel, 3); @@ -717,27 +735,27 @@ static void dump_eeprom(const std::string& filename) for (size_t slot = 0; slot < NUM_MODE_SLOTS; ++slot) { size_t pos = slot * SLOT_SIZE; - Pattern pat; - memcpy((void*)&pat, &memory[pos], sizeof(Pattern)); + pattern_t pat; + memcpy((void*)&pat, &memory[pos], sizeof(pattern_t)); printf("Slot %zu:\n", slot); printf(" Colorset: "); - for (size_t i = 0; i < pat.getColorset().numColors(); ++i) { - RGBColor color = pat.getColorset()[i]; + for (size_t i = 0; i < pat.m_colorset.m_numColors; ++i) { + rgb_color_t color = colorset_get(&pat.m_colorset, i); char hexCode[8]; snprintf(hexCode, sizeof(hexCode), "#%02X%02X%02X", color.red, color.green, color.blue); printf("\033[48;2;%d;%d;%dm \033[0m (%s) ", color.red, color.green, color.blue, hexCode); } printf("\n"); - PatternArgs args = pat.getArgs(); + pattern_args_t args = pat.m_args; printf(" Args: on_dur=%d, off_dur=%d, gap_dur=%d, dash_dur=%d, group_size=%d, blend_speed=%d\n", args.on_dur, args.off_dur, args.gap_dur, args.dash_dur, args.group_size, args.blend_speed); - printf(" Flags: %02X\n", pat.getFlags()); + printf(" Flags: %02X\n", pat.m_patternFlags); } uint8_t flags = (uint8_t)memory[CONFIG_START_INDEX - STORAGE_GLOBAL_FLAG_INDEX]; - bool locked = (flags & Helios::FLAG_LOCKED) != 0; + bool locked = (flags & FLAG_LOCKED) != 0; uint8_t modeIdx = (uint8_t)memory[CONFIG_START_INDEX - STORAGE_CURRENT_MODE_INDEX]; uint8_t brightness = (uint8_t)memory[CONFIG_START_INDEX - STORAGE_BRIGHTNESS_INDEX]; From a56e469efd46052436ccf21547f3a65898c717ce Mon Sep 17 00:00:00 2001 From: Kurt LaVacque Date: Thu, 16 Oct 2025 22:54:25 +0200 Subject: [PATCH 05/17] Fix POSIX function declarations for Linux compatibility --- Helios/TimeControl.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Helios/TimeControl.c b/Helios/TimeControl.c index cc80e655..9b3572dd 100644 --- a/Helios/TimeControl.c +++ b/Helios/TimeControl.c @@ -1,3 +1,8 @@ +/* Enable POSIX features for clock_gettime, usleep, etc. */ +#ifdef HELIOS_CLI +#define _POSIX_C_SOURCE 200112L +#endif + #include "TimeControl.h" #include @@ -17,7 +22,6 @@ #ifdef HELIOS_CLI #include #include -static uint64_t start = 0; /* convert seconds and nanoseconds to microseconds */ #define SEC_TO_US(sec) ((sec)*1000000) #define NS_TO_US(ns) ((ns)/1000) From c46788ba5546d86c50c0c29f267e1bc800d8e7a0 Mon Sep 17 00:00:00 2001 From: Kurt LaVacque Date: Fri, 17 Oct 2025 10:37:27 +0200 Subject: [PATCH 06/17] Fix CLI test issues: increase INPUT_QUEUE_SIZE to 4096 and enable wake on button press in sleep mode --- Helios/Button.c | 5 +++-- Helios/Helios.c | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Helios/Button.c b/Helios/Button.c index 3ea1f9f2..e08587ac 100644 --- a/Helios/Button.c +++ b/Helios/Button.c @@ -42,7 +42,8 @@ static uint8_t m_holdClick = 0; static uint8_t m_pinState = 0; static uint8_t m_enableWake = 0; /* Simple input queue for CLI - using a fixed-size circular buffer */ -#define INPUT_QUEUE_SIZE 64 +/* Larger queue size for CLI to handle long test sequences */ +#define INPUT_QUEUE_SIZE 4096 static char m_inputQueue[INPUT_QUEUE_SIZE]; static uint32_t m_queueHead = 0; static uint32_t m_queueTail = 0; @@ -88,7 +89,7 @@ void button_enable_wake(void) GIMSK |= (1 << PCIE); sei(); #else /* HELIOS_CLI */ - m_enableWake = 0; + m_enableWake = 1; #endif } diff --git a/Helios/Helios.c b/Helios/Helios.c index 6949709c..f70e1ebc 100644 --- a/Helios/Helios.c +++ b/Helios/Helios.c @@ -186,6 +186,8 @@ void helios_enter_sleep(void) cur_state = STATE_SLEEP; /* enable the sleep bool */ sleeping = 1; + /* Enable wake on button press/click for CLI */ + button_enable_wake(); #endif } From a5b7595ebe7bea420c4b619944b82a480c86cc22 Mon Sep 17 00:00:00 2001 From: Kurt LaVacque Date: Fri, 17 Oct 2025 17:40:46 +0200 Subject: [PATCH 07/17] Add new Helios components for button handling, color management, and pattern functionality - Introduced Button.cpp for managing button states and interactions, including support for CLI and embedded environments. - Added Colorset.cpp and Colortypes.cpp to handle color management, including HSV and RGB conversions. - Implemented Pattern.cpp and Patterns.cpp for defining and managing light patterns, enhancing visual effects. - Updated Makefile to include new source files and ensure proper compilation across different environments. - Refactored existing code to improve structure and maintainability, adhering to the KISS principle. --- Helios/{Button.c => Button.cpp} | 6 ++++++ Helios/{Colorset.c => Colorset.cpp} | 0 Helios/{Colortypes.c => Colortypes.cpp} | 0 Helios/{Helios.c => Helios.cpp} | 0 Helios/{Led.c => Led.cpp} | 0 Helios/{Pattern.c => Pattern.cpp} | 0 Helios/{Patterns.c => Patterns.cpp} | 0 Helios/Patterns.h | 8 ++++++++ Helios/{Random.c => Random.cpp} | 0 Helios/{Storage.c => Storage.cpp} | 0 Helios/{TimeControl.c => TimeControl.cpp} | 0 Helios/{Timer.c => Timer.cpp} | 0 HeliosCLI/Makefile | 22 ++++++---------------- HeliosEmbedded/Makefile | 11 +++++------ HeliosEmbedded/{main.c => main.cpp} | 0 15 files changed, 25 insertions(+), 22 deletions(-) rename Helios/{Button.c => Button.cpp} (99%) rename Helios/{Colorset.c => Colorset.cpp} (100%) rename Helios/{Colortypes.c => Colortypes.cpp} (100%) rename Helios/{Helios.c => Helios.cpp} (100%) rename Helios/{Led.c => Led.cpp} (100%) rename Helios/{Pattern.c => Pattern.cpp} (100%) rename Helios/{Patterns.c => Patterns.cpp} (100%) rename Helios/{Random.c => Random.cpp} (100%) rename Helios/{Storage.c => Storage.cpp} (100%) rename Helios/{TimeControl.c => TimeControl.cpp} (100%) rename Helios/{Timer.c => Timer.cpp} (100%) rename HeliosEmbedded/{main.c => main.cpp} (100%) diff --git a/Helios/Button.c b/Helios/Button.cpp similarity index 99% rename from Helios/Button.c rename to Helios/Button.cpp index e08587ac..99840598 100644 --- a/Helios/Button.c +++ b/Helios/Button.cpp @@ -13,8 +13,14 @@ #endif /* Forward declaration */ +#ifdef __cplusplus +extern "C" { +#endif void helios_wakeup(void); void helios_terminate(void); +#ifdef __cplusplus +} +#endif #ifdef HELIOS_CLI /* Forward declarations for CLI functions */ diff --git a/Helios/Colorset.c b/Helios/Colorset.cpp similarity index 100% rename from Helios/Colorset.c rename to Helios/Colorset.cpp diff --git a/Helios/Colortypes.c b/Helios/Colortypes.cpp similarity index 100% rename from Helios/Colortypes.c rename to Helios/Colortypes.cpp diff --git a/Helios/Helios.c b/Helios/Helios.cpp similarity index 100% rename from Helios/Helios.c rename to Helios/Helios.cpp diff --git a/Helios/Led.c b/Helios/Led.cpp similarity index 100% rename from Helios/Led.c rename to Helios/Led.cpp diff --git a/Helios/Pattern.c b/Helios/Pattern.cpp similarity index 100% rename from Helios/Pattern.c rename to Helios/Pattern.cpp diff --git a/Helios/Patterns.c b/Helios/Patterns.cpp similarity index 100% rename from Helios/Patterns.c rename to Helios/Patterns.cpp diff --git a/Helios/Patterns.h b/Helios/Patterns.h index 5ee105e4..100a01cf 100644 --- a/Helios/Patterns.h +++ b/Helios/Patterns.h @@ -1,6 +1,10 @@ #ifndef PATTERNS_H #define PATTERNS_H +#ifdef __cplusplus +extern "C" { +#endif + #include /* Forward declaration */ @@ -36,4 +40,8 @@ enum pattern_id { void patterns_make_default(uint8_t index, pattern_t *pat); void patterns_make_pattern(enum pattern_id id, pattern_t *pat); +#ifdef __cplusplus +} +#endif + #endif diff --git a/Helios/Random.c b/Helios/Random.cpp similarity index 100% rename from Helios/Random.c rename to Helios/Random.cpp diff --git a/Helios/Storage.c b/Helios/Storage.cpp similarity index 100% rename from Helios/Storage.c rename to Helios/Storage.cpp diff --git a/Helios/TimeControl.c b/Helios/TimeControl.cpp similarity index 100% rename from Helios/TimeControl.c rename to Helios/TimeControl.cpp diff --git a/Helios/Timer.c b/Helios/Timer.cpp similarity index 100% rename from Helios/Timer.c rename to Helios/Timer.cpp diff --git a/HeliosCLI/Makefile b/HeliosCLI/Makefile index c9178d1d..7210e298 100644 --- a/HeliosCLI/Makefile +++ b/HeliosCLI/Makefile @@ -56,24 +56,18 @@ LIBS=\ # source files # local source files first, other sources after ifeq ($(OS),Windows_NT) - C_SRC = $(shell find ../Helios -type f -name \\*.c) - CPP_SRC = $(shell find . -type f -name \\*.cpp -not -path "./venv/*") + CPP_SRC = $(shell find ../Helios -type f -name \\*.cpp) $(shell find . -type f -name \\*.cpp -not -path "./venv/*") else - C_SRC = $(shell find ../Helios -type f -name '*.c') - CPP_SRC = $(shell find . -type f -name '*.cpp' -not -path "./venv/*") + CPP_SRC = $(shell find ../Helios -type f -name '*.cpp') $(shell find . -type f -name '*.cpp' -not -path "./venv/*") endif -SRC = $(C_SRC) $(CPP_SRC) +SRC = $(CPP_SRC) -# object files are source files with .c/.cpp replaced with .o -C_OBJS = $(C_SRC:.c=.o) -CPP_OBJS = $(CPP_SRC:.cpp=.o) -OBJS = $(C_OBJS) $(CPP_OBJS) +# object files are source files with .cpp replaced with .o +OBJS = $(CPP_SRC:.cpp=.o) # dependency files -C_DFILES = $(C_SRC:.c=.d) -CPP_DFILES = $(CPP_SRC:.cpp=.d) -DFILES = $(C_DFILES) $(CPP_DFILES) +DFILES = $(CPP_SRC:.cpp=.d) # target dependencies # this includes any script generated c/h files, @@ -103,10 +97,6 @@ helios: compute_version $(DEPS) %.o: %.cpp $(CXX) $(CXXFLAGS) -MMD -c $< -o $@ -# catch-all make target to generate .o and .d files from .c -%.o: %.c - $(CC) $(CFLAGS) -MMD -c $< -o $@ - # catch-all for static libraries in the form of: # / # this expects that the makefile in has a diff --git a/HeliosEmbedded/Makefile b/HeliosEmbedded/Makefile index c89c5586..974ad3b5 100644 --- a/HeliosEmbedded/Makefile +++ b/HeliosEmbedded/Makefile @@ -117,7 +117,6 @@ CFLAGS = -g \ -Wall \ -flto \ -mrelax \ - -std=c11 \ -fshort-enums \ -fpack-struct \ -fdata-sections \ @@ -160,15 +159,15 @@ CFLAGS+=$(INCLUDES) # Source files ifeq ($(OS),Windows_NT) # Windows SRCS = \ - $(shell find ../Helios -maxdepth 1 -type f -name '\*.c') main.c + $(shell find ../Helios -maxdepth 1 -type f -name '\*.cpp') main.cpp else # linux SRCS = \ - $(shell find ../Helios -maxdepth 1 -type f -name \*.c) main.c + $(shell find ../Helios -maxdepth 1 -type f -name \*.cpp) main.cpp endif -OBJS = $(SRCS:.c=.o) +OBJS = $(SRCS:.cpp=.o) -DFILES = $(SRCS:.c=.d) +DFILES = $(SRCS:.cpp=.d) ####################### ### BUILD TARGETS ##### @@ -196,7 +195,7 @@ $(TARGET).elf: compute_version $(OBJS) %.o: %.S $(CC) $(ASMFLAGS) -c $< -o $@ -%.o: %.c +%.o: %.cpp $(CC) $(CFLAGS) -c $< -o $@ upload: set_fuses $(TARGET).hex diff --git a/HeliosEmbedded/main.c b/HeliosEmbedded/main.cpp similarity index 100% rename from HeliosEmbedded/main.c rename to HeliosEmbedded/main.cpp From 0df2d1a347239373425731fef5d36f0e5f92e4a6 Mon Sep 17 00:00:00 2001 From: Kurt LaVacque Date: Fri, 17 Oct 2025 18:02:36 +0200 Subject: [PATCH 08/17] Refactor Makefile for improved compilation and source file management - Removed C++ specific variables and flags, switching to C compiler settings for consistency. - Consolidated source file definitions and updated object and dependency file generation to streamline the build process. - Enhanced compatibility across different operating systems by standardizing source file search patterns. --- HeliosCLI/Makefile | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/HeliosCLI/Makefile b/HeliosCLI/Makefile index 7210e298..a621ffd5 100644 --- a/HeliosCLI/Makefile +++ b/HeliosCLI/Makefile @@ -5,7 +5,6 @@ .PHONY: all tests clean pngs bmps clean_storage # compiler tool definitions -CXX=g++ CC=gcc AR=ar cru @@ -13,7 +12,6 @@ MAKE=make RM=rm -rf RANLIB=ranlib -CXXFLAGS=-O2 -g -Wall -std=c++11 CFLAGS=-O2 -g -Wall -std=c11 # compiler defines @@ -31,11 +29,9 @@ INCLUDES=\ # only set them if they're not empty to prevent unnecessary whitespace ifneq ($(DEFINES),) CFLAGS+=$(DEFINES) - CXXFLAGS+=$(DEFINES) endif ifneq ($(INCLUDES),) CFLAGS+=$(INCLUDES) - CXXFLAGS+=$(INCLUDES) endif # local NONSTANDARD libraries to link with @@ -56,18 +52,20 @@ LIBS=\ # source files # local source files first, other sources after ifeq ($(OS),Windows_NT) - CPP_SRC = $(shell find ../Helios -type f -name \\*.cpp) $(shell find . -type f -name \\*.cpp -not -path "./venv/*") + SRC = $(shell find ../Helios -type f -name \\*.cpp) \ + $(shell find . -type f -name \\*.cpp -not -path "./venv/*") else - CPP_SRC = $(shell find ../Helios -type f -name '*.cpp') $(shell find . -type f -name '*.cpp' -not -path "./venv/*") + SRC = $(shell find ../Helios -type f -name '*.cpp') \ + $(shell find . -type f -name '*.cpp' -not -path "./venv/*") endif -SRC = $(CPP_SRC) +# object files are source files with .c replaced with .o +OBJS=\ + $(SRC:.cpp=.o) \ -# object files are source files with .cpp replaced with .o -OBJS = $(CPP_SRC:.cpp=.o) - -# dependency files -DFILES = $(CPP_SRC:.cpp=.d) +# dependency files are source files with .c replaced with .d +DFILES=\ + $(SRC:.cpp=.d) \ # target dependencies # this includes any script generated c/h files, @@ -91,11 +89,11 @@ tests: $(TESTS) # target for vortex lib helios: compute_version $(DEPS) - $(CXX) $(CXXFLAGS) $(DEPS) -o $@ $(LLIBS) + $(CC) $(CFLAGS) $(DEPS) -o $@ $(LLIBS) -# catch-all make target to generate .o and .d files from .cpp +# catch-all make target to generate .o and .d files %.o: %.cpp - $(CXX) $(CXXFLAGS) -MMD -c $< -o $@ + $(CC) $(CFLAGS) -MMD -c $< -o $@ # catch-all for static libraries in the form of: # / From 66d8186c8c35bf802890f03c886e031fc3580d3c Mon Sep 17 00:00:00 2001 From: Kurt LaVacque Date: Fri, 17 Oct 2025 18:06:49 +0200 Subject: [PATCH 09/17] Update .gitignore to refine ignored file patterns - Removed exclusion for .c files and added support for .test and .conf files. - Included .github/workflows/** to ensure workflow files are tracked. - These changes enhance the management of ignored files, improving build and development processes. --- .gitignore | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 3dea8476..80409b73 100644 --- a/.gitignore +++ b/.gitignore @@ -9,12 +9,11 @@ !*.pattern !*.h !*.cpp -!*.c !*.py !*.atsln !*.componentinfo.xml !*.cppproj - +!*.github/workflows/** # Ignore object files, dependency files, and other build artifacts *.o *.d @@ -38,3 +37,7 @@ !**/Makefile + +!*.test + +!*.conf From e82417cfe2e505adf238d65eb7a7fe6ab7493aa7 Mon Sep 17 00:00:00 2001 From: Kurt LaVacque Date: Fri, 17 Oct 2025 18:50:49 +0200 Subject: [PATCH 10/17] Update Makefile to switch from C to C++ compilation - Changed the compiler from gcc to g++ to support C++ code. - Updated CFLAGS to use the C++11 standard. - Adjusted the linking process to include the C++ standard library. - These changes enhance compatibility for C++ source files and improve the build process. --- HeliosCLI/Makefile | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/HeliosCLI/Makefile b/HeliosCLI/Makefile index a621ffd5..00fb0276 100644 --- a/HeliosCLI/Makefile +++ b/HeliosCLI/Makefile @@ -5,14 +5,14 @@ .PHONY: all tests clean pngs bmps clean_storage # compiler tool definitions -CC=gcc +CC=g++ AR=ar cru MAKE=make RM=rm -rf RANLIB=ranlib -CFLAGS=-O2 -g -Wall -std=c11 +CFLAGS=-O2 -g -Wall -std=c++11 # compiler defines DEFINES=\ @@ -48,6 +48,7 @@ LLIBS=\ # MUST have LLIBS BEFORE the standard libraries LIBS=\ $(LLIBS) \ + -lstdc++ \ # source files # local source files first, other sources after @@ -89,7 +90,7 @@ tests: $(TESTS) # target for vortex lib helios: compute_version $(DEPS) - $(CC) $(CFLAGS) $(DEPS) -o $@ $(LLIBS) + $(CC) $(CFLAGS) $(DEPS) -o $@ $(LIBS) # catch-all make target to generate .o and .d files %.o: %.cpp From 623b3307ef59f7136b060e5061c49b2464e74d23 Mon Sep 17 00:00:00 2001 From: Kurt LaVacque Date: Fri, 17 Oct 2025 18:53:06 +0200 Subject: [PATCH 11/17] Update Makefile to correct linking process for Helios target - Removed the C++ standard library from the linking process. - Adjusted the helios target to link only with local libraries, improving build accuracy. - These changes streamline the compilation process and enhance compatibility with the current project structure. --- HeliosCLI/Makefile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/HeliosCLI/Makefile b/HeliosCLI/Makefile index 00fb0276..a656391a 100644 --- a/HeliosCLI/Makefile +++ b/HeliosCLI/Makefile @@ -48,7 +48,6 @@ LLIBS=\ # MUST have LLIBS BEFORE the standard libraries LIBS=\ $(LLIBS) \ - -lstdc++ \ # source files # local source files first, other sources after @@ -90,7 +89,7 @@ tests: $(TESTS) # target for vortex lib helios: compute_version $(DEPS) - $(CC) $(CFLAGS) $(DEPS) -o $@ $(LIBS) + $(CC) $(CFLAGS) $(DEPS) -o $@ $(LLIBS) # catch-all make target to generate .o and .d files %.o: %.cpp From d8cbe03be97e345e71e4c3a88b1029e37bc06769 Mon Sep 17 00:00:00 2001 From: Kurt LaVacque Date: Sat, 18 Oct 2025 10:38:48 +0200 Subject: [PATCH 12/17] Revert comment style changes back to C++ style comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- Helios/Button.cpp | 28 ++-- Helios/Button.h | 34 ++--- Helios/Colorset.cpp | 34 ++--- Helios/Colorset.h | 76 +++++----- Helios/Colortypes.cpp | 82 +++++----- Helios/Colortypes.h | 14 +- Helios/Helios.cpp | 210 +++++++++++++------------- Helios/Helios.h | 4 +- Helios/HeliosConfig.h | 334 ++++++++++++++++++++--------------------- Helios/Led.cpp | 38 ++--- Helios/Led.h | 16 +- Helios/Pattern.cpp | 48 +++--- Helios/Pattern.h | 56 +++---- Helios/Patterns.cpp | 8 +- Helios/Patterns.h | 10 +- Helios/Random.cpp | 2 +- Helios/Random.h | 10 +- Helios/Storage.cpp | 56 +++---- Helios/Storage.h | 6 +- Helios/TimeControl.cpp | 40 ++--- Helios/TimeControl.h | 10 +- Helios/Timer.cpp | 12 +- Helios/Timer.h | 12 +- 23 files changed, 570 insertions(+), 570 deletions(-) diff --git a/Helios/Button.cpp b/Helios/Button.cpp index 99840598..4b81e748 100644 --- a/Helios/Button.cpp +++ b/Helios/Button.cpp @@ -12,7 +12,7 @@ #define BUTTON_PORT 2 #endif -/* Forward declaration */ +// Forward declaration #ifdef __cplusplus extern "C" { #endif @@ -23,12 +23,12 @@ void helios_terminate(void); #endif #ifdef HELIOS_CLI -/* Forward declarations for CLI functions */ +// Forward declarations for CLI functions static uint8_t button_process_pre_input(void); static uint8_t button_process_post_input(void); #endif -/* static members of Button */ +// static members of Button static uint32_t m_pressTime = 0; static uint32_t m_releaseTime = 0; static uint32_t m_holdDuration = 0; @@ -47,8 +47,8 @@ static uint8_t m_holdClick = 0; * The CLI input queue functionality is omitted for embedded targets. */ static uint8_t m_pinState = 0; static uint8_t m_enableWake = 0; -/* Simple input queue for CLI - using a fixed-size circular buffer */ -/* Larger queue size for CLI to handle long test sequences */ +// Simple input queue for CLI - using a fixed-size circular buffer +// Larger queue size for CLI to handle long test sequences #define INPUT_QUEUE_SIZE 4096 static char m_inputQueue[INPUT_QUEUE_SIZE]; static uint32_t m_queueHead = 0; @@ -79,7 +79,7 @@ uint8_t button_init(void) #ifdef HELIOS_ARDUINO pinMode(3, INPUT); #else - /* turn off wake */ + // turn off wake PCMSK &= ~(1 << PCINT3); GIMSK &= ~(1 << PCIE); #endif @@ -90,7 +90,7 @@ uint8_t button_init(void) void button_enable_wake(void) { #ifdef HELIOS_EMBEDDED - /* Configure INT0 to trigger on falling edge */ + // Configure INT0 to trigger on falling edge PCMSK |= (1 << PCINT3); GIMSK |= (1 << PCIE); sei(); @@ -136,7 +136,7 @@ uint8_t button_hold_pressing(void) void button_update(void) { #ifdef HELIOS_CLI - /* process any pre-input events in the queue */ + // process any pre-input events in the queue uint8_t processed_pre = button_process_pre_input(); #endif @@ -255,14 +255,14 @@ static uint8_t button_process_pre_input(void) helios_terminate(); break; case 'w': /* wait */ - /* wait is pre input I guess */ + // wait is pre input I guess break; default: /* return here! do not pop the queue * do not process post input events */ return 0; } - /* now pop whatever pre-input command was processed */ + // now pop whatever pre-input command was processed m_queueHead = (m_queueHead + 1) % INPUT_QUEUE_SIZE; return 1; } @@ -270,10 +270,10 @@ static uint8_t button_process_pre_input(void) static uint8_t button_process_post_input(void) { if (m_queueHead == m_queueTail) { - /* probably processed the pre-input event already */ + // probably processed the pre-input event already return 0; } - /* process input queue from the command line */ + // process input queue from the command line char command = m_inputQueue[m_queueHead]; switch (command) { case 'c': /* click button */ @@ -283,7 +283,7 @@ static uint8_t button_process_post_input(void) button_do_long_click(); break; default: - /* should never happen */ + // should never happen return 0; } m_queueHead = (m_queueHead + 1) % INPUT_QUEUE_SIZE; @@ -334,7 +334,7 @@ void button_do_toggle(void) m_pinState = !m_pinState; } -/* queue up an input event for the button */ +// queue up an input event for the button void button_queue_input(char input) { uint32_t nextTail = (m_queueTail + 1) % INPUT_QUEUE_SIZE; diff --git a/Helios/Button.h b/Helios/Button.h index 28bc2f7a..1cd534a4 100644 --- a/Helios/Button.h +++ b/Helios/Button.h @@ -7,52 +7,52 @@ extern "C" { #include -/* Initialize button */ +// Initialize button uint8_t button_init(void); -/* Directly poll the pin for whether it's pressed right now */ +// Directly poll the pin for whether it's pressed right now uint8_t button_check(void); -/* Poll the button pin and update the state of the button object */ +// Poll the button pin and update the state of the button object void button_update(void); -/* Whether the button was pressed this tick */ +// Whether the button was pressed this tick uint8_t button_on_press(void); -/* Whether the button was released this tick */ +// Whether the button was released this tick uint8_t button_on_release(void); -/* Whether the button is currently pressed */ +// Whether the button is currently pressed uint8_t button_is_pressed(void); -/* Whether the button was shortclicked this tick */ +// Whether the button was shortclicked this tick uint8_t button_on_short_click(void); -/* Whether the button was long clicked this tick */ +// Whether the button was long clicked this tick uint8_t button_on_long_click(void); -/* Whether the button was hold clicked this tick */ +// Whether the button was hold clicked this tick uint8_t button_on_hold_click(void); -/* Detect if the button is being held past long click */ +// Detect if the button is being held past long click uint8_t button_hold_pressing(void); -/* When the button was last pressed */ +// When the button was last pressed uint32_t button_press_time(void); -/* When the button was last released */ +// When the button was last released uint32_t button_release_time(void); -/* How long the button is currently or was last held down (in ticks) */ +// How long the button is currently or was last held down (in ticks) uint32_t button_hold_duration(void); -/* How long the button is currently or was last released for (in ticks) */ +// How long the button is currently or was last released for (in ticks) uint32_t button_release_duration(void); -/* The number of releases */ +// The number of releases uint8_t button_release_count(void); -/* Enable wake on press */ +// Enable wake on press void button_enable_wake(void); #ifdef HELIOS_CLI @@ -73,7 +73,7 @@ void button_do_press(void); void button_do_release(void); void button_do_toggle(void); -/* Queue up an input event for the button */ +// Queue up an input event for the button void button_queue_input(char input); uint32_t button_input_queue_size(void); #endif diff --git a/Helios/Colorset.cpp b/Helios/Colorset.cpp index e3779af9..758e7195 100644 --- a/Helios/Colorset.cpp +++ b/Helios/Colorset.cpp @@ -20,7 +20,7 @@ void colorset_init_multi(colorset_t *set, rgb_color_t c1, rgb_color_t c2, rgb_co rgb_color_t c4, rgb_color_t c5, rgb_color_t c6, rgb_color_t c7, rgb_color_t c8) { colorset_init(set); - /* would be nice if we could do this another way */ + // would be nice if we could do this another way if (!rgb_empty(&c1)) colorset_add_color(set, c1); if (!rgb_empty(&c2)) colorset_add_color(set, c2); if (!rgb_empty(&c3)) colorset_add_color(set, c3); @@ -54,7 +54,7 @@ void colorset_copy(colorset_t *dest, const colorset_t *src) uint8_t colorset_equals(const colorset_t *a, const colorset_t *b) { - /* only compare the palettes for equality */ + // only compare the palettes for equality return (a->m_numColors == b->m_numColors) && (memcmp(a->m_palette, b->m_palette, a->m_numColors * sizeof(rgb_color_t)) == 0); } @@ -86,7 +86,7 @@ uint8_t colorset_add_color(colorset_t *set, rgb_color_t col) if (set->m_numColors >= NUM_COLOR_SLOTS) { return 0; } - /* insert new color and increment number of colors */ + // insert new color and increment number of colors set->m_palette[set->m_numColors] = col; set->m_numColors++; return 1; @@ -159,7 +159,7 @@ void colorset_remove_color(colorset_t *set, uint8_t index) void colorset_randomize_colors(colorset_t *set, random_t *ctx, uint8_t numColors, enum colorset_color_mode mode) { - /* if they specify randomly pick the color mode then roll it */ + // if they specify randomly pick the color mode then roll it if (mode >= COLOR_MODE_RANDOMLY_PICK) { mode = (enum colorset_color_mode)(random_next8(ctx, 0, 255) % COLOR_MODE_COUNT); } @@ -173,7 +173,7 @@ void colorset_randomize_colors(colorset_t *set, random_t *ctx, uint8_t numColors colorGap = random_next8(ctx, 16, 256 / (numColors - 1)); } enum colorset_value_style valStyle = (enum colorset_value_style)random_next8(ctx, 0, VAL_STYLE_COUNT); - /* the doubleStyle decides if some colors are added to the set twice */ + // the doubleStyle decides if some colors are added to the set twice uint8_t doubleStyle = 0; if (numColors <= 7) { doubleStyle = random_next8(ctx, 0, 1); @@ -194,7 +194,7 @@ void colorset_randomize_colors(colorset_t *set, random_t *ctx, uint8_t numColors hueToUse = (randomizedHue + (256 / numColors) * i); } colorset_add_color_with_value_style(set, ctx, hueToUse, valueToUse, valStyle, numColors, i); - /* double all colors or only first color */ + // double all colors or only first color if (doubleStyle == 2 || (doubleStyle == 1 && !i)) { colorset_add_color_with_value_style(set, ctx, hueToUse, valueToUse, valStyle, numColors, i); } @@ -225,7 +225,7 @@ void colorset_set(colorset_t *set, uint8_t index, rgb_color_t col) * ie adding a new color when you set an index higher than the max */ if (index >= set->m_numColors) { if (!colorset_add_color(set, col)) { - /* ERROR_LOGF("Failed to add new color at index %u", index); */ + // ERROR_LOGF("Failed to add new color at index %u", index); } return; } @@ -237,12 +237,12 @@ void colorset_skip(colorset_t *set, int32_t amount) if (!set->m_numColors) { return; } - /* if the colorset hasn't started yet */ + // if the colorset hasn't started yet if (set->m_curIndex == INDEX_INVALID) { set->m_curIndex = 0; } - /* first modulate the amount to skip to be within +/- the number of colors */ + // first modulate the amount to skip to be within +/- the number of colors amount %= (int32_t)set->m_numColors; /* max = 3 @@ -250,7 +250,7 @@ void colorset_skip(colorset_t *set, int32_t amount) * amount = -10 */ set->m_curIndex = ((int32_t)set->m_curIndex + (int32_t)amount) % (int32_t)set->m_numColors; if (set->m_curIndex > set->m_numColors) { /* must have wrapped */ - /* simply wrap it back */ + // simply wrap it back set->m_curIndex += set->m_numColors; } } @@ -293,13 +293,13 @@ rgb_color_t colorset_get_prev(colorset_t *set) rgb_init_from_raw(&result, RGB_OFF); return result; } - /* handle wrapping at 0 */ + // handle wrapping at 0 if (set->m_curIndex == 0 || set->m_curIndex == INDEX_INVALID) { set->m_curIndex = colorset_num_colors(set) - 1; } else { set->m_curIndex--; } - /* return the color */ + // return the color return set->m_palette[set->m_curIndex]; } @@ -310,11 +310,11 @@ rgb_color_t colorset_get_next(colorset_t *set) rgb_init_from_raw(&result, RGB_OFF); return result; } - /* iterate current index, let it wrap at max uint8 */ + // iterate current index, let it wrap at max uint8 set->m_curIndex++; - /* then modulate the result within max colors */ + // then modulate the result within max colors set->m_curIndex %= colorset_num_colors(set); - /* return the color */ + // return the color return set->m_palette[set->m_curIndex]; } @@ -326,7 +326,7 @@ rgb_color_t colorset_peek(const colorset_t *set, int32_t offset) return result; } uint8_t nextIndex = 0; - /* get index of the next color */ + // get index of the next color if (offset >= 0) { nextIndex = (set->m_curIndex + offset) % colorset_num_colors(set); } else { @@ -336,7 +336,7 @@ rgb_color_t colorset_peek(const colorset_t *set, int32_t offset) } nextIndex = ((set->m_curIndex + colorset_num_colors(set)) + (int)offset) % colorset_num_colors(set); } - /* return the color */ + // return the color return set->m_palette[nextIndex]; } diff --git a/Helios/Colorset.h b/Helios/Colorset.h index 1e194158..eccc28a3 100644 --- a/Helios/Colorset.h +++ b/Helios/Colorset.h @@ -9,131 +9,131 @@ extern "C" { #include "HeliosConfig.h" -/* Forward declaration */ +// Forward declaration typedef struct random_t random_t; typedef struct colorset_t colorset_t; enum colorset_value_style { - /* Random values */ + // Random values VAL_STYLE_RANDOM = 0, - /* First color low value, the rest are random */ + // First color low value, the rest are random VAL_STYLE_LOW_FIRST_COLOR, - /* First color high value, the rest are low */ + // First color high value, the rest are low VAL_STYLE_HIGH_FIRST_COLOR, - /* Alternate between high and low value */ + // Alternate between high and low value VAL_STYLE_ALTERNATING, - /* Ascending values from low to high */ + // Ascending values from low to high VAL_STYLE_ASCENDING, - /* Descending values from high to low */ + // Descending values from high to low VAL_STYLE_DESCENDING, - /* Constant value */ + // Constant value VAL_STYLE_CONSTANT, - /* Total number of value styles */ + // Total number of value styles VAL_STYLE_COUNT }; enum colorset_color_mode { - /* randomize with color theory */ + // randomize with color theory COLOR_MODE_COLOR_THEORY, - /* randomize a monochromatic set */ + // randomize a monochromatic set COLOR_MODE_MONOCHROMATIC, - /* randomize an evenly spaced hue set */ + // randomize an evenly spaced hue set COLOR_MODE_EVENLY_SPACED, - /* total different randomize modes above */ + // total different randomize modes above COLOR_MODE_COUNT, - /* EXTRA OPTION: randomly pick one of the other 3 options */ + // EXTRA OPTION: randomly pick one of the other 3 options COLOR_MODE_RANDOMLY_PICK = COLOR_MODE_COUNT, }; struct colorset_t { - /* palette of colors */ + // palette of colors rgb_color_t m_palette[NUM_COLOR_SLOTS]; - /* the actual number of colors in the set */ + // the actual number of colors in the set uint8_t m_numColors; /* the current index, starts at 255 so that * the very first call to colorset_getNext will iterate to 0 */ uint8_t m_curIndex; }; -/* Empty colorset */ +// Empty colorset void colorset_init(colorset_t *set); -/* Initialize with up to 8 colors */ +// Initialize with up to 8 colors void colorset_init_multi(colorset_t *set, rgb_color_t c1, rgb_color_t c2, rgb_color_t c3, rgb_color_t c4, rgb_color_t c5, rgb_color_t c6, rgb_color_t c7, rgb_color_t c8); -/* Initialize from array of colors */ +// Initialize from array of colors void colorset_init_array(colorset_t *set, uint8_t numCols, const uint32_t *cols); -/* Copy colorset */ +// Copy colorset void colorset_copy(colorset_t *dest, const colorset_t *src); -/* Equality operators */ +// Equality operators uint8_t colorset_equals(const colorset_t *a, const colorset_t *b); -/* Clear the colorset */ +// Clear the colorset void colorset_clear(colorset_t *set); -/* CRC the colorset */ +// CRC the colorset uint32_t colorset_crc32(const colorset_t *set); -/* Index operator to access color index */ +// Index operator to access color index rgb_color_t colorset_get_at_index(const colorset_t *set, int index); -/* Add a single color */ +// Add a single color uint8_t colorset_add_color(colorset_t *set, rgb_color_t col); uint8_t colorset_add_color_hsv(colorset_t *set, uint8_t hue, uint8_t sat, uint8_t val); void colorset_add_color_with_value_style(colorset_t *set, random_t *ctx, uint8_t hue, uint8_t sat, enum colorset_value_style valStyle, uint8_t numColors, uint8_t colorPos); void colorset_remove_color(colorset_t *set, uint8_t index); -/* Function to randomize the colors with various different modes of randomization */ +// Function to randomize the colors with various different modes of randomization void colorset_randomize_colors(colorset_t *set, random_t *ctx, uint8_t numColors, enum colorset_color_mode color_mode); -/* Fade all of the colors in the set */ +// Fade all of the colors in the set void colorset_adjust_brightness(colorset_t *set, uint8_t fadeby); -/* Get a color from the colorset */ +// Get a color from the colorset rgb_color_t colorset_get(const colorset_t *set, uint8_t index); /* Set an rgb color in a slot, or add a new color if you specify * a slot higher than the number of colors in the colorset */ void colorset_set(colorset_t *set, uint8_t index, rgb_color_t col); -/* Skip some amount of colors */ +// Skip some amount of colors void colorset_skip(colorset_t *set, int32_t amount); -/* Get current color in cycle */ +// Get current color in cycle rgb_color_t colorset_cur(const colorset_t *set); -/* Set the current index of the colorset */ +// Set the current index of the colorset void colorset_set_cur_index(colorset_t *set, uint8_t index); void colorset_reset_index(colorset_t *set); -/* The current index */ +// The current index uint8_t colorset_cur_index(const colorset_t *set); -/* Get the prev color in cycle */ +// Get the prev color in cycle rgb_color_t colorset_get_prev(colorset_t *set); -/* Get the next color in cycle */ +// Get the next color in cycle rgb_color_t colorset_get_next(colorset_t *set); -/* Peek at the color indexes from current but don't iterate */ +// Peek at the color indexes from current but don't iterate rgb_color_t colorset_peek(const colorset_t *set, int32_t offset); -/* Better wording for peek 1 ahead */ +// Better wording for peek 1 ahead rgb_color_t colorset_peek_next(const colorset_t *set); -/* The number of colors in the palette */ +// The number of colors in the palette uint8_t colorset_num_colors(const colorset_t *set); -/* Whether the colorset is currently on the first color or last color */ +// Whether the colorset is currently on the first color or last color uint8_t colorset_on_start(const colorset_t *set); uint8_t colorset_on_end(const colorset_t *set); diff --git a/Helios/Colortypes.cpp b/Helios/Colortypes.cpp index be745d7f..813f0dc5 100644 --- a/Helios/Colortypes.cpp +++ b/Helios/Colortypes.cpp @@ -1,11 +1,11 @@ #include "Colortypes.h" #if ALTERNATIVE_HSV_RGB == 1 -/* global hsv to rgb algorithm selector */ +// global hsv to rgb algorithm selector enum hsv_to_rgb_algorithm g_hsv_rgb_alg = HSV_TO_RGB_GENERIC; #endif -/* ========== HSVColor functions ========== */ +// ========== HSVColor functions ========== void hsv_init(hsv_color_t *hsv) { @@ -48,7 +48,7 @@ void hsv_assign_from_raw(hsv_color_t *hsv, uint32_t rhs) void hsv_assign_from_rgb(hsv_color_t *hsv, const rgb_color_t *rhs) { - /* always use generic */ + // always use generic hsv_color_t temp = rgb_to_hsv_generic(rhs); hsv_copy(hsv, &temp); } @@ -75,7 +75,7 @@ uint32_t hsv_raw(const hsv_color_t *hsv) return ((uint32_t)hsv->hue << 16) | ((uint32_t)hsv->sat << 8) | (uint32_t)hsv->val; } -/* ========== RGBColor functions ========== */ +// ========== RGBColor functions ========== void rgb_init(rgb_color_t *rgb) { @@ -152,7 +152,7 @@ void rgb_clear(rgb_color_t *rgb) rgb->blue = 0; } -/* scale down the brightness of a color by some fade amount */ +// scale down the brightness of a color by some fade amount void rgb_adjust_brightness(rgb_color_t *rgb, uint8_t fadeBy) { rgb->red = (((int)rgb->red) * (int)(256 - fadeBy)) >> 8; @@ -166,7 +166,7 @@ uint32_t rgb_raw(const rgb_color_t *rgb) } #ifdef HELIOS_CLI -/* Adjust brightness to ensure visibility on screens, without floating-point arithmetic */ +// Adjust brightness to ensure visibility on screens, without floating-point arithmetic void rgb_bring_up_brightness(rgb_color_t *rgb, uint8_t min_brightness) { hsv_color_t col; @@ -181,10 +181,10 @@ void rgb_bring_up_brightness(rgb_color_t *rgb, uint8_t min_brightness) rgb_assign_from_hsv(rgb, &col); } -/* scale a uint8 by a float value, don't use this on embedded! */ +// scale a uint8 by a float value, don't use this on embedded! #define FSCALE8(x, scale) (uint8_t)(((float)x * scale) > 255 ? 255 : ((float)x * scale)) -/* return a scaled up the brightness version of the current color */ +// return a scaled up the brightness version of the current color void rgb_scale_brightness(rgb_color_t *rgb, float scale) { rgb->red = FSCALE8(rgb->red, scale); @@ -231,26 +231,26 @@ rgb_color_t hsv_to_rgb_rainbow(const hsv_color_t *rhs) uint8_t offset = hue & 0x1F; /* 0..31 */ - /* offset8 = offset * 8 */ + // offset8 = offset * 8 uint8_t offset8 = offset; offset8 <<= 3; uint8_t third = SCALE8(offset8, (256 / 3)); /* max = 85 */ uint8_t r, g, b; if (!(hue & 0x80)) { - /* 0XX */ + // 0XX if (!(hue & 0x40)) { - /* 00X */ - /* section 0-1 */ + // 00X + // section 0-1 if (!(hue & 0x20)) { - /* 000 */ - /* case 0: R -> O */ + // 000 + // case 0: R -> O r = 255 - third; g = third; b = 0; } else { - /* 001 */ - /* case 1: O -> Y */ + // 001 + // case 1: O -> Y if (Y1) { r = 171; g = 85 + third; @@ -258,20 +258,20 @@ rgb_color_t hsv_to_rgb_rainbow(const hsv_color_t *rhs) } if (Y2) { r = 170 + third; - /* uint8_t twothirds = (third << 1); */ + // uint8_t twothirds = (third << 1); uint8_t twothirds = SCALE8(offset8, ((256 * 2) / 3)); /* max=170 */ g = 85 + twothirds; b = 0; } } } else { - /* 01X */ - /* section 2-3 */ + // 01X + // section 2-3 if (!(hue & 0x20)) { - /* 010 */ - /* case 2: Y -> G */ + // 010 + // case 2: Y -> G if (Y1) { - /* uint8_t twothirds = (third << 1); */ + // uint8_t twothirds = (third << 1); uint8_t twothirds = SCALE8(offset8, ((256 * 2) / 3)); /* max=170 */ r = 171 - twothirds; g = 170 + third; @@ -283,43 +283,43 @@ rgb_color_t hsv_to_rgb_rainbow(const hsv_color_t *rhs) b = 0; } } else { - /* 011 */ - /* case 3: G -> A */ + // 011 + // case 3: G -> A r = 0; g = 255 - third; b = third; } } } else { - /* section 4-7 */ - /* 1XX */ + // section 4-7 + // 1XX if (!(hue & 0x40)) { - /* 10X */ + // 10X if (!(hue & 0x20)) { - /* 100 */ - /* case 4: A -> B */ + // 100 + // case 4: A -> B r = 0; - /* uint8_t twothirds = (third << 1); */ + // uint8_t twothirds = (third << 1); uint8_t twothirds = SCALE8(offset8, ((256 * 2) / 3)); /* max=170 */ g = 171 - twothirds; /* 170? */ b = 85 + twothirds; } else { - /* 101 */ - /* case 5: B -> P */ + // 101 + // case 5: B -> P r = third; g = 0; b = 255 - third; } } else { if (!(hue & 0x20)) { - /* 110 */ - /* case 6: P -- K */ + // 110 + // case 6: P -- K r = 85 + third; g = 0; b = 171 - third; } else { - /* 111 */ - /* case 7: K -> R */ + // 111 + // case 7: K -> R r = 170 + third; g = 0; b = 85 - third; @@ -352,13 +352,13 @@ rgb_color_t hsv_to_rgb_rainbow(const hsv_color_t *rhs) } } - /* Now scale everything down if we're at value < 255. */ + // Now scale everything down if we're at value < 255. if (val != 255) { val = SCALE8(val, val); if (val == 0) { r = 0; g = 0; b = 0; } else { - /* nSCALE8x3_video( r, g, b, val); */ + // nSCALE8x3_video( r, g, b, val); if (r) r = SCALE8(r, val) + 1; if (g) g = SCALE8(g, val) + 1; if (b) b = SCALE8(b, val) + 1; @@ -376,7 +376,7 @@ rgb_color_t hsv_to_rgb_rainbow(const hsv_color_t *rhs) } #endif -/* generic hsv to rgb conversion nothing special */ +// generic hsv to rgb conversion nothing special rgb_color_t hsv_to_rgb_generic(const hsv_color_t *rhs) { unsigned char region, remainder, p, q, t; @@ -392,7 +392,7 @@ rgb_color_t hsv_to_rgb_generic(const hsv_color_t *rhs) region = rhs->hue / 43; remainder = ((rhs->hue - (region * 43)) * 6); - /* extraneous casts to uint16_t are to prevent overflow */ + // extraneous casts to uint16_t are to prevent overflow p = (uint8_t)(((uint16_t)(rhs->val) * (255 - rhs->sat)) >> 8); q = (uint8_t)(((uint16_t)(rhs->val) * (255 - (((uint16_t)(rhs->sat) * remainder) >> 8))) >> 8); t = (uint8_t)(((uint16_t)(rhs->val) * (255 - (((uint16_t)(rhs->sat) * (255 - remainder)) >> 8))) >> 8); @@ -420,7 +420,7 @@ rgb_color_t hsv_to_rgb_generic(const hsv_color_t *rhs) return col; } -/* Convert rgb to hsv with generic fast method */ +// Convert rgb to hsv with generic fast method hsv_color_t rgb_to_hsv_generic(const rgb_color_t *rhs) { unsigned char rgbMin, rgbMax; diff --git a/Helios/Colortypes.h b/Helios/Colortypes.h index f7b5d7f3..d32040eb 100644 --- a/Helios/Colortypes.h +++ b/Helios/Colortypes.h @@ -22,7 +22,7 @@ enum hsv_to_rgb_algorithm extern enum hsv_to_rgb_algorithm g_hsv_rgb_alg; #endif -/* Forward declarations */ +// Forward declarations typedef struct hsv_color_t hsv_color_t; typedef struct rgb_color_t rgb_color_t; @@ -40,7 +40,7 @@ struct rgb_color_t uint8_t blue; }; -/* HSVColor functions */ +// HSVColor functions void hsv_init(hsv_color_t *hsv); void hsv_init3(hsv_color_t *hsv, uint8_t hue, uint8_t sat, uint8_t val); void hsv_init_from_raw(hsv_color_t *hsv, uint32_t dwVal); @@ -53,7 +53,7 @@ uint8_t hsv_empty(const hsv_color_t *hsv); void hsv_clear(hsv_color_t *hsv); uint32_t hsv_raw(const hsv_color_t *hsv); -/* RGBColor functions */ +// RGBColor functions void rgb_init(rgb_color_t *rgb); void rgb_init3(rgb_color_t *rgb, uint8_t red, uint8_t green, uint8_t blue); void rgb_init_from_raw(rgb_color_t *rgb, uint32_t dwVal); @@ -72,18 +72,18 @@ uint32_t rgb_raw(const rgb_color_t *rgb); * ex: 0.0 = black, 0.5 = half brightness, 1.0 = no change, * 1.5 = 50% brighter, 2.0 = twice as bright, 255.0 = white */ void rgb_scale_brightness(rgb_color_t *rgb, float scale); -/* Bring up the brightness of a color to a minimum level */ +// Bring up the brightness of a color to a minimum level void rgb_bring_up_brightness(rgb_color_t *rgb, uint8_t min_brightness); #endif -/* Conversion functions */ +// Conversion functions /* Stolen from FastLED hsv to rgb full rainbow where all colours * are given equal weight, this makes for-example yellow larger * best to use this function as it is the legacy choice */ rgb_color_t hsv_to_rgb_rainbow(const hsv_color_t *rhs); -/* Generic hsv to rgb conversion nothing special */ +// Generic hsv to rgb conversion nothing special rgb_color_t hsv_to_rgb_generic(const hsv_color_t *rhs); -/* Convert rgb to hsv with generic fast method */ +// Convert rgb to hsv with generic fast method hsv_color_t rgb_to_hsv_generic(const rgb_color_t *rhs); #ifdef __cplusplus diff --git a/Helios/Helios.cpp b/Helios/Helios.cpp index f70e1ebc..cc1f3757 100644 --- a/Helios/Helios.cpp +++ b/Helios/Helios.cpp @@ -23,15 +23,15 @@ #include -/* some internal macros that shouldn't change */ -/* The number of menus in hue/sat/val selection */ +// some internal macros that shouldn't change +// The number of menus in hue/sat/val selection #define NUM_COLORS_PER_GROUP 4 -/* the number of color groups in the color selection menu */ +// the number of color groups in the color selection menu #define NUM_COLOR_GROUPS 4 -/* the number of menus in group selection */ +// the number of menus in group selection #define NUM_MENUS_GROUP 8 -/* Forward declarations for internal functions */ +// Forward declarations for internal functions static uint8_t helios_init_components(void); static void helios_handle_state(void); static void helios_handle_state_modes(void); @@ -46,7 +46,7 @@ static void helios_handle_state_set_defaults(void); static void helios_show_selection(rgb_color_t color); static void helios_factory_reset(void); -/* the slot selection returns this info for internal menu logic */ +// the slot selection returns this info for internal menu logic enum helios_color_select_option { OPTION_NONE = 0, @@ -67,7 +67,7 @@ enum helios_state { #endif }; -/* static members */ +// static members static enum helios_state cur_state; static enum helios_flags global_flags; static uint8_t menu_selection; @@ -87,25 +87,25 @@ volatile char helios_version[] = HELIOS_VERSION_STR; uint8_t helios_init(void) { - /* first initialize all the components of helios */ + // first initialize all the components of helios if (!helios_init_components()) { return 0; } - /* then initialize the hardware for embedded helios */ + // then initialize the hardware for embedded helios #ifdef HELIOS_EMBEDDED - /* Set PB0, PB1, PB4 as output */ + // Set PB0, PB1, PB4 as output DDRB |= (1 << DDB0) | (1 << DDB1) | (1 << DDB4); - /* Timer0 Configuration for PWM */ + // Timer0 Configuration for PWM TCCR0A = (1 << WGM01) | (1 << WGM00) | (1 << COM0A1) | (1 << COM0B1); - /* No prescaler */ + // No prescaler TCCR0B = (1 << CS00); - /* Timer1 for PWM on PB4, Fast PWM, Non-inverting, No prescaler */ + // Timer1 for PWM on PB4, Fast PWM, Non-inverting, No prescaler TCCR1 = (1 << PWM1A) | (1 << COM1A1) | (1 << CS10); - /* Enable PWM on OC1B */ + // Enable PWM on OC1B GTCCR = (1 << PWM1B) | (1 << COM1B1); - /* Enable Timer0 overflow interrupt */ + // Enable Timer0 overflow interrupt TIMSK |= (1 << TOIE0); - /* Enable interrupts */ + // Enable interrupts sei(); #endif return 1; @@ -113,7 +113,7 @@ uint8_t helios_init(void) static uint8_t helios_init_components(void) { - /* initialize various components of Helios */ + // initialize various components of Helios if (!time_init()) { return 0; } @@ -126,7 +126,7 @@ static uint8_t helios_init_components(void) if (!button_init()) { return 0; } - /* initialize global variables */ + // initialize global variables cur_state = STATE_MODES; menu_selection = 0; cur_mode = 0; @@ -153,7 +153,7 @@ void helios_tick(void) * state by checking button globals, then run the appropriate logic */ helios_handle_state(); - /* Update the Leds once per frame */ + // Update the Leds once per frame led_update(); /* finally tick the clock forward and then sleep till the entire @@ -164,29 +164,29 @@ void helios_tick(void) void helios_enter_sleep(void) { #ifdef HELIOS_EMBEDDED - /* clear the led colors */ + // clear the led colors led_clear(); - /* Set all pins to input */ + // Set all pins to input DDRB = 0x00; - /* Disable pull-ups on all pins */ + // Disable pull-ups on all pins PORTB = 0x00; - /* Enable wake on interrupt for the button */ + // Enable wake on interrupt for the button button_enable_wake(); - /* Set sleep mode to POWER DOWN mode */ + // Set sleep mode to POWER DOWN mode set_sleep_mode(SLEEP_MODE_PWR_DOWN); - /* enter sleep */ + // enter sleep sleep_mode(); - /* ... interrupt will make us wake here */ + // ... interrupt will make us wake here - /* Set PB0, PB1, PB4 as output */ + // Set PB0, PB1, PB4 as output DDRB |= (1 << DDB0) | (1 << DDB1) | (1 << DDB4); - /* wakeup here, re-init */ + // wakeup here, re-init helios_init_components(); #else cur_state = STATE_SLEEP; - /* enable the sleep bool */ + // enable the sleep bool sleeping = 1; - /* Enable wake on button press/click for CLI */ + // Enable wake on button press/click for CLI button_enable_wake(); #endif } @@ -194,44 +194,44 @@ void helios_enter_sleep(void) void helios_wakeup(void) { #ifdef HELIOS_EMBEDDED - /* nothing needed here, this interrupt firing will make the mainthread resume */ + // nothing needed here, this interrupt firing will make the mainthread resume #else /* if the button was held down then they are entering off-menus * but if we re-initialize the button it will clear this state */ uint8_t pressed = button_is_pressed(); - /* re-initialize some stuff */ + // re-initialize some stuff time_init(); button_init(); - /* so just re-press it */ + // so just re-press it if (pressed) { button_do_press(); } cur_state = STATE_MODES; - /* turn off the sleeping flag that only CLI has */ + // turn off the sleeping flag that only CLI has sleeping = 0; #endif } void helios_load_next_mode(void) { - /* increment current mode and wrap around */ + // increment current mode and wrap around cur_mode = (uint8_t)(cur_mode + 1) % NUM_MODE_SLOTS; - /* now load current mode again */ + // now load current mode again helios_load_cur_mode(); } void helios_load_cur_mode(void) { - /* read pattern from storage at cur mode index */ + // read pattern from storage at cur mode index if (!storage_read_pattern(cur_mode, &pat)) { - /* and just initialize default if it cannot be read */ + // and just initialize default if it cannot be read patterns_make_default(cur_mode, &pat); - /* try to write it out because storage was corrupt */ + // try to write it out because storage was corrupt storage_write_pattern(cur_mode, &pat); } - /* then re-initialize the pattern */ + // then re-initialize the pattern pattern_init_state(&pat); - /* Update the last mode switch time when loading a mode */ + // Update the last mode switch time when loading a mode last_mode_switch_time = time_get_current_time(); } @@ -242,7 +242,7 @@ void helios_save_cur_mode(void) void helios_load_global_flags(void) { - /* read the global flags from index 0 config */ + // read the global flags from index 0 config global_flags = (enum helios_flags)storage_read_global_flags(); cur_mode = storage_read_current_mode(); } @@ -256,7 +256,7 @@ void helios_save_global_flags(void) void helios_set_mode_index(uint8_t mode_index) { cur_mode = (uint8_t)mode_index % NUM_MODE_SLOTS; - /* now load current mode again */ + // now load current mode again helios_load_cur_mode(); } @@ -304,21 +304,21 @@ pattern_t *helios_cur_pattern(void) static void helios_handle_state(void) { - /* check for the force sleep button hold regardless of which state we're in */ + // check for the force sleep button hold regardless of which state we're in if (button_hold_duration() > FORCE_SLEEP_TIME) { - /* when released the device will just sleep */ + // when released the device will just sleep if (button_on_release()) { helios_enter_sleep(); - /* ALWAYS RETURN AFTER SLEEP! WE WILL WAKE HERE! */ + // ALWAYS RETURN AFTER SLEEP! WE WILL WAKE HERE! return; } - /* but as long as it's held past the sleep time it just turns off the led */ + // but as long as it's held past the sleep time it just turns off the led if (button_is_pressed()) { led_clear(); return; } } - /* otherwise just handle the state like normal */ + // otherwise just handle the state like normal switch (cur_state) { case STATE_MODES: helios_handle_state_modes(); @@ -338,7 +338,7 @@ static void helios_handle_state(void) break; #ifdef HELIOS_CLI case STATE_SLEEP: - /* simulate sleep in helios CLI */ + // simulate sleep in helios CLI if (button_on_press() || button_on_short_click() || button_on_long_click()) { helios_wakeup(); } @@ -349,7 +349,7 @@ static void helios_handle_state(void) static void helios_handle_state_modes(void) { - /* whether they have released the button since turning on */ + // whether they have released the button since turning on uint8_t hasReleased = (button_release_count() > 0); if (button_release_count() > 1 && button_on_short_click()) { @@ -357,35 +357,35 @@ static void helios_handle_state_modes(void) return; } - /* check for lock and go back to sleep */ + // check for lock and go back to sleep if (helios_has_flag(FLAG_LOCKED) && hasReleased && !button_on_release()) { helios_enter_sleep(); - /* ALWAYS RETURN AFTER SLEEP! WE WILL WAKE HERE! */ + // ALWAYS RETURN AFTER SLEEP! WE WILL WAKE HERE! return; } if (!helios_has_flag(FLAG_LOCKED) && hasReleased) { - /* just play the current mode */ + // just play the current mode pattern_play(&pat); } - /* check how long the button is held */ + // check how long the button is held uint32_t holdDur = button_hold_duration(); /* calculate a magnitude which corresponds to how many times past the MENU_HOLD_TIME * the user has held the button, so 0 means haven't held fully past one yet, etc */ uint8_t magnitude = (uint8_t)(holdDur / MENU_HOLD_TIME); - /* whether the user has held the button longer than a short click */ + // whether the user has held the button longer than a short click uint8_t heldPast = (holdDur > SHORT_CLICK_THRESHOLD); - /* flash red briefly when locked and short clicked */ + // flash red briefly when locked and short clicked if (helios_has_flag(FLAG_LOCKED) && holdDur < SHORT_CLICK_THRESHOLD) { rgb_color_t red; rgb_init_from_raw(&red, RGB_RED_BRI_LOW); led_set_rgb(&red); } - /* if the button is held for at least 1 second */ + // if the button is held for at least 1 second if (button_is_pressed() && heldPast) { rgb_color_t color; - /* if the button has been released before then show the on menu */ + // if the button has been released before then show the on menu if (hasReleased) { switch (magnitude) { default: @@ -410,15 +410,15 @@ static void helios_handle_state_modes(void) } } } - /* if this isn't a release tick there's nothing more to do */ + // if this isn't a release tick there's nothing more to do if (button_on_release()) { - /* Resets the menu selection before entering new state */ + // Resets the menu selection before entering new state menu_selection = 0; if (heldPast && button_release_count() == 1) { helios_handle_off_menu(magnitude, heldPast); return; } - /* otherwise if we have released it then we are in the 'on' menu */ + // otherwise if we have released it then we are in the 'on' menu helios_handle_on_menu(magnitude, heldPast); } } @@ -426,22 +426,22 @@ static void helios_handle_state_modes(void) static void helios_handle_off_menu(uint8_t mag, uint8_t past) { (void)past; /* unused */ - /* if still locked then handle the unlocking menu which is just if mag == 5 */ + // if still locked then handle the unlocking menu which is just if mag == 5 if (helios_has_flag(FLAG_LOCKED)) { switch (mag) { case TIME_TILL_GLOW_LOCK_UNLOCK: /* red lock */ cur_state = STATE_TOGGLE_LOCK; break; default: - /* just go back to sleep in hold-past off menu */ + // just go back to sleep in hold-past off menu helios_enter_sleep(); - /* ALWAYS RETURN AFTER SLEEP! WE WILL WAKE HERE! */ + // ALWAYS RETURN AFTER SLEEP! WE WILL WAKE HERE! } - /* in this case we return either way, since we're locked */ + // in this case we return either way, since we're locked return; } - /* otherwise if not locked handle the off menu */ + // otherwise if not locked handle the off menu switch (mag) { case 1: /* red lock */ cur_state = STATE_TOGGLE_LOCK; @@ -451,9 +451,9 @@ static void helios_handle_off_menu(uint8_t mag, uint8_t past) cur_state = STATE_SET_DEFAULTS; return; /* RETURN HERE */ default: - /* just go back to sleep in hold-past off menu */ + // just go back to sleep in hold-past off menu helios_enter_sleep(); - /* ALWAYS RETURN AFTER SLEEP! WE WILL WAKE HERE! */ + // ALWAYS RETURN AFTER SLEEP! WE WILL WAKE HERE! return; } } @@ -462,30 +462,30 @@ static void helios_handle_on_menu(uint8_t mag, uint8_t past) { switch (mag) { case 0: /* off */ - /* but only if we held for more than a short click */ + // but only if we held for more than a short click if (past) { helios_enter_sleep(); - /* ALWAYS RETURN AFTER SLEEP! WE WILL WAKE HERE! */ + // ALWAYS RETURN AFTER SLEEP! WE WILL WAKE HERE! return; } break; case 1: /* color select */ cur_state = STATE_COLOR_GROUP_SELECTION; - /* reset the menu selection and colors selected */ + // reset the menu selection and colors selected menu_selection = 0; num_colors_selected = 0; - /* Store original colorset before clearing */ + // Store original colorset before clearing new_colorset = *pattern_colorset_ptr(&pat); - /* Clear existing colors in pattern */ + // Clear existing colors in pattern colorset_clear(&new_colorset); #if ALTERNATIVE_HSV_RGB == 1 - /* use the nice hue to rgb rainbow */ + // use the nice hue to rgb rainbow g_hsv_rgb_alg = HSV_TO_RGB_RAINBOW; #endif break; case 2: /* pat select */ cur_state = STATE_PATTERN_SELECT; - /* reset the menu selection */ + // reset the menu selection menu_selection = 0; break; default: /* hold past */ @@ -497,10 +497,10 @@ struct colors_menu_data { uint32_t colors[4]; }; -/* array of colors for selection */ +// array of colors for selection static const struct colors_menu_data color_menu_data[NUM_COLOR_GROUPS] = { - /* color0 color1 color2 color3 */ - /* =================================================================== */ + // color0 color1 color2 color3 + // =================================================================== { {RGB_RED, RGB_CORAL_ORANGE, RGB_ORANGE, RGB_YELLOW} }, { {RGB_LIME_GREEN, RGB_GREEN, RGB_SEAFOAM, RGB_TURQUOISE} }, { {RGB_ICE_BLUE, RGB_LIGHT_BLUE, RGB_BLUE, RGB_ROYAL_BLUE} }, @@ -511,22 +511,22 @@ static void helios_handle_state_color_selection(void) { switch (cur_state) { case STATE_COLOR_GROUP_SELECTION: - /* pick the hue group */ + // pick the hue group helios_handle_state_color_group_selection(); break; case STATE_COLOR_VARIANT_SELECTION: - /* pick the hue */ + // pick the hue helios_handle_state_color_variant_selection(); break; default: break; } - /* get the current color */ + // get the current color rgb_color_t cur = led_get(); cur.red /= 2; cur.green /= 2; cur.blue /= 2; - /* show selection in all of these menus */ + // show selection in all of these menus helios_show_selection(cur); } @@ -538,7 +538,7 @@ static void helios_handle_state_color_group_selection(void) menu_selection = (menu_selection + 1) % NUM_COLOR_GROUPS; } - /* Display a sample color from the selected group */ + // Display a sample color from the selected group rgb_init_from_raw(&color, color_menu_data[menu_selection].colors[0]); led_set_rgb(&color); @@ -554,11 +554,11 @@ static void helios_handle_state_color_variant_selection(void) rgb_color_t color; if (button_on_short_click()) { - /* If we've selected max colors, next click exits */ + // If we've selected max colors, next click exits if (num_colors_selected >= NUM_COLOR_SLOTS) { - /* Apply the newly built colorset */ + // Apply the newly built colorset pattern_set_colorset(&pat, &new_colorset); - /* Save and return to normal mode */ + // Save and return to normal mode helios_save_cur_mode(); cur_state = STATE_MODES; menu_selection = 0; @@ -568,26 +568,26 @@ static void helios_handle_state_color_variant_selection(void) return; } - /* Cycle through colors in the group */ + // Cycle through colors in the group menu_selection = (menu_selection + 1) % NUM_COLORS_PER_GROUP; } - /* Display the currently selected color */ + // Display the currently selected color rgb_init_from_raw(&color, color_menu_data[selected_base_group].colors[menu_selection]); led_set_rgb(&color); if (button_on_long_click()) { - /* Add the selected color to the colorset */ + // Add the selected color to the colorset rgb_init_from_raw(&color, color_menu_data[selected_base_group].colors[menu_selection]); if (colorset_add_color(&new_colorset, color)) { num_colors_selected++; } - /* If we've selected max colors, exit */ + // If we've selected max colors, exit if (num_colors_selected >= NUM_COLOR_SLOTS) { - /* Apply the newly built colorset */ + // Apply the newly built colorset pattern_set_colorset(&pat, &new_colorset); - /* Save and return to normal mode */ + // Save and return to normal mode helios_save_cur_mode(); cur_state = STATE_MODES; menu_selection = 0; @@ -597,7 +597,7 @@ static void helios_handle_state_color_variant_selection(void) return; } - /* Otherwise go back to group selection for next color */ + // Otherwise go back to group selection for next color cur_state = STATE_COLOR_GROUP_SELECTION; menu_selection = 0; } @@ -611,7 +611,7 @@ static void helios_handle_state_pat_select(void) menu_selection = (menu_selection + 1) % PATTERN_COUNT; } - /* show the menu selection */ + // show the menu selection switch (menu_selection) { case 0: rgb_init_from_raw(&color, RGB_RED); break; case 1: rgb_init_from_raw(&color, RGB_GREEN); break; @@ -623,11 +623,11 @@ static void helios_handle_state_pat_select(void) led_set_rgb(&color); if (button_on_long_click()) { - /* make the selected pattern */ + // make the selected pattern patterns_make_pattern((enum pattern_id)(PATTERN_FIRST + menu_selection), &pat); - /* reset the pattern to revert to on/off state */ + // reset the pattern to revert to on/off state pattern_init_state(&pat); - /* save and return to normal mode */ + // save and return to normal mode helios_save_cur_mode(); cur_state = STATE_MODES; menu_selection = 0; @@ -638,11 +638,11 @@ static void helios_handle_state_toggle_flag(enum helios_flags flag) { rgb_color_t color; - /* wait until button release then toggle the flag */ + // wait until button release then toggle the flag if (button_on_release()) { helios_toggle_flag(flag); helios_save_global_flags(); - /* show feedback based on new state */ + // show feedback based on new state if (helios_has_flag(flag)) { rgb_init_from_raw(&color, RGB_GREEN); } else { @@ -657,10 +657,10 @@ static void helios_handle_state_set_defaults(void) { rgb_color_t color; - /* wait until button release then factory reset */ + // wait until button release then factory reset if (button_on_release()) { helios_factory_reset(); - /* show feedback */ + // show feedback rgb_init_from_raw(&color, RGB_BLUE); led_hold(&color); cur_state = STATE_MODES; @@ -673,7 +673,7 @@ static void helios_show_selection(rgb_color_t color) if (button_press_time() > 0) { time_since_click = time_get_current_time() - button_press_time(); } - /* flash the selection color briefly after clicking */ + // flash the selection color briefly after clicking if (time_since_click < 150) { led_set_rgb(&color); } @@ -682,15 +682,15 @@ static void helios_show_selection(rgb_color_t color) static void helios_factory_reset(void) { uint8_t slot; - /* write default patterns to all slots */ + // write default patterns to all slots for (slot = 0; slot < NUM_MODE_SLOTS; ++slot) { patterns_make_default(slot, &pat); storage_write_pattern(slot, &pat); } - /* clear all flags */ + // clear all flags global_flags = FLAG_NONE; helios_save_global_flags(); - /* reload current mode */ + // reload current mode helios_load_cur_mode(); } diff --git a/Helios/Helios.h b/Helios/Helios.h index 3af4dbb7..8efed95a 100644 --- a/Helios/Helios.h +++ b/Helios/Helios.h @@ -11,7 +11,7 @@ extern "C" { #include "Colorset.h" #include "Pattern.h" -/* Forward declaration */ +// Forward declaration typedef struct pattern_t pattern_t; typedef struct colorset_t colorset_t; @@ -41,7 +41,7 @@ enum helios_flags { FLAG_LOCKED = (1 << 0), }; -/* get/set global flags */ +// get/set global flags void helios_set_flag(enum helios_flags flag); uint8_t helios_has_flag(enum helios_flags flag); void helios_clear_flag(enum helios_flags flag); diff --git a/Helios/HeliosConfig.h b/Helios/HeliosConfig.h index 4c34d665..12260037 100644 --- a/Helios/HeliosConfig.h +++ b/Helios/HeliosConfig.h @@ -1,167 +1,167 @@ -#ifndef HELIOS_CONFIG_H -#define HELIOS_CONFIG_H - -// Version Configurations -// -// The engine major version indicates the state of the save file, -// if changes to the save format occur then the major version -// must increment so that the savefiles will not be loaded -#ifndef HELIOS_VERSION_MAJOR -#define HELIOS_VERSION_MAJOR 0 -#endif - -// A minor version simply indicates a bugfix or minor change that -// will not affect the save files produced by the engine. This means -// a savefile produced by 1.1 should be loadable by an engine on 1.2 -// and vice versa, but an engine on 2.0 cannot share savefiles with -// either of the engines on version 1.1 or 1.2 -#ifndef HELIOS_VERSION_MINOR -#define HELIOS_VERSION_MINOR 0 -#endif - -// The build or patch number based on the major.minor version, this is -// set by the build system using the number of commits since last version -#ifndef HELIOS_BUILD_NUMBER -#define HELIOS_BUILD_NUMBER 0 -#endif - -// Produces a number like 1.3.0 -#ifndef HELIOS_VERSION_NUMBER -#define HELIOS_VERSION_NUMBER HELIOS_VERSION_MAJOR.HELIOS_VERSION_MINOR.HELIOS_BUILD_NUMBER -#endif - - -// Helios Version String -// -// This is the string literal equivalent of HELIOS_VERSION_NUMBER above -#define ADD_QUOTES(str) #str -#define EXPAND_AND_QUOTE(str) ADD_QUOTES(str) -#define HELIOS_VERSION_STR EXPAND_AND_QUOTE(HELIOS_VERSION_NUMBER) - -// Short Click Threshold -// -// The length of time in milliseconds for a click to -// be considered either a short or long click -#define SHORT_CLICK_THRESHOLD 400 - -// Selection Flash Duration -// -// How long the led flashes when selecting something -#define TIME_TILL_LONG_CLICK_FLASH 1000 - -// Unlock Glow Lock Duration -// -// How long the hold the button to unlock chip -#define TIME_TILL_GLOW_LOCK_UNLOCK 2 - -// Hold Click Start Threshold -// -// The minimum length a hold click can be -#define HOLD_CLICK_START (SHORT_CLICK_THRESHOLD + TIME_TILL_LONG_CLICK_FLASH) - -// Hold Click End Threshold -// -// The maximum length a long click can be -#define HOLD_CLICK_END (HOLD_CLICK_START + TIME_TILL_LONG_CLICK_FLASH) - -// Max Color Slots -// -// The number of slots in a colorset -#define NUM_COLOR_SLOTS 3 - -// Mode Slots -// -// The number of modes on the device -#define NUM_MODE_SLOTS 1 - -// Default Brightness -// -// The default brightness of the led -#define DEFAULT_BRIGHTNESS 255 - -// Tickrate -// -// The number of engine ticks per second -#define TICKRATE 1000 - -// Menu Hold Time -// -// How long the button must be held for the menus to open and cycle -// note this is a measure of ticks, but if the tickrate is 1000 then -// it is a measure of milliseconds -#define MENU_HOLD_TIME 1000 - -// Force Sleep Time -// -// The duration in ms/ticks to hold the button to force the chip to -// sleep at any location in the menus -#define FORCE_SLEEP_TIME 7000 - - -// Alternative HSV to RGB -// -// This enabled the alternative HSV to RGB algorithm to be used in the -// color selection menu and provide a slightly different range of colors -#define ALTERNATIVE_HSV_RGB 0 - -// ============================================================================ -// Storage Constants -// -// These are various storage sizes of data and some math to help -// calculate sizes or space requirements, note these will produce -// compiler errors unless you include the respective headers - - -// Storage Name -// -// This is mainly used by the CLI tool as a filename for simulated eeprom -#define STORAGE_FILENAME "Helios.storage" - -// Storage Size -// -// The total size of storage where modes and global settings are saved. -// The EEPROM on attiny85 is 512 bytes, but due to limitations on flash -// only the lower half of the eeprom is being used -#define STORAGE_SIZE 256 - -// Colorset Size -// -// the colorset is just an array of colors but it also has a num colors val -#define COLORSET_SIZE ((sizeof(rgb_color_t) * NUM_COLOR_SLOTS) + 1) - -// Pattern Args Size -// -// There is currently 6 args for a pattern: on, off, gap, dash, group, blend -// Each takes up 1 byte currently -#define PAT_ARGS_SIZE (sizeof(pattern_args_t)) - -// Pattern Size -// -// The actual pattern storage size is the size of the colorset + params + 1 pat flags -#define PATTERN_SIZE (COLORSET_SIZE + PAT_ARGS_SIZE + 1) - -// Slot Size -// -// the slot stores the pattern + 1 byte CRC -#define SLOT_SIZE (PATTERN_SIZE + 1) - -// Some math to calculate storage sizes: -// 3 * 6 = 18 for the colorset -// 1 + 7 + 1 + 1 = 10 for the rest -// = 28 bytes total for a pattern including CRC -// -> 8 slots = 8 * 28 = 224 -// = 31 bytes left -// -> 9 slots = 9 * 28 = 252 -// = 3 bytes left - -// forbidden constant: -// #define HELIOS_ARDUINO 1 - -// Debug Pattern Logic -// -// Turn this on to print debug labels on the pattern states, this is useful if you -// are debugging a pattern strip from the command line and want to see what state -// the pattern is in each tick of the pattern -#define DEBUG_BASIC_PATTERN 0 - -#endif +#ifndef HELIOS_CONFIG_H +#define HELIOS_CONFIG_H + +// Version Configurations +// +// The engine major version indicates the state of the save file, +// if changes to the save format occur then the major version +// must increment so that the savefiles will not be loaded +#ifndef HELIOS_VERSION_MAJOR +#define HELIOS_VERSION_MAJOR 0 +#endif + +// A minor version simply indicates a bugfix or minor change that +// will not affect the save files produced by the engine. This means +// a savefile produced by 1.1 should be loadable by an engine on 1.2 +// and vice versa, but an engine on 2.0 cannot share savefiles with +// either of the engines on version 1.1 or 1.2 +#ifndef HELIOS_VERSION_MINOR +#define HELIOS_VERSION_MINOR 0 +#endif + +// The build or patch number based on the major.minor version, this is +// set by the build system using the number of commits since last version +#ifndef HELIOS_BUILD_NUMBER +#define HELIOS_BUILD_NUMBER 0 +#endif + +// Produces a number like 1.3.0 +#ifndef HELIOS_VERSION_NUMBER +#define HELIOS_VERSION_NUMBER HELIOS_VERSION_MAJOR.HELIOS_VERSION_MINOR.HELIOS_BUILD_NUMBER +#endif + + +// Helios Version String +// +// This is the string literal equivalent of HELIOS_VERSION_NUMBER above +#define ADD_QUOTES(str) #str +#define EXPAND_AND_QUOTE(str) ADD_QUOTES(str) +#define HELIOS_VERSION_STR EXPAND_AND_QUOTE(HELIOS_VERSION_NUMBER) + +// Short Click Threshold +// +// The length of time in milliseconds for a click to +// be considered either a short or long click +#define SHORT_CLICK_THRESHOLD 400 + +// Selection Flash Duration +// +// How long the led flashes when selecting something +#define TIME_TILL_LONG_CLICK_FLASH 1000 + +// Unlock Glow Lock Duration +// +// How long the hold the button to unlock chip +#define TIME_TILL_GLOW_LOCK_UNLOCK 2 + +// Hold Click Start Threshold +// +// The minimum length a hold click can be +#define HOLD_CLICK_START (SHORT_CLICK_THRESHOLD + TIME_TILL_LONG_CLICK_FLASH) + +// Hold Click End Threshold +// +// The maximum length a long click can be +#define HOLD_CLICK_END (HOLD_CLICK_START + TIME_TILL_LONG_CLICK_FLASH) + +// Max Color Slots +// +// The number of slots in a colorset +#define NUM_COLOR_SLOTS 3 + +// Mode Slots +// +// The number of modes on the device +#define NUM_MODE_SLOTS 1 + +// Default Brightness +// +// The default brightness of the led +#define DEFAULT_BRIGHTNESS 255 + +// Tickrate +// +// The number of engine ticks per second +#define TICKRATE 1000 + +// Menu Hold Time +// +// How long the button must be held for the menus to open and cycle +// note this is a measure of ticks, but if the tickrate is 1000 then +// it is a measure of milliseconds +#define MENU_HOLD_TIME 1000 + +// Force Sleep Time +// +// The duration in ms/ticks to hold the button to force the chip to +// sleep at any location in the menus +#define FORCE_SLEEP_TIME 7000 + + +// Alternative HSV to RGB +// +// This enabled the alternative HSV to RGB algorithm to be used in the +// color selection menu and provide a slightly different range of colors +#define ALTERNATIVE_HSV_RGB 0 + +// ============================================================================ +// Storage Constants +// +// These are various storage sizes of data and some math to help +// calculate sizes or space requirements, note these will produce +// compiler errors unless you include the respective headers + + +// Storage Name +// +// This is mainly used by the CLI tool as a filename for simulated eeprom +#define STORAGE_FILENAME "Helios.storage" + +// Storage Size +// +// The total size of storage where modes and global settings are saved. +// The EEPROM on attiny85 is 512 bytes, but due to limitations on flash +// only the lower half of the eeprom is being used +#define STORAGE_SIZE 256 + +// Colorset Size +// +// the colorset is just an array of colors but it also has a num colors val +#define COLORSET_SIZE ((sizeof(rgb_color_t) * NUM_COLOR_SLOTS) + 1) + +// Pattern Args Size +// +// There is currently 6 args for a pattern: on, off, gap, dash, group, blend +// Each takes up 1 byte currently +#define PAT_ARGS_SIZE (sizeof(pattern_args_t)) + +// Pattern Size +// +// The actual pattern storage size is the size of the colorset + params + 1 pat flags +#define PATTERN_SIZE (COLORSET_SIZE + PAT_ARGS_SIZE + 1) + +// Slot Size +// +// the slot stores the pattern + 1 byte CRC +#define SLOT_SIZE (PATTERN_SIZE + 1) + +// Some math to calculate storage sizes: +// 3 * 6 = 18 for the colorset +// 1 + 7 + 1 + 1 = 10 for the rest +// = 28 bytes total for a pattern including CRC +// -> 8 slots = 8 * 28 = 224 +// = 31 bytes left +// -> 9 slots = 9 * 28 = 252 +// = 3 bytes left + +// forbidden constant: +// #define HELIOS_ARDUINO 1 + +// Debug Pattern Logic +// +// Turn this on to print debug labels on the pattern states, this is useful if you +// are debugging a pattern strip from the command line and want to see what state +// the pattern is in each tick of the pattern +#define DEBUG_BASIC_PATTERN 0 + +#endif diff --git a/Helios/Led.cpp b/Helios/Led.cpp index 06ec5841..89e6cccd 100644 --- a/Helios/Led.cpp +++ b/Helios/Led.cpp @@ -21,19 +21,19 @@ #define SCALE8(i, scale) (((uint16_t)i * (uint16_t)(scale)) >> 8) -/* Forward declaration */ +// Forward declaration static void led_set_pwm(uint8_t pwmPin, uint8_t pwmValue, volatile uint8_t *controlRegister, uint8_t controlBit, volatile uint8_t *compareRegister); -/* array of led color values */ +// array of led color values static rgb_color_t m_ledColor; static rgb_color_t m_realColor; -/* global brightness */ +// global brightness static uint8_t m_brightness = DEFAULT_BRIGHTNESS; uint8_t led_init(void) { - /* clear the led colors */ + // clear the led colors rgb_init_from_raw(&m_ledColor, RGB_OFF); rgb_init_from_raw(&m_realColor, RGB_OFF); #ifdef HELIOS_EMBEDDED @@ -42,7 +42,7 @@ uint8_t led_init(void) pinMode(1, OUTPUT); pinMode(4, OUTPUT); #else - /* pin ctrl done in helios_init */ + // pin ctrl done in helios_init #endif #endif return 1; @@ -91,23 +91,23 @@ void led_strobe(uint16_t on_time, uint16_t off_time, const rgb_color_t *off_col, void led_breath(uint8_t hue, uint32_t duration, uint8_t magnitude, uint8_t sat, uint8_t val) { if (!duration) { - /* don't divide by 0 */ + // don't divide by 0 return; } - /* Determine the phase in the cycle */ + // Determine the phase in the cycle uint32_t phase = time_get_current_time() % (2 * duration); - /* Calculate hue shift */ + // Calculate hue shift int32_t hueShift; if (phase < duration) { - /* Ascending phase - from hue to hue + magnitude */ + // Ascending phase - from hue to hue + magnitude hueShift = (phase * magnitude) / duration; } else { - /* Descending phase - from hue + magnitude to hue */ + // Descending phase - from hue + magnitude to hue hueShift = ((2 * duration - phase) * magnitude) / duration; } - /* Apply hue shift - ensure hue stays within valid range */ + // Apply hue shift - ensure hue stays within valid range uint8_t shiftedHue = hue + hueShift; - /* Apply the hsv color as a strobing hue shift */ + // Apply the hsv color as a strobing hue shift hsv_color_t hsv; rgb_color_t off, on; hsv_init3(&hsv, shiftedHue, sat, val); @@ -128,15 +128,15 @@ static void led_set_pwm(uint8_t pwmPin, uint8_t pwmValue, volatile uint8_t *cont { #ifdef HELIOS_EMBEDDED if (pwmValue == 0) { - /* digitalWrite(pin, LOW) */ + // digitalWrite(pin, LOW) *controlRegister &= ~controlBit; /* Disable PWM */ PORTB &= ~(1 << pwmPin); /* Set the pin low */ } else if (pwmValue == 255) { - /* digitalWrite(pin, HIGH) */ + // digitalWrite(pin, HIGH) *controlRegister &= ~controlBit; /* Disable PWM */ PORTB |= (1 << pwmPin); /* Set the pin high */ } else { - /* analogWrite(pin, value) */ + // analogWrite(pin, value) *controlRegister |= controlBit; /* Enable PWM */ *compareRegister = pwmValue; /* Set PWM duty cycle */ } @@ -167,22 +167,22 @@ void led_set_brightness(uint8_t brightness) void led_update(void) { #ifdef HELIOS_EMBEDDED - /* write out the rgb values to analog pins */ + // write out the rgb values to analog pins #ifdef HELIOS_ARDUINO analogWrite(PWM_PIN_R, m_realColor.red); analogWrite(PWM_PIN_G, m_realColor.green); analogWrite(PWM_PIN_B, m_realColor.blue); #else - /* backup SREG and turn off interrupts */ + // backup SREG and turn off interrupts uint8_t oldSREG = SREG; cli(); - /* set the PWM for R/G/B output */ + // set the PWM for R/G/B output led_set_pwm(PWM_PIN_R, m_realColor.red, &TCCR0A, (1 << COM0A1), &OCR0A); led_set_pwm(PWM_PIN_G, m_realColor.green, &TCCR0A, (1 << COM0B1), &OCR0B); led_set_pwm(PWM_PIN_B, m_realColor.blue, >CCR, (1 << COM1B1), &OCR1B); - /* turn interrupts back on */ + // turn interrupts back on SREG = oldSREG; #endif #endif diff --git a/Helios/Led.h b/Helios/Led.h index cae2ca2c..fe64fe3d 100644 --- a/Helios/Led.h +++ b/Helios/Led.h @@ -15,34 +15,34 @@ extern "C" { uint8_t led_init(void); void led_cleanup(void); -/* control individual LED, these are appropriate to use in internal pattern logic */ +// control individual LED, these are appropriate to use in internal pattern logic void led_set_rgb(const rgb_color_t *col); void led_set_rgb3(uint8_t r, uint8_t g, uint8_t b); -/* Turn off individual LEDs, these are appropriate to use in internal pattern logic */ +// Turn off individual LEDs, these are appropriate to use in internal pattern logic void led_clear(void); -/* Dim individual LEDs, these are appropriate to use in internal pattern logic */ +// Dim individual LEDs, these are appropriate to use in internal pattern logic void led_adjust_brightness(uint8_t fadeBy); -/* strobe between two colors with a simple on/off timing */ +// strobe between two colors with a simple on/off timing void led_strobe(uint16_t on_time, uint16_t off_time, const rgb_color_t *col1, const rgb_color_t *col2); /* breath the hue on an index * warning: these use hsv to rgb in realtime! */ void led_breath(uint8_t hue, uint32_t duration, uint8_t magnitude, uint8_t sat, uint8_t val); -/* a very specialized api to hold all leds on a color for 250ms */ +// a very specialized api to hold all leds on a color for 250ms void led_hold(const rgb_color_t *col); -/* get the RGBColor of an Led index */ +// get the RGBColor of an Led index rgb_color_t led_get(void); -/* global brightness */ +// global brightness uint8_t led_get_brightness(void); void led_set_brightness(uint8_t brightness); -/* actually update the LEDs and show the changes */ +// actually update the LEDs and show the changes void led_update(void); #ifdef __cplusplus diff --git a/Helios/Pattern.cpp b/Helios/Pattern.cpp index 8dfd4a5d..b9c963e2 100644 --- a/Helios/Pattern.cpp +++ b/Helios/Pattern.cpp @@ -8,7 +8,7 @@ #include /* for memcpy */ -/* Forward declarations for internal functions */ +// Forward declarations for internal functions static void pattern_on_blink_on(pattern_t *pat); static void pattern_on_blink_off(pattern_t *pat); static void pattern_begin_gap(pattern_t *pat); @@ -61,52 +61,52 @@ void pattern_init_state(pattern_t *pat) { colorset_reset_index(&pat->m_colorset); - /* Reset the fade start time to the current time */ + // Reset the fade start time to the current time pat->m_fadeStartTime = time_get_current_time(); - /* the default state to begin with */ + // the default state to begin with pat->m_state = STATE_BLINK_ON; /* if a dash is present then always start with the dash because * it consumes the first color in the colorset */ if (pat->m_args.dash_dur > 0) { pat->m_state = STATE_BEGIN_DASH; } - /* if there's no on duration or dash duration the led is just disabled */ + // if there's no on duration or dash duration the led is just disabled if ((!pat->m_args.on_dur && !pat->m_args.dash_dur) || !colorset_num_colors(&pat->m_colorset)) { pat->m_state = STATE_DISABLED; } pat->m_groupCounter = pat->m_args.group_size ? pat->m_args.group_size : (colorset_num_colors(&pat->m_colorset) - (pat->m_args.dash_dur != 0)); if (pat->m_args.blend_speed > 0) { - /* convert current/next colors to HSV but only if we are doing a blend */ + // convert current/next colors to HSV but only if we are doing a blend pat->m_cur = colorset_get_next(&pat->m_colorset); pat->m_next = colorset_get_next(&pat->m_colorset); } else if (pat->m_args.fade_dur) { - /* if there is a fade dur and no blend need to iterate colorset */ + // if there is a fade dur and no blend need to iterate colorset colorset_get_next(&pat->m_colorset); } - /* Initialize the fluctuating fade value */ + // Initialize the fluctuating fade value pat->m_fadeValue = 0; } static void pattern_tick_fade(pattern_t *pat) { uint32_t now = time_get_current_time(); - /* Calculate relative time since pattern was initialized */ + // Calculate relative time since pattern was initialized uint32_t relativeTime = now - pat->m_fadeStartTime; uint32_t duration = pat->m_args.fade_dur * 10; - /* only tick forward every fade_dur ticks */ + // only tick forward every fade_dur ticks if (!relativeTime || (relativeTime % duration) != 0) { return; } - /* count the number of steps based on relative time */ + // count the number of steps based on relative time uint32_t steps = relativeTime / duration; uint32_t range = pat->m_args.off_dur; - /* make sure the range is non-zero */ + // make sure the range is non-zero if (range == 0) { pat->m_fadeValue = 0; return; @@ -115,10 +115,10 @@ static void pattern_tick_fade(pattern_t *pat) uint32_t double_range = range * 2; uint32_t step = steps % double_range; - /* Triangle wave: up from 0 to range, then down to 0 */ + // Triangle wave: up from 0 to range, then down to 0 pat->m_fadeValue = (step < range) ? step : (double_range - step - 1); - /* iterate color when at lowest point */ + // iterate color when at lowest point if (step == 0) { colorset_get_next(&pat->m_colorset); } @@ -126,7 +126,7 @@ static void pattern_tick_fade(pattern_t *pat) void pattern_play(pattern_t *pat) { - /* tick forward the fade logic each tick */ + // tick forward the fade logic each tick if (pattern_is_fade(pat)) { pattern_tick_fade(pat); } @@ -135,7 +135,7 @@ void pattern_play(pattern_t *pat) * instead of using a loop or recursion I have just used a simple goto */ replay: - /* its kinda evolving as i go */ + // its kinda evolving as i go switch (pat->m_state) { case STATE_DISABLED: return; @@ -143,7 +143,7 @@ void pattern_play(pattern_t *pat) if (pat->m_args.on_dur > 0) { pattern_on_blink_on(pat); --pat->m_groupCounter; - /* When in ON state, use current fading on-time */ + // When in ON state, use current fading on-time pattern_next_state(pat, pat->m_args.on_dur + pat->m_fadeValue); return; } @@ -191,7 +191,7 @@ void pattern_play(pattern_t *pat) } if (!timer_alarm(&pat->m_blinkTimer)) { - /* no alarm triggered just stay in current state, return and don't transition states */ + // no alarm triggered just stay in current state, return and don't transition states return; } @@ -208,10 +208,10 @@ void pattern_play(pattern_t *pat) * left in the group we need to cycle back to blink on instead of to the next state */ pat->m_state = (pat->m_groupCounter > 0) ? STATE_BLINK_ON : STATE_BEGIN_GAP; } else { - /* this is the standard case, iterate to the next state */ + // this is the standard case, iterate to the next state pat->m_state = (enum pattern_state)(pat->m_state + 1); } - /* poor-mans recurse with the new state change (this transitions to a new state within the same tick) */ + // poor-mans recurse with the new state change (this transitions to a new state within the same tick) goto replay; } @@ -237,7 +237,7 @@ static void pattern_on_blink_on(pattern_t *pat) return; } - /* Check if this is a fading duration pattern */ + // Check if this is a fading duration pattern if (pattern_is_fade(pat)) { rgb_color_t cur_col = colorset_cur(&pat->m_colorset); led_set_rgb(&cur_col); @@ -298,11 +298,11 @@ uint8_t pattern_equals(const pattern_t *pat, const pattern_t *other) if (!other) { return 0; } - /* compare the colorset */ + // compare the colorset if (!colorset_equals(&pat->m_colorset, &other->m_colorset)) { return 0; } - /* compare the args of each pattern for equality */ + // compare the args of each pattern for equality if (memcmp(&pat->m_args, &other->m_args, sizeof(pattern_args_t)) != 0) { return 0; } @@ -354,11 +354,11 @@ static void pattern_blend_blink_on(pattern_t *pat) if (rgb_equals(&pat->m_cur, &pat->m_next)) { pat->m_next = colorset_get_next(&pat->m_colorset); } - /* interpolate to the next color */ + // interpolate to the next color pattern_interpolate(&pat->m_cur.red, pat->m_next.red, pat->m_args.blend_speed); pattern_interpolate(&pat->m_cur.green, pat->m_next.green, pat->m_args.blend_speed); pattern_interpolate(&pat->m_cur.blue, pat->m_next.blue, pat->m_args.blend_speed); - /* set the color */ + // set the color led_set_rgb(&pat->m_cur); } diff --git a/Helios/Pattern.h b/Helios/Pattern.h index 68b3c8fa..c49c0b8b 100644 --- a/Helios/Pattern.h +++ b/Helios/Pattern.h @@ -10,11 +10,11 @@ extern "C" { #include "Timer.h" #include "Patterns.h" -/* Forward declarations */ +// Forward declarations typedef struct pattern_args_t pattern_args_t; typedef struct pattern_t pattern_t; -/* for specifying things like default args */ +// for specifying things like default args struct pattern_args_t { uint8_t on_dur; uint8_t off_dur; @@ -25,33 +25,33 @@ struct pattern_args_t { uint8_t fade_dur; }; -/* Initialize pattern args with all parameters */ +// Initialize pattern args with all parameters void pattern_args_init(pattern_args_t *args, uint8_t on, uint8_t off, uint8_t gap, uint8_t dash, uint8_t group, uint8_t blend, uint8_t fade); -/* The various different blinking states the pattern can be in */ +// The various different blinking states the pattern can be in enum pattern_state { - /* the led is disabled (there is no on or dash) */ + // the led is disabled (there is no on or dash) STATE_DISABLED, - /* the pattern is blinking on the next color in the set */ + // the pattern is blinking on the next color in the set STATE_BLINK_ON, STATE_ON, - /* the pattern is blinking off */ + // the pattern is blinking off STATE_BLINK_OFF, STATE_OFF, - /* the pattern is starting a gap after a colorset */ + // the pattern is starting a gap after a colorset STATE_BEGIN_GAP, STATE_IN_GAP, - /* the pattern is beginning a dash after a colorset or gap */ + // the pattern is beginning a dash after a colorset or gap STATE_BEGIN_DASH, STATE_IN_DASH, - /* the pattern is starting a gap after a dash */ + // the pattern is starting a gap after a dash STATE_BEGIN_GAP2, STATE_IN_GAP2, }; @@ -65,77 +65,77 @@ struct pattern_t /* ================================== * Pattern Members */ - /* any flags the pattern has */ + // any flags the pattern has uint8_t m_patternFlags; - /* a copy of the colorset that this pattern is initialized with */ + // a copy of the colorset that this pattern is initialized with colorset_t m_colorset; /* ================================== * Blink Members */ uint8_t m_groupCounter; - /* the state of the current pattern */ + // the state of the current pattern enum pattern_state m_state; - /* the blink timer used to measure blink timings */ + // the blink timer used to measure blink timings helios_timer_t m_blinkTimer; /* ================================== * Blend Members */ - /* current color and target blend color */ + // current color and target blend color rgb_color_t m_cur; rgb_color_t m_next; /* ================================== * Fade Members */ - /* shifting value to represent current fade */ + // shifting value to represent current fade uint8_t m_fadeValue; - /* Add a member variable to store when the pattern was last initialized */ + // Add a member variable to store when the pattern was last initialized uint32_t m_fadeStartTime; }; -/* try to not set on duration to 0 */ +// try to not set on duration to 0 void pattern_init(pattern_t *pat, uint8_t onDur, uint8_t offDur, uint8_t gap, uint8_t dash, uint8_t group, uint8_t blend, uint8_t fade); void pattern_init_with_args(pattern_t *pat, const pattern_args_t *args); -/* init the pattern to initial state */ +// init the pattern to initial state void pattern_init_state(pattern_t *pat); -/* play the pattern */ +// play the pattern void pattern_play(pattern_t *pat); -/* set/get args */ +// set/get args void pattern_set_args(pattern_t *pat, const pattern_args_t *args); pattern_args_t pattern_get_args(const pattern_t *pat); pattern_args_t *pattern_args_ptr(pattern_t *pat); -/* change the colorset */ +// change the colorset colorset_t pattern_get_colorset(const pattern_t *pat); colorset_t *pattern_colorset_ptr(pattern_t *pat); void pattern_set_colorset(pattern_t *pat, const colorset_t *set); void pattern_clear_colorset(pattern_t *pat); -/* comparison to other pattern */ +// comparison to other pattern uint8_t pattern_equals(const pattern_t *pat, const pattern_t *other); -/* set a color in the colorset and re-initialize */ +// set a color in the colorset and re-initialize void pattern_update_color(pattern_t *pat, uint8_t index, const rgb_color_t *col); -/* calculate crc of the colorset + pattern */ +// calculate crc of the colorset + pattern uint32_t pattern_crc32(const pattern_t *pat); -/* get the pattern flags */ +// get the pattern flags uint32_t pattern_get_flags(const pattern_t *pat); uint8_t pattern_has_flags(const pattern_t *pat, uint32_t flags); -/* whether blend speed is non 0 */ +// whether blend speed is non 0 uint8_t pattern_is_blend(const pattern_t *pat); -/* whether fade speed is non 0 */ +// whether fade speed is non 0 uint8_t pattern_is_fade(const pattern_t *pat); #ifdef __cplusplus diff --git a/Helios/Patterns.cpp b/Helios/Patterns.cpp index cc41885e..09a2a999 100644 --- a/Helios/Patterns.cpp +++ b/Helios/Patterns.cpp @@ -9,7 +9,7 @@ * of colors in each set but you can absolutely list a lesser amount */ static const uint32_t color_codes0[] = {RGB_RED, RGB_GREEN, RGB_BLUE}; /* Rainbow Flow */ -/* Define Colorset configurations for each slot */ +// Define Colorset configurations for each slot struct default_colorset_t { uint8_t num_cols; const uint32_t *cols; @@ -34,12 +34,12 @@ void patterns_make_default(uint8_t index, pattern_t *pat) args.off_dur = 23; break; } - /* assign default args */ + // assign default args pattern_set_args(pat, &args); - /* build the set out of the defaults */ + // build the set out of the defaults colorset_t set; colorset_init_array(&set, default_colorsets[index].num_cols, default_colorsets[index].cols); - /* assign default colorset */ + // assign default colorset pattern_set_colorset(pat, &set); } diff --git a/Helios/Patterns.h b/Helios/Patterns.h index 100a01cf..534c51db 100644 --- a/Helios/Patterns.h +++ b/Helios/Patterns.h @@ -7,7 +7,7 @@ extern "C" { #include -/* Forward declaration */ +// Forward declaration typedef struct pattern_t pattern_t; /* List of patterns that can be built, both single and multi-led patterns are found in this list. @@ -20,18 +20,18 @@ enum pattern_id { * PATTERN_FIRST when possible */ PATTERN_NONE = -1, - /* first pattern of all */ + // first pattern of all PATTERN_FIRST = 0, - /* ===================================== */ + // ===================================== - /* Strobe */ + // Strobe PATTERN_STROBE = PATTERN_FIRST, PATTERN_HYPNOSTROBE, PATTERN_STROBIE, PATTERN_RAZOR, PATTERN_DASH_DOPS, - /* Meta pattern constants */ + // Meta pattern constants INTERNAL_PATTERNS_END, PATTERN_LAST = (INTERNAL_PATTERNS_END - 1), PATTERN_COUNT = (PATTERN_LAST - PATTERN_FIRST) + 1, /* total number of patterns */ diff --git a/Helios/Random.cpp b/Helios/Random.cpp index 8950ba08..db855d7a 100644 --- a/Helios/Random.cpp +++ b/Helios/Random.cpp @@ -22,7 +22,7 @@ void random_seed(random_t *rng, uint32_t newseed) uint16_t random_next16(random_t *rng, uint16_t minValue, uint16_t maxValue) { - /* walk the LCG forward to the next step */ + // walk the LCG forward to the next step rng->m_seed = (rng->m_seed * 1103515245 + 12345) & 0x7FFFFFFF; uint32_t range = maxValue - minValue; if (range != 0xFFFFFFFF) { diff --git a/Helios/Random.h b/Helios/Random.h index b5bee10f..bef01d0c 100644 --- a/Helios/Random.h +++ b/Helios/Random.h @@ -14,19 +14,19 @@ struct random_t uint32_t m_seed; }; -/* Initialize a random struct with default seed */ +// Initialize a random struct with default seed void random_init(random_t *rng); -/* Initialize a random struct with a specific seed */ +// Initialize a random struct with a specific seed void random_init_seed(random_t *rng, uint32_t newseed); -/* Set the seed for the random number generator */ +// Set the seed for the random number generator void random_seed(random_t *rng, uint32_t newseed); -/* Generate next random 8-bit value within range [minValue, maxValue] */ +// Generate next random 8-bit value within range [minValue, maxValue] uint8_t random_next8(random_t *rng, uint8_t minValue, uint8_t maxValue); -/* Generate next random 16-bit value within range [minValue, maxValue] */ +// Generate next random 16-bit value within range [minValue, maxValue] uint16_t random_next16(random_t *rng, uint16_t minValue, uint16_t maxValue); #ifdef __cplusplus diff --git a/Helios/Storage.cpp b/Helios/Storage.cpp index 5413c26a..6df4d5cd 100644 --- a/Helios/Storage.cpp +++ b/Helios/Storage.cpp @@ -15,7 +15,7 @@ #include #endif -/* Forward declarations for internal functions */ +// Forward declarations for internal functions static uint8_t storage_crc_pos(uint8_t pos); static uint8_t storage_read_crc(uint8_t pos); static uint8_t storage_check_crc(uint8_t pos); @@ -29,7 +29,7 @@ static inline void storage_internal_write(uint8_t address, uint8_t data); #endif #ifdef HELIOS_CLI -/* whether storage is enabled, default enabled */ +// whether storage is enabled, default enabled static uint8_t m_enableStorage = 1; #endif @@ -39,15 +39,15 @@ uint8_t storage_init(void) if (!m_enableStorage) { return 1; } - /* if the storage filename doesn't exist then create it */ + // if the storage filename doesn't exist then create it if (access(STORAGE_FILENAME, O_RDWR) != 0 && errno == ENOENT) { - /* The file doesn't exist, so try creating it */ + // The file doesn't exist, so try creating it FILE *f = fopen(STORAGE_FILENAME, "w+b"); if (!f) { perror("Error creating storage file for write"); return 0; } - /* fill the storage with 0s */ + // fill the storage with 0s uint32_t i; for (i = 0; i < STORAGE_SIZE; ++i){ uint8_t b = 0x0; @@ -146,25 +146,25 @@ uint8_t storage_crc8(uint8_t pos, uint8_t size) static uint8_t storage_crc_pos(uint8_t pos) { - /* crc the entire slot except last byte */ + // crc the entire slot except last byte return storage_crc8(pos, PATTERN_SIZE); } static uint8_t storage_read_crc(uint8_t pos) { - /* read the last byte of the slot */ + // read the last byte of the slot return storage_read_byte(pos + PATTERN_SIZE); } static uint8_t storage_check_crc(uint8_t pos) { - /* compare the last byte to the calculated crc */ + // compare the last byte to the calculated crc return (storage_read_crc(pos) == storage_crc_pos(pos)); } static void storage_write_crc(uint8_t pos) { - /* compare the last byte to the calculated crc */ + // compare the last byte to the calculated crc storage_write_byte(pos + PATTERN_SIZE, storage_crc_pos(pos)); } @@ -177,11 +177,11 @@ static void storage_write_byte(uint8_t address, uint8_t data) return; } storage_internal_write(address, data); - /* double check that shit */ + // double check that shit if (storage_read_byte(address) != data) { - /* do it again because eeprom is stupid */ + // do it again because eeprom is stupid storage_internal_write(address, data); - /* god forbid it doesn't write again */ + // god forbid it doesn't write again } #else /* HELIOS_CLI */ if (!m_enableStorage) { @@ -192,7 +192,7 @@ static void storage_write_byte(uint8_t address, uint8_t data) perror("Error opening storage file"); return; } - /* Seek to the specified address */ + // Seek to the specified address if (fseek(f, address, SEEK_SET) != 0) { perror("Error opening storage file for write"); fclose(f); @@ -209,7 +209,7 @@ static void storage_write_byte(uint8_t address, uint8_t data) static uint8_t storage_read_byte(uint8_t address) { #ifdef HELIOS_EMBEDDED - /* do a three way read because the attiny85 eeprom basically doesn't work */ + // do a three way read because the attiny85 eeprom basically doesn't work uint8_t b1 = storage_internal_read(address); uint8_t b2 = storage_internal_read(address); if (b1 == b2) { @@ -233,18 +233,18 @@ static uint8_t storage_read_byte(uint8_t address) } FILE *f = fopen(STORAGE_FILENAME, "rb"); /* Open file for reading in binary mode */ if (!f) { - /* this error is ok, just means no storage */ - /* perror("Error opening file for read"); */ + // this error is ok, just means no storage + // perror("Error opening file for read"); return val; } - /* Seek to the specified address */ + // Seek to the specified address if (fseek(f, address, SEEK_SET) != 0) { - /* error */ + // error perror("Failed to seek"); fclose(f); return val; } - /* Read a byte of data */ + // Read a byte of data if (!fread(&val, sizeof(uint8_t), 1, f)) { perror("Failed to read byte"); } @@ -257,29 +257,29 @@ static uint8_t storage_read_byte(uint8_t address) static inline void storage_internal_write(uint8_t address, uint8_t data) { while (EECR & (1< #include -/* convert seconds and nanoseconds to microseconds */ +// convert seconds and nanoseconds to microseconds #define SEC_TO_US(sec) ((sec)*1000000) #define NS_TO_US(ns) ((ns)/1000) #endif -/* static members */ +// static members static uint32_t m_curTick = 0; -/* the last frame timestamp */ +// the last frame timestamp static uint32_t m_prevTime = 0; #ifdef HELIOS_CLI -/* whether timestep is enabled, default enabled */ +// whether timestep is enabled, default enabled static uint8_t m_enableTimestep = 1; #endif @@ -50,7 +50,7 @@ void time_cleanup(void) void time_tick_clock(void) { - /* tick clock forward */ + // tick clock forward m_curTick++; #ifdef HELIOS_CLI @@ -66,12 +66,12 @@ void time_tick_clock(void) uint32_t us; do { us = time_microseconds(); - /* detect rollover of microsecond counter */ + // detect rollover of microsecond counter if (us < m_prevTime) { - /* calculate wrapped around difference */ + // calculate wrapped around difference elapsed_us = (uint32_t)((UINT32_MAX - m_prevTime) + us); } else { - /* otherwise calculate regular difference */ + // otherwise calculate regular difference elapsed_us = (uint32_t)(us - m_prevTime); } /* if building anywhere except visual studio then we can run alternate sleep code @@ -81,7 +81,7 @@ void time_tick_clock(void) * the number of microseconds per tick */ } while (elapsed_us < (1000000 / TICKRATE)); - /* store current time */ + // store current time m_prevTime = time_microseconds(); } @@ -115,10 +115,10 @@ uint32_t time_microseconds(void) * should always just rely on the current tick to perform operations */ uint8_t oldSREG = SREG; cli(); - /* multiply by 8 early to avoid floating point math or division */ + // multiply by 8 early to avoid floating point math or division uint32_t micros = (timer0_overflow_count * (256 * 8)) + (TCNT0 * 8); SREG = oldSREG; - /* then shift right to counteract the multiplication by 8 */ + // then shift right to counteract the multiplication by 8 return micros >> 6; #endif #endif @@ -132,16 +132,16 @@ time_delay_microseconds(uint32_t us) { #ifdef HELIOS_EMBEDDED #if F_CPU >= 16000000L - /* For the ATtiny85 running at 16MHz */ + // For the ATtiny85 running at 16MHz - /* The loop takes 3 cycles per iteration */ + // The loop takes 3 cycles per iteration us *= 2; /* 0.5us per iteration */ /* Subtract the overhead of the function call and loop setup * Assuming approximately 5 cycles overhead */ us -= 5; /* Simplified subtraction */ - /* Assembly loop for delay */ + // Assembly loop for delay __asm__ __volatile__( "1: sbiw %0, 1" "\n\t" /* 2 cycles */ @@ -151,16 +151,16 @@ time_delay_microseconds(uint32_t us) ); #elif F_CPU >= 8000000L - /* For the ATtiny85 running at 8MHz */ + // For the ATtiny85 running at 8MHz - /* The loop takes 4 cycles per iteration */ + // The loop takes 4 cycles per iteration us <<= 1; /* 1us per iteration */ /* Subtract the overhead of the function call and loop setup * Assuming approximately 6 cycles overhead */ us -= 6; /* Simplified subtraction */ - /* Assembly loop for delay */ + // Assembly loop for delay __asm__ __volatile__( "1: sbiw %0, 1" "\n\t" /* 2 cycles */ @@ -174,7 +174,7 @@ time_delay_microseconds(uint32_t us) uint32_t newtime = time_microseconds() + us; while (time_microseconds() < newtime) { - /* busy loop */ + // busy loop } #endif } @@ -184,7 +184,7 @@ void time_delay_milliseconds(uint32_t ms) #ifdef HELIOS_CLI usleep(ms * 1000); #else - /* not very accurate */ + // not very accurate uint16_t i; for (i = 0; i < ms; ++i) { time_delay_microseconds(1000); diff --git a/Helios/TimeControl.h b/Helios/TimeControl.h index 85fd4aac..954bf639 100644 --- a/Helios/TimeControl.h +++ b/Helios/TimeControl.h @@ -9,15 +9,15 @@ extern "C" { #include "HeliosConfig.h" -/* macros to convert milliseconds and seconds to measures of ticks */ +// macros to convert milliseconds and seconds to measures of ticks #define MS_TO_TICKS(ms) (uint32_t)(((uint32_t)(ms) * TICKRATE) / 1000) #define SEC_TO_TICKS(s) (uint32_t)((uint32_t)(s) * TICKRATE) -/* Initialize time system */ +// Initialize time system uint8_t time_init(void); void time_cleanup(void); -/* Tick the clock forward to millis() */ +// Tick the clock forward to millis() void time_tick_clock(void); /* Get the current tick, offset by any active simulation (simulation only exists in vortexlib) @@ -31,12 +31,12 @@ uint32_t time_get_current_time(void); * purpose of comparing against time_get_current_time() */ uint32_t time_microseconds(void); -/* Delay for some number of microseconds or milliseconds, these are bad */ +// Delay for some number of microseconds or milliseconds, these are bad void time_delay_microseconds(uint32_t us); void time_delay_milliseconds(uint32_t ms); #ifdef HELIOS_CLI -/* Toggle timestep on/off */ +// Toggle timestep on/off void time_enable_timestep(uint8_t enabled); #endif diff --git a/Helios/Timer.cpp b/Helios/Timer.cpp index e18be8ae..1f623387 100644 --- a/Helios/Timer.cpp +++ b/Helios/Timer.cpp @@ -19,7 +19,7 @@ void timer_init(helios_timer_t *timer, uint8_t alarm) void timer_start(helios_timer_t *timer, uint32_t offset) { - /* reset the start time */ + // reset the start time timer->m_startTime = time_get_current_time() + offset; } @@ -35,21 +35,21 @@ uint8_t timer_alarm(helios_timer_t *timer) return 0; } uint32_t now = time_get_current_time(); - /* time since start (forward or backwards) */ + // time since start (forward or backwards) int32_t timeDiff = (int32_t)(int64_t)(now - timer->m_startTime); if (timeDiff < 0) { return 0; } - /* if no time passed it's first alarm that is starting */ + // if no time passed it's first alarm that is starting if (timeDiff == 0) { return 1; } - /* if the current alarm duration is not a multiple of the current tick */ + // if the current alarm duration is not a multiple of the current tick if (timer->m_alarm && (timeDiff % timer->m_alarm) != 0) { - /* then the alarm was not hit */ + // then the alarm was not hit return 0; } - /* update the start time of the timer */ + // update the start time of the timer timer->m_startTime = now; return 1; } diff --git a/Helios/Timer.h b/Helios/Timer.h index 40997d07..a84d08ce 100644 --- a/Helios/Timer.h +++ b/Helios/Timer.h @@ -11,26 +11,26 @@ typedef struct helios_timer_t helios_timer_t; struct helios_timer_t { - /* the alarm */ + // the alarm uint32_t m_alarm; - /* start time in microseconds */ + // start time in microseconds uint32_t m_startTime; }; -/* Initialize a timer struct to default values */ +// Initialize a timer struct to default values void timer_init_default(helios_timer_t *timer); -/* Init a timer with a number of alarms and optionally start it */ +// Init a timer with a number of alarms and optionally start it void timer_init(helios_timer_t *timer, uint8_t alarm); /* Start the timer but don't change current alarm, this shifts * the timer startTime but does not reset it's alarm state */ void timer_start(helios_timer_t *timer, uint32_t offset); -/* Delete all alarms from the timer and reset */ +// Delete all alarms from the timer and reset void timer_reset(helios_timer_t *timer); -/* Will return true if the timer hit */ +// Will return true if the timer hit uint8_t timer_alarm(helios_timer_t *timer); #ifdef __cplusplus From 8cded6a041caa3615a23fe425304105f1220d079 Mon Sep 17 00:00:00 2001 From: Kurt LaVacque Date: Sat, 18 Oct 2025 10:55:13 +0200 Subject: [PATCH 13/17] Convert remaining C-style comments to C++ style comments including multi-line comments --- Helios/Button.cpp | 31 ++++++++++-------------- Helios/Button.h | 11 ++------- Helios/Colorset.cpp | 15 ++++-------- Helios/Colorset.h | 6 ++--- Helios/Colortypes.cpp | 45 +++++++++++------------------------ Helios/Colortypes.h | 11 +++------ Helios/Helios.cpp | 54 +++++++++++++++++++----------------------- Helios/Led.cpp | 18 +++++++------- Helios/Led.h | 6 ++--- Helios/Pattern.cpp | 38 ++++++++++------------------- Helios/Pattern.h | 15 ++++-------- Helios/Patterns.cpp | 15 +++++------- Helios/Patterns.h | 11 +++------ Helios/Random.cpp | 5 +--- Helios/Storage.cpp | 13 +++++----- Helios/Storage.h | 6 ++--- Helios/TimeControl.cpp | 44 +++++++++++++--------------------- Helios/TimeControl.h | 9 ++----- Helios/Timer.h | 3 +-- 19 files changed, 129 insertions(+), 227 deletions(-) diff --git a/Helios/Button.cpp b/Helios/Button.cpp index 4b81e748..e7386dd3 100644 --- a/Helios/Button.cpp +++ b/Helios/Button.cpp @@ -43,8 +43,7 @@ static uint8_t m_longClick = 0; static uint8_t m_holdClick = 0; #ifdef HELIOS_CLI -/* Note: For embedded builds, we exclude std::queue and CLI-only features. - * The CLI input queue functionality is omitted for embedded targets. */ +// static uint8_t m_pinState = 0; static uint8_t m_enableWake = 0; // Simple input queue for CLI - using a fixed-size circular buffer @@ -94,7 +93,7 @@ void button_enable_wake(void) PCMSK |= (1 << PCINT3); GIMSK |= (1 << PCIE); sei(); -#else /* HELIOS_CLI */ +#else // m_enableWake = 1; #endif } @@ -116,8 +115,7 @@ uint8_t button_check(void) return (PINB & (1 << 3)) != 0; #endif #elif defined(HELIOS_CLI) - /* then just return the pin state as-is, the input event may have - * adjusted this value */ + // return m_pinState; #else return 0; @@ -165,8 +163,7 @@ void button_update(void) m_holdClick = (m_newRelease && (m_holdDuration >= HOLD_CLICK_START) && (m_holdDuration <= HOLD_CLICK_END)); #ifdef HELIOS_CLI - /* if there was no pre-input event this tick, process a post input event - * to ensure there is only one event per tick processed */ + // if (!processed_pre) { button_process_post_input(); } @@ -242,24 +239,23 @@ static uint8_t button_process_pre_input(void) } char command = m_inputQueue[m_queueHead]; switch (command) { - case 'p': /* press */ + case 'p': // button_do_press(); break; - case 'r': /* release */ + case 'r': // button_do_release(); break; - case 't': /* toggle */ + case 't': // button_do_toggle(); break; - case 'q': /* quit */ + case 'q': // helios_terminate(); break; - case 'w': /* wait */ + case 'w': // // wait is pre input I guess break; default: - /* return here! do not pop the queue - * do not process post input events */ + // return 0; } // now pop whatever pre-input command was processed @@ -276,10 +272,10 @@ static uint8_t button_process_post_input(void) // process input queue from the command line char command = m_inputQueue[m_queueHead]; switch (command) { - case 'c': /* click button */ + case 'c': // button_do_short_click(); break; - case 'l': /* long click button */ + case 'l': // button_do_long_click(); break; default: @@ -317,8 +313,7 @@ void button_do_hold_click(void) m_releaseCount++; } -/* this will actually press down the button, it's your responsibility to wait - * for the appropriate number of ticks and then release the button */ +// void button_do_press(void) { m_pinState = 1; diff --git a/Helios/Button.h b/Helios/Button.h index 1cd534a4..dba3ee09 100644 --- a/Helios/Button.h +++ b/Helios/Button.h @@ -56,19 +56,12 @@ uint8_t button_release_count(void); void button_enable_wake(void); #ifdef HELIOS_CLI -/* These will 'inject' a short/long click without actually touching the - * button state, it's important that code uses 'button_on_short_click' or - * 'button_on_long_click' to capture this injected input event. Code that uses - * for example: 'button_hold_duration() >= threshold && button_on_release()' - * will never trigger because the injected input event doesn't actually - * press the button or change the button state it just sets the 'shortClick' - * or 'longClick' values accordingly */ +// void button_do_short_click(void); void button_do_long_click(void); void button_do_hold_click(void); -/* This will actually press down the button, it's your responsibility to wait - * for the appropriate number of ticks and then release the button */ +// void button_do_press(void); void button_do_release(void); void button_do_toggle(void); diff --git a/Helios/Colorset.cpp b/Helios/Colorset.cpp index 758e7195..b7b4e5a0 100644 --- a/Helios/Colorset.cpp +++ b/Helios/Colorset.cpp @@ -4,9 +4,7 @@ #include -/* when no color is selected in the colorset the index is this - * then when you call colorset_get_next() for the first time it returns - * the 0th color in the colorset and after the index will be 0 */ +// #define INDEX_INVALID 255 void colorset_init(colorset_t *set) @@ -190,7 +188,7 @@ void colorset_randomize_colors(colorset_t *set, random_t *ctx, uint8_t numColors } else if (mode == COLOR_MODE_MONOCHROMATIC) { hueToUse = randomizedHue; valueToUse = 255 - (i * (256 / numColors)); - } else { /* EVENLY_SPACED */ + } else { // hueToUse = (randomizedHue + (256 / numColors) * i); } colorset_add_color_with_value_style(set, ctx, hueToUse, valueToUse, valStyle, numColors, i); @@ -221,8 +219,7 @@ rgb_color_t colorset_get(const colorset_t *set, uint8_t index) void colorset_set(colorset_t *set, uint8_t index, rgb_color_t col) { - /* special case for 'setting' a color at the edge of the palette, - * ie adding a new color when you set an index higher than the max */ + // if (index >= set->m_numColors) { if (!colorset_add_color(set, col)) { // ERROR_LOGF("Failed to add new color at index %u", index); @@ -245,11 +242,9 @@ void colorset_skip(colorset_t *set, int32_t amount) // first modulate the amount to skip to be within +/- the number of colors amount %= (int32_t)set->m_numColors; - /* max = 3 - * m_curIndex = 2 - * amount = -10 */ + // set->m_curIndex = ((int32_t)set->m_curIndex + (int32_t)amount) % (int32_t)set->m_numColors; - if (set->m_curIndex > set->m_numColors) { /* must have wrapped */ + if (set->m_curIndex > set->m_numColors) { // // simply wrap it back set->m_curIndex += set->m_numColors; } diff --git a/Helios/Colorset.h b/Helios/Colorset.h index eccc28a3..9aa3a1ee 100644 --- a/Helios/Colorset.h +++ b/Helios/Colorset.h @@ -55,8 +55,7 @@ struct colorset_t rgb_color_t m_palette[NUM_COLOR_SLOTS]; // the actual number of colors in the set uint8_t m_numColors; - /* the current index, starts at 255 so that - * the very first call to colorset_getNext will iterate to 0 */ + // uint8_t m_curIndex; }; @@ -101,8 +100,7 @@ void colorset_adjust_brightness(colorset_t *set, uint8_t fadeby); // Get a color from the colorset rgb_color_t colorset_get(const colorset_t *set, uint8_t index); -/* Set an rgb color in a slot, or add a new color if you specify - * a slot higher than the number of colors in the colorset */ +// void colorset_set(colorset_t *set, uint8_t index, rgb_color_t col); // Skip some amount of colors diff --git a/Helios/Colortypes.cpp b/Helios/Colortypes.cpp index 813f0dc5..d0eee8f4 100644 --- a/Helios/Colortypes.cpp +++ b/Helios/Colortypes.cpp @@ -193,49 +193,37 @@ void rgb_scale_brightness(rgb_color_t *rgb, float scale) } #endif -/* ======================================================== - * Below are various functions for converting hsv <-> rgb */ +// #if ALTERNATIVE_HSV_RGB == 1 #define SCALE8(i, scale) (((uint16_t)i * (uint16_t)(scale)) >> 8) #define FIXFRAC8(N,D) (((N)*256)/(D)) -/* Stolen from FastLED hsv to rgb full rainbow where all colours - * are given equal weight, this makes for-example yellow larger - * best to use this function as it is the legacy choice */ +// rgb_color_t hsv_to_rgb_rainbow(const hsv_color_t *rhs) { rgb_color_t col; - /* Yellow has a higher inherent brightness than - * any other color; 'pure' yellow is perceived to - * be 93% as bright as white. In order to make - * yellow appear the correct relative brightness, - * it has to be rendered brighter than all other - * colors. - * Level Y1 is a moderate boost, the default. - * Level Y2 is a strong boost. */ + // const uint8_t Y1 = 1; const uint8_t Y2 = 0; - /* G2: Whether to divide all greens by two. - * Depends GREATLY on your particular LEDs */ + // const uint8_t G2 = 0; - /* Gscale: what to scale green down by. - * Depends GREATLY on your particular LEDs */ + // const uint8_t Gscale = 185; uint8_t hue = rhs->hue; uint8_t sat = rhs->sat; uint8_t val = rhs->val; - uint8_t offset = hue & 0x1F; /* 0..31 */ + uint8_t offset = hue & 0x1F; // // offset8 = offset * 8 uint8_t offset8 = offset; offset8 <<= 3; - uint8_t third = SCALE8(offset8, (256 / 3)); /* max = 85 */ + uint8_t third = SCALE8(offset8, (256 / 3)); // uint8_t r, g, b; if (!(hue & 0x80)) { // 0XX @@ -259,7 +247,7 @@ rgb_color_t hsv_to_rgb_rainbow(const hsv_color_t *rhs) if (Y2) { r = 170 + third; // uint8_t twothirds = (third << 1); - uint8_t twothirds = SCALE8(offset8, ((256 * 2) / 3)); /* max=170 */ + uint8_t twothirds = SCALE8(offset8, ((256 * 2) / 3)); // g = 85 + twothirds; b = 0; } @@ -272,7 +260,7 @@ rgb_color_t hsv_to_rgb_rainbow(const hsv_color_t *rhs) // case 2: Y -> G if (Y1) { // uint8_t twothirds = (third << 1); - uint8_t twothirds = SCALE8(offset8, ((256 * 2) / 3)); /* max=170 */ + uint8_t twothirds = SCALE8(offset8, ((256 * 2) / 3)); // r = 171 - twothirds; g = 170 + third; b = 0; @@ -300,8 +288,8 @@ rgb_color_t hsv_to_rgb_rainbow(const hsv_color_t *rhs) // case 4: A -> B r = 0; // uint8_t twothirds = (third << 1); - uint8_t twothirds = SCALE8(offset8, ((256 * 2) / 3)); /* max=170 */ - g = 171 - twothirds; /* 170? */ + uint8_t twothirds = SCALE8(offset8, ((256 * 2) / 3)); // + g = 171 - twothirds; // b = 85 + twothirds; } else { // 101 @@ -327,13 +315,11 @@ rgb_color_t hsv_to_rgb_rainbow(const hsv_color_t *rhs) } } - /* This is one of the good places to scale the green down, - * although the client can scale green down as well. */ + // if (G2) g = g >> 1; if (Gscale) g = SCALE8(g, Gscale); - /* Scale down colors if we're desaturated at all - * and add the brightness_floor to r, g, and b. */ + // if (sat != 255) { if (sat == 0) { r = 255; b = 255; g = 255; @@ -365,10 +351,7 @@ rgb_color_t hsv_to_rgb_rainbow(const hsv_color_t *rhs) } } - /* Here we have the old AVR "missing std X+n" problem again - * It turns out that fixing it winds up costing more than - * not fixing it. - * To paraphrase Dr Bronner, profile! profile! profile! */ + // col.red = r; col.green = g; col.blue = b; diff --git a/Helios/Colortypes.h b/Helios/Colortypes.h index d32040eb..b48681da 100644 --- a/Helios/Colortypes.h +++ b/Helios/Colortypes.h @@ -17,8 +17,7 @@ enum hsv_to_rgb_algorithm HSV_TO_RGB_RAINBOW }; -/* global hsv to rgb algorithm selector, switch this to control - * all hsv to rgb conversions */ +// extern enum hsv_to_rgb_algorithm g_hsv_rgb_alg; #endif @@ -68,18 +67,14 @@ void rgb_adjust_brightness(rgb_color_t *rgb, uint8_t fadeBy); uint32_t rgb_raw(const rgb_color_t *rgb); #ifdef HELIOS_CLI -/* Return a scaled brightness version of the current color - * ex: 0.0 = black, 0.5 = half brightness, 1.0 = no change, - * 1.5 = 50% brighter, 2.0 = twice as bright, 255.0 = white */ +// void rgb_scale_brightness(rgb_color_t *rgb, float scale); // Bring up the brightness of a color to a minimum level void rgb_bring_up_brightness(rgb_color_t *rgb, uint8_t min_brightness); #endif // Conversion functions -/* Stolen from FastLED hsv to rgb full rainbow where all colours - * are given equal weight, this makes for-example yellow larger - * best to use this function as it is the legacy choice */ +// rgb_color_t hsv_to_rgb_rainbow(const hsv_color_t *rhs); // Generic hsv to rgb conversion nothing special rgb_color_t hsv_to_rgb_generic(const hsv_color_t *rhs); diff --git a/Helios/Helios.cpp b/Helios/Helios.cpp index cc1f3757..4d38b798 100644 --- a/Helios/Helios.cpp +++ b/Helios/Helios.cpp @@ -73,14 +73,14 @@ static enum helios_flags global_flags; static uint8_t menu_selection; static uint8_t cur_mode; static uint8_t selected_base_group; -static uint8_t num_colors_selected; /* Track number of colors selected in current session */ +static uint8_t num_colors_selected; // static pattern_t pat; static uint8_t keepgoing; static uint32_t last_mode_switch_time; static colorset_t new_colorset; #ifdef HELIOS_CLI -static uint8_t sleeping; /* Only used in CLI mode */ +static uint8_t sleeping; // #endif volatile char helios_version[] = HELIOS_VERSION_STR; @@ -144,20 +144,16 @@ static uint8_t helios_init_components(void) void helios_tick(void) { - /* sample the button and re-calculate all button globals - * the button globals should not change anywhere else */ + // button_update(); - /* handle the current state of the system, ie whatever state - * we're in we check for the appropriate input events for that - * state by checking button globals, then run the appropriate logic */ + // helios_handle_state(); // Update the Leds once per frame led_update(); - /* finally tick the clock forward and then sleep till the entire - * tick duration has been consumed */ + // time_tick_clock(); } @@ -196,8 +192,7 @@ void helios_wakeup(void) #ifdef HELIOS_EMBEDDED // nothing needed here, this interrupt firing will make the mainthread resume #else - /* if the button was held down then they are entering off-menus - * but if we re-initialize the button it will clear this state */ + // uint8_t pressed = button_is_pressed(); // re-initialize some stuff time_init(); @@ -370,8 +365,7 @@ static void helios_handle_state_modes(void) } // check how long the button is held uint32_t holdDur = button_hold_duration(); - /* calculate a magnitude which corresponds to how many times past the MENU_HOLD_TIME - * the user has held the button, so 0 means haven't held fully past one yet, etc */ + // uint8_t magnitude = (uint8_t)(holdDur / MENU_HOLD_TIME); // whether the user has held the button longer than a short click uint8_t heldPast = (holdDur > SHORT_CLICK_THRESHOLD); @@ -389,23 +383,23 @@ static void helios_handle_state_modes(void) if (hasReleased) { switch (magnitude) { default: - case 0: led_clear(); break; /* Turn off */ - case 1: rgb_init_from_raw(&color, RGB_TURQUOISE_BRI_LOW); led_set_rgb(&color); break; /* Color Selection */ - case 2: rgb_init_from_raw(&color, RGB_MAGENTA_BRI_LOW); led_set_rgb(&color); break; /* Pattern Selection */ + case 0: led_clear(); break; // + case 1: rgb_init_from_raw(&color, RGB_TURQUOISE_BRI_LOW); led_set_rgb(&color); break; // + case 2: rgb_init_from_raw(&color, RGB_MAGENTA_BRI_LOW); led_set_rgb(&color); break; // } } else { if (helios_has_flag(FLAG_LOCKED)) { switch (magnitude) { default: case 0: led_clear(); break; - case TIME_TILL_GLOW_LOCK_UNLOCK: rgb_init_from_raw(&color, RGB_RED_BRI_LOW); led_set_rgb(&color); break; /* Exit */ + case TIME_TILL_GLOW_LOCK_UNLOCK: rgb_init_from_raw(&color, RGB_RED_BRI_LOW); led_set_rgb(&color); break; // } } else { switch (magnitude) { default: - case 0: led_clear(); break; /* nothing */ - case 1: rgb_init_from_raw(&color, RGB_RED_BRI_LOW); led_set_rgb(&color); break; /* Enter Glow Lock */ - case 2: rgb_init_from_raw(&color, RGB_BLUE_BRI_LOW); led_set_rgb(&color); break; /* Master Reset */ + case 0: led_clear(); break; // + case 1: rgb_init_from_raw(&color, RGB_RED_BRI_LOW); led_set_rgb(&color); break; // + case 2: rgb_init_from_raw(&color, RGB_BLUE_BRI_LOW); led_set_rgb(&color); break; // } } } @@ -425,11 +419,11 @@ static void helios_handle_state_modes(void) static void helios_handle_off_menu(uint8_t mag, uint8_t past) { - (void)past; /* unused */ + (void)past; // // if still locked then handle the unlocking menu which is just if mag == 5 if (helios_has_flag(FLAG_LOCKED)) { switch (mag) { - case TIME_TILL_GLOW_LOCK_UNLOCK: /* red lock */ + case TIME_TILL_GLOW_LOCK_UNLOCK: // cur_state = STATE_TOGGLE_LOCK; break; default: @@ -443,13 +437,13 @@ static void helios_handle_off_menu(uint8_t mag, uint8_t past) // otherwise if not locked handle the off menu switch (mag) { - case 1: /* red lock */ + case 1: // cur_state = STATE_TOGGLE_LOCK; led_clear(); - return; /* RETURN HERE */ - case 2: /* blue reset defaults */ + return; // + case 2: // cur_state = STATE_SET_DEFAULTS; - return; /* RETURN HERE */ + return; // default: // just go back to sleep in hold-past off menu helios_enter_sleep(); @@ -461,7 +455,7 @@ static void helios_handle_off_menu(uint8_t mag, uint8_t past) static void helios_handle_on_menu(uint8_t mag, uint8_t past) { switch (mag) { - case 0: /* off */ + case 0: // // but only if we held for more than a short click if (past) { helios_enter_sleep(); @@ -469,7 +463,7 @@ static void helios_handle_on_menu(uint8_t mag, uint8_t past) return; } break; - case 1: /* color select */ + case 1: // cur_state = STATE_COLOR_GROUP_SELECTION; // reset the menu selection and colors selected menu_selection = 0; @@ -483,12 +477,12 @@ static void helios_handle_on_menu(uint8_t mag, uint8_t past) g_hsv_rgb_alg = HSV_TO_RGB_RAINBOW; #endif break; - case 2: /* pat select */ + case 2: // cur_state = STATE_PATTERN_SELECT; // reset the menu selection menu_selection = 0; break; - default: /* hold past */ + default: // break; } } diff --git a/Helios/Led.cpp b/Helios/Led.cpp index 89e6cccd..6d0e6494 100644 --- a/Helios/Led.cpp +++ b/Helios/Led.cpp @@ -14,9 +14,9 @@ #include #include #endif -#define PWM_PIN_R PB0 /* Red channel (pin 5) */ -#define PWM_PIN_G PB1 /* Green channel (pin 6) */ -#define PWM_PIN_B PB4 /* Blue channel (pin 3) */ +#define PWM_PIN_R PB0 // +#define PWM_PIN_G PB1 // +#define PWM_PIN_B PB4 // #endif #define SCALE8(i, scale) (((uint16_t)i * (uint16_t)(scale)) >> 8) @@ -129,16 +129,16 @@ static void led_set_pwm(uint8_t pwmPin, uint8_t pwmValue, volatile uint8_t *cont #ifdef HELIOS_EMBEDDED if (pwmValue == 0) { // digitalWrite(pin, LOW) - *controlRegister &= ~controlBit; /* Disable PWM */ - PORTB &= ~(1 << pwmPin); /* Set the pin low */ + *controlRegister &= ~controlBit; // + PORTB &= ~(1 << pwmPin); // } else if (pwmValue == 255) { // digitalWrite(pin, HIGH) - *controlRegister &= ~controlBit; /* Disable PWM */ - PORTB |= (1 << pwmPin); /* Set the pin high */ + *controlRegister &= ~controlBit; // + PORTB |= (1 << pwmPin); // } else { // analogWrite(pin, value) - *controlRegister |= controlBit; /* Enable PWM */ - *compareRegister = pwmValue; /* Set PWM duty cycle */ + *controlRegister |= controlBit; // + *compareRegister = pwmValue; // } #else (void)pwmPin; diff --git a/Helios/Led.h b/Helios/Led.h index fe64fe3d..86805afa 100644 --- a/Helios/Led.h +++ b/Helios/Led.h @@ -9,8 +9,7 @@ extern "C" { #include "Colortypes.h" -/* opting for static functions here because there should only ever be one - * Led control object and I don't like singletons */ +// uint8_t led_init(void); void led_cleanup(void); @@ -28,8 +27,7 @@ void led_adjust_brightness(uint8_t fadeBy); // strobe between two colors with a simple on/off timing void led_strobe(uint16_t on_time, uint16_t off_time, const rgb_color_t *col1, const rgb_color_t *col2); -/* breath the hue on an index - * warning: these use hsv to rgb in realtime! */ +// void led_breath(uint8_t hue, uint32_t duration, uint8_t magnitude, uint8_t sat, uint8_t val); // a very specialized api to hold all leds on a color for 250ms diff --git a/Helios/Pattern.cpp b/Helios/Pattern.cpp index b9c963e2..25207723 100644 --- a/Helios/Pattern.cpp +++ b/Helios/Pattern.cpp @@ -6,7 +6,7 @@ #include "HeliosConfig.h" #include "Led.h" -#include /* for memcpy */ +#include // // Forward declarations for internal functions static void pattern_on_blink_on(pattern_t *pat); @@ -18,8 +18,7 @@ static void pattern_blend_blink_on(pattern_t *pat); static void pattern_interpolate(uint8_t *current, const uint8_t next, uint8_t blend_speed); static void pattern_tick_fade(pattern_t *pat); -/* ================================== - * Pattern Args Functions */ +// void pattern_args_init(pattern_args_t *args, uint8_t on, uint8_t off, uint8_t gap, uint8_t dash, uint8_t group, uint8_t blend, uint8_t fade) @@ -33,8 +32,7 @@ void pattern_args_init(pattern_args_t *args, uint8_t on, uint8_t off, uint8_t ga args->fade_dur = fade; } -/* ================================== - * Pattern Functions */ +// void pattern_init(pattern_t *pat, uint8_t onDur, uint8_t offDur, uint8_t gap, uint8_t dash, uint8_t group, uint8_t blend, uint8_t fade) @@ -66,8 +64,7 @@ void pattern_init_state(pattern_t *pat) // the default state to begin with pat->m_state = STATE_BLINK_ON; - /* if a dash is present then always start with the dash because - * it consumes the first color in the colorset */ + // if (pat->m_args.dash_dur > 0) { pat->m_state = STATE_BEGIN_DASH; } @@ -131,8 +128,7 @@ void pattern_play(pattern_t *pat) pattern_tick_fade(pat); } - /* Sometimes the pattern needs to cycle multiple states in a single frame so - * instead of using a loop or recursion I have just used a simple goto */ + // replay: // its kinda evolving as i go @@ -149,8 +145,7 @@ void pattern_play(pattern_t *pat) } pat->m_state = STATE_BLINK_OFF; case STATE_BLINK_OFF: - /* the whole 'should blink off' situation is tricky because we might need - * to go back to blinking on if our colorset isn't at the end yet */ + // if (pat->m_groupCounter > 0 || (!pat->m_args.gap_dur && !pat->m_args.dash_dur)) { if (pat->m_args.off_dur > 0) { pattern_on_blink_off(pat); @@ -195,17 +190,12 @@ void pattern_play(pattern_t *pat) return; } - /* this just transitions the state into the next state, with some edge conditions for - * transitioning to different states under certain circumstances. Honestly this is - * a nightmare to read now and idk how to fix it */ + // if (pat->m_state == STATE_IN_GAP2 || (pat->m_state == STATE_OFF && pat->m_groupCounter > 0)) { - /* this is an edge condition for when in the second gap or off in the non-last off blink - * then the state actually needs to jump backwards rather than iterate */ + // pat->m_state = pat->m_args.on_dur ? STATE_BLINK_ON : (pat->m_args.dash_dur ? STATE_BEGIN_DASH : STATE_BEGIN_GAP); } else if (pat->m_state == STATE_OFF && (!pat->m_groupCounter || colorset_num_colors(&pat->m_colorset) == 1)) { - /* this is an edge condition when the state is off but this is the last off blink in the - * group or there's literally only one color in the group then if there is more blinks - * left in the group we need to cycle back to blink on instead of to the next state */ + // pat->m_state = (pat->m_groupCounter > 0) ? STATE_BLINK_ON : STATE_BEGIN_GAP; } else { // this is the standard case, iterate to the next state @@ -250,13 +240,13 @@ static void pattern_on_blink_on(pattern_t *pat) static void pattern_on_blink_off(pattern_t *pat) { - (void)pat; /* unused */ + (void)pat; // led_clear(); } static void pattern_begin_gap(pattern_t *pat) { - (void)pat; /* unused */ + (void)pat; // led_clear(); } @@ -306,8 +296,7 @@ uint8_t pattern_equals(const pattern_t *pat, const pattern_t *other) if (memcmp(&pat->m_args, &other->m_args, sizeof(pattern_args_t)) != 0) { return 0; } - /* if those match then it's effectively the same - * pattern even if anything else is different */ + // return 1; } @@ -349,8 +338,7 @@ uint8_t pattern_is_fade(const pattern_t *pat) static void pattern_blend_blink_on(pattern_t *pat) { - /* if we reached the next color, then cycle the colorset - * like normal and begin playing the next color */ + // if (rgb_equals(&pat->m_cur, &pat->m_next)) { pat->m_next = colorset_get_next(&pat->m_colorset); } diff --git a/Helios/Pattern.h b/Helios/Pattern.h index c49c0b8b..8dc724ed 100644 --- a/Helios/Pattern.h +++ b/Helios/Pattern.h @@ -58,20 +58,17 @@ enum pattern_state struct pattern_t { - /* ================================== - * Pattern Parameters */ + // pattern_args_t m_args; - /* ================================== - * Pattern Members */ + // // any flags the pattern has uint8_t m_patternFlags; // a copy of the colorset that this pattern is initialized with colorset_t m_colorset; - /* ================================== - * Blink Members */ + // uint8_t m_groupCounter; // the state of the current pattern @@ -80,15 +77,13 @@ struct pattern_t // the blink timer used to measure blink timings helios_timer_t m_blinkTimer; - /* ================================== - * Blend Members */ + // // current color and target blend color rgb_color_t m_cur; rgb_color_t m_next; - /* ================================== - * Fade Members */ + // // shifting value to represent current fade uint8_t m_fadeValue; diff --git a/Helios/Patterns.cpp b/Helios/Patterns.cpp index 09a2a999..50934291 100644 --- a/Helios/Patterns.cpp +++ b/Helios/Patterns.cpp @@ -4,10 +4,8 @@ #include "Pattern.h" #include "ColorConstants.h" -/* define arrays of colors, you can reuse these if you have multiple - * modes that use the same colorset -- these demonstrate the max amount - * of colors in each set but you can absolutely list a lesser amount */ -static const uint32_t color_codes0[] = {RGB_RED, RGB_GREEN, RGB_BLUE}; /* Rainbow Flow */ +// +static const uint32_t color_codes0[] = {RGB_RED, RGB_GREEN, RGB_BLUE}; // // Define Colorset configurations for each slot struct default_colorset_t { @@ -15,10 +13,9 @@ struct default_colorset_t { const uint32_t *cols; }; -/* the array of colorset entries, make sure the number on the left reflects - * the number of colors in the array on the right */ +// static const struct default_colorset_t default_colorsets[] = { - { 3, color_codes0 }, /* 0 Rainbow Flow */ + { 3, color_codes0 }, // }; void patterns_make_default(uint8_t index, pattern_t *pat) @@ -29,7 +26,7 @@ void patterns_make_default(uint8_t index, pattern_t *pat) pattern_args_t args; pattern_args_init(&args, 0, 0, 0, 0, 0, 0, 0); switch (index) { - case 0: /* Rainbow Flow */ + case 0: // args.on_dur = 3; args.off_dur = 23; break; @@ -69,7 +66,7 @@ void patterns_make_pattern(enum pattern_id id, pattern_t *pat) case PATTERN_RAZOR: args.on_dur = 3; args.off_dur = 1; - args.gap_dur = 30; /* 29 for flashing pattern circles */ + args.gap_dur = 30; // break; case PATTERN_DASH_DOPS: diff --git a/Helios/Patterns.h b/Helios/Patterns.h index 534c51db..b9c181bf 100644 --- a/Helios/Patterns.h +++ b/Helios/Patterns.h @@ -10,14 +10,9 @@ extern "C" { // Forward declaration typedef struct pattern_t pattern_t; -/* List of patterns that can be built, both single and multi-led patterns are found in this list. - * Within both single and multi LED pattern lists there are 'core' patterns which are associated - * with a class, and there are 'shell' patterns which are simply wrappers around another pattern - * with different parameters passed to the constructor. There is no way to know which patterns - * are 'core' patterns, except by looking at patterns_make_pattern to see which classes exist */ +// enum pattern_id { - /* no pattern at all, use this sparingly and default to - * PATTERN_FIRST when possible */ + // PATTERN_NONE = -1, // first pattern of all @@ -34,7 +29,7 @@ enum pattern_id { // Meta pattern constants INTERNAL_PATTERNS_END, PATTERN_LAST = (INTERNAL_PATTERNS_END - 1), - PATTERN_COUNT = (PATTERN_LAST - PATTERN_FIRST) + 1, /* total number of patterns */ + PATTERN_COUNT = (PATTERN_LAST - PATTERN_FIRST) + 1, // }; void patterns_make_default(uint8_t index, pattern_t *pat); diff --git a/Helios/Random.cpp b/Helios/Random.cpp index db855d7a..bf221b52 100644 --- a/Helios/Random.cpp +++ b/Helios/Random.cpp @@ -26,10 +26,7 @@ uint16_t random_next16(random_t *rng, uint16_t minValue, uint16_t maxValue) rng->m_seed = (rng->m_seed * 1103515245 + 12345) & 0x7FFFFFFF; uint32_t range = maxValue - minValue; if (range != 0xFFFFFFFF) { - /* shift the seed 16 bits to the right because the lower 16 bits - * of this LCG are apparently not uniform whatsoever, where as the - * upper 16 bits appear to be quite uniform as per tests. We don't - * really need 32bit random values so we offer max 16bits of entropy */ + // return ((rng->m_seed >> 16) % (range + 1)) + minValue; } return (rng->m_seed >> 16); diff --git a/Helios/Storage.cpp b/Helios/Storage.cpp index 6df4d5cd..5a318ac9 100644 --- a/Helios/Storage.cpp +++ b/Helios/Storage.cpp @@ -136,7 +136,7 @@ void storage_write_brightness(uint8_t brightness) uint8_t storage_crc8(uint8_t pos, uint8_t size) { - uint8_t hash = 33; /* A non-zero initial value */ + uint8_t hash = 33; // uint8_t i; for (i = 0; i < size; ++i) { hash = ((hash << 5) + hash) + storage_read_byte(pos); @@ -171,8 +171,7 @@ static void storage_write_crc(uint8_t pos) static void storage_write_byte(uint8_t address, uint8_t data) { #ifdef HELIOS_EMBEDDED - /* reads out the byte of the eeprom first to see if it's different - * before writing out the byte -- this is faster than always writing */ + // if (storage_read_byte(address) == data) { return; } @@ -183,7 +182,7 @@ static void storage_write_byte(uint8_t address, uint8_t data) storage_internal_write(address, data); // god forbid it doesn't write again } -#else /* HELIOS_CLI */ +#else // if (!m_enableStorage) { return; } @@ -202,7 +201,7 @@ static void storage_write_byte(uint8_t address, uint8_t data) fclose(f); return; } - fclose(f); /* Close the file */ + fclose(f); // #endif } @@ -231,7 +230,7 @@ static uint8_t storage_read_byte(uint8_t address) if (access(STORAGE_FILENAME, O_RDONLY) != 0) { return val; } - FILE *f = fopen(STORAGE_FILENAME, "rb"); /* Open file for reading in binary mode */ + FILE *f = fopen(STORAGE_FILENAME, "rb"); // if (!f) { // this error is ok, just means no storage // perror("Error opening file for read"); @@ -248,7 +247,7 @@ static uint8_t storage_read_byte(uint8_t address) if (!fread(&val, sizeof(uint8_t), 1, f)) { perror("Failed to read byte"); } - fclose(f); /* Close the file */ + fclose(f); // return val; #endif } diff --git a/Helios/Storage.h b/Helios/Storage.h index 85dc1a6c..fbd2c2f1 100644 --- a/Helios/Storage.h +++ b/Helios/Storage.h @@ -8,11 +8,9 @@ extern "C" { #include #include "HeliosConfig.h" -/* the index of the first config byte, the config bytes start at the end - * then work their way backwards (so 'config index 0' is the last byte) */ +// #define CONFIG_START_INDEX (STORAGE_SIZE - 2) -/* the crc of the config bytes is the very last byte in storage - * TODO: implement the global config CRC again it got removed at some point */ +// #define CONFIG_CRC_INDEX (STORAGE_SIZE - 1) // Storage Config Indexes relative to the CONFIG_START_INDEX diff --git a/Helios/TimeControl.cpp b/Helios/TimeControl.cpp index d3d0b6b6..b48afed0 100644 --- a/Helios/TimeControl.cpp +++ b/Helios/TimeControl.cpp @@ -59,9 +59,7 @@ void time_tick_clock(void) } #endif - /* the rest of this only runs inside vortexlib because on the duo the tick runs in the - * tcb timer callback instead of in a busy loop constantly checking microseconds() - * perform timestep */ + // uint32_t elapsed_us; uint32_t us; do { @@ -74,11 +72,7 @@ void time_tick_clock(void) // otherwise calculate regular difference elapsed_us = (uint32_t)(us - m_prevTime); } - /* if building anywhere except visual studio then we can run alternate sleep code - * because in visual studio + windows it's better to just spin and check the high - * resolution clock instead of trying to sleep for microseconds. - * 1000us per ms, divided by tickrate gives - * the number of microseconds per tick */ + // } while (elapsed_us < (1000000 / TICKRATE)); // store current time @@ -93,7 +87,7 @@ uint32_t time_get_current_time(void) #ifdef HELIOS_EMBEDDED volatile uint32_t timer0_overflow_count = 0; ISR(TIMER0_OVF_vect) { - timer0_overflow_count++; /* Increment on each overflow */ + timer0_overflow_count++; // } #endif @@ -108,11 +102,7 @@ uint32_t time_microseconds(void) #ifdef HELIOS_ARDUINO return micros(); #else - /* The only reason that micros() is actually necessary is if Helios::tick() - * cannot be called in a 1Khz ISR. If Helios::tick() cannot be reliably called - * by an interrupt then Time::tickClock() must perform manual timestep via micros(). - * If Helios::tick() is called by an interrupt then you don't need this function and - * should always just rely on the current tick to perform operations */ + // uint8_t oldSREG = SREG; cli(); // multiply by 8 early to avoid floating point math or division @@ -135,38 +125,36 @@ time_delay_microseconds(uint32_t us) // For the ATtiny85 running at 16MHz // The loop takes 3 cycles per iteration - us *= 2; /* 0.5us per iteration */ + us *= 2; // - /* Subtract the overhead of the function call and loop setup - * Assuming approximately 5 cycles overhead */ - us -= 5; /* Simplified subtraction */ + // + us -= 5; // // Assembly loop for delay __asm__ __volatile__( "1: sbiw %0, 1" - "\n\t" /* 2 cycles */ + "\n\t" // "nop" - "\n\t" /* 1 cycle */ - "brne 1b" : "=w"(us) : "0"(us) /* 2 cycles */ + "\n\t" // + "brne 1b" : "=w"(us) : "0"(us) // ); #elif F_CPU >= 8000000L // For the ATtiny85 running at 8MHz // The loop takes 4 cycles per iteration - us <<= 1; /* 1us per iteration */ + us <<= 1; // - /* Subtract the overhead of the function call and loop setup - * Assuming approximately 6 cycles overhead */ - us -= 6; /* Simplified subtraction */ + // + us -= 6; // // Assembly loop for delay __asm__ __volatile__( "1: sbiw %0, 1" - "\n\t" /* 2 cycles */ + "\n\t" // "rjmp .+0" - "\n\t" /* 2 cycles */ - "brne 1b" : "=w"(us) : "0"(us) /* 2 cycles */ + "\n\t" // + "brne 1b" : "=w"(us) : "0"(us) // ); #endif diff --git a/Helios/TimeControl.h b/Helios/TimeControl.h index 954bf639..725317ac 100644 --- a/Helios/TimeControl.h +++ b/Helios/TimeControl.h @@ -20,15 +20,10 @@ void time_cleanup(void); // Tick the clock forward to millis() void time_tick_clock(void); -/* Get the current tick, offset by any active simulation (simulation only exists in vortexlib) - * Exposing this as inline or macro seems to save on space a non negligible amount, it is used a lot - * and exposing in the header probably allows the compiler to optimize away repetitive calls */ +// uint32_t time_get_current_time(void); -/* Current microseconds since startup, only use this for things like measuring rapid data transfer timings. - * If you just need to perform regular time checks for a pattern or some logic then use time_get_current_time() and measure - * time in ticks, use the SEC_TO_TICKS() or MS_TO_TICKS() macros to convert timings to measures of ticks for - * purpose of comparing against time_get_current_time() */ +// uint32_t time_microseconds(void); // Delay for some number of microseconds or milliseconds, these are bad diff --git a/Helios/Timer.h b/Helios/Timer.h index a84d08ce..05a99e3e 100644 --- a/Helios/Timer.h +++ b/Helios/Timer.h @@ -23,8 +23,7 @@ void timer_init_default(helios_timer_t *timer); // Init a timer with a number of alarms and optionally start it void timer_init(helios_timer_t *timer, uint8_t alarm); -/* Start the timer but don't change current alarm, this shifts - * the timer startTime but does not reset it's alarm state */ +// void timer_start(helios_timer_t *timer, uint32_t offset); // Delete all alarms from the timer and reset From 043d5e496bf235e29481fe05dd0f6992b36027f3 Mon Sep 17 00:00:00 2001 From: Kurt LaVacque Date: Sat, 18 Oct 2025 10:58:11 +0200 Subject: [PATCH 14/17] Refactor comments across multiple files to improve clarity and consistency - Converted remaining C-style comments to C++ style comments. - Updated comments to provide clearer descriptions of functionality and intent. - Enhanced readability and maintainability of the codebase. --- Helios/Button.cpp | 38 +++++++++++++++++++++++--------------- Helios/Button.h | 4 ++-- Helios/Colorset.cpp | 10 +++++----- Helios/Colorset.h | 4 ++-- Helios/Colortypes.cpp | 28 ++++++++++++++-------------- Helios/Colortypes.h | 6 +++--- Helios/Led.cpp | 18 +++++++++--------- Helios/Led.h | 4 ++-- Helios/Pattern.cpp | 26 +++++++++++++------------- Helios/Pattern.h | 10 +++++----- Helios/Patterns.cpp | 12 ++++++------ Helios/Patterns.h | 6 +++--- Helios/Random.cpp | 2 +- Helios/Storage.cpp | 12 ++++++------ Helios/Storage.h | 4 ++-- Helios/TimeControl.cpp | 32 ++++++++++++++++---------------- Helios/TimeControl.h | 4 ++-- Helios/Timer.h | 2 +- 18 files changed, 115 insertions(+), 107 deletions(-) diff --git a/Helios/Button.cpp b/Helios/Button.cpp index e7386dd3..20dd5bde 100644 --- a/Helios/Button.cpp +++ b/Helios/Button.cpp @@ -43,17 +43,17 @@ static uint8_t m_longClick = 0; static uint8_t m_holdClick = 0; #ifdef HELIOS_CLI -// static uint8_t m_pinState = 0; static uint8_t m_enableWake = 0; -// Simple input queue for CLI - using a fixed-size circular buffer -// Larger queue size for CLI to handle long test sequences +// an input queue for the button, each tick one even is processed +// out of this queue and used to produce input #define INPUT_QUEUE_SIZE 4096 static char m_inputQueue[INPUT_QUEUE_SIZE]; static uint32_t m_queueHead = 0; static uint32_t m_queueTail = 0; #endif +// initialize a new button object with a pin number uint8_t button_init(void) { m_pressTime = 0; @@ -86,6 +86,7 @@ uint8_t button_init(void) return 1; } +// enable wake on press void button_enable_wake(void) { #ifdef HELIOS_EMBEDDED @@ -93,7 +94,7 @@ void button_enable_wake(void) PCMSK |= (1 << PCINT3); GIMSK |= (1 << PCIE); sei(); -#else // +#else // HELIOS_CLI m_enableWake = 1; #endif } @@ -106,6 +107,7 @@ ISR(PCINT0_vect) { } #endif +// directly poll the pin for whether it's pressed right now uint8_t button_check(void) { #ifdef HELIOS_EMBEDDED @@ -115,13 +117,15 @@ uint8_t button_check(void) return (PINB & (1 << 3)) != 0; #endif #elif defined(HELIOS_CLI) - // + // then just return the pin state as-is, the input event may have + // adjusted this value return m_pinState; #else return 0; #endif } +// detect if the button is being held for a long hold (past long click) uint8_t button_hold_pressing(void) { uint16_t holDur = (uint16_t)(button_hold_duration()); @@ -131,6 +135,7 @@ uint8_t button_hold_pressing(void) return 0; } +// poll the button pin and update the state of the button object void button_update(void) { #ifdef HELIOS_CLI @@ -163,7 +168,8 @@ void button_update(void) m_holdClick = (m_newRelease && (m_holdDuration >= HOLD_CLICK_START) && (m_holdDuration <= HOLD_CLICK_END)); #ifdef HELIOS_CLI - // + // if there was no pre-input event this tick, process a post input event + // to ensure there is only one event per tick processed if (!processed_pre) { button_process_post_input(); } @@ -239,23 +245,24 @@ static uint8_t button_process_pre_input(void) } char command = m_inputQueue[m_queueHead]; switch (command) { - case 'p': // + case 'p': // press button_do_press(); break; - case 'r': // + case 'r': // release button_do_release(); break; - case 't': // + case 't': // toggle button_do_toggle(); break; - case 'q': // + case 'q': // quit helios_terminate(); break; - case 'w': // + case 'w': // wait // wait is pre input I guess break; default: - // + // return here! do not pop the queue + // do not process post input events return 0; } // now pop whatever pre-input command was processed @@ -272,10 +279,10 @@ static uint8_t button_process_post_input(void) // process input queue from the command line char command = m_inputQueue[m_queueHead]; switch (command) { - case 'c': // + case 'c': // click button button_do_short_click(); break; - case 'l': // + case 'l': // long click button button_do_long_click(); break; default: @@ -313,7 +320,8 @@ void button_do_hold_click(void) m_releaseCount++; } -// +// this will actually press down the button, it's your responsibility to wait +// for the appropriate number of ticks and then release the button void button_do_press(void) { m_pinState = 1; diff --git a/Helios/Button.h b/Helios/Button.h index dba3ee09..809d09ab 100644 --- a/Helios/Button.h +++ b/Helios/Button.h @@ -56,12 +56,12 @@ uint8_t button_release_count(void); void button_enable_wake(void); #ifdef HELIOS_CLI -// +// void button_do_short_click(void); void button_do_long_click(void); void button_do_hold_click(void); -// +// void button_do_press(void); void button_do_release(void); void button_do_toggle(void); diff --git a/Helios/Colorset.cpp b/Helios/Colorset.cpp index b7b4e5a0..fd774797 100644 --- a/Helios/Colorset.cpp +++ b/Helios/Colorset.cpp @@ -4,7 +4,7 @@ #include -// +// #define INDEX_INVALID 255 void colorset_init(colorset_t *set) @@ -188,7 +188,7 @@ void colorset_randomize_colors(colorset_t *set, random_t *ctx, uint8_t numColors } else if (mode == COLOR_MODE_MONOCHROMATIC) { hueToUse = randomizedHue; valueToUse = 255 - (i * (256 / numColors)); - } else { // + } else { // hueToUse = (randomizedHue + (256 / numColors) * i); } colorset_add_color_with_value_style(set, ctx, hueToUse, valueToUse, valStyle, numColors, i); @@ -219,7 +219,7 @@ rgb_color_t colorset_get(const colorset_t *set, uint8_t index) void colorset_set(colorset_t *set, uint8_t index, rgb_color_t col) { - // + // if (index >= set->m_numColors) { if (!colorset_add_color(set, col)) { // ERROR_LOGF("Failed to add new color at index %u", index); @@ -242,9 +242,9 @@ void colorset_skip(colorset_t *set, int32_t amount) // first modulate the amount to skip to be within +/- the number of colors amount %= (int32_t)set->m_numColors; - // + // set->m_curIndex = ((int32_t)set->m_curIndex + (int32_t)amount) % (int32_t)set->m_numColors; - if (set->m_curIndex > set->m_numColors) { // + if (set->m_curIndex > set->m_numColors) { // // simply wrap it back set->m_curIndex += set->m_numColors; } diff --git a/Helios/Colorset.h b/Helios/Colorset.h index 9aa3a1ee..0318036e 100644 --- a/Helios/Colorset.h +++ b/Helios/Colorset.h @@ -55,7 +55,7 @@ struct colorset_t rgb_color_t m_palette[NUM_COLOR_SLOTS]; // the actual number of colors in the set uint8_t m_numColors; - // + // uint8_t m_curIndex; }; @@ -100,7 +100,7 @@ void colorset_adjust_brightness(colorset_t *set, uint8_t fadeby); // Get a color from the colorset rgb_color_t colorset_get(const colorset_t *set, uint8_t index); -// +// void colorset_set(colorset_t *set, uint8_t index, rgb_color_t col); // Skip some amount of colors diff --git a/Helios/Colortypes.cpp b/Helios/Colortypes.cpp index d0eee8f4..871b16e8 100644 --- a/Helios/Colortypes.cpp +++ b/Helios/Colortypes.cpp @@ -193,37 +193,37 @@ void rgb_scale_brightness(rgb_color_t *rgb, float scale) } #endif -// +// #if ALTERNATIVE_HSV_RGB == 1 #define SCALE8(i, scale) (((uint16_t)i * (uint16_t)(scale)) >> 8) #define FIXFRAC8(N,D) (((N)*256)/(D)) -// +// rgb_color_t hsv_to_rgb_rainbow(const hsv_color_t *rhs) { rgb_color_t col; - // + // const uint8_t Y1 = 1; const uint8_t Y2 = 0; - // + // const uint8_t G2 = 0; - // + // const uint8_t Gscale = 185; uint8_t hue = rhs->hue; uint8_t sat = rhs->sat; uint8_t val = rhs->val; - uint8_t offset = hue & 0x1F; // + uint8_t offset = hue & 0x1F; // // offset8 = offset * 8 uint8_t offset8 = offset; offset8 <<= 3; - uint8_t third = SCALE8(offset8, (256 / 3)); // + uint8_t third = SCALE8(offset8, (256 / 3)); // uint8_t r, g, b; if (!(hue & 0x80)) { // 0XX @@ -247,7 +247,7 @@ rgb_color_t hsv_to_rgb_rainbow(const hsv_color_t *rhs) if (Y2) { r = 170 + third; // uint8_t twothirds = (third << 1); - uint8_t twothirds = SCALE8(offset8, ((256 * 2) / 3)); // + uint8_t twothirds = SCALE8(offset8, ((256 * 2) / 3)); // g = 85 + twothirds; b = 0; } @@ -260,7 +260,7 @@ rgb_color_t hsv_to_rgb_rainbow(const hsv_color_t *rhs) // case 2: Y -> G if (Y1) { // uint8_t twothirds = (third << 1); - uint8_t twothirds = SCALE8(offset8, ((256 * 2) / 3)); // + uint8_t twothirds = SCALE8(offset8, ((256 * 2) / 3)); // r = 171 - twothirds; g = 170 + third; b = 0; @@ -288,8 +288,8 @@ rgb_color_t hsv_to_rgb_rainbow(const hsv_color_t *rhs) // case 4: A -> B r = 0; // uint8_t twothirds = (third << 1); - uint8_t twothirds = SCALE8(offset8, ((256 * 2) / 3)); // - g = 171 - twothirds; // + uint8_t twothirds = SCALE8(offset8, ((256 * 2) / 3)); // + g = 171 - twothirds; // b = 85 + twothirds; } else { // 101 @@ -315,11 +315,11 @@ rgb_color_t hsv_to_rgb_rainbow(const hsv_color_t *rhs) } } - // + // if (G2) g = g >> 1; if (Gscale) g = SCALE8(g, Gscale); - // + // if (sat != 255) { if (sat == 0) { r = 255; b = 255; g = 255; @@ -351,7 +351,7 @@ rgb_color_t hsv_to_rgb_rainbow(const hsv_color_t *rhs) } } - // + // col.red = r; col.green = g; col.blue = b; diff --git a/Helios/Colortypes.h b/Helios/Colortypes.h index b48681da..0468d86b 100644 --- a/Helios/Colortypes.h +++ b/Helios/Colortypes.h @@ -17,7 +17,7 @@ enum hsv_to_rgb_algorithm HSV_TO_RGB_RAINBOW }; -// +// extern enum hsv_to_rgb_algorithm g_hsv_rgb_alg; #endif @@ -67,14 +67,14 @@ void rgb_adjust_brightness(rgb_color_t *rgb, uint8_t fadeBy); uint32_t rgb_raw(const rgb_color_t *rgb); #ifdef HELIOS_CLI -// +// void rgb_scale_brightness(rgb_color_t *rgb, float scale); // Bring up the brightness of a color to a minimum level void rgb_bring_up_brightness(rgb_color_t *rgb, uint8_t min_brightness); #endif // Conversion functions -// +// rgb_color_t hsv_to_rgb_rainbow(const hsv_color_t *rhs); // Generic hsv to rgb conversion nothing special rgb_color_t hsv_to_rgb_generic(const hsv_color_t *rhs); diff --git a/Helios/Led.cpp b/Helios/Led.cpp index 6d0e6494..9b108d58 100644 --- a/Helios/Led.cpp +++ b/Helios/Led.cpp @@ -14,9 +14,9 @@ #include #include #endif -#define PWM_PIN_R PB0 // -#define PWM_PIN_G PB1 // -#define PWM_PIN_B PB4 // +#define PWM_PIN_R PB0 // +#define PWM_PIN_G PB1 // +#define PWM_PIN_B PB4 // #endif #define SCALE8(i, scale) (((uint16_t)i * (uint16_t)(scale)) >> 8) @@ -129,16 +129,16 @@ static void led_set_pwm(uint8_t pwmPin, uint8_t pwmValue, volatile uint8_t *cont #ifdef HELIOS_EMBEDDED if (pwmValue == 0) { // digitalWrite(pin, LOW) - *controlRegister &= ~controlBit; // - PORTB &= ~(1 << pwmPin); // + *controlRegister &= ~controlBit; // + PORTB &= ~(1 << pwmPin); // } else if (pwmValue == 255) { // digitalWrite(pin, HIGH) - *controlRegister &= ~controlBit; // - PORTB |= (1 << pwmPin); // + *controlRegister &= ~controlBit; // + PORTB |= (1 << pwmPin); // } else { // analogWrite(pin, value) - *controlRegister |= controlBit; // - *compareRegister = pwmValue; // + *controlRegister |= controlBit; // + *compareRegister = pwmValue; // } #else (void)pwmPin; diff --git a/Helios/Led.h b/Helios/Led.h index 86805afa..dd83bb81 100644 --- a/Helios/Led.h +++ b/Helios/Led.h @@ -9,7 +9,7 @@ extern "C" { #include "Colortypes.h" -// +// uint8_t led_init(void); void led_cleanup(void); @@ -27,7 +27,7 @@ void led_adjust_brightness(uint8_t fadeBy); // strobe between two colors with a simple on/off timing void led_strobe(uint16_t on_time, uint16_t off_time, const rgb_color_t *col1, const rgb_color_t *col2); -// +// void led_breath(uint8_t hue, uint32_t duration, uint8_t magnitude, uint8_t sat, uint8_t val); // a very specialized api to hold all leds on a color for 250ms diff --git a/Helios/Pattern.cpp b/Helios/Pattern.cpp index 25207723..4a125791 100644 --- a/Helios/Pattern.cpp +++ b/Helios/Pattern.cpp @@ -6,7 +6,7 @@ #include "HeliosConfig.h" #include "Led.h" -#include // +#include // // Forward declarations for internal functions static void pattern_on_blink_on(pattern_t *pat); @@ -18,7 +18,7 @@ static void pattern_blend_blink_on(pattern_t *pat); static void pattern_interpolate(uint8_t *current, const uint8_t next, uint8_t blend_speed); static void pattern_tick_fade(pattern_t *pat); -// +// void pattern_args_init(pattern_args_t *args, uint8_t on, uint8_t off, uint8_t gap, uint8_t dash, uint8_t group, uint8_t blend, uint8_t fade) @@ -32,7 +32,7 @@ void pattern_args_init(pattern_args_t *args, uint8_t on, uint8_t off, uint8_t ga args->fade_dur = fade; } -// +// void pattern_init(pattern_t *pat, uint8_t onDur, uint8_t offDur, uint8_t gap, uint8_t dash, uint8_t group, uint8_t blend, uint8_t fade) @@ -64,7 +64,7 @@ void pattern_init_state(pattern_t *pat) // the default state to begin with pat->m_state = STATE_BLINK_ON; - // + // if (pat->m_args.dash_dur > 0) { pat->m_state = STATE_BEGIN_DASH; } @@ -128,7 +128,7 @@ void pattern_play(pattern_t *pat) pattern_tick_fade(pat); } - // + // replay: // its kinda evolving as i go @@ -145,7 +145,7 @@ void pattern_play(pattern_t *pat) } pat->m_state = STATE_BLINK_OFF; case STATE_BLINK_OFF: - // + // if (pat->m_groupCounter > 0 || (!pat->m_args.gap_dur && !pat->m_args.dash_dur)) { if (pat->m_args.off_dur > 0) { pattern_on_blink_off(pat); @@ -190,12 +190,12 @@ void pattern_play(pattern_t *pat) return; } - // + // if (pat->m_state == STATE_IN_GAP2 || (pat->m_state == STATE_OFF && pat->m_groupCounter > 0)) { - // + // pat->m_state = pat->m_args.on_dur ? STATE_BLINK_ON : (pat->m_args.dash_dur ? STATE_BEGIN_DASH : STATE_BEGIN_GAP); } else if (pat->m_state == STATE_OFF && (!pat->m_groupCounter || colorset_num_colors(&pat->m_colorset) == 1)) { - // + // pat->m_state = (pat->m_groupCounter > 0) ? STATE_BLINK_ON : STATE_BEGIN_GAP; } else { // this is the standard case, iterate to the next state @@ -240,13 +240,13 @@ static void pattern_on_blink_on(pattern_t *pat) static void pattern_on_blink_off(pattern_t *pat) { - (void)pat; // + (void)pat; // led_clear(); } static void pattern_begin_gap(pattern_t *pat) { - (void)pat; // + (void)pat; // led_clear(); } @@ -296,7 +296,7 @@ uint8_t pattern_equals(const pattern_t *pat, const pattern_t *other) if (memcmp(&pat->m_args, &other->m_args, sizeof(pattern_args_t)) != 0) { return 0; } - // + // return 1; } @@ -338,7 +338,7 @@ uint8_t pattern_is_fade(const pattern_t *pat) static void pattern_blend_blink_on(pattern_t *pat) { - // + // if (rgb_equals(&pat->m_cur, &pat->m_next)) { pat->m_next = colorset_get_next(&pat->m_colorset); } diff --git a/Helios/Pattern.h b/Helios/Pattern.h index 8dc724ed..244f7054 100644 --- a/Helios/Pattern.h +++ b/Helios/Pattern.h @@ -58,17 +58,17 @@ enum pattern_state struct pattern_t { - // + // pattern_args_t m_args; - // + // // any flags the pattern has uint8_t m_patternFlags; // a copy of the colorset that this pattern is initialized with colorset_t m_colorset; - // + // uint8_t m_groupCounter; // the state of the current pattern @@ -77,13 +77,13 @@ struct pattern_t // the blink timer used to measure blink timings helios_timer_t m_blinkTimer; - // + // // current color and target blend color rgb_color_t m_cur; rgb_color_t m_next; - // + // // shifting value to represent current fade uint8_t m_fadeValue; diff --git a/Helios/Patterns.cpp b/Helios/Patterns.cpp index 50934291..2a0cd88c 100644 --- a/Helios/Patterns.cpp +++ b/Helios/Patterns.cpp @@ -4,8 +4,8 @@ #include "Pattern.h" #include "ColorConstants.h" -// -static const uint32_t color_codes0[] = {RGB_RED, RGB_GREEN, RGB_BLUE}; // +// +static const uint32_t color_codes0[] = {RGB_RED, RGB_GREEN, RGB_BLUE}; // // Define Colorset configurations for each slot struct default_colorset_t { @@ -13,9 +13,9 @@ struct default_colorset_t { const uint32_t *cols; }; -// +// static const struct default_colorset_t default_colorsets[] = { - { 3, color_codes0 }, // + { 3, color_codes0 }, // }; void patterns_make_default(uint8_t index, pattern_t *pat) @@ -26,7 +26,7 @@ void patterns_make_default(uint8_t index, pattern_t *pat) pattern_args_t args; pattern_args_init(&args, 0, 0, 0, 0, 0, 0, 0); switch (index) { - case 0: // + case 0: // args.on_dur = 3; args.off_dur = 23; break; @@ -66,7 +66,7 @@ void patterns_make_pattern(enum pattern_id id, pattern_t *pat) case PATTERN_RAZOR: args.on_dur = 3; args.off_dur = 1; - args.gap_dur = 30; // + args.gap_dur = 30; // break; case PATTERN_DASH_DOPS: diff --git a/Helios/Patterns.h b/Helios/Patterns.h index b9c181bf..6cd74bb5 100644 --- a/Helios/Patterns.h +++ b/Helios/Patterns.h @@ -10,9 +10,9 @@ extern "C" { // Forward declaration typedef struct pattern_t pattern_t; -// +// enum pattern_id { - // + // PATTERN_NONE = -1, // first pattern of all @@ -29,7 +29,7 @@ enum pattern_id { // Meta pattern constants INTERNAL_PATTERNS_END, PATTERN_LAST = (INTERNAL_PATTERNS_END - 1), - PATTERN_COUNT = (PATTERN_LAST - PATTERN_FIRST) + 1, // + PATTERN_COUNT = (PATTERN_LAST - PATTERN_FIRST) + 1, // }; void patterns_make_default(uint8_t index, pattern_t *pat); diff --git a/Helios/Random.cpp b/Helios/Random.cpp index bf221b52..12c7b521 100644 --- a/Helios/Random.cpp +++ b/Helios/Random.cpp @@ -26,7 +26,7 @@ uint16_t random_next16(random_t *rng, uint16_t minValue, uint16_t maxValue) rng->m_seed = (rng->m_seed * 1103515245 + 12345) & 0x7FFFFFFF; uint32_t range = maxValue - minValue; if (range != 0xFFFFFFFF) { - // + // return ((rng->m_seed >> 16) % (range + 1)) + minValue; } return (rng->m_seed >> 16); diff --git a/Helios/Storage.cpp b/Helios/Storage.cpp index 5a318ac9..fa88f57e 100644 --- a/Helios/Storage.cpp +++ b/Helios/Storage.cpp @@ -136,7 +136,7 @@ void storage_write_brightness(uint8_t brightness) uint8_t storage_crc8(uint8_t pos, uint8_t size) { - uint8_t hash = 33; // + uint8_t hash = 33; // uint8_t i; for (i = 0; i < size; ++i) { hash = ((hash << 5) + hash) + storage_read_byte(pos); @@ -171,7 +171,7 @@ static void storage_write_crc(uint8_t pos) static void storage_write_byte(uint8_t address, uint8_t data) { #ifdef HELIOS_EMBEDDED - // + // if (storage_read_byte(address) == data) { return; } @@ -182,7 +182,7 @@ static void storage_write_byte(uint8_t address, uint8_t data) storage_internal_write(address, data); // god forbid it doesn't write again } -#else // +#else // if (!m_enableStorage) { return; } @@ -201,7 +201,7 @@ static void storage_write_byte(uint8_t address, uint8_t data) fclose(f); return; } - fclose(f); // + fclose(f); // #endif } @@ -230,7 +230,7 @@ static uint8_t storage_read_byte(uint8_t address) if (access(STORAGE_FILENAME, O_RDONLY) != 0) { return val; } - FILE *f = fopen(STORAGE_FILENAME, "rb"); // + FILE *f = fopen(STORAGE_FILENAME, "rb"); // if (!f) { // this error is ok, just means no storage // perror("Error opening file for read"); @@ -247,7 +247,7 @@ static uint8_t storage_read_byte(uint8_t address) if (!fread(&val, sizeof(uint8_t), 1, f)) { perror("Failed to read byte"); } - fclose(f); // + fclose(f); // return val; #endif } diff --git a/Helios/Storage.h b/Helios/Storage.h index fbd2c2f1..ca6a1836 100644 --- a/Helios/Storage.h +++ b/Helios/Storage.h @@ -8,9 +8,9 @@ extern "C" { #include #include "HeliosConfig.h" -// +// #define CONFIG_START_INDEX (STORAGE_SIZE - 2) -// +// #define CONFIG_CRC_INDEX (STORAGE_SIZE - 1) // Storage Config Indexes relative to the CONFIG_START_INDEX diff --git a/Helios/TimeControl.cpp b/Helios/TimeControl.cpp index b48afed0..3ee61ed3 100644 --- a/Helios/TimeControl.cpp +++ b/Helios/TimeControl.cpp @@ -59,7 +59,7 @@ void time_tick_clock(void) } #endif - // + // uint32_t elapsed_us; uint32_t us; do { @@ -72,7 +72,7 @@ void time_tick_clock(void) // otherwise calculate regular difference elapsed_us = (uint32_t)(us - m_prevTime); } - // + // } while (elapsed_us < (1000000 / TICKRATE)); // store current time @@ -87,7 +87,7 @@ uint32_t time_get_current_time(void) #ifdef HELIOS_EMBEDDED volatile uint32_t timer0_overflow_count = 0; ISR(TIMER0_OVF_vect) { - timer0_overflow_count++; // + timer0_overflow_count++; // } #endif @@ -102,7 +102,7 @@ uint32_t time_microseconds(void) #ifdef HELIOS_ARDUINO return micros(); #else - // + // uint8_t oldSREG = SREG; cli(); // multiply by 8 early to avoid floating point math or division @@ -125,36 +125,36 @@ time_delay_microseconds(uint32_t us) // For the ATtiny85 running at 16MHz // The loop takes 3 cycles per iteration - us *= 2; // + us *= 2; // - // - us -= 5; // + // + us -= 5; // // Assembly loop for delay __asm__ __volatile__( "1: sbiw %0, 1" - "\n\t" // + "\n\t" // "nop" - "\n\t" // - "brne 1b" : "=w"(us) : "0"(us) // + "\n\t" // + "brne 1b" : "=w"(us) : "0"(us) // ); #elif F_CPU >= 8000000L // For the ATtiny85 running at 8MHz // The loop takes 4 cycles per iteration - us <<= 1; // + us <<= 1; // - // - us -= 6; // + // + us -= 6; // // Assembly loop for delay __asm__ __volatile__( "1: sbiw %0, 1" - "\n\t" // + "\n\t" // "rjmp .+0" - "\n\t" // - "brne 1b" : "=w"(us) : "0"(us) // + "\n\t" // + "brne 1b" : "=w"(us) : "0"(us) // ); #endif diff --git a/Helios/TimeControl.h b/Helios/TimeControl.h index 725317ac..6dba610b 100644 --- a/Helios/TimeControl.h +++ b/Helios/TimeControl.h @@ -20,10 +20,10 @@ void time_cleanup(void); // Tick the clock forward to millis() void time_tick_clock(void); -// +// uint32_t time_get_current_time(void); -// +// uint32_t time_microseconds(void); // Delay for some number of microseconds or milliseconds, these are bad diff --git a/Helios/Timer.h b/Helios/Timer.h index 05a99e3e..97ac4ae2 100644 --- a/Helios/Timer.h +++ b/Helios/Timer.h @@ -23,7 +23,7 @@ void timer_init_default(helios_timer_t *timer); // Init a timer with a number of alarms and optionally start it void timer_init(helios_timer_t *timer, uint8_t alarm); -// +// void timer_start(helios_timer_t *timer, uint32_t offset); // Delete all alarms from the timer and reset From e29c6c57cdf58f4e8004fb5e531433605e664c87 Mon Sep 17 00:00:00 2001 From: Kurt LaVacque Date: Sat, 18 Oct 2025 10:59:42 +0200 Subject: [PATCH 15/17] Enhance comments in Colorset.cpp for clarity and consistency - Updated comments to provide clearer descriptions of color selection behavior. - Converted C-style comments to C++ style for improved readability. - These changes contribute to better understanding and maintainability of the code. --- Helios/Colorset.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Helios/Colorset.cpp b/Helios/Colorset.cpp index fd774797..a06bb5dd 100644 --- a/Helios/Colorset.cpp +++ b/Helios/Colorset.cpp @@ -4,7 +4,9 @@ #include -// +// when no color is selected in the colorset the index is this +// then when you call getNext() for the first time it returns +// the 0th color in the colorset and after the index will be 0 #define INDEX_INVALID 255 void colorset_init(colorset_t *set) @@ -188,7 +190,7 @@ void colorset_randomize_colors(colorset_t *set, random_t *ctx, uint8_t numColors } else if (mode == COLOR_MODE_MONOCHROMATIC) { hueToUse = randomizedHue; valueToUse = 255 - (i * (256 / numColors)); - } else { // + } else { // EVENLY_SPACED hueToUse = (randomizedHue + (256 / numColors) * i); } colorset_add_color_with_value_style(set, ctx, hueToUse, valueToUse, valStyle, numColors, i); @@ -207,6 +209,7 @@ void colorset_adjust_brightness(colorset_t *set, uint8_t fadeby) } } +// get a color from the colorset rgb_color_t colorset_get(const colorset_t *set, uint8_t index) { rgb_color_t result; From 6042a5d1415333974c76a04ddf9be46fbe2f1176 Mon Sep 17 00:00:00 2001 From: Kurt LaVacque Date: Sat, 18 Oct 2025 11:04:38 +0200 Subject: [PATCH 16/17] Restore meaningful comments that were unnecessarily removed --- Helios/Button.h | 45 ++++++++++++++++++++++++------------------ Helios/Colorset.cpp | 11 +++++++---- Helios/Colorset.h | 6 ++++-- Helios/Colortypes.cpp | 45 +++++++++++++++++++++++++++++------------- Helios/Colortypes.h | 11 ++++++++--- Helios/Led.cpp | 18 ++++++++--------- Helios/Led.h | 6 ++++-- Helios/Pattern.cpp | 38 +++++++++++++++++++++++------------ Helios/Pattern.h | 15 +++++++++----- Helios/Random.cpp | 5 ++++- Helios/Storage.cpp | 13 ++++++------ Helios/Storage.h | 6 ++++-- Helios/TimeControl.cpp | 44 ++++++++++++++++++++++++++--------------- Helios/TimeControl.h | 9 +++++++-- Helios/Timer.h | 3 ++- 15 files changed, 176 insertions(+), 99 deletions(-) diff --git a/Helios/Button.h b/Helios/Button.h index 809d09ab..56d195bb 100644 --- a/Helios/Button.h +++ b/Helios/Button.h @@ -7,66 +7,73 @@ extern "C" { #include -// Initialize button +// initialize a new button object with a pin number uint8_t button_init(void); -// Directly poll the pin for whether it's pressed right now +// directly poll the pin for whether it's pressed right now uint8_t button_check(void); -// Poll the button pin and update the state of the button object +// poll the button pin and update the state of the button object void button_update(void); -// Whether the button was pressed this tick +// whether the button was pressed this tick uint8_t button_on_press(void); -// Whether the button was released this tick +// whether the button was released this tick uint8_t button_on_release(void); -// Whether the button is currently pressed +// whether the button is currently pressed uint8_t button_is_pressed(void); -// Whether the button was shortclicked this tick +// whether the button was shortclicked this tick uint8_t button_on_short_click(void); -// Whether the button was long clicked this tick +// whether the button was long clicked this tick uint8_t button_on_long_click(void); -// Whether the button was hold clicked this tick +// whether the button was hold clicked this tick uint8_t button_on_hold_click(void); -// Detect if the button is being held past long click +// detect if the button is being held past long click uint8_t button_hold_pressing(void); -// When the button was last pressed +// when the button was last pressed uint32_t button_press_time(void); -// When the button was last released +// when the button was last released uint32_t button_release_time(void); -// How long the button is currently or was last held down (in ticks) +// how long the button is currently or was last held down (in ticks) uint32_t button_hold_duration(void); -// How long the button is currently or was last released for (in ticks) +// how long the button is currently or was last released for (in ticks) uint32_t button_release_duration(void); -// The number of releases +// the number of releases uint8_t button_release_count(void); -// Enable wake on press +// enable wake on press void button_enable_wake(void); #ifdef HELIOS_CLI -// +// these will 'inject' a short/long click without actually touching the +// button state, it's important that code uses 'onShortClick' or +// 'onLongClick' to capture this injected input event. Code that uses +// for example: 'button.holdDuration() >= threshold && button.onRelease()' +// will never trigger because the injected input event doesn't actually +// press the button or change the button state it just sets the 'shortClick' +// or 'longClick' values accordingly void button_do_short_click(void); void button_do_long_click(void); void button_do_hold_click(void); -// + // this will actually press down the button, it's your responsibility to wait + // for the appropriate number of ticks and then release the button void button_do_press(void); void button_do_release(void); void button_do_toggle(void); -// Queue up an input event for the button +// queue up an input event for the button void button_queue_input(char input); uint32_t button_input_queue_size(void); #endif diff --git a/Helios/Colorset.cpp b/Helios/Colorset.cpp index a06bb5dd..1d808825 100644 --- a/Helios/Colorset.cpp +++ b/Helios/Colorset.cpp @@ -5,7 +5,7 @@ #include // when no color is selected in the colorset the index is this -// then when you call getNext() for the first time it returns +// then when you call colorset_getNext() for the first time it returns // the 0th color in the colorset and after the index will be 0 #define INDEX_INVALID 255 @@ -222,7 +222,8 @@ rgb_color_t colorset_get(const colorset_t *set, uint8_t index) void colorset_set(colorset_t *set, uint8_t index, rgb_color_t col) { - // + // special case for 'setting' a color at the edge of the palette, + // ie adding a new color when you set an index higher than the max if (index >= set->m_numColors) { if (!colorset_add_color(set, col)) { // ERROR_LOGF("Failed to add new color at index %u", index); @@ -245,9 +246,11 @@ void colorset_skip(colorset_t *set, int32_t amount) // first modulate the amount to skip to be within +/- the number of colors amount %= (int32_t)set->m_numColors; - // + // max = 3 + // m_curIndex = 2 + // amount = -10 set->m_curIndex = ((int32_t)set->m_curIndex + (int32_t)amount) % (int32_t)set->m_numColors; - if (set->m_curIndex > set->m_numColors) { // + if (set->m_curIndex > set->m_numColors) { // must have wrapped // simply wrap it back set->m_curIndex += set->m_numColors; } diff --git a/Helios/Colorset.h b/Helios/Colorset.h index 0318036e..47642a5b 100644 --- a/Helios/Colorset.h +++ b/Helios/Colorset.h @@ -55,7 +55,8 @@ struct colorset_t rgb_color_t m_palette[NUM_COLOR_SLOTS]; // the actual number of colors in the set uint8_t m_numColors; - // + // the current index, starts at 255 so that + // the very first call to colorset_getNext will iterate to 0 uint8_t m_curIndex; }; @@ -100,7 +101,8 @@ void colorset_adjust_brightness(colorset_t *set, uint8_t fadeby); // Get a color from the colorset rgb_color_t colorset_get(const colorset_t *set, uint8_t index); -// +// Set an rgb color in a slot, or add a new color if you specify +// a slot higher than the number of colors in the colorset void colorset_set(colorset_t *set, uint8_t index, rgb_color_t col); // Skip some amount of colors diff --git a/Helios/Colortypes.cpp b/Helios/Colortypes.cpp index 871b16e8..7e8adf11 100644 --- a/Helios/Colortypes.cpp +++ b/Helios/Colortypes.cpp @@ -193,37 +193,49 @@ void rgb_scale_brightness(rgb_color_t *rgb, float scale) } #endif -// +// ======================================================== +// Below are various functions for converting hsv <-> rgb #if ALTERNATIVE_HSV_RGB == 1 #define SCALE8(i, scale) (((uint16_t)i * (uint16_t)(scale)) >> 8) #define FIXFRAC8(N,D) (((N)*256)/(D)) -// +// Stolen from FastLED hsv to rgb full rainbow where all colours +// are given equal weight, this makes for-example yellow larger +// best to use this function as it is the legacy choice rgb_color_t hsv_to_rgb_rainbow(const hsv_color_t *rhs) { rgb_color_t col; - // + // Yellow has a higher inherent brightness than + // any other color; 'pure' yellow is perceived to + // be 93% as bright as white. In order to make + // yellow appear the correct relative brightness, + // it has to be rendered brighter than all other + // colors. + // Level Y1 is a moderate boost, the default. + // Level Y2 is a strong boost. const uint8_t Y1 = 1; const uint8_t Y2 = 0; - // + // G2: Whether to divide all greens by two. + // Depends GREATLY on your particular LEDs const uint8_t G2 = 0; - // + // Gscale: what to scale green down by. + // Depends GREATLY on your particular LEDs const uint8_t Gscale = 185; uint8_t hue = rhs->hue; uint8_t sat = rhs->sat; uint8_t val = rhs->val; - uint8_t offset = hue & 0x1F; // + uint8_t offset = hue & 0x1F; // 0..31 // offset8 = offset * 8 uint8_t offset8 = offset; offset8 <<= 3; - uint8_t third = SCALE8(offset8, (256 / 3)); // + uint8_t third = SCALE8(offset8, (256 / 3)); // max = 85 uint8_t r, g, b; if (!(hue & 0x80)) { // 0XX @@ -247,7 +259,7 @@ rgb_color_t hsv_to_rgb_rainbow(const hsv_color_t *rhs) if (Y2) { r = 170 + third; // uint8_t twothirds = (third << 1); - uint8_t twothirds = SCALE8(offset8, ((256 * 2) / 3)); // + uint8_t twothirds = SCALE8(offset8, ((256 * 2) / 3)); // max=170 g = 85 + twothirds; b = 0; } @@ -260,7 +272,7 @@ rgb_color_t hsv_to_rgb_rainbow(const hsv_color_t *rhs) // case 2: Y -> G if (Y1) { // uint8_t twothirds = (third << 1); - uint8_t twothirds = SCALE8(offset8, ((256 * 2) / 3)); // + uint8_t twothirds = SCALE8(offset8, ((256 * 2) / 3)); // max=170 r = 171 - twothirds; g = 170 + third; b = 0; @@ -288,8 +300,8 @@ rgb_color_t hsv_to_rgb_rainbow(const hsv_color_t *rhs) // case 4: A -> B r = 0; // uint8_t twothirds = (third << 1); - uint8_t twothirds = SCALE8(offset8, ((256 * 2) / 3)); // - g = 171 - twothirds; // + uint8_t twothirds = SCALE8(offset8, ((256 * 2) / 3)); // max=170 + g = 171 - twothirds; // 170? b = 85 + twothirds; } else { // 101 @@ -315,11 +327,13 @@ rgb_color_t hsv_to_rgb_rainbow(const hsv_color_t *rhs) } } - // + // This is one of the good places to scale the green down, + // although the client can scale green down as well. if (G2) g = g >> 1; if (Gscale) g = SCALE8(g, Gscale); - // + // Scale down colors if we're desaturated at all + // and add the brightness_floor to r, g, and b. if (sat != 255) { if (sat == 0) { r = 255; b = 255; g = 255; @@ -351,7 +365,10 @@ rgb_color_t hsv_to_rgb_rainbow(const hsv_color_t *rhs) } } - // + // Here we have the old AVR "missing std X+n" problem again + // It turns out that fixing it winds up costing more than + // not fixing it. + // To paraphrase Dr Bronner, profile! profile! profile! col.red = r; col.green = g; col.blue = b; diff --git a/Helios/Colortypes.h b/Helios/Colortypes.h index 0468d86b..b1f0616b 100644 --- a/Helios/Colortypes.h +++ b/Helios/Colortypes.h @@ -17,7 +17,8 @@ enum hsv_to_rgb_algorithm HSV_TO_RGB_RAINBOW }; -// +// global hsv to rgb algorithm selector, switch this to control +// all hsv to rgb conversions extern enum hsv_to_rgb_algorithm g_hsv_rgb_alg; #endif @@ -67,14 +68,18 @@ void rgb_adjust_brightness(rgb_color_t *rgb, uint8_t fadeBy); uint32_t rgb_raw(const rgb_color_t *rgb); #ifdef HELIOS_CLI -// +// Return a scaled brightness version of the current color +// ex: 0.0 = black, 0.5 = half brightness, 1.0 = no change, +// 1.5 = 50% brighter, 2.0 = twice as bright, 255.0 = white void rgb_scale_brightness(rgb_color_t *rgb, float scale); // Bring up the brightness of a color to a minimum level void rgb_bring_up_brightness(rgb_color_t *rgb, uint8_t min_brightness); #endif // Conversion functions -// +// Stolen from FastLED hsv to rgb full rainbow where all colours +// are given equal weight, this makes for-example yellow larger +// best to use this function as it is the legacy choice rgb_color_t hsv_to_rgb_rainbow(const hsv_color_t *rhs); // Generic hsv to rgb conversion nothing special rgb_color_t hsv_to_rgb_generic(const hsv_color_t *rhs); diff --git a/Helios/Led.cpp b/Helios/Led.cpp index 9b108d58..9bce4e01 100644 --- a/Helios/Led.cpp +++ b/Helios/Led.cpp @@ -14,9 +14,9 @@ #include #include #endif -#define PWM_PIN_R PB0 // -#define PWM_PIN_G PB1 // -#define PWM_PIN_B PB4 // +#define PWM_PIN_R PB0 // Red channel (pin 5) +#define PWM_PIN_G PB1 // Green channel (pin 6) +#define PWM_PIN_B PB4 // Blue channel (pin 3) #endif #define SCALE8(i, scale) (((uint16_t)i * (uint16_t)(scale)) >> 8) @@ -129,16 +129,16 @@ static void led_set_pwm(uint8_t pwmPin, uint8_t pwmValue, volatile uint8_t *cont #ifdef HELIOS_EMBEDDED if (pwmValue == 0) { // digitalWrite(pin, LOW) - *controlRegister &= ~controlBit; // - PORTB &= ~(1 << pwmPin); // + *controlRegister &= ~controlBit; // Disable PWM + PORTB &= ~(1 << pwmPin); // Set the pin low } else if (pwmValue == 255) { // digitalWrite(pin, HIGH) - *controlRegister &= ~controlBit; // - PORTB |= (1 << pwmPin); // + *controlRegister &= ~controlBit; // Disable PWM + PORTB |= (1 << pwmPin); // Set the pin high } else { // analogWrite(pin, value) - *controlRegister |= controlBit; // - *compareRegister = pwmValue; // + *controlRegister |= controlBit; // Enable PWM + *compareRegister = pwmValue; // Set PWM duty cycle } #else (void)pwmPin; diff --git a/Helios/Led.h b/Helios/Led.h index dd83bb81..a132b493 100644 --- a/Helios/Led.h +++ b/Helios/Led.h @@ -9,7 +9,8 @@ extern "C" { #include "Colortypes.h" -// +// opting for static functions here because there should only ever be one +// Led control object and I don't like singletons uint8_t led_init(void); void led_cleanup(void); @@ -27,7 +28,8 @@ void led_adjust_brightness(uint8_t fadeBy); // strobe between two colors with a simple on/off timing void led_strobe(uint16_t on_time, uint16_t off_time, const rgb_color_t *col1, const rgb_color_t *col2); -// +// breath the hue on an index +// warning: these use hsv to rgb in realtime! void led_breath(uint8_t hue, uint32_t duration, uint8_t magnitude, uint8_t sat, uint8_t val); // a very specialized api to hold all leds on a color for 250ms diff --git a/Helios/Pattern.cpp b/Helios/Pattern.cpp index 4a125791..7d1b701a 100644 --- a/Helios/Pattern.cpp +++ b/Helios/Pattern.cpp @@ -6,7 +6,7 @@ #include "HeliosConfig.h" #include "Led.h" -#include // +#include // for memcpy // Forward declarations for internal functions static void pattern_on_blink_on(pattern_t *pat); @@ -18,7 +18,8 @@ static void pattern_blend_blink_on(pattern_t *pat); static void pattern_interpolate(uint8_t *current, const uint8_t next, uint8_t blend_speed); static void pattern_tick_fade(pattern_t *pat); -// +// ================================== +// Pattern Args Functions void pattern_args_init(pattern_args_t *args, uint8_t on, uint8_t off, uint8_t gap, uint8_t dash, uint8_t group, uint8_t blend, uint8_t fade) @@ -32,7 +33,8 @@ void pattern_args_init(pattern_args_t *args, uint8_t on, uint8_t off, uint8_t ga args->fade_dur = fade; } -// +// ================================== +// Pattern Functions void pattern_init(pattern_t *pat, uint8_t onDur, uint8_t offDur, uint8_t gap, uint8_t dash, uint8_t group, uint8_t blend, uint8_t fade) @@ -64,7 +66,8 @@ void pattern_init_state(pattern_t *pat) // the default state to begin with pat->m_state = STATE_BLINK_ON; - // + // if a dash is present then always start with the dash because + // it consumes the first color in the colorset if (pat->m_args.dash_dur > 0) { pat->m_state = STATE_BEGIN_DASH; } @@ -128,7 +131,8 @@ void pattern_play(pattern_t *pat) pattern_tick_fade(pat); } - // + // Sometimes the pattern needs to cycle multiple states in a single frame so + // instead of using a loop or recursion I have just used a simple goto replay: // its kinda evolving as i go @@ -145,7 +149,8 @@ void pattern_play(pattern_t *pat) } pat->m_state = STATE_BLINK_OFF; case STATE_BLINK_OFF: - // + // the whole 'should blink off' situation is tricky because we might need + // to go back to blinking on if our colorset isn't at the end yet if (pat->m_groupCounter > 0 || (!pat->m_args.gap_dur && !pat->m_args.dash_dur)) { if (pat->m_args.off_dur > 0) { pattern_on_blink_off(pat); @@ -190,12 +195,17 @@ void pattern_play(pattern_t *pat) return; } - // + // this just transitions the state into the next state, with some edge conditions for + // transitioning to different states under certain circumstances. Honestly this is + // a nightmare to read now and idk how to fix it if (pat->m_state == STATE_IN_GAP2 || (pat->m_state == STATE_OFF && pat->m_groupCounter > 0)) { - // + // this is an edge condition for when in the second gap or off in the non-last off blink + // then the state actually needs to jump backwards rather than iterate pat->m_state = pat->m_args.on_dur ? STATE_BLINK_ON : (pat->m_args.dash_dur ? STATE_BEGIN_DASH : STATE_BEGIN_GAP); } else if (pat->m_state == STATE_OFF && (!pat->m_groupCounter || colorset_num_colors(&pat->m_colorset) == 1)) { - // + // this is an edge condition when the state is off but this is the last off blink in the + // group or there's literally only one color in the group then if there is more blinks + // left in the group we need to cycle back to blink on instead of to the next state pat->m_state = (pat->m_groupCounter > 0) ? STATE_BLINK_ON : STATE_BEGIN_GAP; } else { // this is the standard case, iterate to the next state @@ -240,13 +250,13 @@ static void pattern_on_blink_on(pattern_t *pat) static void pattern_on_blink_off(pattern_t *pat) { - (void)pat; // + (void)pat; // unused led_clear(); } static void pattern_begin_gap(pattern_t *pat) { - (void)pat; // + (void)pat; // unused led_clear(); } @@ -296,7 +306,8 @@ uint8_t pattern_equals(const pattern_t *pat, const pattern_t *other) if (memcmp(&pat->m_args, &other->m_args, sizeof(pattern_args_t)) != 0) { return 0; } - // + // if those match then it's effectively the same + // pattern even if anything else is different return 1; } @@ -338,7 +349,8 @@ uint8_t pattern_is_fade(const pattern_t *pat) static void pattern_blend_blink_on(pattern_t *pat) { - // + // if we reached the next color, then cycle the colorset + // like normal and begin playing the next color if (rgb_equals(&pat->m_cur, &pat->m_next)) { pat->m_next = colorset_get_next(&pat->m_colorset); } diff --git a/Helios/Pattern.h b/Helios/Pattern.h index 244f7054..bee17c0f 100644 --- a/Helios/Pattern.h +++ b/Helios/Pattern.h @@ -58,17 +58,20 @@ enum pattern_state struct pattern_t { - // + // ================================== + // Pattern Parameters pattern_args_t m_args; - // + // ================================== + // Pattern Members // any flags the pattern has uint8_t m_patternFlags; // a copy of the colorset that this pattern is initialized with colorset_t m_colorset; - // + // ================================== + // Blink Members uint8_t m_groupCounter; // the state of the current pattern @@ -77,13 +80,15 @@ struct pattern_t // the blink timer used to measure blink timings helios_timer_t m_blinkTimer; - // + // ================================== + // Blend Members // current color and target blend color rgb_color_t m_cur; rgb_color_t m_next; - // + // ================================== + // Fade Members // shifting value to represent current fade uint8_t m_fadeValue; diff --git a/Helios/Random.cpp b/Helios/Random.cpp index 12c7b521..a4c90905 100644 --- a/Helios/Random.cpp +++ b/Helios/Random.cpp @@ -26,7 +26,10 @@ uint16_t random_next16(random_t *rng, uint16_t minValue, uint16_t maxValue) rng->m_seed = (rng->m_seed * 1103515245 + 12345) & 0x7FFFFFFF; uint32_t range = maxValue - minValue; if (range != 0xFFFFFFFF) { - // + // shift the seed 16 bits to the right because the lower 16 bits + // of this LCG are apparently not uniform whatsoever, where as the + // upper 16 bits appear to be quite uniform as per tests. We don't + // really need 32bit random values so we offer max 16bits of entropy return ((rng->m_seed >> 16) % (range + 1)) + minValue; } return (rng->m_seed >> 16); diff --git a/Helios/Storage.cpp b/Helios/Storage.cpp index fa88f57e..c3e0d636 100644 --- a/Helios/Storage.cpp +++ b/Helios/Storage.cpp @@ -136,7 +136,7 @@ void storage_write_brightness(uint8_t brightness) uint8_t storage_crc8(uint8_t pos, uint8_t size) { - uint8_t hash = 33; // + uint8_t hash = 33; // A non-zero initial value uint8_t i; for (i = 0; i < size; ++i) { hash = ((hash << 5) + hash) + storage_read_byte(pos); @@ -171,7 +171,8 @@ static void storage_write_crc(uint8_t pos) static void storage_write_byte(uint8_t address, uint8_t data) { #ifdef HELIOS_EMBEDDED - // + // reads out the byte of the eeprom first to see if it's different + // before writing out the byte -- this is faster than always writing if (storage_read_byte(address) == data) { return; } @@ -182,7 +183,7 @@ static void storage_write_byte(uint8_t address, uint8_t data) storage_internal_write(address, data); // god forbid it doesn't write again } -#else // +#else // HELIOS_CLI if (!m_enableStorage) { return; } @@ -201,7 +202,7 @@ static void storage_write_byte(uint8_t address, uint8_t data) fclose(f); return; } - fclose(f); // + fclose(f); // Close the file #endif } @@ -230,7 +231,7 @@ static uint8_t storage_read_byte(uint8_t address) if (access(STORAGE_FILENAME, O_RDONLY) != 0) { return val; } - FILE *f = fopen(STORAGE_FILENAME, "rb"); // + FILE *f = fopen(STORAGE_FILENAME, "rb"); // Open file for reading in binary mode if (!f) { // this error is ok, just means no storage // perror("Error opening file for read"); @@ -247,7 +248,7 @@ static uint8_t storage_read_byte(uint8_t address) if (!fread(&val, sizeof(uint8_t), 1, f)) { perror("Failed to read byte"); } - fclose(f); // + fclose(f); // Close the file return val; #endif } diff --git a/Helios/Storage.h b/Helios/Storage.h index ca6a1836..55eaa9b1 100644 --- a/Helios/Storage.h +++ b/Helios/Storage.h @@ -8,9 +8,11 @@ extern "C" { #include #include "HeliosConfig.h" -// +// the index of the first config byte, the config bytes start at the end +// then work their way backwards (so 'config index 0' is the last byte) #define CONFIG_START_INDEX (STORAGE_SIZE - 2) -// +// the crc of the config bytes is the very last byte in storage +// TODO: implement the global config CRC again it got removed at some point #define CONFIG_CRC_INDEX (STORAGE_SIZE - 1) // Storage Config Indexes relative to the CONFIG_START_INDEX diff --git a/Helios/TimeControl.cpp b/Helios/TimeControl.cpp index 3ee61ed3..ff33a894 100644 --- a/Helios/TimeControl.cpp +++ b/Helios/TimeControl.cpp @@ -59,7 +59,9 @@ void time_tick_clock(void) } #endif - // + // the rest of this only runs inside vortexlib because on the duo the tick runs in the + // tcb timer callback instead of in a busy loop constantly checking microseconds() + // perform timestep uint32_t elapsed_us; uint32_t us; do { @@ -72,7 +74,11 @@ void time_tick_clock(void) // otherwise calculate regular difference elapsed_us = (uint32_t)(us - m_prevTime); } - // + // if building anywhere except visual studio then we can run alternate sleep code + // because in visual studio + windows it's better to just spin and check the high + // resolution clock instead of trying to sleep for microseconds. + // 1000us per ms, divided by tickrate gives + // the number of microseconds per tick } while (elapsed_us < (1000000 / TICKRATE)); // store current time @@ -87,7 +93,7 @@ uint32_t time_get_current_time(void) #ifdef HELIOS_EMBEDDED volatile uint32_t timer0_overflow_count = 0; ISR(TIMER0_OVF_vect) { - timer0_overflow_count++; // + timer0_overflow_count++; // Increment on each overflow } #endif @@ -102,7 +108,11 @@ uint32_t time_microseconds(void) #ifdef HELIOS_ARDUINO return micros(); #else - // + // The only reason that micros() is actually necessary is if Helios::tick() + // cannot be called in a 1Khz ISR. If Helios::tick() cannot be reliably called + // by an interrupt then Time::tickClock() must perform manual timestep via micros(). + // If Helios::tick() is called by an interrupt then you don't need this function and + // should always just rely on the current tick to perform operations uint8_t oldSREG = SREG; cli(); // multiply by 8 early to avoid floating point math or division @@ -125,36 +135,38 @@ time_delay_microseconds(uint32_t us) // For the ATtiny85 running at 16MHz // The loop takes 3 cycles per iteration - us *= 2; // + us *= 2; // 0.5us per iteration - // - us -= 5; // + // Subtract the overhead of the function call and loop setup + // Assuming approximately 5 cycles overhead + us -= 5; // Simplified subtraction // Assembly loop for delay __asm__ __volatile__( "1: sbiw %0, 1" - "\n\t" // + "\n\t" // 2 cycles "nop" - "\n\t" // - "brne 1b" : "=w"(us) : "0"(us) // + "\n\t" // 1 cycle + "brne 1b" : "=w"(us) : "0"(us) // 2 cycles ); #elif F_CPU >= 8000000L // For the ATtiny85 running at 8MHz // The loop takes 4 cycles per iteration - us <<= 1; // + us <<= 1; // 1us per iteration - // - us -= 6; // + // Subtract the overhead of the function call and loop setup + // Assuming approximately 6 cycles overhead + us -= 6; // Simplified subtraction // Assembly loop for delay __asm__ __volatile__( "1: sbiw %0, 1" - "\n\t" // + "\n\t" // 2 cycles "rjmp .+0" - "\n\t" // - "brne 1b" : "=w"(us) : "0"(us) // + "\n\t" // 2 cycles + "brne 1b" : "=w"(us) : "0"(us) // 2 cycles ); #endif diff --git a/Helios/TimeControl.h b/Helios/TimeControl.h index 6dba610b..587bddb8 100644 --- a/Helios/TimeControl.h +++ b/Helios/TimeControl.h @@ -20,10 +20,15 @@ void time_cleanup(void); // Tick the clock forward to millis() void time_tick_clock(void); -// +// Get the current tick, offset by any active simulation (simulation only exists in vortexlib) +// Exposing this as inline or macro seems to save on space a non negligible amount, it is used a lot +// and exposing in the header probably allows the compiler to optimize away repetitive calls uint32_t time_get_current_time(void); -// +// Current microseconds since startup, only use this for things like measuring rapid data transfer timings. +// If you just need to perform regular time checks for a pattern or some logic then use time_get_current_time() and measure +// time in ticks, use the SEC_TO_TICKS() or MS_TO_TICKS() macros to convert timings to measures of ticks for +// purpose of comparing against time_get_current_time() uint32_t time_microseconds(void); // Delay for some number of microseconds or milliseconds, these are bad diff --git a/Helios/Timer.h b/Helios/Timer.h index 97ac4ae2..f3c2e1f0 100644 --- a/Helios/Timer.h +++ b/Helios/Timer.h @@ -23,7 +23,8 @@ void timer_init_default(helios_timer_t *timer); // Init a timer with a number of alarms and optionally start it void timer_init(helios_timer_t *timer, uint8_t alarm); -// +// Start the timer but don't change current alarm, this shifts +// the timer startTime but does not reset it's alarm state void timer_start(helios_timer_t *timer, uint32_t offset); // Delete all alarms from the timer and reset From fe2094deb6394ab80ca359de292ef0abd24b5287 Mon Sep 17 00:00:00 2001 From: Kurt LaVacque Date: Sat, 18 Oct 2025 11:35:58 +0200 Subject: [PATCH 17/17] Fix missing and empty comments in Patterns.cpp --- Helios/Patterns.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/Helios/Patterns.cpp b/Helios/Patterns.cpp index 2a0cd88c..80399183 100644 --- a/Helios/Patterns.cpp +++ b/Helios/Patterns.cpp @@ -4,8 +4,10 @@ #include "Pattern.h" #include "ColorConstants.h" -// -static const uint32_t color_codes0[] = {RGB_RED, RGB_GREEN, RGB_BLUE}; // +// define arrays of colors, you can reuse these if you have multiple +// modes that use the same colorset -- these demonstrate the max amount +// of colors in each set but you can absolutely list a lesser amount +static const uint32_t color_codes0[] = {RGB_RED, RGB_GREEN, RGB_BLUE}; // Nyx Default // Define Colorset configurations for each slot struct default_colorset_t { @@ -13,9 +15,10 @@ struct default_colorset_t { const uint32_t *cols; }; -// +// the array of colorset entries, make sure the number on the left reflects +// the number of colors in the array on the right static const struct default_colorset_t default_colorsets[] = { - { 3, color_codes0 }, // + { 3, color_codes0 }, // 0 Nyx Default }; void patterns_make_default(uint8_t index, pattern_t *pat) @@ -26,7 +29,7 @@ void patterns_make_default(uint8_t index, pattern_t *pat) pattern_args_t args; pattern_args_init(&args, 0, 0, 0, 0, 0, 0, 0); switch (index) { - case 0: // + case 0: // Nyx Default args.on_dur = 3; args.off_dur = 23; break; @@ -66,7 +69,7 @@ void patterns_make_pattern(enum pattern_id id, pattern_t *pat) case PATTERN_RAZOR: args.on_dur = 3; args.off_dur = 1; - args.gap_dur = 30; // + args.gap_dur = 30; break; case PATTERN_DASH_DOPS: