diff --git a/.github/workflows/build_zephyr.yml b/.github/workflows/build_zephyr.yml index ba4b5c8..7f1ec22 100644 --- a/.github/workflows/build_zephyr.yml +++ b/.github/workflows/build_zephyr.yml @@ -63,6 +63,7 @@ jobs: west init -l app west update --narrow -o=--depth=1 west zephyr-export + pip3 install ecdsa # Thingy91x pip3 install -r deps/zephyr/scripts/requirements-base.txt # Needed for TF-M pip3 install cryptography pyasn1 pyyaml cbor>=1.0.0 imgtool>=1.9.0 jinja2 click diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3924fe4..b1cdcba 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -17,7 +17,7 @@ jobs: strategy: matrix: ZEPHYR_SDK: [0.16.3] - BOARD: ["thingy91/nrf9160/ns"] + BOARD: ["thingy91/nrf9160/ns", "thingy91x/nrf9151/ns"] uses: ./.github/workflows/build_zephyr.yml with: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d30f457..b1636ea 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,3 +16,9 @@ jobs: ZEPHYR_SDK: 0.16.3 BOARD: thingy91/nrf9160/ns ARTIFACT: false + test_build_thingy91x: + uses: ./.github/workflows/build_zephyr.yml + with: + ZEPHYR_SDK: 0.16.3 + BOARD: thingy91x/nrf9151/ns + ARTIFACT: false diff --git a/boards/thingy91_nrf9160_ns.conf b/boards/thingy91_nrf9160_ns.conf index 1f7d4e8..04a87db 100644 --- a/boards/thingy91_nrf9160_ns.conf +++ b/boards/thingy91_nrf9160_ns.conf @@ -1,45 +1,17 @@ -# Copyright (c) 2022 Golioth, Inc. +# Copyright (c) 2024 Golioth, Inc. # SPDX-License-Identifier: Apache-2.0 -# General config -CONFIG_HEAP_MEM_POOL_SIZE=4096 -CONFIG_NEWLIB_LIBC=y +CONFIG_BH1749=y +CONFIG_BH1749_TRIGGER=y -# Networking -CONFIG_NET_SOCKETS_OFFLOAD=y -CONFIG_NET_IPV6=y -CONFIG_NET_IPV6_NBR_CACHE=n -CONFIG_NET_IPV6_MLD=n +CONFIG_BME680=y -# Increase native TLS socket implementation, so that it is chosen instead of -# offloaded nRF91 sockets -CONFIG_NET_SOCKETS_TLS_PRIORITY=35 +CONFIG_ADXL362=y +CONFIG_ADXL362_TRIGGER_GLOBAL_THREAD=y +CONFIG_ADXL362_INTERRUPT_MODE=1 +CONFIG_ADXL362_ABS_REF_MODE=1 +CONFIG_ADXL362_ACCEL_RANGE_2G=y +CONFIG_ADXL362_ACCEL_ODR_12_5=y -# Modem library -CONFIG_NRF_MODEM_LIB=y - -# LTE connectivity with network connection manager -CONFIG_NRF_MODEM_LIB_NET_IF=y -CONFIG_NRF_MODEM_LIB_NET_IF_AUTO_START=y -CONFIG_NRF_MODEM_LIB_NET_IF_AUTO_CONNECT=n -CONFIG_NET_CONNECTION_MANAGER=y -CONFIG_NET_CONNECTION_MANAGER_MONITOR_STACK_SIZE=1024 - -# Add Logs for LTE Link Handler -CONFIG_GOLIOTH_SAMPLE_NRF91_LTE_MONITOR=y - -# Disable options y-selected by NCS for no good reason -CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED=n -CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED=n - -# MbedTLS configuration to support p-384 curve. These options -# enable using the MbedTLS built-in support for operations not -# supported by the default nRF Oberon crypto backend -CONFIG_NORDIC_SECURITY_BACKEND=n -CONFIG_MBEDTLS_LEGACY_CRYPTO_C=y - -# Add Network Info Support -CONFIG_MODEM_INFO=y - -# Generate MCUboot compatible images -CONFIG_BOOTLOADER_MCUBOOT=y +# Disable unused libraries to save flash +CONFIG_ADXL372=n diff --git a/boards/thingy91_nrf9160_ns.overlay b/boards/thingy91_nrf9160_ns.overlay index 0c4d373..9770af0 100644 --- a/boards/thingy91_nrf9160_ns.overlay +++ b/boards/thingy91_nrf9160_ns.overlay @@ -1,9 +1,5 @@ / { aliases { - click-uart = &uart1; - click-i2c = &i2c2; - golioth-led = &green_led; - user-led = &blue_led; sw1 = &button0; buzzer-pwm = &buzzer; }; diff --git a/boards/thingy91x_nrf9151_ns.conf b/boards/thingy91x_nrf9151_ns.conf new file mode 100644 index 0000000..bbe198d --- /dev/null +++ b/boards/thingy91x_nrf9151_ns.conf @@ -0,0 +1,7 @@ +# Copyright (c) 2024 Golioth, Inc. +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_BME680=n +CONFIG_BME68X_IAQ=y +CONFIG_BME68X_IAQ_THREAD_STACK_SIZE=2048 +CONFIG_BME68X_IAQ_SAMPLE_RATE_ULTRA_LOW_POWER=y diff --git a/boards/thingy91x_nrf9151_ns.overlay b/boards/thingy91x_nrf9151_ns.overlay new file mode 100644 index 0000000..153c98e --- /dev/null +++ b/boards/thingy91x_nrf9151_ns.overlay @@ -0,0 +1,14 @@ +/ { + aliases { + sw1 = &button0; + }; + +}; + +&bme680 { + status = "okay"; +}; + +&accel { + status = "okay"; +}; diff --git a/prj.conf b/prj.conf index e8fe3c1..7718419 100644 --- a/prj.conf +++ b/prj.conf @@ -54,24 +54,11 @@ CONFIG_NETWORK_INFO=y # Longer response length needed for network info CONFIG_GOLIOTH_RPC_MAX_RESPONSE_LEN=512 CONFIG_I2C=y - CONFIG_SENSOR=y -CONFIG_BH1749=y -CONFIG_BH1749_TRIGGER=y - -CONFIG_BME680=y - -CONFIG_ADXL362=y -CONFIG_ADXL362_TRIGGER_GLOBAL_THREAD=y -CONFIG_ADXL362_INTERRUPT_MODE=1 -CONFIG_ADXL362_ABS_REF_MODE=1 -CONFIG_ADXL362_ACCEL_RANGE_2G=y -CONFIG_ADXL362_ACCEL_ODR_12_5=y CONFIG_PWM=y CONFIG_PWM_LOG_LEVEL_DBG=n # Disable unused libraries to save flash -CONFIG_ADXL372=n CONFIG_FLASH_SHELL=n CONFIG_SENSOR_SHELL=n diff --git a/socs/nrf9151_ns.conf b/socs/nrf9151_ns.conf new file mode 100644 index 0000000..3aecf53 --- /dev/null +++ b/socs/nrf9151_ns.conf @@ -0,0 +1,45 @@ +# Copyright (c) 2024 Golioth, Inc. +# SPDX-License-Identifier: Apache-2.0 + +# General config +CONFIG_HEAP_MEM_POOL_SIZE=4096 +CONFIG_NEWLIB_LIBC=y + +# Networking +CONFIG_NET_SOCKETS_OFFLOAD=y +CONFIG_NET_IPV6=y +CONFIG_NET_IPV6_NBR_CACHE=n +CONFIG_NET_IPV6_MLD=n + +# Increase native TLS socket implementation, so that it is chosen instead of +# offloaded nRF91 sockets +CONFIG_NET_SOCKETS_TLS_PRIORITY=35 + +# Modem library +CONFIG_NRF_MODEM_LIB=y + +# LTE connectivity with network connection manager +CONFIG_NRF_MODEM_LIB_NET_IF=y +CONFIG_NRF_MODEM_LIB_NET_IF_AUTO_START=y +CONFIG_NRF_MODEM_LIB_NET_IF_AUTO_CONNECT=n +CONFIG_NET_CONNECTION_MANAGER=y +CONFIG_NET_CONNECTION_MANAGER_MONITOR_STACK_SIZE=1024 + +# Add Logs for LTE Link Handler +CONFIG_GOLIOTH_SAMPLE_NRF91_LTE_MONITOR=y + +# Disable options y-selected by NCS for no good reason +CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED=n +CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED=n + +# MbedTLS configuration to support p-384 curve. These options +# enable using the MbedTLS built-in support for operations not +# supported by the default nRF Oberon crypto backend +CONFIG_NORDIC_SECURITY_BACKEND=n +CONFIG_MBEDTLS_LEGACY_CRYPTO_C=y + +# Add Network Info Support +CONFIG_MODEM_INFO=y + +# Generate MCUboot compatible images +CONFIG_BOOTLOADER_MCUBOOT=y diff --git a/socs/nrf9160_ns.conf b/socs/nrf9160_ns.conf new file mode 100644 index 0000000..3aecf53 --- /dev/null +++ b/socs/nrf9160_ns.conf @@ -0,0 +1,45 @@ +# Copyright (c) 2024 Golioth, Inc. +# SPDX-License-Identifier: Apache-2.0 + +# General config +CONFIG_HEAP_MEM_POOL_SIZE=4096 +CONFIG_NEWLIB_LIBC=y + +# Networking +CONFIG_NET_SOCKETS_OFFLOAD=y +CONFIG_NET_IPV6=y +CONFIG_NET_IPV6_NBR_CACHE=n +CONFIG_NET_IPV6_MLD=n + +# Increase native TLS socket implementation, so that it is chosen instead of +# offloaded nRF91 sockets +CONFIG_NET_SOCKETS_TLS_PRIORITY=35 + +# Modem library +CONFIG_NRF_MODEM_LIB=y + +# LTE connectivity with network connection manager +CONFIG_NRF_MODEM_LIB_NET_IF=y +CONFIG_NRF_MODEM_LIB_NET_IF_AUTO_START=y +CONFIG_NRF_MODEM_LIB_NET_IF_AUTO_CONNECT=n +CONFIG_NET_CONNECTION_MANAGER=y +CONFIG_NET_CONNECTION_MANAGER_MONITOR_STACK_SIZE=1024 + +# Add Logs for LTE Link Handler +CONFIG_GOLIOTH_SAMPLE_NRF91_LTE_MONITOR=y + +# Disable options y-selected by NCS for no good reason +CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED=n +CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED=n + +# MbedTLS configuration to support p-384 curve. These options +# enable using the MbedTLS built-in support for operations not +# supported by the default nRF Oberon crypto backend +CONFIG_NORDIC_SECURITY_BACKEND=n +CONFIG_MBEDTLS_LEGACY_CRYPTO_C=y + +# Add Network Info Support +CONFIG_MODEM_INFO=y + +# Generate MCUboot compatible images +CONFIG_BOOTLOADER_MCUBOOT=y diff --git a/src/app_sensors.c b/src/app_sensors.c index ac60ae1..8413b03 100644 --- a/src/app_sensors.c +++ b/src/app_sensors.c @@ -20,20 +20,18 @@ LOG_MODULE_REGISTER(app_sensors, LOG_LEVEL_DBG); static struct golioth_client *client; -static const struct gpio_dt_spec user_led = GPIO_DT_SPEC_GET(DT_ALIAS(user_led), gpios); - /* Sensor device structs */ +#if defined(CONFIG_BOARD_THINGY91_NRF9160_NS) const struct device *light = DEVICE_DT_GET_ONE(rohm_bh1749); const struct device *weather = DEVICE_DT_GET_ONE(bosch_bme680); const struct device *accel = DEVICE_DT_GET_ONE(adi_adxl362); +#endif -/* Set (unset) LED indicators for user action */ -void user_led_set(uint8_t state) -{ - uint8_t pin_state = state ? 1 : 0; - /* Turn on Golioth logo LED once connected */ - gpio_pin_set_dt(&user_led, pin_state); -} +#if defined(CONFIG_BOARD_THINGY91X_NRF9151_NS) +#include +const struct device *weather = DEVICE_DT_GET_ONE(bosch_bme680); +const struct device *accel = DEVICE_DT_GET_ONE(adi_adxl367); +#endif /* Callback for LightDB Stream */ static void async_error_handler(struct golioth_client *client, enum golioth_status status, @@ -48,6 +46,8 @@ static void async_error_handler(struct golioth_client *client, enum golioth_stat static enum golioth_status read_light_sensor(zcbor_state_t *zse) { +#if defined(CONFIG_DT_HAS_ROHM_BH1749_ENABLED) + struct sensor_value BH1749_RED; struct sensor_value BH1749_GREEN; struct sensor_value BH1749_BLUE; @@ -109,15 +109,78 @@ static enum golioth_status read_light_sensor(zcbor_state_t *zse) } return GOLIOTH_OK; + +#else + + return GOLIOTH_OK; + +#endif /* CONFIG_DT_HAS_ROHM_BH1749_ENABLED */ } + +/* This function assume that sensor_sample_fetch() has already been run */ +static enum golioth_status process_gas_sensor(zcbor_state_t *zse) +{ +#if defined(CONFIG_BOARD_THINGY91_NRF9160_NS) + + struct sensor_value gas_res; + bool ok; + + sensor_channel_get(weather, SENSOR_CHAN_GAS_RES, &gas_res); + LOG_DBG("G: %d.%06d", gas_res.val1, gas_res.val2); + + ok = zcbor_tstr_put_lit(zse, "gas") && + zcbor_float64_put(zse, sensor_value_to_double(&gas_res)); + + if (!ok) + { + LOG_ERR("ZCBOR unable to encode gas data"); + return GOLIOTH_ERR_QUEUE_FULL; + } + + return GOLIOTH_OK; + +#elif defined(CONFIG_BOARD_THINGY91X_NRF9151_NS) + + struct sensor_value gas_iaq = { 0 }; + struct sensor_value gas_co2 = { 0 }; + struct sensor_value gas_voc = { 0 }; + bool ok; + + sensor_channel_get(weather, SENSOR_CHAN_IAQ, &gas_iaq); + sensor_channel_get(weather, SENSOR_CHAN_CO2, &gas_co2); + sensor_channel_get(weather, SENSOR_CHAN_VOC, &gas_voc); + LOG_DBG("IAQ: %d; CO2: %d.%06d; VOC: %d.%06d", + gas_iaq.val1, gas_co2.val1, gas_co2.val2, gas_voc.val1, gas_voc.val2); + + ok = zcbor_tstr_put_lit(zse, "iaq") && + zcbor_int32_put(zse, gas_iaq.val1) && + zcbor_tstr_put_lit(zse, "co2") && + zcbor_float64_put(zse, sensor_value_to_double(&gas_co2)) && + zcbor_tstr_put_lit(zse, "voc") && + zcbor_float64_put(zse, sensor_value_to_double(&gas_voc)); + + if (!ok) + { + LOG_ERR("ZCBOR unable to encode gas data"); + return GOLIOTH_ERR_QUEUE_FULL; + } + + return GOLIOTH_OK; + +#else + + return GOLIOTH_OK; + +#endif +} static enum golioth_status read_weather_sensor(zcbor_state_t *zse) { struct sensor_value temp; struct sensor_value press; struct sensor_value humidity; - struct sensor_value gas_res; bool ok; + enum golioth_status status; /* BME680 */ int err = sensor_sample_fetch(weather); @@ -128,9 +191,8 @@ static enum golioth_status read_weather_sensor(zcbor_state_t *zse) sensor_channel_get(weather, SENSOR_CHAN_AMBIENT_TEMP, &temp); sensor_channel_get(weather, SENSOR_CHAN_PRESS, &press); sensor_channel_get(weather, SENSOR_CHAN_HUMIDITY, &humidity); - sensor_channel_get(weather, SENSOR_CHAN_GAS_RES, &gas_res); - LOG_DBG("T: %d.%06d; P: %d.%06d; H: %d.%06d; G: %d.%06d", temp.val1, abs(temp.val2), - press.val1, press.val2, humidity.val1, humidity.val2, gas_res.val1, gas_res.val2); + LOG_DBG("T: %d.%06d; P: %d.%06d; H: %d.%06d", temp.val1, abs(temp.val2), press.val1, + press.val2, humidity.val1, humidity.val2); ok = zcbor_tstr_put_lit(zse, "weather") && zcbor_map_start_encode(zse, 4); if (!ok) @@ -144,15 +206,19 @@ static enum golioth_status read_weather_sensor(zcbor_state_t *zse) zcbor_tstr_put_lit(zse, "pre") && zcbor_float64_put(zse, sensor_value_to_double(&press)) && zcbor_tstr_put_lit(zse, "hum") && - zcbor_float64_put(zse, sensor_value_to_double(&humidity)) && - zcbor_tstr_put_lit(zse, "gas") && - zcbor_float64_put(zse, sensor_value_to_double(&gas_res)); + zcbor_float64_put(zse, sensor_value_to_double(&humidity)); if (!ok) { LOG_ERR("ZCBOR failed to encode weather data"); return GOLIOTH_ERR_QUEUE_FULL; } + status = process_gas_sensor(zse); + if (status != GOLIOTH_OK) + { + return status; + } + ok = zcbor_map_end_encode(zse, 4); if (!ok) { @@ -256,11 +322,16 @@ void app_sensors_read_and_stream(void) size_t cbor_size = zse->payload - (const uint8_t *) cbor_buf; - /* Send to LightDB Stream on "sensor" endpoint */ - err = golioth_stream_set_async(client, "sensor", GOLIOTH_CONTENT_TYPE_CBOR, cbor_buf, - cbor_size, async_error_handler, NULL); - if (err) { - LOG_ERR("Failed to send sensor data to Golioth: %d", err); + /* Only stream sensor data if connected */ + if (golioth_client_is_connected(client)) { + /* Send to LightDB Stream on "sensor" endpoint */ + err = golioth_stream_set_async(client, "sensor", GOLIOTH_CONTENT_TYPE_CBOR, cbor_buf, + cbor_size, async_error_handler, NULL); + if (err) { + LOG_ERR("Failed to send sensor data to Golioth: %d", err); + } + } else { + LOG_DBG("No connection available, skipping sending data to Golioth"); } } diff --git a/src/main.c b/src/main.c index cc86203..422c158 100644 --- a/src/main.c +++ b/src/main.c @@ -20,7 +20,7 @@ LOG_MODULE_REGISTER(thingy91_golioth, LOG_LEVEL_DBG); #include #include -#ifdef CONFIG_SOC_NRF9160 +#if defined(CONFIG_SOC_SERIES_NRF91X) #include #endif @@ -39,15 +39,9 @@ K_SEM_DEFINE(connected, 0, 1); static k_tid_t _system_thread; -#if DT_NODE_EXISTS(DT_ALIAS(golioth_led)) -static const struct gpio_dt_spec golioth_led = GPIO_DT_SPEC_GET(DT_ALIAS(golioth_led), gpios); -#endif /* DT_NODE_EXISTS(DT_ALIAS(golioth_led)) */ static const struct gpio_dt_spec user_btn = GPIO_DT_SPEC_GET(DT_ALIAS(sw1), gpios); static struct gpio_callback button_cb_data; -/* forward declarations */ -void golioth_connection_led_set(uint8_t state); - void wake_system_thread(void) { k_wakeup(_system_thread); @@ -61,7 +55,7 @@ static void on_client_event(struct golioth_client *client, if (is_connected) { k_sem_give(&connected); - golioth_connection_led_set(1); + app_led_pwm_init(); } LOG_INF("Golioth client %s", is_connected ? "connected" : "disconnected"); } @@ -96,7 +90,7 @@ static void start_golioth_client(void) app_rpc_register(client); } -#ifdef CONFIG_SOC_NRF9160 +#if defined(CONFIG_SOC_SERIES_NRF91X) static void lte_handler(const struct lte_lc_evt *const evt) { @@ -147,12 +141,6 @@ void button_pressed(const struct device *dev, struct gpio_callback *cb, uint32_t k_wakeup(_system_thread); } -/* Set (unset) LED indicators for active Golioth connection */ -void golioth_connection_led_set(uint8_t state) -{ - app_led_pwm_init(); /* Once the connection is available, fire up the LED pwms */ -} - int main(void) { int err; @@ -165,15 +153,7 @@ int main(void) /* Get system thread id so loop delay change event can wake main */ _system_thread = k_current_get(); -#if DT_NODE_EXISTS(DT_ALIAS(golioth_led)) - /* Initialize Golioth logo LED */ - err = gpio_pin_configure_dt(&golioth_led, GPIO_OUTPUT_INACTIVE); - if (err) { - LOG_ERR("Unable to configure LED for Golioth Logo"); - } -#endif /* #if DT_NODE_EXISTS(DT_ALIAS(golioth_led)) */ - -#ifdef CONFIG_SOC_NRF9160 +#if defined(CONFIG_SOC_SERIES_NRF91X) /* Start LTE asynchronously if the nRF9160 is used. * Golioth Client will start automatically when LTE connects */ diff --git a/west.yml b/west.yml index 89e6e69..3b12401 100644 --- a/west.yml +++ b/west.yml @@ -4,6 +4,9 @@ manifest: version: 0.8 + group-filter: + - +bsec + projects: - name: golioth path: modules/lib/golioth-firmware-sdk @@ -17,6 +20,8 @@ manifest: name-allowlist: - nrf - zephyr + - bme68x + - bsec - cmsis - hal_nordic - mbedtls