Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
AT组件
RT-Thread
RIL(Radio Interface Layer)
RT-Thread AT组件对接Modem RIL xMUX的AT接口的方法
发布于 2022-01-23 13:56:56 浏览:797
订阅该版
[tocm] [RT-Thread 入门学习笔记 - 目录](https://club.rt-thread.org/ask/article/3420.html) ## 前言 - RT-Thread 的AT组件,可以用于对接基于串口的蜂窝模块,如SIM800这样的模块,实现电话与短信等业务 - 目前部分蜂窝厂商,提供的Modem芯片,可能不是uart串口,而是SPI、USB或其他串口,他们提供了xMUX多路复用的组件,也就说,底层可以提供一个类uart的AT收发接口。 - 如何使用AT组件对接这种xMUX出来的AT收发接口呢?如物理上是SPI接口,通过xMUX出来几个接口,包括数据服务与AT命令的接口。 ## 解决方法 - 这时,需要手动注册一个基于RT-Thread rt_device 字符设备,因为AT组件,就是通过字符设备,对底层进行AT命令的收发控制的。 - 如何注册这样的设备?我开个BSP_USING_UART?不用,这个字符设备不是具体的外设的接口设备,只是一个字符设备即可。 - 上一篇我们讲过把一个引脚(LED)抽象成一个设备,本篇就用这个方法,改改名字,抽象一个ril设备出来,用于对接Modem xMUX的AT命令接口。 - 后续可以根据这个思路,抽象一个【虚拟网卡】设备出来,用于对接Modem xMUX的【数据服务】接口。 ## 操作步骤 - 验证平台:STM32L475 Pandora 开发板 - `board\Kconfig`配置,用于控制是否开启设备,这里使用RIL_VDEVICE命名。 ```c config BSP_USING_RIL_VDEVICE bool "Enable RIL Virtual Device" default n if BSP_USING_RIL_VDEVICE config BSP_RIL_VDEVICE_NAME string "RIL Virtual Device Name" default "ril_dev" endif ``` - 配置`board\SConscript` ```c if GetDepend(['BSP_USING_RIL_VDEVICE']): src += Glob('ril_vdevice/*.c') ``` - 添加的文件  - 开启AT组件   - 开启配置的ril_dev设备  - `ril_vdev.c`,字符设备的注册,对接xMUX AT收发接口 ```c #include "ril_vdev.h" #include "board.h" #ifndef BSP_RIL_VDEVICE_NAME #define BSP_RIL_VDEVICE_NAME "ril_dev" #endif static struct rt_device _ril_vdev; static rt_err_t _ril_vdev_init(rt_device_t dev) { return RT_EOK; } static rt_err_t _ril_vdev_open(rt_device_t dev, rt_uint16_t oflag) { if (dev == RT_NULL) return -RT_ERROR; return RT_EOK; } static rt_err_t _ril_vdev_close(rt_device_t dev) { if (dev == RT_NULL) return -RT_ERROR; return RT_EOK; } rt_size_t _ril_vdev_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size) { rt_kprintf("%s : buffer = %s, size = %d\r\n", __func__, buffer, size); // XMUX_read(buffer, size); return RT_EOK; } rt_size_t _ril_vdev_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size) { rt_kprintf("%s : buffer = %s, size = %d\r\n", __func__, buffer, size); // XMUX_write(buffer, size); return RT_EOK; } #if 0 /* app will set */ rt_err_t _ril_vdev_rx_indicate(rt_device_t dev, rt_size_t size) { rt_kprintf("%s : rx_in size = %d\r\n", __func__, size); // XMUX_rx_indicate(size); return RT_EOK; } rt_err_t _ril_vdev_tx_complete(rt_device_t dev, void *buffer) { rt_kprintf("%s : buffer=%s\r\n", __func__, buffer); // XMUX_tx_indicate(size); return RT_EOK; } #endif static rt_err_t _ril_vdev_control(rt_device_t dev, int cmd, void *args) { if (dev == RT_NULL) return -RT_ERROR; switch (cmd) { case RIL_VDEV_CTRL_CMD_POWER_ON: break; case RIL_VDEV_CTRL_CMD_POWER_OFF: break; default: break; } return RT_EOK; } #ifdef RT_USING_DEVICE_OPS const static struct rt_device_ops ril_vdev_ops = { _ril_vdev_init, _ril_vdev_open, _ril_vdev_close, _ril_vdev_read, _ril_vdev_write, _ril_vdev_control }; #endif static int ril_vdevice_register(const char *name, void *user_data) { _ril_vdev.type = RT_Device_Class_Char; _ril_vdev.rx_indicate = RT_NULL; _ril_vdev.tx_complete = RT_NULL; #ifdef RT_USING_DEVICE_OPS _ril_vdev.ops = &ril_vdev_ops; #else _ril_vdev.init = _ril_vdev_init; _ril_vdev.open = _ril_vdev_open; _ril_vdev.close = _ril_vdev_close; _ril_vdev.read = _ril_vdev_read; _ril_vdev.write = _ril_vdev_write; _ril_vdev.control = _ril_vdev_control; #endif _ril_vdev.user_data = user_data; /* register a character device */ rt_device_register(&_ril_vdev, name, RT_DEVICE_FLAG_RDWR); return 0; } int ril_vdevice_init(void) { return ril_vdevice_register(BSP_RIL_VDEVICE_NAME, RT_NULL); } ``` - `ril_vdev.h` 头文件 ```c #ifndef __RIL_VDEV_H__ #define __RIL_VDEV_H__ #include
#include
#define RIL_VDEV_CTRL_CMD_POWER_OFF 0xAA00 #define RIL_VDEV_CTRL_CMD_POWER_ON 0xAA01 int ril_vdevice_init(void); #endif ``` - `ril_app.c`,ril device的操作接口,AT client设备的初始化与简单操作 ```c #include "ril_app.h" #include "at.h" #define DBG_ENABLE #define DBG_SECTION_NAME "rild.test" #define DBG_LEVEL DBG_LOG #include
#ifndef BSP_RIL_VDEVICE_NAME #define BSP_RIL_VDEVICE_NAME "ril_dev" #endif #ifndef BSP_RIL_RECV_MAX_SIZE #define BSP_RIL_RECV_MAX_SIZE 1600 #endif static rt_device_t _ril_dev = RT_NULL; static rt_device_t get_ril_dev(void) { if (_ril_dev != RT_NULL) return _ril_dev; _ril_dev = rt_device_find(BSP_RIL_VDEVICE_NAME); return _ril_dev; } static rt_err_t ril_dev_open(void) { rt_device_t dev = get_ril_dev(); if (dev == RT_NULL) return -RT_ERROR; return rt_device_open(dev, RT_DEVICE_FLAG_RDWR); } rt_err_t ril_dev_power_on(void) { rt_device_t dev = get_ril_dev(); if (dev == RT_NULL) return -RT_ERROR; return rt_device_control(dev, RIL_VDEV_CTRL_CMD_POWER_ON, RT_NULL); } rt_err_t ril_dev_power_off(void) { rt_device_t dev = get_ril_dev(); if (dev == RT_NULL) return -RT_ERROR; return rt_device_control(dev, RIL_VDEV_CTRL_CMD_POWER_OFF, RT_NULL); } rt_err_t ril_dev_init(void) { ril_vdevice_init(); return ril_dev_open(); } int ril_at_device_init(void) { ril_dev_init(); at_client_init(BSP_RIL_VDEVICE_NAME, BSP_RIL_RECV_MAX_SIZE); return 0; } static void at_response_dump(at_response_t resp) { rt_uint8_t line_num = 0; LOG_D("%s: line_counts=%d\n", __func__, resp->line_counts); for (line_num = 1; line_num <= resp->line_counts; line_num++) { const char *resp_line_buf = at_resp_get_line(resp, line_num); if (resp_line_buf != RT_NULL) { LOG_D("%s:line=%d, buf=%s\n", __func__, line_num, resp_line_buf); } } } rt_err_t ril_test_check_sim(void) { at_response_t resp = RT_NULL; resp = at_create_resp(64, 3, rt_tick_from_millisecond(500)); if (resp == RT_NULL) { LOG_E("%s:at_create_resp error!", __func__); return -RT_ERROR; } at_exec_cmd(resp, "AT+CPIN?"); at_response_dump(resp); if (at_resp_get_line_by_kw(resp, "READY")) { LOG_D("at_check_sim success."); if (resp != RT_NULL) at_delete_resp(resp); return RT_EOK; } if (resp != RT_NULL) at_delete_resp(resp); LOG_E("at_check_sim failed."); return -RT_ERROR; } MSH_CMD_EXPORT(ril_test_check_sim, ril_test_check_sim); /* ril_test_at_cmd */ static void ril_test_at_cmd(int argc, char **argv) { at_response_t resp = RT_NULL; char *at_cmd = RT_NULL; if (argc >= 2) { at_cmd = argv[1]; } resp = at_create_resp(1024, 4, rt_tick_from_millisecond(1000)); if (resp == RT_NULL) { LOG_E("%s:at_create_resp error!", __func__); return; } at_exec_cmd(resp, at_cmd); at_response_dump(resp); if (resp != RT_NULL) at_delete_resp(resp); } MSH_CMD_EXPORT(ril_test_at_cmd, ril_test_at_cmd); INIT_DEVICE_EXPORT(ril_at_device_init); ``` - `ril_app.h` 头文件 ```c #ifndef __RIL_APP_H__ #define __RIL_APP_H__ #include "ril_vdev.h" rt_err_t ril_app_init(void); rt_err_t ril_vdev_power_on(void); rt_err_t ril_vdev_power_off(void); int ril_at_device_init(void); #endif ``` ## 测试验证 - 构建、编译、下载,打开串口终端,`list_device` 查看设备是否正常注册 ```c \ | / - RT - Thread Operating System / | \ 4.1.0 build Jan 23 2022 13:17:49 2006 - 2021 Copyright by rt-thread team _ril_vdev_read : buffer = , size = 1 [I/at.clnt] AT client(V1.3.1) on device ril_dev initialize success. [I/sensor] rt_sensor[humi_humidity] init success [I/sensor] rt_sensor[temp_temperature] init success [I/sensor] rt_sensor[baro_barometer] init success [I/sensor] rt_sensor[gyro_gyroscope] init success [I/sensor] rt_sensor[acce_accelerometer] init success msh > msh > msh > msh > msh >list_de list_device msh >list_device device type ref count -------- -------------------- ---------- acce_acc Sensor Device 0 gyro_gyr Sensor Device 0 baro_bar Sensor Device 0 temp_tem Sensor Device 0 humi_hum Sensor Device 0 ril_dev Character Device 2 /* 注册的ril AT 字符设备 */ uart2 Character Device 0 uart1 Character Device 2 pin Miscellaneous Device 0 msh > ``` - 测试AT组件,这里使用自己封装的AT组件的命令 ```c msh >ril_test_check_sim _ril_vdev_write : buffer = AT+CPIN? , size = 10 [W/at.clnt] execute command (AT+CPIN?) timeout (500 ticks)! [D/rild.test] at_response_dump: line_counts=0 [E/rild.test] at_check_sim failed. msh >ril_test_at_cmd AT+CSQ? _ril_vdev_write : buffer = AT+CSQ? , size = 9 [W/at.clnt] execute command (AT+CSQ?) timeout (1000 ticks)! [D/rild.test] at_response_dump: line_counts=0 msh > ``` - 上面是发送命令,发现已经成功调用了我们注册的ril_dev write接口:_ril_vdev_write,无响应是因为没有使用xMUX接口。 - xMUX接口需要根据具体Modem xMUX的接口对接。 ## 使用总结 - AT组件对接的是字符设备,不需要一定是uart设备 - 对接xMUX虚拟出来的AT命令接口,需要实现rt_device的 ```c rt_size_t _ril_vdev_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size) { rt_kprintf("%s : buffer = %s, size = %d\r\n", __func__, buffer, size); // XMUX_read(buffer, size); return RT_EOK; } rt_size_t _ril_vdev_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size) { rt_kprintf("%s : buffer = %s, size = %d\r\n", __func__, buffer, size); // XMUX_write(buffer, size); return RT_EOK; } ``` - 后续可以根据AT命令做一个【虚拟Modem】设备,从而让AT组件【空跑】运转起来 ## 小结 - 熟悉AT组件的AT client的使用 - 熟悉AT组件对接Modem RIL层的xMUX AT命令接口的方法
2
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
张世争
学以致用
文章
131
回答
813
被采纳
177
关注TA
发私信
相关文章
1
RT-THREAD在STM32H747平台上移植lwip
2
正点原子miniSTM32开发板读写sdcard
3
反馈rtt串口驱动对低功耗串口lpuart1不兼容的问题
4
Keil MDK 移植 RT-Thread Nano
5
RT1061/1052 带 RTT + LWIP和LPSPI,有什么坑要注意吗?
6
RT thread HID 如何收发数据
7
求一份基于RTT系统封装好的STM32F1系列的FLASH操作程序
8
RT-Thread修改项目名称之后不能下载
9
rt-studio编译c++
10
有木有移植rt-thread(nano)到riscv 32位MCU上
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
DMA
USB
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
rt-smart
FAL
I2C_IIC
UART
ESP8266
cubemx
WIZnet_W5500
ota在线升级
PWM
BSP
flash
freemodbus
packages_软件包
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
编译报错
中断
Debug
rt_mq_消息队列_msg_queue
keil_MDK
ulog
SFUD
msh
C++_cpp
MicroPython
本月问答贡献
RTT_逍遥
10
个答案
3
次被采纳
xiaorui
3
个答案
2
次被采纳
winfeng
2
个答案
2
次被采纳
三世执戟
8
个答案
1
次被采纳
KunYi
8
个答案
1
次被采纳
本月文章贡献
catcatbing
3
篇文章
5
次点赞
lizimu
2
篇文章
9
次点赞
swet123
1
篇文章
4
次点赞
Days
1
篇文章
4
次点赞
YZRD
1
篇文章
2
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部