RT-Thread-packages / ppp_device

lwIP PPP porting for GSM modem (like sim800)
Apache License 2.0
39 stars 32 forks source link

建议添加异步发送数据功能 #16

Open zcj20080882 opened 4 years ago

zcj20080882 commented 4 years ago

文档中说明建议不要打开RT_DEVICE_FLAG_DMA_TX,现实情况是一定不能打开该标志。原因是RTT串口发送时,是直接将数据地址传送给DMA(在打开DMA时并且开启RT_DEVICE_FLAG_DMA_TX),这样在DMA发送数据时,一定不能修改传给serial层的数据,如果是动态分配的内存更不能释放该内存,否则会导致发送数据出错或者崩溃。 但是,某些情况下,需要开启DMA以节省CPU资源,这时需要ppp_device能够保证数据不出错而且还能异步(DMA)发送,这就需要简单实现一下异步发送的功能。我简单写了一个串口异步发送数据的示例,你看是否可行或者是否有必要:

#define MIN(a,b)            (((a) > (b)) ? (b) : (a))
#define SEND_TIMEOUT 1000
uint8_t ppp_tx_buf[1500] = {0};
/*发送完成信号*/
rt_sem_t tx_sem;

rt_inline rt_err_t __send_complete_callback(rt_device_t dev, void *buffer)
{
    rt_sem_release(tx_sem);
    return RT_EOK;
}

int ppp_serial_write(rt_device_t dev, const uint8_t *data, int data_len)
{
    int ret = RT_EOK;

    if (!dev)
    {
        return -RT_EINVAL;
    }
    if (!data || data_len == 0)
    {
        log_w("Invalid data!");
        return 0;
    }

    ret = rt_sem_take(tx_sem, SEND_TIMEOUT);
    if (RT_EOK != ret)
    {
        log_e("Write %s failed,err: %d", uart->name, ret);
        return -RT_EBUSY;
    }
    ret = MIN(data_len,sizeof(ppp_tx_buf));
    memcpy(ppp_tx_buf, data, ret);

    ret = rt_device_write(dev, 0,tx_buf, ret);
    if (ret <= 0)
    {
        log_e("Write %s failed,err: %d", uart->name, ret);
    }
    else if (ret < data_len)
    {
       //待优化,连续发送大量数据可能导致栈溢出
        ret = ppp_serial_write(fd, data + ret, data_len - ret);
    }
    return ret;
}
armink commented 4 years ago

可否跟 rbb 有些结合呢

https://www.rt-thread.org/document/api/group__ring__block__buffer.html#details

zcj20080882 commented 4 years ago

可否跟 rbb 有些结合呢

https://www.rt-thread.org/document/api/group__ring__block__buffer.html#details 这不错,适合应用层做缓存。这个场景使用是不是有点复杂?这里其实不需要太复杂,只需要DMA发送数据,静态分配一个1500字节的内存就好了,保证DMA发送数据时数据不被破坏就好。 rbb确实很好用,我在其他项目里用了,而且rbb的使用场景也很广泛,只是这个场景貌似不需要。

armink commented 4 years ago

主要感觉这个功能放在串口设备层去实现会更加通用一些,当时设计 RBB 最早也是考虑到了 DMA 发送的需求。

zcj20080882 commented 4 years ago

主要感觉这个功能放在串口设备层去实现会更加通用一些,当时设计 RBB 最早也是考虑到了 DMA 发送的需求。

是呢,最初接触到RTT也发现这个问题,串口驱动层对DMA发送的处理逻辑对应用层不是特别友好,尤其是新手,可能会直接使用rt_device_write写数据,函数返回后就直接复用了,导致数据发送出错。在实际项目中,串口这块基本上都需要再封一层使用(这里使用rbb就非常方便)。