Files
Frame-rate-optimization/app_cail/app_calibration.c
2026-04-09 10:14:20 +08:00

1290 lines
37 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "app_calibration.h"
#include "flash_port.h"
#include <stdio.h>
#include <string.h>
#undef MX_LOGD
#undef MX_LOGI
#undef MX_LOGW
#undef MX_LOGE
#define MX_LOGD APP_CALI_LOGD
#define MX_LOGI APP_CALI_LOGI
#define MX_LOGW APP_CALI_LOGW
#define MX_LOGE APP_CALI_LOGE
#define CALI_TAG "APP_CALIBRATION"
#include "app_mozen_handler.h"
#include "lib_cal_creep_resistance.h"
/*************************** Public Parameters **********************/
volatile bool g_check_cali = false;
volatile bool g_reset_takeEffect = false;
volatile bool g_is_active_reporting = true;
volatile bool g_is_creep_enable = true;
pressure_params_t* pressure_params = NULL;
/********************************************************************/
static app_device_status_t g_device_status = {0};
static CALI_INFO_T cali_info = {0};
static app_math_cali_t s_temp_cali = {0};
static app_creep_params s_temp_creep = {5U, 20U};
static uint16_t s_map_matrix[APP_MAP_MATRIX_WORDS] = {0};
static uint8_t sensor_data_payload[APP_SENSOR_FRAME_PAYLOAD_MAX_BYTES];
static volatile bool s_is_payload_packing = false;
#define APP_CREEP_DEFAULT_STRENGTH 2U
#define APP_CREEP_DEFAULT_LEVEL 10U
/**
* @brief Get legacy device status
* @return Pointer to legacy status structure
*/
app_device_status_t* app_device_status_get(void)
{
return &g_device_status;
}
/**
* @brief Set legacy device status
* @param status Pointer to status data to apply
*/
void app_device_status_set(const app_device_status_t *status)
{
if (status != NULL) {
g_device_status = *status;
}
}
void app_device_status_init(void)
{
memset(&g_device_status, 0x00, sizeof(g_device_status));
g_device_status.sensor_tx_sw = 1;
g_device_status.tx_stopping = 0;
g_device_status.output_pick = 0;
}
/**
* @brief Parse math calibration parameters from payload
* @param data Input byte buffer
* @param len Length of data
* @param out_params Output structure
* @return 1 on success, 0 on failure
*/
static uint8_t app_math_parse_payload(const uint8_t *data, uint16_t len, app_math_cali_t *out_params)
{
if ((data == NULL) || (out_params == NULL) || (len < APP_MATH_PARAM_FRAME_SIZE)) {
return 0;
}
out_params->max_trigger_res_value = (uint16_t)(((uint16_t)data[1] << 8) | data[0]);
out_params->min_trigger_res_value = (uint16_t)(((uint16_t)data[3] << 8) | data[2]);
out_params->div_trigger_res_value = (uint16_t)(((uint16_t)data[5] << 8) | data[4]);
out_params->max_display_value = (uint16_t)(((uint16_t)data[7] << 8) | data[6]);
if (out_params->min_trigger_res_value >= out_params->max_trigger_res_value) {
return 0;
}
return 1;
}
uint16_t g_buf[5];
/**
* @brief Apply math calibration parameters to runtime algorithms
* @param params Parameter structure
*/
static void app_math_apply_runtime(const app_math_cali_t *params)
{
if (params == NULL) {
return;
}
MX_LOGI(CALI_TAG, "Math apply runtime: min=%u max=%u div=%u max_display=%u",
(unsigned int)params->min_trigger_res_value,
(unsigned int)params->max_trigger_res_value,
(unsigned int)params->div_trigger_res_value,
(unsigned int)params->max_display_value);
g_buf[0] = params->max_trigger_res_value;
g_buf[1] = params->min_trigger_res_value;
g_buf[2] = params->div_trigger_res_value;
g_buf[3] = MAX_DISPLAY_ADC_VALUE;
g_buf[4] = params->max_display_value;
math_resi_init(params->max_trigger_res_value,
params->min_trigger_res_value,
params->div_trigger_res_value,
MAX_DISPLAY_ADC_VALUE,
params->max_display_value);
}
/**
* @brief Set default creep parameters
* @param params Parameter structure
*/
static void app_creep_set_default(app_creep_params *params)
{
if (params == NULL) {
return;
}
params->creep_strength = APP_CREEP_DEFAULT_STRENGTH;
params->creep_level = APP_CREEP_DEFAULT_LEVEL;
}
/**
* @brief Apply creep parameters to runtime algorithms
* @param params Parameter structure
*/
static void app_creep_apply_runtime(const app_creep_params *params)
{
if (params == NULL) {
return;
}
MX_LOGI(CALI_TAG, "Creep apply runtime: strength=%u level=%u",
(unsigned int)params->creep_strength,
(unsigned int)params->creep_level);
cal_creep_resistance_init(params->creep_strength, params->creep_level);
}
/**
* @brief Set default device info
* @param dev_info Device info structure
*/
static void app_device_info_set_default(app_dev_info *dev_info)
{
char sensor_size_text[16] = {0};
if (dev_info == NULL) {
return;
}
memset(dev_info, 0, sizeof(app_dev_info));
memcpy(dev_info->pn, DEFAULT_PN, sizeof(DEFAULT_PN) - 1);
memcpy(dev_info->sn, DEFAULT_SN, sizeof(DEFAULT_SN) - 1);
memcpy(dev_info->sw_ver, DEFAULT_SW_VER, sizeof(DEFAULT_SW_VER) - 1);
memcpy(dev_info->hw_ver, DEFAULT_HW_VER, sizeof(DEFAULT_HW_VER) - 1);
(void)snprintf(sensor_size_text,
sizeof(sensor_size_text),
"%u,%u",
(unsigned int)MT_AX_NUM,
(unsigned int)MT_AY_NUM);
memcpy(dev_info->sensor_size, sensor_size_text, strlen(sensor_size_text));
memcpy(dev_info->protocol_ver, APP_DEVICE_PROTOCOL_VER, strlen(APP_DEVICE_PROTOCOL_VER));
}
/**
* @brief Ensure device info strings are properly null-terminated
* @param dev_info Device info structure
*/
static void app_device_info_normalize(app_dev_info *dev_info)
{
if (dev_info == NULL) {
return;
}
dev_info->pn[sizeof(dev_info->pn) - 1U] = '\0';
dev_info->sn[sizeof(dev_info->sn) - 1U] = '\0';
dev_info->sw_ver[sizeof(dev_info->sw_ver) - 1U] = '\0';
dev_info->hw_ver[sizeof(dev_info->hw_ver) - 1U] = '\0';
dev_info->sensor_size[sizeof(dev_info->sensor_size) - 1U] = '\0';
dev_info->protocol_ver[sizeof(dev_info->protocol_ver) - 1U] = '\0';
}
/**
* @brief Validate device info structure fields
* @param dev_info Device info structure
* @return 1 if valid, 0 otherwise
*/
static uint8_t app_device_info_is_valid(const app_dev_info *dev_info)
{
if (dev_info == NULL) {
return 0;
}
if ((dev_info->pn[0] == '\0') || (dev_info->sn[0] == '\0') ||
(dev_info->sw_ver[0] == '\0') || (dev_info->hw_ver[0] == '\0')) {
return 0;
}
if (((uint8_t)dev_info->pn[0] == 0xFFU) ||
((uint8_t)dev_info->sn[0] == 0xFFU) ||
((uint8_t)dev_info->sw_ver[0] == 0xFFU) ||
((uint8_t)dev_info->hw_ver[0] == 0xFFU)) {
return 0;
}
if ((memchr(dev_info->pn, '\0', sizeof(dev_info->pn)) == NULL) ||
(memchr(dev_info->sn, '\0', sizeof(dev_info->sn)) == NULL) ||
(memchr(dev_info->sw_ver, '\0', sizeof(dev_info->sw_ver)) == NULL) ||
(memchr(dev_info->hw_ver, '\0', sizeof(dev_info->hw_ver)) == NULL)) {
return 0;
}
return 1;
}
/**
* @brief Build 8-bit sensor payload
* @param sensor_data 2D array of sensor data
* @param payload Output buffer
* @param payload_size Output buffer size
* @param payload_len Actual payload length
* @return 1 on success, 0 on failure
*/
uint8_t app_calibration_build_sensor8bit_payload(const uint8_t (*sensor_data)[MT_AY_NUM],
uint8_t *payload,
uint16_t payload_size,
uint16_t *payload_len)
{
uint16_t matrix_count = (uint16_t)(MT_AX_NUM * MT_AY_NUM);
uint16_t need_len;
if ((sensor_data == NULL) || (payload == NULL) || (payload_len == NULL)) {
return 0U;
}
need_len = (uint16_t)(1U + matrix_count);
if (payload_size < need_len) {
return 0U;
}
payload[0] = 0x01U;
memcpy(&payload[1], sensor_data, (size_t)(need_len - 1U));
*payload_len = need_len;
return 1U;
}
/**
* @brief Build 16-bit sensor payload
* @param sensor_data 2D array of sensor data
* @param payload Output buffer
* @param payload_size Output buffer size
* @param payload_len Actual payload length
* @return 1 on success, 0 on failure
*/
uint8_t app_calibration_build_sensor16bit_payload(const uint16_t (*sensor_data)[MT_AY_NUM],
uint8_t *payload,
uint16_t payload_size,
uint16_t *payload_len)
{
uint16_t matrix_count = (uint16_t)(MT_AX_NUM * MT_AY_NUM);
uint16_t need_len;
if ((sensor_data == NULL) || (payload == NULL) || (payload_len == NULL)) {
return 0U;
}
need_len = (uint16_t)(1U + (matrix_count * (uint16_t)sizeof(uint16_t)));
if (payload_size < need_len) {
return 0U;
}
payload[0] = 0x02U;
memcpy(&payload[1], sensor_data, (size_t)(need_len - 1U));
*payload_len = need_len;
return 1U;
}
/**
* @brief Initialize math parameters
* @return 1 on success, 0 on failure
*/
uint8_t app_math_init(uint16_t *min_trigger_res_value,
uint16_t *max_trigger_res_value,
uint16_t *div_trigger_res_value,
uint16_t *max_display_value,
uint16_t *sensor_data_type)
{
app_math_cali_t flash_params;
if ((min_trigger_res_value == NULL) ||
(max_trigger_res_value == NULL) ||
(div_trigger_res_value == NULL) ||
(max_display_value == NULL) ||
(sensor_data_type == NULL)) {
MX_LOGE(CALI_TAG, "Math init bad output pointers");
return 0;
}
if (!flash_port_math_load(&flash_params)) {
MX_LOGE(CALI_TAG, "Math init load flash params failed");
return 0;
}
if (flash_params.check_cail != APP_CALI_STATUS_CALIBRATED) {
MX_LOGW(CALI_TAG, "Math init skipped: not calibrated");
return 0;
}
if (flash_params.min_trigger_res_value >= flash_params.max_trigger_res_value) {
MX_LOGE(CALI_TAG, "Math init invalid range, min=%u max=%u",
(unsigned int)flash_params.min_trigger_res_value,
(unsigned int)flash_params.max_trigger_res_value);
return 0;
}
*min_trigger_res_value = flash_params.min_trigger_res_value;
*max_trigger_res_value = flash_params.max_trigger_res_value;
*div_trigger_res_value = flash_params.div_trigger_res_value;
*max_display_value = flash_params.max_display_value;
*sensor_data_type = flash_params.sensor_data_type;
app_math_apply_runtime(&flash_params);
MX_LOGI(CALI_TAG, "Math init from calibration flash params");
return 1;
}
/**
* @brief Get current temporary math parameters
* @param out_params Output parameter structure pointer
* @return 1 on success, 0 on failure
*/
uint8_t app_math_get_temp_params(app_math_cali_t *out_params)
{
if (out_params == NULL) {
MX_LOGE(CALI_TAG, "Math get temp bad arg");
return 0;
}
out_params->max_trigger_res_value = s_temp_cali.max_trigger_res_value;
out_params->min_trigger_res_value = s_temp_cali.min_trigger_res_value;
out_params->div_trigger_res_value = s_temp_cali.div_trigger_res_value;
out_params->max_display_value = s_temp_cali.max_display_value;
out_params->sensor_data_type = s_temp_cali.sensor_data_type;
return 1;
}
/**
* @brief Set current temporary math parameters
* @param params Input parameter structure pointer
* @return 1 on success, 0 on failure
*/
uint8_t app_math_set_temp_params(const app_math_cali_t *params)
{
if (params == NULL) {
MX_LOGE(CALI_TAG, "Math set temp bad arg");
return 0;
}
s_temp_cali.min_trigger_res_value = params->min_trigger_res_value;
s_temp_cali.max_trigger_res_value = params->max_trigger_res_value;
s_temp_cali.div_trigger_res_value = params->div_trigger_res_value;
s_temp_cali.max_display_value = params->max_display_value;
s_temp_cali.sensor_data_type = params->sensor_data_type;
app_math_apply_runtime(&s_temp_cali);
// Persist the effective sensor_data_type together with runtime params
if (!flash_port_math_save(&s_temp_cali)) {
MX_LOGE(CALI_TAG, "Save math params failed");
return 0;
}
return 1;
}
/**
* @brief Apply temporary math parameters immediately from a byte buffer
* @param data Input data buffer pointer
* @param len Length of the buffer
* @return 1 on success, 0 on failure
*/
uint8_t app_math_write_temp_params(const uint8_t *data, uint16_t len)
{
app_math_cali_t params;
if (!app_math_parse_payload(data, len, &params)) {
MX_LOGE(CALI_TAG, "Math temp parse failed, len=%u", (unsigned int)len);
return 0;
}
s_temp_cali.min_trigger_res_value = params.min_trigger_res_value;
s_temp_cali.max_trigger_res_value = params.max_trigger_res_value;
s_temp_cali.div_trigger_res_value = params.div_trigger_res_value;
s_temp_cali.max_display_value = params.max_display_value;
app_math_apply_runtime(&s_temp_cali);
return 1;
}
/**
* @param data Input data buffer pointer
* @param len Length of the buffer
* @return 1 on success, 0 on failure
*/
uint8_t app_math_save_params(const uint8_t *data, uint16_t len)
{
app_math_cali_t flash_params;
if (!app_math_write_temp_params(data, len)) {
return 0;
}
if (flash_port_math_load(&flash_params)) {
s_temp_cali.check_cail = flash_params.check_cail;
} else {
s_temp_cali.check_cail = APP_CALI_STATUS_UNCALIBRATED;
}
if (!flash_port_math_save(&s_temp_cali)) {
MX_LOGE(CALI_TAG, "Save math params failed");
return 0;
}
if (!flash_port_math_load(&flash_params)) {
MX_LOGE(CALI_TAG, "Verify math params failed");
}
app_math_apply_runtime(&flash_params);
return 1;
}
/**
* @brief Clear math parameters to default values
* @return 1 on success, 0 on failure
*/
uint8_t app_math_clear_params(void)
{
app_math_cali_t default_params = {0};
default_params.min_trigger_res_value = DEFAULT_MIN_TRIGGER_RES_VALUE;
default_params.max_trigger_res_value = DEFAULT_MAX_TRIGGER_RES_VALUE;
default_params.div_trigger_res_value = DEFAULT_DIV_TRIGGER_RES_VALUE;
default_params.max_display_value = DEFAULT_MAX_DISPLAY_VALUE;
default_params.check_cail = APP_CALI_STATUS_UNCALIBRATED;
app_math_apply_runtime(&default_params);
s_temp_cali.check_cail = APP_CALI_STATUS_UNCALIBRATED;
s_temp_cali.min_trigger_res_value = default_params.min_trigger_res_value;
s_temp_cali.max_trigger_res_value = default_params.max_trigger_res_value;
s_temp_cali.div_trigger_res_value = default_params.div_trigger_res_value;
s_temp_cali.max_display_value = default_params.max_display_value;
return flash_port_math_save(&s_temp_cali);
}
/**
* @brief Read temporary math parameters into response buffer
* @param response_buf Output buffer
* @param response_len Output length pointer
* @return 1 on success, 0 on failure
*/
uint8_t app_math_read_temp_params(uint8_t *response_buf, uint16_t *response_len)
{
if ((response_buf == NULL) || (response_len == NULL)) {
MX_LOGE(CALI_TAG, "Read temp math params bad arg");
return 0;
}
response_buf[0] = (uint8_t)(s_temp_cali.max_trigger_res_value & 0xFFU);
response_buf[1] = (uint8_t)((s_temp_cali.max_trigger_res_value >> 8) & 0xFFU);
response_buf[2] = (uint8_t)(s_temp_cali.min_trigger_res_value & 0xFFU);
response_buf[3] = (uint8_t)((s_temp_cali.min_trigger_res_value >> 8) & 0xFFU);
response_buf[4] = (uint8_t)(s_temp_cali.div_trigger_res_value & 0xFFU);
response_buf[5] = (uint8_t)((s_temp_cali.div_trigger_res_value >> 8) & 0xFFU);
response_buf[6] = (uint8_t)(s_temp_cali.max_display_value & 0xFFU);
response_buf[7] = (uint8_t)((s_temp_cali.max_display_value >> 8) & 0xFFU);
*response_len = APP_MATH_PARAM_FRAME_SIZE;
return 1;
}
/**
* @brief Read solidified math parameters from Flash
* @param response_buf Output buffer
* @param response_len Output length pointer
* @return 1 on success, 0 on failure
*/
uint8_t app_math_read_solidified_params(uint8_t *response_buf, uint16_t *response_len)
{
app_math_cali_t flash_params;
if ((response_buf == NULL) || (response_len == NULL)) {
MX_LOGE(CALI_TAG, "Read flash math params bad arg");
return 0;
}
if (!flash_port_math_load(&flash_params)) {
MX_LOGE(CALI_TAG, "Load flash math params failed");
memset(response_buf, 0xFF, APP_MATH_PARAM_FRAME_SIZE);
*response_len = APP_MATH_PARAM_FRAME_SIZE;
return 0;
}
response_buf[0] = (uint8_t)(flash_params.max_trigger_res_value & 0xFFU);
response_buf[1] = (uint8_t)((flash_params.max_trigger_res_value >> 8) & 0xFFU);
response_buf[2] = (uint8_t)(flash_params.min_trigger_res_value & 0xFFU);
response_buf[3] = (uint8_t)((flash_params.min_trigger_res_value >> 8) & 0xFFU);
response_buf[4] = (uint8_t)(flash_params.div_trigger_res_value & 0xFFU);
response_buf[5] = (uint8_t)((flash_params.div_trigger_res_value >> 8) & 0xFFU);
response_buf[6] = (uint8_t)(flash_params.max_display_value & 0xFFU);
response_buf[7] = (uint8_t)((flash_params.max_display_value >> 8) & 0xFFU);
*response_len = APP_MATH_PARAM_FRAME_SIZE;
return 1;
}
/**
* @brief Initialize pressure parameters from Flash
* @return Pointer to pressure_params_t or NULL if failed
*/
pressure_params_t *app_pressure_init(void)
{
if (!flash_port_pressure_load(&s_temp_cali)) {
s_temp_cali.check_cail = APP_CALI_STATUS_UNCALIBRATED;
s_temp_cali.min_trigger_res_value = DEFAULT_MIN_TRIGGER_RES_VALUE;
s_temp_cali.max_trigger_res_value = DEFAULT_MAX_TRIGGER_RES_VALUE;
s_temp_cali.div_trigger_res_value = DEFAULT_DIV_TRIGGER_RES_VALUE;
s_temp_cali.max_display_value = DEFAULT_MAX_DISPLAY_VALUE;
s_temp_cali.num_points = 0;
memset(s_temp_cali.pressure_points, 0, sizeof(s_temp_cali.pressure_points));
return NULL;
}
return &s_temp_cali;
}
/**
* @brief Write temporary pressure parameters from buffer
* @param data Buffer pointer
* @param len Length of the data
* @return 1 on success, 0 on failure
*/
uint8_t app_pressure_write_temp_params(const uint8_t *data, uint16_t len)
{
uint16_t num_points;
if ((data == NULL) || (len < 2U)) {
MX_LOGE(CALI_TAG, "Pressure temp write bad arg, len=%u", (unsigned int)len);
return 0;
}
// mx_log_hex_frame(CALI_TAG, data, len);
num_points = (uint16_t)data[0];
MX_LOGD(CALI_TAG, "Pressure temp write num_points=%u len=%u", (unsigned int)num_points, (unsigned int)len);
if (num_points > MAX_PRESSURE_POINTS) {
MX_LOGE(CALI_TAG, "Pressure temp write invalid points=%u len=%u",
(unsigned int)num_points, (unsigned int)len);
return 0;
}
s_temp_cali.num_points = num_points;
memset(s_temp_cali.pressure_points, 0, sizeof(s_temp_cali.pressure_points));
memcpy(s_temp_cali.pressure_points, &data[1], (size_t)num_points * sizeof(uint16_t));
return 1;
}
/**
* @brief Read temporary pressure parameters
* @param response_buf Output buffer
* @param response_len Output length pointer
* @return 1 on success, 0 on failure
*/
uint8_t app_pressure_read_temp_params(uint8_t *response_buf, uint16_t *response_len)
{
if ((response_buf == NULL) || (response_len == NULL)) {
MX_LOGE(CALI_TAG, "Read temp pressure params bad arg");
return 0;
}
response_buf[0] = (uint8_t)(s_temp_cali.num_points & 0xFFU);
response_buf[1] = (uint8_t)((s_temp_cali.num_points >> 8) & 0xFFU);
memcpy(&response_buf[2],
s_temp_cali.pressure_points,
(size_t)s_temp_cali.num_points * sizeof(uint16_t));
*response_len = (uint16_t)(2U + (s_temp_cali.num_points * 2U));
return 1;
}
/**
* @brief Save pressure parameters to Flash
* @param data Input byte buffer
* @param len Length of the data
* @return 1 on success, 0 on failure
*/
uint8_t app_pressure_save_params(const uint8_t *data, uint16_t len)
{
if (!app_pressure_write_temp_params(data, len)) {
MX_LOGE(CALI_TAG, "Write temp pressure params failed");
return 0;
}
if (!flash_port_pressure_save(&s_temp_cali)) {
MX_LOGE(CALI_TAG, "Save pressure params failed");
return 0;
}
return 1;
}
/**
* @brief Read solidified pressure parameters from Flash
* @param response_buf Output buffer
* @param response_len Output length pointer
* @return 1 on success, 0 on failure
*/
uint8_t app_pressure_read_solidified_params(uint8_t *response_buf, uint16_t *response_len)
{
app_math_cali_t flash_params;
if ((response_buf == NULL) || (response_len == NULL)) {
MX_LOGE(CALI_TAG, "Read flash pressure params bad arg");
return 0;
}
if (!flash_port_pressure_load(&flash_params)) {
MX_LOGE(CALI_TAG, "Load flash pressure params failed");
*response_len = 0;
return 0;
}
response_buf[0] = (uint8_t)(flash_params.num_points & 0xFFU);
response_buf[1] = (uint8_t)((flash_params.num_points >> 8) & 0xFFU);
memcpy(&response_buf[2],
flash_params.pressure_points,
(size_t)flash_params.num_points * sizeof(uint16_t));
*response_len = (uint16_t)(2U + (flash_params.num_points * 2U));
return 1;
}
/**
* @brief Clear pressure parameters
* @return 1 on success, 0 on failure
*/
uint8_t app_pressure_clear_params(void)
{
s_temp_cali.num_points = 0;
memset(s_temp_cali.pressure_points, 0, sizeof(s_temp_cali.pressure_points));
if (!flash_port_pressure_save(&s_temp_cali)) {
MX_LOGE(CALI_TAG, "Clear pressure params failed");
return 0;
}
return 1;
}
/**
* @brief Initialize map matrix from Flash
* @return 1 on success, 0 on failure
*/
uint8_t app_map_init(void)
{
if (!flash_port_map_load(s_map_matrix, APP_MAP_MATRIX_WORDS)) {
memset(s_map_matrix, 0, sizeof(s_map_matrix));
return 0;
}
return 1;
}
/**
* @brief Write temporary map parameters
* @param data Input byte buffer
* @param len Length of data
* @return 1 on success, 0 on failure
*/
uint8_t app_map_write_temp_params(const uint8_t *data, uint16_t len)
{
if ((data == NULL) || (len != (uint16_t)APP_MAP_MATRIX_BYTES)) {
MX_LOGE(CALI_TAG, "Map temp write bad arg, len=%u", (unsigned int)len);
return 0;
}
memcpy(s_map_matrix, data, APP_MAP_MATRIX_BYTES);
return 1;
}
/**
* @brief Save map parameters to Flash
* @param data Input byte buffer
* @param len Length of data
* @return 1 on success, 0 on failure
*/
uint8_t app_map_save_params(const uint8_t *data, uint16_t len)
{
if (!app_map_write_temp_params(data, len)) {
MX_LOGE(CALI_TAG, "Map param length invalid: %u", (unsigned int)len);
return 0;
}
if (!flash_port_map_save(s_map_matrix, APP_MAP_MATRIX_WORDS)) {
MX_LOGE(CALI_TAG, "Save map params failed");
return 0;
}
if (!flash_port_map_load(s_map_matrix, APP_MAP_MATRIX_WORDS)) {
MX_LOGE(CALI_TAG, "Verify map params failed");
return 0;
}
if (!app_calibration_set(1U)) {
MX_LOGE(CALI_TAG, "Set calibrated state failed");
return 0;
}
return 1;
}
/**
* @brief Clear map parameters from Flash
* @return 1 on success, 0 on failure
*/
uint8_t app_map_clear_params(void)
{
memset(s_map_matrix, 0, sizeof(s_map_matrix));
if (!flash_port_map_clear()) {
MX_LOGE(CALI_TAG, "Clear map params failed");
return 0;
}
if (!app_calibration_set(0U)) {
MX_LOGE(CALI_TAG, "Clear calibrated state failed");
return 0;
}
return 1;
}
/**
* @brief Read temporary map parameters
* @param response_buf Output buffer
* @param response_len Output length pointer
* @return 1 on success, 0 on failure
*/
uint8_t app_map_read_temp_params(uint8_t *response_buf, uint16_t *response_len)
{
if ((response_buf == NULL) || (response_len == NULL)) {
MX_LOGE(CALI_TAG, "Read temp map params bad arg");
return 0;
}
*response_len = (uint16_t)APP_MAP_MATRIX_BYTES;
memcpy(response_buf, s_map_matrix, *response_len);
return 1;
}
/**
* @brief Get pointer to map data buffer
* @return Pointer to map data
*/
uint8_t *app_map_data_ptr(void)
{
return (uint8_t *)s_map_matrix;
}
/**
* @brief Get map data size
* @return Size of map data in bytes
*/
uint32_t app_map_data_size(void)
{
return (uint32_t)APP_MAP_MATRIX_BYTES;
}
/**
* @brief Write temporary creep parameters
* @param creep_params Input parameter structure
* @return 1 on success, 0 on failure
*/
uint8_t app_creep_write_temp_params(app_creep_params *creep_params)
{
if (creep_params == NULL) {
MX_LOGE(CALI_TAG, "Creep temp write bad arg");
return 0;
}
s_temp_creep.creep_strength = creep_params->creep_strength;
s_temp_creep.creep_level = creep_params->creep_level;
app_creep_apply_runtime(&s_temp_creep);
MX_LOGI(CALI_TAG, "Creep temp updated: strength=%u level=%u",
(unsigned int)s_temp_creep.creep_strength,
(unsigned int)s_temp_creep.creep_level);
return 1;
}
/**
* @brief Save creep parameters to Flash
* @param creep_params Input parameter structure
* @return 1 on success, 0 on failure
*/
uint8_t app_creep_save_params(app_creep_params *creep_params)
{
if (!app_creep_write_temp_params(creep_params)) {
return 0;
}
if (!flash_port_creep_save(&s_temp_creep)) {
return 0;
}
return 1;
}
/**
* @brief Clear creep parameters
* @return 1 on success, 0 on failure
*/
uint8_t app_creep_clear_params(void)
{
app_creep_set_default(&s_temp_creep);
app_creep_apply_runtime(&s_temp_creep);
if (!flash_port_creep_clear()) {
MX_LOGE(CALI_TAG, "Creep clear failed");
return 0;
}
return 1;
}
/**
* @brief Read device information from Flash
* @param dev_info Output structure
* @return 1 on success, 0 on failure
*/
uint8_t app_device_get_info(app_dev_info *dev_info)
{
if (dev_info == NULL) {
MX_LOGE(CALI_TAG, "Device info get bad arg");
return 0;
}
if (!flash_port_device_info_load(dev_info))
{
app_device_info_set_default(dev_info);
if (!app_device_set_info(dev_info)) {
MX_LOGW(CALI_TAG, "Device info load default save failed");
}
return 1;
}
app_device_info_normalize(dev_info);
if (!app_device_info_is_valid(dev_info))
{
app_device_info_set_default(dev_info);
if (!app_device_set_info(dev_info)) {
MX_LOGW(CALI_TAG, "Device info repair save failed");
}
}
return 1;
}
/**
* @brief Write device information to Flash
* @param dev_info Input structure
* @return 1 on success, 0 on failure
*/
uint8_t app_device_set_info(const app_dev_info *dev_info)
{
app_dev_info flash_info;
if (dev_info == NULL) {
MX_LOGE(CALI_TAG, "Device info set bad arg");
return 0;
}
memcpy(&flash_info, dev_info, sizeof(flash_info));
app_device_info_normalize(&flash_info);
if (!app_device_info_is_valid(&flash_info)) {
MX_LOGE(CALI_TAG, "Device info set invalid data");
return 0;
}
if (!flash_port_device_info_save(&flash_info)) {
MX_LOGE(CALI_TAG, "Device info save failed");
return 0;
}
return 1;
}
/**
* @brief Read creep parameters from Flash, load defaults if invalid
* @param creep_params Output structure
* @return 1 on success, 0 on failure
*/
uint8_t app_creep_read_params(app_creep_params *creep_params)
{
if (creep_params == NULL) {
MX_LOGE(CALI_TAG, "Creep read bad arg");
return 0;
}
if (!flash_port_creep_load(creep_params)) {
app_creep_set_default(creep_params);
if (!flash_port_creep_save(creep_params)) {
MX_LOGE(CALI_TAG, "Creep read default save failed");
return 0;
}
}
s_temp_creep = *creep_params;
app_creep_apply_runtime(&s_temp_creep);
return 1;
}
/**
* @brief Invalidate calibration runtime state
*/
void app_calibration_invalidate_runtime(void)
{
#if APP_CALI_USE_PROJECT_RUNTIME_FLAGS
pressure_params = NULL;
g_check_cali = false;
g_is_creep_enable = false;
#endif
}
/**
* @brief Request reset of runtime calibration logic
* This will be applied after the next pressure measurementis taken.
*
*/
void app_calibration_request_reset_effect(void)
{
#if APP_CALI_USE_PROJECT_RUNTIME_FLAGS
g_reset_takeEffect = true;
g_is_creep_enable = false;
#endif
}
/**
* @brief Check if device is calibrated
* @return 1 if calibrated, 0 otherwise
*/
uint8_t app_calibration_check(void)
{
app_math_cali_t flash_params;
if (!flash_port_math_load(&flash_params))
{
MX_LOGW(CALI_TAG, "Check calibration state failed, treat as uncalibrated");
return 0;
}
return (uint8_t)(flash_params.check_cail == APP_CALI_STATUS_CALIBRATED);
}
/**
* @brief Get global calibration status
* @return Value of g_check_cali
*/
uint8_t app_calibration_get_cail_status(void)
{
return g_check_cali;
}
/**
* @brief Set calibration status
* @param calibrated 1 to mark as calibrated, 0 otherwise
* @return 1 on success, 0 on failure
*/
uint8_t app_calibration_set(uint8_t calibrated)
{
s_temp_cali.check_cail = calibrated ? APP_CALI_STATUS_CALIBRATED : APP_CALI_STATUS_UNCALIBRATED;
if (!flash_port_math_save(&s_temp_cali)) {
return 0;
}
g_check_cali = (calibrated != 0);
return 1;
}
/**
* @brief Initialize the calibration module and underlying flash port.
* @param flash_ops Pointer to flash operations mapping.
*/
void app_calibration_init(const struct flash_port_ops_t *flash_ops)
{
if (flash_ops != NULL) {
flash_port_init((const flash_port_ops_t *)flash_ops);
}
app_calibration_reset_init();
}
/**
* @brief Initialize all calibration components and states
*/
void app_calibration_reset_init(void)
{
uint16_t min_trig, max_trig, div_trig, max_disp, sensor_type;
app_math_cali_t cali_param;
g_check_cali = (app_calibration_check() != 0);
g_is_creep_enable = true;
if (g_check_cali) {
if (!app_math_init(&min_trig, &max_trig, &div_trig, &max_disp, &sensor_type)) {
MX_LOGW(CALI_TAG, "Math init failed, fallback to default");
(void)app_math_clear_params();
g_check_cali = false;
}
pressure_params = app_pressure_init();
if (pressure_params == NULL || pressure_params->num_points < 2) {
MX_LOGE(CALI_TAG, "Pressure params invalid");
g_check_cali = false;
}
if (!app_map_init()) {
MX_LOGE(CALI_TAG, "Map init failed");
g_check_cali = false;
}
} else {
(void)app_math_clear_params();
pressure_params = NULL;
}
(void)app_creep_read_params(&s_temp_creep);
app_math_get_temp_params(&cali_param);
if (g_check_cali) {
g_sensor_data_type = cali_param.sensor_data_type;
} else {
g_sensor_data_type = SENSOR_BIT_8;
}
// Default override to 8bit (from original code)
g_sensor_data_type = SENSOR_BIT_8;
cali_param.max_display_value = 255;
g_buf[0] = cali_param.max_trigger_res_value;
g_buf[1] = cali_param.min_trigger_res_value;
g_buf[2] = cali_param.div_trigger_res_value;
g_buf[3] = MAX_DISPLAY_ADC_VALUE;
g_buf[4] = cali_param.max_display_value;
math_resi_init(cali_param.max_trigger_res_value,
cali_param.min_trigger_res_value,
cali_param.div_trigger_res_value,
MAX_DISPLAY_ADC_VALUE,
cali_param.max_display_value);
MX_LOGI(CALI_TAG, "Calibration params -> max_trig:%u, min_trig:%u, div_trig:%u, max_disp:%u, type:%u",
(unsigned int)cali_param.max_trigger_res_value,
(unsigned int)cali_param.min_trigger_res_value,
(unsigned int)cali_param.div_trigger_res_value,
(unsigned int)cali_param.max_display_value,
(unsigned int)cali_param.sensor_data_type
);
MX_LOGI(CALI_TAG, "g_sensor_data_type : %u, g_is_creep_enable : %u",
(unsigned int)g_sensor_data_type,
(unsigned int)g_is_creep_enable);
}
/**
* @brief Process raw 16-bit sensor data against calibration map
* @param in_raw_data Input raw sensor data matrix (MT_AX_NUM x MT_AY_NUM)
* @param out_cali_data Output buffer to store processed data
* @return 1 on success, 0 on invalid parameters
*/
void process_calibration_frame(const uint16_t in_raw_data[MT_AX_NUM][MT_AY_NUM],
uint16_t out_cali_data[MT_AX_NUM][MT_AY_NUM])
{
if (in_raw_data == NULL || out_cali_data == NULL) {
return;
}
if (g_check_cali &&
(pressure_params != NULL) &&
(pressure_params->num_points >= 2U) &&
(pressure_params->num_points <= MAX_PRESSURE_POINTS))
{
// ʵʱ<CAB5><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>µı<C4B1><EAB6A8><EFBFBD><EFBFBD>
cali_info.real_pressure_value = pressure_params->pressure_points;
cali_info.cali_params = (uint16_t *)app_map_data_ptr();
cali_info.cali_pressure_num = (uint8_t)pressure_params->num_points;
cali_info.cali_data_out_bit_size = UINT16_DOUBLE;
// <20><><EFBFBD><EFBFBD>һά<D2BB>׵<EFBFBD>ַ<EFBFBD><D6B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
math_resi_cali((uint16_t *)in_raw_data,
&cali_info,
(uint16_t *)out_cali_data,
(uint32_t)(MT_AX_NUM * MT_AY_NUM));
}
else
{
// δ<><EFBFBD><EAB6A8><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʧЧʱ<D0A7><CAB1><EFBFBD><EFBFBD>ȫ͸<C8AB><CDB8>ԭʼ<D4AD><CABC><EFBFBD><EFBFBD>
if ((const void *)in_raw_data != (const void *)out_cali_data) {
memcpy((void *)out_cali_data, (const void *)in_raw_data, sizeof(uint16_t) * MT_AX_NUM * MT_AY_NUM);
}
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>յ<EFBFBD><D5B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ã<EFBFBD><C3A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD>õײ<C3B5><D7B2><EFBFBD><EAB6A8><EFBFBD><EFBFBD>
if (g_reset_takeEffect) {
g_reset_takeEffect = false;
app_calibration_reset_init();
}
}
/*
* @brief Check if sensor frame can be sent
* @return true if sensor frame can be sent, false otherwise
*/
static bool can_send_sensor_frame(void)
{
if (!g_is_active_reporting && (g_sensor_frames_to_send <= 0)) {
return false;
}
if (g_sensor_frames_to_send > 0) {
g_sensor_frames_to_send--;
}
return true;
}
/**
* @brief Send 8-bit sensor frame through Mozen protocol
* @param sensor_data 8-bit sensor matrix
* @return 1 on success, 0 on failure or busy
*/
uint8_t send_sensor_frame_8bit(const uint8_t (*sensor_data)[MT_AY_NUM])
{
uint16_t payload_len = 0U;
if (sensor_data == NULL || !can_send_sensor_frame()) {
return 0;
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EBBBA5><EFBFBD><EFBFBD>
if (s_is_payload_packing) {
return 0;
}
s_is_payload_packing = true;
if (!app_calibration_build_sensor8bit_payload(sensor_data, sensor_data_payload, (uint16_t)sizeof(sensor_data_payload), &payload_len)) {
s_is_payload_packing = false;
return 0;
}
(void)mozen_protocol_send_frame(&g_mozen_prot, 0x01U, sensor_data_payload, payload_len, false);
s_is_payload_packing = false;
return 1;
}
/**
* @brief Send 16-bit sensor frame through Mozen protocol
* @param sensor_data 16-bit sensor matrix
* @return 1 on success, 0 on failure or busy
*/
uint8_t send_sensor_frame_16bit(const uint16_t (*sensor_data)[MT_AY_NUM])
{
uint16_t payload_len = 0U;
if (sensor_data == NULL || !can_send_sensor_frame()) {
return 0;
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EBBBA5><EFBFBD><EFBFBD>
if (s_is_payload_packing) {
return 0;
}
s_is_payload_packing = true;
if (!app_calibration_build_sensor16bit_payload(sensor_data, sensor_data_payload, (uint16_t)sizeof(sensor_data_payload), &payload_len)) {
s_is_payload_packing = false;
return 0;
}
(void)mozen_protocol_send_frame(&g_mozen_prot, 0x01U, sensor_data_payload, payload_len, false);
s_is_payload_packing = false;
return 1;
}
/* Legacy compatibility wrappers */
#if APP_CALI_ENABLE_LEGACY_API
uint8_t array_resi_params_write(const uint8_t *data, uint16_t len)
{
return app_math_write_temp_params(data, len);
}
uint8_t array_resi_params_save(const uint8_t *data, uint16_t len)
{
return app_math_save_params(data, len);
}
uint8_t clear_array_init_info(void)
{
return app_math_clear_params();
}
uint8_t return_array_resi_init_info(uint8_t *response_buf, uint16_t *response_len)
{
return app_math_read_temp_params(response_buf, response_len);
}
uint8_t return_flash_array_resi_init_info(uint8_t *response_buf, uint16_t *response_len)
{
return app_math_read_solidified_params(response_buf, response_len);
}
pressure_params_t *init_pressure_params(void)
{
return app_pressure_init();
}
uint8_t write_temp_pressure_params(const uint8_t *data, uint16_t len)
{
return app_pressure_write_temp_params(data, len);
}
uint8_t read_temp_pressure_params(uint8_t *response_buf, uint16_t *response_len)
{
return app_pressure_read_temp_params(response_buf, response_len);
}
uint8_t write_solidified_pressure_params(const uint8_t *data, uint16_t len)
{
return app_pressure_save_params(data, len);
}
uint8_t read_solidified_pressure_params(uint8_t *response_buf, uint16_t *response_len)
{
return app_pressure_read_solidified_params(response_buf, response_len);
}
uint8_t clear_pressure_params_from_flash(void)
{
return app_pressure_clear_params();
}
void write_cali_params_to_ram(const uint8_t *data, uint16_t len)
{
(void)app_map_write_temp_params(data, len);
}
uint8_t save_cali_params_to_flash(const uint8_t *data, uint16_t len)
{
return app_map_save_params(data, len);
}
uint8_t clear_cali_params_from_flash(void)
{
return app_map_clear_params();
}
uint8_t read_cali_params_from_ram(uint8_t *response_buf, uint16_t *response_len)
{
return app_map_read_temp_params(response_buf, response_len);
}
#endif