GSM 07.10 协议支持

以上是一次 CMUX 建立,通话和销毁的基本流程,因为牵扯到真实串口到虚拟串口的交互,所以可以在一个物理串口上同时实现多个功能。在 PPP 拨号启用时,仍然可以调用 AT 命令,也可以使用 Modem 功能同时支持数据通话。
多路复用协议提供在单个物理通信通道之上虚拟出多个并行的逻辑通信通道的能力,一般应用于TE(Terminal Equipment)与MS(Mobile Station)之间,TE相当于智能手机的AP端,MS相当于智能手机的MODEM端。多路复用协议的实现效果如图:

实际使用中,TE 端的 MUX 向 MS 端的 MUX 发起通道建立请求,设置通道参数等,是主动的一方;
MS端的MUX等待TE端的服务请求,根据自身能力提供相应服务。
| Flag | Address | Control | Length | Information | FCS | Flag |
|---|---|---|---|---|---|---|
| 0xF9(basic) | 地址域 | 控制域 | 数据域长度 | 实际数据域 | 校验域 | 0xF9(basic) |
地址域:
| Bit No. | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
|---|---|---|---|---|---|---|---|---|
| Signal | EA | C/R | DLCI | DLCI | DLCI | DLCI | DLCI | DLCI |
控制域:
| Frame Type | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 备注 |
|---|---|---|---|---|---|---|---|---|---|
| SABM (Set Asynchronous Balanced Mode) | 1 | 1 | 1 | 1 | P/F | 1 | 0 | 0 | |
| UA (Unnumbered Acknowledgement) | 1 | 1 | 0 | 0 | P/F | 1 | 1 | 0 | |
| DM (Disconnected Mode) | 1 | 1 | 1 | 1 | P/F | 0 | 0 | 0 | |
| DISC (Disconnect) | 1 | 1 | 0 | 0 | P/F | 0 | 1 | 0 | |
| UIH(Unnumbered Information with Header check) | 1 | 1 | 1 | 1 | P/F | 1 | 1 | 1 | |
| UI (Unnumbered Information) | 1 | 1 | 0 | 0 | P/F | 0 | 0 | 0 | 可选 |
STM32F407 + Air720H(手动拼接命令测试)
使用 AT+CMUX 命令,进入 CMUX 配置功能;测试 CMUX 功能是否正常:
手动发送的 CMUX 命令:
使用 STM32F407 + Air720H 平台,实现 CMUX 功能;
目标是做成软件包的形式,软件包的功能是打开后,将通过 cmux 软件包向上虚拟出 vcom1, vcom2, vcom3 以代表 ppp, at, modem 这些接口,向下接管真实物理串口,通过 cmux 协议解析数据以实现正常传输。使用时通过 rt_device_find 查找使用,以实现较大的通用性。
基于 Github 上 gsmmux 仓库,该仓库是针对 Linux 系统实现的 CMUX 协议支持;
cmux
├───docs
│ └───figures // 文档使用图片
├───class
│ └───cmux_air720.c // 针对不同设备
├───sample // 示例文件
│ └─── sample.c
├───inc // 头文件
│ └─── cmux.h
├───src // 移植文件
│ └─── cmux.c
├───LICENSE // 软件包许可证
├───README.md // 软件包使用说明
└───SConscript // RT-Thread 默认的构建脚本
CMUX 的帧结构介绍
typedef struct cmux_buffer
{
rt_uint8_t data[CMUX_BUFFER_SIZE];
rt_uint8_t *read_point; // 用于读取 CMUX 数据的指针
rt_uint8_t *write_point; // 指向 CMUX 数据区的指针
rt_uint8_t *end_point; // 指向 CMUX 数据区末尾的指针
int flag_found; // 是否找到 0xF9 帧头
} cmux_buffer;
typedef struct cmux_frame {
rt_uint8_t channel; // 地址域
rt_uint8_t control; // 数据帧类型, SABM,UIH,UA; 控制域
int data_length; // 数据长度
rt_uint8_t *data; // 实际数据
} cmux_frame;
CMUX 不同帧类型介绍
// bits: Poll/final, Command/Response, Extension
#define CMUX_CONTROL_PF 16
#define CMUX_ADDRESS_CR 2
#define CMUX_ADDRESS_EA 1
// the types of the frames
#define CMUX_FRAME_SABM 47
#define CMUX_FRAME_UA 99
#define CMUX_FRAME_DM 15
#define CMUX_FRAME_DISC 67
#define CMUX_FRAME_UIH 239
#define CMUX_FRAME_UI 3
// the types of the control channel commands
#define CMUX_C_CLD 193
#define CMUX_C_TEST 33
#define CMUX_C_MSC 225
#define CMUX_C_NSC 17
// basic mode flag for frame start and end
#define CMUX_HEAD_FLAG (unsigned char)0xF9
需要实现的结构体
typedef struct cmux
{
struct rt_device *dev; /* device object */
const struct cmux_ops *ops; /* cmux device ops interface */
cmux_set_command_t cmd; /* CMUX start AT command */
struct cmux_buffer *buffer; /* cmux buffer */
rt_thread_t *recv_tid; /* recieve thread point */
rt_uint8_t vcom_num; /* the cmux port number array */
struct cmux_vcom *vcom; /* virual serial device */
rt_slist_t *list; /* cmux list */
void *user_data; /* reserve */
}cmux;
struct cmux_ops
{
rt_err_t *(start) (struct cmux *obj);
rt_err_t *(stop) (struct cmux *obj);
rt_err_t *(control) (struct cmux *obj, int cmd, void *arg);
};