通過串列埠使用AT指令傳送短訊息(下)

2021-06-16 13:52:39 字數 4818 閱讀 8230

q pdu的核心編碼方式已經清楚了,如何實現用at命令收發短訊息呢?

a 在上篇中,我們已經討論了7bit, 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 sm_param;

// 正常順序的字串轉換為兩兩顛倒的字串,若長度為奇數,補''f''湊成偶數

// 如:"8613851872468" --> "683158812764f8"

// psrc: 源字串指標

// pdst: 目標字串指標

// nsrclength: 源字串長度

// 返回: 目標字串長度

int gsminvertnumbers(const char* psrc, char* pdst, int nsrclength)

// 源串長度是奇數嗎?

if (nsrclength & 1)

// 輸出字串加個結束符

*pdst = ''/0'';

// 返回目標字串長度

return ndstlength;}

// 兩兩顛倒的字串轉換為正常順序的字串

// 如:"683158812764f8" --> "8613851872468"

// psrc: 源字串指標

// pdst: 目標字串指標

// nsrclength: 源字串長度

// 返回: 目標字串長度

int gsmserializenumbers(const char* psrc, char* pdst, int nsrclength)

// 最後的字元是''f''嗎?

if (*(pdst-1) == ''f'')

// 輸出字串加個結束符

*pdst = ''/0'';

// 返回目標字串長度

return ndstlength;

}

以下是pdu全串的編譯碼模組。為簡化程式設計,有些欄位用了固定值。

// pdu編碼,用於編制、傳送短訊息

// psrc: 源pdu引數指標

// pdst: 目標pdu串指標

// 返回: 目標pdu串長度

int gsmencodepdu(const sm_param* psrc, char* pdst)

else if (psrc->tp_dcs == gsm_ucs2)

else

ndstlength += gsmbytes2string(buf, &pdst[ndstlength], nlength); // 轉換該段資料到目標pdu串

// 返回目標字串長度

return ndstlength;}

// pdu解碼,用於接收、閱讀短訊息

// psrc: 源pdu串指標

// pdst: 目標pdu引數指標

// 返回: 使用者資訊串長度

int gsmdecodepdu(const char* psrc, sm_param* pdst)

// 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)

else if (pdst->tp_dcs == gsm_ucs2)

else

// 返回目標字串長度

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)

}return false;}

// 讀取短訊息

// 用+cmgl代替+cmgr,可一次性讀出全部短訊息

// pmsg: 短訊息緩衝區,必須足夠大

// 返回: 短訊息條數

int gsmreadmessage(sm_param* pmsg)

}return nmsg;}

// 刪除短訊息

// index: 短訊息序號,從1開始

bool gsmdeletemessage(int index)

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, int nstopbits)

// 關閉串列埠

bool closecomm()

// 寫串列埠

// pdata: 待寫的資料緩衝區指標

// nlength: 待寫的資料長度

void writecomm(void* pdata, int nlength)

// 讀串列埠

// pdata: 待讀的資料緩衝區指標

// nlength: 待讀的最大資料長度

// 返回: 實際讀入的資料長度

int readcomm(void* pdata, int nlength)

q 在用at命令同手機通訊時,需要注意哪些問題?

a 任何乙個at命令發給手機,都可能返回成功或失敗。例如,用at+cmgs命令傳送短訊息時,如果此時正好手機處於振鈴或通話狀態,就會返回乙個"+cms error"。所以,應當在傳送命令後,檢測手機的響應,失敗後重發。而且,因為只有乙個通訊埠,傳送和接收不可能同時進行。

如果串列埠通訊用超時控制的同步(阻塞)模式,一般做法是專門將傳送/接收處理封裝在乙個工作子執行緒內。因為**較多,這裡就不詳細介紹了。所附的demo中,包含了完整的子執行緒和傳送/接收應用程式介面的原始碼。

q 以上at命令,是不是所有廠家的手機都支援?

a etsi gsm 07.05規範直到2023年才形成最終release版本(ver 7.0.1),在這之前及之後一段時間內,不排除各廠商在dte-dce的短訊息at命令有所不同的可能性。我們用到的幾個pdu模式下的at命令,是基本的命令,從原則上講,各廠家的手機以及gsm模組應該都支援,但可能有細微差別。

q 使用者資訊(tp-ud)內除了一般意義上的短訊息,還可以是和聲音資料。關於手機鈴聲和格式方面,有什麼規範嗎?

a 為統一手機鈴聲、格式,motorola和ericsson, siemens, alcatel等共同開發了ems(enhanced messaging service)標準,並於2023年2月份公布。這些廠商格式相同。但另一手機巨頭nokia未參加標準的制定,手機鈴聲、格式與它們不同。所以沒有形成統一的規範。ems其實並沒有超越gsm 07.05,只是tp-ud資料部分包含一定格式而已。各廠家的手機鈴聲、格式資料,可以查閱相關**。

q 使用者資訊(tp-ud)其實可以是任何的自定義資料,是嗎?

a 是的,儘管手機上會顯示亂碼。這種情況下,編碼方式已經沒有任何意義。但注意仍然要遵守規範。比如,若指定7-bit編碼方式,tp-udl應等於實際資料長度的8/7(用進一法,而不是四捨五入)。在利用sms進行點對點或多點對一點的資料通訊的應用中,可以傳輸各種自定義資料,如gps資訊,環境監測資訊,加密的個人資訊,等等。

如果在傳輸自定義資料的同時還要收發普通短訊息,最簡單的辦法是在資料前面額外加個識別標誌,比如"ffff",以區分自定義資料和普通短訊息。

通過串列埠收發短訊息 下

原文出處 http www.kernelstudio.com getitem.asp?id 14 q pdu的核心編碼方式已經清楚了,如何實現用at命令收發短訊息呢?a 在上篇中,我們已經討論了7bit,8bit和ucs2這幾種pdu使用者資訊的編碼方式,並且給出了實現 現在,重點描述pdu全串的編...

通過串列埠收發短訊息 下

qpdu的核心編碼方式已經清楚了,如何實現用at命令收發短訊息呢?a在上篇中,我們已經討論了7 bit,8bit和ucs2這幾種pdu使用者資訊的編碼方式,並且給出了實現 現在,重點描述pdu全串的編碼和解碼過程,以及g 07.05的at命令實現方法。這些是底層的核心 為了保證 的可移植性,我們盡可...

通過串列埠收發短訊息 下

q pdu的核心編碼方式已經清楚了,如何實現用at命令收發短訊息呢?a 在上篇中,我們已經討論了7bit,8bit和ucs2這幾種pdu使用者資訊的編碼方式,並且給出了實現 現在,重點描述pdu全串的編碼和解碼過程,以及gsm 07.05的at命令實現方法。這些是底層的核心 為了保證 的可移植性,我...