




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
1、. . . . 串口連接GSM手機(jī)發(fā)送和接收短消息,在應(yīng)用程序中如何編程實(shí)現(xiàn)? Q 我們打算開發(fā)一個(gè)基于GSM短消息方式的GPS系統(tǒng),如何利用SMS進(jìn)行數(shù)據(jù)通信?A 首先,我們要對由ESTI制訂的SMS規(guī)有所了解。與我們討論的短消息收發(fā)有關(guān)的規(guī)主要包括GSM 03.38、GSM 03.40和GSM 07.05。前二者著重描述SMS的技術(shù)實(shí)現(xiàn)(含編碼方式),后者則規(guī)定了SMS的DTE-DCE接口標(biāo)準(zhǔn)(AT命令集)。一共有三種方式來發(fā)送和接收SMS信息:Block Mode, Text Mode和PDU Mode。Block Mode已是昔日黃花,目前很少用了。Text Mode是純文
2、本方式,可使用不同的字符集,從技術(shù)上說也可用于發(fā)送中文短消息,但國手機(jī)基本上不支持,主要用于歐美地區(qū)。PDU Mode被所有手機(jī)支持,可以使用任何字符集,這也是手機(jī)默認(rèn)的編碼方式。Text Mode比較簡單,而且不適合做自定義數(shù)據(jù)傳輸,我們就不討論了。下面介紹的容,是在PDU Mode下發(fā)送和接收短消息的實(shí)現(xiàn)方法。PDU串表面上是一串ASCII碼,由0-9、 A-F這些數(shù)字和字母組成。它們是8位字節(jié)的十六進(jìn)制數(shù),或者BCD碼十進(jìn)制數(shù)。PDU串不僅包含可顯示的消息本身,還包含很多其它信息,如 SMS服務(wù)中心、目標(biāo)、回復(fù)、編碼方式和服務(wù)時(shí)間等。發(fā)送和接收的PDU串,結(jié)構(gòu)是不完全一樣的。我們先用兩個(gè)
3、實(shí)際的例子說明PDU串的結(jié)構(gòu)和編排方式。例1 發(fā)送:SMSC是+00,對方是,消息容是“Hello!”。從手機(jī)發(fā)出的PDU串可以是08 91 68 31 08 20 05 05 F0 11 00 0D 91 68 31 58 81 27 64 F8 00 00 00 06 C8 32 9B FD 0E 01對照規(guī),具體分析:分段含義說明08SMSC地址信息的長度共8個(gè)八位字節(jié)(包括91)91SMSC地址格式(TON/NPI)用國際格式(在前面加+)68 31 08 20 05 05 F0SMSC地址00,補(bǔ)F湊成偶數(shù)個(gè)11基本參數(shù)(TP-MTI/VFP)發(fā)送,TP-VP用相對格式00消息基準(zhǔn)值
4、(TP-MR)00D目標(biāo)地址數(shù)字個(gè)數(shù)共13個(gè)十進(jìn)制數(shù)(不包括91和F)91目標(biāo)地址格式(TON/NPI)用國際格式(在前面加+)68 31 58 81 27 64 F8目標(biāo)地址(TP-DA)68,補(bǔ)F湊成偶數(shù)個(gè)00協(xié)議標(biāo)識(TP-PID)是普通GSM類型,點(diǎn)到點(diǎn)方式00用戶信息編碼方式(TP-DCS)7-bit編碼00有效期(TP-VP)5分鐘06用戶信息長度(TP-UDL)實(shí)際長度6個(gè)字節(jié)C8 32 9B FD 0E 01用戶信息(TP-UD)“Hello!”例2 接收:SMSC是+00,對方是,消息容是“你好!”。手機(jī)接收到的PDU串可以是08 91 68 31 08 20 05 05 F
5、0 84 0D 91 68 31 58 81 27 64 F8 00 08 30 30 21 80 63 54 80 06 4F 60 59 7D 00 21對照規(guī),具體分析:分段含義說明08地址信息的長度個(gè)八位字節(jié)(包括91)91SMSC地址格式(TON/NPI)用國際格式(在前面加+)68 31 08 20 05 05 F0SMSC地址00,補(bǔ)F湊成偶數(shù)個(gè)84基本參數(shù)(TP-MTI/MMS/RP)接收,無更多消息,有回復(fù)地址0D回復(fù)地址數(shù)字個(gè)數(shù)共13個(gè)十進(jìn)制數(shù)(不包括91和F)91回復(fù)地址格式(TON/NPI)用國際格式(在前面加+)68 31 58 81 27 64 F8回復(fù)地
6、址(TP-RA)68,補(bǔ)F湊成偶數(shù)個(gè)00協(xié)議標(biāo)識(TP-PID)是普通GSM類型,點(diǎn)到點(diǎn)方式08用戶信息編碼方式(TP-DCS)UCS2編碼30 30 21 80 63 54 80時(shí)間戳(TP-SCTS)2003-3-12 08:36:45 +8時(shí)區(qū)06用戶信息長度(TP-UDL)實(shí)際長度6個(gè)字節(jié)4F 60 59 7D 00 21用戶信息(TP-UD)“你好!”若基本參數(shù)的最高位(TP-RP)為0,則沒有回復(fù)地址的三個(gè)段。從Internet上發(fā)出的短消息常常是這種情形。注意和時(shí)間的表示方法,不是按正常順序順著來的,而且要以F將奇數(shù)補(bǔ)成偶數(shù)。Q 上面兩例中已經(jīng)出現(xiàn)了7-bit和UCS
7、2編碼,請?jiān)敿?xì)介紹一下這些編碼方式?A 在PDU Mode中,可以采用三種編碼方式來對發(fā)送的容進(jìn)行編碼,它們是7-bit、8-bit和UCS2編碼。7-bit編碼用于發(fā)送普通的ASCII字符,它將一串7-bit的字符(最高位為0)編碼成8-bit的數(shù)據(jù),每8個(gè)字符可“壓縮”成7個(gè);8-bit編碼通常用于發(fā)送數(shù)據(jù)消息,比如圖片和鈴聲等;而UCS2編碼用于發(fā)送Unicode字符。PDU串的用戶信息(TP-UD)段最大容量是140字節(jié),所以在這三種編碼方式下,可以發(fā)送的短消息的最大字符數(shù)分別是160、140和70。這里,將一個(gè)英文字母、一個(gè)漢字和一個(gè)數(shù)據(jù)字節(jié)都視為一個(gè)字符。需要注意的是,PDU串的用
8、戶信息長度(TP -UDL),在各種編碼方式下意義有所不同。7-bit編碼時(shí),指原始短消息的字符個(gè)數(shù),而不是編碼后的字節(jié)數(shù)。8-bit編碼時(shí),就是字節(jié)數(shù)。UCS2 編碼時(shí),也是字節(jié)數(shù),等于原始短消息的字符數(shù)的兩倍。如果用戶信息(TP-UD)中存在一個(gè)頭(基本參數(shù)的TP-UDHI為1),在所有編碼方式下,用戶信息長度(TP-UDL)都等于頭長度與編碼后字節(jié)數(shù)之和。如果采用GSM 03.42所建議的壓縮算法(TP-DCS的高3位為001),則該長度也是壓縮編碼后字節(jié)數(shù)或頭長度與壓縮編碼后字節(jié)數(shù)之和。下面以一個(gè)具體的例子說明7-bit編碼的過程。我們對英文短信“Hello!”進(jìn)行編碼:將源串每8個(gè)字
9、符分為一組(這個(gè)例子中不滿8個(gè))進(jìn)行編碼,在組字符間壓縮,但每組之間是沒有什么聯(lián)系的。用C實(shí)現(xiàn)7-bit編碼和解碼的算法如下:/ 7-bit編碼/ pSrc: 源字符串指針/ pDst: 目標(biāo)編碼串指針/ nSrcLength: 源字符串長度/ 返回: 目標(biāo)編碼串長度int gsmEncode7bit(const char* pSrc, unsigned char* pDst, int nSrcLength) int nSrc; / 源字符串的計(jì)數(shù)值 int nDst; / 目標(biāo)編碼串的計(jì)數(shù)值 int nChar; / 當(dāng)前正在處理的組字符字節(jié)的序號,圍是0-7 unsigned char n
10、Left; / 上一字節(jié)殘余的數(shù)據(jù) / 計(jì)數(shù)值初始化 nSrc = 0; nDst = 0; / 將源串每8個(gè)字節(jié)分為一組,壓縮成7個(gè)字節(jié) / 循環(huán)該處理過程,直至源串被處理完 / 如果分組不到8字節(jié),也能正確處理 while(nSrc<nSrcLength) / 取源字符串的計(jì)數(shù)值的最低3位 nChar = nSrc & 7; / 處理源串的每個(gè)字節(jié) if(nChar = 0) / 組第一個(gè)字節(jié),只是保存起來,待處理下一個(gè)字節(jié)時(shí)使用 nLeft = *pSrc; else / 組其它字節(jié),將其右邊部分與殘余數(shù)據(jù)相加,得到一個(gè)目標(biāo)編碼字節(jié) *pDst = (*pSrc <&
11、lt; (8-nChar) | nLeft; / 將該字節(jié)剩下的左邊部分,作為殘余數(shù)據(jù)保存起來 nLeft = *pSrc >> nChar; / 修改目標(biāo)串的指針和計(jì)數(shù)值 pDst+; nDst+; / 修改源串的指針和計(jì)數(shù)值 pSrc+; nSrc+; / 返回目標(biāo)串長度 return nDst; / 7-bit解碼/ pSrc: 源編碼串指針/ pDst: 目標(biāo)字符串指針/ nSrcLength: 源編碼串長度/ 返回: 目標(biāo)字符串長度int gsmDecode7bit(const unsigned char* pSrc, char* pDst, int nSrcLength
12、) int nSrc; / 源字符串的計(jì)數(shù)值 int nDst; / 目標(biāo)解碼串的計(jì)數(shù)值 int nByte; / 當(dāng)前正在處理的組字節(jié)的序號,圍是0-6 unsigned char nLeft; / 上一字節(jié)殘余的數(shù)據(jù) / 計(jì)數(shù)值初始化 nSrc = 0; nDst = 0; / 組字節(jié)序號和殘余數(shù)據(jù)初始化 nByte = 0; nLeft = 0; / 將源數(shù)據(jù)每7個(gè)字節(jié)分為一組,解壓縮成8個(gè)字節(jié) / 循環(huán)該處理過程,直至源數(shù)據(jù)被處理完 / 如果分組不到7字節(jié),也能正確處理 while(nSrc<nSrcLength) / 將源字節(jié)右邊部分與殘余數(shù)據(jù)相加,去掉最高位,得到一個(gè)目標(biāo)解碼
13、字節(jié) *pDst = (*pSrc << nByte) | nLeft) & 0x7f; / 將該字節(jié)剩下的左邊部分,作為殘余數(shù)據(jù)保存起來 nLeft = *pSrc >> (7-nByte); / 修改目標(biāo)串的指針和計(jì)數(shù)值 pDst+; nDst+; / 修改字節(jié)計(jì)數(shù)值 nByte+; / 到了一組的最后一個(gè)字節(jié) if(nByte = 7) / 額外得到一個(gè)目標(biāo)解碼字節(jié) *pDst = nLeft; / 修改目標(biāo)串的指針和計(jì)數(shù)值 pDst+; nDst+; / 組字節(jié)序號和殘余數(shù)據(jù)初始化 nByte = 0; nLeft = 0; / 修改源串的指針和計(jì)數(shù)值
14、pSrc+; nSrc+; *pDst = 0; / 返回目標(biāo)串長度 return nDst;需要指出的是,7-bit的字符集與ANSI標(biāo)準(zhǔn)字符集不完全一致,在0x20以下也排布了一些可打印字符,但英文字母、阿拉伯?dāng)?shù)字和常用符號的位置兩者是一樣的。用上面介紹的算法收發(fā)純英文短消息,一般情況應(yīng)該是夠用了。如果是法語、德語、西班牙語等,含有 “å”、 “é”這一類字符,則要按上面編碼的輸出去查表,請參閱GSM 03.38的規(guī)定。8-bit編碼其實(shí)沒有規(guī)定什么具體的算法,不需要介紹。UCS2編碼是將每個(gè)字符(1-2個(gè)字節(jié))按照ISO/IEC10646的規(guī)定,轉(zhuǎn)變?yōu)?6位的Unic
15、ode寬字符。在Windows系統(tǒng)中,特別是在2000/XP中,可以簡單地調(diào)用API 函數(shù)實(shí)現(xiàn)編碼和解碼。如果沒有系統(tǒng)的支持,比如用單片機(jī)控制手機(jī)模塊收發(fā)短消息,只好用查表法解決了。Windows環(huán)境下,用C實(shí)現(xiàn)UCS2編碼和解碼的算法如下:/ UCS2編碼/ pSrc: 源字符串指針/ pDst: 目標(biāo)編碼串指針/ nSrcLength: 源字符串長度/ 返回: 目標(biāo)編碼串長度int gsmEncodeUcs2(const char* pSrc, unsigned char* pDst, int nSrcLength) int nDstLength; / UNICODE寬字符數(shù)目 WCHAR
16、 wchar128; / UNICODE串緩沖區(qū) / 字符串->UNICODE串 nDstLength = :MultiByteToWideChar(CP_ACP, 0, pSrc, nSrcLength, wchar, 128); / 高低字節(jié)對調(diào),輸出 for(int i=0; i<nDstLength; i+) / 先輸出高位字節(jié) *pDst+ = wchari >> 8; / 后輸出低位字節(jié) *pDst+ = wchari & 0xff; / 返回目標(biāo)編碼串長度 return nDstLength * 2;/ UCS2解碼/ pSrc: 源編碼串指針/
17、pDst: 目標(biāo)字符串指針/ nSrcLength: 源編碼串長度/ 返回: 目標(biāo)字符串長度int gsmDecodeUcs2(const unsigned char* pSrc, char* pDst, int nSrcLength) int nDstLength; / UNICODE寬字符數(shù)目 WCHAR wchar128; / UNICODE串緩沖區(qū) / 高低字節(jié)對調(diào),拼成UNICODE for(int i=0; i<nSrcLength/2; i+) / 先高位字節(jié) wchari = *pSrc+ << 8; / 后低位字節(jié) wchari |= *pSrc+; / U
18、NICODE串->字符串 nDstLength = :WideCharToMultiByte(CP_ACP, 0, wchar, nSrcLength/2, pDst, 160, NULL, NULL); / 輸出字符串加個(gè)結(jié)束符 pDstnDstLength = '0' / 返回目標(biāo)字符串長度 return nDstLength;用以上編碼和解碼模塊,還不能將短消息字符串編碼為PDU串需要的格式,也不能直接將PDU串中的用戶信息解碼為短消息字符串,因?yàn)檫€差一個(gè)在可打印字符串和字節(jié)數(shù)據(jù)之間相互轉(zhuǎn)換的環(huán)節(jié)。可以循環(huán)調(diào)用sscanf和sprintf函數(shù)實(shí)現(xiàn)這種變換。下面提供不
19、用這些函數(shù)的算法,它們也適用于單片機(jī)、 DSP編程環(huán)境。/ 可打印字符串轉(zhuǎn)換為字節(jié)數(shù)據(jù)/ 如:"C8329BFD0E01" -> 0xC8, 0x32, 0x9B, 0xFD, 0x0E, 0x01/ pSrc: 源字符串指針/ pDst: 目標(biāo)數(shù)據(jù)指針/ nSrcLength: 源字符串長度/ 返回: 目標(biāo)數(shù)據(jù)長度int gsmString2Bytes(const char* pSrc, unsigned char* pDst, int nSrcLength) for(int i=0; i<nSrcLength; i+=2) / 輸出高4位 if(*pSrc&
20、gt;='0' && *pSrc<='9') *pDst = (*pSrc - '0') << 4; else *pDst = (*pSrc - 'A' + 10) << 4; pSrc+; / 輸出低4位 if(*pSrc>='0' && *pSrc<='9') *pDst |= *pSrc - '0' else *pDst |= *pSrc - 'A' + 10; pSrc+; pDst+;
21、 / 返回目標(biāo)數(shù)據(jù)長度 returnnSrcLength / 2;/ 字節(jié)數(shù)據(jù)轉(zhuǎn)換為可打印字符串/ 如:0xC8, 0x32, 0x9B, 0xFD, 0x0E, 0x01 -> "C8329BFD0E01" / pSrc: 源數(shù)據(jù)指針/ pDst: 目標(biāo)字符串指針/ nSrcLength: 源數(shù)據(jù)長度/ 返回: 目標(biāo)字符串長度int gsmBytes2String(const unsigned char* pSrc, char* pDst, int nSrcLength) const char tab="0123456789ABCDEF" / 0
22、x0-0xf的字符查找表 for(int i=0; i<nSrcLength; i+) / 輸出低4位 *pDst+ = tab*pSrc >> 4; / 輸出高4位 *pDst+ = tab*pSrc & 0x0f; pSrc+; / 輸出字符串加個(gè)結(jié)束符 *pDst = '0' / 返回目標(biāo)字符串長度 return nSrcLength * 2;Q PDU的核心編碼方式已經(jīng)清楚了,如何實(shí)現(xiàn)用AT命令收發(fā)短消息呢?A 在上篇中,我們已經(jīng)討論了7-bit, 8bit和UCS2這幾種PDU用戶信息的編碼方式,并且給出了實(shí)現(xiàn)代碼。現(xiàn)在,重點(diǎn)描述PDU全串的
23、編碼和解碼過程,以與GSM 07.05的AT命令實(shí)現(xiàn)方法。這些是底層的核心代碼,為了保證代碼的可移植性,我們盡可能不用MFC的類,必要時(shí)用ANSI C標(biāo)準(zhǔn)庫函數(shù)。首先,定義如下常量和結(jié)構(gòu):/ 用戶信息編碼方式#define GSM_7BIT 0#define GSM_8BIT 4#define GSM_UCS2 8/ 短消息參數(shù)結(jié)構(gòu),編碼/解碼共用/ 其中,字符串以0結(jié)尾typedef struct char SCA16; / 短消息服務(wù)中心(SMSC地址) char TPA16; / 目標(biāo)或回復(fù)(TP-DA或TP-RA) char TP_PID; / 用戶信息協(xié)議標(biāo)識(TP-PID) cha
24、r TP_DCS; / 用戶信息編碼方式(TP-DCS) char TP_SCTS16; / 服務(wù)時(shí)間戳字符串(TP_SCTS), 接收時(shí)用到 char TP_UD161; / 原始用戶信息(編碼前或解碼后的TP-UD) char index; / 短消息序號,在讀取時(shí)用到 SM_PARAM;大家已經(jīng)注意到PDU串中的和時(shí)間,都是兩兩顛倒的字符串。利用下面兩個(gè)函數(shù)可進(jìn)行正反變換:/ 正常順序的字符串轉(zhuǎn)換為兩兩顛倒的字符串,若長度為奇數(shù),補(bǔ)'F'湊成偶數(shù)/ 如:"68" -> "4F8"/ pSrc: 源字符串指針/ pDst: 目標(biāo)
25、字符串指針/ nSrcLength: 源字符串長度/ 返回: 目標(biāo)字符串長度int gsmInvertNumbers(const char* pSrc, char* pDst, int nSrcLength) int nDstLength; / 目標(biāo)字符串長度 char ch; / 用于保存一個(gè)字符 / 復(fù)制串長度 nDstLength = nSrcLength; / 兩兩顛倒 for(int i=0; i<nSrcLength;i+=2) ch = *pSrc+; / 保存先出現(xiàn)的字符 *pDst+ = *pSrc+; / 復(fù)制后出現(xiàn)的字符 *pDst+ = ch; / 復(fù)制先出現(xiàn)的字
26、符 / 源串長度是奇數(shù)嗎? if(nSrcLength & 1) *(pDst-2) = 'F' / 補(bǔ)'F' nDstLength+; / 目標(biāo)串長度加1 / 輸出字符串加個(gè)結(jié)束符 *pDst = '0' / 返回目標(biāo)字符串長度 return nDstLength;/ 兩兩顛倒的字符串轉(zhuǎn)換為正常順序的字符串/ 如:"4F8" -> "68"/ pSrc: 源字符串指針/ pDst: 目標(biāo)字符串指針/ nSrcLength: 源字符串長度/ 返回: 目標(biāo)字符串長度int gsmSerializ
27、eNumbers(const char* pSrc, char* pDst, int nSrcLength) int nDstLength; / 目標(biāo)字符串長度 char ch; / 用于保存一個(gè)字符 / 復(fù)制串長度 nDstLength = nSrcLength; / 兩兩顛倒 for(int i=0; i<nSrcLength;i+=2) ch = *pSrc+; / 保存先出現(xiàn)的字符 *pDst+ = *pSrc+; / 復(fù)制后出現(xiàn)的字符 *pDst+ = ch; / 復(fù)制先出現(xiàn)的字符 / 最后的字符是'F'嗎? if(*(pDst-1) = 'F'
28、) pDst-; nDstLength-; / 目標(biāo)字符串長度減1 / 輸出字符串加個(gè)結(jié)束符 *pDst = '0' / 返回目標(biāo)字符串長度 return nDstLength;以下是PDU全串的編解碼模塊。為簡化編程,有些字段用了固定值。/ PDU編碼,用于編制、發(fā)送短消息/ pSrc: 源PDU參數(shù)指針/ pDst: 目標(biāo)PDU串指針/ 返回: 目標(biāo)PDU串長度int gsmEncodePdu(const SM_PARAM* pSrc, char* pDst) int nLength; / 部用的串長度 int nDstLength; / 目標(biāo)PDU串長度 unsigned
29、 char buf256; / 部用的緩沖區(qū) / SMSC地址信息段 nLength = strlen(pSrc->SCA); / SMSC地址字符串的長度 buf0 = (char)(nLength & 1) = 0 ? nLength : nLength + 1) / 2 + 1; / SMSC地址信息長度 buf1 = 0x91; / 固定: 用國際格式 nDstLength = gsmBytes2String(buf, pDst, 2); / 轉(zhuǎn)換2個(gè)字節(jié)到目標(biāo)PDU串 nDstLength += gsmInvertNumbers(pSrc->SCA, &p
30、DstnDstLength, nLength); / 轉(zhuǎn)換SMSC到目標(biāo)PDU串 / TPDU段基本參數(shù)、目標(biāo)地址等 nLength = strlen(pSrc->TPA); / TP-DA地址字符串的長度 buf0 = 0x11; / 是發(fā)送短信(TP-MTI=01),TP-VP用相對格式(TP-VPF=10) buf1 = 0; / TP-MR=0 buf2 = (char)nLength; / 目標(biāo)地址數(shù)字個(gè)數(shù)(TP-DA地址字符串真實(shí)長度) buf3 = 0x91; / 固定: 用國際格式 nDstLength += gsmBytes2String(buf, &pDstn
31、DstLength, 4); / 轉(zhuǎn)換4個(gè)字節(jié)到目標(biāo)PDU串 nDstLength += gsmInvertNumbers(pSrc->TPA, &pDstnDstLength, nLength); / 轉(zhuǎn)換TP-DA到目標(biāo)PDU串 / TPDU段協(xié)議標(biāo)識、編碼方式、用戶信息等 nLength = strlen(pSrc->TP_UD); / 用戶信息字符串的長度 buf0 = pSrc->TP_PID; / 協(xié)議標(biāo)識(TP-PID) buf1 = pSrc->TP_DCS; / 用戶信息編碼方式(TP-DCS) buf2 = 0; / 有效期(TP-VP)為5
32、分鐘 if(pSrc->TP_DCS = GSM_7BIT) / 7-bit編碼方式 buf3 = nLength; / 編碼前長度 nLength = gsmEncode7bit(pSrc->TP_UD, &buf4, nLength+1) + 4; / 轉(zhuǎn)換TP-DA到目標(biāo)PDU串 else if(pSrc->TP_DCS = GSM_UCS2) / UCS2編碼方式 buf3 = gsmEncodeUcs2(pSrc->TP_UD, &buf4, nLength); / 轉(zhuǎn)換TP-DA到目標(biāo)PDU串 nLength = buf3 + 4; / nL
33、ength等于該段數(shù)據(jù)長度 else / 8-bit編碼方式 buf3 = gsmEncode8bit(pSrc->TP_UD, &buf4, nLength); / 轉(zhuǎn)換TP-DA到目標(biāo)PDU串 nLength = buf3 + 4; / nLength等于該段數(shù)據(jù)長度 nDstLength += gsmBytes2String(buf, &pDstnDstLength, nLength); / 轉(zhuǎn)換該段數(shù)據(jù)到目標(biāo)PDU串 / 返回目標(biāo)字符串長度 return nDstLength;/ PDU解碼,用于接收、閱讀短消息/ pSrc: 源PDU串指針/ pDst: 目標(biāo)P
34、DU參數(shù)指針/ 返回: 用戶信息串長度int gsmDecodePdu(const char* pSrc, SM_PARAM* pDst) int nDstLength; / 目標(biāo)PDU串長度 unsigned char tmp; / 部用的臨時(shí)字節(jié)變量 unsigned char buf256; / 部用的緩沖區(qū) / SMSC地址信息段 gsmString2Bytes(pSrc, &tmp, 2); / 取長度 tmp = (tmp - 1) * 2; / SMSC串長度 pSrc += 4; / 指針后移 gsmSerializeNumbers(pSrc, pDst->SCA
35、, tmp); / 轉(zhuǎn)換SMSC到目標(biāo)PDU串 pSrc += tmp; / 指針后移 / TPDU段基本參數(shù)、回復(fù)地址等 gsmString2Bytes(pSrc, &tmp, 2); / 取基本參數(shù) pSrc += 2; / 指針后移 if(tmp & 0x80) / 包含回復(fù)地址,取回復(fù)地址信息 gsmString2Bytes(pSrc, &tmp, 2); / 取長度 if(tmp & 1) tmp += 1; / 調(diào)整奇偶性 pSrc += 4; / 指針后移 gsmSerializeNumbers(pSrc, pDst->TPA, tmp);
36、/ 取TP-RA pSrc += tmp; / 指針后移 / TPDU段協(xié)議標(biāo)識、編碼方式、用戶信息等 gsmString2Bytes(pSrc, (unsigned char*)&pDst->TP_PID, 2); / 取協(xié)議標(biāo)識(TP-PID) pSrc += 2; / 指針后移 gsmString2Bytes(pSrc, (unsigned char*)&pDst->TP_DCS, 2); / 取編碼方式(TP-DCS) pSrc += 2; / 指針后移 gsmSerializeNumbers(pSrc, pDst->TP_SCTS, 14); / 服
37、務(wù)時(shí)間戳字符串(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); / 格式轉(zhuǎn)換 gsmDecode7bit(buf, pDst->TP_UD, nDstLength); /
38、 轉(zhuǎn)換到TP-DU nDstLength = tmp; else if(pDst->TP_DCS = GSM_UCS2) / UCS2解碼 nDstLength = gsmString2Bytes(pSrc, buf, tmp * 2); / 格式轉(zhuǎn)換 nDstLength = gsmDecodeUcs2(buf, pDst->TP_UD, nDstLength); / 轉(zhuǎn)換到TP-DU else / 8-bit解碼 nDstLength = gsmString2Bytes(pSrc, buf, tmp * 2); / 格式轉(zhuǎn)換 nDstLength = gsmDecode8bit
39、(buf, pDst->TP_UD, nDstLength); / 轉(zhuǎn)換到TP-DU / 返回目標(biāo)字符串長度 return nDstLength;依照GSM 07.05,發(fā)送短消息用AT+CMGS命令,閱讀短消息用AT+CMGR命令,列出短消息用AT+CMGL命令,刪除短消息用AT+CMGD命令。但 AT+CMGL命令能夠讀出所有的短消息,所以我們用它實(shí)現(xiàn)閱讀短消息功能,而沒用AT+CMGR。下面是發(fā)送、讀取和刪除短消息的實(shí)現(xiàn)代碼:/ 發(fā)送短消息/ pSrc: 源PDU參數(shù)指針BOOL gsmSendMessage(const SM_PARAM* pSrc) int nPduLength
40、; / PDU串長度 unsigned char nSmscLength; / SMSC串長度 int nLength; / 串口收到的數(shù)據(jù)長度 char cmd16; / 命令串 char pdu512; / PDU串 char ans128; / 應(yīng)答串 nPduLength = gsmEncodePdu(pSrc, pdu); / 根據(jù)PDU參數(shù),編碼PDU串 strcat(pdu, "x01a"); / 以Ctrl-Z結(jié)束 gsmString2Bytes(pdu, &nSmscLength, 2); / 取PDU串中的SMSC信息長度 nSmscLength
41、+; / 加上長度字節(jié)本身 / 命令中的長度,不包括SMSC信息長度,以數(shù)據(jù)字節(jié)計(jì) sprintf(cmd, "AT+CMGS=%dr", nPduLength / 2 - nSmscLength); / 生成命令 WriteComm(cmd, strlen(cmd); / 先輸出命令串 nLength = ReadComm(ans, 128); / 讀應(yīng)答數(shù)據(jù) / 根據(jù)能否找到"rn> "決定成功與否 if(nLength = 4 && strncmp(ans, "rn> ", 4) = 0) Write
42、Comm(pdu, strlen(pdu); / 得到肯定回答,繼續(xù)輸出PDU串 nLength = ReadComm(ans, 128); / 讀應(yīng)答數(shù)據(jù) / 根據(jù)能否找到"+CMS ERROR"決定成功與否 if(nLength > 0 && strncmp(ans, "+CMS ERROR", 10) != 0) return TRUE; return FALSE;/ 讀取短消息/ 用+CMGL代替+CMGR,可一次性讀出全部短消息/ pMsg: 短消息緩沖區(qū),必須足夠大/ 返回: 短消息條數(shù)int gsmReadMessag
43、e(SM_PARAM* pMsg) int nLength; / 串口收到的數(shù)據(jù)長度 int nMsg; / 短消息計(jì)數(shù)值 char* ptr; / 部用的數(shù)據(jù)指針 char cmd16; / 命令串 char ans1024; / 應(yīng)答串 nMsg = 0; ptr = ans; sprintf(cmd, "AT+CMGLr"); / 生成命令 WriteComm(cmd, strlen(cmd); / 輸出命令串 nLength = ReadComm(ans, 1024); / 讀應(yīng)答數(shù)據(jù) / 根據(jù)能否找到"+CMS ERROR"決定成功與否 if(
44、nLength > 0 && strncmp(ans, "+CMS ERROR", 10) != 0) / 循環(huán)讀取每一條短消息, 以"+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+; / 準(zhǔn)備讀下一條短消息 nMsg+; / 短消息計(jì)數(shù)加1 ret
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 核心聚焦2025年證券從業(yè)資格證考試內(nèi)容試題及答案
- 項(xiàng)目管理創(chuàng)新思維的訓(xùn)練方法試題及答案
- 證券投資實(shí)務(wù)的證券從業(yè)資格證試題及答案
- 2025年券商業(yè)務(wù)拓展策略試題及答案
- 2024年項(xiàng)目管理資格考試的知識點(diǎn)整合試題及答案
- 拆彩鋼瓦房施工方案
- 窯爐基礎(chǔ)工程施工方案
- 礦山作業(yè)工程施工方案
- 銀行從業(yè)資格證模擬考試的試題及答案
- 碘化鉀在農(nóng)業(yè)中的應(yīng)用考核試卷
- 2025-2030中國汽車金融行業(yè)市場深度調(diào)研及發(fā)展策略與投資前景研究報(bào)告
- 2025年鐵路車輛鉗工(高級)職業(yè)技能鑒定參考試題庫(含答案)
- 跨越高原勇敢前行 課件 2025屆高考學(xué)習(xí)的高原期主題班會
- 2025年中國共青團(tuán)入團(tuán)團(tuán)員必知知識考試題與答案
- 2024年鄭州鐵路職業(yè)技術(shù)學(xué)院單招職業(yè)傾向性測試題庫必考題
- 2025年山東省濟(jì)南市平陰縣中考一模英語試題(原卷版+解析版)
- 成人腦室外引流護(hù)理-中華護(hù)理學(xué)會團(tuán)體 標(biāo)準(zhǔn)
- BS EN ISO 15848-1-2015 工業(yè)閥-逸散性排放的測量、試驗(yàn)和鑒定程序(中文)
- 英阿馬島戰(zhàn)爭
- 五金沖壓車間質(zhì)量管理規(guī)范(含表格)
- 病媒生物防制PPT課件
評論
0/150
提交評論