aboutsummaryrefslogtreecommitdiff
path: root/power
diff options
context:
space:
mode:
Diffstat (limited to 'power')
-rw-r--r--power/Makefile22
-rw-r--r--power/application.c267
2 files changed, 289 insertions, 0 deletions
diff --git a/power/Makefile b/power/Makefile
new file mode 100644
index 0000000..a86d630
--- /dev/null
+++ b/power/Makefile
@@ -0,0 +1,22 @@
+APP_DIR ?= .
+SDK_DIR ?= ../sdk
+VERSION ?= vdev
+
+CFLAGS += -D'VERSION="${VERSION}"'
+
+Q ?= @
+
+-include $(SDK_DIR)/Makefile.mk
+
+.PHONY: all
+all: debug
+
+.PHONY: sdk
+sdk: ../sdk/Makefile.mk
+
+.PHONY: update
+update: sdk
+ @echo "Updating Git submodule 'sdk'..."; git submodule update --remote --merge sdk
+
+../sdk/Makefile.mk:
+ $(Q) git submodule update --init ../sdk
diff --git a/power/application.c b/power/application.c
new file mode 100644
index 0000000..61fe126
--- /dev/null
+++ b/power/application.c
@@ -0,0 +1,267 @@
+#include <bcl.h>
+
+#define LED_STRIP_COUNT 300
+#define LED_STRIP_TYPE BC_LED_STRIP_TYPE_RGB
+
+#define TEMPERATURE_PUB_NO_CHANGE_INTEVAL (15 * 60 * 1000)
+#define TEMPERATURE_PUB_VALUE_CHANGE 0.2f
+#define TEMPERATURE_UPDATE_INTERVAL (1 * 1000)
+
+typedef struct {
+ uint8_t channel;
+ float value;
+ bc_tick_t next_pub;
+} event_param_t;
+
+// LED instance
+bc_led_t led;
+bool led_state = false;
+
+// Button instance
+bc_button_t button;
+
+// Temperature instance
+bc_tag_temperature_t temperature;
+event_param_t temperature_event_param = { .next_pub = 0 };
+
+// Led strip
+static uint32_t _bc_module_power_led_strip_dma_buffer[LED_STRIP_COUNT * LED_STRIP_TYPE * 2];
+const bc_led_strip_buffer_t led_strip_buffer = {
+ .type = LED_STRIP_TYPE,
+ .count = LED_STRIP_COUNT,
+ .buffer = _bc_module_power_led_strip_dma_buffer
+};
+
+static struct {
+ enum {
+ LED_STRIP_SHOW_COLOR = 0,
+ LED_STRIP_SHOW_COMPOUND = 1,
+ LED_STRIP_SHOW_EFFECT = 2,
+ LED_STRIP_SHOW_THERMOMETER = 3
+
+ } show;
+ bc_led_strip_t self;
+ uint32_t color;
+ struct {
+ uint8_t data[BC_RADIO_NODE_MAX_COMPOUND_BUFFER_SIZE];
+ int length;
+ } compound;
+ struct {
+ float temperature;
+ int8_t min;
+ int8_t max;
+ uint8_t white_dots;
+ float set_point;
+ uint32_t color;
+
+ } thermometer;
+
+ bc_scheduler_task_id_t update_task_id;
+
+} led_strip = { .show = LED_STRIP_SHOW_COLOR, .color = 0 };
+
+void button_event_handler(bc_button_t *self, bc_button_event_t event, void *event_param) {
+ (void) self;
+ (void) event_param;
+
+ if (event == BC_BUTTON_EVENT_PRESS)
+ {
+ bc_led_pulse(&led, 100);
+ }
+}
+
+void temperature_tag_event_handler(bc_tag_temperature_t *self, bc_tag_temperature_event_t event, void *event_param) {
+ float value;
+ event_param_t *param = (event_param_t *)event_param;
+
+ if (event == BC_TAG_TEMPERATURE_EVENT_UPDATE) {
+ if (bc_tag_temperature_get_temperature_celsius(self, &value)) {
+ if ((fabs(value - param->value) >= TEMPERATURE_PUB_VALUE_CHANGE) || (param->next_pub < bc_scheduler_get_spin_tick())) {
+ bc_radio_pub_temperature(param->channel, &value);
+
+ param->value = value;
+ param->next_pub = bc_scheduler_get_spin_tick() + TEMPERATURE_PUB_NO_CHANGE_INTEVAL;
+ }
+ }
+ }
+}
+
+void bc_radio_node_on_state_get(uint64_t *id, uint8_t state_id) {
+ (void) id;
+
+ if (state_id == BC_RADIO_NODE_STATE_POWER_MODULE_RELAY) {
+ bool state = bc_module_power_relay_get_state();
+ bc_radio_pub_state(BC_RADIO_PUB_STATE_POWER_MODULE_RELAY, &state);
+ } else if (state_id == BC_RADIO_NODE_STATE_LED) {
+ bc_radio_pub_state(BC_RADIO_PUB_STATE_LED, &led_state);
+ }
+}
+
+void bc_radio_node_on_state_set(uint64_t *id, uint8_t state_id, bool *state) {
+ (void) id;
+
+ if (state_id == BC_RADIO_NODE_STATE_POWER_MODULE_RELAY) {
+ bc_module_power_relay_set_state(*state);
+
+ bc_radio_pub_state(BC_RADIO_PUB_STATE_POWER_MODULE_RELAY, state);
+ } else if (state_id == BC_RADIO_NODE_STATE_LED) {
+ led_state = *state;
+ bc_led_set_mode(&led, led_state ? BC_LED_MODE_ON : BC_LED_MODE_OFF);
+ bc_radio_pub_state(BC_RADIO_PUB_STATE_LED, &led_state);
+ }
+}
+
+void led_strip_update_task(void *param) {
+ (void) param;
+
+ if (!bc_led_strip_is_ready(&led_strip.self)) {
+ bc_scheduler_plan_current_now();
+ return;
+ }
+
+ bc_led_strip_write(&led_strip.self);
+ bc_scheduler_plan_current_relative(250);
+}
+
+void led_strip_fill(void) {
+ if (led_strip.show == LED_STRIP_SHOW_COLOR) {
+ bc_led_strip_fill(&led_strip.self, led_strip.color);
+ } else if (led_strip.show == LED_STRIP_SHOW_COMPOUND) {
+ int from = 0;
+ int to;
+ uint8_t *color;
+
+ for (int i = 0; i < led_strip.compound.length; i += 5) {
+ color = led_strip.compound.data + i + 1;
+ to = from + led_strip.compound.data[i];
+
+ for (;(from < to) && (from < LED_STRIP_COUNT); from++) {
+ bc_led_strip_set_pixel_rgbw(&led_strip.self, from, color[3], color[2], color[1], color[0]);
+ }
+
+ from = to;
+ }
+ } else if (led_strip.show == LED_STRIP_SHOW_THERMOMETER) {
+ bc_led_strip_thermometer(&led_strip.self, led_strip.thermometer.temperature, led_strip.thermometer.min, led_strip.thermometer.max, led_strip.thermometer.white_dots, led_strip.thermometer.set_point, led_strip.thermometer.color);
+ }
+}
+
+void bc_radio_node_on_led_strip_color_set(uint64_t *id, uint32_t *color) {
+ (void) id;
+
+ bc_led_strip_effect_stop(&led_strip.self);
+ led_strip.color = *color;
+ led_strip.show = LED_STRIP_SHOW_COLOR;
+ led_strip_fill();
+ bc_scheduler_plan_now(led_strip.update_task_id);
+}
+
+void bc_radio_node_on_led_strip_brightness_set(uint64_t *id, uint8_t *brightness) {
+ (void) id;
+
+ bc_led_strip_set_brightness(&led_strip.self, *brightness);
+ led_strip_fill();
+ bc_scheduler_plan_now(led_strip.update_task_id);
+}
+
+void bc_radio_node_on_led_strip_compound_set(uint64_t *id, uint8_t *compound, size_t length) {
+ (void) id;
+
+ bc_led_strip_effect_stop(&led_strip.self);
+ memcpy(led_strip.compound.data, compound, length);
+ led_strip.compound.length = length;
+ led_strip.show = LED_STRIP_SHOW_COMPOUND;
+ led_strip_fill();
+ bc_scheduler_plan_now(led_strip.update_task_id);
+}
+
+void bc_radio_node_on_led_strip_effect_set(uint64_t *id, bc_radio_node_led_strip_effect_t type, uint16_t wait, uint32_t *color) {
+ (void) id;
+
+ switch (type) {
+ case BC_RADIO_NODE_LED_STRIP_EFFECT_TEST:
+ bc_led_strip_effect_test(&led_strip.self);
+ break;
+ case BC_RADIO_NODE_LED_STRIP_EFFECT_RAINBOW:
+ bc_led_strip_effect_rainbow(&led_strip.self, wait);
+ break;
+ case BC_RADIO_NODE_LED_STRIP_EFFECT_RAINBOW_CYCLE:
+ bc_led_strip_effect_rainbow_cycle(&led_strip.self, wait);
+ break;
+ case BC_RADIO_NODE_LED_STRIP_EFFECT_THEATER_CHASE_RAINBOW:
+ bc_led_strip_effect_theater_chase_rainbow(&led_strip.self, wait);
+ break;
+ case BC_RADIO_NODE_LED_STRIP_EFFECT_COLOR_WIPE:
+ bc_led_strip_effect_color_wipe(&led_strip.self, *color, wait);
+ break;
+ case BC_RADIO_NODE_LED_STRIP_EFFECT_THEATER_CHASE:
+ bc_led_strip_effect_theater_chase(&led_strip.self, *color, wait);
+ break;
+ case BC_RADIO_NODE_LED_STRIP_EFFECT_STROBOSCOPE:
+ bc_led_strip_effect_stroboscope(&led_strip.self, *color, wait);
+ break;
+ case BC_RADIO_NODE_LED_STRIP_EFFECT_ICICLE:
+ bc_led_strip_effect_icicle(&led_strip.self, *color, wait);
+ break;
+ case BC_RADIO_NODE_LED_STRIP_EFFECT_PULSE_COLOR:
+ bc_led_strip_effect_pulse_color(&led_strip.self, *color, wait);
+ break;
+ default:
+ return;
+ }
+ led_strip.show = LED_STRIP_SHOW_EFFECT;
+}
+
+void bc_radio_node_on_led_strip_thermometer_set(uint64_t *id, float *temperature, int8_t *min, int8_t *max, uint8_t *white_dots, float *set_point, uint32_t *set_point_color) {
+ (void) id;
+
+ bc_led_strip_effect_stop(&led_strip.self);
+
+ led_strip.thermometer.temperature = *temperature;
+ led_strip.thermometer.min = *min;
+ led_strip.thermometer.max = *max;
+ led_strip.thermometer.white_dots = *white_dots;
+
+ if (set_point != NULL) {
+ led_strip.thermometer.set_point = *set_point;
+ led_strip.thermometer.color = *set_point_color;
+ } else {
+ led_strip.thermometer.set_point = *min - 1;
+ }
+
+ led_strip.show = LED_STRIP_SHOW_THERMOMETER;
+ led_strip_fill();
+
+ bc_scheduler_plan_now(led_strip.update_task_id);
+}
+
+void application_init(void) {
+ // Initialize LED
+ bc_led_init(&led, BC_GPIO_LED, false, false);
+ bc_led_set_mode(&led, BC_LED_MODE_OFF);
+
+ bc_radio_init(BC_RADIO_MODE_NODE_LISTENING);
+
+ // Initialize button
+ bc_button_init(&button, BC_GPIO_BUTTON, BC_GPIO_PULL_DOWN, false);
+ bc_button_set_scan_interval(&button, 20);
+ bc_button_set_event_handler(&button, button_event_handler, NULL);
+
+ // Initialize temperature
+ temperature_event_param.channel = BC_RADIO_PUB_CHANNEL_R1_I2C0_ADDRESS_ALTERNATE;
+ bc_tag_temperature_init(&temperature, BC_I2C_I2C0, BC_TAG_TEMPERATURE_I2C_ADDRESS_ALTERNATE);
+ bc_tag_temperature_set_update_interval(&temperature, TEMPERATURE_UPDATE_INTERVAL);
+ bc_tag_temperature_set_event_handler(&temperature, temperature_tag_event_handler, &temperature_event_param);
+
+ // Initialize power module
+ bc_module_power_init();
+
+ // Initialize led-strip on power module
+ bc_led_strip_init(&led_strip.self, bc_module_power_get_led_strip_driver(), &led_strip_buffer);
+
+ led_strip.update_task_id = bc_scheduler_register(led_strip_update_task, NULL, 0);
+
+ bc_radio_pairing_request("power-controller", VERSION);
+
+ bc_led_pulse(&led, 2000);
+}