diff --git a/.vscode/settings.json b/.vscode/settings.json index 0ecacf6..5bb08ba 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -7,6 +7,12 @@ "log.h": "c", "mlx90614.h": "c", "sensor.h": "c", - "sht4x.h": "c" - } + "sht4x.h": "c", + "array": "c", + "string_view": "c", + "initializer_list": "c", + "stm32-pinctrl-common.h": "c", + "printk.h": "c" + }, + "cmake.sourceDirectory": "C:/Users/xlemmingx/Documents/PlatformIO/Projects/embedded_raumsenor_lorawan/zephyr" } \ No newline at end of file diff --git a/src/gpio.c b/src/gpio.c new file mode 100644 index 0000000..c67f762 --- /dev/null +++ b/src/gpio.c @@ -0,0 +1,50 @@ +#include + +#include +#include +#include + +LOG_MODULE_REGISTER(gpio_relais); + +#if !DT_NODE_EXISTS(DT_NODELABEL(load_switch)) +#error "Overlay for power output node not properly defined." +#endif + +static const struct gpio_dt_spec load_switch = + GPIO_DT_SPEC_GET_OR(DT_NODELABEL(load_switch), gpios, {0}); + +void init_gpio() +{ + int err; + + if (!gpio_is_ready_dt(&load_switch)) + { + LOG_ERR("The load switch pin GPIO port is not ready.\n"); + return 0; + } + + LOG_INF("Initializing pin with inactive level.\n"); + + err = gpio_pin_configure_dt(&load_switch, GPIO_OUTPUT_INACTIVE); + if (err != 0) + { + LOG_ERR("Configuring GPIO pin failed: %d\n", err); + return 0; + } + /* Make sure relais is switched off */ + set_relais_state(false); +} + +void set_relais_state(bool state) +{ + int err = gpio_pin_set_dt(&load_switch, state); + if (err != 0) + { + LOG_ERR("Setting GPIO pin level failed: %d\n", err); + } +} + +uint8_t get_relais_state() +{ + return (uint8_t)gpio_pin_get_dt(&load_switch); +} \ No newline at end of file diff --git a/src/gpio.h b/src/gpio.h new file mode 100644 index 0000000..af4e732 --- /dev/null +++ b/src/gpio.h @@ -0,0 +1,7 @@ +#include + +void init_gpio(); + +void set_relais_state(bool state); + +uint8_t get_relais_state(); \ No newline at end of file diff --git a/src/lora/lorawan.c b/src/lora/lorawan.c index 0c34025..6e3253f 100644 --- a/src/lora/lorawan.c +++ b/src/lora/lorawan.c @@ -1,39 +1,52 @@ -#include -#include #include +#include +#include +#include +#include #include +#include -/* - TODO: - - DEV NONCE in non volatile memory and increase - - format packets - - send: check if still in network - - downlink callback +#define SETTINGS_KEY "LORAWAN_DEV_NONCE" +LOG_MODULE_REGISTER(lorawan_class_a); - // Build payload byte array - uint8_t uplinkPayload[6]; - uplinkPayload[0] = uint8_t (int(temp_room_mlx)); - uplinkPayload[1] = uint8_t (int((temp_room_mlx-int(temp_room_mlx)*100))); // See notes for high/lowByte functions - uplinkPayload[2] = uint8_t (int(temp_floor)); - uplinkPayload[3] = uint8_t (int((temp_floor-int(temp_floor)*100))); // See notes for high/lowByte functions - uplinkPayload[4] = uint8_t (int(humidity)); - uplinkPayload[5] = uint8_t (relaisstate); // See notes for high/lowByte functions -*/ +extern bool relais_state; +const static struct device *lora_dev; +static struct lorawan_join_config join_cfg; +static uint8_t app_key[] = LORAWAN_APP_KEY; -const struct device *lora_dev; -struct lorawan_join_config join_cfg; -uint8_t dev_eui[] = LORAWAN_DEV_EUI; -uint8_t join_eui[] = LORAWAN_JOIN_EUI; -uint8_t app_key[] = LORAWAN_APP_KEY; +static void dl_callback(uint8_t port, uint8_t flags, int16_t rssi, int8_t snr, uint8_t len, + const uint8_t *hex_data) +{ + LOG_INF("Port %d, Pending %d, RSSI %ddB, SNR %ddBm, Len: %d, Time %d", port, + flags & LORAWAN_DATA_PENDING, rssi, snr, len, !!(flags & LORAWAN_TIME_UPDATED)); + if (hex_data) + { + LOG_HEXDUMP_INF(hex_data, len, "Payload: "); + } -void init_lorawan() { - int ret; + /* Could be moved in a separate thread so we only have to set the variable here */ + if (len > 3 && hex_data[0] == 'r' && hex_data[1] == '1') + { + uint8_t relais_value = hex_data[3]; + LOG_INF("Received relais1 state change: %d", relais_value); + if (get_relais_state() != relais_value) + { + set_relais_state(relais_value); + LOG_INF("Set relais 1 value"); + } + relais_state = relais_value; + } +} - struct lorawan_downlink_cb downlink_cb = { - .port = LW_RECV_PORT_ANY, - .cb = dl_callback}; +struct lorawan_downlink_cb downlink_cb = { + .port = LW_RECV_PORT_ANY, + .cb = dl_callback}; + +void init_lorawan() +{ + int err; lora_dev = DEVICE_DT_GET(DT_ALIAS(lora0)); if (!device_is_ready(lora_dev)) @@ -42,10 +55,10 @@ void init_lorawan() { return 0; } - ret = lorawan_start(); - if (ret < 0) + err = lorawan_start(); + if (err < 0) { - LOG_ERR("lorawan_start failed: %d", ret); + LOG_ERR("lorawan_start failed: %d", err); return 0; } else @@ -54,70 +67,66 @@ void init_lorawan() { } lorawan_register_downlink_callback(&downlink_cb); - lorawan_register_dr_changed_callback(lorwan_datarate_changed); join_cfg.mode = LORAWAN_ACT_OTAA; - join_cfg.dev_eui = dev_eui; - join_cfg.otaa.join_eui = join_eui; join_cfg.otaa.app_key = app_key; - join_cfg.otaa.nwk_key = app_key; - join_cfg.otaa.dev_nonce = 14u; // TODO + join_cfg.otaa.dev_nonce = sys_rand16_get(); } -void join_network_otaa() { - int8_t status = -1; - while (lorawan_join(&join_cfg) < 0) { +void join_network_otaa() +{ + int8_t ret = -1; + while (lorawan_join(&join_cfg) < 0) + { LOG_ERR("lorawan_join_network failed: %d, retrying..", ret); + // use another dev nonce + join_cfg.otaa.dev_nonce = sys_rand16_get(); k_sleep(K_MSEC(5000)); } - LOG_INF("Joining network over OTAA"); + LOG_INF("Succesfully joined network over OTAA"); } -void send_data_packet(char *data) { +void send_data_packet(char *data, uint8_t data_len) +{ LOG_INF("Sending data..."); while (1) { - int8_t ret = lorawan_send(LORAWAN_PORT, data, sizeof(data), LORAWAN_MSG_CONFIRMED); + int8_t ret = lorawan_send(LORAWAN_PORT, (uint8_t *)data, data_len, LORAWAN_MSG_UNCONFIRMED); if (ret == -EAGAIN) { LOG_ERR("lorawan_send failed: %d. Continuing...", ret); - k_sleep(DELAY); + k_sleep(RETRY_DELAY); continue; } - - if (ret < 0) + else if (ret < 0) { LOG_ERR("lorawan_send failed: %d", ret); - k_sleep(DELAY); - continue; + k_sleep(RETRY_DELAY); + break; } else { LOG_INF("Data sent!"); + break; } - k_sleep(DELAY); + k_sleep(RETRY_DELAY); } } - - -static void dl_callback(uint8_t port, uint8_t flags, int16_t rssi, int8_t snr, uint8_t len, - const uint8_t *hex_data) +void create_data_package(char *buffer, float temp_room_mlx, float temp_floor, float humidity, uint8_t relais_state) { - LOG_INF("Port %d, Pending %d, RSSI %ddB, SNR %ddBm, Time %d", port, - flags & LORAWAN_DATA_PENDING, rssi, snr, !!(flags & LORAWAN_TIME_UPDATED)); - if (hex_data) - { - LOG_HEXDUMP_INF(hex_data, len, "Payload: "); - } -} + int16_t temp = (int16_t)(temp_room_mlx * 100); + int16_t floor_temp = (int16_t)(temp_floor * 100); + int16_t hum = (int16_t)(humidity * 100); -static void lorwan_datarate_changed(enum lorawan_datarate dr) -{ - uint8_t unused, max_size; - - lorawan_get_payload_sizes(&unused, &max_size); - LOG_INF("New Datarate: DR_%d, Max Payload %d", dr, max_size); + // Packen der Daten in das Byte-Array + buffer[0] = (temp >> 8) & 0xFF; + buffer[1] = temp & 0xFF; + buffer[2] = (floor_temp >> 8) & 0xFF; + buffer[3] = floor_temp & 0xFF; + buffer[4] = (hum >> 8) & 0xFF; + buffer[5] = hum & 0xFF; + buffer[6] = relais_state; } \ No newline at end of file diff --git a/src/lora/lorawan.h b/src/lora/lorawan.h index d0ec396..57ead51 100644 --- a/src/lora/lorawan.h +++ b/src/lora/lorawan.h @@ -1,23 +1,20 @@ #include #include - #define LORAWAN_PORT 2 /* Customize based on network configuration */ -#define LORAWAN_DEV_EUI { 0x2D, 0xBF, 0xF6, 0xC2, 0xA1, 0x20,\ - 0x01, 0x4A } -#define LORAWAN_JOIN_EUI { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ - 0x00, 0x00 } -/* #define LORAWAN_APP_KEY { 0x71, 0x5A, 0x39, 0xB2, 0x86, 0xC3,\ - 0x37, 0xA3, 0xC4, 0xF0, 0x78, 0xF9,\ - 0x0F, 0x33, 0x07, 0x7D } */ -#define LORAWAN_APP_KEY { 0x71, 0x5A, 0x39, 0xB2, 0x86, 0xC3,\ - 0x37, 0xA3, 0xC4, 0xF0, 0x78, 0xF9,\ - 0x0F, 0x33, 0x07, 0x7D } +#define LORAWAN_APP_KEY {0x71, 0x5A, 0x39, 0xB2, 0x86, 0xC3, \ + 0x37, 0xA3, 0xC4, 0xF0, 0x78, 0xF9, \ + 0x0F, 0x33, 0x07, 0x7D} - -static void dl_callback(uint8_t port, uint8_t flags, int16_t rssi, int8_t snr, uint8_t len, - const uint8_t *hex_data); +#define RETRY_DELAY K_MSEC(1000) +#define SEND_INTERVALL K_SECONDS(20) -static void lorwan_datarate_changed(enum lorawan_datarate dr); \ No newline at end of file +void init_lorawan(); + +void join_network_otaa(); + +void send_data_packet(char *data, uint8_t data_len); + +void create_data_package(char *package, float temp_room_mlx, float temp_floor, float humidity, uint8_t relais_state); \ No newline at end of file diff --git a/src/main.c b/src/main.c index 8679d24..d91ba06 100644 --- a/src/main.c +++ b/src/main.c @@ -2,28 +2,54 @@ #include #include #include -#include -#include -#include +#include #include +#include #include #include #include +#include +LOG_MODULE_REGISTER(g2h_heat_main); - -#define DELAY K_MSEC(10000) -#define LOG_LEVEL CONFIG_LOG_DEFAULT_LEVEL - - -LOG_MODULE_REGISTER(lorawan_class_a); - - +volatile bool relais_state = false; /* MAIN */ int main(void) { + /* Initialization */ + init_gpio(); + init_mlx90614(); + init_sht4x(); + init_lorawan(); + join_network_otaa(); + float humidity, temp, floor_temp; + + while (true) + { + /* Get values from SHT4X */ + request_sensor_data_sht4x(); + humidity = get_value_from_current_sample_sht4x(SENSOR_CHAN_HUMIDITY); + printk("hum: %.2f%%\n", humidity); + + /* Get values from MLX90614 */ + request_sensor_data_mlx90614(MLX90614_INTERNAL_TEMP_ADDR); + temp = get_temp_from_raw_data_mlx90614(); + printk("temp: %.2f °C\n", temp); + request_sensor_data_mlx90614(MLX90614_IR_TEMP_ADDR); + floor_temp = get_temp_from_raw_data_mlx90614(); + printk("floor_temp: %.2f °C\n", floor_temp); + + /* Pack and send values */ + char data[7]; + create_data_package(data, temp, floor_temp, humidity, relais_state); + LOG_HEXDUMP_DBG(data, 7, "data"); + send_data_packet(data, 7); + + /* Delay until next cycle */ + k_sleep(SEND_INTERVALL); + } } \ No newline at end of file diff --git a/src/sensors/mlx90614.c b/src/sensors/mlx90614.c index c8810aa..43aeaed 100644 --- a/src/sensors/mlx90614.c +++ b/src/sensors/mlx90614.c @@ -3,13 +3,16 @@ #include #include #include +#include -static struct device *i2c_dev; -static uint16_t i2c_addr = 0x00; +LOG_MODULE_REGISTER(mlx90614); -void init_mlx90614() { +static const struct device *i2c_dev; +static const uint16_t i2c_addr = 0x5A; +static uint8_t read_data_buffer[3]; + +int init_mlx90614() { i2c_dev = DEVICE_DT_GET(DT_NODELABEL(i2c1)); - i2c_addr = DT_PROP(DT_NODELABEL(mlx90614), reg); if (!i2c_dev) { LOG_ERR("I2C device not found!"); @@ -17,27 +20,27 @@ void init_mlx90614() { } else { LOG_INF("I2C device initialized."); } - - if (i2c_addr == 0x00) { - LOG_ERR("MLX90614 I2C address fetch from device tree failed!"); - } else { - LOG_INF("MLX90614 I2C address found."); - } } -void request_sensor_data_mlx90614(uint16_t target_addr, const uint8_t *read_data) { - for (int i = 0; i < MLX90614_RETRY_COUNT; i++) { - if (i2c_write_read(i2c_dev, i2c_addr, &target_addr, sizeof(target_addr), &read_data, sizeof(read_data) == 0)) { +void request_sensor_data_mlx90614(uint8_t target_addr) { + uint8_t err; + for (int i = 0; i < MLX90614_RETRY_COUNT; i++) + { + err = i2c_write_read(i2c_dev, 0x5A, &target_addr, sizeof(target_addr), &read_data_buffer, sizeof(read_data_buffer)); + if (err == 0) + { LOG_INF("MLX90614 sensor values successfully read after %d tries", i+1); return; - } else { + } + else + { k_sleep(K_MSEC(100)); } } - LOG_ERR("MLX90614 reading sensor values failed %d times!", MLX90614_RETRY_COUNT); + LOG_ERR("MLX90614 reading sensor values failed %d times with error %d!", MLX90614_RETRY_COUNT, err); } -float get_temp_from_raw_data_mlx90614(const uint8_t *read_data) { - int16_t temperature = (read_data[1] << 8) | read_data[0]; // Temperaturwert aus den empfangenen Daten - return temperature * 0.02 - 273.15; // Umrechnung in Celsius +float get_temp_from_raw_data_mlx90614() { + int16_t temperature = (read_data_buffer[1] << 8) | read_data_buffer[0]; // Temperaturwert aus den empfangenen Daten + return temperature * 0.02 - 273.15; // Umrechnung in Celsius } \ No newline at end of file diff --git a/src/sensors/mlx90614.h b/src/sensors/mlx90614.h index 83ff841..1793f49 100644 --- a/src/sensors/mlx90614.h +++ b/src/sensors/mlx90614.h @@ -6,6 +6,6 @@ int init_mlx90614(); -int request_sensor_data_mlx90614(uint16_t target_addr, const uint8_t *read_data); +void request_sensor_data_mlx90614(uint8_t target_addr); -float get_temp_from_raw_data_mlx90614(const uint8_t *read_data); \ No newline at end of file +float get_temp_from_raw_data_mlx90614(); \ No newline at end of file diff --git a/src/sensors/sht4x.c b/src/sensors/sht4x.c index f76e173..6556eac 100644 --- a/src/sensors/sht4x.c +++ b/src/sensors/sht4x.c @@ -5,7 +5,9 @@ #include #include -static struct device *sht; +LOG_MODULE_REGISTER(sht4x); + +static const struct device *sht; void init_sht4x() { @@ -46,10 +48,10 @@ float get_value_from_current_sample_sht4x(enum sensor_channel sensor) float result; if (sensor_channel_get(sht, sensor, &value) == 0) { result = sensor_value_to_double(&value); - LOG_INF("Value '%s' successfully read [%f]", sensor, result); + printf("Value '%s' successfully read [%f]", sensor, result); } else { LOG_ERR("Can't read sensor value '%s' from sample!", sensor); return 0.0; } - return value; + return result; } \ No newline at end of file diff --git a/src/sensors/sht4x.h b/src/sensors/sht4x.h index 27455e5..e701722 100644 --- a/src/sensors/sht4x.h +++ b/src/sensors/sht4x.h @@ -6,4 +6,4 @@ void init_sht4x(); void request_sensor_data_sht4x(); -float get_value_from_raw_data_sht4x(enum sensor_channel sensor); \ No newline at end of file +float get_value_from_current_sample_sht4x(enum sensor_channel sensor); \ No newline at end of file diff --git a/zephyr/boards/st/g2h_lorawan_heat_control/g2h_lorawan_heat_control.dts b/zephyr/boards/st/g2h_lorawan_heat_control/g2h_lorawan_heat_control.dts index ae3d54e..2b6204b 100644 --- a/zephyr/boards/st/g2h_lorawan_heat_control/g2h_lorawan_heat_control.dts +++ b/zephyr/boards/st/g2h_lorawan_heat_control/g2h_lorawan_heat_control.dts @@ -10,6 +10,7 @@ #include "arduino_r3_connector.dtsi" #include "st_morpho_connector.dtsi" #include +//#include "g2h_lorawan_heat_control.dtsi" / { model = "G2H LoraWAN Heat control based on STM32WL55JC-NUCLEO"; @@ -208,4 +209,4 @@ stm32_lp_tick_source: &lptim1 { &vbat { status = "okay"; -}; +}; \ No newline at end of file diff --git a/zephyr/boards/st/g2h_lorawan_heat_control/g2h_lorawan_heat_control.dtsi b/zephyr/boards/st/g2h_lorawan_heat_control/g2h_lorawan_heat_control.dtsi new file mode 100644 index 0000000..db32aa2 --- /dev/null +++ b/zephyr/boards/st/g2h_lorawan_heat_control/g2h_lorawan_heat_control.dtsi @@ -0,0 +1,8 @@ +#include +#include + +&pinctrl { + gpio_pc0: gpio_pc0 { + pinmux = ; + }; +}; diff --git a/zephyr/dts/bindings/power-switch.yaml b/zephyr/dts/bindings/power-switch.yaml new file mode 100644 index 0000000..438faf1 --- /dev/null +++ b/zephyr/dts/bindings/power-switch.yaml @@ -0,0 +1,10 @@ +description: GPIO pin to switch a power output on or off + +compatible: "power-switch" + +properties: + gpios: + type: phandle-array + required: true + description: | + The GPIO connected to the gate driver for the MOSFET. \ No newline at end of file diff --git a/zephyr/g2h_lorawan_heat_control.overlay b/zephyr/g2h_lorawan_heat_control.overlay new file mode 100644 index 0000000..08e6e90 --- /dev/null +++ b/zephyr/g2h_lorawan_heat_control.overlay @@ -0,0 +1,6 @@ +/ { + load_switch: load_switch { + compatible = "power-switch"; + gpios = <&gpioc 0 GPIO_ACTIVE_HIGH>; + }; +}; \ No newline at end of file diff --git a/zephyr/prj.conf b/zephyr/prj.conf index 77c880e..3f075cf 100644 --- a/zephyr/prj.conf +++ b/zephyr/prj.conf @@ -1,12 +1,18 @@ CONFIG_LOG=y CONFIG_SENSOR=y +CONFIG_GPIO=y +CONFIG_SETTINGS=y +CONFIG_FLASH=y +CONFIG_FLASH_MAP=y +CONFIG_ZMS=y CONFIG_I2C=y CONFIG_SHT4X=y CONFIG_LORA=y CONFIG_LORAWAN=y CONFIG_LORAMAC_REGION_EU868=y -CONFIG_MAIN_STACK_SIZE=2048 -CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 +CONFIG_MAIN_STACK_SIZE=4096 +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096 CONFIG_LOG_DEFAULT_LEVEL=3 CONFIG_NEWLIB_LIBC=y -CONFIG_NEWLIB_LIBC_FLOAT_PRINTF=y \ No newline at end of file +CONFIG_NEWLIB_LIBC_FLOAT_PRINTF=y +CONFIG_ENTROPY_GENERATOR=y \ No newline at end of file