Hi everyone,
I'm collecting some data from the adxl362 accelerometer and from the env. sensor and sending them over MQTT.
This is the main.c file:
#include <zephyr.h>
#include <cJSON.h>
#include <stdio.h>
#include <drivers/uart.h>
#include <string.h>
#include <random/rand32.h>
#include <net/mqtt.h>
#include <net/socket.h>
#include <modem/at_cmd.h>
#include <modem/lte_lc.h>
#include <logging/log.h>
#include <dk_buttons_and_leds.h>
#include <cJSON_OS.h>
#include <date_time.h>
#include <time.h>
#include "env_sensors.c"
#include "accel.c"
#include "net_controller.c"
#include "certificates.h"
/*Sensor data structures*/
const struct device *env_sensor, *accel;
/*Message Buffers, counters & locks*/
char *buf1[10]; int counter_buf1; bool lock_buf1;
char *buf2[10]; int counter_buf2; bool lock_buf2;
int BUFFERING_TIMER_RELOAD_VALUE_MS;
/*String to contain time*/
static char time_string[80];
int64_t unix_time_ms = 0;
/*Button handler function - sends pre-defined message on publish configured topic */
#if defined(CONFIG_DK_LIBRARY)
static void button_handler(uint32_t button_states, uint32_t has_changed)
{
if (has_changed & button_states &
BIT(CONFIG_BUTTON_EVENT_BTN_NUM - 1)){
;
/*
printk("Disconnecting MQTT client...\n");
err = mqtt_disconnect(&client);
if (err) {
printk("Could not disconnect MQTT client. Error: %d\n", err);
}*/
}
}
#endif
char *time_to_string(int64_t time_ms)
{
time_t time = time_ms / 1000;
struct tm local_time;
local_time = *localtime(&time);
strftime(time_string, 80, "%Y-%m-%d %H:%M:%S", &local_time);
return time_string;
}
/* Date time function using NTP Server */
struct k_work datetime_work;
struct k_timer datetime_timer;
void get_datetime_work_handler(){
int err = 0;
date_time_update_async(NULL);
err = date_time_now(&unix_time_ms);
// Check if we have successfully acquired a timestamp, and print it out if we have
if(err != 0){
printk("Error getting date_time (%i)!\n", err);
}
}
K_WORK_DEFINE(datetime_work, get_datetime_work_handler);
void datetime_expires(struct k_timer *timer_id) {
k_work_submit(&datetime_work);
}
K_TIMER_DEFINE(datetime_timer, datetime_expires, NULL);
/*Encode Json packet in string (all channels encoded)*/
char * cJson_encode(int env_sensor_data[], double accel_sensor_data[]){
static char *string = NULL;
cJSON *device_name = NULL;
cJSON *timestamp = NULL;
//create Json Object
cJSON *packet = cJSON_CreateObject();
//create device name
device_name = cJSON_CreateString(CONFIG_MQTT_CLIENT_ID);
//adding device name to root of json structure
cJSON_AddItemToObject(packet, "device_name", device_name);
//create timestamp
if(unix_time_ms > 0 && time_to_string(unix_time_ms) != NULL){
timestamp = cJSON_CreateString(time_to_string(unix_time_ms));
}else {
timestamp = cJSON_CreateString("timestamp placeholder");
}
cJSON_AddItemToObject(packet, "timestamp", timestamp);
cJSON_AddNumberToObject(packet, "temp", env_sensor_data[0]);
cJSON_AddNumberToObject(packet, "press", env_sensor_data[1]);
cJSON_AddNumberToObject(packet, "humid", env_sensor_data[2]);
cJSON_AddNumberToObject(packet, "gas", env_sensor_data[3]);
cJSON_AddNumberToObject(packet, "accel_x", accel_sensor_data[0]);
cJSON_AddNumberToObject(packet, "accel_y", accel_sensor_data[1]);
cJSON_AddNumberToObject(packet, "accel_z", accel_sensor_data[2]);
cJSON_AddNumberToObject(packet, "mov_avg_x", moving_average_x);
cJSON_AddNumberToObject(packet, "mov_avg_y", moving_average_y);
cJSON_AddNumberToObject(packet, "mov_avg_z", moving_average_z);
string = cJSON_Print(packet);
cJSON_Delete(packet);
return string;
}
/*Work that reads measures and encodes data in json format to buf1 or buf2*/
struct k_work buffering_work;
struct k_timer buffering_timer;
void buffering_work_handler (struct k_work *work){
int y;
static char * payload = NULL;
double accel_data_double[3];
int env_data[4];
//Getting data from accel.
if (get_accel_data(accel, accel_data_double) == -1){
LOG_ERR("Failed getting data from env. sensor");
}
//Getting data from env sensor
if (get_env_sensor_data(env_sensor, env_data) == -1){
LOG_ERR("Failed getting data from env. sensor");
}
payload = cJson_encode(env_data, accel_data_double);
//Concurrent buffering on buf1 and buf2
if(lock_buf1==false){
buf1[counter_buf1] = payload;
counter_buf1 = counter_buf1 + 1;
if(counter_buf1 == 10){
counter_buf2 = 0;
lock_buf1 = true;
lock_buf2 = false;
for(y=0;y<10;y++){
free(buf2[y]);
}
}
}
if(lock_buf2 == false){
buf2[counter_buf2] = payload;
counter_buf2 = counter_buf2 + 1;
if(counter_buf2 == 10){
counter_buf1 = 0;
lock_buf1 = false;
lock_buf2 = true;
for(y=0;y<10;y++){
free(buf1[y]);
}
}
}
if(payload != NULL)
free(payload);
}
K_WORK_DEFINE(buffering_work, buffering_work_handler);
void buffering_expires(struct k_timer *timer_id) {
k_work_submit(&buffering_work);
}
K_TIMER_DEFINE(buffering_timer, buffering_expires, NULL);
/*Work to keep alive MQTT connection and submit bufs*/
struct k_work submitting_work;
struct k_timer submitting_timer;
void submitting_work_handler(struct k_work *work){
int err, ret, y;
//Polling MQTT Socket waiting for event
err = poll(&fds, 1, mqtt_keepalive_time_left(&client));
if (err < 0) {
LOG_ERR("poll: %d", errno);
}
//Upkeep the connection
err = mqtt_live(&client);
if ((err != 0) && (err != -EAGAIN)) {
LOG_ERR("ERROR: mqtt_live: %d", err);
}
//If event occurred and poll succed, call mqtt input
if ((fds.revents & POLLIN) == POLLIN) {
err = mqtt_input(&client);
if (err != 0) {
LOG_ERR("mqtt_input: %d", err);
}
}
//Error on polling from MQTT
if ((fds.revents & POLLERR) == POLLERR) {
LOG_ERR("POLLERR");
}
//Error on polling from MQTT
if ((fds.revents & POLLNVAL) == POLLNVAL) {
LOG_ERR("POLLNVAL");
}
if(lock_buf1==true){
for(y=0;y<10;y++){
ret = data_publish(&client, MQTT_QOS_1_AT_LEAST_ONCE, buf1[y], strlen(buf1[y]), CONFIG_MQTT_PUB_D2C_TOPIC);
if (ret)
LOG_ERR("Publish failed on %s: %d", CONFIG_MQTT_PUB_D2C_TOPIC, ret);
}
}
if(lock_buf2==true){
for(y=0;y<10;y++){
ret = data_publish(&client, MQTT_QOS_1_AT_LEAST_ONCE, buf2[y], strlen(buf2[y]), CONFIG_MQTT_PUB_D2C_TOPIC);
if (ret)
LOG_ERR("Publish failed on %s: %d", CONFIG_MQTT_PUB_D2C_TOPIC, ret);
}
}
}
K_WORK_DEFINE(submitting_work, submitting_work_handler);
void submitting_expires(struct k_timer *timer_id) {
k_work_submit(&submitting_work);
}
K_TIMER_DEFINE(submitting_timer, submitting_expires, NULL);
/*Log application boot info*/
void application_boot_logs(void){
LOG_INF("Starting MQTT connection and sampling data...");
k_sleep(K_MSEC(500));
LOG_INF("Network mode:");
k_sleep(K_MSEC(500));
if(IS_ENABLED(CONFIG_LTE_NETWORK_MODE_LTE)){
LOG_INF("\t-LTE-M");
k_sleep(K_MSEC(500));
}
if(IS_ENABLED(CONFIG_LTE_NETWORK_MODE_NBIOT)){
LOG_INF("\t-NB-IoT");
k_sleep(K_MSEC(500));
}
if(BROKER_HOSTNAME != NULL){
LOG_INF("MQTT Broker Host: %s", BROKER_HOSTNAME);
k_sleep(K_MSEC(500));
}
if(BROKER_PORT != 0){
LOG_INF("MQTT Broker Port: %d", BROKER_PORT);
k_sleep(K_MSEC(500));
}
if(CONFIG_MQTT_CLIENT_ID != NULL){
LOG_INF("MQTT Client ID: %s", CONFIG_MQTT_CLIENT_ID);
k_sleep(K_MSEC(500));
}
if(CONFIG_MQTT_PUB_D2C_TOPIC != NULL){
LOG_INF("MQTT Publish Topic: %s", CONFIG_MQTT_PUB_D2C_TOPIC);
k_sleep(K_MSEC(500));
}
if(CONFIG_MQTT_SUB_TOPIC != NULL){
LOG_INF("MQTT Subscribe Topic: %s", CONFIG_MQTT_SUB_TOPIC);
k_sleep(K_MSEC(500));
}
LOG_INF("Using Sensors:");
k_sleep(K_MSEC(500));
if(IS_ENABLED(CONFIG_ADXL362)){
LOG_INF("\t-ADXL362 3-Axis Accelerometer");
k_sleep(K_MSEC(500));
if(IS_ENABLED(CONFIG_ADXL362_ACCEL_RANGE_2G)){
LOG_INF("\t\t-2G Range acceleration");
k_sleep(K_MSEC(500));
}
if(IS_ENABLED(CONFIG_ADXL362_ACCEL_RANGE_4G)){
LOG_INF("\t\t-4G Range acceleration");
k_sleep(K_MSEC(500));
}
if(IS_ENABLED(CONFIG_ADXL362_ACCEL_RANGE_8G)){
LOG_INF("\t\t-8G Range acceleration");
k_sleep(K_MSEC(500));
}
if(IS_ENABLED(CONFIG_ADXL362_ACCEL_RANGE_RUNTIME)){
LOG_INF("\t\t-Range Acceleration set on runtime");
k_sleep(K_MSEC(500));
}
if(IS_ENABLED(CONFIG_ADXL362_ACCEL_ODR_100)){
LOG_INF("\t\t-Output data rate 100 Hz");
k_sleep(K_MSEC(500));
}
if(IS_ENABLED(CONFIG_ADXL362_ACCEL_ODR_12_5)){
LOG_INF("\t\t-Output data rate 12.5 Hz");
k_sleep(K_MSEC(500));
}
if(IS_ENABLED(CONFIG_ADXL362_ACCEL_ODR_200)){
LOG_INF("\t\t-Output data rate 200 Hz");
k_sleep(K_MSEC(500));
}
if(IS_ENABLED(CONFIG_ADXL362_ACCEL_ODR_400)){
LOG_INF("\t\t-Output data rate 400 Hz");
k_sleep(K_MSEC(500));
}
if(IS_ENABLED(CONFIG_ADXL362_ACCEL_ODR_25)){
LOG_INF("\t\t-Output data rate 25 Hz");
k_sleep(K_MSEC(500));
}
if(IS_ENABLED(CONFIG_ADXL362_ACCEL_ODR_50)){
LOG_INF("\t\t-Output data rate 50 Hz");
k_sleep(K_MSEC(500));
}
if(IS_ENABLED(CONFIG_ADXL362_ACCEL_ODR_RUNTIME)){
LOG_INF("\t\t-Output data rate set on runtime");
k_sleep(K_MSEC(500));
}
}
if(IS_ENABLED(CONFIG_BME680)){
LOG_INF("\t-BME680 Environment Sensor: temp, humidity, pression, air_quality");
k_sleep(K_MSEC(500));
}
LOG_INF("Sampling Period: %d ms", BUFFERING_TIMER_RELOAD_VALUE_MS);
k_sleep(K_MSEC(500));
LOG_INF("");
k_sleep(K_MSEC(500));
}
static void config_init(void){
//BUFFERING_TIMER_RELOAD_VALUE_MS = 1000; //DEBUG
BUFFERING_TIMER_RELOAD_VALUE_MS = CONFIG_SAMPLING_FREQUENCY;
#if defined(CONFIG_MQTT_BROKER)
if(strcmp(CONFIG_MQTT_BROKER,"test_eclipse")==0){
BROKER_HOSTNAME = CONFIG_MQTT_ECLIPSE_BROKER_HOSTNAME;
BROKER_PORT = CONFIG_MQTT_ECLIPSE_BROKER_PORT;
}
if(strcmp(CONFIG_MQTT_BROKER, "AWS_IoT")==0){
BROKER_HOSTNAME = CONFIG_MQTT_AWS_BROKER_HOSTNAME;
BROKER_PORT = CONFIG_MQTT_AWS_BROKER_PORT;
}
#endif
}
void main(void){
int err;
lock_buf1 = false;
lock_buf2 = true;
counter_buf1 = 0;
counter_buf2 = 0;
config_init();
application_boot_logs();
//Memory leak if enabled
//cJSON_Init(); //Initializing the cJSON library
/*Stop the UART RX for power consumption reasons - Uncomment on production env.
if (!IS_ENABLED(CONFIG_AT_HOST_LIBRARY)) {
NRF_UARTE0_NS->TASKS_STOPRX = 1;
NRF_UARTE1_NS->TASKS_STOPRX = 1;
}*/
#if defined(CONFIG_MQTT_LIB_TLS) && defined(CONFIG_CERTIFICATES_PROVISION)
err = certificates_provision();
if (err != 0) {
LOG_ERR("Failed to provision certificates");
return;
}
#endif
//Modem setup and init
do {
err = modem_configure();
if (err) {
LOG_INF("Retrying in %d seconds",
CONFIG_LTE_CONNECT_RETRY_DELAY_S);
k_sleep(K_SECONDS(CONFIG_LTE_CONNECT_RETRY_DELAY_S));
}
} while (err);
//Define button event handler if enabled
#if defined(CONFIG_DK_LIBRARY)
dk_buttons_init(button_handler);
#endif
//mqtt client init
err = client_init(&client);
if (err != 0) {
LOG_ERR("client_init: %d", err);
return;
}
//mqtt client connect
err = mqtt_connect(&client);
if (err != 0) {
LOG_ERR("mqtt_connect %d", err);
return;
}
//mqtt file descriptor init
err = fds_init(&client);
if (err != 0) {
LOG_ERR("fds_init: %d", err);
return;
}
//Env. sensor init
if (init_env_sensor(&env_sensor) != 0)
LOG_ERR("Failed to initialize environment sensors");
//Accel. init
if (init_accel(&accel) != 0)
LOG_ERR("Failed to initialize accelerometer");
k_sleep(K_MSEC(2000));
/*Starting datetime timer:
read datetime every 1 sec */
k_timer_start(&datetime_timer, K_SECONDS(1), K_SECONDS(1));
/*Starting buffering timer:
performs one shot buffer element fill every TIMER_RELOAD_VALUE_MS*/
k_timer_start(&buffering_timer, K_MSEC(BUFFERING_TIMER_RELOAD_VALUE_MS), K_MSEC(BUFFERING_TIMER_RELOAD_VALUE_MS));
/*Starting submitting timer:
performs a bulk submit either of buf1 or buf2 (10 elements)
it lasts TIMER_RELOAD_VALUE_MS*20 and repeats every TIMER_RELOAD_VALUE_MS*10*/
k_timer_start(&submitting_timer, K_MSEC(BUFFERING_TIMER_RELOAD_VALUE_MS*20), K_MSEC(BUFFERING_TIMER_RELOAD_VALUE_MS*10));
}
And this is the accel.c file where I get data from the accelerometer:
#include <zephyr.h>
#include <device.h>
#include <drivers/sensor.h>
#include <stdio.h>
double mov_avg_x_elements[10];
double mov_avg_y_elements[10];
double mov_avg_z_elements[10];
double moving_average_x, moving_average_y, moving_average_z;
int mov_avg_counter;
bool first_ten_flag;
uint8_t init_accel(const struct device **dev){
/*binding device*/
*dev = device_get_binding(DT_LABEL(DT_INST(0, adi_adxl362)));
/*Init mov. average params*/
moving_average_x = 0;
moving_average_y = 0;
moving_average_z = 0;
mov_avg_counter = 0;
first_ten_flag = false;
if(*dev == NULL){
return -1;
}
else{
return 0;
}
}
/*Update moving average by 1 element*/
void moving_average_update(double mov_avg_element, double *avg_array_ptr, double *moving_average_ptr){
int i;
double sum;
avg_array_ptr[mov_avg_counter] = mov_avg_element;
if(!first_ten_flag && mov_avg_counter==10){
first_ten_flag = true;
}
if(first_ten_flag){
sum = 0;
for (i=0; i<10; i++){
sum += avg_array_ptr[i];
}
*moving_average_ptr = sum/10;
}
if(mov_avg_counter == 10){
mov_avg_counter = 0;
}
}
//get double value 3-axis acceleration
uint8_t get_accel_data(const struct device *dev, double accel_data_array[]){
struct sensor_value accel_sensor_data[3];
if (sensor_sample_fetch(dev) < 0) {
printf("Sample fetch error\n");
return -1;
}
if (sensor_channel_get(dev, SENSOR_CHAN_ACCEL_X, &accel_sensor_data[0]) < 0) {
printf("Channel get error\n");
return -1;
}
if (sensor_channel_get(dev, SENSOR_CHAN_ACCEL_Y, &accel_sensor_data[1]) < 0) {
printf("Channel get error\n");
return -1;
}
if (sensor_channel_get(dev, SENSOR_CHAN_ACCEL_Z, &accel_sensor_data[2]) < 0) {
printf("Channel get error\n");
return -1;
}
for(int i=0; i<3; i++){
accel_data_array[i] = sensor_value_to_double(&accel_sensor_data[i]);
}
moving_average_update(accel_data_array[0], mov_avg_x_elements, &moving_average_x);
moving_average_update(accel_data_array[1], mov_avg_y_elements, &moving_average_y);
moving_average_update(accel_data_array[2], mov_avg_z_elements, &moving_average_z);
mov_avg_counter++;
return 1;
}
Everything works fine if comment lines 132, 133, 134 on main.c (where I try to encode accel moving average values), but if I uncomment them occurs a databus error (on instruction cJSON_Print() - line 136 on main.c) after some publishes on MQTT:
[00:00:32.851,684] [1;31m<err> os: ***** BUS FAULT *****[0m [00:00:32.851,684] [1;31m<err> os: Precise data bus error[0m [00:00:32.851,684] [1;31m<err> os: BFAR Address: 0x83638ead[0m [00:00:32.851,715] [1;31m<err> os: r0/a1: 0x00000000 r1/a2: 0x2001a2d4 r2/a3: 0x20026d00[0m [00:00:32.851,715] [1;31m<err> os: r3/a4: 0x636120f1 r12/ip: 0x78c00000 r14/lr: 0x0002b1db[0m [00:00:32.851,715] [1;31m<err> os: xpsr: 0x21020000[0m [00:00:32.851,745] [1;31m<err> os: s[ 0]: 0x00000000 s[ 1]: 0x00000000 s[ 2]: 0x00000000 s[ 3]: 0x00000000[0m [00:00:32.851,745] [1;31m<err> os: s[ 4]: 0x00000000 s[ 5]: 0x00000000 s[ 6]: 0xffffffff s[ 7]: 0x00000000[0m [00:00:32.851,776] [1;31m<err> os: s[ 8]: 0x00000000 s[ 9]: 0x00000000 s[10]: 0x00000000 s[11]: 0x00000000[0m [00:00:32.851,776] [1;31m<err> os: s[12]: 0x00000000 s[13]: 0x00000000 s[14]: 0x00000000 s[15]: 0x00000000[0m [00:00:32.851,776] [1;31m<err> os: fpscr: 0x00000002[0m [00:00:32.851,776] [1;31m<err> os: Faulting instruction address (r15/pc): 0x0002b218[0m [00:00:32.851,776] [1;31m<err> os: >>> ZEPHYR FATAL ERROR 0: CPU exception on CPU 0[0m [00:00:32.851,806] [1;31m<err> os: Current thread: 0x20019748 (unknown)[0m [00:00:33.496,154] [1;31m<err> fatal_error: Resetting system[0m
I suppose it is a memory leak happening because not correctly initializing/freeing some variables.
Could anyone help me with that?
Thank you,
Giuls