#include "hmi_server.h"
#include "et_log.h"
#include "etk_utils.h"
#include "mb_command.h"
#include "mb_interface.h"
#include "bsp_hmi.h"
#include "bsp_motor.h"


nmbs_t            nmbs;
static rt_uint8_t mb_hmi_stack[HMI_THREAD_STACK_SIZE];
struct rt_thread  mb_hmi_thread;

static nmbs_error server_read_input_registers(uint16_t address, uint16_t quantity, uint16_t *registers_out,
                                              uint8_t unit_id, void *arg);

static nmbs_error server_read_holding_registers(uint16_t address, uint16_t quantity, uint16_t *registers_out,
                                                uint8_t unit_id, void *arg);
static nmbs_error server_write_single_register(uint16_t address, uint16_t value, uint8_t unit_id, void *arg);
static nmbs_error server_write_multiple_registers(uint16_t address, uint16_t quantity, const uint16_t *registers,
                                                  uint8_t unit_id, void *arg);

static nmbs_error nmbs_server_init(nmbs_t *nmbs)
{
    nmbs_platform_conf conf;
    nmbs_callbacks     cb;

    nmbs_platform_conf_create(&conf);

    conf.transport = NMBS_TRANSPORT_RTU;
    conf.read      = bsp_hmi_uart_read;
    conf.write     = bsp_hmi_uart_write;

    nmbs_callbacks_create(&cb);
    cb.read_coils               = NULL;
    cb.read_holding_registers   = server_read_holding_registers;
    cb.write_single_coil        = NULL;
    cb.write_multiple_coils     = NULL;
    cb.write_single_register    = server_write_single_register;
    cb.write_multiple_registers = server_write_multiple_registers;
    cb.read_input_registers     = server_read_input_registers;

    nmbs_error status = nmbs_server_create(nmbs, MB_SLAVE_ID, &conf, &cb);
    if (status != NMBS_ERROR_NONE)
    {
        return status;
    }

    nmbs_set_byte_timeout(nmbs, 100);
    nmbs_set_read_timeout(nmbs, 1000);

    return NMBS_ERROR_NONE;
}

static nmbs_error server_read_input_registers(uint16_t address, uint16_t quantity, uint16_t *registers_out,
                                              uint8_t unit_id, void *arg)
{
    ETK_UNUSED(unit_id);
    ETK_UNUSED(arg);
    return mb_handle_read_input_registers(address, quantity, registers_out);
}


static nmbs_error server_read_holding_registers(uint16_t address, uint16_t quantity, uint16_t *registers_out,
                                                uint8_t unit_id, void *arg)
{
    ETK_UNUSED(unit_id);
    ETK_UNUSED(arg);

    // 直接从底层寄存器区读取
    if (address + quantity > REG_BUF_SIZE)
    {
        ET_ERR("Read holding registers out of range: addr=%u, qty=%u", address, quantity);
        return NMBS_ERROR_INVALID_REQUEST;
    }

    mb_command_t *cmd = get_command_instance();
    if (cmd == RT_NULL)
    {
        ET_ERR("Failed to get command instance");
        return NMBS_ERROR_INVALID_ARGUMENT;
    }

    mb_command_t *get_command_instance(void);
    for (uint16_t i = 0; i < quantity; ++i)
    {
        registers_out[i] = cmd->regs[address + i];
        ET_DBG("Read holding register[%u] = 0x%04X", address + i, registers_out[i]);
    }

    return NMBS_ERROR_NONE;
}
// function: 0x06 Write Single Register

static nmbs_error server_write_single_register(uint16_t address, uint16_t value, uint8_t unit_id, void *arg)
{
    ETK_UNUSED(unit_id);
    ETK_UNUSED(arg);
    uint16_t reg = value;
    return server_write_multiple_registers(address, 1, &reg, unit_id, arg);
}

static nmbs_error server_write_multiple_registers(uint16_t address, uint16_t quantity, const uint16_t *registers,
                                                  uint8_t unit_id, void *arg)
{
    ETK_UNUSED(unit_id);
    ETK_UNUSED(arg);
    return mb_handle_write_holding_registers(address, quantity, registers);
}

static void mb_hmi_thread_entry(void *parameter)
{
    RT_UNUSED(parameter);

    while (1)
    {
        nmbs_server_poll(&nmbs);
        rt_thread_mdelay(20);
    }
}

int hmi_server_start(void)
{
    rt_err_t result;
    result = rt_thread_init(&mb_hmi_thread, "HMI", mb_hmi_thread_entry, RT_NULL, mb_hmi_stack, sizeof(mb_hmi_stack),
                            HMI_THREAD_PRIORITY, 50);
    if (result == RT_EOK)
    {
        ET_INFO("servo thread init success.");
        rt_thread_startup(&mb_hmi_thread);
    }
    else
    {
        ET_ERR("servo thread init failed.%d", result);
        return -1;
    }
    return 0;
}

int hmi_server_handler_register(hmi_server_t *hmi, mb_cmd_handler_t *handler)
{
    hmi->cmd.handler = handler;
    return 0;
}

int hmi_server_init(hmi_server_t *hmi)
{
    if (bsp_mb_hmi_init() != 0)
    {
        ET_ERR("Failed to initialize Modbus HMI");
        return -1;
    }
    mb_command_init(&hmi->cmd);
    mb_interface_init();
    nmbs_server_init(&nmbs);

    return 0;
}
