




已阅读5页,还剩11页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1.消息编码与解码用C实现7-bit编码和解码的算法如下:/ 7-bit编码/ pSrc: 源字符串指针/ pDst: 目标编码串指针/ nSrcLength: 源字符串长度/ 返回: 目标编码串长度int gsmEncode7bit(const char* pSrc, unsigned char* pDst, int nSrcLength) int nSrc; / 源字符串的计数值 int nDst; / 目标编码串的计数值 int nChar; / 当前正在处理的组内字符字节的序号,范围是0-7 unsigned char nLeft; / 上一字节残余的数据 / 计数值初始化 nSrc = 0; nDst = 0; / 将源串每8个字节分为一组,压缩成7个字节 / 循环该处理过程,直至源串被处理完 / 如果分组不到8字节,也能正确处理 while(nSrc / 取源字符串的计数值的最低3位 nChar = nSrc & 7; / 处理源串的每个字节 if(nChar = 0) / 组内第一个字节,只是保存起来,待处理下一个字节时使用 nLeft = *pSrc; else / 组内其它字节,将其右边部分与残余数据相加,得到一个目标编码字节 *pDst = (*pSrc nChar; / 修改目标串的指针和计数值 pDst+; nDst+; / 修改源串的指针和计数值 pSrc+; nSrc+; / 返回目标串长度 return nDst; / 7-bit解码/ pSrc: 源编码串指针/ pDst: 目标字符串指针/ nSrcLength: 源编码串长度/ 返回: 目标字符串长度int gsmDecode7bit(const unsigned char* pSrc, char* pDst, int nSrcLength) int nSrc; / 源字符串的计数值 int nDst; / 目标解码串的计数值 int nByte; / 当前正在处理的组内字节的序号,范围是0-6 unsigned char nLeft; / 上一字节残余的数据 / 计数值初始化 nSrc = 0; nDst = 0; / 组内字节序号和残余数据初始化 nByte = 0; nLeft = 0; / 将源数据每7个字节分为一组,解压缩成8个字节 / 循环该处理过程,直至源数据被处理完 / 如果分组不到7字节,也能正确处理 while(nSrc / 将源字节右边部分与残余数据相加,去掉最高位,得到一个目标解码字节 *pDst = (*pSrc (7-nByte); / 修改目标串的指针和计数值 pDst+; nDst+; / 修改字节计数值 nByte+; / 到了一组的最后一个字节 if(nByte = 7) / 额外得到一个目标解码字节 *pDst = nLeft; / 修改目标串的指针和计数值 pDst+; nDst+; / 组内字节序号和残余数据初始化 nByte = 0; nLeft = 0; / 修改源串的指针和计数值 pSrc+; nSrc+; *pDst = 0; / 返回目标串长度 return nDst;需要指出的是,7-bit的字符集与ANSI标准字符集不完全一致,在0x20以下也排布了一些可打印字符,但英文字母、阿拉伯数字和常用符号的位 置两者是一样的。用上面介绍的算法收发纯英文短消息,一般情况应该是够用了。如果是法语、德语、西班牙语等,含有 “?”、 “”这一类字符,则要按上面编码的输出去查表,请参阅GSM 03.38的规定。8-bit编码其实没有规定什么具体的算法,不需要介绍。UCS2编码是将每个字符(1-2个字节)按照ISO/IEC10646的规定,转变为16位的Unicode宽字符。在Windows系统中,特 别是在2000/XP中,可以简单地调用API 函数实现编码和解码。如果没有系统的支持,比如用单片机控制手机模块收发短消息,只好用查表法解决了。Windows环境下,用C实现UCS2编码和解码的算法如下:/ UCS2编码/ pSrc: 源字符串指针/ pDst: 目标编码串指针/ nSrcLength: 源字符串长度/ 返回: 目标编码串长度int gsmEncodeUcs2(const char* pSrc, unsigned char* pDst, int nSrcLength) int nDstLength; / UNICODE宽字符数目 WCHAR wchar128; / UNICODE串缓冲区 / 字符串-UNICODE串 nDstLength = :MultiByteToWideChar(CP_ACP, 0, pSrc, nSrcLength, wchar, 128); / 高低字节对调,输出 for(int i=0; i / 先输出高位字节 *pDst+ = wchari 8; / 后输出低位字节 *pDst+ = wchari & 0xff; / 返回目标编码串长度 return nDstLength * 2; / UCS2解码/ pSrc: 源编码串指针/ pDst: 目标字符串指针/ nSrcLength: 源编码串长度/ 返回: 目标字符串长度int gsmDecodeUcs2(const unsigned char* pSrc, char* pDst, int nSrcLength) int nDstLength; / UNICODE宽字符数目 WCHAR wchar128; / UNICODE串缓冲区 / 高低字节对调,拼成UNICODE for(int i=0; i / 先高位字节 wchari = *pSrc+ 字符串 nDstLength = :WideCharToMultiByte(CP_ACP, 0, wchar, nSrcLength/2, pDst, 160, NULL, NULL); / 输出字符串加个结束符 pDstnDstLength = 0; / 返回目标字符串长度 return nDstLength;用以上编码和解码模块,还不能将短消息字符串编码为PDU串需要的格式,也不能直接将PDU串中的用户信息解码为短消息字符串,因为还差一个在可打 印字符串和字节数据之间相互转换的环节。可以循环调用sscanf和sprintf函数实现这种变换。下面提供不用这些函数的算法,它们也适用于单片机、 DSP编程环境。/ 可打印字符串转换为字节数据/ 如:C8329BFD0E01 - 0xC8, 0x32, 0x9B, 0xFD, 0x0E, 0x01/ pSrc: 源字符串指针/ pDst: 目标数据指针/ nSrcLength: 源字符串长度/ 返回: 目标数据长度int gsmString2Bytes(const char* pSrc, unsigned char* pDst, int nSrcLength) for(int i=0; i / 输出高4位 if(*pSrc=0 & *pSrc=9) *pDst = (*pSrc - 0) 4; else *pDst = (*pSrc - A + 10) =0 & *pSrc C8329BFD0E01 / pSrc: 源数据指针/ pDst: 目标字符串指针/ nSrcLength: 源数据长度/ 返回: 目标字符串长度int gsmBytes2String(const unsigned char* pSrc, char* pDst, int nSrcLength) const char tab=0123456789ABCDEF; / 0x0-0xf的字符查找表 for(int i=0; i / 输出低4位 *pDst+ = tab*pSrc 4; / 输出高4位 *pDst+ = tab*pSrc & 0x0f; pSrc+; / 输出字符串加个结束符 *pDst = 0; / 返回目标字符串长度 return nSrcLength * 2;2,消息发送/ 用户信息编码方式#define GSM_7BIT 0#define GSM_8BIT 4#define GSM_UCS2 8 / 短消息参数结构,编码/解码共用/ 其中,字符串以0结尾typedef struct char SCA16; / 短消息服务中心号码(SMSC地址) char TPA16; / 目标号码或回复号码(TP-DA或TP-RA) char TP_PID; / 用户信息协议标识(TP-PID) char TP_DCS; / 用户信息编码方式(TP-DCS) char TP_SCTS16; / 服务时间戳字符串(TP_SCTS), 接收时用到 char TP_UD161; / 原始用户信息(编码前或解码后的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 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 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 buf256; / 内部用的缓冲区 / SMSC地址信息段 nLength = strlen(pSrc-SCA); / SMSC地址字符串的长度 buf0 = (char)(nLength & 1) = 0 ? nLength : nLength + 1) / 2 + 1; / SMSC地址信息长度 buf1 = 0x91; / 固定: 用国际格式号码 nDstLength = gsmBytes2String(buf, pDst, 2); / 转换2个字节到目标PDU串 nDstLength += gsmInvertNumbers(pSrc-SCA, &pDstnDstLength, nLength); / 转换SMSC到目标PDU串 / TPDU段基本参数、目标地址等 nLength = strlen(pSrc-TPA); / TP-DA地址字符串的长度 buf0 = 0x11; / 是发送短信(TP-MTI=01),TP-VP用相对格式(TP-VPF=10) buf1 = 0; / TP-MR=0 buf2 = (char)nLength; / 目标地址数字个数(TP-DA地址字符串真实长度) buf3 = 0x91; / 固定: 用国际格式号码 nDstLength += gsmBytes2String(buf, &pDstnDstLength, 4); /转换4个字节到目标PDU串 nDstLength += gsmInvertNumbers(pSrc-TPA, &pDstnDstLength, nLength); / 转换TP-DA到目标PDU串 / TPDU段协议标识、编码方式、用户信息等 nLength = strlen(pSrc-TP_UD); / 用户信息字符串的长度 buf0 = pSrc-TP_PID; / 协议标识(TP-PID) buf1 = pSrc-TP_DCS; / 用户信息编码方式(TP-DCS)buf2 = 0; / 有效期(TP-VP)为5分钟 if(pSrc-TP_DCS = GSM_7BIT) / 7-bit编码方式 buf3 = nLength; / 编码前长度 nLength = gsmEncode7bit(pSrc-TP_UD, &buf4, nLength+1) + 4; / 转换TP-DA到目标PDU串 else if(pSrc-TP_DCS = GSM_UCS2) / UCS2编码方式 buf3 = gsmEncodeUcs2(pSrc-TP_UD, &buf4, nLength); / 转换TP-DA到目标PDU串 nLength = buf3 + 4; / nLength等于该段数据长度 else / 8-bit编码方式 buf3 = gsmEncode8bit(pSrc-TP_UD, &buf4, nLength); / 转换TP-DA到目标PDU串 nLength = buf3 + 4; / nLength等于该段数据长度 nDstLength += gsmBytes2String(buf, &pDstnDstLength, nLength); / 转换该段数据到目标PDU串 / 返回目标字符串长度 return nDstLength; / PDU解码,用于接收、阅读短消息/ pSrc: 源PDU串指针/ pDst: 目标PDU参数指针/ 返回: 用户信息串长度int gsmDecodePdu(const char* pSrc, SM_PARAM* pDst) int nDstLength; / 目标PDU串长度 unsigned char tmp; / 内部用的临时字节变量 unsigned char buf256; / 内部用的缓冲区 / SMSC地址信息段 gsmString2Bytes(pSrc, &tmp, 2); / 取长度 tmp = (tmp - 1) * 2; / SMSC号码串长度 pSrc += 4; / 指针后移 gsmSerializeNumbers(pSrc, pDst-SCA, tmp); / 转换SMSC号码到目标PDU串 pSrc += tmp; / 指针后移 / TPDU段基本参数、回复地址等 gsmString2Bytes(pSrc, &tmp, 2); / 取基本参数 pSrc += 2; / 指针后移 if(tmp & 0x80) / 包含回复地址,取回复地址信息 gsmString2Bytes(pSrc, &tmp, 2); / 取长度 if(tmp & 1) tmp += 1; / 调整奇偶性 pSrc += 4; / 指针后移 gsmSerializeNumbers(pSrc, pDst-TPA, tmp); / 取TP-RA号码 pSrc += tmp; / 指针后移 / TPDU段协议标识、编码方式、用户信息等 gsmString2Bytes(pSrc, (unsigned char*)&pDst-TP_PID, 2); / 取协议标识(TP-PID) pSrc += 2; / 指针后移 gsmString2Bytes(pSrc, (unsigned char*)&pDst-TP_DCS, 2); / 取编码方式(TP-DCS) pSrc += 2; / 指针后移 gsmSerializeNumbers(pSrc, pDst-TP_SCTS, 14); / 服务时间戳字符串(TP_SCTS) pSrc += 14; / 指针后移 gsmString2Bytes(pSrc, &tmp, 2); / 用户信息长度(TP-UDL) pSrc += 2; / 指针后移 if(pDst-TP_DCS = GSM_7BIT) / 7-bit解码 nDstLength = gsmString2Bytes(pSrc, buf, tmp & 7 ? (int)tmp * 7 / 4 + 2 : (int)tmp * 7 / 4); / 格式转换 gsmDecode7bit(buf, pDst-TP_UD, nDstLength); / 转换到TP-DU nDstLength = tmp; else if(pDst-TP_DCS = GSM_UCS2) / UCS2解码 nDstLength = gsmString2Bytes(pSrc, buf, tmp * 2); / 格式转换 nDstLength = gsmDecodeUcs2(buf, pDst-TP_UD, nDstLength); / 转换到TP-DU else / 8-bit解码 nDstLength = gsmString2Bytes(pSrc, buf, tmp * 2); / 格式转换 nDstLength = gsmDecode8bit(buf, pDst-TP_UD, nDstLength); / 转换到TP-DU / 返回目标字符串长度 return nDstLength;依照GSM 07.05,发送短消息用AT+CMGS命令,阅读短消息用AT+CMGR命令,列出短消息用AT+CMGL命令,删除短消息用AT+CMGD命令。但 AT+CMGL命令能够读出所有的短消息,所以我们用它实现阅读短消息功能,而没用AT+CMGR。下面是发送、读取和删除短消息的实现代码:/ 发送短消息/ pSrc: 源PDU参数指针BOOL gsmSendMessage(const SM_PARAM* pSrc) int nPduLength; / PDU串长度 unsigned char nSmscLength; / SMSC串长度 int nLength; / 串口收到的数据长度 char cmd16; / 命令串 char pdu512; / PDU串 char ans128; / 应答串 nPduLength = gsmEncodePdu(pSrc, pdu); / 根据PDU参数,编码PDU串 strcat(pdu, x01a); / 以Ctrl-Z结束 gsmString2Bytes(pdu, &nSmscLength, 2); / 取PDU串中的SMSC信息长度 nSmscLength+; / 加上长度字节本身 / 命令中的长度,不包括SMSC信息长度,以数据字节计 sprintf(cmd, AT+CMGS=%dr, nPduLength / 2 - nSmscLength); / 生成命令 WriteComm(cmd, strlen(cmd); / 先输出命令串 nLength = ReadComm(ans, 128); / 读应答数据 / 根据能否找到rn 决定成功与否 if(nLength = 4 & strncmp(ans, rn , 4) = 0) WriteComm(pdu, strlen(pdu); / 得到肯定回答,继续输出PDU串 nLength = ReadComm(ans, 128); / 读应答数据 / 根据能否找到+CMS ERROR决定成功与否 if(nLength 0 & strncmp(ans, +CMS ERROR, 10) != 0) return TRUE; return FALSE; / 读取短消息/ 用+CMGL代替+CMGR,可一次性读出全部短消息/ pMsg: 短消息缓冲区,必须足够大/ 返回: 短消息条数int gsmReadMessage(SM_PARAM* pMsg) int nLength; / 串口收到的数据长度 int nMsg; / 短消息计数值 char* ptr; / 内部用的数据指针 char cmd16; / 命令串 char ans1024; / 应答串 nMsg = 0; ptr = ans; sprintf(cmd, AT+CMGLr); / 生成命令 WriteComm(cmd, strlen(cmd); / 输出命令串 nLength = ReadComm(ans, 1024); / 读应答数据 / 根据能否找到+CMS ERROR决定成功与否 if(nLength 0 & strncmp(ans, +CMS ERROR, 10) != 0) / 循环读取每一条短消息, 以+CMGL:开头 while(ptr = strstr(ptr, +CMGL:) != NULL) ptr += 6; / 跳过+CMGL: sscanf(ptr, %d, &pMsg-index); / 读取序号 TRACE( index=%dn,pMsg-index); ptr = strstr(ptr, rn); / 找下一行 ptr += 2; / 跳过rn gsmDecodePdu(ptr, pMsg); / PDU串解码 pMsg+; / 准备读下一条短消息 nMsg+; / 短消息计数加1 return nMsg; / 删除短消息/ index: 短消息序号,从1开始BOOL gsmDeleteMessage(const int index) int nLength; / 串口收到的数据长度 char cmd16; / 命令串 char ans128; / 应答串 sprintf(cmd, AT+CMGD=%dr, index); / 生成命令 / 输出命令串 WriteComm(cmd, strlen(cmd); / 读应答数据 nLength = ReadComm(ans, 128); / 根据能否找到+CMS ERROR决定成功与否 if(nLength 0 & strncmp(ans, +CMS ERROR, 10) != 0) return TRUE; return FALSE;以上发送AT命令过程中用到了WriteComm和ReadComm函数,它们是用来读写串口的,依赖于具体的操作系统。在Windows环境下, 除了用MSComm控件,以及某些现成的串口通信类之外,也可以简单地调用一些Windows API用实现。以下是利用API实现的主要代码,注意我们用的是超时控制的同步(阻塞)模式。/ 串口设备句柄HANDLE hComm; / 打开串口/ pPort: 串口名称或设备路径,可用COM1或.COM1两种方式,建议用后者/ nBaudRate: 波特率/ nParity: 奇偶校验/ nByteSize: 数据字节宽度/ nStopBits: 停止位BOOL OpenComm(const char* pPort, int nBaudRate, int nParity, int nByteSize, in
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 薪酬绩效管理培训
- 魔幻消气屋课件
- 巨人创意画课件
- 自然拼读字母课件
- 表情包转盘课件
- 新媒体案例培训
- 朱子治家培训讲座
- 课件最美的眼神
- 课件最后一页内容
- 课件智能生成
- 货物仓储托管合同协议
- 2025至2030中国汽车前大灯及后装市场经营策略及投融资趋势研究报告
- 中心静脉导管并发症处理
- 铁路货运信息化的国际比较与借鉴
- 中建八局《建筑工程质量管理口袋书~基础、主体结构、装饰分册》
- 智能矿山技术在硬岩铀矿山的应用实例与挑战
- 畜禽疫病防控技术课件教学
- 2025静脉输液规范
- 2025年轻型民用无人驾驶航空器安全操控(多旋翼)理论备考试题库(含答案)
- 大学英语 专升本 课件 第十节 定语从句
- 瑜伽急救知识培训课件
评论
0/150
提交评论