polarimeter_software/User/app/mb_hmi/mb_command.c

426 lines
16 KiB
C
Raw Normal View History

2025-09-30 02:37:23 +00:00
/*
* @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);
}
}