/* * @Author: mypx * @Date: 2025-08-01 16:41:44 * @LastEditTime: 2025-09-26 15:00:17 * @LastEditors: mypx mypx_coder@163.com * @Description: */ #include "mb_command.h" #include "et_log.h" #include "etk_byte_conv.h" #include "tec_control.h" #include #include static mb_cmd_handler_t *cmd_handler = NULL; static mb_command_t *mb_cmd = NULL; // external declaration for temperature control extern tec_control_t *tec_control; // Note: g_mb_regs was removed; use mb_command_t->input_regs as the authoritative cache static mb_cmd_handler_t *get_command_handler(void); mb_command_t *get_command_instance(void); // 输入寄存器同步接口 void mb_sync_running_status_reg(PmRunningState state) { mb_command_t *mb = get_command_instance(); if (!mb) return; mb->input_regs[INPUT_REG_DEV_RUNNING_STATE] = state; } void mb_sync_exception_reg(uint32_t exception, bool set) { mb_command_t *mb = get_command_instance(); if (!mb) return; if (set) { /* ALARM_STATUS occupies two registers (U32). We store as little-endian word pair * INPUT_REG_ALARM_STATUS = high-word? choose big-endian ordering consistent with docs. * Here we pack into two 16-bit words: high 16 bits and low 16 bits. */ uint32_t cur = ((uint32_t)mb->input_regs[INPUT_REG_ALARM_STATUS] << 16) | (uint32_t)mb->input_regs[INPUT_REG_ALARM_STATUS + 1]; cur |= exception; mb->input_regs[INPUT_REG_ALARM_STATUS] = (uint16_t)((cur >> 16) & 0xFFFF); mb->input_regs[INPUT_REG_ALARM_STATUS + 1] = (uint16_t)(cur & 0xFFFF); } else { uint32_t cur = ((uint32_t)mb->input_regs[INPUT_REG_ALARM_STATUS] << 16) | (uint32_t)mb->input_regs[INPUT_REG_ALARM_STATUS + 1]; cur &= ~exception; mb->input_regs[INPUT_REG_ALARM_STATUS] = (uint16_t)((cur >> 16) & 0xFFFF); mb->input_regs[INPUT_REG_ALARM_STATUS + 1] = (uint16_t)(cur & 0xFFFF); } } // 新增:同步实时温度到底层输入寄存器(ABCD顺序,2寄存器) void mb_sync_realtime_temp(float temperature) { mb_command_t *mb = get_command_instance(); if (!mb) return; uint16_t reg_h, reg_l; et_float_to_mb_abcd(temperature, ®_h, ®_l); if (mb->input_lock != RT_NULL) rt_mutex_take(mb->input_lock, RT_WAITING_FOREVER); mb->input_regs[INPUT_REG_REAL_TEMP_H] = reg_h; mb->input_regs[INPUT_REG_REAL_TEMP_L] = reg_l; if (mb->input_lock != RT_NULL) rt_mutex_release(mb->input_lock); } // 新增:同步实时旋光度到底层输入寄存器(ABCD顺序,2寄存器) void mb_sync_realtime_rotation(float rotation) { mb_command_t *mb = get_command_instance(); if (!mb) return; uint16_t reg_h, reg_l; et_float_to_mb_abcd(rotation, ®_h, ®_l); if (mb->input_lock != RT_NULL) rt_mutex_take(mb->input_lock, RT_WAITING_FOREVER); mb->input_regs[INPUT_REG_REAL_ROT_H] = reg_h; mb->input_regs[INPUT_REG_REAL_ROT_L] = reg_l; if (mb->input_lock != RT_NULL) rt_mutex_release(mb->input_lock); } // 新增:同步测量结果(模式、数值、温度)到底层输入寄存器 void mb_sync_result(uint8_t mode, float value, float temp) { uint16_t reg_h, reg_l; mb_command_t *mb = get_command_instance(); if (!mb) return; if (mb->input_lock != RT_NULL) rt_mutex_take(mb->input_lock, RT_WAITING_FOREVER); mb->input_regs[INPUT_REG_RESULT_MODE] = mode; et_float_to_mb_abcd(value, ®_h, ®_l); mb->input_regs[INPUT_REG_RESULT_VAL_H] = reg_h; mb->input_regs[INPUT_REG_RESULT_VAL_L] = reg_l; et_float_to_mb_abcd(temp, ®_h, ®_l); mb->input_regs[INPUT_REG_RESULT_TEMP_H] = reg_h; mb->input_regs[INPUT_REG_RESULT_TEMP_L] = reg_l; if (mb->input_lock != RT_NULL) rt_mutex_release(mb->input_lock); } void mb_sync_meas_done_flag(bool done) { mb_command_t *mb = get_command_instance(); if (!mb) return; if (mb->input_lock != RT_NULL) rt_mutex_take(mb->input_lock, RT_WAITING_FOREVER); mb->input_regs[INPUT_REG_MEAS_DONE_FLAG] = done ? 1 : 0; if (mb->input_lock != RT_NULL) rt_mutex_release(mb->input_lock); } // 处理保持寄存器写入 nmbs_error mb_handle_write_holding_registers(uint16_t address, uint16_t quantity, const uint16_t *registers) { mb_command_t *mb_cmd = get_command_instance(); mb_cmd_handler_t *handler = get_command_handler(); if (mb_cmd == NULL || handler == NULL) { ET_ERR("mb command instance failed"); return NMBS_EXCEPTION_SERVER_DEVICE_FAILURE; } switch (address) { case HOLD_REG_SYS_CTRL_CMD: // 系统控制命令(30001) if (quantity != 1) { ET_ERR("HOLD_REG_SYS_CTRL_CMD quantity error, expect 1, got %d", quantity); return NMBS_ERROR_INVALID_REQUEST; } if (handler->system_ctrl_handler) { handler->system_ctrl_handler(registers[0]); } mb_cmd->regs[address] = registers[0] & 0xFF; return NMBS_ERROR_NONE; case HOLD_REG_MEAS_MODE: // 测量模式设置(30002) if (quantity != 1) { ET_ERR("HOLD_REG_MEAS_MODE quantity error, expect 1, got %d", quantity); return NMBS_ERROR_INVALID_REQUEST; } mb_cmd->regs[address] = registers[0] & 0xFF; // 取低8位,写入底层寄存器 ET_INFO("Measurement mode set to: %d", mb_cmd->regs[address]); if (handler->meas_mode_handler) { handler->meas_mode_handler(mb_cmd->regs[address]); } return NMBS_ERROR_NONE; case HOLD_REG_TARGET_TEMP_H: // 目标温度设置(30003-30004) if (quantity != 2) { ET_ERR("HOLD_REG_TARGET_TEMP_H quantity error, expect 2, got %d", quantity); return NMBS_ERROR_INVALID_REQUEST; } float target_temp = et_mb_to_float_abcd(registers[0], registers[1]); // 温度范围检查(-10℃ ~ 100℃) if (target_temp > PM_TARGET_TEMP_MAX || target_temp < PM_TARGET_TEMP_MIN) { ET_ERR("HOLD_REG_TARGET_TEMP_H value error, expect:[%.2f~%.2f], got %.2f", PM_TARGET_TEMP_MIN, PM_TARGET_TEMP_MAX, target_temp); return NMBS_EXCEPTION_ILLEGAL_DATA_VALUE; } if (handler->target_temp_handler) { handler->target_temp_handler(target_temp); } // 写入底层寄存器(高16位和低16位) mb_cmd->regs[address] = registers[0]; mb_cmd->regs[address + 1] = registers[1]; ET_INFO("Target temperature set to: %.1f deg", target_temp); // send temperature update event if (tec_control && tec_control->control_event) { rt_event_send(tec_control->control_event, TEC_TEMP_UPDATE_EVENT); } ET_WARN("[MB] RX Target Temp: %.2f C", target_temp); return NMBS_ERROR_NONE; case HOLD_REG_TARGET_TEMP_L: // // 低16位单独写入时拒绝(需通过高地址写入2个寄存器) ET_ERR("[MB] RX Target Temp Low, Rejected"); return NMBS_ERROR_INVALID_REQUEST; case HOLD_REG_TUBE_LEN: // 旋光管长度设置(30005-30006) if (quantity != 1) { ET_ERR("[MB] RX HOLD_REG_TUBE_LEN quantity error, expect 2, got %d", quantity); return NMBS_ERROR_INVALID_REQUEST; } uint16_t tube_length = registers[0]; // 检查旋光管长度是否有效(>0) if (tube_length < PM_TUBE_LENGTH_MIN || tube_length > PM_TUBE_LENGTH_MAX) { ET_ERR("[MB] RX tube length value error, expect:[%d~%d], got %d", PM_TUBE_LENGTH_MIN, PM_TUBE_LENGTH_MAX, tube_length); return NMBS_EXCEPTION_ILLEGAL_DATA_VALUE; // 对应Modbus异常0x03 } if (handler->tube_length_handler) { handler->tube_length_handler(tube_length); } // 写入底层寄存器(高16位和低16位) mb_cmd->regs[address] = registers[0]; ET_INFO("Tube length set to: %d mm", tube_length); return NMBS_ERROR_NONE; case HOLD_REG_MEAS_PRECISION: // 测量精度设置(30007) if (quantity != 1) { ET_ERR("[MB] RX HOLD_REG_MEAS_PRECISION value error, must write one register"); return NMBS_ERROR_INVALID_REQUEST; } uint8_t measure_precision = registers[0] & 0xFF; if (handler->meas_precision_handler) { handler->meas_precision_handler(measure_precision); } // 写入底层寄存器 mb_cmd->regs[address] = measure_precision; ET_INFO("Measure precision set to: %d", measure_precision); return NMBS_ERROR_NONE; case HOLD_REG_AUTO_MEAS_CNT: // 自动测量次数(30008) if (quantity != 1) { ET_ERR("Auto measure count write error: %d", registers[0]); return NMBS_ERROR_INVALID_REQUEST; } float auto_measure_count = registers[0] & 0xFF; if (handler->auto_measure_count_handler) { handler->auto_measure_count_handler(auto_measure_count); } if (auto_measure_count == 0) { ET_ERR("Auto measure count write error: %d", auto_measure_count); return NMBS_ERROR_INVALID_REQUEST; // 次数不能为0(0x01错误) } // 写入底层寄存器 mb_cmd->regs[address] = auto_measure_count; ET_INFO("Auto measure count set to: %d", auto_measure_count); return NMBS_ERROR_NONE; case HOLD_REG_HIST_QUERY_START: // 历史数据查询范围(30009-30010) if (quantity != 2) { ET_ERR("History query start error, quantity error, expect 2, got %d", quantity); return NMBS_ERROR_INVALID_REQUEST; } uint8_t history_start = registers[0]; uint8_t history_count = registers[1]; // 检查历史数据范围有效性 if (history_count == 0 || history_count > 5) { ET_ERR("History query count error, expect 1-5, got %d", history_count); return NMBS_EXCEPTION_ILLEGAL_DATA_VALUE; // 对应Modbus异常0x03 } ET_INFO("History query range set: start=%d, count=%d", history_start, history_count); return NMBS_ERROR_NONE; default: return NMBS_ERROR_INVALID_REQUEST; } return NMBS_EXCEPTION_SERVER_DEVICE_FAILURE; } // 处理输入寄存器读取 nmbs_error mb_handle_read_input_registers(uint16_t address, uint16_t quantity, uint16_t *registers_out) { mb_command_t *mb = get_command_instance(); if (!mb) return NMBS_EXCEPTION_SERVER_DEVICE_FAILURE; if (address + quantity > 0x0029) return NMBS_ERROR_INVALID_REQUEST; for (uint16_t i = 0; i < quantity;) { uint16_t curr_addr = address + i; switch (curr_addr) { case INPUT_REG_REAL_TEMP_H: { if (mb->input_lock != RT_NULL) rt_mutex_take(mb->input_lock, RT_WAITING_FOREVER); registers_out[i++] = mb->input_regs[INPUT_REG_REAL_TEMP_H]; if (i < quantity) registers_out[i++] = mb->input_regs[INPUT_REG_REAL_TEMP_L]; if (mb->input_lock != RT_NULL) rt_mutex_release(mb->input_lock); ET_DBG("Send real temp high: 0x%x low: 0x%x", mb->input_regs[INPUT_REG_REAL_TEMP_H], mb->input_regs[INPUT_REG_REAL_TEMP_L]); break; } case INPUT_REG_REAL_ROT_H: { if (mb->input_lock != RT_NULL) rt_mutex_take(mb->input_lock, RT_WAITING_FOREVER); registers_out[i++] = mb->input_regs[INPUT_REG_REAL_ROT_H]; if (i < quantity) registers_out[i++] = mb->input_regs[INPUT_REG_REAL_ROT_L]; if (mb->input_lock != RT_NULL) rt_mutex_release(mb->input_lock); ET_DBG("Send real rot high: 0x%x low: 0x%x", mb->input_regs[INPUT_REG_REAL_ROT_H], mb->input_regs[INPUT_REG_REAL_ROT_L]); break; } case INPUT_REG_RESULT_MODE: registers_out[i++] = mb->input_regs[INPUT_REG_RESULT_MODE]; ET_DBG("Send result val high: 0x%x low: 0x%x", mb->input_regs[INPUT_REG_RESULT_VAL_H], mb->input_regs[INPUT_REG_RESULT_VAL_L]); break; case INPUT_REG_RESULT_VAL_H: { if (mb->input_lock != RT_NULL) rt_mutex_take(mb->input_lock, RT_WAITING_FOREVER); registers_out[i++] = mb->input_regs[INPUT_REG_RESULT_VAL_H]; if (i < quantity) registers_out[i++] = mb->input_regs[INPUT_REG_RESULT_VAL_L]; if (mb->input_lock != RT_NULL) rt_mutex_release(mb->input_lock); ET_DBG("Send result val high: 0x%x low: 0x%x", mb->input_regs[INPUT_REG_RESULT_VAL_H], mb->input_regs[INPUT_REG_RESULT_VAL_L]); break; } case INPUT_REG_RESULT_TEMP_H: { if (mb->input_lock != RT_NULL) rt_mutex_take(mb->input_lock, RT_WAITING_FOREVER); registers_out[i++] = mb->input_regs[INPUT_REG_RESULT_TEMP_H]; if (i < quantity) registers_out[i++] = mb->input_regs[INPUT_REG_RESULT_TEMP_L]; if (mb->input_lock != RT_NULL) rt_mutex_release(mb->input_lock); ET_DBG("Send result temp high: 0x%x low: 0x%x", mb->input_regs[INPUT_REG_RESULT_TEMP_H], mb->input_regs[INPUT_REG_RESULT_TEMP_L]); break; } case INPUT_REG_DEV_RUNNING_STATE: registers_out[i++] = mb->input_regs[INPUT_REG_DEV_RUNNING_STATE]; ET_DBG("Send device running state: %d", mb->input_regs[INPUT_REG_DEV_RUNNING_STATE]); break; case INPUT_REG_ALARM_STATUS: { /* Output two registers (high then low) representing 32-bit alarm bitmap */ registers_out[i++] = mb->input_regs[INPUT_REG_ALARM_STATUS]; if (i < quantity) registers_out[i++] = mb->input_regs[INPUT_REG_ALARM_STATUS + 1]; ET_DBG("Send alarm status high: 0x%x low: 0x%x", mb->input_regs[INPUT_REG_ALARM_STATUS], mb->input_regs[INPUT_REG_ALARM_STATUS + 1]); break; } case INPUT_REG_MEAS_DONE_FLAG: registers_out[i++] = mb->input_regs[INPUT_REG_MEAS_DONE_FLAG]; ET_DBG("Send meas done flag: %d", mb->input_regs[INPUT_REG_MEAS_DONE_FLAG]); break; case INPUT_REG_DEVICE_MODEL_H: registers_out[i++] = mb->input_regs[INPUT_REG_DEVICE_MODEL_H]; ET_DBG("Send device model high: 0x%x", mb->input_regs[INPUT_REG_DEVICE_MODEL_H]); break; case INPUT_REG_DEVICE_MODEL_L: registers_out[i++] = mb->input_regs[INPUT_REG_DEVICE_MODEL_L]; ET_DBG("Send device model low: 0x%x", mb->input_regs[INPUT_REG_DEVICE_MODEL_L]); break; case INPUT_REG_FW_VERSION_H: registers_out[i++] = mb->input_regs[INPUT_REG_FW_VERSION_H]; ET_DBG("Send firmware version high: 0x%x", mb->input_regs[INPUT_REG_FW_VERSION_H]); break; case INPUT_REG_FW_VERSION_L: registers_out[i++] = mb->input_regs[INPUT_REG_FW_VERSION_L]; ET_DBG("Send firmware version low: 0x%x", mb->input_regs[INPUT_REG_FW_VERSION_L]); break; default: return NMBS_ERROR_INVALID_REQUEST; } } return NMBS_ERROR_NONE; } mb_cmd_handler_t *get_command_handler(void) { return cmd_handler; } mb_command_t *get_command_instance(void) { return mb_cmd; } // 初始化命令模块 void mb_command_init(mb_command_t *cmd) { cmd_handler = cmd->handler; mb_cmd = cmd; /* create mutex for protecting input_regs (ignore if already created) */ if (mb_cmd->input_lock == RT_NULL) { mb_cmd->input_lock = rt_mutex_create("mb_in_lk", RT_IPC_FLAG_PRIO); } }