From c5c93d7c22ecc0fb6a7d4aefea5c04b194577f46 Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Mon, 3 Feb 2020 22:15:08 +0100 Subject: [PATCH 1/3] add optional support for WS2812 RGB LED, fixes #106 specific indexes in the LED color time sequence are used for: - dark separator indicates "start of sequence" (also used for LED init and re-init) - color according to indications (3bits encoded via RGB color) (can be extended to show up to 32 indication bits) (dark if there is nothing to indicate) - white separator indicates "start of radiation display" (also works as LED test, white = R on + G on + B on) - color according to radiation (repeated, displayed most of the time) dark (unusually low / 0) green (normal) yellow (more than normal) red (much more than normal) --- multigeiger/multigeiger.ino | 4 ++ multigeiger/status_led.cpp | 107 ++++++++++++++++++++++++++++++ multigeiger/status_led.h | 15 +++++ multigeiger/userdefines-example.h | 3 + platformio-example.ini | 1 + 5 files changed, 130 insertions(+) create mode 100644 multigeiger/status_led.cpp create mode 100644 multigeiger/status_led.h diff --git a/multigeiger/multigeiger.ino b/multigeiger/multigeiger.ino index 4de753b6..1c0787cc 100644 --- a/multigeiger/multigeiger.ino +++ b/multigeiger/multigeiger.ino @@ -18,6 +18,7 @@ #include "ble.h" #include "chkhardware.h" #include "clock.h" +#include "status_led.h" // Measurement interval (default 2.5min) [sec] #define MEASUREMENT_INTERVAL 150 @@ -138,6 +139,9 @@ void publish(unsigned long current_ms, unsigned long current_counts, unsigned lo float Count_Rate = (dt != 0) ? (float)counts * 1000.0 / (float)dt : 0.0; float Dose_Rate = Count_Rate * GMC_factor_uSvph; + // indicate status on RGB LED (if any) + indicate(Dose_Rate, I_TEST); + // calculate the count rate and dose rate over the complete time from start accumulated_Count_Rate = (accumulated_time != 0) ? (float)accumulated_GMC_counts * 1000.0 / (float)accumulated_time : 0.0; accumulated_Dose_Rate = accumulated_Count_Rate * GMC_factor_uSvph; diff --git a/multigeiger/status_led.cpp b/multigeiger/status_led.cpp new file mode 100644 index 00000000..2f6be01c --- /dev/null +++ b/multigeiger/status_led.cpp @@ -0,0 +1,107 @@ +// show status indication via WS2812 RGB LED + +#include "userdefines.h" + +#if STATUS_LED==1 // we have a WS2812 RGB LED! + +#include + +#include "status_led.h" + +#define PIXEL_COUNT 1 +#define PIXEL_PIN 25 + +RgbColor red(255, 0, 0); +RgbColor green(0, 255, 0); +RgbColor blue(0, 0, 255); +RgbColor yellow(255, 255, 0); +RgbColor white(255, 255, 255); +RgbColor black(0, 0, 0); + +static NeoPixelBus LEDs(PIXEL_COUNT, PIXEL_PIN); + +static RgbColor last_col = black; + +static void set_LED(RgbColor col) { + if (col == last_col) + return; // nothing to change + + LEDs.SetPixelColor(0, col); // only 1 LED at index 0 + LEDs.Show(); + last_col = col; +} + +static void init_LED(void) { + LEDs.Begin(); // all LEDs off + LEDs.Show(); + last_col = black; // consistency sw state == hw state +} + +static void compute_color(unsigned int indication, + unsigned int mask_r, unsigned int mask_g, unsigned int mask_b, + RgbColor *color) { + // assign to *color depending on whether the r/g/b masked bits are set in the indication value + *color = RgbColor((indication & mask_r) ? 255 : 0, + (indication & mask_g) ? 255 : 0, + (indication & mask_b) ? 255 : 0); +} + +#define IDX_W 2 +#define CSL 30 + +void indicate(float radiation, unsigned int indication) { + // radiation [uSv/h] given to set the primary color R that is shown most of the time + // indication: 32 bit flags to indicate additional stuff, see status_led.h. + // + // this code will generate a time sequence of LED colors: + // index color + // ------------------------------------------------------ + // 0 dark (LED init) + // 1 indication color 1 + // ... reserved for more indications + // IDX_W white (LED test) + // ...+1 radiation color + // ... radiation color + // CSL-1 radiation color + + RgbColor col; + static int index = 0; // index counting modulo COLOR_SEQUENCE_LENGTH + + switch (index) { + case 0: // show a fixed dark separator after LED init + init_LED(); // (re-)init the LED + col = black; + break; + case 1: + // indication color 1: R G B + compute_color(indication, I_CONN_ERROR, I_TEST, I_HV_ERROR, &col); + break; + case IDX_W: // show a fixed white separator and LED test + col = white; + break; + default: // show radiation color + if (radiation > 1.0) { + col = red; + } else if (radiation > 0.2) { + col = yellow; + } else if (radiation > 0.01) { + col = green; + } else { + col = black; + } + } + + set_LED(col); + + if (++index == CSL) + index = 0; +} + +#else // no STATUS_LED + +void indicate(float radiation, unsigned int indication) { + // do nothing +} + +#endif // STATUS_LED + diff --git a/multigeiger/status_led.h b/multigeiger/status_led.h new file mode 100644 index 00000000..2a23f8bf --- /dev/null +++ b/multigeiger/status_led.h @@ -0,0 +1,15 @@ +// show status indication via WS2812 RGB LED + +// indication value used to reset indications to "all off" +#define I_RESET 0 +// indication value used to mask no bit, e.g. in compute_color +#define I_NONE 0 + +// indications, values are 32bit bit masks, valid values are 2^N +#define I_TEST 1 // reserved to test the indication code +#define I_HV_ERROR 2 // there is a problem with high voltage generation +#define I_CONN_ERROR 4 // there is a problem with the network connection + +// indicate radiation and special indications via a color time sequence. +// you should call this in regular time intervals [e.g. 1s]. +void indicate(float radiation, unsigned int indication); diff --git a/multigeiger/userdefines-example.h b/multigeiger/userdefines-example.h index fb9a0d7c..a71df84a 100644 --- a/multigeiger/userdefines-example.h +++ b/multigeiger/userdefines-example.h @@ -63,3 +63,6 @@ // 0x2A38: Heart Rate Sensor Position --> sends TUBE_TYPE // 0x2A39: Heart Rate Control Point --> allows to reset "energy expenditure", as required by service definition #define SEND2BLE false + +// 0: no RGB status LED, 1: WS2812B status LED +#define STATUS_LED 1 diff --git a/platformio-example.ini b/platformio-example.ini index d7e59631..9d087048 100644 --- a/platformio-example.ini +++ b/platformio-example.ini @@ -31,3 +31,4 @@ lib_deps= IotWebConf MCCI LoRaWAN LMIC library h2zero/NimBLE-Arduino + NeoPixelBus@>=2.6.0,!=2.6.2,<3.0.0 From 959c7e7829090762232fcddd182b2cd4704260ca Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Thu, 13 May 2021 17:35:42 +0200 Subject: [PATCH 2/3] remove userdefines.h based LED configuration needs to be done by iotwebconf config item. --- multigeiger/status_led.cpp | 11 ----------- multigeiger/userdefines-example.h | 3 --- 2 files changed, 14 deletions(-) diff --git a/multigeiger/status_led.cpp b/multigeiger/status_led.cpp index 2f6be01c..9507d427 100644 --- a/multigeiger/status_led.cpp +++ b/multigeiger/status_led.cpp @@ -2,8 +2,6 @@ #include "userdefines.h" -#if STATUS_LED==1 // we have a WS2812 RGB LED! - #include #include "status_led.h" @@ -96,12 +94,3 @@ void indicate(float radiation, unsigned int indication) { if (++index == CSL) index = 0; } - -#else // no STATUS_LED - -void indicate(float radiation, unsigned int indication) { - // do nothing -} - -#endif // STATUS_LED - diff --git a/multigeiger/userdefines-example.h b/multigeiger/userdefines-example.h index a71df84a..fb9a0d7c 100644 --- a/multigeiger/userdefines-example.h +++ b/multigeiger/userdefines-example.h @@ -63,6 +63,3 @@ // 0x2A38: Heart Rate Sensor Position --> sends TUBE_TYPE // 0x2A39: Heart Rate Control Point --> allows to reset "energy expenditure", as required by service definition #define SEND2BLE false - -// 0: no RGB status LED, 1: WS2812B status LED -#define STATUS_LED 1 From cb239038631900ae9d34648bdcfbbb532e694f7e Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Thu, 13 May 2021 19:43:40 +0200 Subject: [PATCH 3/3] init WS2812 LED from main setup(), more logging --- multigeiger/multigeiger.ino | 1 + multigeiger/status_led.cpp | 8 +++++--- multigeiger/status_led.h | 2 ++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/multigeiger/multigeiger.ino b/multigeiger/multigeiger.ino index 1c0787cc..b55f5a38 100644 --- a/multigeiger/multigeiger.ino +++ b/multigeiger/multigeiger.ino @@ -43,6 +43,7 @@ static Switches switches; void setup() { bool isLoraBoard = init_hwtest(); setup_log(DEFAULT_LOG_LEVEL); + setup_status_LED(); setup_display(isLoraBoard); setup_switches(isLoraBoard); switches = read_switches(); // only read DIP switches once at boot time diff --git a/multigeiger/status_led.cpp b/multigeiger/status_led.cpp index 9507d427..892756cd 100644 --- a/multigeiger/status_led.cpp +++ b/multigeiger/status_led.cpp @@ -4,6 +4,7 @@ #include +#include "log.h" #include "status_led.h" #define PIXEL_COUNT 1 @@ -18,7 +19,7 @@ RgbColor black(0, 0, 0); static NeoPixelBus LEDs(PIXEL_COUNT, PIXEL_PIN); -static RgbColor last_col = black; +static RgbColor last_col; static void set_LED(RgbColor col) { if (col == last_col) @@ -29,7 +30,7 @@ static void set_LED(RgbColor col) { last_col = col; } -static void init_LED(void) { +void setup_status_LED(void) { LEDs.Begin(); // all LEDs off LEDs.Show(); last_col = black; // consistency sw state == hw state @@ -65,9 +66,10 @@ void indicate(float radiation, unsigned int indication) { RgbColor col; static int index = 0; // index counting modulo COLOR_SEQUENCE_LENGTH + log(INFO, "LED index: %d, radiation: %f", index, radiation); + switch (index) { case 0: // show a fixed dark separator after LED init - init_LED(); // (re-)init the LED col = black; break; case 1: diff --git a/multigeiger/status_led.h b/multigeiger/status_led.h index 2a23f8bf..22d6eb5a 100644 --- a/multigeiger/status_led.h +++ b/multigeiger/status_led.h @@ -13,3 +13,5 @@ // indicate radiation and special indications via a color time sequence. // you should call this in regular time intervals [e.g. 1s]. void indicate(float radiation, unsigned int indication); + +void setup_status_LED(void);