polarimeter_software/User/app/mb_hmi/mb_command.c
2025-09-30 10:37:23 +08:00

426 lines
16 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* @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 <stdio.h>
#include <string.h>
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, &reg_h, &reg_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, &reg_h, &reg_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, &reg_h, &reg_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, &reg_h, &reg_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; // 次数不能为00x01错误
}
// 写入底层寄存器
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);
}
}