#include "app_calibration.h" #include "flash_port.h" #include #include #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, ¶ms)) { 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)) { // 实时加载最新的标定配置 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; // 传递一维首地址给核心算法 math_resi_cali((uint16_t *)in_raw_data, &cali_info, (uint16_t *)out_cali_data, (uint32_t)(MT_AX_NUM * MT_AY_NUM)); } else { // 未标定或参数失效时,安全透传原始数据 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); } } // 如果满足重置条件(收到新配置),重置底层标定组件 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; } // 防重入互斥锁 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; } // 防重入互斥锁 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