//
// Created by Administrator on 2025/12/24.
//

#include "erpc_serial_transport.hpp"

#include "drv_gpio.h"

extern "C" {
#include <stdint.h>
}

namespace erpc {

SerialTransport::SerialTransport(const char *portName, speed_t baudRate)
    : m_portName(portName),
      m_baudRate(baudRate),
      m_serial(RT_NULL),
      m_rx_sem(RT_NULL),
      m_read_timeout_ms(-1)
{
}

SerialTransport::~SerialTransport(void)
{
    if (m_serial)
    {
        // 解绑回调与 user_data，避免析构后回调访问野指针
        rt_device_set_rx_indicate(m_serial, RT_NULL);
        m_serial->user_data = RT_NULL;

        rt_device_close(m_serial);
        m_serial = RT_NULL;
    }

    if (m_rx_sem)
    {
        rt_sem_delete(m_rx_sem);
        m_rx_sem = RT_NULL;
    }
}

rt_err_t SerialTransport::rx_indicate(rt_device_t dev, rt_size_t size)
{
    (void)size;

    auto *self = reinterpret_cast<SerialTransport *>(dev->user_data);
    if (self && self->m_rx_sem)
    {
        rt_sem_release(self->m_rx_sem);
    }
    return RT_EOK;
}

erpc_status_t SerialTransport::init(uint8_t vtime, uint8_t vmin)
{
    (void)vmin;

    m_serial = rt_device_find(m_portName);
    if (!m_serial)
        return kErpcStatus_InitFailed;

    // vtime（POSIX: 0.1s 单位）这里简单映射：0 -> forever；否则 vtime*100ms
    if (vtime == 0)
        m_read_timeout_ms = -1;
    else
        m_read_timeout_ms = (int32_t)vtime * 100;

    // 绑定实例到设备，回调里通过 dev->user_data 找到 this
    m_serial->user_data = this;

    // 配置串口
    struct serial_configure cfg = RT_SERIAL_CONFIG_DEFAULT;
    cfg.baud_rate = (rt_uint32_t)m_baudRate;
    cfg.data_bits = DATA_BITS_8;
    cfg.stop_bits = STOP_BITS_1;
    cfg.parity    = PARITY_NONE;

    cfg.bufsz = 1024;
    // cfg.rx_bufsz     = 1024;
    // cfg.tx_bufsz     = 1024;

    rt_device_control(m_serial, RT_DEVICE_CTRL_CONFIG, &cfg);

    // 打开：中断接收
    if (rt_device_open(m_serial,  RT_DEVICE_FLAG_INT_RX   ) != RT_EOK)
        return kErpcStatus_InitFailed;

    // 创建信号量（唯一名字：erxXXXX）
    char sem_name[RT_NAME_MAX];
    rt_uint32_t tag = (rt_uint32_t)((uintptr_t)this & 0xFFFFu);
    rt_snprintf(sem_name, sizeof(sem_name), "erx%04x", (unsigned)tag);

    m_rx_sem = rt_sem_create(sem_name, 0, RT_IPC_FLAG_PRIO);
    if (!m_rx_sem)
        return kErpcStatus_InitFailed;

    // 绑定 RX 回调
    rt_device_set_rx_indicate(m_serial, rx_indicate);

    return kErpcStatus_Success;
}

    erpc_status_t SerialTransport::underlyingReceive(uint8_t *data, uint32_t size)
{
    uint32_t received = 0;

    while (received < size)
    {
        // 先尝试直接读（不等信号量）
        rt_size_t r = rt_device_read(m_serial, 0, data + received, size - received);
        if (r > 0)
        {
            received += (uint32_t)r;
            continue;
        }

        // 没读到再等中断唤醒
        if (rt_sem_take(m_rx_sem, RT_WAITING_FOREVER) != RT_EOK)
            return kErpcStatus_ReceiveFailed;

        // 被唤醒后，连续读到“读不到”为止
        while (received < size)
        {
            r = rt_device_read(m_serial, 0, data + received, size - received);
            if (r > 0) received += (uint32_t)r;
            else break;
        }
    }

    // rt_tick_t now = rt_tick_get();
    // rt_uint32_t ms = (rt_uint32_t)((rt_uint64_t)now * 1000 / RT_TICK_PER_SECOND);
    //
    //
    // rt_kprintf("%s rx at [%lu ms]:\n", m_portName,(unsigned long)ms);
    //
    // for (int i = 0; i < size; i ++)
    //     rt_kprintf("%0x  ", data[i]);
    // rt_kprintf("\n");


    return kErpcStatus_Success;
}




erpc_status_t SerialTransport::underlyingSend(const uint8_t *data, uint32_t size)
{
    uint32_t sent = 0;

    while (sent < size)
    {
        rt_size_t n = rt_device_write(m_serial, 0, data + sent, size - sent);
        if (n > 0)
        {
            sent += (uint32_t)n;
        }
        else
        {
            return kErpcStatus_SendFailed;
        }
    }

    return kErpcStatus_Success;
}

} // namespace erpc

