From 9d053f8b1eb12d1877e9cb8e0bc98e2f934440a9 Mon Sep 17 00:00:00 2001 From: Dennis German Date: Mon, 25 Feb 2019 22:00:16 -0500 Subject: [PATCH 1/5] add tuneables Use static variables, saved in UICR, initialized to DEFINEs. This mitigates the need to modify sources and compile to just change (the frequently requested) TX_power, transmit interval, accelerometer thresholds ToDo: add code in gatt to allow these to be modified iff the password is == 0. --- ruuvi_examples/ruuvi_firmware/main.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/ruuvi_examples/ruuvi_firmware/main.c b/ruuvi_examples/ruuvi_firmware/main.c index 22b5dfec..e7927d7b 100644 --- a/ruuvi_examples/ruuvi_firmware/main.c +++ b/ruuvi_examples/ruuvi_firmware/main.c @@ -1,8 +1,9 @@ /** RuuviTag Environment-station */ -// Version 2.4.1 January 07, 2019 modes now RAWv1(RED), RAWv2_FAST(GREEN) and RAWv2_SLOW(GREEN) preserved in flash. (URL removed) +// Version 2.4.2 March 03, 2019 add tuneables +// Version 2.4.1 January 07, 2019 modes now RAWv1(RED), RAWv2_FAST(GREEN) and RAWv2_SLOW(GREEN) preserved in flash. (URL removed) // long button hold or NFC triggers reset. // short button or NFC triggers become_connectable i.e. fast_advertising BUT -// default is always non-connectable, non-scannable (see bluetooth_application_config.h) +// default is always non-connectable, non-scannable (see bluetooth_application_config.h) // accelerometer (lis2dh12) reewritten as pre STM // Only get battery voltage from ADC after radio has been quiet // Version 2.2.3 August 01, 2018; @@ -109,6 +110,14 @@ static uint64_t last_battery_measurement = 0; // Timestamp of VBat update. static ruuvi_sensor_t data; static uint8_t advertisement_delay = 0; //Random, static delay to reduce collisions. +// tuneables retained in UICR +static uint32_t password = 0; // if !0 tuneables are protected +static uint16_t advertising_interval = ADVERTISING_INTERVAL_RAW; +static uint16_t main_loop_interval = MAIN_LOOP_INTERVAL_RAW; +static uint16_t ble_tx_power = BLE_TX_POWER; +static uint16_t accel_sample_rate = LIS2DH12_SAMPLERATE_RAWv1; +static uint16_t accel_resolution = LIS2DH12_RESOLUTION; + // Possible modes of the app #define RAWv1 0 #define RAWv2_FAST 1 @@ -390,7 +399,7 @@ static void main_sensor_task(void* p_data, uint16_t length) { case RAWv2_FAST: case RAWv2_SLOW: - encodeToRawFormat5(data_buffer, &environmental, &buffer.sensor, acceleration_events, vbat, BLE_TX_POWER); + encodeToRawFormat5(data_buffer, &environmental, &buffer.sensor, acceleration_events, vbat, ble_tx_power); break; case RAWv1: @@ -541,7 +550,7 @@ int main(void) app_sched_event_put (&tag_mode, sizeof(&tag_mode), change_mode); // Initialize repeated timer for sensor read and single-shot timer for button reset - if( init_timer(main_timer_id, APP_TIMER_MODE_REPEATED, MAIN_LOOP_INTERVAL_RAW, main_timer_handler) ) + if( init_timer(main_timer_id, APP_TIMER_MODE_REPEATED, main_loop_interval, main_timer_handler) ) { init_status |= TIMER_FAILED_INIT; } @@ -571,8 +580,8 @@ int main(void) // Enable XYZ axes. lis2dh12_enable(); lis2dh12_set_scale(LIS2DH12_SCALE); - lis2dh12_set_sample_rate(LIS2DH12_SAMPLERATE_RAWv1); - lis2dh12_set_resolution(LIS2DH12_RESOLUTION); + lis2dh12_set_sample_rate(accel_sample_rate); + lis2dh12_set_resolution(accel_resolution); lis2dh12_set_activity_interrupt_pin_2(LIS2DH12_ACTIVITY_THRESHOLD); NRF_LOG_INFO("Accelerometer configuration done \r\n"); @@ -616,10 +625,11 @@ int main(void) // bluetooth_configure_advertisement_type(STARTUP_ADVERTISEMENT_TYPE); - bluetooth_tx_power_set(BLE_TX_POWER); - bluetooth_configure_advertising_interval(ADVERTISING_INTERVAL_STARTUP); + bluetooth_tx_power_set(ble_tx_power); + bluetooth_configure_advertising_interval(advertising_interval); bluetooth_advertising_start(); NRF_LOG_INFO("Advertising started\r\n"); + password=password; // just to make compiler happy // Enter main loop. Executes tasks scheduled by timers and interrupts. for (;;) From b32895e65ec768b0f11c1f280dde414b0feb4eb9 Mon Sep 17 00:00:00 2001 From: Dennis German Date: Thu, 28 Feb 2019 11:06:09 -0500 Subject: [PATCH 2/5] Update main.c --- ruuvi_examples/ruuvi_firmware/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruuvi_examples/ruuvi_firmware/main.c b/ruuvi_examples/ruuvi_firmware/main.c index e7927d7b..f6ad143b 100644 --- a/ruuvi_examples/ruuvi_firmware/main.c +++ b/ruuvi_examples/ruuvi_firmware/main.c @@ -1,5 +1,5 @@ /** RuuviTag Environment-station */ -// Version 2.4.2 March 03, 2019 add tuneables +// Version 2.4.3 March 03, 2019 add tuneables // Version 2.4.1 January 07, 2019 modes now RAWv1(RED), RAWv2_FAST(GREEN) and RAWv2_SLOW(GREEN) preserved in flash. (URL removed) // long button hold or NFC triggers reset. // short button or NFC triggers become_connectable i.e. fast_advertising BUT From 4760eaa7b759edaae1ecf1298fd02f289d392ea7 Mon Sep 17 00:00:00 2001 From: Dennis German Date: Thu, 28 Feb 2019 11:06:28 -0500 Subject: [PATCH 3/5] Update bluetooth_application_config.h --- ruuvi_examples/ruuvi_firmware/bluetooth_application_config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruuvi_examples/ruuvi_firmware/bluetooth_application_config.h b/ruuvi_examples/ruuvi_firmware/bluetooth_application_config.h index d20c5d5e..a8b4ed3f 100644 --- a/ruuvi_examples/ruuvi_firmware/bluetooth_application_config.h +++ b/ruuvi_examples/ruuvi_firmware/bluetooth_application_config.h @@ -9,7 +9,7 @@ #define APP_DEVICE_NAME_LENGTH APPLICATION_DEVICE_NAME_LENGTH #define APPLICATION_ADV_INTERVAL 1010 /**< ms. Use value which is not exactly divisible by 1000 ms to be seen by gateways which have limited scan windows in second divisible intervals. **/ #define APP_TX_POWER 4 /**< dBm **/ -#define INIT_FWREV "2.4.1" /**< Github tag. Do not include specifiers such as "alpha" so you can accept ready binaries as they are **/ +#define INIT_FWREV "2.4.3" /**< Github tag. Do not include specifiers such as "alpha" so you can accept ready binaries as they are **/ #define INIT_SWREV INIT_FWREV /**< FW and SW are same thing in this context **/ // milliseconds until main loop timer function is called. Other timers can bring From dba5c80b625ac173bfa04cfa6fabb12a59cbafff Mon Sep 17 00:00:00 2001 From: Dennis German Date: Tue, 5 Mar 2019 11:19:00 -0500 Subject: [PATCH 4/5] Restore tunables Remove initialization from main to uncluttered it. Begin initialization with setting of tunable variables used in the code to the values from NVM UICR. This commit is for code not yes complete but a work on progress. --- ruuvi_examples/ruuvi_firmware/initialize.c | 324 +++++++++++++++++++++ ruuvi_examples/ruuvi_firmware/initialize.h | 3 + 2 files changed, 327 insertions(+) create mode 100644 ruuvi_examples/ruuvi_firmware/initialize.c create mode 100644 ruuvi_examples/ruuvi_firmware/initialize.h diff --git a/ruuvi_examples/ruuvi_firmware/initialize.c b/ruuvi_examples/ruuvi_firmware/initialize.c new file mode 100644 index 00000000..3b69f99d --- /dev/null +++ b/ruuvi_examples/ruuvi_firmware/initialize.c @@ -0,0 +1,324 @@ +#include +#include +#include + +// Nordic SDK +#include "ble_advdata.h" +#include "ble_advertising.h" +#include "ble_radio_notification.h" +#include "nordic_common.h" +#include "softdevice_handler.h" +#include "app_scheduler.h" +#include "app_timer_appsh.h" +#include "nrf_drv_clock.h" +#include "nrf_gpio.h" +#include "nrf_drv_gpiote.h" +#include "nrf_delay.h" + +#define NRF_LOG_MODULE_NAME "INITIALIZE" +#include "nrf_log.h" +#include "nrf_log_ctrl.h" + +// BSP Board Support Package : +#include "bsp.h" + +// Drivers +#include "flash.h" +#include "lis2dh12.h" +#include "lis2dh12_acceleration_handler.h" +#include "bme280.h" +#include "battery.h" +#include "bluetooth_core.h" +#include "eddystone.h" +#include "pin_interrupt.h" +#include "nfc.h" +#include "nfc_t2t_lib.h" +#include "rtc.h" +#include "application_config.h" + +// Libraries +#include "sensortag.h" + +// Init +#include "init.h" +#include initialize.h + +// Configuration +#include "bluetooth_config.h" // including REVision, intervals, APP_TX_POWER + + +// ID for main loop timer. +APP_TIMER_DEF(main_timer_id); // Creates timer id for our program. +APP_TIMER_DEF(reset_timer_id); // Creates timer id for our program. + +// +// initalize "tunables" from header file values. Might be changed by NFC command: (some day) +static uint16_t ble_tx_power = BLE_TX_POWER; +static uint16_t advertising_interval_highres = ADVERTISING_INTERVAL_RAW; // why are these even different?? +static uint16_t advertising_interval_raw = ADVERTISING_INTERVAL_RAW; +static uint16_t advertising_interval_url = ADVERTISING_INTERVAL_URL; +static uint16_t advertising_interval; +static uint32_t main_loop_interval_raw = MAIN_LOOP_INTERVAL_RAW; +static uint32_t main_loop_interval_url = MAIN_LOOP_INTERVAL_URL; +static uint32_t main_loop_interval; +static uint16_t battery_min_v = BATTERY_MIN_V; + + + +static uint16_t init_status = 0; // combined status of all initalizations. Zero when all are complete if no errors occured. +#define LOG_FAILED_INIT 0x0002 +#define ACCELEROMETER_FAILED_INIT 0x0004 +#define TEMP_HUM_PRESS_FAILED_INIT 0x0008 +#define NFC_FAILED_INIT 0x0010 +#define BLE_FAILED_INIT 0x0020 +#define TIMER_FAILED_INIT 0x0040 +#define RTC_FAILED_INIT 0x0080 +#define PIN_ENA_FAILED_INIT 0x0200 +#define ACCEL_INT_FAILED_INIT 0x0400 +#define ACC_INT_FAILED_INIT 0x0800 +#define BATTERY_FAILED_INIT 0x1000 +#define BUTTON_FAILED_INIT 0x2000 +#define BME_FAILED_INIT 0x4000 + +// File and record for app mode +#define FDS_FILE_ID 1 +#define FDS_RECORD_ID 1 + +// define unconfusing macros for LEDs +#define RED_LED_ON nrf_gpio_pin_clear(LED_RED) +#define RED_LED_OFF nrf_gpio_pin_set(LED_RED) +#define GREEN_LED_ON nrf_gpio_pin_clear(LED_GREEN) +#define GREEN_LED_OFF nrf_gpio_pin_set(LED_GREEN) + +static uint8_t data_buffer[RAWv2_DATA_LENGTH] = { 0 }; +static bool model_plus = false; // Flag for sensors available +static bool fast_advertising = true; // Connectable mode +static uint64_t fast_advertising_start = 0; // Timestamp of when tag became connectable +static uint64_t debounce = 0; // Flag for avoiding double presses +static uint16_t acceleration_events = 0; // Number of times accelerometer has triggered +static volatile uint16_t vbat = 0; //Update in interrupt after radio activity. +static uint64_t last_battery_measurement = 0; // Timestamp of VBat update. +static ruuvi_sensor_t data; +static uint8_t advertisement_delay = 0; //Random, static delay to reduce collisions. +static uint8_t NFC_message[100]; // NFC message buffer has 4 records, up to 128 bytes each minus some overhead for NFC NDEF data keeping. +static size_t NFC_message_length = sizeof(NFC_message); + +// Possible modes of the app +#define RAWv1 0 +#define RAWv2_FAST 1 +#define RAWv2_SLOW 2 + +// Must be UINT32_T as flash storage operated in 4-byte chunks +// Will get loaded from flash, this is default. +static uint32_t tag_mode __attribute__ ((aligned (4))) = RAWv1; +// Rates of advertising. These must match the tag mode enum. +static const uint16_t advertising_rates[] = { + ADVERTISING_INTERVAL_RAW, + ADVERTISING_INTERVAL_RAW, + ADVERTISING_INTERVAL_RAW_SLOW +}; +// Rates of advertising. These must match the tag mode enum. +static const uint16_t advertising_sizes[] = { + RAWv1_DATA_LENGTH, + RAWv2_DATA_LENGTH, + RAWv2_DATA_LENGTH +}; + +// Prototype declaration +static void main_timer_handler(void * p_context); + +int initialize(void) +{ + // LEDs first (they're easy and cannot fail) drivers/init/init.c + init_leds(); + RED_LED_ON; + + if( init_log() ) { init_status |=LOG_FAILED_INIT; } + else { NRF_LOG_INFO("LOG initalized \r\n"); } // subsequent initalizations assume log is working + + + // tuneables retained in UICR start at 4 since some Nordic guys use 1... + // is UICR appropriate for this version of the program; if not go with factory defaults defined in .h + int version[3]; sscanf(INIT_FWREV, "%1d%1c%1d%1c%1d", &version[0],&x,&version[1],&x, &version[2]); + if ( ( NRF_FICR->UICR[0]&& 0xFFFF00) == version[0] **24 + version[1] **16 + version[2] **8 ) // any minor-minor verion + { + password = + packet_format = NRF_FICR->UICR[4] & 0xF0000000 >> 28; // 0..15 Example: 03 , 05 + ble_tx_power = NRF_FICR->UICR[4] & 0x0F000000 >> 24; // 0 .. 16 ( -xxdB ??) + main_loop_interval = NRF_FICR->UICR[4] & 0x00FFFFFF ; // 1 .. 16,777.215 seconds aka 279 minutes Example: 3E8 1,000ms + advertising_interval = NRF_FICR->UICR[5] & 0x00FFFFFF ; // 1 .. aka 4.66 hours 7DA 2,010ms + accel_sample_rate = NRF_FICR->UICR[5] & 0xF0000000 >>24; // 0 .. 7 LIS2DH12_RATE_400 = 7<<4 see drivers/lis2dh12/lis2dh12.h + accel_resolution = NRF_FICR->UICR[5] & 0x0F000000 >>24; // 0 .. F 8,6,4 + humidity_oversampling = NRF_FICR->UICR[6] & 0xFF000000 >>24; // uint_8 + temperature_oversampling = NRF_FICR->UICR[6] & 0x00FF0000 >>16; + pressure_oversampling = NRF_FICR->UICR[6] & 0x0000FF00 >> 8; + bme280_IIR = NRF_FICR->UICR[7] & 0xFF000000 >>24; // uint_8 + bme280_delay = NRF_FICR->UICR[7] & 0x00FF0000 >>24; // uint_8 + battery_min_v = (NRF_FICR->UICR[6] & 0x0000000F) * 100 +2000; // 2.000-2.800 Example 2.100 = 01 *100 +2000 + // 2.200 = 02 *100 +2000 + // 3.000 = 0A *100 +2000 +// available 6 000000F0 +// available 7 0000FFFF + } + +// example 540007DA 360007DA 0A0A0A08 +// fmt 5, Tx 4, loop 2.01 Hos=Tos=Pos=10 +// acc_samp 3 batMin 2.800 +// acc_reso 6 +// advertis 2.100 + + + // start watchdog now in case program hangs up. + // watchdog_default_handler logs error and resets the tag. + init_watchdog(NULL); + + // Battery voltage initialization cannot fail under any reasonable circumstance. + battery_voltage_init(); + vbat = getBattery(); + + if( vbat < BATTERY_MIN_V ) { init_status |=BATTERY_FAILED_INIT; } + else NRF_LOG_INFO("BATTERY initalized \r\n"); + + if(init_sensors() == NRF_SUCCESS ) + { + model_plus = true; + NRF_LOG_INFO("Sensors initialized \r\n"); + } + + // Init NFC ASAP in case we're waking from deep sleep via NFC (todo) + // outputs ID:DEVICEID ,MAC:DEVICEADDR, SW:REVision + set_nfc_callback(app_nfc_callback); + if( init_nfc() ) { init_status |= NFC_FAILED_INIT; } + else { NRF_LOG_INFO("NFC init \r\n"); } + + pin_interrupt_init(); + + if( pin_interrupt_enable(BSP_BUTTON_0, NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIO_PIN_PULLUP, button_press_handler) ) + { + init_status |= BUTTON_FAILED_INIT; + } + + // Initialize BLE Stack. Starts LFCLK required for timer operation. + if( init_ble() ) { init_status |= BLE_FAILED_INIT; } + bluetooth_configure_advertisement_type(STARTUP_ADVERTISEMENT_TYPE); + bluetooth_tx_power_set(BLE_TX_POWER); + bluetooth_configure_advertising_interval(ADVERTISING_INTERVAL_STARTUP); + advertisement_delay = NRF_FICR->DEVICEID[0]&0x0F; + + // Priorities 2 and 3 are after SD timing critical events. + // 6, 7 after SD non-critical events. + // Triggers ADC, so use 3. + ble_radio_notification_init(3, + NRF_RADIO_NOTIFICATION_DISTANCE_800US, + on_radio_evt); + + // If GATT is enabled BLE init inits peer manager which uses flash. + // BLE init should handle insufficient space gracefully (i.e. erase flash and proceed). + // Flash must be initialized after softdevice. + if(flash_init()) + { + NRF_LOG_ERROR("Failed to init flash \r\n"); + } + size_t flash_space_remaining = 0; + flash_free_size_get(&flash_space_remaining); + NRF_LOG_INFO("Largest continuous space remaining %d bytes\r\n", flash_space_remaining); + if(4000 > flash_space_remaining) + { + NRF_LOG_INFO("Flash space is almost used, running gc\r\n") + flash_gc_run(); + flash_free_size_get(&flash_space_remaining); + NRF_LOG_INFO("Continuous space remaining after gc %d bytes\r\n", flash_space_remaining); + } + else if (flash_record_get(FDS_FILE_ID, FDS_RECORD_ID, sizeof(tag_mode), &tag_mode)) + { + NRF_LOG_INFO("Did not find mode in flash, is this first boot? \r\n"); + } + else + { + NRF_LOG_INFO("Loaded mode %d from flash\r\n", tag_mode); + } + + if( init_rtc() ) { init_status |= RTC_FAILED_INIT; } + else { NRF_LOG_INFO("RTC initialized \r\n"); } + + // Initialize lis2dh12 and BME280 - TODO: Differentiate LIS2DH12 and BME280 + if (model_plus) + { + lis2dh12_reset(); // Clear memory. + + // Enable Low-To-Hi rising edge trigger interrupt on nRF52 to detect acceleration events. + if (pin_interrupt_enable(INT_ACC2_PIN, NRF_GPIOTE_POLARITY_LOTOHI, NRF_GPIO_PIN_NOPULL, lis2dh12_int2_handler) ) + { + init_status |= ACC_INT_FAILED_INIT; + } + + nrf_delay_ms(10); // Wait for LIS reboot. + // Enable XYZ axes. + lis2dh12_enable(); + lis2dh12_set_scale(LIS2DH12_SCALE); + lis2dh12_set_sample_rate(LIS2DH12_SAMPLERATE_RAWv1); + lis2dh12_set_resolution(LIS2DH12_RESOLUTION); + + lis2dh12_set_activity_interrupt_pin_2(LIS2DH12_ACTIVITY_THRESHOLD); + NRF_LOG_INFO("Accelerometer configuration done \r\n"); + + // oversampling must be set for each used sensor. + bme280_set_oversampling_hum (BME280_HUMIDITY_OVERSAMPLING); + bme280_set_oversampling_temp (BME280_TEMPERATURE_OVERSAMPLING); + bme280_set_oversampling_press(BME280_PRESSURE_OVERSAMPLING); + bme280_set_iir(BME280_IIR); + bme280_set_interval(BME280_DELAY); + bme280_set_mode(BME280_MODE_NORMAL); + NRF_LOG_INFO("BME280 configuration done \r\n"); + } + + // Enter stored mode after boot - or default mode if store mode was not found + app_sched_event_put (&tag_mode, sizeof(&tag_mode), change_mode); + + // Initialize repeated timer for sensor read and single-shot timer for button reset + if( init_timer(main_timer_id, APP_TIMER_MODE_REPEATED, MAIN_LOOP_INTERVAL_RAW, main_timer_handler) ) + { + init_status |= TIMER_FAILED_INIT; + } + + if( init_timer(reset_timer_id, APP_TIMER_MODE_SINGLE_SHOT, BUTTON_RESET_TIME, reboot) ) + { + init_status |= TIMER_FAILED_INIT; + } + // Init starts timers, stop the reset + app_timer_stop(reset_timer_id); + + // Log errors, add a note to NFC, blink RED to visually indicate the problem + if (init_status) + { + snprintf((char* )NFC_message, NFC_message_length, "Error: %X", init_status); + NRF_LOG_WARNING (" -- Initalization error : %X \r\n", init_status); + for ( int16_t i=0; i<13; i++) + { + RED_LED_ON; + nrf_delay_ms(500u); + RED_LED_OFF; + nrf_delay_ms(500u); + } + } + + // Turn green led on if model+ with no errors. + // Power manage turns led off + if (model_plus & !init_status) + { + GREEN_LED_ON; + } + + // Turn off red led, leave green on to signal model+ without errors + RED_LED_OFF; + + nrf_delay_ms( sample_interval * 2); // Wait for sensors to take first sample + // Get first sample from sensors + app_sched_event_put (NULL, 0, main_sensor_task); + app_sched_execute(); + + // Start advertising + bluetooth_advertising_start(); + NRF_LOG_INFO("Advertising started\r\n"); + +} diff --git a/ruuvi_examples/ruuvi_firmware/initialize.h b/ruuvi_examples/ruuvi_firmware/initialize.h new file mode 100644 index 00000000..54eec612 --- /dev/null +++ b/ruuvi_examples/ruuvi_firmware/initialize.h @@ -0,0 +1,3 @@ + + +#define BATTERY_MIN_V 2300 /// Millivolts, this value should be high enough to not trigger error on a tag on a freezer From 971afcb721894c8dc8ce7ff9ae1bb7844c9b7f3f Mon Sep 17 00:00:00 2001 From: Dennis German Date: Tue, 5 Mar 2019 21:31:34 -0500 Subject: [PATCH 5/5] more packet formatters from library move packet formatters from library to same directory as main. add errorPacket remove URL code A work in progress --- ruuvi_examples/ruuvi_firmware/packit.c | 139 +++++++++++++++++++++++++ ruuvi_examples/ruuvi_firmware/packit.h | 63 +++++++++++ 2 files changed, 202 insertions(+) create mode 100644 ruuvi_examples/ruuvi_firmware/packit.c create mode 100644 ruuvi_examples/ruuvi_firmware/packit.h diff --git a/ruuvi_examples/ruuvi_firmware/packit.c b/ruuvi_examples/ruuvi_firmware/packit.c new file mode 100644 index 00000000..75fa5e1e --- /dev/null +++ b/ruuvi_examples/ruuvi_firmware/packit.c @@ -0,0 +1,139 @@ +// 03/03/19 Remove URL code +// 01/07/19 Don't change temperature, pressure in structure! +// add (restore) encodeToSensorDataFormat format v1 (03) +#include "packit.h" + +#include "nrf52.h" +#include "nrf52_bitfields.h" + +#define NRF_LOG_MODULE_NAME "PACKIT" +#include "nrf_log.h" +#include "nrf_log_ctrl.h" + +/** + * Encoded sensor values into data_buffer + * Increments packet counter + * + * @param data_buffer payload + * @param environmental Environmental data as data comes from BME280, i.e. uint32_t pressure, int32_t temperature, uint32_t humidity + * @param acceleration 3 acceleration along X-Y-Z axes in MG. Low pass and last sample are allowed DSP operations + * @param acceleration_events counter of acceleration events. Events are configured , "value exceeds 1.1 G" recommended. + * @param vbatt Voltage of battery in millivolts + * @param tx_pwr power in dBm, -40 ... 16 + * + */ +void encodeToRawFormat5(uint8_t* data_buffer, const bme280_data_t* environmental, const acceleration_t* acceleration, uint16_t acceleration_events, uint16_t vbatt, int8_t tx_pwr) +{ + static uint32_t packet_counter = 0; + + data_buffer[0] = RAW_FORMAT_2; + + int32_t temperature = environmental->temperature; + temperature *= 2; //Spec calls for 0.005 degree resolution, bme280 gives 0.01 + data_buffer [1] = (temperature)>>8; data_buffer[2] = (temperature)&0xFF; + + uint32_t humidity = environmental->humidity; + humidity *= 400; humidity /= 1024; + data_buffer [3] = humidity>>8; data_buffer[4] = humidity&0xFF; + NRF_LOG_DEBUG("Humidity is %d\r\n", humidity/400); + + uint32_t pressure = environmental->pressure; + pressure = (uint16_t)((pressure >> 8) - 50000); //Scale into pa, Shift by -50000 pa as per Ruu.vi interface. + data_buffer [5] = (pressure)>>8; data_buffer[6] = (pressure)&0xFF; + + data_buffer [7] = (acceleration->x)>>8; data_buffer[8] = (acceleration->x)&0xFF; + data_buffer [9] = (acceleration->y)>>8; data_buffer[10] = (acceleration->y)&0xFF; + data_buffer[11] = (acceleration->z)>>8; data_buffer[12] = (acceleration->z)&0xFF; + + vbatt -= 1600; //Bias by 1600 mV + vbatt <<= 5; //Shift to make room for TX PWR + data_buffer[13] = (vbatt)>>8; data_buffer[14] = (vbatt)&0xFF; + tx_pwr += 40; tx_pwr /= 2; + data_buffer[14] |= (tx_pwr)&0x1F; //5 lowest bits for TX power + + data_buffer[15] = acceleration_events % 256; // N.B. a zero does not necessarily mean no events occured! + data_buffer[16] = packet_counter>>8; data_buffer[17] = packet_counter&0xFF; + packet_counter++; + + data_buffer[18] = ((NRF_FICR->DEVICEADDR[1]>>8)&0xFF) | 0xC0; //2 MSB must be 11; + data_buffer[19] = ((NRF_FICR->DEVICEADDR[1]>>0)&0xFF); + data_buffer[20] = ((NRF_FICR->DEVICEADDR[0]>>24)&0xFF); + data_buffer[21] = ((NRF_FICR->DEVICEADDR[0]>>16)&0xFF); + data_buffer[22] = ((NRF_FICR->DEVICEADDR[0]>>8)&0xFF); + data_buffer[23] = ((NRF_FICR->DEVICEADDR[0]>>0)&0xFF); +} + +/** + * Encodes data into Ruuvi data format + * @param *data pointer to ruuvi_sensor_t object + * @param raw_t raw temperature as given by BME280, i.e 2s-complement int32_t in celcius * 100, -2134 = 21.34 + * @param raw_p raw pressure as given by BME280, uint32_t, multiplied by 256 + * @param acceleration along 3 axes in milliG, X Y Z. + */ + +void parseSensorData(ruuvi_sensor_t* data, int32_t raw_t, uint32_t raw_p, uint32_t raw_h, uint16_t vbat, int32_t acc[3]) +{ + NRF_LOG_DEBUG("temperature: %d, pressure: %d, humidity: %d\r\n", raw_t, raw_p, raw_h); + /* + 0: uint8_t format; // (0x02 = realtime sensor readings base64) + 1: uint8_t humidity; // one lsb is 0.5% + 2-3: uint16_t temperature; // Signed 8.8 fixed-point notation. + 4-5: uint16_t pressure; // (-50kPa) + */ + //Convert raw values to ruu.vi specification + //Round values: 1 deg C, 1 hPa, 1% RH + data->format = 0x00; //Will be decided in encoding phase + data->temperature = (raw_t < 0) ? 0x8000 : 0x0000; //Sign bit + if(raw_t < 0) raw_t = 0-raw_t; // disrecard sign + data->temperature |= (((raw_t / 100) << 8)); //raw_t is 2:2 signed fixed point in base-10, Drop decimals, scale up to next byte. + data->temperature |= (raw_t % 100); //take decimals. + data->pressure = (uint16_t)((raw_p >> 8) - 50000); //Scale into pa, Shift by -50000 pa as per Ruu.vi interface. + data->humidity = (uint8_t)(raw_h >> 9); //scale into 0.5% + + // Set accelerometer data + data->accX = acc[0]; + data->accY = acc[1]; + data->accZ = acc[2]; + + data->vbat = vbat; +} + +/** + * Encode sensor values from data structure into RuuviTag Raw format v1. (03) + * @param char* data_buffer character array with length of 14 bytes + */ +void encodeToSensorDataFormat(uint8_t* data_buffer, const ruuvi_sensor_t* data) +{ + //serialize values into a string + data_buffer [0] = SENSOR_TAG_DATA_FORMAT; + data_buffer [1] = data->humidity; + data_buffer [2] = (data->temperature)>>8; data_buffer [3] = (data->temperature)&0xFF; + data_buffer [4] = (data->pressure)>>8; data_buffer [5] = (data->pressure)&0xFF; + data_buffer [6] = (data->accX)>>8; data_buffer [7] = (data->accX)&0xFF; + data_buffer [8] = (data->accY)>>8; data_buffer [9] = (data->accY)&0xFF; + data_buffer[10] = (data->accZ)>>8; data_buffer[11] = (data->accZ)&0xFF; + data_buffer[12] = (data->vbat)>>8; data_buffer[13] = (data->vbat)&0xFF; +} + +//void packError( status, init_status_worst) +// // To view packet with command line utilities: +// // export bdaddr='zz yy xx ww vv uu' # MAC address least significant byte FIRST +// // hcidump --raw |g --line-buffered --after-context=2 $bdaddr +// // 04 3E 2B 02 01 00 01 C2 24 68 3C 10 C7 1F 02 01 06 03 03 AA +// // zz yy xx ww vv uu +// // FE 17 16 AA FE 10 F6 +//// 04 13 FE 1D 1D 0B AD 10 00 04 00 08 41 00 00 00 +//// I did bad ii_ss ww ww vv_vv +// ii_ss is init status (example BATTERY_FAILED_INIT); vv_vv=vbat=0x0841 ie 2.113v +// ^^ ^ init_status_worst i.e. previously ACCEL_INT_FAILED +// +//{ data_buffer[0] = 0x13 ; // errorPacket format +// data_buffer[1] = 254; +// data_buffer[2] = 11125 >>8; data_buffer[3] = 11125 & 0xFF; +// data_buffer[4] = 0x1D1D >>8; data_buffer[5] = 0x1D1D & 0xFF; +// data_buffer[6] = 0x0BAD >>8; data_buffer[7] = 0x0BAD & 0xFF; +// data_buffer[8 ] = init_status >>8; data_buffer[9] = init_status & 0xFF; // ss ss +// data_buffer[10] = init_status_worst >>8; data_buffer[11] = init_status & 0xFF; // ww ww +// data_buffer[12] = vbat >>8; data_buffer[13] = vbat & 0xFF; +// nrf_delay_ms(600u); // keep sending URL error packet for a while +//} diff --git a/ruuvi_examples/ruuvi_firmware/packit.h b/ruuvi_examples/ruuvi_firmware/packit.h new file mode 100644 index 00000000..45db5e90 --- /dev/null +++ b/ruuvi_examples/ruuvi_firmware/packit.h @@ -0,0 +1,63 @@ +#ifndef PACKIT_H +#define PACKIT_H + +#include +#include +#include "bme280.h" +#include "lis2dh12.h" + +/* +0: uint8_t format; // 03 = realtime sensor readings +1: uint8_t humidity; // one lsb is 0.5% +2-3: uint16_t temperature; // Signed 8.8 fixed-point notation. +4-5: uint16_t pressure; // (-50kPa) +6-7: int16_t acceleration_x; // mg +8-9: int16_t acceleration_y; // mg +10-11: int16_t acceleration_z; // mg +12-13: int16_t vbat; // mv +*/ +#define SENSOR_TAG_DATA_FORMAT 0x03 /**< raw binary, includes acceleration */ +#define SENSORTAG_ENCODED_DATA_LENGTH 14 + +#define RAW_FORMAT_2 0x05 /**< includes Tx power, movement counter, Seq number and MAC +#define RAW_2_ENCODED_DATA_LENGTH 24 /**< see https://f.ruuvi.com/t/proposed-next-high-precision-data-format/692 */ + +// Sensor values +typedef struct +{ +uint8_t format; // 0x00 ... 0x09 for official Ruuvi applications +uint8_t humidity; // one lsb is 0.5% +uint16_t temperature; // Signed 8.8 fixed-point notation. +uint16_t pressure; // Pascals (pa) +int16_t accX; // Milli-g (mg) +int16_t accY; +int16_t accZ; +uint16_t vbat; // mv +}ruuvi_sensor_t; + +/** + * Parses data into Ruuvi data format scale + * @param *data pointer to ruuvi_sensor_t object + * @param raw_t raw temperature as given by BME280, i.e 2s-complement int32_t in celcius * 100, -2134 = 21.34 + * @param raw_p raw pressure as given by BME280, uint32_t, multiplied by 256 + * @param acceleration along 3 axes in milliG, X Y Z. + */ +void parseSensorData(ruuvi_sensor_t* data, int32_t raw_t, uint32_t raw_p, uint32_t raw_h, uint16_t vbat, int32_t acc[3]); + +/** + * Parses sensor values into RuuviTag format. + * @param char* data_buffer character array with length of 14 bytes + */ +void encodeToSensorDataFormat(uint8_t* data_buffer, const ruuvi_sensor_t* data); + +/** + * Parses sensor values into format. + * @param data_buffer uint8_t array with length of 24 bytes + * @param environmental Environmental data as data comes from BME280, i.e. uint32_t pressure, int32_t temperature, uint32_t humidity + * @param acceleration 3 x int16_t having acceleration along X-Y-Z axes in MG. Low pass and last sample are allowed DSP operations + * @param acceleration_events counter of acceleration events. Events are configured by application, "value exceeds 1.1 G" recommended. + * @param vbatt Voltage of battery in millivolts + */ +void encodeToRawFormat5(uint8_t* data_buffer, const bme280_data_t* environmental, const acceleration_t* acceleration, uint16_t acceleration_events, uint16_t vbatt, int8_t tx_pwr); + +#endif