#include "erpc_uart_cmsis_transport.hpp"

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

namespace erpc {

UartTransport::UartTransport(const char *uartDevName)
    : m_uartDevName(uartDevName),
      m_serial(RT_NULL),
      m_rx_sem(RT_NULL)
{
}

UartTransport::~UartTransport(void)
{
    if (m_serial)
    {
        rt_device_set_rx_indicate(m_serial, RT_NULL);
        // 取消 user_data，避免野指针
        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;
    }
}

void UartTransport::build_rx_sem_name(char *out, rt_size_t out_sz)
{
    // 生成一个 <= 11 字符的名字（RT_NAME_MAX=12）
    // 例：uart2 -> "erx2"；uart3 -> "erx3"
    // 找到尾部数字
    const char *p = m_uartDevName;
    const char *last_digit = RT_NULL;

    for (; *p; ++p)
    {
        if (*p >= '0' && *p <= '9')
            last_digit = p;
    }

    if (last_digit)
        rt_snprintf(out, out_sz, "erx%c", *last_digit);
    else
        rt_snprintf(out, out_sz, "erx");
}

rt_err_t UartTransport::uart_rx_ind(rt_device_t dev, rt_size_t size)
{
    (void)size;

    // 通过 dev->user_data 找到实例
    UartTransport *self = reinterpret_cast<UartTransport *>(dev->user_data);
    if (self && self->m_rx_sem)
    {
        rt_sem_release(self->m_rx_sem);
    }
    return RT_EOK;
}

erpc_status_t UartTransport::init(void)
{
    m_serial = rt_device_find(m_uartDevName);
    if (!m_serial)
        return kErpcStatus_InitFailed;

    // 绑定实例到设备
    m_serial->user_data = this;

    // 配串口参数
    struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
    config.baud_rate = BAUD_RATE_115200;
    config.data_bits = DATA_BITS_8;
    config.stop_bits = STOP_BITS_1;
    config.parity    = PARITY_NONE;
    config.bufsz     = 512;

    rt_device_control(m_serial, RT_DEVICE_CTRL_CONFIG, &config);

    // 打开：中断接收（发送默认轮询）
    if (rt_device_open(m_serial, RT_DEVICE_FLAG_INT_RX) != RT_EOK)
        return kErpcStatus_InitFailed;

    // 创建信号量（名字必须短！）
    char sem_name[RT_NAME_MAX] = {0};
    build_rx_sem_name(sem_name, sizeof(sem_name));

    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, uart_rx_ind);

    return kErpcStatus_Success;
}

erpc_status_t UartTransport::underlyingReceive(uint8_t *data, uint32_t size)
{
    // 确保读满 size 字节（FramedTransport 需要）
    uint32_t received = 0;

    // rt_kprintf("%s",m_uartDevName);
    while (received < size)
    {
        // 没数据就等（收到中断会 release）
        if (rt_sem_take(m_rx_sem, RT_WAITING_FOREVER) != RT_EOK)
            return kErpcStatus_ReceiveFailed;

        // 读尽可能多
        rt_size_t r = rt_device_read(m_serial, 0, data + received, size - received);
        if (r > 0)
            received += (uint32_t)r;
        // r==0 就继续等下一次中断
    }

    return kErpcStatus_Success;
}

erpc_status_t UartTransport::underlyingSend(const uint8_t *data, uint32_t size)
{
    // 确保写完
    uint32_t sent = 0;

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

    return kErpcStatus_Success;
}

} // namespace erpc
