通过串口收发短消息(下)

本文介绍了通过串口使用AT命令收发短消息的核心编码和解码过程,包括PDU串的编解码模块,以及遵循GSM 07.05规范的AT+CMGS、AT+CMGR、AT+CMGL和AT+CMGD命令的使用。同时,讨论了与手机通信时的注意事项,如错误处理和同步模式。此外,提到了不同手机厂商对于短消息AT命令可能存在细微差异,以及自定义数据作为用户信息的传输可能性。
摘要由CSDN通过智能技术生成

Q PDU的核心编码方式已经清楚了,如何实现用AT命令收发短消息呢?

A 在上篇中,我们已经讨论了7-bit, 8bit和UCS2这几种PDU用户信息的编码方式,并且给出了实现代码。现在,重点描述PDU全串的编码和解码过程,以及GSM 07.05的AT命令实现方法。这些是底层的核心代码,为了保证代码的可移植性,我们尽可能不用MFC的类,必要时用ANSI C标准库函数。
首先,定义如下常量和结构:

// 用户信息编码方式
#define GSM_7BIT        0
#define GSM_8BIT        4
#define GSM_UCS2        8
    
// 短消息参数结构,编码/解码共用
// 其中,字符串以0结尾
typedef struct {
    char SCA[16];       // 短消息服务中心号码(SMSC地址)
    char TPA[16];       // 目标号码或回复号码(TP-DA或TP-RA)
    char TP_PID;        // 用户信息协议标识(TP-PID)
    char TP_DCS;        // 用户信息编码方式(TP-DCS)
    char TP_SCTS[16];   // 服务时间戳字符串(TP_SCTS), 接收时用到
    char TP_UD[161];    // 原始用户信息(编码前或解码后的TP-UD)
    char index;         // 短消息序号,在读取时用到
} SM_PARAM;

大家已经注意到PDU串中的号码和时间,都是两两颠倒的字符串。利用下面两个函数可进行正反变换:

// 正常顺序的字符串转换为两两颠倒的字符串,若长度为奇数,补'F'凑成偶数
// 如:"8613851872468" --> "683158812764F8"
// pSrc: 源字符串指针
// pDst: 目标字符串指针
// nSrcLength: 源字符串长度
// 返回: 目标字符串长度
int gsmInvertNumbers(const char* pSrc, char* pDst, int nSrcLength)
{
    int nDstLength;   // 目标字符串长度
    char ch;          // 用于保存一个字符
    
    // 复制串长度
    nDstLength = nSrcLength;
    
    // 两两颠倒
    for(int i=0; i<nSrcLength;i+=2)
    {
        ch = *pSrc++;        // 保存先出现的字符
        *pDst++ = *pSrc++;   // 复制后出现的字符
        *pDst++ = ch;        // 复制先出现的字符
    }
    
    // 源串长度是奇数吗?
    if(nSrcLength & 1)
    {
        *(pDst-2) = 'F';     // 补'F'
        nDstLength++;        // 目标串长度加1
    }
    
    // 输出字符串加个结束符
    *pDst = '/0';
    
    // 返回目标字符串长度
    return nDstLength;
}
    
// 两两颠倒的字符串转换为正常顺序的字符串
// 如:"683158812764F8" --> "8613851872468"
// pSrc: 源字符串指针
// pDst: 目标字符串指针
// nSrcLength: 源字符串长度
// 返回: 目标字符串长度
int gsmSerializeNumbers(const char* pSrc, char* pDst, int nSrcLength)
{
    int nDstLength;   // 目标字符串长度
    char ch;          // 用于保存一个字符
    
    // 复制串长度
    nDstLength = nSrcLength;
    
    // 两两颠倒
    for(int i=0; i<nSrcLength;i+=2)
    {
        ch = *pSrc++;        // 保存先出现的字符
        *pDst++ = *pSrc++;   // 复制后出现的字符
        *pDst++ = ch;        // 复制先出现的字符
    }
    
    // 最后的字符是'F'吗?
    if(*(pDst-1) == 'F')
    {
        pDst--;
        nDstLength--;        // 目标字符串长度减1
    }
    
    // 输出字符串加个结束符
    *pDst = '/0';
    
    // 返回目标字符串长度
    return nDstLength;
}

以下是PDU全串的编解码模块。为简化编程,有些字段用了固定值。

// PDU编码,用于编制、发送短消息
// pSrc: 源PDU参数指针
// pDst: 目标PDU串指针
// 返回: 目标PDU串长度
int gsmEncodePdu(const SM_PARAM* pSrc, char* pDst)
{
    int nLength;             // 内部用的串长度
    int nDstLength;          // 目标PDU串长度
    unsigned char buf[256];  //
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值