摘要:在介紹SMS無線數(shù)據(jù)傳輸與MC35i模塊的基礎(chǔ)上,解析SMS無線數(shù)據(jù)傳輸格式,采用標(biāo)準(zhǔn)C語言實(shí)現(xiàn)。結(jié)果表明采用C語言實(shí)現(xiàn)的基于MC35i模塊實(shí)現(xiàn)電表的集中監(jiān)測系統(tǒng)具有系統(tǒng)結(jié)構(gòu)明晰、成本低、性能可靠等優(yōu)點(diǎn),適合于在近似領(lǐng)域推廣使用。
關(guān)鍵詞:SMS;無線監(jiān)測;MC35i
中圖分類號:TP393 文獻(xiàn)標(biāo)示碼:A文章編號:1009-3044(2009)36-10594-03
The Design and Implement of the Wireless MM System Based on the MC35i Module
CHEN Jun1, CHEN Lin2, WU Wen-ping2
(1.Xinjiang Branch of Armed Police, Urumqi 830063, China; 2.Unit 69046, Urumqi 830001, China)
Abstract: The format of the SMS wireless data transport is explained with the C language based on the introduction of the wireless Data transport and MC35i module. The result is reached that the centralized MM system with the C language based on the the MC35i module has the advantages of clear system structure, low expensive, high stability and so on. The system can be used on similar areas.
Key words: SMS; Wireless MM; MC35i
1 概述
本模塊采用MC35i通過RS-232接口實(shí)現(xiàn),數(shù)據(jù)傳輸上采用SMS方式進(jìn)行。
SMS是由ESTI制定的一個規(guī)范,在收發(fā)短信上,按照時間先后有三種模式:Block模式、Text模式、PDU模式。在我國由于需要支持中文,基本都采用PDU模式。PDU模式使用三種編碼,分別是7bit、8bit、16bit。16bit編碼也叫UCS2編碼或Unicode編碼,要支持中文必須用UCS2編碼方式,最多一次可發(fā)送70字符。
2 SMS數(shù)據(jù)格式解析
以一組收發(fā)數(shù)據(jù)為例,介紹SMS數(shù)據(jù)格式。
假設(shè)要發(fā)送“你好”到手機(jī)“13812345678”,發(fā)送的PDU數(shù)據(jù)串為:08 91 683108701305F0 11 00 0D 91 683118325476F8 00 08 00 04 4F60597D。其數(shù)據(jù)格式解析如下:
08:短消息服務(wù)中心地址長度,8個字節(jié)。
91:短消息服務(wù)中心號碼類型。
683108701305F0:短消息服務(wù)中心號碼,8613800731500。
11:文件頭部。
00:信息參考。
0D:被叫號碼長度13位。
91:被叫號碼類型。
683118325476F8:被叫號碼8613812345678。
00:協(xié)議標(biāo)示。
08:數(shù)據(jù)編碼方案。
00:有效期。
04:用戶數(shù)據(jù)長度。
4F60597D:用戶數(shù)據(jù)“你好”的Unicode編碼。
假設(shè)接收到一組PDU串,08 91 683108701305F0 24 0B A1 3118325476F8 00 08 50303211509220 04 4F60597D。分析如下:
08:短消息服務(wù)中心地址長度,8個字節(jié)。
91:短消息服務(wù)中心號碼類型。
683108701305F0:短消息服務(wù)中心號碼8613800731500。
24:文件頭字節(jié)。
0B:被叫號碼長度,11位。
A1:被叫號碼類型。
3118325476F8:被叫號碼13812345678。
00:協(xié)議標(biāo)示。
08:數(shù)據(jù)編碼方案。
50303211509220:時間戳。
04:用戶數(shù)據(jù)長度。
4F60597D:用戶數(shù)據(jù)“你好”的Unicode編碼。
3 SMS編程實(shí)現(xiàn)
SMS信息必須經(jīng)過字符到字節(jié)以及其相反的轉(zhuǎn)換。其轉(zhuǎn)換函數(shù)為:int gsmString2Bytes(const char* pSrc,unsigned char* pDst,int nSrcLength),pSrc為源字符串指針,nSrcLength源字符串長度,pDst為目標(biāo)數(shù)據(jù)指針;int gsmBytes2String(const unsigned char* pSrc,char* pDst,int nSrcLength),pSrc為源數(shù)據(jù)指針,nSrcLength源數(shù)據(jù)長度,pDst為目標(biāo)字符串指針。代碼略。
UCS2編碼函數(shù)gsmEncodeUcs2(const char* pSrc, unsigned char* pDst, int nSrcLength)和UCS2解碼函數(shù)int gsmDecodeUcs2(const unsigned char* pSrc, char* pDst, int nSrcLength)部分代碼如下所示:
UCS2編碼,輸入:pSrc - 源字符串指針,nSrcLength - 源字符串長度,輸出:pDst - 目標(biāo)編碼串指針,返回:目標(biāo)編碼串長度
int gsmEncodeUcs2(const char* pSrc, unsigned char* pDst, int nSrcLength)
{int nDstLength;// UNICODE寬字符數(shù)目
WCHAR wchar[128];// UNICODE串緩沖區(qū)
// 字符串-->UNICODE串
nDstLength = MultiByteToWideChar(CP_ACP, 0, pSrc, nSrcLength, wchar, 128);
// 高低字節(jié)對調(diào),輸出
for(int i=0; i {*pDst++ = wchar[i] >> 8;// 先輸出高位字節(jié) *pDst++ = wchar[i] 0xff;// 后輸出低位字節(jié) } // 返回目標(biāo)編碼串長度 return nDstLength * 2; } UCS2解碼,輸入:pSrc - 源編碼串指針,nSrcLength -源編碼串長度,輸出:pDst -目標(biāo)字符串指針,返回:目標(biāo)字符串長度 int gsmDecodeUcs2(const unsigned char* pSrc, char* pDst, int nSrcLength) {int nDstLength;// UNICODE寬字符數(shù)目 WCHAR wchar[128];// UNICODE串緩沖區(qū) // 高低字節(jié)對調(diào),拼成UNICODE for(int i=0; i {wchar[i] = *pSrc++ << 8;// 先高位字節(jié) wchar[i] |= *pSrc++;// 后低位字節(jié) } // UNICODE串-->字符串 nDstLength = WideCharToMultiByte(CP_ACP, 0, wchar, nSrcLength/2, pDst, 160, NULL, NULL); // 輸出字符串加個結(jié)束符 pDst[nDstLength] = '\\0'; // 返回目標(biāo)字符串長度 return nDstLength; } 在PDU編碼解碼函數(shù)中,還要用到如下數(shù)據(jù)順序轉(zhuǎn)換函數(shù):1、正常順序的字符串轉(zhuǎn)換為兩兩顛倒的字符串,若長度為奇數(shù),補(bǔ)'F'湊成偶數(shù)。輸入:pSrc - 源字符串指針,nSrcLength - 源字符串長度,輸出:pDst - 目標(biāo)字符串指針,返回:目標(biāo)字符串長度,int gsmInvertNumbers(const char* pSrc, char* pDst, int nSrcLength)。2、兩兩顛倒的字符串轉(zhuǎn)換為正常順序的字符串,輸入: pSrc - 源字符串指針, nSrcLength - 源字符串長度,輸出:pDst - 目標(biāo)字符串指針,返回:目標(biāo)字符串長度,int gsmSerializeNumbers(const char* pSrc, char* pDst, int nSrcLength)。 PDU編碼,用于編制、發(fā)送短消息,輸入:pSrc - 源PDU參數(shù)指針,輸出:pDst - 目標(biāo)PDU串指針,返回:目標(biāo)PDU串長度 int gsmEncodePdu(const SM_PARAM* pSrc, char* pDst) {int nLength;// 內(nèi)部用的串長度 int nDstLength;// 目標(biāo)PDU串長度 unsigned char buf[256];// 內(nèi)部用的緩沖區(qū) // SMSC地址信息段 nLength = strlen(pSrc->SCA);// SMSC地址字符串的長度 buf[0] = (char)((nLength 1) == 0 ? nLength : nLength + 1) / 2 + 1;//SMSC地址信息長度 buf[1] = 0x91;// 固定: 用國際格式號碼 nDstLength = gsmBytes2String(buf, pDst, 2);// 轉(zhuǎn)換2個字節(jié)到目標(biāo)PDU串 nDstLength += gsmInvertNumbers(pSrc->SCA, pDst[nDstLength], nLength);// 轉(zhuǎn)換SMSC號碼到目標(biāo)PDU串 // TPDU段基本參數(shù)、目標(biāo)地址等 nLength = strlen(pSrc->TPA);// TP-DA地址字符串的長度 buf[0] = 0x11;// 是發(fā)送短信(TP-MTI=01),TP-VP用相對格式(TP-VPF=10) buf[1] = 0;// TP-MR=0 buf[2] = (char)nLength; // 目標(biāo)地址數(shù)字個數(shù)(TP-DA地址字符串真實(shí)長度) buf[3] = 0x91;// 固定: 用國際格式號碼 nDstLength += gsmBytes2String(buf, pDst[nDstLength], 4);//轉(zhuǎn)換4字節(jié)到目標(biāo)PDU串 nDstLength += gsmInvertNumbers(pSrc->TPA, pDst[nDstLength], nLength); //轉(zhuǎn)換TP-DA到目標(biāo)PDU串 // TPDU段協(xié)議標(biāo)識、編碼方式、用戶信息等 nLength = strlen(pSrc->TP_UD);// 用戶信息字符串的長度 buf[0] = pSrc->TP_PID;// 協(xié)議標(biāo)識(TP-PID) buf[1] = pSrc->TP_DCS;// 用戶信息編碼方式(TP-DCS) buf[2] = 0;// 有效期(TP-VP)為5分鐘 // UCS2編碼方式 buf[3] = gsmEncodeUcs2(pSrc->TP_UD, buf[4], nLength); // 轉(zhuǎn)換TP-DA到目標(biāo)PDU串 nLength = buf[3] + 4;// nLength等于該段數(shù)據(jù)長度 nDstLength += gsmBytes2String(buf, pDst[nDstLength], nLength); // 轉(zhuǎn)換該段數(shù)據(jù)到目標(biāo)PDU串 // 返回目標(biāo)字符串長度 return nDstLength; } PDU解碼,用于接收、閱讀短消息,輸入:pSrc - 源PDU串指針,輸出: pDst - 目標(biāo)PDU參數(shù)指針,返回:用戶信息串長度。 int gsmDecodePdu(const char* pSrc, SM_PARAM* pDst) {int nDstLength;// 目標(biāo)PDU串長度 unsigned char tmp;// 內(nèi)部用的臨時字節(jié)變量 unsigned char buf[256];// 內(nèi)部用的緩沖區(qū) // SMSC地址信息段 gsmString2Bytes(pSrc, tmp, 2);// 取長度 tmp = (tmp - 1) * 2;// SMSC號碼串長度 pSrc += 4;// 指針后移,忽略了SMSC地址格式 gsmSerializeNumbers(pSrc, pDst->SCA, tmp);// 轉(zhuǎn)換SMSC號碼到目標(biāo)PDU串 pSrc += tmp;// 指針后移 // TPDU段基本參數(shù) gsmString2Bytes(pSrc, tmp, 2);// 取基本參數(shù) pSrc += 2;// 指針后移 // 取回復(fù)號碼 gsmString2Bytes(pSrc, tmp, 2);// 取長度 if(tmp 1) tmp += 1;// 調(diào)整奇偶性 pSrc += 4;// 指針后移,忽略了回復(fù)地址(TP-RA)格式 gsmSerializeNumbers(pSrc, pDst->TPA, tmp);// 取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);// 服務(wù)時間戳字符串(TP_SCTS) pSrc += 14;// 指針后移 gsmString2Bytes(pSrc, tmp, 2);// 用戶信息長度(TP-UDL) pSrc += 2;// 指針后移 // UCS2解碼 nDstLength = gsmString2Bytes(pSrc, buf, tmp * 2);// 格式轉(zhuǎn)換 nDstLength = gsmDecodeUcs2(buf, pDst->TP_UD, nDstLength);// 轉(zhuǎn)換到TP-DU // 返回目標(biāo)字符串長度 return nDstLength; } 整體程序的編制就是調(diào)用以上函數(shù),從而實(shí)現(xiàn)讀取顯示SMS信息和發(fā)送SMS信息的功能。 4 結(jié)論 該程序在電表遠(yuǎn)程監(jiān)測應(yīng)用,功能基本完善,性能可靠,由于程序采用標(biāo)準(zhǔn)C語言實(shí)現(xiàn),可以不用改變移植到嵌入式系統(tǒng)使用,具有很好的通用性。 參考文獻(xiàn): [1] 高守傳,聶云銘,鄭靜.Visual C++開發(fā)指南[M].北京:人民郵電出版社,2007. [2] 胡志坤,秦業(yè),鄢鋒.Visual C++通信編程工程實(shí)例精解[M].北京:機(jī)械工業(yè)出版社,2007. [3] 龔建偉,熊光明.Visual C++/Turbo C 串口通信編程實(shí)踐[M].2版.北京:電子工業(yè)出版社,2007. [4] 賽奎春,高春艷,李俊民.Visual Basic 工程應(yīng)用與項(xiàng)目實(shí)踐[M].北京:機(jī)械工業(yè)出版社,2007.