第一次提交
This commit is contained in:
754
app_cail/moxzen_protocol/app_mozen_handler.c
Normal file
754
app_cail/moxzen_protocol/app_mozen_handler.c
Normal file
@@ -0,0 +1,754 @@
|
||||
#include "app_mozen_handler.h"
|
||||
#include "mozen_tunnel.h"
|
||||
#include "mx_log.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "app_calibration.h"
|
||||
#include "main.h"
|
||||
#include "cJSON.h"
|
||||
|
||||
// Define logs if not using MX_LOG directly
|
||||
#ifndef MX_LOGD
|
||||
#define MX_LOGD MOZEN_LOGD
|
||||
#define MX_LOGI MOZEN_LOGI
|
||||
#define MX_LOGW MOZEN_LOGW
|
||||
#define MX_LOGE MOZEN_LOGE
|
||||
#endif
|
||||
|
||||
#define MX_PTO_TAG "MOZEN_APP"
|
||||
|
||||
volatile uint16_t g_sensor_frames_to_send = 0;
|
||||
volatile uint8_t g_sensor_data_type = SENSOR_BIT_16;
|
||||
|
||||
static mozen_protocol_t *s_prot_instance = NULL;
|
||||
static mozen_tunnel_t s_tunnel_instance;
|
||||
|
||||
// --- Tunnel Stream State ---
|
||||
static struct
|
||||
{
|
||||
bool is_streaming_write;
|
||||
uint8_t* write_ptr;
|
||||
uint8_t target_cmd;
|
||||
uint8_t target_sub_class;
|
||||
} s_stream_state;
|
||||
|
||||
// --- Response Utilities ---
|
||||
#pragma pack(1)
|
||||
typedef struct
|
||||
{
|
||||
uint8_t target_id;
|
||||
uint8_t sub_class;
|
||||
uint8_t operation;
|
||||
} mozen_cmd_header_t;
|
||||
#pragma pack()
|
||||
|
||||
typedef void (*cmd_sub_handler_t)(const mozen_cmd_header_t* header, const uint8_t* payload, uint16_t payload_len);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t target_id;
|
||||
cmd_sub_handler_t handler;
|
||||
} cmd_handler_entry_t;
|
||||
|
||||
// --- Forward Declarations ---
|
||||
static void param_handle_report_mode(const mozen_cmd_header_t* header, const uint8_t* payload, uint16_t payload_len);
|
||||
static void param_handle_device_info(const mozen_cmd_header_t* header, const uint8_t* payload, uint16_t payload_len);
|
||||
static void param_handle_cali_display(const mozen_cmd_header_t* header, const uint8_t* payload, uint16_t payload_len);
|
||||
static void prod_handle_sys_cmd(const mozen_cmd_header_t* header, const uint8_t* payload, uint16_t payload_len);
|
||||
static void prod_handle_map_cali_cmd(const mozen_cmd_header_t* header, const uint8_t* payload, uint16_t payload_len);
|
||||
|
||||
// --- param setters ---
|
||||
static const cmd_handler_entry_t s_param_handlers[] =
|
||||
{
|
||||
{MOZEN_PARAM_TGT_REPORT_MODE, param_handle_report_mode}, // 0x01
|
||||
{MOZEN_PARAM_TGT_DEVICE_INFO, param_handle_device_info}, // 0x02
|
||||
{MOZEN_PARAM_TGT_CALI_DISPLAY, param_handle_cali_display}, // 0x03
|
||||
};
|
||||
|
||||
// --- Production Test Targets ---
|
||||
static const cmd_handler_entry_t s_prod_handlers[] =
|
||||
{
|
||||
{MOZEN_PROD_TGT_SYS, prod_handle_sys_cmd},
|
||||
{MOZEN_PROD_TGT_MAP_CALI, prod_handle_map_cali_cmd},
|
||||
};
|
||||
|
||||
// --- Init ---
|
||||
mozen_protocol_t g_mozen_prot; // Global mozen protocol instance
|
||||
#define RX_BUFFER_SIZE 1024 // RX buffer size
|
||||
#define TX_BUFFER_SIZE 1024 // TX buffer size
|
||||
static uint8_t s_rx_buf[RX_BUFFER_SIZE]; // RX buffer
|
||||
static uint8_t s_tx_buf_main[TX_BUFFER_SIZE]; // TX buffer
|
||||
static uint8_t s_tx_buf_irq[TX_BUFFER_SIZE]; // TX buffer
|
||||
|
||||
// --- Legacy Compatibility Functions ---
|
||||
static uint8_t is_legacy_config_payload(const uint8_t *data, uint16_t len)
|
||||
{
|
||||
if ((data == NULL) || (len < 3U)) return 0U;
|
||||
if ((data[0] != 0x3DU) && (data[0] != 0x3FU)) return 0U;
|
||||
if ((data[1] != '{') || (data[len - 1U] != '}')) return 0U;
|
||||
|
||||
return 1U;
|
||||
}
|
||||
|
||||
static int handle_old_protocol_device_status(uint8_t *data, uint16_t length)
|
||||
{
|
||||
if ((data == NULL) || (length < 2U)) return -1;
|
||||
|
||||
if (data[0] == 0x3D) // "=" <20><><EFBFBD>ò<EFBFBD><C3B2><EFBFBD>
|
||||
{
|
||||
cJSON *root = cJSON_Parse((char *)&data[1]);
|
||||
if (!root)
|
||||
{
|
||||
MX_LOGE(MX_PTO_TAG, "old protocol json parse failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
MX_LOGD(MX_PTO_TAG, "old protocol json parsed");
|
||||
|
||||
// 1. <20><>Ӧ<EFBFBD>ò<EFBFBD><C3B2><EFBFBD>ȡ<EFBFBD><C8A1>ǰ״̬<D7B4><CCAC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>и<EFBFBD><D0B8><EFBFBD>
|
||||
app_device_status_t new_status = *app_device_status_get();
|
||||
|
||||
// 2. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֶ<EFBFBD>
|
||||
cJSON *led_sw = cJSON_GetObjectItem(root, "led_sw");
|
||||
if (led_sw) new_status.led_sw = (uint8_t)led_sw->valueint;
|
||||
|
||||
cJSON *tx_sw = cJSON_GetObjectItem(root, "tx_sw");
|
||||
if (tx_sw)
|
||||
{
|
||||
int tx_sw_val = tx_sw->valueint;
|
||||
if (new_status.sensor_tx_sw == 1 && tx_sw_val == 0)
|
||||
{
|
||||
new_status.tx_stopping = 1;
|
||||
}
|
||||
new_status.sensor_tx_sw = (uint8_t)tx_sw_val;
|
||||
}
|
||||
|
||||
cJSON *pick_sw = cJSON_GetObjectItem(root, "pick_sw");
|
||||
if (pick_sw) new_status.output_pick = (uint8_t)pick_sw->valueint;
|
||||
// printf("pick_sw: %d\n", new_status.output_pick);
|
||||
|
||||
// 3. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѧ<EFBFBD>궨<EFBFBD><EAB6A8><EFBFBD><EFBFBD> (math / math_full)
|
||||
cJSON *math_arr = cJSON_GetObjectItem(root, "math");
|
||||
cJSON *extra_flag = cJSON_GetObjectItem(root, "math_full");
|
||||
|
||||
if (math_arr && cJSON_IsArray(math_arr))
|
||||
{
|
||||
int size = cJSON_GetArraySize(math_arr);
|
||||
app_math_cali_t temp_params;
|
||||
|
||||
if (app_math_get_temp_params(&temp_params))
|
||||
{
|
||||
if (size >= 1) {
|
||||
temp_params.max_trigger_res_value = (uint16_t)cJSON_GetArrayItem(math_arr, 0)->valueint;
|
||||
}
|
||||
if (size >= 2) {
|
||||
temp_params.min_trigger_res_value = (uint16_t)cJSON_GetArrayItem(math_arr, 1)->valueint;
|
||||
}
|
||||
|
||||
if (extra_flag && extra_flag->valueint && size >= 5) {
|
||||
temp_params.max_display_value = (uint16_t)cJSON_GetArrayItem(math_arr, 4)->valueint;
|
||||
}
|
||||
|
||||
app_math_set_temp_params(&temp_params);
|
||||
}
|
||||
}
|
||||
|
||||
// 4. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
cJSON *creep_strength = cJSON_GetObjectItem(root, "creep_strength");
|
||||
cJSON *creep_level = cJSON_GetObjectItem(root, "creep_level");
|
||||
|
||||
if (creep_strength || creep_level)
|
||||
{
|
||||
app_creep_params temp_creep;
|
||||
app_creep_read_params(&temp_creep);
|
||||
|
||||
if (creep_strength) {
|
||||
temp_creep.creep_strength = (uint8_t)creep_strength->valueint;
|
||||
}
|
||||
if (creep_level) {
|
||||
temp_creep.creep_level = (uint8_t)creep_level->valueint;
|
||||
}
|
||||
|
||||
app_creep_write_temp_params(&temp_creep);
|
||||
}
|
||||
|
||||
// 5. Flash <20>־û<D6BE><C3BB><EFBFBD><EFBFBD><EFBFBD>
|
||||
cJSON *flash_cmd = cJSON_GetObjectItem(root, "flash");
|
||||
if(flash_cmd && cJSON_IsString(flash_cmd))
|
||||
{
|
||||
if (strcmp(flash_cmd->valuestring, "creep_write") == 0)
|
||||
{
|
||||
app_creep_params temp_creep;
|
||||
app_creep_read_params(&temp_creep);
|
||||
app_creep_save_params(&temp_creep);
|
||||
}
|
||||
}
|
||||
|
||||
// 6. <20><><EFBFBD><EFBFBD><EFBFBD>º<EFBFBD><C2BA><EFBFBD> Legacy ״̬<D7B4><CCAC>д<EFBFBD><D0B4>Ӧ<EFBFBD>ò<EFBFBD>
|
||||
app_device_status_set(&new_status);
|
||||
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool app_mozen_raw_frame_handler(void *context, const uint8_t *raw_frame, uint16_t length)
|
||||
{
|
||||
mozen_frame_header_t header;
|
||||
if (length < sizeof(mozen_frame_header_t) + 2) return false;
|
||||
|
||||
memcpy(&header, raw_frame, sizeof(mozen_frame_header_t));
|
||||
if (header.command_id == MOZEN_CMD_ID_PARAM_CONFIG) // 0x02
|
||||
{
|
||||
uint16_t full_frame_len = header.frame_length;
|
||||
uint16_t data_len = full_frame_len - sizeof(mozen_frame_header_t);
|
||||
const uint8_t *data_ptr = raw_frame + sizeof(mozen_frame_header_t);
|
||||
uint16_t received_crc;
|
||||
memcpy(&received_crc, raw_frame + full_frame_len, sizeof(uint16_t));
|
||||
|
||||
uint16_t calc_crc = mozen_protocol_checksum(raw_frame, full_frame_len);
|
||||
if ((calc_crc == received_crc) || is_legacy_config_payload(data_ptr, data_len))
|
||||
{
|
||||
handle_old_protocol_device_status((uint8_t *)data_ptr, data_len);
|
||||
return true; // Handled
|
||||
}
|
||||
}
|
||||
return false; // Not handled, fallback to standard parsing
|
||||
}
|
||||
|
||||
// --- Command Handlers ---
|
||||
/*
|
||||
* @brief handle sensor data
|
||||
* @param context: context
|
||||
* @param cmd_id: command id
|
||||
* @param data: data
|
||||
* @param length: length
|
||||
* @retval none
|
||||
*/
|
||||
static void handle_sensor_data(void *context, uint8_t cmd_id, const uint8_t *data, uint16_t length)
|
||||
{
|
||||
if (length < 3)
|
||||
{
|
||||
MX_LOGE(MX_PTO_TAG, "sensor command length invalid: %u", (unsigned int)length);
|
||||
return;
|
||||
}
|
||||
uint8_t new_data_type = data[0];
|
||||
if (new_data_type != g_sensor_data_type)
|
||||
{
|
||||
g_sensor_data_type = new_data_type;
|
||||
app_math_cali_t temp_params;
|
||||
bool got_params = false;
|
||||
|
||||
got_params = app_math_get_temp_params(&temp_params);
|
||||
|
||||
if (got_params)
|
||||
{
|
||||
temp_params.max_display_value = 4095;
|
||||
temp_params.sensor_data_type = g_sensor_data_type;
|
||||
|
||||
app_math_set_temp_params(&temp_params);
|
||||
}
|
||||
}
|
||||
g_sensor_frames_to_send = *(uint16_t*)(&data[1]);
|
||||
}
|
||||
|
||||
// --- Response Utilities ---
|
||||
/*
|
||||
* @brief send mozen command response
|
||||
* @param cmd_id: command id
|
||||
* @param req_header: request header
|
||||
* @param payload: payload
|
||||
* @param payload_len: payload length
|
||||
* @retval none
|
||||
*/
|
||||
static void send_mozen_cmd_response(uint8_t cmd_id, const mozen_cmd_header_t* req_header, const uint8_t* payload, uint16_t payload_len)
|
||||
{
|
||||
static uint8_t response_buf[1024];
|
||||
mozen_cmd_header_t* res_header = (mozen_cmd_header_t*)response_buf;
|
||||
res_header->target_id = req_header->target_id;
|
||||
res_header->sub_class = req_header->sub_class;
|
||||
res_header->operation = req_header->operation;
|
||||
if (payload && payload_len > 0)
|
||||
{
|
||||
memcpy(response_buf + sizeof(mozen_cmd_header_t), payload, payload_len);
|
||||
}
|
||||
mozen_protocol_send_frame(s_prot_instance, cmd_id, response_buf, sizeof(mozen_cmd_header_t) + payload_len, false);
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief send mozen command ok or ng
|
||||
* @param cmd_id: command id
|
||||
* @param req_header: request header
|
||||
* @param success: success or not
|
||||
* @retval none
|
||||
*/
|
||||
static inline void send_mozen_cmd_ok_ng(uint8_t cmd_id, const mozen_cmd_header_t* req_header, bool success)
|
||||
{
|
||||
uint8_t payload[2] = { success ? 'o' : 'N', success ? 'k' : 'G' };
|
||||
send_mozen_cmd_response(cmd_id, req_header, payload, 2);
|
||||
}
|
||||
|
||||
// --- Parameter Config Handlers (Cmd ID: 0x02) ---
|
||||
/*
|
||||
* @brief handle report mode
|
||||
* @param header: header
|
||||
* @param payload: payload
|
||||
* @param payload_len: payload length
|
||||
* @retval none
|
||||
*/
|
||||
static void param_handle_report_mode(const mozen_cmd_header_t* header, const uint8_t* payload, uint16_t payload_len)
|
||||
{
|
||||
if (header->sub_class == 0x01 && header->operation == 0x01 && payload_len >= 1)
|
||||
{
|
||||
if (payload[0] == 0x00) g_is_active_reporting = false;
|
||||
else if (payload[0] == 0x01) g_is_active_reporting = true;
|
||||
send_mozen_cmd_ok_ng(MOZEN_CMD_ID_PARAM_CONFIG, header, true);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* @brief handle device info
|
||||
* @param header: header
|
||||
* @param payload: payload
|
||||
* @param payload_len: payload length
|
||||
* @retval none
|
||||
*/
|
||||
static void param_handle_device_info(const mozen_cmd_header_t* header, const uint8_t* payload, uint16_t payload_len)
|
||||
{
|
||||
if (header->operation == 0x00)
|
||||
{
|
||||
app_dev_info dev_info;
|
||||
char sensor_size_text[sizeof(dev_info.sensor_size) + 1U] = {0};
|
||||
char protocol_ver_text[sizeof(dev_info.protocol_ver) + 1U] = {0};
|
||||
|
||||
if (app_device_get_info(&dev_info))
|
||||
{
|
||||
memcpy(sensor_size_text, dev_info.sensor_size, sizeof(dev_info.sensor_size));
|
||||
memcpy(protocol_ver_text, dev_info.protocol_ver, sizeof(dev_info.protocol_ver));
|
||||
|
||||
uint8_t resp_payload[256];
|
||||
resp_payload[0] = 'o';
|
||||
resp_payload[1] = 'k';
|
||||
int json_len = snprintf((char *)(resp_payload + 2),
|
||||
sizeof(resp_payload) - 2,
|
||||
"{\"PN\":\"%s\",\"SN\":\"%s\",\"SV\":\"%s\",\"HVI\":\"%s\",\"XY\":\"%s\",\"Protocol\":\"%s\"}",
|
||||
dev_info.pn, dev_info.sn, dev_info.sw_ver, dev_info.hw_ver, sensor_size_text, protocol_ver_text);
|
||||
if (json_len > 0) {
|
||||
send_mozen_cmd_response(MOZEN_CMD_ID_PARAM_CONFIG, header, resp_payload, 2 + (uint16_t)json_len);
|
||||
} else {
|
||||
send_mozen_cmd_ok_ng(MOZEN_CMD_ID_PARAM_CONFIG, header, false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
send_mozen_cmd_ok_ng(MOZEN_CMD_ID_PARAM_CONFIG, header, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* @brief handle calibration display
|
||||
* @param header: header
|
||||
* @param payload: payload
|
||||
* @param payload_len: payload length
|
||||
* @retval none
|
||||
*/
|
||||
static void param_handle_cali_display(const mozen_cmd_header_t* header, const uint8_t* payload, uint16_t payload_len)
|
||||
{
|
||||
if (header->operation == 0x00)
|
||||
{
|
||||
uint8_t success = 0;
|
||||
uint16_t data_len = 0;
|
||||
uint8_t resp_payload[256];
|
||||
|
||||
if (header->sub_class == 0x01)
|
||||
{
|
||||
success = app_math_read_temp_params(resp_payload + 2, &data_len);
|
||||
}
|
||||
else if (header->sub_class == 0x02)
|
||||
{
|
||||
success = app_math_read_solidified_params(resp_payload + 2, &data_len);
|
||||
}
|
||||
|
||||
if (success)
|
||||
{
|
||||
resp_payload[0] = 'o'; resp_payload[1] = 'k';
|
||||
send_mozen_cmd_response(MOZEN_CMD_ID_PARAM_CONFIG, header, resp_payload, 2 + data_len);
|
||||
}
|
||||
else
|
||||
{
|
||||
send_mozen_cmd_ok_ng(MOZEN_CMD_ID_PARAM_CONFIG, header, false);
|
||||
}
|
||||
}
|
||||
else if (header->operation == 0x01)
|
||||
{
|
||||
uint8_t success = 0;
|
||||
if (header->sub_class == 0x01)
|
||||
{
|
||||
success = app_math_write_temp_params(payload, payload_len);
|
||||
}
|
||||
else if (header->sub_class == 0x02)
|
||||
{
|
||||
success = app_math_save_params(payload, payload_len);
|
||||
}
|
||||
else if (header->sub_class == 0x03)
|
||||
{
|
||||
success = app_math_clear_params();
|
||||
app_calibration_invalidate_runtime();
|
||||
}
|
||||
send_mozen_cmd_ok_ng(MOZEN_CMD_ID_PARAM_CONFIG, header, success);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* @brief handle param config
|
||||
* @param context: context
|
||||
* @param cmd_id: cmd id
|
||||
* @param data: data
|
||||
* @param length: length
|
||||
* @retval none
|
||||
*/
|
||||
static void handle_param_config(void *context, uint8_t cmd_id, const uint8_t *data, uint16_t length)
|
||||
{
|
||||
if (length < sizeof(mozen_cmd_header_t)) return;
|
||||
|
||||
const mozen_cmd_header_t* cmd_header = (const mozen_cmd_header_t*)data;
|
||||
const uint8_t* cmd_payload = data + sizeof(mozen_cmd_header_t);
|
||||
uint16_t payload_len = length - sizeof(mozen_cmd_header_t);
|
||||
|
||||
for (size_t i = 0; i < sizeof(s_param_handlers) / sizeof(s_param_handlers[0]); i++)
|
||||
{
|
||||
if (s_param_handlers[i].target_id == cmd_header->target_id)
|
||||
{
|
||||
s_param_handlers[i].handler(cmd_header, cmd_payload, payload_len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// --- Production Test Handlers (Cmd ID: 0xAA) ---
|
||||
|
||||
/*
|
||||
* @brief handle system command
|
||||
* @param header: header
|
||||
* @param payload: payload
|
||||
* @param payload_len: payload length
|
||||
* @retval none
|
||||
*/
|
||||
static void prod_handle_sys_cmd(const mozen_cmd_header_t* header, const uint8_t* payload, uint16_t payload_len)
|
||||
{
|
||||
if (header->operation == 0x01)
|
||||
{
|
||||
if (header->sub_class == 0x02)
|
||||
{
|
||||
if(payload_len > 0)
|
||||
{
|
||||
g_is_creep_enable = (payload[0] == 0x01);
|
||||
send_mozen_cmd_ok_ng(MOZEN_CMD_ID_PROD_TEST, header, true);
|
||||
}
|
||||
}
|
||||
else if (header->sub_class == 0x01)
|
||||
{
|
||||
app_dev_info dev_info;
|
||||
if (payload_len == 0U || payload_len >= sizeof(dev_info.sn))
|
||||
{
|
||||
send_mozen_cmd_ok_ng(MOZEN_CMD_ID_PROD_TEST, header, false);
|
||||
return;
|
||||
}
|
||||
if (!app_device_get_info(&dev_info))
|
||||
{
|
||||
send_mozen_cmd_ok_ng(MOZEN_CMD_ID_PROD_TEST, header, false);
|
||||
return;
|
||||
}
|
||||
memset(dev_info.sn, 0, sizeof(dev_info.sn));
|
||||
memcpy(dev_info.sn, payload, payload_len);
|
||||
if (!app_device_set_info(&dev_info))
|
||||
{
|
||||
send_mozen_cmd_ok_ng(MOZEN_CMD_ID_PROD_TEST, header, false);
|
||||
return;
|
||||
}
|
||||
send_mozen_cmd_ok_ng(MOZEN_CMD_ID_PROD_TEST, header, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief handle map calibration
|
||||
* @param header: header
|
||||
* @param payload: payload
|
||||
* @param payload_len: payload length
|
||||
* @retval none
|
||||
*/
|
||||
static void prod_handle_map_cali_cmd(const mozen_cmd_header_t* header, const uint8_t* payload, uint16_t payload_len)
|
||||
{
|
||||
uint8_t resp_payload[260];
|
||||
|
||||
// First, handle map temp params (operation 0x01, sub_class 0x3F / 0x3D) which return no response
|
||||
// First, handle map temp params (operation 0x01, sub_class 0x3F / 0x3D) which return no response
|
||||
if (header->operation == 0x01)
|
||||
{
|
||||
if (header->sub_class == 0x3F)
|
||||
{
|
||||
app_map_write_temp_params(payload, payload_len);
|
||||
return;
|
||||
}
|
||||
else if (header->sub_class == 0x3D)
|
||||
{
|
||||
app_map_save_params(payload, payload_len);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch (header->sub_class)
|
||||
{
|
||||
case 0x4F:
|
||||
if (header->operation == 0x00)
|
||||
{
|
||||
uint16_t d_len;
|
||||
if(app_pressure_read_temp_params(resp_payload + 2, &d_len))
|
||||
{
|
||||
resp_payload[0] = 'o'; resp_payload[1] = 'k';
|
||||
send_mozen_cmd_response(MOZEN_CMD_ID_PROD_TEST, header, resp_payload, 2 + d_len);
|
||||
} else {
|
||||
send_mozen_cmd_ok_ng(MOZEN_CMD_ID_PROD_TEST, header, false);
|
||||
}
|
||||
} else if (header->operation == 0x01) {
|
||||
bool success = app_pressure_write_temp_params(payload, payload_len);
|
||||
send_mozen_cmd_ok_ng(MOZEN_CMD_ID_PROD_TEST, header, success);
|
||||
}
|
||||
break;
|
||||
case 0x4D:
|
||||
if (header->operation == 0x00)
|
||||
{
|
||||
uint16_t d_len;
|
||||
if(app_pressure_read_solidified_params(resp_payload + 2, &d_len))
|
||||
{
|
||||
resp_payload[0] = 'o'; resp_payload[1] = 'k';
|
||||
send_mozen_cmd_response(MOZEN_CMD_ID_PROD_TEST, header, resp_payload, 2 + d_len);
|
||||
} else {
|
||||
send_mozen_cmd_ok_ng(MOZEN_CMD_ID_PROD_TEST, header, false);
|
||||
}
|
||||
} else if (header->operation == 0x01)
|
||||
{
|
||||
bool success = app_pressure_save_params(payload, payload_len);
|
||||
send_mozen_cmd_ok_ng(MOZEN_CMD_ID_PROD_TEST, header, success);
|
||||
}
|
||||
break;
|
||||
case 0x3F:
|
||||
case 0x3D:
|
||||
if (header->operation == 0x00)
|
||||
{
|
||||
uint32_t total_data_len = app_map_data_size();
|
||||
uint16_t total_packets = (total_data_len + 240 - 1) / 240;
|
||||
memcpy(resp_payload, &total_data_len, sizeof(uint32_t));
|
||||
memcpy(resp_payload + 4, &total_packets, sizeof(uint16_t));
|
||||
send_mozen_cmd_response(MOZEN_CMD_ID_PROD_TEST, header, resp_payload, 6);
|
||||
}
|
||||
else if (header->operation == 0x02)
|
||||
{
|
||||
if (payload_len < 2)
|
||||
{
|
||||
send_mozen_cmd_ok_ng(MOZEN_CMD_ID_PROD_TEST, header, false);
|
||||
break;
|
||||
}
|
||||
uint16_t packet_index;
|
||||
memcpy(&packet_index, payload, sizeof(uint16_t));
|
||||
uint32_t total_data_len = app_map_data_size();
|
||||
uint32_t offset = (packet_index - 1) * 240;
|
||||
|
||||
if (offset >= total_data_len)
|
||||
{
|
||||
send_mozen_cmd_ok_ng(MOZEN_CMD_ID_PROD_TEST, header, false);
|
||||
break;
|
||||
}
|
||||
uint16_t chunk_len = 240;
|
||||
if (offset + chunk_len > total_data_len) chunk_len = total_data_len - offset;
|
||||
|
||||
memcpy(resp_payload, &packet_index, sizeof(uint16_t));
|
||||
memcpy(resp_payload + 2, app_map_data_ptr() + offset, chunk_len);
|
||||
send_mozen_cmd_response(MOZEN_CMD_ID_PROD_TEST, header, resp_payload, 2 + chunk_len);
|
||||
}
|
||||
break;
|
||||
case 0x00:
|
||||
if (header->operation == 0x01)
|
||||
{
|
||||
bool success = app_pressure_clear_params();
|
||||
success = success && app_map_clear_params();
|
||||
send_mozen_cmd_ok_ng(MOZEN_CMD_ID_PROD_TEST, header, success);
|
||||
app_calibration_invalidate_runtime();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This function handles the production test command.
|
||||
* It checks the target ID and calls the appropriate handler function.
|
||||
* @param context The context pointer.
|
||||
* @param cmd_id The command ID.
|
||||
* @param data The command data.
|
||||
* @param length The length of the command data.
|
||||
*/
|
||||
static void handle_production_test(void *context, uint8_t cmd_id, const uint8_t *data, uint16_t length)
|
||||
{
|
||||
if (length < sizeof(mozen_cmd_header_t)) return;
|
||||
|
||||
const mozen_cmd_header_t* cmd_header = (const mozen_cmd_header_t*)data;
|
||||
const uint8_t* cmd_payload = data + sizeof(mozen_cmd_header_t);
|
||||
uint16_t payload_len = length - sizeof(mozen_cmd_header_t);
|
||||
|
||||
for (size_t i = 0; i < sizeof(s_prod_handlers) / sizeof(s_prod_handlers[0]); i++)
|
||||
{
|
||||
if (s_prod_handlers[i].target_id == cmd_header->target_id) {
|
||||
s_prod_handlers[i].handler(cmd_header, cmd_payload, payload_len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This function handles the tunnel command.
|
||||
* It calls the tunnel handle command function with the command data.
|
||||
* @param context The context pointer.
|
||||
* @param cmd_id The command ID.
|
||||
* @param data The command data.
|
||||
* @param length The length of the command data.
|
||||
*/
|
||||
static void handle_tunnel_command(void *context, uint8_t cmd_id, const uint8_t *data, uint16_t length)
|
||||
{
|
||||
mozen_tunnel_handle_command(&s_tunnel_instance, data, length);
|
||||
}
|
||||
|
||||
// --- Tunnel Callbacks ---
|
||||
/*
|
||||
* This function is called when a stream starts.
|
||||
* It checks if the target command is production test and the sub class is 0x3F or 0x3D.
|
||||
* If so, it sets the stream state to streaming write and initializes the write pointer.
|
||||
* @param context The context pointer.
|
||||
* @param target_cmd The target command.
|
||||
* @param first_chunk_data The first chunk of data.
|
||||
* @param chunk_len The length of the chunk.
|
||||
* @return true if the stream is started, false otherwise.
|
||||
*/
|
||||
static bool tunnel_on_stream_start(void *context, uint8_t target_cmd, const uint8_t *first_chunk_data, uint16_t chunk_len)
|
||||
{
|
||||
if (target_cmd == MOZEN_CMD_ID_PROD_TEST) {
|
||||
const mozen_cmd_header_t* pt_header = (const mozen_cmd_header_t*)first_chunk_data;
|
||||
if (chunk_len >= sizeof(mozen_cmd_header_t) && pt_header->target_id == MOZEN_PROD_TGT_MAP_CALI && pt_header->operation == 0x01)
|
||||
{
|
||||
if (pt_header->sub_class == 0x3F || pt_header->sub_class == 0x3D)
|
||||
{
|
||||
s_stream_state.is_streaming_write = true;
|
||||
s_stream_state.target_sub_class = pt_header->sub_class;
|
||||
s_stream_state.target_cmd = target_cmd;
|
||||
s_stream_state.write_ptr = app_map_data_ptr();
|
||||
|
||||
uint16_t data_offset = sizeof(mozen_cmd_header_t);
|
||||
uint16_t data_to_write = chunk_len - data_offset;
|
||||
uint8_t* end_ptr = (app_map_data_ptr() + app_map_data_size());
|
||||
|
||||
if (s_stream_state.write_ptr + data_to_write > end_ptr) {
|
||||
data_to_write = end_ptr - s_stream_state.write_ptr;
|
||||
}
|
||||
|
||||
if (data_to_write > 0) {
|
||||
memcpy(s_stream_state.write_ptr, first_chunk_data + data_offset, data_to_write);
|
||||
s_stream_state.write_ptr += data_to_write;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called when data is received during a stream.
|
||||
* It checks if the stream is in streaming write mode and writes the data to the map data buffer.
|
||||
* @param context The context pointer.
|
||||
* @param data The data.
|
||||
* @param len The length of the data.
|
||||
* @return true if the data is handled, false otherwise.
|
||||
*/
|
||||
static bool tunnel_on_stream_data(void *context, const uint8_t *data, uint16_t len)
|
||||
{
|
||||
if (s_stream_state.is_streaming_write) {
|
||||
uint8_t* end_ptr = (app_map_data_ptr() + app_map_data_size());
|
||||
uint16_t data_to_write = len;
|
||||
|
||||
if (s_stream_state.write_ptr >= end_ptr) {
|
||||
data_to_write = 0;
|
||||
} else if (s_stream_state.write_ptr + data_to_write > end_ptr) {
|
||||
data_to_write = end_ptr - s_stream_state.write_ptr;
|
||||
}
|
||||
|
||||
if (data_to_write > 0) {
|
||||
memcpy(s_stream_state.write_ptr, data, data_to_write);
|
||||
s_stream_state.write_ptr += data_to_write;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called when a stream finishes.
|
||||
* It checks if the stream is in streaming write mode and saves the map parameters if the target command is production test and the sub class is 0x3F or 0x3D.
|
||||
* @param context The context pointer.
|
||||
* @param success The success flag.
|
||||
* @return None.
|
||||
*/
|
||||
static void tunnel_on_stream_finish(void *context, bool success)
|
||||
{
|
||||
if (s_stream_state.is_streaming_write && success)
|
||||
{
|
||||
uint32_t expected_bytes = app_map_data_size();
|
||||
uint32_t written_bytes = (uint32_t)(s_stream_state.write_ptr - app_map_data_ptr());
|
||||
|
||||
if (written_bytes >= expected_bytes)
|
||||
{
|
||||
if (s_stream_state.target_cmd == MOZEN_CMD_ID_PROD_TEST && s_stream_state.target_sub_class == 0x3D)
|
||||
{
|
||||
app_map_save_params(app_map_data_ptr(), (uint16_t)expected_bytes);
|
||||
app_calibration_request_reset_effect();
|
||||
}
|
||||
}
|
||||
}
|
||||
s_stream_state.is_streaming_write = false;
|
||||
s_stream_state.write_ptr = NULL;
|
||||
}
|
||||
|
||||
// --- Init ---
|
||||
|
||||
/*
|
||||
* @brief: Initialize the mozen handler.
|
||||
* @param tx_fn: The function to send data.
|
||||
* @return None.
|
||||
*/
|
||||
void app_mozen_init(mozen_tx_fn_t tx_fn)
|
||||
{
|
||||
mozen_protocol_init(&g_mozen_prot, s_rx_buf, sizeof(s_rx_buf),
|
||||
s_tx_buf_main, s_tx_buf_irq, sizeof(s_tx_buf_main),
|
||||
tx_fn, NULL);
|
||||
app_mozen_handler_init(&g_mozen_prot);
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief: Handle raw frame from mozen protocol
|
||||
* @param: prot - Protocol instance
|
||||
* @return: None
|
||||
*/
|
||||
void app_mozen_handler_init(mozen_protocol_t *prot)
|
||||
{
|
||||
s_prot_instance = prot;
|
||||
|
||||
// Register commands
|
||||
mozen_protocol_register_handler(prot, MOZEN_CMD_ID_SENSOR_DATA, handle_sensor_data);
|
||||
mozen_protocol_register_handler(prot, MOZEN_CMD_ID_PARAM_CONFIG, handle_param_config);
|
||||
mozen_protocol_register_handler(prot, MOZEN_CMD_ID_PROD_TEST, handle_production_test);
|
||||
mozen_protocol_register_handler(prot, MOZEN_TUNNEL_COMMAND_ID, handle_tunnel_command);
|
||||
|
||||
// Legacy handler
|
||||
mozen_protocol_set_raw_handler(prot, app_mozen_raw_frame_handler);
|
||||
|
||||
// Init tunnel
|
||||
mozen_tunnel_init(&s_tunnel_instance, prot, 240, NULL);
|
||||
mozen_tunnel_set_callbacks(&s_tunnel_instance, tunnel_on_stream_start, tunnel_on_stream_data, tunnel_on_stream_finish);
|
||||
}
|
||||
48
app_cail/moxzen_protocol/app_mozen_handler.h
Normal file
48
app_cail/moxzen_protocol/app_mozen_handler.h
Normal file
@@ -0,0 +1,48 @@
|
||||
#ifndef __APP_MOZEN_HANDLER_H
|
||||
#define __APP_MOZEN_HANDLER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "mozen_protocol.h"
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ͷ<EFBFBD><CDB6><EFBFBD>
|
||||
enum
|
||||
{
|
||||
SENSOR_BIT_8 = 0x01,
|
||||
SENSOR_BIT_16,
|
||||
};
|
||||
|
||||
// ȫ<><C8AB>״̬<D7B4><CCAC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><D4AD> mozen_protocol.h <20>ж<EFBFBD><D0B6>壬<EFBFBD><E5A3AC><EFBFBD><EFBFBD>Ӧ<EFBFBD>ò<EFBFBD><C3B2><EFBFBD><EFBFBD><EFBFBD>
|
||||
extern volatile uint16_t g_sensor_frames_to_send;
|
||||
extern volatile uint8_t g_sensor_data_type;
|
||||
|
||||
// --- Protocol Command IDs ---
|
||||
#define MOZEN_CMD_ID_SENSOR_DATA 0x01 // --- <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ---
|
||||
#define MOZEN_CMD_ID_PARAM_CONFIG 0x02 // --- <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ---
|
||||
#define MOZEN_CMD_ID_PROD_TEST 0xAA // --- <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ---
|
||||
|
||||
// --- Param Config Target IDs (Command 0x02) ---
|
||||
#define MOZEN_PARAM_TGT_REPORT_MODE 0x01
|
||||
#define MOZEN_PARAM_TGT_CALI_DISPLAY 0x3D
|
||||
#define MOZEN_PARAM_TGT_DEVICE_INFO 0x3F
|
||||
|
||||
// --- Production Test Target IDs (Command 0xAA) ---
|
||||
#define MOZEN_PROD_TGT_SYS 0x01
|
||||
#define MOZEN_PROD_TGT_MAP_CALI 0x03
|
||||
|
||||
// Global protocol instance for application
|
||||
extern mozen_protocol_t g_mozen_prot;
|
||||
|
||||
/**
|
||||
* @brief Initialize the Mozen application handlers.
|
||||
* This will register all necessary command handlers to the protocol instance.
|
||||
* @param prot Protocol instance to bind to.
|
||||
*/
|
||||
void app_mozen_handler_init(mozen_protocol_t *prot);
|
||||
|
||||
/**
|
||||
* @brief Top level initialization for Mozen protocol and application handlers.
|
||||
* @param tx_fn The transmit callback function.
|
||||
*/
|
||||
void app_mozen_init(mozen_tx_fn_t tx_fn);
|
||||
|
||||
#endif // __APP_MOZEN_HANDLER_H
|
||||
315
app_cail/moxzen_protocol/mozen_protocol.c
Normal file
315
app_cail/moxzen_protocol/mozen_protocol.c
Normal file
@@ -0,0 +1,315 @@
|
||||
#include "mozen_protocol.h"
|
||||
#include <string.h>
|
||||
#include "bsp_uart.h"
|
||||
|
||||
// --- Helper Functions ---
|
||||
/*
|
||||
* Calculate CRC16 for data
|
||||
* @param data: Pointer to data
|
||||
* @param length: Length of data
|
||||
* @return: CRC16 value
|
||||
* @note: This function is used for Modbus CRC16
|
||||
*/
|
||||
uint16_t mozen_protocol_crc16_modbus(const uint8_t *data, uint16_t length)
|
||||
{
|
||||
uint16_t crc = 0xFFFF;
|
||||
for (uint16_t i = 0; i < length; i++)
|
||||
{
|
||||
crc ^= data[i];
|
||||
for (uint8_t j = 0; j < 8; j++)
|
||||
{
|
||||
if (crc & 0x0001) crc = (crc >> 1) ^ 0xA001;
|
||||
else crc >>= 1;
|
||||
}
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate checksum for data
|
||||
* @param data: Pointer to data
|
||||
* @param len: Length of data
|
||||
* @return: Checksum value
|
||||
* @note: This function is used for legacy checksum protocols
|
||||
*/
|
||||
uint16_t mozen_protocol_checksum(const uint8_t *data, uint32_t len)
|
||||
{
|
||||
uint16_t sum = 0;
|
||||
for (uint32_t i = 0; i < len; ++i)
|
||||
{
|
||||
sum += data[i];
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
// --- Internal Functions ---
|
||||
|
||||
/*
|
||||
* Reset RX state
|
||||
* @param prot: Pointer to mozen_protocol_t structure
|
||||
* @note: This function is called automatically by mozen_protocol_process_rx
|
||||
*/
|
||||
static void mozen_protocol_reset_rx(mozen_protocol_t *prot)
|
||||
{
|
||||
prot->rx_state = MOZEN_RX_STATE_WAIT_SOF1; // Reset to wait for SOF1
|
||||
prot->rx_index = 0; // Reset index
|
||||
prot->expected_data_len = 0; // Reset expected data length
|
||||
}
|
||||
|
||||
/*
|
||||
* Dispatch received frame
|
||||
* @param prot: Pointer to mozen_protocol_t structure
|
||||
* @note: This function is called automatically by mozen_protocol_process_rx
|
||||
* when a complete frame is received
|
||||
*/
|
||||
static void mozen_protocol_dispatch(mozen_protocol_t *prot)
|
||||
{
|
||||
if (prot->rx_index < sizeof(mozen_frame_header_t) + 2) return; // Too short
|
||||
|
||||
uint16_t received_crc; // Extract CRC from frame
|
||||
mozen_frame_header_t header;
|
||||
memcpy(&header, prot->rx_buffer, sizeof(mozen_frame_header_t));
|
||||
|
||||
if (header.sof != MOZEN_PROTOCOL_SOF) return;
|
||||
|
||||
uint16_t full_frame_len = header.frame_length;
|
||||
uint32_t total_len = (uint32_t)full_frame_len + 2; // +2 for SOF and CRC
|
||||
if (total_len > prot->rx_index || total_len > prot->rx_buffer_size) return;
|
||||
|
||||
|
||||
uint16_t data_len = full_frame_len - sizeof(mozen_frame_header_t); // Exclude header
|
||||
const uint8_t *data_ptr = prot->rx_buffer + sizeof(mozen_frame_header_t); // Point to data
|
||||
|
||||
memcpy(&received_crc, prot->rx_buffer + full_frame_len, sizeof(uint16_t)); // Extract CRC from frame
|
||||
|
||||
// 1. Raw frame handler check (e.g. for legacy checksum protocols)
|
||||
if (prot->raw_frame_handler)
|
||||
{
|
||||
if (prot->raw_frame_handler(prot->user_context, prot->rx_buffer, total_len)) return; // Handled by custom raw handler
|
||||
}
|
||||
|
||||
// 2. Standard CRC16 check
|
||||
uint16_t calculated_crc = mozen_protocol_crc16_modbus(prot->rx_buffer, full_frame_len);
|
||||
if (received_crc != calculated_crc) return; // CRC Error
|
||||
|
||||
// 3. Dispatch to registered handlers
|
||||
for (uint8_t i = 0; i < prot->handler_count; i++)
|
||||
{
|
||||
if (prot->handlers[i].cmd_id == header.command_id)
|
||||
{
|
||||
prot->handlers[i].handler(prot->user_context, header.command_id, data_ptr, data_len);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Default handler fallback
|
||||
if (prot->default_handler)
|
||||
{
|
||||
prot->default_handler(prot->user_context, header.command_id, data_ptr, data_len);
|
||||
}
|
||||
}
|
||||
|
||||
// --- API Functions ---
|
||||
/*
|
||||
* Initialize mozen_protocol_t structure
|
||||
* @param prot: Pointer to mozen_protocol_t structure
|
||||
* @param rx_buf: Pointer to RX buffer
|
||||
* @param rx_buf_size: Size of RX buffer
|
||||
* @param tx_buf_main: Pointer to TX buffer
|
||||
* @param tx_buf_irq: Pointer to IRQ TX buffer (optional)
|
||||
* @param tx_buf_size: Size of TX buffer
|
||||
* @param tx_fn: TX function
|
||||
* @param user_context: User context for TX function
|
||||
* @note: This function should be called once before using the protocol
|
||||
*/
|
||||
void mozen_protocol_init(mozen_protocol_t *prot,
|
||||
uint8_t *rx_buf, uint16_t rx_buf_size,
|
||||
uint8_t *tx_buf_main, uint8_t *tx_buf_irq, uint16_t tx_buf_size,
|
||||
mozen_tx_fn_t tx_fn, void *user_context)
|
||||
{
|
||||
if (!prot) return;
|
||||
|
||||
memset(prot, 0, sizeof(mozen_protocol_t));
|
||||
|
||||
prot->rx_buffer = rx_buf;
|
||||
prot->rx_buffer_size = rx_buf_size;
|
||||
prot->tx_buffer_main = tx_buf_main;
|
||||
prot->tx_buffer_irq = tx_buf_irq ? tx_buf_irq : tx_buf_main;
|
||||
prot->tx_buffer_size = tx_buf_size;
|
||||
prot->tx_fn = tx_fn;
|
||||
prot->user_context = user_context;
|
||||
|
||||
mozen_protocol_reset_rx(prot);
|
||||
}
|
||||
|
||||
/*
|
||||
* Register a command handler
|
||||
* @param prot: Pointer to mozen_protocol_t structure
|
||||
* @param cmd_id: Command ID
|
||||
* @param handler: Command handler function
|
||||
* @return: 0 on success, -1 on failure
|
||||
* @note: This function can be called multiple times to register multiple handlers
|
||||
*/
|
||||
int mozen_protocol_register_handler(mozen_protocol_t *prot, uint8_t cmd_id, mozen_cmd_handler_t handler)
|
||||
{
|
||||
if (!prot || !handler) return -1;
|
||||
if (prot->handler_count >= MOZEN_MAX_HANDLERS) return -1;
|
||||
|
||||
prot->handlers[prot->handler_count].cmd_id = cmd_id;
|
||||
prot->handlers[prot->handler_count].handler = handler;
|
||||
prot->handler_count++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Process RX buffer
|
||||
* @param prot: Pointer to mozen_protocol_t structure
|
||||
* @param current_time_ms: Current time in milliseconds
|
||||
* @note: This function should be called periodically to process incoming data
|
||||
*/
|
||||
void mozen_protocol_set_default_handler(mozen_protocol_t *prot, mozen_cmd_handler_t handler)
|
||||
{
|
||||
if (prot) prot->default_handler = handler;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set raw frame handler
|
||||
* @param prot: Pointer to mozen_protocol_t structure
|
||||
* @param handler: Raw frame handler function
|
||||
* @note: This function can be used to handle legacy checksum protocols or custom protocols
|
||||
*/
|
||||
void mozen_protocol_set_raw_handler(mozen_protocol_t *prot, mozen_raw_frame_handler_t handler)
|
||||
{
|
||||
if (prot) prot->raw_frame_handler = handler;
|
||||
}
|
||||
|
||||
/*
|
||||
* Feed a byte to the protocol
|
||||
* @param prot: Pointer to mozen_protocol_t structure
|
||||
* @param byte: Byte to feed
|
||||
* @param current_time_ms: Current time in milliseconds
|
||||
* @note: This function should be called whenever a new byte is received
|
||||
*/
|
||||
void mozen_protocol_feed_byte(mozen_protocol_t *prot, uint8_t byte, uint32_t current_time_ms)
|
||||
{
|
||||
if (!prot || !prot->rx_buffer) return;
|
||||
|
||||
prot->last_rx_time_ms = current_time_ms;
|
||||
|
||||
switch (prot->rx_state)
|
||||
{
|
||||
case MOZEN_RX_STATE_WAIT_SOF1:
|
||||
if (byte == (MOZEN_PROTOCOL_SOF & 0xFF))
|
||||
{
|
||||
prot->rx_buffer[0] = byte;
|
||||
prot->rx_index = 1;
|
||||
prot->rx_state = MOZEN_RX_STATE_WAIT_SOF2;
|
||||
}
|
||||
break;
|
||||
|
||||
case MOZEN_RX_STATE_WAIT_SOF2:
|
||||
if (byte == (MOZEN_PROTOCOL_SOF >> 8))
|
||||
{
|
||||
prot->rx_buffer[1] = byte;
|
||||
prot->rx_index = 2;
|
||||
prot->rx_state = MOZEN_RX_STATE_WAIT_HEADER;
|
||||
}
|
||||
else { mozen_protocol_reset_rx(prot);}
|
||||
break;
|
||||
|
||||
case MOZEN_RX_STATE_WAIT_HEADER: // Wait for frame header
|
||||
prot->rx_buffer[prot->rx_index++] = byte;
|
||||
if (prot->rx_index >= sizeof(mozen_frame_header_t))
|
||||
{
|
||||
mozen_frame_header_t header;
|
||||
memcpy(&header, prot->rx_buffer, sizeof(mozen_frame_header_t));
|
||||
|
||||
prot->expected_data_len = header.frame_length - sizeof(mozen_frame_header_t) + 2; // +2 for CRC
|
||||
|
||||
if ((sizeof(mozen_frame_header_t) + prot->expected_data_len) > prot->rx_buffer_size)
|
||||
{
|
||||
mozen_protocol_reset_rx(prot);
|
||||
return;
|
||||
}
|
||||
prot->rx_state = MOZEN_RX_STATE_WAIT_DATA;
|
||||
}
|
||||
break;
|
||||
|
||||
case MOZEN_RX_STATE_WAIT_DATA:
|
||||
prot->rx_buffer[prot->rx_index++] = byte;
|
||||
if (prot->rx_index >= (sizeof(mozen_frame_header_t) + prot->expected_data_len))
|
||||
{
|
||||
mozen_protocol_dispatch(prot);
|
||||
mozen_protocol_reset_rx(prot);
|
||||
} else if (prot->rx_index >= prot->rx_buffer_size) {
|
||||
// Should not happen due to header check, but safe guard against buffer overflow
|
||||
mozen_protocol_reset_rx(prot);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset the protocol state
|
||||
* @param prot: Pointer to mozen_protocol_t structure
|
||||
* current_time_ms: Current time in milliseconds
|
||||
* timeout_ms: Timeout in milliseconds
|
||||
* @note: This function should be called when a timeout occurs or when a frame is received
|
||||
*/
|
||||
void mozen_protocol_tick(mozen_protocol_t *prot, uint32_t current_time_ms, uint32_t timeout_ms)
|
||||
{
|
||||
if (!prot) return;
|
||||
|
||||
if (prot->rx_state != MOZEN_RX_STATE_WAIT_SOF1)
|
||||
{
|
||||
// Calculate diff taking into account potential integer overflow/wraparound
|
||||
uint32_t time_diff = current_time_ms - prot->last_rx_time_ms;
|
||||
if (time_diff > timeout_ms)
|
||||
{
|
||||
mozen_protocol_reset_rx(prot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a frame
|
||||
* @param prot: Pointer to mozen_protocol_t structure
|
||||
* @param command_id: Command ID
|
||||
* @param data: Data to send
|
||||
* @param length: Length of data
|
||||
* @param use_irq_buffer: Use IRQ buffer for sending
|
||||
* @return: 0 on success, -1 on error
|
||||
* @note: This function sends a frame using the provided data and command ID
|
||||
*/
|
||||
int mozen_protocol_send_frame(mozen_protocol_t *prot, uint8_t command_id, const uint8_t* data, uint16_t length, bool use_irq_buffer)
|
||||
{
|
||||
if (!prot || !prot->tx_fn) return -1;
|
||||
|
||||
uint16_t frame_length = sizeof(mozen_frame_header_t) + length; //Total length after removing CRC
|
||||
uint16_t total_length = frame_length + 2; // Total length including CRC
|
||||
|
||||
if (total_length > prot->tx_buffer_size) return -1;
|
||||
|
||||
// During the transmission stage, double buffering is employed to prevent the data frames of the main loop from overlapping with the interrupt ACKs.
|
||||
// The sensor data frames and ACKs may be sent concurrently in different contexts.
|
||||
// The two static buffers can avoid overwriting and competition.
|
||||
// The ACKs use an independent buffer to prevent interference with large packet transmission.
|
||||
uint8_t *active_buffer = use_irq_buffer ? prot->tx_buffer_irq : prot->tx_buffer_main;
|
||||
|
||||
mozen_frame_header_t header;
|
||||
header.sof = MOZEN_PROTOCOL_SOF;
|
||||
header.command_id = command_id;
|
||||
header.frame_length = frame_length;
|
||||
|
||||
memcpy(active_buffer, &header, sizeof(mozen_frame_header_t));
|
||||
if (data && length > 0)
|
||||
{
|
||||
memcpy(active_buffer + sizeof(mozen_frame_header_t), data, length);
|
||||
}
|
||||
|
||||
uint16_t crc = mozen_protocol_crc16_modbus(active_buffer, frame_length);
|
||||
memcpy(active_buffer + frame_length, &crc, sizeof(uint16_t));
|
||||
|
||||
return prot->tx_fn(active_buffer, total_length);
|
||||
}
|
||||
120
app_cail/moxzen_protocol/mozen_protocol.h
Normal file
120
app_cail/moxzen_protocol/mozen_protocol.h
Normal file
@@ -0,0 +1,120 @@
|
||||
#ifndef __MOZEN_PROTOCOL_H
|
||||
#define __MOZEN_PROTOCOL_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define MOZEN_PROTOCOL_SOF 0x5AA5 // ֡ͷ
|
||||
|
||||
// --- Core Protocol Data Structures ---
|
||||
|
||||
#pragma pack(1)
|
||||
/**
|
||||
* @brief Represents the header of a Mozen protocol frame.
|
||||
* The payload data follows this header directly in the buffer.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint16_t sof;
|
||||
uint8_t command_id;
|
||||
uint16_t frame_length;
|
||||
} mozen_frame_header_t;
|
||||
#pragma pack()
|
||||
|
||||
/**
|
||||
* @brief Command handler callback type.
|
||||
* @param context User context provided during registration.
|
||||
* @param cmd_id The command ID of the received frame.
|
||||
* @param data Pointer to the 'Data' field of the received frame.
|
||||
* @param length The length of the 'Data' field.
|
||||
*/
|
||||
typedef void (*mozen_cmd_handler_t)(void *context, uint8_t cmd_id, const uint8_t *data, uint16_t length);
|
||||
|
||||
/**
|
||||
* @brief Custom raw frame handler, used for legacy protocol compatibility or custom validation.
|
||||
* @param context User context.
|
||||
* @param raw_frame The complete raw frame data.
|
||||
* @param length The length of the complete raw frame.
|
||||
* @return true if the frame is handled and should not be processed further, false otherwise.
|
||||
*/
|
||||
typedef bool (*mozen_raw_frame_handler_t)(void *context, const uint8_t *raw_frame, uint16_t length);
|
||||
|
||||
/**
|
||||
* @brief Transport TX callback type.
|
||||
* @param frame Complete protocol frame buffer (header + payload + crc).
|
||||
* @param len Frame length in bytes.
|
||||
* @return 0 on success, negative value on failure.
|
||||
*/
|
||||
typedef int (*mozen_tx_fn_t)(const uint8_t *frame, uint16_t len);
|
||||
|
||||
// Max number of registered command handlers
|
||||
#define MOZEN_MAX_HANDLERS 10
|
||||
|
||||
// RX State Machine States
|
||||
typedef enum
|
||||
{
|
||||
MOZEN_RX_STATE_WAIT_SOF1,
|
||||
MOZEN_RX_STATE_WAIT_SOF2,
|
||||
MOZEN_RX_STATE_WAIT_HEADER,
|
||||
MOZEN_RX_STATE_WAIT_DATA,
|
||||
} mozen_rx_state_t;
|
||||
|
||||
/**
|
||||
* @brief Mozen Protocol Instance Context
|
||||
* Contains state and configurations for a single protocol instance.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
// Buffers and configuration
|
||||
uint8_t *rx_buffer;
|
||||
uint16_t rx_buffer_size;
|
||||
uint8_t *tx_buffer_main; // Main TX buffer
|
||||
uint8_t *tx_buffer_irq; // IRQ TX buffer
|
||||
uint16_t tx_buffer_size;
|
||||
|
||||
// Callbacks
|
||||
mozen_tx_fn_t tx_fn;
|
||||
void *user_context;
|
||||
|
||||
// Command Handlers
|
||||
struct
|
||||
{
|
||||
uint8_t cmd_id;
|
||||
mozen_cmd_handler_t handler;
|
||||
} handlers[MOZEN_MAX_HANDLERS];
|
||||
uint8_t handler_count;
|
||||
|
||||
mozen_cmd_handler_t default_handler;
|
||||
mozen_raw_frame_handler_t raw_frame_handler;
|
||||
|
||||
// RX State Machine
|
||||
mozen_rx_state_t rx_state;
|
||||
uint16_t rx_index;
|
||||
uint16_t expected_data_len;
|
||||
uint32_t last_rx_time_ms; // For timeout handling
|
||||
} mozen_protocol_t;
|
||||
|
||||
// --- API Functions ---
|
||||
|
||||
void mozen_protocol_init(mozen_protocol_t *prot,
|
||||
uint8_t *rx_buf, uint16_t rx_buf_size,
|
||||
uint8_t *tx_buf_main, uint8_t *tx_buf_irq, uint16_t tx_buf_size,
|
||||
mozen_tx_fn_t tx_fn, void *user_context);
|
||||
|
||||
int mozen_protocol_register_handler(mozen_protocol_t *prot, uint8_t cmd_id, mozen_cmd_handler_t handler);
|
||||
|
||||
void mozen_protocol_set_default_handler(mozen_protocol_t *prot, mozen_cmd_handler_t handler);
|
||||
|
||||
void mozen_protocol_set_raw_handler(mozen_protocol_t *prot, mozen_raw_frame_handler_t handler);
|
||||
|
||||
void mozen_protocol_feed_byte(mozen_protocol_t *prot, uint8_t byte, uint32_t current_time_ms);
|
||||
|
||||
void mozen_protocol_tick(mozen_protocol_t *prot, uint32_t current_time_ms, uint32_t timeout_ms);
|
||||
|
||||
int mozen_protocol_send_frame(mozen_protocol_t *prot, uint8_t command_id, const uint8_t* data, uint16_t length, bool use_irq_buffer);
|
||||
|
||||
uint16_t mozen_protocol_crc16_modbus(const uint8_t *data, uint16_t length);
|
||||
|
||||
uint16_t mozen_protocol_checksum(const uint8_t *data, uint32_t len);
|
||||
|
||||
#endif // __MOZEN_PROTOCOL_H
|
||||
197
app_cail/moxzen_protocol/mozen_tunnel.c
Normal file
197
app_cail/moxzen_protocol/mozen_tunnel.c
Normal file
@@ -0,0 +1,197 @@
|
||||
#include "mozen_tunnel.h"
|
||||
#include <string.h>
|
||||
// <20>ְ<EFBFBD>
|
||||
|
||||
/*
|
||||
* Initialize tunnel
|
||||
* tunnel: tunnel context
|
||||
* prot: protocol context
|
||||
* mtu: maximum transmission unit
|
||||
* user_context: user context
|
||||
* returns: none
|
||||
*/
|
||||
void mozen_tunnel_init(mozen_tunnel_t *tunnel, mozen_protocol_t *prot, uint16_t mtu, void *user_context)
|
||||
{
|
||||
if (!tunnel) return;
|
||||
memset(tunnel, 0, sizeof(mozen_tunnel_t));
|
||||
tunnel->prot = prot;
|
||||
tunnel->mtu = mtu;
|
||||
tunnel->user_context = user_context;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a response to the tunnel command
|
||||
* tunnel: tunnel context
|
||||
* target_cmd: command id
|
||||
* is_ok: true if the command was successful, false otherwise
|
||||
* returns: none
|
||||
*/
|
||||
void mozen_tunnel_set_callbacks(mozen_tunnel_t *tunnel,
|
||||
mozen_tunnel_on_stream_start_t on_start,
|
||||
mozen_tunnel_on_stream_data_t on_data,
|
||||
mozen_tunnel_on_stream_finish_t on_finish)
|
||||
{
|
||||
if (!tunnel) return;
|
||||
tunnel->on_start = on_start;
|
||||
tunnel->on_data = on_data;
|
||||
tunnel->on_finish = on_finish;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a response to the tunnel command
|
||||
* tunnel: tunnel context
|
||||
* target_cmd: command id
|
||||
* is_ok: true if the command was successful, false otherwise
|
||||
* returns: none
|
||||
*/
|
||||
static void mozen_tunnel_send_response(mozen_tunnel_t *tunnel, uint8_t target_cmd, bool is_ok)
|
||||
{
|
||||
if (!tunnel || !tunnel->prot) return;
|
||||
|
||||
uint8_t res_buf[sizeof(mozen_tunnel_header_t) + 2];
|
||||
mozen_tunnel_header_t *res_header = (mozen_tunnel_header_t *)res_buf;
|
||||
|
||||
res_header->tunnel_type = TUNNEL_TYPE_DATA_TRANSFER;
|
||||
res_header->target_cmd = target_cmd;
|
||||
res_buf[sizeof(mozen_tunnel_header_t)] = is_ok ? 'o' : 'N';
|
||||
res_buf[sizeof(mozen_tunnel_header_t) + 1] = is_ok ? 'k' : 'G';
|
||||
// tunnel messages go through IRQ buffer context to avoid disrupting main buffer?
|
||||
// The previous implementation used the default send context.
|
||||
mozen_protocol_send_frame(tunnel->prot, MOZEN_TUNNEL_COMMAND_ID, res_buf, sizeof(res_buf), true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle a received tunnel frame
|
||||
* tunnel: tunnel context
|
||||
* data: received data
|
||||
* length: received data length
|
||||
* returns: none
|
||||
*/
|
||||
static void mozen_tunnel_abort(mozen_tunnel_t *tunnel)
|
||||
{
|
||||
if (tunnel->is_active)
|
||||
{
|
||||
if (tunnel->on_finish)
|
||||
{
|
||||
tunnel->on_finish(tunnel->user_context, false);
|
||||
}
|
||||
tunnel->is_active = false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle a received tunnel frame
|
||||
* tunnel: tunnel context
|
||||
* data: received data
|
||||
* length: received data length
|
||||
* returns: none
|
||||
*/
|
||||
void mozen_tunnel_handle_command(mozen_tunnel_t *tunnel, const uint8_t *data, uint16_t length)
|
||||
{
|
||||
if (!tunnel || length < sizeof(mozen_tunnel_header_t)) return;
|
||||
|
||||
const mozen_tunnel_header_t *tunnel_header = (const mozen_tunnel_header_t *)data;
|
||||
const uint8_t *payload = data + sizeof(mozen_tunnel_header_t);
|
||||
uint16_t payload_len = length - sizeof(mozen_tunnel_header_t);
|
||||
|
||||
switch (tunnel_header->tunnel_type)
|
||||
{
|
||||
case TUNNEL_TYPE_HANDSHAKE: // handshake request
|
||||
{
|
||||
if (payload_len < sizeof(uint32_t) + sizeof(uint16_t)) return;
|
||||
|
||||
mozen_tunnel_abort(tunnel); // Abort any ongoing stream
|
||||
|
||||
tunnel->is_active = true;
|
||||
tunnel->target_cmd = tunnel_header->target_cmd;
|
||||
|
||||
memcpy(&tunnel->total_data_len, payload, sizeof(uint32_t));
|
||||
memcpy(&tunnel->total_packets, payload + sizeof(uint32_t), sizeof(uint16_t));
|
||||
|
||||
tunnel->next_packet_index = 1;
|
||||
tunnel->received_data_len = 0;
|
||||
|
||||
// Prepare and send handshake response
|
||||
uint8_t res_buf[sizeof(mozen_tunnel_handshake_res_t)];
|
||||
mozen_tunnel_handshake_res_t *res = (mozen_tunnel_handshake_res_t *)res_buf;
|
||||
res->header.tunnel_type = TUNNEL_TYPE_RESPONSE;
|
||||
res->header.target_cmd = tunnel_header->target_cmd;
|
||||
res->status = 0x6B6F; // 'ok' (little-endian: 'o' is 0x6F, 'k' is 0x6B)
|
||||
res->mtu = tunnel->mtu;
|
||||
|
||||
if (tunnel->prot)
|
||||
{
|
||||
mozen_protocol_send_frame(tunnel->prot, MOZEN_TUNNEL_COMMAND_ID, (uint8_t *)res, sizeof(mozen_tunnel_handshake_res_t), true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case TUNNEL_TYPE_DATA_TRANSFER: // data transfer
|
||||
{
|
||||
if (!tunnel->is_active || tunnel_header->target_cmd != tunnel->target_cmd) return;
|
||||
if (payload_len < sizeof(uint16_t)) return;
|
||||
|
||||
uint16_t packet_index;
|
||||
memcpy(&packet_index, payload, sizeof(uint16_t));
|
||||
|
||||
if (packet_index != tunnel->next_packet_index)
|
||||
{
|
||||
mozen_tunnel_send_response(tunnel, tunnel->target_cmd, false);
|
||||
mozen_tunnel_abort(tunnel);
|
||||
return;
|
||||
}
|
||||
|
||||
const uint8_t *chunk_data = payload + sizeof(uint16_t);
|
||||
uint16_t chunk_len = payload_len - sizeof(uint16_t);
|
||||
|
||||
bool accepted = true;
|
||||
|
||||
if (packet_index == 1)
|
||||
{
|
||||
if (tunnel->on_start)
|
||||
{
|
||||
accepted = tunnel->on_start(tunnel->user_context, tunnel->target_cmd, chunk_data, chunk_len);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tunnel->on_data)
|
||||
{
|
||||
accepted = tunnel->on_data(tunnel->user_context, chunk_data, chunk_len);
|
||||
}
|
||||
}
|
||||
|
||||
if (!accepted)
|
||||
{
|
||||
mozen_tunnel_send_response(tunnel, tunnel->target_cmd, false);
|
||||
mozen_tunnel_abort(tunnel);
|
||||
return;
|
||||
}
|
||||
|
||||
tunnel->received_data_len += chunk_len;
|
||||
tunnel->next_packet_index++;
|
||||
|
||||
mozen_tunnel_send_response(tunnel, tunnel->target_cmd, true);
|
||||
|
||||
if (tunnel->next_packet_index > tunnel->total_packets)
|
||||
{
|
||||
if (tunnel->received_data_len == tunnel->total_data_len)
|
||||
{
|
||||
if (tunnel->on_finish)
|
||||
{
|
||||
tunnel->on_finish(tunnel->user_context, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tunnel->on_finish)
|
||||
{
|
||||
tunnel->on_finish(tunnel->user_context, false);
|
||||
}
|
||||
}
|
||||
tunnel->is_active = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
113
app_cail/moxzen_protocol/mozen_tunnel.h
Normal file
113
app_cail/moxzen_protocol/mozen_tunnel.h
Normal file
@@ -0,0 +1,113 @@
|
||||
#ifndef __MOZEN_TUNNEL_H
|
||||
#define __MOZEN_TUNNEL_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "mozen_protocol.h"
|
||||
|
||||
// --- Tunnel Protocol Definitions ---
|
||||
|
||||
#define MOZEN_TUNNEL_COMMAND_ID 0xFB // Tunnel command ID
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TUNNEL_TYPE_HANDSHAKE = 0x01, // Handshake request
|
||||
TUNNEL_TYPE_DATA_TRANSFER = 0x02, // Data transfer
|
||||
TUNNEL_TYPE_RESPONSE = 0xFF, // Special type for responses
|
||||
} mozen_tunnel_type_t;
|
||||
|
||||
#pragma pack(1)
|
||||
// <20><><EFBFBD><EFBFBD>Э<EFBFBD><D0AD>ͷ<EFBFBD><CDB7><EFBFBD><EFBFBD>
|
||||
typedef struct {
|
||||
uint8_t tunnel_type;
|
||||
uint8_t target_cmd;
|
||||
} mozen_tunnel_header_t;
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ṹ<EFBFBD><E1B9B9>
|
||||
typedef struct {
|
||||
mozen_tunnel_header_t header;
|
||||
uint32_t total_data_length;
|
||||
uint16_t total_packets;
|
||||
} mozen_tunnel_handshake_req_t;
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݰ<EFBFBD><DDB0>ṹ<EFBFBD><E1B9B9>
|
||||
typedef struct {
|
||||
mozen_tunnel_header_t header;
|
||||
uint16_t status; // 'ok' or 'NG'
|
||||
uint16_t mtu;
|
||||
} mozen_tunnel_handshake_res_t;
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݴ<EFBFBD><DDB4><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ṹ<EFBFBD><E1B9B9>
|
||||
typedef struct {
|
||||
mozen_tunnel_header_t header;
|
||||
uint16_t packet_index;
|
||||
uint8_t data_chunk[]; // Flexible array member for data
|
||||
} mozen_tunnel_data_t;
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӧ<EFBFBD>ṹ<EFBFBD><E1B9B9>
|
||||
typedef struct {
|
||||
mozen_tunnel_header_t header;
|
||||
uint16_t status; // 'ok' or 'NG'
|
||||
} mozen_tunnel_response_t;
|
||||
#pragma pack()
|
||||
|
||||
// --- Tunnel Context and Callbacks ---
|
||||
|
||||
/**
|
||||
* @brief Callback for starting a stream write.
|
||||
* @param context User context.
|
||||
* @param target_cmd The command indicating the stream target.
|
||||
* @param first_chunk_data The first chunk of data, useful for analyzing sub-headers.
|
||||
* @param chunk_len Length of the first chunk.
|
||||
* @return True if streaming can begin, false to reject.
|
||||
*/
|
||||
typedef bool (*mozen_tunnel_on_stream_start_t)(void *context, uint8_t target_cmd, const uint8_t *first_chunk_data, uint16_t chunk_len);
|
||||
|
||||
/**
|
||||
* @brief Callback for continuing a stream write.
|
||||
* @param context User context.
|
||||
* @param data Chunk data.
|
||||
* @param len Chunk length.
|
||||
* @return True if chunk accepted, false to abort.
|
||||
*/
|
||||
typedef bool (*mozen_tunnel_on_stream_data_t)(void *context, const uint8_t *data, uint16_t len);
|
||||
|
||||
/**
|
||||
* @brief Callback for finishing a stream write.
|
||||
* @param context User context.
|
||||
* @param success True if the transfer completed successfully, false if aborted.
|
||||
*/
|
||||
typedef void (*mozen_tunnel_on_stream_finish_t)(void *context, bool success);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
bool is_active;
|
||||
uint8_t target_cmd;
|
||||
uint32_t total_data_len;
|
||||
uint16_t total_packets;
|
||||
uint16_t next_packet_index;
|
||||
uint32_t received_data_len;
|
||||
|
||||
// Config
|
||||
uint16_t mtu; // Max packet size
|
||||
mozen_protocol_t *prot; // For sending ACKs
|
||||
void *user_context; // For callbacks
|
||||
|
||||
// Callbacks
|
||||
mozen_tunnel_on_stream_start_t on_start;
|
||||
mozen_tunnel_on_stream_data_t on_data;
|
||||
mozen_tunnel_on_stream_finish_t on_finish;
|
||||
} mozen_tunnel_t;
|
||||
|
||||
// --- API ---
|
||||
|
||||
void mozen_tunnel_init(mozen_tunnel_t *tunnel, mozen_protocol_t *prot, uint16_t mtu, void *user_context);
|
||||
|
||||
void mozen_tunnel_set_callbacks(mozen_tunnel_t *tunnel,
|
||||
mozen_tunnel_on_stream_start_t on_start,
|
||||
mozen_tunnel_on_stream_data_t on_data,
|
||||
mozen_tunnel_on_stream_finish_t on_finish);
|
||||
|
||||
void mozen_tunnel_handle_command(mozen_tunnel_t *tunnel, const uint8_t *data, uint16_t length);
|
||||
|
||||
#endif // __MOZEN_TUNNEL_H
|
||||
Reference in New Issue
Block a user