#include "modbus_m.h"
#include "myLog.h"
#include "myFunc.h"
#include "myCmd.h"
#include "myDatacenter.h"
#include "tinyxml2.h"

#include <algorithm>
#include <mutex>

using namespace tinyxml2;

LOCAL std::string g_modbus_m_base_path;
LOCAL stru_modbus_m_cfg g_modbus_m_cfg;
LOCAL std::mutex g_write_mutex;
LOCAL std::vector<stru_modbus_m_write_req> g_write_queue;


// ==================== 工具函数 ====================

LOCAL std::string get_base_path()
{
    char buf[512] = {0};

    /* 优先使用 WORK_PATH 环境变量（RK3568 装置运行时设置） */
    if (0 == func_get_work_path(buf, sizeof(buf)))
    {
        return std::string(buf) + "/";
    }

    /* fallback: 从可执行文件路径推导（本地调试用） */
    if (0 != func_proc_self_dir(buf, sizeof(buf)))
    {
        LOG_E("func_proc_self_dir failed");

        return "";
    }

    return std::string(buf) + "/";
}

// ==================== 数据类型映射 ====================

LOCAL uint8_t modbus_type_to_local_type(uint8_t type)
{
    switch (type)
    {
        case 2:  return DATA_TYPE_B;      // bit/线圈
        case 4:  return DATA_TYPE_U16;    // uint16
        case 6:  return DATA_TYPE_F32;    // float32
        case 7:  return DATA_TYPE_U32;    // uint32
        case 13: return DATA_TYPE_STR;    // string
        default: return DATA_TYPE_U16;
    }
}

LOCAL uint8_t dc_data_type_size(uint8_t data_type) __attribute__((unused));
LOCAL uint8_t dc_data_type_size(uint8_t data_type)
{
    switch (data_type)
    {
        case DATA_TYPE_B:   return 1;
        case DATA_TYPE_U8:  return 1;
        case DATA_TYPE_S16:
        case DATA_TYPE_U16: return 2;
        case DATA_TYPE_S32:
        case DATA_TYPE_U32:
        case DATA_TYPE_F32: return 4;
        case DATA_TYPE_STR: return 128;
        default:            return 2;
    }
}

// ==================== XML 解析 ====================

LOCAL int parse_channels(XMLElement *p_root)
{
    XMLElement *p_ch = p_root->FirstChildElement("Channel");
    while (NULL != p_ch)
    {
        stru_modbus_m_channel ch;
        ch.id = (uint32_t)p_ch->IntAttribute("id", 0);
        ch.mode = p_ch->Attribute("mode") ? p_ch->Attribute("mode") : "tcp";
        ch.host = p_ch->Attribute("host") ? p_ch->Attribute("host") : "";
        ch.port = (uint16_t)p_ch->IntAttribute("port", 502);
        ch.device = p_ch->Attribute("device") ? p_ch->Attribute("device") : "";
        ch.baud = p_ch->IntAttribute("baud", 9600);
        ch.parity = p_ch->Attribute("parity") ? p_ch->Attribute("parity")[0] : 'N';
        ch.data_bit = p_ch->IntAttribute("data_bit", 8);
        ch.stop_bit = p_ch->IntAttribute("stop_bit", 1);
        ch.timeout_ms = p_ch->IntAttribute("timeout_ms", 1000);
        ch.retry_cnt = p_ch->IntAttribute("retry_cnt", 3);
        ch.ctx = NULL;
        ch.connected = false;

        g_modbus_m_cfg.channels.push_back(ch);
        LOG_I("channel %d: mode=%s, host=%s:%d", ch.id, ch.mode.c_str(), ch.host.c_str(), ch.port);

        p_ch = p_ch->NextSiblingElement("Channel");
    }

    if (g_modbus_m_cfg.channels.empty())
    {
        LOG_E("no channel configured");
        return -1;
    }
    return 0;
}

LOCAL int parse_point_item(XMLElement *p_item, std::vector<stru_modbus_m_item> &vec)
{
    stru_modbus_m_item item;
    item.no = 0;
    item.type = 0;
    item.channel = 0;
    item.slave = 0;
    item.fc = 0;
    item.addr = 0;
    item.count = 0;
    item.bit = 0;
    item.factor = 0.0f;
    item.offset = 0.0f;
    item.p_val = NULL;

    item.no = (uint16_t)p_item->IntAttribute("no", 0);
    item.type = (uint8_t)p_item->IntAttribute("type", 4);
    item.channel = (uint32_t)p_item->IntAttribute("channel", 0);
    item.slave = (uint8_t)p_item->IntAttribute("slave", 1);
    item.fc = (uint8_t)p_item->IntAttribute("fc", 0x03);
    item.addr = (uint16_t)p_item->IntAttribute("addr", 0);
    item.count = (uint16_t)p_item->IntAttribute("count", 1);
    item.bit = (uint8_t)p_item->IntAttribute("bit", 0);
    item.factor = (float)p_item->FloatAttribute("factor", 1.0f);
    item.offset = (float)p_item->FloatAttribute("offset", 0.0f);

    if (NULL != p_item->Attribute("saddr"))
        item.saddr = p_item->Attribute("saddr");
    if (NULL != p_item->Attribute("desc"))
        item.desc = p_item->Attribute("desc");

    // 验证通道ID
    bool ch_found = false;
    for (auto &ch : g_modbus_m_cfg.channels)
    {
        if (ch.id == item.channel)
        {
            ch_found = true;
            break;
        }
    }
    if (!ch_found)
    {
        LOG_E("item no=%d: channel %d not found", item.no, item.channel);
        return -1;
    }

    // 创建数据指针
    uint8_t local_type = modbus_type_to_local_type(item.type);
    item.p_val = dc_create_data(local_type);
    if (NULL == item.p_val)
    {
        LOG_E("dc_create_data_ptr_by_type failed, type=%d", local_type);
        return -1;
    }

    vec.push_back(item);
    return 0;
}

LOCAL int parse_points(XMLElement *p_root)
{
    XMLElement *p_point = p_root->FirstChildElement("Point");
    if (NULL == p_point)
    {
        LOG_E("Point not found");
        return -1;
    }

    if (NULL != p_point->Attribute("desc"))
        g_modbus_m_cfg.point.desc = p_point->Attribute("desc");

    // 解析 St（遥信）
    XMLElement *p_st = p_point->FirstChildElement("St");
    if (NULL != p_st)
    {
        XMLElement *p_item = p_st->FirstChildElement("Item");
        while (NULL != p_item)
        {
            if (0 != parse_point_item(p_item, g_modbus_m_cfg.point.st_vec))
            {
                return -1;
            }
            p_item = p_item->NextSiblingElement("Item");
        }
        LOG_I("parsed %zu st items", g_modbus_m_cfg.point.st_vec.size());
    }

    // 解析 Mx（遥测）
    XMLElement *p_mx = p_point->FirstChildElement("Mx");
    if (NULL != p_mx)
    {
        XMLElement *p_item = p_mx->FirstChildElement("Item");
        while (NULL != p_item)
        {
            if (0 != parse_point_item(p_item, g_modbus_m_cfg.point.mx_vec))
            {
                return -1;
            }
            p_item = p_item->NextSiblingElement("Item");
        }
        LOG_I("parsed %zu mx items", g_modbus_m_cfg.point.mx_vec.size());
    }

    // 解析 Co（遥控）
    XMLElement *p_co = p_point->FirstChildElement("Co");
    if (NULL != p_co)
    {
        XMLElement *p_item = p_co->FirstChildElement("Item");
        while (NULL != p_item)
        {
            if (0 != parse_point_item(p_item, g_modbus_m_cfg.point.co_vec))
            {
                return -1;
            }
            p_item = p_item->NextSiblingElement("Item");
        }
        LOG_I("parsed %zu co items", g_modbus_m_cfg.point.co_vec.size());
    }

    // 解析 Ao（参数）
    XMLElement *p_ao = p_point->FirstChildElement("Ao");
    if (NULL != p_ao)
    {
        XMLElement *p_item = p_ao->FirstChildElement("Item");
        while (NULL != p_item)
        {
            if (0 != parse_point_item(p_item, g_modbus_m_cfg.point.ao_vec))
            {
                return -1;
            }
            p_item = p_item->NextSiblingElement("Item");
        }
        LOG_I("parsed %zu ao items", g_modbus_m_cfg.point.ao_vec.size());
    }

    return 0;
}

int modbus_m_cfg_parse(const std::string &path)
{
    XMLDocument doc;
    if (XML_SUCCESS != doc.LoadFile(path.c_str()))
    {
        LOG_E("load xml failed: %s", path.c_str());
        return -1;
    }

    XMLElement *p_root = doc.RootElement();
    if (NULL == p_root)
    {
        LOG_E("root element not found");
        return -1;
    }

    if (0 != parse_channels(p_root))
    {
        LOG_E("parse channels failed");
        return -1;
    }

    if (0 != parse_points(p_root))
    {
        LOG_E("parse points failed");
        return -1;
    }

    LOG_I("modbus_m cfg parsed: %zu channels, st=%zu, mx=%zu, co=%zu, ao=%zu",
        g_modbus_m_cfg.channels.size(),
        g_modbus_m_cfg.point.st_vec.size(),
        g_modbus_m_cfg.point.mx_vec.size(),
        g_modbus_m_cfg.point.co_vec.size(),
        g_modbus_m_cfg.point.ao_vec.size());

    return 0;
}


// ==================== 通道连接管理 ====================

LOCAL int channel_connect(stru_modbus_m_channel *p_ch)
{
    if (NULL == p_ch)
    {
        return -1;
    }

    // 释放旧连接
    if (NULL != p_ch->ctx)
    {
        modbus_close(p_ch->ctx);
        modbus_free(p_ch->ctx);
        p_ch->ctx = NULL;
    }

    // 创建上下文
    if (p_ch->mode == "tcp")
    {
        p_ch->ctx = modbus_new_tcp(p_ch->host.c_str(), p_ch->port);
        if (NULL == p_ch->ctx)
        {
            LOG_E("modbus_new_tcp failed: %s:%d", p_ch->host.c_str(), p_ch->port);
            return -1;
        }
        // TCP 模式下设置默认从站地址
        modbus_set_slave(p_ch->ctx, MODBUS_TCP_SLAVE);
    }
    else if (p_ch->mode == "rtu")
    {
        p_ch->ctx = modbus_new_rtu(p_ch->device.c_str(), p_ch->baud, p_ch->parity, p_ch->data_bit, p_ch->stop_bit);
        if (NULL == p_ch->ctx)
        {
            LOG_E("modbus_new_rtu failed: %s", p_ch->device.c_str());
            return -1;
        }
    }
    else
    {
        LOG_E("unknown mode: %s", p_ch->mode.c_str());
        return -1;
    }

    // 设置超时
    uint32_t sec = p_ch->timeout_ms / 1000;
    uint32_t usec = (p_ch->timeout_ms % 1000) * 1000;
    modbus_set_response_timeout(p_ch->ctx, sec, usec);
    modbus_set_error_recovery(p_ch->ctx, (modbus_error_recovery_mode)(MODBUS_ERROR_RECOVERY_LINK | MODBUS_ERROR_RECOVERY_PROTOCOL));

    // 建立连接
    if (0 != modbus_connect(p_ch->ctx))
    {
        LOG_E("modbus_connect failed: ch=%d, mode=%s", p_ch->id, p_ch->mode.c_str());
        modbus_free(p_ch->ctx);
        p_ch->ctx = NULL;
        p_ch->connected = false;
        return -1;
    }

    p_ch->connected = true;
    LOG_I("channel %d connected: mode=%s", p_ch->id, p_ch->mode.c_str());
    return 0;
}

LOCAL int channels_init()
{
    for (auto &ch : g_modbus_m_cfg.channels)
    {
        channel_connect(&ch);
    }
    return 0;
}

LOCAL void channels_close(void) __attribute__((unused));
LOCAL void channels_close()
{
    for (auto &ch : g_modbus_m_cfg.channels)
    {
        if (NULL != ch.ctx)
        {
            modbus_close(ch.ctx);
            modbus_free(ch.ctx);
            ch.ctx = NULL;
        }
        ch.connected = false;
    }
}


// ==================== 数据读取 ====================

// 读取线圈 (FC 0x01) 或离散输入 (FC 0x02)
LOCAL int read_bits(stru_modbus_m_channel *p_ch, uint8_t slave, uint8_t fc, uint16_t addr, uint16_t count, uint8_t *p_dest)
{
    if (NULL == p_ch || NULL == p_ch->ctx || !p_ch->connected)
    {
        return -1;
    }

    modbus_set_slave(p_ch->ctx, slave);

    int ret = -1;
    if (fc == 0x01)
    {
        ret = modbus_read_bits(p_ch->ctx, addr, count, p_dest);
    }
    else if (fc == 0x02)
    {
        ret = modbus_read_input_bits(p_ch->ctx, addr, count, p_dest);
    }

    return ret;
}

// 读取寄存器 (FC 0x03 或 0x04)
LOCAL int read_registers(stru_modbus_m_channel *p_ch, uint8_t slave, uint8_t fc, uint16_t addr, uint16_t count, uint16_t *p_dest)
{
    if (NULL == p_ch || NULL == p_ch->ctx || !p_ch->connected)
    {
        return -1;
    }

    modbus_set_slave(p_ch->ctx, slave);

    int ret = -1;
    if (fc == 0x03)
    {
        ret = modbus_read_registers(p_ch->ctx, addr, count, p_dest);
    }
    else if (fc == 0x04)
    {
        ret = modbus_read_input_registers(p_ch->ctx, addr, count, p_dest);
    }

    return ret;
}


// 读取单个 Item 值（按 fc 分发）
LOCAL int read_item_value(stru_modbus_m_channel *p_ch, stru_modbus_m_item *p_item) __attribute__((unused));
LOCAL int read_item_value(stru_modbus_m_channel *p_ch, stru_modbus_m_item *p_item)
{
    if (NULL == p_ch || NULL == p_item)
    {
        return -1;
    }

    uint8_t local_type = modbus_type_to_local_type(p_item->type);
    (void)local_type;

    // FC 0x01/0x02: 读线圈/离散输入（位）
    if (p_item->fc == 0x01 || p_item->fc == 0x02)
    {
        uint8_t bit_val = 0;
        int ret = read_bits(p_ch, p_item->slave, p_item->fc, p_item->addr, p_item->count, &bit_val);
        if (ret > 0)
        {
            uint8_t val = bit_val ? 1 : 0;
            memcpy(p_item->p_val, &val, 1);
        }
        return ret;
    }

    // FC 0x03/0x04: 读保持/输入寄存器
    if (p_item->fc == 0x03 || p_item->fc == 0x04)
    {
        // 临时缓冲区（最大 125 个寄存器）
        uint16_t reg_buf[256];
        uint16_t read_cnt = p_item->count > 125 ? 125 : p_item->count;

        int ret = read_registers(p_ch, p_item->slave, p_item->fc, p_item->addr, read_cnt, reg_buf);
        if (ret <= 0)
        {
            return ret;
        }

        // type=2: 从寄存器提取位（FC03/04 读线圈模式）
        if (p_item->type == 2 && p_item->bit < 16)
        {
            uint8_t val = (reg_buf[0] >> p_item->bit) & 0x01;
            memcpy(p_item->p_val, &val, 1);
            return ret;
        }

        // type=4 (uint16)
        if (p_item->type == 4)
        {
            uint16_t val = reg_buf[0];
            if (p_item->factor != 1.0f || p_item->offset != 0.0f)
            {
                float fval = val * p_item->factor + p_item->offset;
                val = (uint16_t)fval;
            }
            memcpy(p_item->p_val, &val, 2);
            return ret;
        }

        // type=6 (float32): 2 个连续寄存器
        if (p_item->type == 6 && read_cnt >= 2)
        {
            float val = modbus_get_float(&reg_buf[0]);
            if (p_item->factor != 1.0f || p_item->offset != 0.0f)
            {
                val = val * p_item->factor + p_item->offset;
            }
            memcpy(p_item->p_val, &val, 4);
            return ret;
        }

        // type=7 (uint32): 2 个连续寄存器
        if (p_item->type == 7 && read_cnt >= 2)
        {
            uint32_t val = ((uint32_t)reg_buf[0] << 16) | reg_buf[1];
            memcpy(p_item->p_val, &val, 4);
            return ret;
        }

        // type=13 (string)
        if (p_item->type == 13)
        {
            char *p_str = (char *)p_item->p_val;
            for (uint16_t i = 0; i < read_cnt && i < 64; i++)
            {
                p_str[i * 2] = (reg_buf[i] >> 8) & 0xFF;
                p_str[i * 2 + 1] = reg_buf[i] & 0xFF;
            }
            p_str[read_cnt * 2] = '\0';
            return ret;
        }

        // 默认: 按 uint16 处理
        memcpy(p_item->p_val, &reg_buf[0], 2);
        return ret;
    }

    return -1;
}


// ==================== 批量轮询 ====================

// 读取组: (channel, slave, fc) 三元组
typedef struct
{
    uint32_t channel;
    uint8_t slave;
    uint8_t fc;
    uint16_t min_addr;
    uint16_t max_addr;
    std::vector<stru_modbus_m_item *> items;
}stru_poll_group;

LOCAL void build_poll_groups(std::vector<stru_modbus_m_item> &items, std::vector<stru_poll_group> &groups)
{
    for (auto &item : items)
    {
        // 只处理读类型的 fc
        if (item.fc != 0x01 && item.fc != 0x02 && item.fc != 0x03 && item.fc != 0x04)
        {
            continue;
        }

        // 查找已有组
        bool found = false;
        for (auto &g : groups)
        {
            if (g.channel == item.channel && g.slave == item.slave && g.fc == item.fc)
            {
                g.items.push_back(&item);
                if (item.addr < g.min_addr) g.min_addr = item.addr;
                if (item.addr + item.count > g.max_addr) g.max_addr = item.addr + item.count;
                found = true;
                break;
            }
        }

        if (!found)
        {
            stru_poll_group g;
            g.channel = item.channel;
            g.slave = item.slave;
            g.fc = item.fc;
            g.min_addr = item.addr;
            g.max_addr = item.addr + item.count;
            g.items.push_back(&item);
            groups.push_back(g);
        }
    }
}

LOCAL void poll_groups(std::vector<stru_poll_group> &groups)
{
    for (auto &g : groups)
    {
        // 查找通道
        stru_modbus_m_channel *p_ch = NULL;
        for (auto &ch : g_modbus_m_cfg.channels)
        {
            if (ch.id == g.channel && ch.connected)
            {
                p_ch = &ch;
                break;
            }
        }
        if (NULL == p_ch)
        {
            continue;
        }

        uint16_t total_count = g.max_addr - g.min_addr;

        // FC 01/02: 读位
        if (g.fc == 0x01 || g.fc == 0x02)
        {
            uint8_t bits[256] = {0};
            int ret = read_bits(p_ch, g.slave, g.fc, g.min_addr, total_count > 2000 ? 2000 : total_count, bits);
            if (ret > 0)
            {
                for (auto *p_item : g.items)
                {
                    uint16_t offset = p_item->addr - g.min_addr;
                    uint8_t val = bits[offset] ? 1 : 0;
                    memcpy(p_item->p_val, &val, 1);
                    dc_set_out_signal_val(p_item->saddr.c_str(), p_item->p_val, MODULE_MODBUS_M);
                }
            }
        }

        // FC 03/04: 读寄存器
        if (g.fc == 0x03 || g.fc == 0x04)
        {
            uint16_t regs[256] = {0};
            int ret = read_registers(p_ch, g.slave, g.fc, g.min_addr, total_count > 125 ? 125 : total_count, regs);
            if (ret > 0)
            {
                for (auto *p_item : g.items)
                {
                    uint16_t offset = (p_item->addr - g.min_addr);

                    if (p_item->type == 2)
                    {
                        // FC03/04 线圈模式：从寄存器提取位
                        uint16_t reg_idx = offset;
                        uint8_t val = (regs[reg_idx] >> p_item->bit) & 0x01;
                        memcpy(p_item->p_val, &val, 1);
                    }
                    else if (p_item->type == 4)
                    {
                        uint16_t val = regs[offset];
                        if (p_item->factor != 1.0f || p_item->offset != 0.0f)
                        {
                            float fval = val * p_item->factor + p_item->offset;
                            val = (uint16_t)fval;
                        }
                        memcpy(p_item->p_val, &val, 2);
                    }
                    else if (p_item->type == 6 && offset + 1 < 256)
                    {
                        // float val = modbus_get_float(&regs[offset]);
                        float val = modbus_get_float_abcd(&regs[offset]);
                        if (p_item->factor != 1.0f || p_item->offset != 0.0f)
                        {
                            val = val * p_item->factor + p_item->offset;
                        }
                        memcpy(p_item->p_val, &val, 4);
                    }
                    else if (p_item->type == 7 && offset + 1 < 256)
                    {
                        uint32_t val = ((uint32_t)regs[offset] << 16) | regs[offset + 1];
                        memcpy(p_item->p_val, &val, 4);
                    }

                    dc_set_out_signal_val(p_item->saddr.c_str(), p_item->p_val, MODULE_MODBUS_M);
                }
            }
        }
    }
}


// ==================== 写操作 ====================

LOCAL void process_write_queue()
{
    std::vector<stru_modbus_m_write_req> queue;
    {
        std::lock_guard<std::mutex> lock(g_write_mutex);
        queue.swap(g_write_queue);
    }

    for (auto &req : queue)
    {
        // 查找通道
        stru_modbus_m_channel *p_ch = NULL;
        for (auto &ch : g_modbus_m_cfg.channels)
        {
            if (ch.id == req.channel && ch.ctx != NULL)
            {
                p_ch = &ch;
                break;
            }
        }
        if (NULL == p_ch)
        {
            LOG_E("write: channel %d not found", req.channel);
            continue;
        }

        modbus_set_slave(p_ch->ctx, req.slave);

        int ret = -1;
        if (req.is_coil)
        {
            ret = modbus_write_bit(p_ch->ctx, req.addr, req.value ? 1 : 0);
        }
        else
        {
            ret = modbus_write_register(p_ch->ctx, req.addr, req.value);
        }

        if (ret < 0)
        {
            LOG_E("write failed: ch=%d, slave=%d, fc=0x%02x, addr=%d", req.channel, req.slave, req.fc, req.addr);
        }
    }
}

LOCAL void enqueue_write(const stru_modbus_m_write_req &req)
{
    std::lock_guard<std::mutex> lock(g_write_mutex);
    g_write_queue.push_back(req);
}


// ==================== 数据中心信号回调 ====================

LOCAL void modbus_m_signal_co_change_callback(const char *saddr, dc_ctrl_step_t step, uint8_t data_type, uint8_t setting_zone, const void *p_data)
{
    if (step != (dc_ctrl_step_t)DC_CTRL_DIRECT)
    {
        return;
    }

    for (auto &item : g_modbus_m_cfg.point.co_vec)
    {
        if (item.saddr == saddr)
        {
            stru_modbus_m_write_req req;
            req.channel = item.channel;
            req.slave = item.slave;
            req.fc = item.fc;
            req.addr = item.addr;
            req.is_coil = true;

            if (data_type == DATA_TYPE_B)
            {
                req.value = p_data ? (*(uint8_t *)p_data ? 1 : 0) : 0;
            }
            else
            {
                req.value = p_data ? (*(uint8_t *)p_data ? 1 : 0) : 0;
            }

            enqueue_write(req);
            LOG_I("co write: ch=%d, slave=%d, addr=%d, val=%d", req.channel, req.slave, req.addr, req.value);
            break;
        }
    }
}

LOCAL void modbus_m_signal_ao_change_callback(const char *saddr, dc_ctrl_step_t step, uint8_t data_type, uint8_t setting_zone, const void *p_data)
{
    if (step != (dc_ctrl_step_t)DC_CTRL_DIRECT)
    {
        return;
    }

    for (auto &item : g_modbus_m_cfg.point.ao_vec)
    {
        if (item.saddr == saddr)
        {
            stru_modbus_m_write_req req;
            req.channel = item.channel;
            req.slave = item.slave;
            req.fc = item.fc;
            req.addr = item.addr;
            req.is_coil = false;

            if (data_type == DATA_TYPE_U16)
            {
                req.value = p_data ? *(uint16_t *)p_data : 0;
            }
            else if (data_type == DATA_TYPE_F32)
            {
                float f = p_data ? *(float *)p_data : 0;
                req.value = (uint16_t)f;
            }
            else
            {
                req.value = p_data ? *(uint16_t *)p_data : 0;
            }

            enqueue_write(req);
            LOG_I("ao write: ch=%d, slave=%d, addr=%d, val=%d", req.channel, req.slave, req.addr, req.value);
            break;
        }
    }
}


// ==================== 数据中心信号注册 ====================

LOCAL int signal_register_items(const std::vector<stru_modbus_m_item> &items, const std::string &signal_type)
{
    for (auto &item : items)
    {
        uint8_t local_type = modbus_type_to_local_type(item.type);

        if (signal_type == "st")
        {
            if (0 != dc_signal_out(item.saddr.c_str(), item.desc.c_str(), local_type, item.p_val, MODULE_MODBUS_M))
            {
                LOG_E("dc_signal_out failed: %s", item.saddr.c_str());
                return -1;
            }
        }
        else if (signal_type == "mx")
        {
            if (0 != dc_signal_out(item.saddr.c_str(), item.desc.c_str(), local_type, item.p_val, MODULE_MODBUS_M))
            {
                LOG_E("dc_signal_out failed: %s", item.saddr.c_str());
                return -1;
            }
        }
        else if (signal_type == "co")
        {
            if (0 != dc_signal_yk(item.saddr.c_str(), item.desc.c_str(), local_type, DC_CTRL_DIRECT, item.p_val, modbus_m_signal_co_change_callback, MODULE_MODBUS_M))
            {
                LOG_E("dc_signal_yk failed: %s", item.saddr.c_str());
                return -1;
            }
        }
        else if (signal_type == "ao")
        {
            if (0 != dc_signal_ao(item.saddr.c_str(), item.desc.c_str(), local_type, DC_CTRL_DIRECT, item.p_val, modbus_m_signal_ao_change_callback, MODULE_MODBUS_M))
            {
                LOG_E("dc_signal_ao failed: %s", item.saddr.c_str());
                return -1;
            }
        }
    }

    return 0;
}

LOCAL int signals_init()
{
    if (0 != signal_register_items(g_modbus_m_cfg.point.st_vec, "st"))
    {
        return -1;
    }
    if (0 != signal_register_items(g_modbus_m_cfg.point.mx_vec, "mx"))
    {
        return -1;
    }
    if (0 != signal_register_items(g_modbus_m_cfg.point.co_vec, "co"))
    {
        return -1;
    }
    if (0 != signal_register_items(g_modbus_m_cfg.point.ao_vec, "ao"))
    {
        return -1;
    }

    LOG_I("signals registered: st=%zu, mx=%zu, co=%zu, ao=%zu",
        g_modbus_m_cfg.point.st_vec.size(),
        g_modbus_m_cfg.point.mx_vec.size(),
        g_modbus_m_cfg.point.co_vec.size(),
        g_modbus_m_cfg.point.ao_vec.size());

    return 0;
}


// ==================== 模块初始化 ====================

int modbus_m_init()
{
    if (0 != signals_init())
    {
        LOG_E("signals_init failed");
        return -1;
    }

    if (0 != channels_init())
    {
        LOG_E("channels_init failed");
        // 部分通道失败也可继续
    }

    return 0;
}


// ==================== 信息显示 ====================

void modbus_m_show_info()
{
    printf("===== Modbus Master Info =====\n");
    printf("Channels: %zu\n", g_modbus_m_cfg.channels.size());
    for (auto &ch : g_modbus_m_cfg.channels)
    {
        printf("  ch[%d]: mode=%s, connected=%d", ch.id, ch.mode.c_str(), ch.connected);
        if (ch.mode == "tcp")
        {
            printf(", %s:%d", ch.host.c_str(), ch.port);
        }
        else
        {
            printf(", %s %d %c%d/%d", ch.device.c_str(), ch.baud, ch.parity, ch.data_bit, ch.stop_bit);
        }
        printf("\n");
    }
    printf("Points: st=%zu, mx=%zu, co=%zu, ao=%zu\n",
        g_modbus_m_cfg.point.st_vec.size(),
        g_modbus_m_cfg.point.mx_vec.size(),
        g_modbus_m_cfg.point.co_vec.size(),
        g_modbus_m_cfg.point.ao_vec.size());
}


// ==================== 命令行 ====================

LOCAL void cmd_modbus_m(int argc, char *argv[])
{
    const char *str = "\
        modbus_m info ----------> 查看所有通道和点表信息\n";

    if (argc < 2)
    {
        printf("%s", str);
        return;
    }

    if (0 == strcmp(argv[1], "info"))
    {
        modbus_m_show_info();
    }
}

LOCAL void cmd_modbus_m_complete(const char *buf, char ***completions, int *ncomp)
{
    static const char *subs[] = {"info"};
    cmd_sub_complete(buf, completions, ncomp, subs, sizeof(subs)/sizeof(subs[0]));
}

CMD_REGISTER_C(MODULE_MODBUS_M, cmd_modbus_m, "Modbus主站线程的控制命令", cmd_modbus_m_complete);


// ==================== 应用线程入口 ====================

int app_modbus_m_init1(void *arg)
{
    stru_app *p_app = (stru_app *)arg;

    dc_signal_out("modbus_m.run_cnt", "modbus_m.run_cnt", DATA_TYPE_U32, &p_app->run_cnt, MODULE_MODBUS_M);

    std::string base_path = get_base_path();
    if (base_path.empty())
    {
        LOG_E("get_base_path failed");
        return -1;
    }
    g_modbus_m_base_path = base_path + "config/MODBUS/";

    std::string cfg_path = g_modbus_m_base_path + "modbus_m.xml";
    if (0 != modbus_m_cfg_parse(cfg_path))
    {
        LOG_E("modbus_m_cfg_parse failed: %s", cfg_path.c_str());
        return -1;
    }

    if (0 != modbus_m_init())
    {
        LOG_E("modbus_m_init failed");
        return -1;
    }

    return 0;
}

int app_modbus_m_init2(void *arg)
{
    return 0;
}

void *app_modbus_m(void *arg)
{
    if (NULL == arg)
    {
        LOG_E("app_modbus_m arg null");
        return NULL;
    }

    stru_app *p_app = (stru_app *)arg;

    uint32_t event;
    std::vector<stru_poll_group> st_groups;
    std::vector<stru_poll_group> mx_groups;

    // 预构建轮询分组
    build_poll_groups(g_modbus_m_cfg.point.st_vec, st_groups);
    build_poll_groups(g_modbus_m_cfg.point.mx_vec, mx_groups);
    LOG_I("poll groups: st=%zu, mx=%zu", st_groups.size(), mx_groups.size());

    while (1)
    {
        task_event_recv(p_app->p_event,
            EV_TIMER1 | EV_TIMER2 | EV_TIMER3,
            TASK_EVENT_FLAG_OR | TASK_EVENT_FLAG_CLEAR,
            TASK_EVENT_WAIT_FOREVER,
            &event);

        if(event & EV_TIMER1)
        {
            // 处理写请求队列 (10ms)
            process_write_queue();
        }

        if(event & EV_TIMER2)
        {
            // 轮询遥信 (100ms)
            poll_groups(st_groups);
        }

        if(event & EV_TIMER3)
        {
            // 轮询遥测/参数 (1000ms)
            poll_groups(mx_groups);
            p_app->run_cnt++;
        }

        if(EV_STOP & event)
        {
            LOG_I("app_modbus_m: received EV_STOP, exiting");
            break;
        }
    }

    return NULL;
}

/* ==================== 模块注册（由 app_modules.h X-Macro 自动完成，无需手动 register） ==================== */
