同步操作将从 yshark/at_client_with_rtos 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
将RT-Thread 的AT组件移植到FreeRTOS中,若移植到其他操作系统也可以参照此项目
at.h
#define RT_EOK 0
#define RT_ERROR 1
#define RT_ETIMEOUT 2
#define RT_EFULL 3
#define RT_EEMPTY 4
#define RT_ENOMEM 5
#define RT_ENOSYS 6
#define RT_EBUSY 7
#define RT_EIO 8
#define RT_EINTR 9
#define RT_EINVAL 10
#define RT_TRUE 1
#define RT_FALSE 0
#define RT_NAME_MAX 16
#define RT_IPC_FLAG_PRIO 0x01
#define RT_IPC_FLAG_FIFO 0x00
#define RT_THREAD_PRIORITY_MAX configMAX_PRIORITIES
#define RT_ASSERT(expression) do{if(!(expression))printf("expression:(%s) == 0\r\nfile:%s line:%d\r\n",#expression,__FILE__,__LINE__);}while(0)
#define rt_memcpy memcpy
#define rt_memset memset
#define rt_strstr strstr
#define rt_memcmp memcmp
#define rt_snprintf snprintf
#define rt_strlen strlen
#define rt_strcmp strcmp
#define rt_strncmp strncmp
#define RT_WAITING_FOREVER portMAX_DELAY
#define rt_weak __attribute__((weak))
#define rt_sem_take(Sem,timeout) xSemaphoreTake(Sem,timeout)
#define rt_sem_release(Sem) do{if(xPortIsInsideInterrupt()){BaseType_t pxHigherPriorityTaskWoken;xSemaphoreGiveFromISR(Sem,&pxHigherPriorityTaskWoken);} else xSemaphoreGive(Sem);}while(0)
#define rt_mutex_release(mutex) xSemaphoreGive(mutex)
#define rt_mutex_take(mutex,timeout) xSemaphoreTake(mutex,timeout)
#define rt_tick_from_millisecond pdMS_TO_TICKS
#define rt_tick_get xTaskGetTickCount
/* 根据实际需要选择是否修改以下宏定义 */
#define rt_calloc calloc
#define rt_free free
#define rt_realloc realloc
#define rt_kprintf printf
#define rt_device_t COM_PORT_E
typedef size_t rt_size_t ;
typedef size_t rt_size_t ;
typedef int32_t rt_int32_t ;
typedef uint32_t rt_uint32_t ;
typedef TaskHandle_t rt_thread_t ;
typedef SemaphoreHandle_t rt_sem_t ;
typedef SemaphoreHandle_t rt_mutex_t ;
typedef size_t rt_tick_t;
typedef size_t rt_off_t;
typedef int rt_bool_t;
typedef uint8_t rt_uint8_t;
typedef long rt_base_t;
typedef rt_base_t rt_err_t;
struct at_client
{
rt_device_t device;
/* 自己添加的 */
char *client_name;
at_status_t status;
char end_sign;
/* the current received one line data buffer */
char *recv_line_buf;
/* The length of the currently received one line data */
rt_size_t recv_line_len;
/* The maximum supported receive data length */
rt_size_t recv_bufsz;
rt_sem_t rx_notice;
rt_mutex_t lock;
at_response_t resp;
rt_sem_t resp_notice;
at_resp_status_t resp_status;
struct at_urc_table *urc_table;
rt_size_t urc_table_size;
rt_thread_t parser; //线程控制块
};
at_utils.c
/*************************************************移植到freertos需要做的修改*******************************************************/
/**
* 为了兼容 rt_device_read()函数自己定义的
*
* @param dev 设备句柄
* @param pos 读取的偏移量
* @param buffer 用于保存读取数据的数据缓冲区
* @param size 缓冲区的大小
*
* @return 成功返回实际读取的大小,如果是字符设备,返回大小以字节为单位,如果是块设备,返回的大小以块为单位;失败则返回0
*/
rt_weak rt_size_t rt_device_read ( rt_device_t dev,
rt_off_t pos,
void * buffer,
rt_size_t size
)
{
uint32_t rx_num = 0;
for(uint32_t i = 0; i < size; i++){
if(comGetChar(dev - 1,buffer))
rx_num++;
else
goto exit;
}
exit:
return rx_num;
}
/**
* 为了兼容 rt_device_write()函数自己定义的
*
* @param dev 设备句柄
* @param pos 写入的偏移量
* @param buffer 要写入设备的数据缓冲区
* @param size 写入数据的大小
*
* @return 成功返回实际写入数据的大小,如果是字符设备,返回大小以字节为单位;如果是块设备,返回的大小以块为单位;失败则返回0。
*/
rt_size_t rt_device_write (rt_device_t dev,
rt_off_t pos,
const void * buffer,
rt_size_t size
)
{
comSendBuf(dev - 1,(uint8_t*)buffer,size);
return size;
}
/*创建信号量 */
rt_sem_t rt_sem_create (const char * name,
rt_uint32_t value,
rt_uint8_t flag
)
{
return xSemaphoreCreateBinary();
}
/*创建互斥量 */
rt_mutex_t rt_mutex_create (const char * name,
rt_uint8_t flag
)
{
return xSemaphoreCreateMutex();
}
/* 删除互斥量 */
rt_err_t rt_mutex_delete (rt_mutex_t mutex)
{
vSemaphoreDelete(mutex);
return RT_EOK;
}
/* 删除信号量 */
rt_err_t rt_sem_delete ( rt_sem_t sem )
{
vSemaphoreDelete(sem);
return RT_EOK;
}
根据实际需要修改 rt_device_read() rt_device_write()函数
at_client.c
/**
* AT client initialize.
* 为了兼容安富莱的串口驱动,新增一个参数 _ucPort
* @param dev_name AT client device name
* @param recv_bufsz the maximum number of receive buffer length
* @param _ucPort 为at客户端指定一个串口设备
* @return 0 : initialize success
* -1 : initialize failed
* -5 : no memory
*/
int at_client_init(const char *dev_name, rt_size_t recv_bufsz ,COM_PORT_E _ucPort)
{
int idx = 0;
int result = RT_EOK;
rt_err_t open_result = RT_EOK;
at_client_t client = RT_NULL;
RT_ASSERT(dev_name);
RT_ASSERT(recv_bufsz > 0);
if (at_client_get(dev_name) != RT_NULL)
{
return result;
}
for (idx = 0; idx < AT_CLIENT_NUM_MAX && at_client_table[idx].device; idx++);
if (idx >= AT_CLIENT_NUM_MAX)
{
LOG_E("AT client initialize failed! Check the maximum number(%d) of AT client.", AT_CLIENT_NUM_MAX);
result = -RT_EFULL;
goto __exit;
}
client = &at_client_table[idx];
client->recv_bufsz = recv_bufsz;
result = at_client_para_init(client);
if (result != RT_EOK)
{
goto __exit;
}
/* find and open command device */
/* 为了兼容安富莱驱动 */
client->client_name = (char*)dev_name;
client->device = _ucPort + 1; /* 加一是因为at_client_init会通过dev来遍历at_client_table,遍历语句for (idx = 0; idx < AT_CLIENT_NUM_MAX && at_client_table[idx].device; idx++); */
// client->device = rt_device_find(dev_name);
// if (client->device)
// {
// /* using DMA mode first */
// open_result = rt_device_open(client->device, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_DMA_RX);
// /* using interrupt mode when DMA mode not supported */
// if (open_result == -RT_EIO)
// {
// open_result = rt_device_open(client->device, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX);
// }
// RT_ASSERT(open_result == RT_EOK);
// rt_device_set_rx_indicate(client->device, at_client_rx_ind);
// }
// else
// {
// LOG_E("AT client initialize failed! Not find the device(%s).", dev_name);
// result = -RT_ERROR;
// goto __exit;
// }
__exit:
if (result == RT_EOK)
{
client->status = AT_STATUS_INITIALIZED;
// rt_thread_startup(client->parser);
LOG_I("AT client(V%s) on device %s initialize success.", AT_SW_VERSION, dev_name);
}
else
{
LOG_E("AT client(V%s) on device %s initialize failed(%d).", AT_SW_VERSION, dev_name, result);
}
return result;
}
根据实际需要修改at_client_init()函数,让at client和串口设备关联在一起,这里通过client->device = _ucPort + 1;
语句,使client和安富莱串口驱动关联在一起。
串口驱动接收到字符需要通知线程来处理字符,at client组件已经为我们准备好了串口回调函数,我们只需要在串口接收中断或者DMA中断中调用即可。回调函数如下所示:
/* 由静态函数改为全局函数 */
rt_err_t at_client_rx_ind(rt_device_t dev, rt_size_t size)
{
int idx = 0;
for (idx = 0; idx < AT_CLIENT_NUM_MAX; idx++)
{
if (at_client_table[idx].device == dev && size > 0)
{
rt_sem_release(at_client_table[idx].rx_notice);
}
}
return RT_EOK;
}
调用示例如下:
/* AIR780E_ReciveNew是我的串口接收中断回调函数 */
void AIR780E_ReciveNew(uint8_t _byte)
{
at_client_rx_ind(COM1 + 1,1); /* 加一是因为at_client_init会通过dev来遍历at_client_table,遍历语句for (idx = 0; idx < AT_CLIENT_NUM_MAX && at_client_table[idx].device; idx++); */
}
这里需要注意:由于需要在中断中使用freertos的API,所以中断的优先级需要小于等于configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY
(数值越小,优先级越高。即中断优先级的数值需要大于等于configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY
)
如果需要移植到其他操作系统,需要特别注意你使用的操作系统成功释放信号量是返回1还是返回0。(RT-Thread成功释放返回0,FreeRTOS成功释放返回1)
举例:
rt_size_t at_client_obj_recv(at_client_t client, char *buf, rt_size_t size, rt_int32_t timeout)
{
rt_size_t len = 0;
RT_ASSERT(buf);
if (client == RT_NULL)
{
LOG_E("input AT Client object is NULL, please create or get AT Client object!");
return 0;
}
while (1)
{
rt_size_t read_len;
// rt_sem_control(client->rx_notice, RT_IPC_CMD_RESET, RT_NULL);
read_len = rt_device_read(client->device, 0, buf + len, size);
if(read_len > 0)
{
len += read_len;
size -= read_len;
if(size == 0)
break;
continue;
}
// if(rt_sem_take(client->rx_notice, rt_tick_from_millisecond(timeout)) != RT_EOK) //RT-Thread #define RT_EOK 0
if(rt_sem_take(client->rx_notice, rt_tick_from_millisecond(timeout)) != pdTRUE) //FreeRTOS #define pdTRUE 1
break;
}
#ifdef AT_PRINT_RAW_CMD
at_print_raw_cmd("urc_recv", buf, len);
#endif
return len;
}
事实上,为了移植到freertos上所作出的修改不仅仅只是上面的那些修改,作出修改的地方一般都以注释的方式保留了原始代码。可以通过是否有注释来判断是否修改了源码。
example:
在main.c
文件中创建了以下任务:
static void LED_Task (void* parameter)
{
if(at_client_wait_connect(10000)){
printf("连接失败\r\n");
}else{
printf("AT连接成功\r\n");
}
while (1)
{
bsp_LedToggle(1);
vTaskDelay(1000); /* 延时 500 个 tick */
}
}
at_client_wait_connect()
函数会在10秒内不断发送AT\r\n
,直到接收字符串OK\r\n
请参考以下链接
转载文章请保留以下链接:
资源下载链接1: https://gitee.com/sharkisyou/at_client_with_rtos
文章转载链接: https://blog.csdn.net/qq_41430785/article/details/133416610?spm=1001.2014.3001.5501
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。