Hard Fault when calling bt_le_ext_adv_start

Hi

I am getting a hard fault when I am trying to call  bt_le_ext_adv_start(). I am not sure if it is related to the manufacturer data contents or something else.

The error code is -120. Any ideas what could that mean?

Can someone advise or suggest debugging techniques to understand what could be the problem?

Thanks

/* main.c - Application main entry point */

/*
 * Copyright (c) 2015-2016 Intel Corporation
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/devicetree.h>
#include <zephyr/drivers/sensor.h>
#include <zephyr/types.h>
#include <zephyr/logging/log.h>
#include <stdio.h>
#include <stddef.h>
#include <string.h>
#include <zephyr/sys/printk.h>
#include <zephyr/sys/util.h>
#include <zephyr/sys/util_macro.h>
#include <zephyr/drivers/i2c.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/direction.h>

#include <zephyr/bluetooth/hci.h>
#include <stdlib.h>
#include <math.h>
#include <hal/nrf_gpio.h>
#include <zephyr/drivers/adc.h>

#include "app_types.h"
#include "app_fram.h"
#include "app_encryption.h"
#include "app_accel.h"
#include "app_temp_pressure.h"
#include "zephyr/drivers/gpio.h"
#include <zephyr/init.h>
#include <zephyr/drivers/uart.h>

// conditional compile options
#define FORCE_TOGGLE (1)
#define FORCE_FRAM_VALS (0)
#define HAVE_ISL9122 (0)
#define USING_MG24 (0)
#define ENCR_KEY_IN_FRAM (0)

#define DEVICE_NAME CONFIG_BT_DEVICE_NAME
#define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1)
#define DEVICE_ID 3

#define MANUF_DATA_CUSTOM_START_INDEX   2
#define PAYLOAD_TX_REPEAT_COUNTER_INDEX 18
#define PAYLOAD_DEVICE_ID_INDEX         19
#define PAYLOAD_STATUS_BYTE_INDEX       21
#define PAYLOAD_RFU_BYTE_INDEX          22
#define PAYLOAD_ENCRYPTION_STATUS_ENC   0
#define PAYLOAD_ENCRYPTION_STATUS_CLEAR 1
#define FRAME_LENGTH                    24

#define BLE_ADV_INTERVAL_MIN            (32) // N * 0.625. corresponds to dec. 32; 32*0.625 = 20ms
#define BLE_ADV_INTERVAL_MAX            (36) // N * 0.625. corresponds to dec. 36; 36*0.625 = 22.5ms
#define BLE_ADV_TIMEOUT                 (0)  // N * 10ms for advertiser timeout
#define BLE_ADV_EVENTS                  (1)


#define PACKET_INTERVAL_MIN (10) // ms repeat rate
#define PACKET_INTERVAL_MAX (50) // ms repeat rate

#define LOGS (1) // if printk doesn't handle it use if(LOGS) printk();

#define POL_GPIO_PIN                    13

#define FIELD_NAME_MAX_LENGTH       32

/* Length of CTE in unit of 8[us] */
#define CTE_LEN (0x14U)
/* Number of CTE send in single periodic advertising train */
#define PER_ADV_EVENT_CTE_COUNT 5


struct bt_df_adv_cte_tx_param cte_params = { .cte_len = CTE_LEN,
					     .cte_count = PER_ADV_EVENT_CTE_COUNT,
#if defined(CONFIG_BT_DF_CTE_TX_AOD)
					     .cte_type = BT_DF_CTE_TYPE_AOD_2US,
					     .num_ant_ids = ARRAY_SIZE(ant_patterns),
					     .ant_ids = ant_patterns
#else
					     .cte_type = BT_DF_CTE_TYPE_AOA,
					     .num_ant_ids = 0,
					     .ant_ids = NULL
#endif /* CONFIG_BT_DF_CTE_TX_AOD */
};

enum FRAM_TYPE {
    NUMBER = 0,
    STRING,
    BYTE_ARRAY,
};

typedef struct
{
    char name[FIELD_NAME_MAX_LENGTH];
    uint8_t type;
    uint8_t field_length;
    uint32_t min_value;
    uint32_t max_value;
}fram_info_t;

const fram_info_t FRAM_INFO[MAX_FRAM_FIELDS] = {
    {"EVENT Counter", NUMBER, FRAM_COUNTER_NUM_BYTES, 0, 0xFFFFFFFF},
    {"SERIAL NUMBER", NUMBER, SER_NUM_BYTES, 0, 0xFFFFFFFF},
    {"TYPE", NUMBER, TYPE_NUM_BYTES, 0, 0xFF},
    {"EVENT INTERVAL", NUMBER, EV_INT_NUM_BYTES, 10, 100},  // advertising interval within an event
    {"EVENT MAXIMUM LIMITS", NUMBER,EV_MAX_NUM_BYTES, 1, 0xF0}, // max advertising repeats within an event
    {"EVENT MINIMUM SLEEP", NUMBER, EV_SLP_NUM_BYTES, 0, 10000}, // sleep time before next event, 0 just wastes rest of power.
    {"SLEEP AFTER WAKEUP", NUMBER, IN_SLP_NUM_BYTES, 0, 100}, // 
    {"VOLT of ISL9122", NUMBER, ISL9122_NUM_BYTES, 0, 0xFF},
    {"POL METHOD", NUMBER, POL_MET_NUM_BYTES, 0, 2},
    {"ENCRYPTED KEY", BYTE_ARRAY, ENCRYPTED_KEY_NUM_BYTES, NULL, NULL},
    {"TX dBM 10", NUMBER, TX_DBM_NUM_BYTES, 0, 200},
    {"Device NAME", STRING, NAME_NUM_BYTES, NULL, NULL}
};
/*
const char FRAM_FIELD_NAMES[MAX_FRAM_FIELDS][FIELD_NAME_MAX_LENGTH] = {
    "EVENT Counter", "SERIAL NUMBER", "TYPE", "EVENT INTERVAL", "EVENT MAXIMUM LIMITS", "EVENT MINIMUM SLEEP",
	"SLEEP AFTER WAKEUP", "VOLT of ISL9122", "POL METHOD", "ENCRYPTED KEY", "TX dBM 10", "Device NAME",};

const uint8_t FRAM_FIELD_LENGTH[MAX_FRAM_FIELDS] = {
    (FRAM_COUNTER_NUM_BYTES), SER_NUM_BYTES, TYPE_NUM_BYTES, EV_INT_NUM_BYTES, EV_MAX_NUM_BYTES, 
    EV_SLP_NUM_BYTES, IN_SLP_NUM_BYTES, ISL9122_NUM_BYTES, POL_MET_NUM_BYTES, NAME_NUM_BYTES,
};

const uint8_t bIsNumeric[MAX_FRAM_FIELDS] = {NUMBER, NUMBER, NUMBER, NUMBER, NUMBER, NUMBER, NUMBER, NUMBER, NUMBER, BYTE_ARRAY, NUMBER, STRING};

const uint32_t MinValue[MAX_FRAM_FIELDS] = {0, 0, 0, 20, 1, 0, 0, 0, 0, 0, 0, 0};
const uint32_t MaxValue[MAX_FRAM_FIELDS] = {0xFFFFFF, 0xFFFF, 0xFF, 30, 0xF0, 100, 1000, 1700, 1, 0xFF, 0xFF, 0xFF};
*/

/* Data of ADC io-channels specified in devicetree. */
static const struct adc_dt_spec adc_channel =
    ADC_DT_SPEC_GET_BY_IDX(DT_PATH(zephyr_user), 0);

#define UART_DEVICE_NODE DT_CHOSEN(zephyr_shell_uart)
#define UART_MSG_SIZE 256
/* queue to store up to 1 messages (aligned to 4-byte boundary) */
K_MSGQ_DEFINE(uart_msgq, UART_MSG_SIZE, 1, 4);
static const struct device *const uart_dev = DEVICE_DT_GET(UART_DEVICE_NODE);
static struct k_work process_command_task;

/* receive buffer used in UART ISR callback */
static uint8_t rx_buf[UART_MSG_SIZE];
static int rx_buf_pos;

static void timer_event_handler(struct k_timer *dummy);
static void timer_event_handler2(struct k_timer *dummy);

K_TIMER_DEFINE(timer_event, timer_event_handler, NULL);
K_TIMER_DEFINE(timer_event2, timer_event_handler2, NULL);

static struct k_work start_advertising_worker;
static struct k_work start_timer_task;
static struct k_work_delayable update_frame_work;

static we_power_data_ble_adv_t we_power_data;
static struct bt_data we_power_adv_data;
static struct bt_le_ext_adv *adv;

// variable to store the FRAM data
static fram_data_t fram_data = {0};
//static u16_u8_t device_id;
static uint8_t TX_Repeat_Counter;
static uint8_t TX_Repeat_Counter_Init = 1;  

uint32_t serial_number = DEVICE_ID;
uint8_t  type = 1;
uint8_t  event_inteval = 20;
uint16_t event_max_limits = 240;
uint16_t sleep_min_interval = 200;
uint16_t sleep_after_wake = 0; // assumes sleep(0) is just a yield()
uint8_t u8Polarity = 0;

uint8_t bPressureRequested = 0;

extern uint8_t ecb_key[16];
static const struct device *dev_uart;


struct bt_le_adv_param param =
		BT_LE_ADV_PARAM_INIT(
				     BT_LE_ADV_OPT_EXT_ADV | BT_LE_ADV_OPT_USE_IDENTITY | BT_LE_ADV_OPT_USE_NAME,
				     BLE_ADV_INTERVAL_MIN,
				     BLE_ADV_INTERVAL_MAX,
				     NULL);




typedef struct
{
    uint8_t type;
    int8_t field_index;
    uint8_t data_len;
    uint8_t data[(UART_MSG_SIZE - 3)];
}command_data_t;

command_data_t command_data = {0};
//                                                    |--------- ENCRYPTED ENCRYPTED ENCRYPTED ENCRYPTED ENCRYPTED ENCRYPTED ENCRYPTED ------------ |  cnt    id    id  status RFU
static uint8_t manf_data[FRAME_LENGTH] = { 0x50, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F};
static struct bt_data ad[] = {
	BT_DATA_BYTES(BT_DATA_FLAGS, BT_LE_AD_NO_BREDR),
    BT_DATA(BT_DATA_MANUFACTURER_DATA, manf_data, FRAME_LENGTH),
	BT_DATA_BYTES(BT_DATA_UUID16_ALL, 0x50, 0x57)
};


//JPTV Vars
static uint16_t timer_flag = 0;
#define DURATION 1000
#define PERIOD 50

static void adv_sent(struct bt_le_ext_adv *instance,
		     struct bt_le_ext_adv_sent_info *info)
{	
	if (FORCE_TOGGLE || (fram_data.u8_POLmethod == OUT_POL)) nrf_gpio_pin_toggle(POL_GPIO_PIN);
}


static const struct bt_le_ext_adv_cb adv_cb = {
		.sent = adv_sent,
	};


static void init_gpio_fn(void)
{
    #if (FORCE_TOGGLE)
    	nrf_gpio_cfg_output(POL_GPIO_PIN); 
        nrf_gpio_pin_toggle(POL_GPIO_PIN);
    #endif 
}

SYS_INIT(init_gpio_fn, POST_KERNEL, 0); // Define the Initi function of System

void print_uart(char *buffer)
{
	int msg_len = strlen(buffer);

	for (int i = 0; i < msg_len; i++) {
		uart_poll_out(dev_uart, buffer[i]);
	}

    uart_poll_out(dev_uart, '\n');
}

void parse_command(uint8_t *buf)
{
    uint8_t space_idx = 0;
    uint8_t data_idx = 0;

    memset(&command_data, 0x00, sizeof(command_data_t));

    for (uint8_t i=0; buf[i]!='\0'; i++){
        if ((buf[i] == ' ') && (space_idx < 2)){
            space_idx++;

            if ((space_idx == 2) || (command_data.field_index == NAME)){
                memset(&command_data.data, ' ', NAME_NUM_BYTES); // init cName with space character
            }
        }
        else{
            if (space_idx == 0){
                command_data.type = buf[i];
            }
            else if (space_idx == 1){
                if (command_data.type == 'K') { // K command
                    command_data.type = 'S';
                    command_data.field_index = ENCRYPTED_KEY;
                    space_idx = 2;
                }
                else if (command_data.type == 'N'){ // N command
                    command_data.type = 'S';
                    command_data.field_index = NAME;
                    memset(&command_data.data, ' ', NAME_NUM_BYTES); // init cName with space character
                    space_idx = 2;
                }
                else {
                    if ((buf[i] >= 48) && (buf[i] <= 57)){
                        command_data.field_index = command_data.field_index * 10 + (buf[i] - 48);
                    }
                    else {
                        command_data.field_index = -1;
                    }
                }
            }
            
            if(space_idx == 2){
                if(command_data.field_index == ENCRYPTED_KEY){
                    if((buf[i] >= '0') && (buf[i] <= '9')) {
                        command_data.data[data_idx] = command_data.data[data_idx] * 16 + (buf[i] - 48);
                    }
                    else if ((buf[i] >= 'a') && (buf[i] <= 'f')){
                        command_data.data[data_idx] = command_data.data[data_idx] * 16 + (buf[i] - 87);
                    }
                    else if ((buf[i] >= 'A') && (buf[i] <= 'F')){
                        command_data.data[data_idx] = command_data.data[data_idx] * 16 + (buf[i] - 55);
                    }
                    else if (buf[i] == ' '){
                        data_idx++;
                    }
                }
                else {
                    command_data.data[data_idx] = buf[i];
                    data_idx++;
                }
            }
        }
    }

    command_data.data_len = data_idx;
}

int process_command_fn(struct k_work *work)
{
    uint8_t response[256] = {0};
    uint8_t encrypted_key_str[(3 * ENCRYPTED_KEY_NUM_BYTES) + 1] = {0};
    uint32_t field_data = 0;

    printk("Parsed Command is Type: %c, field: %d, data: %s\n", command_data.type, command_data.field_index, command_data.data);

    if(command_data.field_index >= MAX_FRAM_FIELDS){
        sprintf(response, "FRAM field %d does not exist\n", command_data.field_index);
        printk("%s\n", response);
        print_uart(response);
        return -EINVAL;
    }
    else if (command_data.field_index < 0){
        sprintf(response, "FRAM field %d is invalid.\n", command_data.field_index);
        printk("%s\n", response);
        print_uart(response);
        return -EINVAL;
    }

    if ((command_data.type == 'G') || (command_data.type == 'g'))
    {
        if ( app_fram_read_field(command_data.field_index, command_data.data) == FRAM_SUCCESS){
            if (FRAM_INFO[command_data.field_index].type == NUMBER){
                memcpy(&field_data, command_data.data, FRAM_INFO[command_data.field_index].field_length);
                sprintf(response, "FRAM field %s, length, %d, value is %d.\n", 
                        FRAM_INFO[command_data.field_index].name, FRAM_INFO[command_data.field_index].field_length, field_data);
            }
            else if (FRAM_INFO[command_data.field_index].type == STRING){
                sprintf(response, "FRAM field %s, length, %d, value is %s.\n", 
                        FRAM_INFO[command_data.field_index].name, FRAM_INFO[command_data.field_index].field_length, command_data.data);
            }
            else if (FRAM_INFO[command_data.field_index].type == BYTE_ARRAY){
                for (uint8_t i = 0; i < ENCRYPTED_KEY_NUM_BYTES; i++){
                    sprintf(&encrypted_key_str[(i * 3)], "%02X ", command_data.data[i]);
                }
                encrypted_key_str[(3*ENCRYPTED_KEY_NUM_BYTES - 1)] = '.';
                sprintf(response, "FRAM field %s, length, %d, value is 0x%s\n", 
                        FRAM_INFO[command_data.field_index].name, FRAM_INFO[command_data.field_index].field_length, encrypted_key_str);
            }
        }
        else{
            sprintf(response, "Access to FRAM failed.\n");
        }
    }
    else if ((command_data.type == 'S') || (command_data.type == 's')){
        if (FRAM_INFO[command_data.field_index].type == NUMBER){ //Numeric
            for (uint8_t i = 0; i < command_data.data_len; i++){
                field_data = field_data * 10 + (command_data.data[i] - 48);
            }

            printk(" Numeric Data: %d\n", field_data);

            if(field_data < FRAM_INFO[command_data.field_index].min_value){
                if (app_fram_read_field(command_data.field_index, &field_data) == FRAM_SUCCESS){
                    sprintf(response, "FRAM field %s, Min limit %d, Value is %d.\n", 
                        FRAM_INFO[command_data.field_index].name, FRAM_INFO[command_data.field_index].min_value, field_data);
                }else{
                    sprintf(response, "Access to FRAM failed.\n");
                }
            }
            else if (field_data > FRAM_INFO[command_data.field_index].max_value){
                if (app_fram_read_field(command_data.field_index, &field_data) == FRAM_SUCCESS){
                    sprintf(response, "FRAM field %s, Max limit %d exceeded, Value is %d.\n", 
                        FRAM_INFO[command_data.field_index].name, FRAM_INFO[command_data.field_index].max_value, field_data);
                } else {
                    sprintf(response, "Access to FRAM failed.\n");
                }
            }
            else {
                if (app_fram_write_field(command_data.field_index, &field_data) == FRAM_SUCCESS){
                    sprintf(response, "FRAM field %s, Value is %d.\n", FRAM_INFO[command_data.field_index].name, field_data);
                }
                else {
                    sprintf(response, "Access to FRAM failed.\n");
                }
            }   
        }
        else if(FRAM_INFO[command_data.field_index].type == STRING){ //String
            if (command_data.data_len > FRAM_INFO[command_data.field_index].field_length){
                if (app_fram_read_field(command_data.field_index, &command_data.data) == FRAM_SUCCESS){
                    sprintf(
                        response, 
                        "Number of characters exceeds maximum length of 10 bytes. FRAM field %s, length exceeded, Value is %s.\n", 
                        FRAM_INFO[command_data.field_index].name, command_data.data
                    );
                }
                else{
                    sprintf(response, "Access to FRAM failed.\n");
                }
            }
            else{
                if(app_fram_write_field(command_data.field_index, command_data.data) == FRAM_SUCCESS){
                    sprintf(
                        response, 
                        "Fram field %s, length %d, value is %s.\n",
                        FRAM_INFO[command_data.field_index].name, FRAM_INFO[command_data.field_index].field_length, command_data.data
                    );
                } else {
                    sprintf(response, "Access to FRAM failed.\n");
                }
            }
        }
        else if (FRAM_INFO[command_data.field_index].type == BYTE_ARRAY){
            if(app_fram_write_field(command_data.field_index, command_data.data) == FRAM_SUCCESS){
                for (uint8_t i = 0; i < ENCRYPTED_KEY_NUM_BYTES; i++){
                    sprintf(&encrypted_key_str[(i * 3)], "%02X ", command_data.data[i]);
                }
                encrypted_key_str[(3*ENCRYPTED_KEY_NUM_BYTES - 1)] = '.';
                sprintf(response, "FRAM field %s, length, %d, value is 0x%s\n", 
                        FRAM_INFO[command_data.field_index].name, FRAM_INFO[command_data.field_index].field_length, encrypted_key_str);       
            } else {
                sprintf(response, "Access to FRAM failed.\n");
            }
        }
    }
    else if ((command_data.type == 'C') || (command_data.type == 'c')){
        if (FRAM_INFO[command_data.field_index].type == NUMBER){
            field_data = 0;
            if (app_fram_write_field(command_data.field_index, &field_data) == FRAM_SUCCESS){
                sprintf(response, "FRAM field %s, Value is %d.\n", FRAM_INFO[command_data.field_index].name, field_data);
            }
            else {
                sprintf(response, "Access to FRAM failed.\n");
            }
        }
        else if (FRAM_INFO[command_data.field_index].type == STRING){
            memset(command_data.data, ' ', FRAM_INFO[command_data.field_index].field_length);
            if(app_fram_write_field(command_data.field_index, command_data.data) == FRAM_SUCCESS){
                sprintf(response, "FRAM field %s, Value is \"%s\".\n", FRAM_INFO[command_data.field_index].name, field_data);
            }
            else{
                sprintf(response, "Access to FRAM failed.\n");
            }
        }
        else if (FRAM_INFO[command_data.field_index].type == BYTE_ARRAY){
            memset(command_data.data, 0x00, FRAM_INFO[command_data.field_index].field_length);
            if(app_fram_write_field(command_data.field_index, command_data.data) == FRAM_SUCCESS){
                sprintf(response, "FRAM field %s, Value is \"%s\".\n", FRAM_INFO[command_data.field_index].name, field_data);
            }
            else{
                sprintf(response, "Access to FRAM failed.\n");
            }
        }
    }

    printk("%s",response);
    print_uart(response);
    return 0;
}
/*
 * Read characters from UART until line end is detected. Afterwards push the
 * data to the message queue.
 */
void serial_cb(const struct device *dev, void *user_data)
{
	uint8_t c;

	if (!uart_irq_update(uart_dev)) {
		return;
	}

	if (!uart_irq_rx_ready(uart_dev)) {
		return;
	}

	/* read until FIFO empty */
	while (uart_fifo_read(uart_dev, &c, 1) == 1) {
		if ((c == '\n' || c == '\r') && rx_buf_pos > 0) {
			/* terminate string */
			rx_buf[rx_buf_pos] = '\0';

            if(LOGS){
                printk("--------- UART Received Data -------------\n ");
                for (int i = 0; i < rx_buf_pos; i++){
                    printk("%c", rx_buf[i]);
                }
                printk("\n");
            }

			/* if queue is full, message is silently dropped */
			k_msgq_put(&uart_msgq, &rx_buf, K_NO_WAIT);
            parse_command(rx_buf);
            /* reset the buffer (it was copied to the msgq) */
			rx_buf_pos = 0;

            k_work_submit(&process_command_task);

          
		} else if (rx_buf_pos < (sizeof(rx_buf) - 1)) {
			rx_buf[rx_buf_pos++] = c;
		}
		/* else: characters beyond buffer size are dropped */
	}
}

static int init_uart(void)
{
    dev_uart = device_get_binding("UART_0");
	if (dev_uart == NULL) {
		printk("Failed to get UART binding\n");
		return;
	}

    if (!device_is_ready(dev_uart)) {
		printk("UART device not found!");
		return 0;
	}

	// configure interrupt and callback to receive data 
	int ret = uart_irq_callback_user_data_set(dev_uart, serial_cb, NULL);

	if (ret < 0) {
		if (ret == -ENOTSUP) {
			printk("Interrupt-driven UART API support not enabled\n");
		} else if (ret == -ENOSYS) {
			printk("UART device does not support interrupt-driven API\n");
		} else {
			printk("Error setting UART callback: %d\n", ret);
		}
		return 0;
	}
	uart_irq_rx_enable(dev_uart);
    
    printk("UART is initiated.\n");

    return 0;
}


static int create_advertising(void)
{
	int err;

	err = bt_le_ext_adv_create(&param, &adv_cb, &adv);
	if (err) {
		printk("Failed to create advertiser set (%d)\n", err);
		return err;
	}

	printk("Created adv: %p\n", adv);

	return 0;
}

void start_advertising(struct k_work *work)
{
	int err;

     if(LOGS){
        printk("Manufacturer Data: ");
        for (uint8_t i = 0; i < FRAME_LENGTH; i++){
            printk("%02X ", manf_data[i]);
        }
        printk("\n");
    }

	err = bt_le_ext_adv_set_data(adv, ad, ARRAY_SIZE(ad), NULL, 0);
	if (err) {
		printk("Failed to set advertising data (%d)\n", err);
		return err;
	}

	err = bt_le_ext_adv_start(adv, BT_LE_EXT_ADV_START_PARAM(BLE_ADV_TIMEOUT, BLE_ADV_EVENTS));
	if (err) {
		printk("Failed to start advertising set (%d)\n", err);
		return;
	}
}


void start_task_periodic(struct k_work *work)
{


}



void start_ble_adv(void)
{
	int err;

     if(LOGS){
        printk("Manufacturer Data: ");
        for (uint8_t i = 0; i < FRAME_LENGTH; i++){
            printk("%02X ", manf_data[i]);
        }
        printk("\n");
    }

	err = bt_le_ext_adv_set_data(adv, ad, ARRAY_SIZE(ad), NULL, 0);
	if (err) {
		printk("Failed to set advertising data (%d)\n", err);
		return err;
	}

	err = bt_le_ext_adv_start(adv, BT_LE_EXT_ADV_START_PARAM(BLE_ADV_TIMEOUT, BLE_ADV_EVENTS));
	if (err) {
		printk("Failed to start advertising set (%d)\n", err);
		return;
	}
}


static void bt_ready(void)
{
	int err = 0;

	printk("Bluetooth initialized\n");

	err = create_advertising();
	if (err) {
		printk("Advertising failed to create (err %d)\n", err);
		return;
	}
    
}

// hopefully it is valid to do this in a timer event
void burn_energy()
{
	volatile double foo = 3.0;
	while (1)
	{
		foo = sqrt(foo);
		foo = foo * foo;
	}
}

static void timer_event_handler(struct k_timer *dummy)
{
    TX_Repeat_Counter++;
    //TODO JPTV: Replace back the FRAM Variable
    //if (TX_Repeat_Counter <= fram_data.event_max_limits) // starts at 0, we send 1 if max is 1 by incrementing after the test.
    if (TX_Repeat_Counter <= 5) // starts at 0, we send 1 if max is 1 by incrementing after the test.
    {
        manf_data[PAYLOAD_TX_REPEAT_COUNTER_INDEX] = TX_Repeat_Counter;
        k_work_submit(&start_advertising_worker);
    }
    else {
        printk(">>> Sent maximum packets.\n");
        TX_Repeat_Counter = TX_Repeat_Counter_Init;
        k_timer_stop(&timer_event);
		if (fram_data.sleep_min_interval)
			k_work_schedule(&update_frame_work, K_MSEC(fram_data.sleep_min_interval));
		//else
		//	burn_energy(); // TODO - if it is not legal to do a while(1) in a handler, then queue this up.
    }
}


static void timer_event_handler2(struct k_timer *dummy)
{
    timer_flag++;

    if(timer_flag<500)
        start_ble_adv();
    else
        timer_flag = 600;
}


static void measure_sensors(we_power_data_ble_adv_t *we_power_data)
{
     // Get the accelerometer data
    static accel_data_t accel_data;
    if(app_accel_service(&accel_data) == ACCEL_SUCCESS)
    {
        // Success!
        we_power_data->data_fields.accel_x.i16 = accel_data.x_accel;
        we_power_data->data_fields.accel_y.i16 = accel_data.y_accel;
        we_power_data->data_fields.accel_z.i16 = accel_data.z_accel;
    }
    else
    {
        we_power_data->data_fields.accel_x.i16 = 0xFFFF;
        we_power_data->data_fields.accel_y.i16 = 0xFFFF;
        we_power_data->data_fields.accel_z.i16 = 0xFFFF;
    }

    // Get temp and pressure
    temp_pressure_data_t temp_pressure_data;
    if(app_temp_pressure_service(&temp_pressure_data) == TEMP_PRESSURE_SUCCESS)
    {
        we_power_data->data_fields.pressure.i16 = temp_pressure_data.pressure;
        we_power_data->data_fields.temp.i16 = temp_pressure_data.temp;
    }
    else
    {
        we_power_data->data_fields.pressure.i16 = 0xFFFF;
        we_power_data->data_fields.temp.i16 = 0xFFFF;
    }

}

void encryptedData(uint8_t* clear_text_buf, uint8_t* encrypted_text_buf, uint8_t len )
{
#define ENCRYPT
#ifdef ENCRYPT
    // Not we want to encrypt the data
    if(app_encrypt_payload(clear_text_buf, len, encrypted_text_buf, len) == ENCRYPTION_ERROR)
    {
        memcpy(encrypted_text_buf, clear_text_buf, 16);
        manf_data[PAYLOAD_STATUS_BYTE_INDEX] = PAYLOAD_ENCRYPTION_STATUS_CLEAR;
    }
    else
    {
        manf_data[PAYLOAD_STATUS_BYTE_INDEX] = PAYLOAD_ENCRYPTION_STATUS_ENC;
    }
#else
    memcpy(cipher_text, encrypted_text_buf, 16);
    manf_data[PAYLOAD_STATUS_BYTE_INDEX] = PAYLOAD_ENCRYPTION_STATUS_CLEAR;
#endif
    if (LOGS){
        printk("Payload - Cleartext: ");
        for(int i = 0; i < len; i++)
        {
            printk("%02X ", clear_text_buf[i]);
        }
        printk("\n");

        printk("Payload - Encrypted: ");
        for(int i = 0; i < len; i++)
        {
            printk("%02X ", encrypted_text_buf[i]);
        }
        printk("\n");
    }
}

// only call this ONCE per EventCounter (FRAM[0:3])
void updateManufacturerData(void){
    printk(">>> Updating the Manufacturer Data\n");
   //Get sensor data
	switch (type)
	{
	default: 
		measure_sensors(&we_power_data);
		break;

	case 3: 
		we_power_data.data_bytes[4] = u8Polarity;
		memcpy(&we_power_data.data_bytes[5], fram_data.cName, 9);
		break;

	case 4: 
		memcpy(&we_power_data.data_bytes[4], fram_data.cName, 10);
		break;

	}

    // increase the FRAM Event counter and set first four bytes
	fram_data.event_counter++;
    app_fram_write_counter(&fram_data);

	we_power_data.data_fields.type = fram_data.type;
	we_power_data.data_fields.event_counter24[0] = (uint8_t)((fram_data.event_counter & 0x000000FF));
	we_power_data.data_fields.event_counter24[1] = (uint8_t)((fram_data.event_counter & 0x0000FF00)>>8);
	we_power_data.data_fields.event_counter24[2] = (uint8_t)((fram_data.event_counter & 0x00FF0000)>>16);
    we_power_data.data_fields.id.u16 = fram_data.serial_number & 0xFFFF;

    // initialize the TX counter

	TX_Repeat_Counter = TX_Repeat_Counter_Init;
	manf_data[PAYLOAD_TX_REPEAT_COUNTER_INDEX] = TX_Repeat_Counter;
   
    // Handle encryption
    static uint8_t cipher_text[DATA_SIZE_BYTES];

    encryptedData(we_power_data.data_bytes, cipher_text, DATA_SIZE_BYTES);
    // Build the BLE adv data
    memcpy(&manf_data[MANUF_DATA_CUSTOM_START_INDEX], cipher_text, DATA_SIZE_BYTES);
    memcpy(&manf_data[PAYLOAD_DEVICE_ID_INDEX], &(fram_data.serial_number), 2);

    we_power_adv_data.type = BT_DATA_SVC_DATA16;
    we_power_adv_data.data = manf_data;
    we_power_adv_data.data_len = sizeof(manf_data);

}

void update_frame_work_fn(struct k_work *work)
{
    updateManufacturerData();
    k_timer_start(&timer_event, K_MSEC(fram_data.event_inteval), K_MSEC(fram_data.event_inteval)); // Start 20ms timer event
}

// TODO - make this run much faster
int32_t read_vcc10(void)
{
    int8_t err;

    uint16_t buf;
	struct adc_sequence sequence = {
		.buffer = &buf,
		/* buffer size in bytes, not number of samples */
		.buffer_size = sizeof(buf),
	};

    int32_t val_mv;

    if (!device_is_ready(adc_channel.dev)) {
		printk("ADC controller device %s not ready\n", adc_channel.dev->name);
		return -EINVAL;
	}

    err = adc_channel_setup_dt(&adc_channel);
	if (err < 0) {
		printk("Could not setup channel (%d)\n", err);
		return -EINVAL;
	}

    printk("- %s, channel %d: ",
			       adc_channel.dev->name,
			       adc_channel.channel_id);
    (void)adc_sequence_init_dt(&adc_channel, &sequence);

    err = adc_read(adc_channel.dev, &sequence);
	if (err < 0) {
		printk("Could not read (%d)\n", err);
        return -EINVAL;
	}

    val_mv = (int32_t)buf;

    printk("%"PRId32, val_mv);

    err = adc_raw_to_millivolts_dt(&adc_channel, &val_mv);

	if (err < 0) {
		printk(" (value in mV not available)\n");
        return -EINVAL;
	} else {
		printk(" = %"PRId32" mV\n", val_mv);
	}
    return val_mv;
}

// Main Application
void main(void)
{
    int err;
    int32_t vext10_mv;
    // read VEXT10 ADC, decide to run this or the configuration app.
    vext10_mv = read_vcc10() * 11;

#if (FORCE_TOGGLE)
    nrf_gpio_pin_toggle(POL_GPIO_PIN);
#endif

	// if VEXT10 > 0.165V we have external power
    if (vext10_mv > 1700){
        //Init UART
        init_uart();
        //Process the UART Command
        k_work_init(&process_command_task, process_command_fn);
    }
    else{
        // ask for temp/pressure data now so we don't sleep(10) later
		if (TEMP_PRESSURE_SUCCESS == app_temp_pressure_trigger())
			bPressureRequested = 1;
        
        // Reading FRAM.
        if(app_fram_read_data(&fram_data) == FRAM_SUCCESS)
        {
            // Success! Add it to the payload

            if (LOGS){
                printk(">> ------- Writing FRAM Data -------\n");
		        printk(">>[FRAM INFO]->Event Counter: 0x%08X\n", fram_data.event_counter);
		        printk(">>[FRAM INFO]->Serial Number: 0x%08X\n", fram_data.serial_number);
		        printk(">>[FRAM INFO]->Device Type: %d\n", fram_data.type);
		        printk(">>[FRAM INFO]->Frame Interval: %d ms\n", fram_data.event_inteval);
		        printk(">>[FRAM INFO]->Frame Maximum Number: %d\n", fram_data.event_max_limits);
		        printk(">>[FRAM INFO]->Minimum Sleeping Interval: %d\n", fram_data.sleep_min_interval);
		        printk(">>[FRAM INFO]->Sleep time After Wake up: %d\n", fram_data.sleep_after_wake);
		        printk(">>[FRAM INFO]->Voltage of ISL9122: %d\n", fram_data.u8_voltsISL9122);
		        printk(">>[FRAM INFO]->POL Method: %d\n", fram_data.u8_POLmethod);
		        printk(">>[FRAM INFO]->Encrypted Key: ");
		        for (uint8_t i = 0; i < ENCRYPTED_KEY_NUM_BYTES; i++){
			        printk("0x%02X,", fram_data.encrypted_key[i]);
		        }
		        printk("\n");
		        printk(">>[FRAM INFO]->TX dBM 10: %d\n", fram_data.tx_dbm_10);
		        printk(">>[FRAM INFO]->cName: %s\n", fram_data.cName);
            }
		
			// TODO - use the same limits as the UART code
            serial_number = fram_data.serial_number?fram_data.serial_number&0xFFFF:DEVICE_ID;
		    type = (fram_data.type ? (fram_data.type < 0xFF ? fram_data.type : 1) : 1);
		    event_inteval = (fram_data.event_inteval >= PACKET_INTERVAL_MIN ? (fram_data.event_inteval <= PACKET_INTERVAL_MAX ? fram_data.event_inteval : PACKET_INTERVAL_MAX) : PACKET_INTERVAL_MIN); //
		    event_max_limits = (fram_data.event_max_limits >= 3 ? (fram_data.event_max_limits < 0xF0 ? fram_data.event_max_limits : 3) : 0xF0);
		    sleep_min_interval = (fram_data.sleep_min_interval >= 50 ? fram_data.sleep_min_interval : 50);
		    sleep_after_wake = (fram_data.sleep_after_wake ? (fram_data.sleep_after_wake < 20 ? fram_data.sleep_after_wake : 20) : 0);
#if (FORCE_FRAM_VALS)
            fram_data.event_inteval=20;
            fram_data.event_max_limits = 0xF0;
            fram_data.serial_number = DEVICE_ID;
            fram_data.sleep_after_wake = 0;
            fram_data.sleep_min_interval = 50;
            fram_data.u8_POLmethod = OUT_POL;
            fram_data.u8_voltsISL9122 = 0;
#endif
#if (HAVE_ISL9122)  
            if (fram_data.u8_voltsISL9122 >= 72 && fram_data.u8_voltsISL9122 <= 132)
		    {// // write fram_data.u8_voltsISL9122 to addr 0x18, reg 0x11
		    };
#endif	
#if (!FORCE_TOGGLE)		
		    if (fram_data.u8_POLmethod == OUT_POL) {// toggle output POL_GPIO_PIN
    			nrf_gpio_cfg_output(POL_GPIO_PIN);
			    nrf_gpio_pin_toggle(POL_GPIO_PIN);
		    }
		    else if (fram_data.u8_POLmethod == IN_POL) {// sleep sleep_after_wake then read GPIO --> u8Polarity
                // sleep sleep_after_wake
                k_sleep(K_MSEC(fram_data.sleep_after_wake));
			    nrf_gpio_cfg_input(POL_GPIO_PIN, NRF_GPIO_PIN_PULLUP);
			    u8Polarity = nrf_gpio_pin_read(POL_GPIO_PIN);
		    }
#if (USING_MG24)
		    else if (fram_data.u8_POLmethod == CMP_POL) {/* not possible on nRF design.  sleep sleep_after_wake then read ACMP0 on EFR32*/
                // init ACMP0

				// sleep
				k_sleep(K_MSEC(fram_data.sleep_after_wake));

				// read ACMP0
            }
#endif
#endif           
            if(ENCR_KEY_IN_FRAM){
                for(uint8_t i = 0; i < ENCRYPTED_KEY_NUM_BYTES; i++){
                    ecb_key[i] = fram_data.encrypted_key[i];
                }
            }
        }
        else
        {
		     fram_data.event_counter = 0;
        }
    
        // Init and run the BLE
	    err = bt_enable(NULL);
	    if (err) {
		    printk("Bluetooth init failed (err %d)\n", err);
		    return;
	    }
	
        //Create Advertiser Set Create
	    bt_ready();

        /*
        err = bt_le_ext_adv_set_data(adv, ad, ARRAY_SIZE(ad), NULL, 0);
        if (err) {
            printk("Failed to set advertising data (%d)\n", err);
            return err;
        }

        err = bt_le_ext_adv_start(adv, BT_LE_EXT_ADV_START_PARAM(BLE_ADV_TIMEOUT, BLE_ADV_EVENTS));
        if (err) {
            printk("Failed to start advertising set (%d)\n", err);
            return;
        }

              
        //k_timer_start(&timer_event2, K_MSEC(DURATION), K_MSEC(PERIOD)); // Start 20ms timer event
       */
       
       if (FORCE_TOGGLE || (fram_data.u8_POLmethod == OUT_POL)) 
		   nrf_gpio_pin_toggle(POL_GPIO_PIN);

        updateManufacturerData();
        TX_Repeat_Counter_Init = 0; // TODO - figure out why init changes and make sure TX packets always go 1, 2, 3, ...

        if (FORCE_TOGGLE || (fram_data.u8_POLmethod == OUT_POL)) 
			nrf_gpio_pin_toggle(POL_GPIO_PIN);

        // Init works for advertising and measuring data
        k_work_init(&start_advertising_worker, start_advertising);
        k_work_init_delayable(&update_frame_work, update_frame_work_fn);
        k_timer_start(&timer_event, K_MSEC(fram_data.event_inteval), K_MSEC(fram_data.event_inteval)); // Start 20ms timer event
        k_work_submit(&start_advertising_worker);// submit the first packet // TODO - see if inter event delay is event_interval + sleep_min_interval or just sleep_min_interval

        
    }
}

Parents
  • Vidar

    Thanks for the feedback. I am using a custom board without an external crystal. What changes do I need to apply to reflect this custom board configuration?

    As you can see in the code, there is a timer (20ms) which calls:

     k_work_submit(&start_advertising_worker); which executes:

     start_advertising()

    So wondering if I need to check current status before running another advertise request? 

    Regarding debugging, I can disable breakpoints but wondering best way to check BLE functionality when I am figuring this issue 

  • You can use Bluetooth on a board without the 32 kHz crystal, but not without the 32 MHz crystal. The radio requires the accuracy of the crystal oscillator to transmit on the correct frequencies.

    If you have a 32 MHz crystal and the device is actually advertising as indicated by the error message, then you should be able to see the advertisements from a BLE scanner. You can use the nRF Connect app on Android or iOS to scan for your device.

Reply
  • You can use Bluetooth on a board without the 32 kHz crystal, but not without the 32 MHz crystal. The radio requires the accuracy of the crystal oscillator to transmit on the correct frequencies.

    If you have a 32 MHz crystal and the device is actually advertising as indicated by the error message, then you should be able to see the advertisements from a BLE scanner. You can use the nRF Connect app on Android or iOS to scan for your device.

Children
Related