diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..0ecacf6 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,12 @@ +{ + "files.associations": { + "devicetree.h": "c", + "lorawan.h": "c", + "kernel.h": "c", + "device.h": "c", + "log.h": "c", + "mlx90614.h": "c", + "sensor.h": "c", + "sht4x.h": "c" + } +} \ No newline at end of file diff --git a/src/lora/lorawan.c b/src/lora/lorawan.c new file mode 100644 index 0000000..0c34025 --- /dev/null +++ b/src/lora/lorawan.c @@ -0,0 +1,123 @@ +#include +#include +#include + +#include + +/* + TODO: + - DEV NONCE in non volatile memory and increase + - format packets + - send: check if still in network + - downlink callback + + + // 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 +*/ + +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; + +void init_lorawan() { + int ret; + + struct lorawan_downlink_cb downlink_cb = { + .port = LW_RECV_PORT_ANY, + .cb = dl_callback}; + + lora_dev = DEVICE_DT_GET(DT_ALIAS(lora0)); + if (!device_is_ready(lora_dev)) + { + LOG_ERR("%s: device not ready.", lora_dev->name); + return 0; + } + + ret = lorawan_start(); + if (ret < 0) + { + LOG_ERR("lorawan_start failed: %d", ret); + return 0; + } + else + { + LOG_INF("LoraWan started successfully"); + } + + 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 +} + +void join_network_otaa() { + int8_t status = -1; + while (lorawan_join(&join_cfg) < 0) { + LOG_ERR("lorawan_join_network failed: %d, retrying..", ret); + k_sleep(K_MSEC(5000)); + } + LOG_INF("Joining network over OTAA"); +} + +void send_data_packet(char *data) { + LOG_INF("Sending data..."); + while (1) + { + int8_t ret = lorawan_send(LORAWAN_PORT, data, sizeof(data), LORAWAN_MSG_CONFIRMED); + + if (ret == -EAGAIN) + { + LOG_ERR("lorawan_send failed: %d. Continuing...", ret); + k_sleep(DELAY); + continue; + } + + if (ret < 0) + { + LOG_ERR("lorawan_send failed: %d", ret); + k_sleep(DELAY); + continue; + } + else + { + LOG_INF("Data sent!"); + } + + k_sleep(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) +{ + 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: "); + } +} + +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); +} \ No newline at end of file diff --git a/src/lora/lorawan.h b/src/lora/lorawan.h new file mode 100644 index 0000000..d0ec396 --- /dev/null +++ b/src/lora/lorawan.h @@ -0,0 +1,23 @@ +#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 } + + +static void dl_callback(uint8_t port, uint8_t flags, int16_t rssi, int8_t snr, uint8_t len, + const uint8_t *hex_data); + +static void lorwan_datarate_changed(enum lorawan_datarate dr); \ No newline at end of file diff --git a/src/main.c b/src/main.c index 696d160..8679d24 100644 --- a/src/main.c +++ b/src/main.c @@ -1,203 +1,29 @@ -/* - * Class A LoRaWAN sample application - * - * Copyright (c) 2020 Manivannan Sadhasivam - * - * SPDX-License-Identifier: Apache-2.0 - */ - +#include +#include #include #include #include -#include -#include #include #include - #include -/* 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 } +#include +#include +#include + + #define DELAY K_MSEC(10000) - #define LOG_LEVEL CONFIG_LOG_DEFAULT_LEVEL -#include + + LOG_MODULE_REGISTER(lorawan_class_a); -char data[] = {'h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd'}; - -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, Time %d", port, - flags & LORAWAN_DATA_PENDING, rssi, snr, !!(flags & LORAWAN_TIME_UPDATED)); - if (hex_data) { - LOG_HEXDUMP_INF(hex_data, len, "Payload: "); - } -} - -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); -} /* MAIN */ int main(void) { - // MLX90614 Example Fetch - const struct device *i2c_dev = DEVICE_DT_GET(DT_NODELABEL(i2c1)); - uint8_t reg_addr; - uint8_t read_data[3]; - if (!i2c_dev) { - printk("I2C device not found\n"); - return; - } - - reg_addr = 0x06; - if (i2c_write_read(i2c_dev, 0x5A, ®_addr, sizeof(reg_addr), &read_data, sizeof(read_data)) < 0) - { - printk("Failed to write to I2C device\n"); - } - int16_t temperature = (read_data[1] << 8) | read_data[0]; // Temperaturwert aus den empfangenen Daten - float temp_celsius = temperature * 0.02 - 273.15; // Umrechnung in Celsius - - printf("Temperatur Sensor: %.2f °C\n", temp_celsius); - - - - reg_addr = 0x07; - if (i2c_write_read(i2c_dev, 0x5A, ®_addr, sizeof(reg_addr), &read_data, sizeof(read_data)) < 0) - { - printk("Failed to write to I2C device\n"); - } - - // Temperaturdaten verarbeiten - temperature = (read_data[1] << 8) | read_data[0]; // Temperaturwert aus den empfangenen Daten - temp_celsius = temperature * 0.02 - 273.15; // Umrechnung in Celsius - - printf("Temperatur IR: %.2f °C\n", temp_celsius); - - return 0; - - - - /* - // SHT4X Example Fetch - if(!DT_HAS_COMPAT_STATUS_OKAY(sensirion_sht4x)) { - printf("No sensirion,sht4x compatible node found in the device tree"); - } - - const struct device *const sht = DEVICE_DT_GET_ANY(sensirion_sht4x); - struct sensor_value temp, hum; - - if (!device_is_ready(sht)) { - printf("SHT4X-Device %s is not ready.\n", sht->name); - return 0; - } - - while (true) { - - if (sensor_sample_fetch(sht)) { - printf("Failed to fetch sample from SHT4X device\n"); - return 0; - } - - sensor_channel_get(sht, SENSOR_CHAN_AMBIENT_TEMP, &temp); - sensor_channel_get(sht, SENSOR_CHAN_HUMIDITY, &hum); - - printf("SHT4X: %.2f Temp. [C] ; %0.2f RH [%%]\n", - sensor_value_to_double(&temp), - sensor_value_to_double(&hum)); - - k_sleep(K_MSEC(5000)); - } - */ - - 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; - int ret; - - struct lorawan_downlink_cb downlink_cb = { - .port = LW_RECV_PORT_ANY, - .cb = dl_callback - }; - - lora_dev = DEVICE_DT_GET(DT_ALIAS(lora0)); - if (!device_is_ready(lora_dev)) { - LOG_ERR("%s: device not ready.", lora_dev->name); - return 0; - } - - ret = lorawan_start(); - if (ret < 0) { - LOG_ERR("lorawan_start failed: %d", ret); - return 0; - } else { - LOG_INF("LoraWan started successfully"); - } - - 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: Repeat until success - LOG_INF("Joining network over OTAA"); - ret = lorawan_join(&join_cfg); - if (ret < 0) { - LOG_ERR("lorawan_join_network failed: %d", ret); - return 0; - } - - LOG_INF("Sending data..."); - while (1) { - ret = lorawan_send(2, data, sizeof(data), - LORAWAN_MSG_CONFIRMED); - - /* - * Note: The stack may return -EAGAIN if the provided data - * length exceeds the maximum possible one for the region and - * datarate. But since we are just sending the same data here, - * we'll just continue. - */ - if (ret == -EAGAIN) { - LOG_ERR("lorawan_send failed: %d. Continuing...", ret); - k_sleep(DELAY); - continue; - } - - if (ret < 0) { - LOG_ERR("lorawan_send failed: %d", ret); - k_sleep(DELAY); - continue; - } else { - LOG_INF("Data sent!"); - } - - k_sleep(DELAY); - } } \ No newline at end of file diff --git a/src/sensors/mlx90614.c b/src/sensors/mlx90614.c new file mode 100644 index 0000000..c8810aa --- /dev/null +++ b/src/sensors/mlx90614.c @@ -0,0 +1,43 @@ +#include + +#include +#include +#include + +static struct device *i2c_dev; +static uint16_t i2c_addr = 0x00; + +void 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!"); + return; + } 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)) { + LOG_INF("MLX90614 sensor values successfully read after %d tries", i+1); + return; + } else { + k_sleep(K_MSEC(100)); + } + } + LOG_ERR("MLX90614 reading sensor values failed %d times!", MLX90614_RETRY_COUNT); +} + +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 +} \ No newline at end of file diff --git a/src/sensors/mlx90614.h b/src/sensors/mlx90614.h new file mode 100644 index 0000000..83ff841 --- /dev/null +++ b/src/sensors/mlx90614.h @@ -0,0 +1,11 @@ +#include + +#define MLX90614_INTERNAL_TEMP_ADDR 0x06 +#define MLX90614_IR_TEMP_ADDR 0x07 +#define MLX90614_RETRY_COUNT 5 + +int init_mlx90614(); + +int request_sensor_data_mlx90614(uint16_t target_addr, const uint8_t *read_data); + +float get_temp_from_raw_data_mlx90614(const uint8_t *read_data); \ No newline at end of file diff --git a/src/sensors/sht4x.c b/src/sensors/sht4x.c new file mode 100644 index 0000000..f76e173 --- /dev/null +++ b/src/sensors/sht4x.c @@ -0,0 +1,55 @@ +#include + +#include +#include +#include +#include + +static struct device *sht; + +void init_sht4x() +{ + if (!DT_HAS_COMPAT_STATUS_OKAY(sensirion_sht4x)) { + LOG_ERR("No sensirion,sht4x compatible node found in the device tree"); + return; + } + + sht = DEVICE_DT_GET_ANY(sensirion_sht4x); + + if (!device_is_ready(sht)) + { + LOG_ERR("SHT4X-Device %s is not ready.\n", sht->name); + return; + } +} + +void request_sensor_data_sht4x() +{ + for (int i = 0; i < SHT4X_RETRY_COUNT; i++) + { + if (sensor_sample_fetch(sht) == 0) + { + LOG_INF("SHT4X sensor values successfully read after %d tries", i + 1); + return; + } + else + { + k_sleep(K_MSEC(100)); + } + } + LOG_ERR("SHT4X reading sensor values failed %d times!", SHT4X_RETRY_COUNT); +} + +float get_value_from_current_sample_sht4x(enum sensor_channel sensor) +{ + struct sensor_value value; + 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); + } else { + LOG_ERR("Can't read sensor value '%s' from sample!", sensor); + return 0.0; + } + return value; +} \ No newline at end of file diff --git a/src/sensors/sht4x.h b/src/sensors/sht4x.h new file mode 100644 index 0000000..27455e5 --- /dev/null +++ b/src/sensors/sht4x.h @@ -0,0 +1,9 @@ +#include + +#define SHT4X_RETRY_COUNT 5 + +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