From 8075f044348634447d7d3187b50b7d75f4790c6c Mon Sep 17 00:00:00 2001 From: ZodiusInfuser Date: Fri, 4 Aug 2023 16:29:00 +0100 Subject: [PATCH] Tidied LED strip class --- .../yukon/modules/led_strip/led_strip.cpp | 162 +++++++++++++ .../yukon/modules/led_strip/led_strip.hpp | 222 +++++------------- 2 files changed, 224 insertions(+), 160 deletions(-) diff --git a/libraries/yukon/modules/led_strip/led_strip.cpp b/libraries/yukon/modules/led_strip/led_strip.cpp index fbc91ead..88ded89d 100644 --- a/libraries/yukon/modules/led_strip/led_strip.cpp +++ b/libraries/yukon/modules/led_strip/led_strip.cpp @@ -11,4 +11,166 @@ namespace pimoroni { return adc_level == ADC_LOW && slow1 == HIGH && slow2 == HIGH && slow3 == HIGH; } + LEDStripModule::LEDStripModule(StripType strip_type, uint num_pixels, float brightness, bool halt_on_not_pgood) : + YukonModule(), + strip_type(strip_type), + num_pixels(num_pixels), + brightness(brightness), + halt_on_not_pgood(halt_on_not_pgood), + last_pgood(false), + ws_pixels(nullptr), + apa_pixels(nullptr), + power_good(nullptr), + power_en(nullptr) { + } + + LEDStripModule::~LEDStripModule() { + if(strip_type == NEOPIXEL) { + if(ws_pixels != nullptr) { + ws_pixels->stop(); + delete(ws_pixels); + } + } + else { + if(apa_pixels != nullptr) { + apa_pixels->stop(); + delete(apa_pixels); + } + } + delete(power_good); + delete(power_en); + } + + std::string LEDStripModule::name() { + if(strip_type == NEOPIXEL) { + return LEDStripModule::NAME + " (NeoPixel)"; + } + else { + return LEDStripModule::NAME + " (DotStar)"; + } + } + + void LEDStripModule::initialise(const SLOT& slot, SlotAccessor& accessor) { + // Create the strip driver object + if(strip_type == NEOPIXEL) { + ws_pixels = new WS2812(num_pixels, pio0, 0, slot.FAST4); + ws_pixels->start(60); + for(auto i = 0u; i < ws_pixels->num_leds; ++i) { + float hue = float(i) / ws_pixels->num_leds; + ws_pixels->set_hsv(i, hue, 1.0f, 1.0f); + } + } + else { + apa_pixels = new APA102(num_pixels, pio0, 0, slot.FAST4, slot.FAST3); + apa_pixels->start(60); + for(auto i = 0u; i < apa_pixels->num_leds; ++i) { + float hue = float(i) / apa_pixels->num_leds; + apa_pixels->set_hsv(i, hue, 1.0f, 1.0f); + } + } + + // Create the power control pin objects + power_good = new IO(slot.FAST1); + power_en = new IO(slot.FAST2); + + // Configure strip and power pins + configure(); + + // Pass the slot and adc functions up to the parent now that module specific initialisation has finished + YukonModule::initialise(slot, accessor); + } + + void LEDStripModule::configure() { + power_en->to_output(false); + power_good->to_input(true, false); + } + + void LEDStripModule::enable() { + if(!is_initialised()) { + throw std::runtime_error("Module not initialised\n"); + } + power_en->value(true); + } + + void LEDStripModule::disable() { + if(!is_initialised()) { + throw std::runtime_error("Module not initialised\n"); + } + power_en->value(false); + } + + bool LEDStripModule::is_enabled() { + if(!is_initialised()) { + throw std::runtime_error("Module not initialised\n"); + } + return power_en->value(); + } + + bool LEDStripModule::read_power_good() { + if(!is_initialised()) { + throw std::runtime_error("Module not initialised\n"); + } + return power_good->value(); + } + + float LEDStripModule::read_temperature() { + return __read_adc2_as_temp(); + } + + void LEDStripModule::monitor() { + bool pgood = read_power_good(); + if(!pgood) { + if(halt_on_not_pgood) { + throw FaultError(__message_header() + "Power is not good! Turning off output\n"); + } + } + + float temperature = read_temperature(); + if(temperature > TEMPERATURE_THRESHOLD) { + throw OverTemperatureError(__message_header() + "Temperature of " + std::to_string(temperature) + "°C exceeded the user set level of " + std::to_string(TEMPERATURE_THRESHOLD) + "°C! Turning off output\n"); + } + + if(last_pgood && !pgood) { + logging.warn(__message_header() + "Power is not good\n"); + } + else if(!last_pgood && pgood) { + logging.warn(__message_header() + "Power is good\n"); + } + + // Run some user action based on the latest readings + //if self.__monitor_action_callback is not None: + // self.__monitor_action_callback(pgood, temperature) + + last_pgood = pgood; + power_good_throughout = power_good_throughout && pgood; + + max_temperature = MAX(temperature, max_temperature); + min_temperature = MIN(temperature, min_temperature); + avg_temperature += temperature; + count_avg += 1; + } + + std::vector> LEDStripModule::get_readings() { + std::vector> values; + values.push_back(std::pair("PGood", power_good_throughout)); + values.push_back(std::pair("T_max", max_temperature)); + values.push_back(std::pair("T_min", min_temperature)); + values.push_back(std::pair("T_avg", avg_temperature)); + return values; + } + + void LEDStripModule::process_readings() { + if(count_avg > 0) { + avg_temperature /= count_avg; + } + } + + void LEDStripModule::clear_readings() { + power_good_throughout = true; + max_temperature = -std::numeric_limits::infinity(); + min_temperature = std::numeric_limits::infinity(); + avg_temperature = 0; + count_avg = 0; + } + } diff --git a/libraries/yukon/modules/led_strip/led_strip.hpp b/libraries/yukon/modules/led_strip/led_strip.hpp index 497a0ba5..edaea219 100644 --- a/libraries/yukon/modules/led_strip/led_strip.hpp +++ b/libraries/yukon/modules/led_strip/led_strip.hpp @@ -13,185 +13,87 @@ using namespace plasma; namespace pimoroni { class LEDStripModule : public YukonModule { + //-------------------------------------------------- + // Constants + //-------------------------------------------------- public: - static const std::string NAME; + static const std::string NAME; // Required by all modules. Set in .cpp + static constexpr float TEMPERATURE_THRESHOLD = 50.0f; - enum strip_type { + + //-------------------------------------------------- + // Enums + //-------------------------------------------------- + public: + enum StripType { NEOPIXEL = 0, DOTSTAR = 1 }; - static constexpr float TEMPERATURE_THRESHOLD = 50.0f; + //-------------------------------------------------- + // Statics + //-------------------------------------------------- static bool is_module(uint adc_level, bool slow1, bool slow2, bool slow3); - - virtual std::string name() { - return LEDStripModule::NAME + " (NeoPixel)"; - } - TYPE_FUNCTION(LEDStripModule) + + //-------------------------------------------------- + // Variables + //-------------------------------------------------- + private: + const StripType strip_type; + const uint num_pixels; + const float brightness; + public: bool halt_on_not_pgood; - bool __last_pgood; - bool __power_good_throughout; - float __max_temperature; - float __min_temperature; - float __avg_temperature; - float __count_avg; + //-------------------------------------------------- + private: + bool last_pgood; + bool power_good_throughout; + float max_temperature; + float min_temperature; + float avg_temperature; + float count_avg; - WS2812* led_strip; - APA102* apa_strip; - IO* __power_good_io; - IO* __power_en_io; + //-------------------------------------------------- + public: + WS2812* ws_pixels; + APA102* apa_pixels; + private: + IO* power_good; + IO* power_en; + //-------------------------------------------------- + // Constructors/Destructor + //-------------------------------------------------- + public: + LEDStripModule(StripType strip_type, uint num_pixels, float brightness = 1.0f, bool halt_on_not_pgood = false); + virtual ~LEDStripModule(); - LEDStripModule(bool halt_on_not_pgood = false) : - YukonModule(), - halt_on_not_pgood(halt_on_not_pgood), - __last_pgood(false), - led_strip(nullptr), - apa_strip(nullptr), - __power_good_io(nullptr), - __power_en_io(nullptr) { //TODO strip_type, num_pixels, brightness=1.0, halt_on_not_pgood=False): - //self.__strip_type = strip_type - //if self.__strip_type == self.NEOPIXEL: - // self.NAME += " (NeoPixel)" - //else: - // self.NAME += " (DotStar)" - //self.__num_pixels = num_pixels - //self.__brightness = brightness - } + //-------------------------------------------------- + // Methods + //-------------------------------------------------- + public: + virtual std::string name(); + virtual void initialise(const SLOT& slot, SlotAccessor& accessor); + virtual void configure(); - ~LEDStripModule() { - delete(led_strip); - delete(apa_strip); - delete(__power_good_io); - delete(__power_en_io); - } + //-------------------------------------------------- + void enable(); + void disable(); + bool is_enabled(); + bool read_power_good() ; + float read_temperature(); - virtual void initialise(const SLOT& slot, SlotAccessor& accessor) { - /* - // Create the strip driver object - if self.__strip_type == self.NEOPIXEL: - from neopixel import NeoPixel - self.pixels = NeoPixel(slot.FAST4, self.__num_pixels, brightness=self.__brightness, auto_write=False) - else: - from adafruit_dotstar import DotStar - self.pixels = DotStar(slot.FAST3, slot.FAST4, self.__num_pixels, brightness=self.__brightness, auto_write=False) - */ - led_strip = new WS2812(60, pio0, 0, slot.FAST4); - led_strip->start(60); - for(auto i = 0u; i < led_strip->num_leds; ++i) { - float hue = float(i) / led_strip->num_leds; - led_strip->set_hsv(i, hue, 1.0f, 1.0f); - } - - // Create the power control pin objects - __power_good_io = new IO(slot.FAST1); - __power_en_io = new IO(slot.FAST2); - - // Configure strip and power pins - configure(); - - // Pass the slot and adc functions up to the parent now that module specific initialisation has finished - YukonModule::initialise(slot, accessor); - } - - virtual void configure() { - __power_en_io->to_output(false); - __power_good_io->to_input(true, false); - } - - void enable() { - if(!is_initialised()) { - throw std::runtime_error("Module not initialised\n"); - } - __power_en_io->value(true); - } - - void disable() { - if(!is_initialised()) { - throw std::runtime_error("Module not initialised\n"); - } - __power_en_io->value(false); - } - - bool is_enabled() { - if(!is_initialised()) { - throw std::runtime_error("Module not initialised\n"); - } - return __power_en_io->value(); - } - - bool read_power_good() { - if(!is_initialised()) { - throw std::runtime_error("Module not initialised\n"); - } - return __power_good_io->value(); - } - - float read_temperature() { - return __read_adc2_as_temp(); - } - - virtual void monitor() { - bool pgood = read_power_good(); - if(!pgood) { - if(halt_on_not_pgood) { - throw FaultError(__message_header() + "Power is not good! Turning off output\n"); - } - } - - float temperature = read_temperature(); - if(temperature > TEMPERATURE_THRESHOLD) { - throw OverTemperatureError(__message_header() + "Temperature of " + std::to_string(temperature) + "°C exceeded the user set level of " + std::to_string(TEMPERATURE_THRESHOLD) + "°C! Turning off output\n"); - } - - if(__last_pgood && !pgood) { - logging.warn(__message_header() + "Power is not good\n"); - } - else if(!__last_pgood && pgood) { - logging.warn(__message_header() + "Power is good\n"); - } - - // Run some user action based on the latest readings - //if self.__monitor_action_callback is not None: - // self.__monitor_action_callback(pgood, temperature) - - __last_pgood = pgood; - __power_good_throughout = __power_good_throughout && pgood; - - __max_temperature = MAX(temperature, __max_temperature); - __min_temperature = MIN(temperature, __min_temperature); - __avg_temperature += temperature; - __count_avg += 1; - } - - virtual std::vector> get_readings() { - std::vector> values; - values.push_back(std::pair("PGood", __power_good_throughout)); - values.push_back(std::pair("T_max", __max_temperature)); - values.push_back(std::pair("T_min", __min_temperature)); - values.push_back(std::pair("T_avg", __avg_temperature)); - return values; - } - - virtual void process_readings() { - if(__count_avg > 0) { - __avg_temperature /= __count_avg; - } - } - - virtual void clear_readings() { - __power_good_throughout = true; - __max_temperature = -std::numeric_limits::infinity(); - __min_temperature = std::numeric_limits::infinity(); - __avg_temperature = 0; - __count_avg = 0; - } + //-------------------------------------------------- + virtual void monitor(); + virtual std::vector> get_readings(); + virtual void process_readings(); + virtual void clear_readings(); }; }