CODE¶
Warning
The following code should be based on the code in the release code, which may have been updated.
online_sensing.h¶
/**
* @file online_sensing.h
* @author SHUAIWEN CUI (SHUAIWEN001@e.ntu.edu.sg)
* @brief Online sensing module - Continuous sensor data acquisition and transmission
* @version 1.0
* @date 2025-01-XX
* @copyright Copyright (c) 2025
*
* @details
* This module provides online sensor data acquisition with configurable:
* - Sampling frequency (default: 20 Hz)
* - MQTT transmission (enabled/disabled)
* - Serial output (enabled/disabled)
*
* Features:
* - Fixed-rate data acquisition using FreeRTOS tasks
* - Automatic MQTT payload formatting (JSON)
* - Configurable output channels
* - Thread-safe operation
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "esp_err.h"
#include "node_acc_adxl355.h"
#include "tiny_measurement_config.h"
#ifdef __cplusplus
extern "C"
{
#endif
/* ============================================================================
* CONFIGURATION STRUCTURE
* ============================================================================ */
/**
* @brief Online sensing configuration
*/
typedef struct
{
float sampling_frequency_hz; ///< Sampling frequency in Hz (default: 20.0)
bool enable_mqtt; ///< Enable MQTT transmission (default: true)
bool enable_serial; ///< Enable serial output (default: true)
#ifdef TINY_MEASUREMENT_ENABLE_LCD
bool enable_lcd; ///< Enable LCD display output (default: false)
#endif
const char *mqtt_topic; ///< MQTT topic for publishing (default: NULL)
} online_sensing_config_t;
/* ============================================================================
* FUNCTION DECLARATIONS
* ============================================================================ */
/**
* @brief Initialize online sensing module
* @param config Configuration structure (NULL for default configuration)
* @return ESP_OK on success, error code on failure
*/
esp_err_t online_sensing_init(const online_sensing_config_t *config);
/**
* @brief Start online sensing task
* @return ESP_OK on success, error code on failure
*/
esp_err_t online_sensing_start(void);
/**
* @brief Stop online sensing task
* @return ESP_OK on success, error code on failure
*/
esp_err_t online_sensing_stop(void);
/**
* @brief Deinitialize online sensing module
* @return ESP_OK on success, error code on failure
*/
esp_err_t online_sensing_deinit(void);
/**
* @brief Update sampling frequency at runtime
* @param frequency_hz New sampling frequency in Hz
* @return ESP_OK on success, error code on failure
*/
esp_err_t online_sensing_set_frequency(float frequency_hz);
/**
* @brief Enable or disable MQTT transmission
* @param enable true to enable, false to disable
* @return ESP_OK on success, error code on failure
*/
esp_err_t online_sensing_set_mqtt_enable(bool enable);
/**
* @brief Enable or disable serial output
* @param enable true to enable, false to disable
* @return ESP_OK on success, error code on failure
*/
esp_err_t online_sensing_set_serial_enable(bool enable);
/**
* @brief Get current configuration
* @param config Output parameter for current configuration
* @return ESP_OK on success, error code on failure
*/
esp_err_t online_sensing_get_config(online_sensing_config_t *config);
/**
* @brief Check if online sensing is running
* @param is_running Output parameter: true if running, false otherwise
* @return ESP_OK on success, error code on failure
*/
esp_err_t online_sensing_is_running(bool *is_running);
/**
* @brief Set ADXL355 sensor handle (must be called before starting)
* @param handle ADXL355 handle pointer
* @return ESP_OK on success, error code on failure
*/
esp_err_t online_sensing_set_sensor_handle(adxl355_handle_t *handle);
#ifdef __cplusplus
}
#endif
online_sensing.c¶
Key Implementation Details¶
Timer Callback¶
static void sampling_timer_callback(void *arg)
{
if (!s_is_running || s_adxl355_handle == NULL)
{
return;
}
adxl355_accelerations_t accel;
float temperature;
char mqtt_pub_buff[128];
// Read sensor data
esp_err_t accel_ret = adxl355_read_accelerations(s_adxl355_handle, &accel);
esp_err_t temp_ret = adxl355_read_temperature(s_adxl355_handle, &temperature);
if (accel_ret == ESP_OK && temp_ret == ESP_OK)
{
// MQTT transmission - compact format
if (s_config.enable_mqtt && s_is_mqtt_connected)
{
snprintf(mqtt_pub_buff, sizeof(mqtt_pub_buff), "%.6f,%.6f,%.6f,%.2f",
accel.x, accel.y, accel.z, temperature);
const char *topic = s_config.mqtt_topic ? s_config.mqtt_topic : MQTT_PUBLISH_TOPIC;
esp_mqtt_client_publish(s_mqtt_client, topic,
mqtt_pub_buff, strlen(mqtt_pub_buff), 1, 0);
}
// Serial output
if (s_config.enable_serial)
{
printf("%.6f,%.6f,%.6f,%.2f\n", accel.x, accel.y, accel.z, temperature);
fflush(stdout);
}
#ifdef TINY_MEASUREMENT_ENABLE_LCD
// LCD display
if (s_config.enable_lcd)
{
char lcd_str[48];
snprintf(lcd_str, sizeof(lcd_str), "X:%.6f", accel.x);
lcd_show_string(0, 0, lcd_self.width, 16, 16, lcd_str, BLACK);
// ... (Y, Z, temperature)
}
#endif
}
}
Initialization¶
esp_err_t online_sensing_init(const online_sensing_config_t *config)
{
if (s_is_running)
{
ESP_LOGW(TAG, "Online sensing is already running, stop it first");
return ESP_ERR_INVALID_STATE;
}
// Apply configuration
if (config != NULL)
{
memcpy(&s_config, config, sizeof(online_sensing_config_t));
}
else
{
// Use default configuration
s_config.sampling_frequency_hz = ONLINE_SENSING_DEFAULT_FREQ_HZ;
s_config.enable_mqtt = ONLINE_SENSING_DEFAULT_ENABLE_MQTT;
s_config.enable_serial = ONLINE_SENSING_DEFAULT_ENABLE_SERIAL;
s_config.mqtt_topic = NULL;
}
// Validate configuration
if (s_config.sampling_frequency_hz <= 0.0f || s_config.sampling_frequency_hz > 10000.0f)
{
ESP_LOGE(TAG, "Invalid sampling frequency: %.2f Hz (valid range: 0.1 - 10000 Hz)",
s_config.sampling_frequency_hz);
return ESP_ERR_INVALID_ARG;
}
return ESP_OK;
}
Start Function¶
esp_err_t online_sensing_start(void)
{
if (s_is_running)
{
ESP_LOGW(TAG, "Online sensing is already running");
return ESP_ERR_INVALID_STATE;
}
if (s_adxl355_handle == NULL)
{
ESP_LOGE(TAG, "ADXL355 handle not set. Call online_sensing_set_sensor_handle() first");
return ESP_ERR_INVALID_STATE;
}
// Calculate timer period in microseconds
uint64_t period_us = (uint64_t)(1000000.0f / s_config.sampling_frequency_hz);
// Validate period
if (period_us < 100)
{
ESP_LOGE(TAG, "Sampling frequency too high: %.2f Hz (max: 10000 Hz)",
s_config.sampling_frequency_hz);
return ESP_ERR_INVALID_ARG;
}
// Create timer
esp_timer_create_args_t timer_args = {
.callback = sampling_timer_callback,
.arg = NULL,
.name = "online_sampling_timer"
};
esp_err_t ret = esp_timer_create(&timer_args, &s_sampling_timer);
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "Failed to create timer: %s", esp_err_to_name(ret));
return ret;
}
// Set running flag before starting timer
s_is_running = true;
// Perform immediate first sample (at t=0)
sampling_timer_callback(NULL);
// Start periodic timer
ret = esp_timer_start_periodic(s_sampling_timer, period_us);
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "Failed to start timer: %s", esp_err_to_name(ret));
esp_timer_delete(s_sampling_timer);
s_sampling_timer = NULL;
s_is_running = false;
return ret;
}
ESP_LOGI(TAG, "Online sensing started (frequency: %.2f Hz, period: %llu us)",
s_config.sampling_frequency_hz, period_us);
return ESP_OK;
}
Stop Function¶
esp_err_t online_sensing_stop(void)
{
if (!s_is_running)
{
ESP_LOGW(TAG, "Online sensing is not running");
return ESP_ERR_INVALID_STATE;
}
s_is_running = false;
// Stop and delete timer
if (s_sampling_timer != NULL)
{
esp_timer_stop(s_sampling_timer);
esp_timer_delete(s_sampling_timer);
s_sampling_timer = NULL;
}
ESP_LOGI(TAG, "Online sensing stopped");
return ESP_OK;
}
Usage Example¶
#include "online_sensing.h"
#include "node_acc_adxl355.h"
// Initialize sensor
adxl355_handle_t adxl355_handle;
adxl355_init(&adxl355_handle, ADXL355_RANGE_2G, ADXL355_ODR_1000);
// Set sensor handle
online_sensing_set_sensor_handle(&adxl355_handle);
// Initialize with default configuration
online_sensing_init(NULL);
// Start online sensing
online_sensing_start();
// Runtime configuration update
online_sensing_set_frequency(50.0f); // Change to 50 Hz
online_sensing_set_mqtt_enable(false); // Disable MQTT
// Stop when done
online_sensing_stop();
// Cleanup
online_sensing_deinit();