/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : UARTCallback.c * @brief : ****************************************************************************** * @attention * * Copyright (c) 2025 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** */ /* USER CODE END Header */ /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "FreeRTOS.h" #include "cmsis_os.h" #include "task.h" #include "queue.h" #include "main.h" #include "Callback.h" #include "Modbussimple.h" #include "FLASH.h" #include "DRV8837D.h" #include "kv_flash.h" /* USER CODE END Includes */ /* Exported types ------------------------------------------------------------*/ /* USER CODE BEGIN ET */ extern DMA_HandleTypeDef hdma_usart1_rx; extern DMA_HandleTypeDef hdma_usart2_rx; extern osThreadId_t ReadTaskHandle; extern osMessageQueueId_t uart485rxqueueHandle; extern osMessageQueueId_t consolemsgqueueHandle; extern uint8_t dataReceive485[BUFFER_SIZE485]; // 485 extern uint8_t dataReceivep[BUFFER_SIZEP]; // 调试 extern uint32_t uartIRQ_rx_len; // 485串口接收数据长度 extern uint32_t uartprint_rx_len ; /* * @ 多功能API阀参数信息 */ uint16_t Valve_status = 0; // 阀状态0000关0001开 uint32_t uint_liquidHeight = 0; // 液位高度 uint32_t uint_oil_percent = 0; // 油水百分比 uint32_t uint_filtered_cap = 0; // 滤波之后的电容值 /* USER CODE END ET */ /* Exported functions prototypes ---------------------------------------------*/ void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) // UART 接收完成回调 { if (huart->Instance == USART1) HAL_GPIO_WritePin(GPIOA, RS485_RD_Pin, GPIO_PIN_RESET); } void UART1_IdleCallback(void) { HAL_UART_DMAStop(&huart1); // 停止 DMA,获取剩余数据长度 uint32_t remain = __HAL_DMA_GET_COUNTER(&hdma_usart1_rx); uartIRQ_rx_len = BUFFER_SIZE485 - remain; if (uartIRQ_rx_len == 0 || uartIRQ_rx_len > BUFFER_SIZE485) { // 异常长度,忽略 Restart_UART1_DMA(); return; } Uart485Rx_msg uart485_msg; memset(&uart485_msg, 0, sizeof(uart485_msg)); uart485_msg.len = uartIRQ_rx_len; memcpy(uart485_msg.data, dataReceive485, uartIRQ_rx_len); // 只拷贝有效长度 BaseType_t xHigherPriorityTaskWoken = pdFALSE; if (xQueueSendToBackFromISR(uart485rxqueueHandle, &uart485_msg, &xHigherPriorityTaskWoken) != pdPASS) { // 队列满,移出一个旧数据再塞入 Uart485Rx_msg discard_msg; xQueueReceiveFromISR(uart485rxqueueHandle, &discard_msg, &xHigherPriorityTaskWoken); xQueueSendToBackFromISR(uart485rxqueueHandle, &uart485_msg, &xHigherPriorityTaskWoken); } Restart_UART1_DMA(); // 重启 DMA 接收 } void UART2_IdleCallback(void) { HAL_UART_DMAStop(&huart2); // 计算接收长度 uint32_t remain = __HAL_DMA_GET_COUNTER(&hdma_usart2_rx); uartprint_rx_len = BUFFER_SIZEP - remain; if (uartprint_rx_len < 4 || uartprint_rx_len > BUFFER_SIZEP) { Restart_UART2_DMA(); // 长度异常直接重启 DMA return; } Console_msg console_msg; memset(&console_msg, 0, sizeof(console_msg)); // BaseType_t xHigherPriorityTaskWoken = pdFALSE; console_msg.len = uartprint_rx_len; memcpy(console_msg.data, dataReceivep, uartprint_rx_len); // 拷贝接收数据 memset(dataReceivep, 0, sizeof(dataReceivep)); if (xQueueSendToBackFromISR(consolemsgqueueHandle, &console_msg, &xHigherPriorityTaskWoken) != pdPASS) // FreeRTOS 原生 API { Console_msg discard_msg; xQueueReceiveFromISR(consolemsgqueueHandle, &discard_msg, &xHigherPriorityTaskWoken); // 丢弃队首 xQueueSendToBackFromISR(consolemsgqueueHandle, &console_msg, &xHigherPriorityTaskWoken); } } void Process_Consolecallback(void) // 处理控制台命令 { Console_msg conmsg; if (osMessageQueueGet(consolemsgqueueHandle, &conmsg, NULL, 0) == osOK) { // CMSIS API if (conmsg.len > 0 && conmsg.data[0] != '\0'){ // 过滤空命令 parse_AT_command(conmsg.data); } Restart_UART2_DMA(); } } void Process_Uart485callback(void) { Uart485Rx_msg rxMsg; if (osMessageQueueGet(uart485rxqueueHandle, &rxMsg, NULL, 0) == osOK) { DEBUG_PRINTF("485rxBuffer: "); for (int i = 0; i < rxMsg.len; i++) { DEBUG_PRINTF("%02X ", rxMsg.data[i]); } DEBUG_PRINTF("\n"); // if(Systemmode != releasemode) // { // taskprint(rxMsg.data, rxMsg.len); // } if (is_modbus_03_response(rxMsg.data)) { // 处理03读指令 process_modbus_03(rxMsg.data); return; } if (is_modbus_06_response(rxMsg.data)) { // 处理06写单指令 process_modbus_06(rxMsg.data); return; } if (is_modbus_10_response(rxMsg.data)) { // 处理10写多指令 process_modbus_10(rxMsg.data); return; } if (is_modbus_42_response(rxMsg.data)) { // 处理42升级指令 process_modbus_42(rxMsg.data); return; } } } bool is_modbus_03_response(uint8_t *data) { if (!((data[0] == (JsRoot.addr & 0xFF) || data[0] == 0xFF) && data[1] == 0x03)) return false; // 不匹配,直接返回 false uint16_t crc_received = (data[7] << 8) | data[6]; uint16_t crc_calculated = modbus_crc16(data, 6); return memcmp(&crc_received, &crc_calculated, sizeof(crc_calculated)) == 0; } void process_modbus_03(uint8_t *data) { memset(g_modbusbuffer, 0, sizeof(g_modbusbuffer)); // 清零缓存,防止旧数据影响 uint8_t *tx_buf = (uint8_t *)g_modbusbuffer; // 强制转成字节指针 uint8_t func_code = data[1]; // 功能码 uint16_t reg_addr = (data[2] <<8) | data[3]; // 寄存器地址 uint8_t reg_count = data[5]; // 寄存器数量 // 最多读取125个寄存器(Modbus限制) if (reg_count == 0 || reg_count > 125) return; // 填充应答头部 tx_buf[0] = JsRoot.addr & 0xFF; tx_buf[1] = func_code; tx_buf[2] = reg_count * 2; uint16_t data_len = 0; bool found = read_modbus_registers(reg_addr, reg_count, &tx_buf[3], &data_len); if (!found) return; // 地址非法 // 计算CRC uint16_t crc = modbus_crc16(tx_buf, 3 + data_len); tx_buf[3 + data_len] = crc & 0xFF; tx_buf[4 + data_len] = (crc >> 8) & 0xFF; // 发送帧长度 uint16_t total_len = 5 + data_len; uart485send(tx_buf, total_len); } bool is_modbus_06_response(uint8_t *data) { if (!((data[0] == (JsRoot.addr & 0xFF) || data[0] == 0xFF)&& data[1] == 0x06)) return false; // 不匹配,直接返回 false uint16_t crc_received = (data[7] << 8) | data[6]; uint16_t crc_calculated = modbus_crc16(data, 6); return memcmp(&crc_received, &crc_calculated, sizeof(crc_calculated)) == 0; } void process_modbus_06(uint8_t *data) { memset(g_modbusbuffer, 0, sizeof(g_modbusbuffer)); uint8_t* tx_buf = (uint8_t *)g_modbusbuffer; uint8_t func_code = data[1]; uint16_t reg_addr = (data[2] << 8) | data[3]; uint16_t reg_data = (data[4] << 8) | data[5]; bool found = false; for (size_t i = 0; i < REGISTER_MAP_SIZE; ++i) { if (WriteReg_map[i].address == reg_addr) { found = true; if (WriteReg_map[i].handler(reg_data)) { break; } else { return; } } } if (!found) { return; // 地址无效,不做任何处理 } // 构造应答 uint16_t len = 0; tx_buf[len++] = JsRoot.addr; tx_buf[len++] = func_code; tx_buf[len++] = (reg_addr >> 8) & 0xFF; tx_buf[len++] = reg_addr & 0xFF; tx_buf[len++] = (reg_data >> 8) & 0xFF; tx_buf[len++] = reg_data & 0xFF; uint16_t crc = modbus_crc16(tx_buf, len); tx_buf[len++] = crc & 0xFF; tx_buf[len++] = (crc >> 8) & 0xFF; uart485send(tx_buf, len); } bool is_modbus_10_response(uint8_t *data) { if (!((data[0] == (JsRoot.addr & 0xFF) || data[0] == 0xFF)&& data[1] == 0x10)) return false; // 不匹配,直接返回 false uint16_t crc_received = (data[uartIRQ_rx_len-1] << 8) | data[uartIRQ_rx_len - 2]; uint16_t crc_calculated = modbus_crc16(data, uartIRQ_rx_len - 2); if (crc_received != crc_calculated) { return false; // 返回false,不执行后续处理 } return true; // CRC正确 } void process_modbus_10(uint8_t *data) { memset(g_modbusbuffer, 0, sizeof(g_modbusbuffer)); uint8_t *tx_buf = (uint8_t *)g_modbusbuffer; uint8_t func_code = data[1]; uint16_t reg_addr = (data[2] << 8) | data[3]; uint16_t reg_count = (data[4] << 8) | data[5]; // uint16_t byte_count = data[6]; // 数据段转成 uint16_t 数组 uint16_t values[reg_count]; for (uint16_t i = 0; i < reg_count; i++) { values[i] = (data[7 + i * 2] << 8) | data[8 + i * 2]; } bool found = false; for (size_t i = 0; i < MULTI_REGISTER_MAP_SIZE; i++) { if (WriteMultiReg_map[i].start_address == reg_addr && WriteMultiReg_map[i].reg_count == reg_count) { found = true; if (!WriteMultiReg_map[i].handler(values, WriteMultiReg_map[i].arg)) { return; // 处理失败,不应答 } break; } } if (!found) { return; } // 构造应答帧 uint16_t len = 0; tx_buf[len++] = JsRoot.addr; tx_buf[len++] = func_code; tx_buf[len++] = (reg_addr >> 8) & 0xFF; tx_buf[len++] = reg_addr & 0xFF; tx_buf[len++] = (reg_count >> 8) & 0xFF; tx_buf[len++] = reg_count & 0xFF; uint16_t crc = modbus_crc16(tx_buf, len); tx_buf[len++] = crc & 0xFF; tx_buf[len++] = (crc >> 8) & 0xFF; uart485send(tx_buf, len); } bool is_modbus_42_response(uint8_t *data) { // 检查前个字节是否符合要求 if (!((data[0] == (JsRoot.addr & 0xFF) && data[0] == 0xFF)&& data[1] == 0x42 && data[2] == 0xAA && data[3] == 0xBB)) return false; // 不匹配,直接返回 false uint16_t crc_received = (data[uartIRQ_rx_len-1] << 8) | data[uartIRQ_rx_len - 2]; uint16_t crc_calculated = modbus_crc16(data, uartIRQ_rx_len - 2); if (crc_received != crc_calculated) { return false; // 返回false,不执行后续处理 } return true; // CRC正确 } void process_modbus_42(uint8_t *data) { memset(g_modbusbuffer, 0, sizeof(g_modbusbuffer)); // 清零缓存,防止旧数据影响 uint16_t iapDataCommandCode = (data[4] <<8) |data[5]; // IAP数据的命令码 switch(iapDataCommandCode) { case 0x4000: // 升级程序起始帧 handle_upgrade_start_frame(data); break; case 0x4001: // 升级程序数据帧 handle_upgrade_data_frame(data); break; case 0x4002: // 升级程序结束帧 handle_upgrade_end_frame(); break; default: send_upgrade_end_response(0x42, 0xAABB, 0x07, 0x0000); // 命令码错误 break; } } bool is_modbus_errorfunc_response(uint8_t *data) { // 检查从机地址是否符合要求(等于 JsRoot.addr 或 0xFF) bool is_valid_addr = (data[0] == (JsRoot.addr & 0xFF)) || (data[0] == 0xFF); // 检查功能码是否不在允许的范围内(0x03, 0x06, 0x10, 0x42) bool is_invalid_func = (data[1] != 0x03) && (data[1] != 0x06) && (data[1] != 0x10) && (data[1] != 0x42); if (is_valid_addr && is_invalid_func) { uint16_t crc_received = (data[7] << 8) | data[6]; uint16_t crc_calculated = modbus_crc16(data, 6); return (memcmp(&crc_received, &crc_calculated, sizeof(crc_received)) == 0); } return false; // 不匹配,直接返回 false } void process_modbus_errorfunc(uint8_t *data) { memset(g_modbusbuffer, 0, sizeof(g_modbusbuffer)); // 清零缓存,防止旧数据影响 uint8_t *tx_buf = (uint8_t *)g_modbusbuffer; // 强制转成字节指针 uint8_t func_code = data[1]; // 功能码 uint8_t total_len = 0; total_len = modbus_error_response(JsRoot.addr & 0xFF, func_code, 0x01, tx_buf); // 功能码错误 uart485send(tx_buf, total_len); } bool is_modbus_error_regaddr_response(uint8_t *data) { // 检查从机地址是否符合要求(等于 JsRoot.addr 或 0xFF) bool is_valid_addr = (data[0] == (JsRoot.addr & 0xFF)) || (data[0] == 0xFF); // 检查功能码是否不在允许的范围内(0x03, 0x06, 0x10, 0x42) bool is_valid_func = (data[1] == 0x03) || (data[1] == 0x06) || (data[1] == 0x10) || (data[1] == 0x42); uint16_t reg_addr = (data[2] <<8) | data[3]; // 寄存器地址 // 检查寄存器地址是否不在允许的范围内(0x0000 到 0x001D 之间,0xAABB) bool is_invalid_regaddr = (reg_addr > 0x0021) && (reg_addr != 0xAABB); if (is_valid_addr && is_valid_func && is_invalid_regaddr) { uint16_t crc_received = (data[7] << 8) | data[6]; uint16_t crc_calculated = modbus_crc16(data, 6); return (memcmp(&crc_received, &crc_calculated, sizeof(crc_received)) == 0); } return false; // 不匹配,直接返回 false } void process_modbus_error_regaddr(uint8_t *data) { memset(g_modbusbuffer, 0, sizeof(g_modbusbuffer)); // 清零缓存,防止旧数据影响 uint8_t *tx_buf = (uint8_t *)g_modbusbuffer; // 强制转成字节指针 uint8_t func_code = data[1]; // 功能码 uint8_t total_len = 0; total_len = modbus_error_response(JsRoot.addr & 0xFF, func_code, 0x02, tx_buf); // 功能码错误 uart485send(tx_buf, total_len); } void process_modbus_error_data(uint8_t *data) { memset(g_modbusbuffer, 0, sizeof(g_modbusbuffer)); // 清零缓存,防止旧数据影响 uint8_t *tx_buf = (uint8_t *)g_modbusbuffer; // 强制转成字节指针 uint8_t func_code = data[1]; // 功能码 uint8_t total_len = modbus_error_response(JsRoot.addr & 0xFF, func_code, 0x03, tx_buf); // 功能码错误 uart485send(tx_buf, total_len); } void taskprint(uint8_t *tx_buf, uint16_t len) { char buf[1024]; int offset = 0; offset += snprintf(buf + offset, sizeof(buf) - offset, "RX_BUF: "); for (uint16_t i = 0; i < len && offset < sizeof(buf) - 2; i++) { // 防止越界 offset += snprintf(buf + offset, sizeof(buf) - offset, "%02X ", tx_buf[i]); } CommonPrintf("%s\r\n", buf); } void taskprinttx(uint8_t *tx_buf, uint16_t len) { char buf[128]; int offset = 0; offset += snprintf(buf + offset, sizeof(buf) - offset, "TX_BUF: "); for (uint16_t i = 0; i < len && offset < sizeof(buf) - 3; i++) { // 防止越界 offset += snprintf(buf + offset, sizeof(buf) - offset, "%02X ", tx_buf[i]); } CommonPrintf("%s\r\n", buf); } void uart485send(uint8_t *tx_buf, uint16_t total_len) { HAL_GPIO_WritePin(GPIOA, RS485_RD_Pin, GPIO_PIN_SET); // 拉高发送 HAL_UART_Transmit_DMA(&huart1, tx_buf, total_len); } void parse_AT_command(uint8_t *buf) { if (buf == NULL || buf[0] == '\0') // 去空 return; size_t len = strlen((char*)buf); // // 调试打印原始数据 // printf("Raw recv (len=%d): ", (int)len); // for (size_t i = 0; i < len; i++) { // if (buf[i] >= 32 && buf[i] <= 126) { // // 可打印字符 // printf("%c", buf[i]); // } else { // // 控制字符打印为 [xx] // printf("[0x%02X]", buf[i]); // } // } // printf("\r\n"); // 必须以 "###::" 开头 if (len < 5 || strncmp((char*)buf, "###::", 5) != 0) {// 排除不符帧头的命令串 printf("error=invalid prefix, rlt=401\r\n"); return; } // 必须以 "\r\n" 结尾 if (len < 5 || !(buf[len - 2] == '\r' && buf[len - 1] == '\n')) { printf("error=invalid ending, rlt=402\r\n"); return; } buf[len - 2] = '\0'; // 去掉 \r\n char *cmd = (char*)buf + 5; // 去掉开头 "###::" // printf("AT Raw: %s\r\n", buf); // ================== 文档命令判断 ================== if (strncmp(cmd, "--debug=", 8) == 0) { // 控制台调试时限 int minutes = atoi(cmd + 8); // 限制范围:UART1 特殊限制 if (minutes >= 0 && minutes <= 1440) { // uint32_t debug_console_timeout = minutes; printf("Debug console %s, timeout=%d min\r\n, OK", (minutes > 0) ? "enabled" : "disabled", minutes); } else { printf("Invalid debug time\r\n"); } return; } if (strcmp(cmd, "ls") == 0) { // printf("ls OK \r\n"); print_JsRoot(); // 数据缓存 dump 输出 return; } if (strncmp(cmd, "{\"mac\":\"", 8) == 0) { handle_mac_set_cmd(cmd); // 设置设备sn return; } if (strncmp(cmd, "--set_time=", 11) == 0) { printf("no rtc time, ok\r\n"); // 设置系统时间 return; } if (strncmp(cmd, "--cfg_set=", 10) == 0) { handle_cfg_set_cmd(cmd); // 系统配置-KV设置 return; } if (strncmp(cmd, "--cfg_setx=", 11) == 0) { handle_cfg_setx_cmd(cmd); // 通用配置-KV设置 return; } if (strncmp(cmd, "--cfg_get=", 10) == 0) { handle_cfg_get_cmd(cmd); // 读取键值内容 return; } if (strcmp(cmd, "reboot") == 0) { printf("ok\r\n"); NVIC_SystemReset(); // 重启设备 return; } if (strncmp(cmd, "--fileid=", 9) == 0) { handle_fileid_cmd(cmd); // 读取库存信息 return; } if (strncmp(cmd, "--clear_fileid=", 15) == 0) { handle_clear_fileid_cmd(cmd); // 清除内部配置库 return; } if (strncmp(cmd, "--iwdg_get", 10) == 0) { if (__HAL_RCC_GET_FLAG(RCC_FLAG_IWDGRST)) // 清除复位标志 { printf ("\r\n IWDG_RST flag"); __HAL_RCC_CLEAR_RESET_FLAGS(); // 清除所有复位标志(包括IWDG复位标志) }else{ printf ("\r\n No IWDG_RST flag"); } return; } if (strncmp(cmd, "--Stack_size", 12) == 0) { Read_Remaining_stack_space(); // 读取每个任务栈剩余空间 return; } if (strncmp(cmd, "--debug_printf=", 15) == 0) { char val = cmd[15]; if (val == '0' || val == '1') { debug_print_enabled = (val == '1') ? 1 : 0; printf("Debug print %s\r\n", debug_print_enabled ? "enabled" : "disabled"); } else { printf("Invalid debugprintf value: %c\r\n", val); } return; } if (strncmp(cmd, "--fdc_printf=", 13) == 0) { char val = cmd[13]; if (val == '0' || val == '1') { fdc_print_enabled = (val == '1') ? 1 : 0; printf("FDC print %s\r\n", fdc_print_enabled ? "enabled" : "disabled"); } else { printf("Invalid fdcprintf value: %c\r\n", val); } return; } if (strncmp(cmd, "--ads_printf=", 13) == 0) { char val = cmd[13]; if (val == '0' || val == '1') { ads_print_enabled = (val == '1') ? 1 : 0; printf("ADS print %s\r\n", ads_print_enabled ? "enabled" : "disabled"); } else { printf("Invalid adsprintf value: %c\r\n", val); } return; } if (strncmp((char*)cmd, "help", 4) == 0) { CommonPrintf("--debug=X\r\n"); CommonPrintf("ls\r\n"); CommonPrintf("{\"mac\":\"X\"}\r\n"); CommonPrintf("--cfg_set=${key1}=${val1}\r\n"); CommonPrintf("--cfg_setx=X,${key}=${val}\r\n"); CommonPrintf("--cfg_get=${key}\r\n"); CommonPrintf("reboot\r\n"); CommonPrintf("--fileid=X,0\r\n"); CommonPrintf("--clear_fileid=X\r\n"); CommonPrintf("--iwdg_get\r\n"); CommonPrintf("--Stack_size\r\n"); CommonPrintf("--debug_printf=X\r\n"); CommonPrintf("--fdc_printf=X\r\n"); CommonPrintf("--ads_printf=X\r\n"); return; } printf("error=unknown command, rlt=409\r\n"); // 未识别的命令 // // AT+sys=release\r\n 更改系统模式为发布模式 // if (strncmp((char*)buf, "AT+sys=release", 14) == 0) // { // Systemmode = releasemode; // printf(" Systemmode = releasemode \r\n"); // return; // } // // AT+sys=iapboot\r\n 更改系统模式为升级模式 // if (strncmp((char*)buf, "AT+sys=iapboot", 14) == 0) // { // Systemmode = IAPbootloader; // printf(" Systemmode = iapbootloader \r\n"); // return; // } // // AT+sys=debug\r\n 更改系统模式为调试模式 // if (strncmp((char*)buf, "AT+sys=debug", 12) == 0) // { // Systemmode = Debugmode; // printf(" Systemmode = debugmode \r\n"); // return; // } } void print_JsRoot(void) { // 打印 JsonDat_Root 基础字段 CommonPrintf( "mac=%s, addr=%u, role=%d, vers_id=%u, age=%d, age_ms=%ld, " "iapSize=%d, iapMd5=%s, iapLoadStatus=%u, subcode=%u, ubootback=%d, " "debug=%d, console=%d, baudrate=%d, update_ok=%d, update_err=%d\n", JsRoot.mac, JsRoot.addr, JsRoot.role, JsRoot.vers_id, JsRoot.age, JsRoot.age_ms, JsRoot.iapSize, JsRoot.iapMd5, JsRoot.iapLoadStatus, JsRoot.subcode, JsRoot.ubootback, JsRoot.debug, JsRoot.console, JsRoot.baudrate, JsRoot.update_ok, JsRoot.update_err ); // 打印 calib_rod CommonPrintf("[calib_rod.vol_values]="); for (int i = 0; i < CALIB_ROD_POINT_NUM; i++) { CommonPrintf("%.3f%s", JsWork.calib_rod.vol_values[i], (i < CALIB_ROD_POINT_NUM - 1) ? "," : "\n"); } // 打印 calib_oil_water CommonPrintf("[calib_oil_water.cap_values]="); for (int i = 0; i < CALIB_POINT_NUM; i++) { CommonPrintf("%.3f%s", JsWork.calib_oil_water.cap_values[i], (i < CALIB_POINT_NUM - 1) ? "," : "\n"); } // 打印 calib_residual_oil CommonPrintf("[calib_residual_oil.cap_values]="); for (int i = 0; i < CALIB_HEIGHT_POINT_NUM; i++) { CommonPrintf("%.3f%s", JsWork.calib_residual_oil.cap_values[i], (i < CALIB_HEIGHT_POINT_NUM - 1) ? "," : "\n"); } CommonPrintf("[calib_residual_oil.vol_values]="); for (int i = 0; i < CALIB_HEIGHT_POINT_NUM; i++) { CommonPrintf("%.3f%s", JsWork.calib_residual_oil.vol_values[i], (i < CALIB_HEIGHT_POINT_NUM - 1) ? "," : "\n"); } // 打印 JsWork 其他 float 字段 CommonPrintf( "rod_vol_offset=%.3f, rod_dialog=%.3f, " "oil_para_indu=%.3f, oil_para_cap=%.3f, oil_cap_offset=%.3f, oil_dialog=%.3f, rod_coltime=%d\n", JsWork.rod_vol_offset, JsWork.rod_dialog, JsWork.oil_para_indu, JsWork.oil_para_cap, JsWork.oil_cap_offset, JsWork.oil_dialog, JsWork.rod_coltime ); CommonPrintf( "res_para_indu=%.3f, res_para_cap=%.3f, res_cap_offset=%.3f, res_vol_offset=%.3f, " "res_cap_dialog=%.3f, res_vol_dialog=%.3f, res_oil_cap_coltime=%d, res_oil_vol_coltime=%d\n", JsWork.res_para_indu, JsWork.res_para_cap, JsWork.res_cap_offset, JsWork.res_vol_offset, JsWork.res_cap_dialog, JsWork.res_vol_dialog, JsWork.res_oil_cap_coltime, JsWork.res_oil_vol_coltime ); CommonPrintf( "temp_vol_offset=%.3f, temp_dialog=%.3f, temp_coltime=%d\n", JsWork.temp_vol_offset, JsWork.temp_dialog, JsWork.temp_coltime ); } /* USER CODE BEGIN EFP */