Serial port connection
GSM mobile phone sends and receive short messages, how to program the implementation in the application?
Q We plan to develop a
GSM short message mode
GPS system, how to use
SMS data communication?
A First, we have to
Esti formulated
The SMS specification has aware. The specifications related to the short message transceiver we discussed have mainly include
GSM 03.38,
GSM 03.40 and
GSM 07.05. The top two focused
SMS technology implementation
(Including encoding
), The latter specified
SMS
DTE-DCE interface standard
(AT command set
).
There are three ways to send and receive
SMS information:
Block Mode, Text Mode and
PDU Mode.
Block Mode is already a former yellow flowers, and it is rarely used.
Text Mode is a plain text method that can be used in different character sets, which can also be used to send Chinese short messages, but domestic mobile phones are basically not supported, mainly for Europe and America.
PDU MODE is supported by all mobile phones, you can use any character set, which is also a default encoding method.
Text Mode is relatively simple, and we don't discuss it without custom data transmission. The content introduced below is
Implementation method for transmitting and receiving short messages under PDU MODE.
PDU string is a string
ASCII code, by '
0 '
- '
9', '
A '
- '
F 'these numbers and letters. They are
8-digit hexadecimal number, or
BCD code decimal number.
The PDU string not only contains the displayed message itself, but also contains many other information, such as
SMS service center number, target number, reply number, encoding method, and service time, etc. Send and receive
The PDU string is not exactly the same. We will use two practical examples to explain
The structure and arrangement of the PDU string.
example
1 Send:
SMSC number is
8613800250500, the other party number is
13851872468, message content is "
Hello! ". From the mobile phone
PDU string can be
08 91 68 31 08 205 05 F0 11 00 0D 91 68 31 58 81 27 64 F8 00 00 00 06 C8 32 9B FD 0E 01 control specifications, specific analysis:
Segmentation meaning
08 SMSC address information length
8-eight-bit bytes
(include
91) 91 SMSC address format
(TON / NPI) with international format numbers
(In front add)
'
68 31 08 20 05 05 F0 SMSC address
8613800250500, makeup '
F 'a number of even
11 basic parameters
(TP-MTI / VFP) Send,
TP-VP with relative format
00 message reference value
(TP-MR) 0 0D Target Address Digital Number
13 decimal numbers
(Excluding
91 and '
F '
91 Target Address Format
(TON / NPI) with international format numbers
(In front add)
'
68 31 58 81 27 64 F8 target address
(TP-DA) 8613851872468, supplement
F 'a number of even
00 protocol identification
(TP-PID) is ordinary
GSM type, point-to-point mode
00 user information encoding method
(TP-DCS) 7-bit encoding
00 validity period
(TP-VP) 5 minutes
06 user information length
(TP-UDL) actual length
6 bytes
C8 32 9B FD 0E 01 User Information
(TP-UD) "
Hello! "
example
2 Receive:
SMSC number is
8613800250500, the other party number is
13851872468, message content is "Hello
! ".
PDU string can be
08 91 68 31 08 205 05 F0 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 Control Specifications, Specific Analysis: Segment Meaning Description
08 address information length eight-bit bytes
(include
91) 91 SMSC address format
(TON / NPI) with international format numbers
(In front add)
'
68 31 08 20 05 05 F0 SMSC address
8613800250500, makeup '
F 'a number of even
84 basic parameters
(TP-MTI / MMS / RP) Receive, no more news, there is a reply address
0D replies address number
13 decimal numbers
(Excluding
91 and '
F '
91 Reply Address format
(TON / NPI) with international format numbers
(In front add)
'
68 31 58 81 27 64 F8 Reply Address
(TP-RA) 8613851872468, supplement
F 'a number of even
00 protocol identification
(TP-PID) is ordinary
GSM type, point-to-point mode
08 User Information Coding Method
(TP-DCS) UCS2 encoding
30 30 21 80 63 54 80 Time Stamp
(TP-SCTS) 2003-3-12 08:36:45 8 Time Zone
06 user information length
(TP-UDL) actual length
6 bytes
4F 60 59 7D 00 21 User Information
(TP-UD) "Hello
! "
If the basic parameters are the highest
(TP-RP) is
0, there is no three segments of the address. From
Short messages issued on the Internet are often this situation.
Note that the number and time representation is not in normal order, and
F 'Reduces odd numbers.
Q The above two have appeared
7-bit and
UCS2 encoding, please tell us about these coding methods.
A
In the PDU Mode, three coding methods can be used to encode the seminated content, they are
7-bit,
8-bit and
UCS2 encoding.
7-bit encoding is used to send ordinary
ASCII characters, it will
7-bit character
(The highest bit is
0) encoded
8-bit data, each
8 characters can be "compressed"
7;
8-bit encoding is usually used to send data messages, such as pictures and ringtones, etc.
UCS2 encoding for sending
Unicode characters.
User information of PDU string
(TP-UD) section maximum capacity is
140 bytes, so in these three coding mode, the maximum number of characters that can be sent is
160,
140 and
70. Here, all English letters, one Chinese character and a data byte are viewed as a character.
have to be aware of is,
PDU string user information length
(TP-UDL), which is different in various coding methods.
7-bit encoding, refers to the number of characters of the original short message, not the number of bytes encoded.
8-bit encoding is the number of bytes.
When UCS2 encodes, it is also the number of bytes, equal to twice the number of characters of the original short message. If user information
(TP-UD) There is a head
(Basic parameters
TP-UDHI is
1) In all encoding mode, user information length
(TP-UDL) is equivalent to the sum of the number of the number and the number of bytes of encoding. If used
Compression algorithm recommended by GSM 03.42
(TP-DCS high)
3-bit
001), then the length is also the sum of the byte or head length and the compression encoding after compression encoding.
The following is a specific example
7-bit encoding process. Our English SMS "
Hello! "Code:
Source string each
8 characters are divided into groups
(This example is dissatisfied
8
) Code, compressed between the characters in the group, but there is no connection between each group. use
C realization
7-bit encoding and decoding algorithms are as follows:
// 7-bit encoding
// psrc: Source string pointer
// PDST: Target Code String Pointer
// nsrclength: Source string length
// Return
: Target Code String Length
INT GSMENCODE7bit (const char * psrc, unsigned char * pdst, int nsrclength) {INT nsrc; // source string count value
INT NDST; / / Target Code String Counting Value
INT nchar; // The serial number of the character byte that is currently being processed, the range is
0-7 unsigned char nLEFT; / / Previous byte residual data
/ / Count value initialization
Nsrc = 0; ndst = 0; // Put the source string
8 bytes are divided into groups, compressed into
7 bytes
// Cycle this processing process until the source string is processed
/ / If the packet is not
8 bytes, can also handle properly
While (nsrc 3-bit nchar = nsrc & 7; // Treat a source string for each byte IF (nchar == 0) {// The first byte in the group, just saved, use the next byte to use NLEFT = * psrc;} else {// group other bytes, add the right part to the residual data to get a target coded byte * PDST = (* psrc << (8-nchar)) | NLEFT; // Save the left part of the byte, saved as residual data NLEFT = * psrc >> nchar; // Modify the pointer and count value of the target string PDST ; NDST ;} // Modify the pointer and count value of the source string PSRC ; NSRC ;} // Return to the target string length Return ndst;} // 7-bit decoding // psrc: source code string pointer // PDST: Target string pointer // nsrclength: Source Code String Length // Return : Target string length INT GSMDECode7bit (const unsigned char * psrc, char * pdst, int nsrclength) {int NSRC; // Source string count value INT NDST; / / Target decoding string count value INT NBYTE; / / The number of bytes currently being processed, the range is 0-6 unsigned char nLEFT; / / The last byte residual data / / Count value initialization NSRC = 0; NDST = 0; // Group byte serial number and residual data initialization nbyte = 0; NLEFT = 0; // Put the source data per 7 bytes are divided into groups, unzipped into 8 bytes // Cycle the process, until the source data is processed / / If the packet is not 7 bytes, can also be handled correctly While (nsrc NLEFT = * psrc >> (7-nbyte); / / Modify the pointer and count value of the target string PDST ; NDST ; // Modify byte count value NBYTE ; // to a group of last bytes IF (nbyte == 7) {// extra target decoded byte * PDST = NLEFT; / / Modify the pointer and count value of the target string PDST ; NDST ; // Group byte serial number and residual data initialization NBYTE = 0; NLEFT = 0;} // Modify the pointer and count value of the source string PSRC ; NSRC ;} * pdst = 0; // Return to the target string length Return ndst;} It should be pointed out that 7-bit character set The ANSI standard character set is incomplete, 0x20 The following also arranged some printable characters, but both English letters, Arabic numbers, and common symbols are the same. Use the algorithm described above to send and receive pure English short messages, the general situation should be enough. If it is French, German, Spanish, etc. "," É "characters, then press the output of the above-mentioned output to check the table, see The provisions of GSM 03.38. 8-bit encoding actually does not specify what specific algorithm does not need to be introduced. UCS2 encoding is to put each character (1-2 bytes )according to The provisions of ISO / IEC10646, transition to 16-bit Unicode wide character. in In the Windows system, especially In 2000 / XP, you can simply call The API function implements encoding and decoding. If there is no system support, for example, the mobile module is controlled by the microcontroller to send and receive short messages. In the Windows environment, use C realization The algorithm for UCS2 encoding and decoding is as follows: // UCS2 encoding // psrc: Source string pointer // PDST: Target Code String Pointer // nsrclength: Source string length // Return : Target Code String Length INT GSMENCODEUCS2 (const char * psrc, unsigned char * pdst, int nsrclength) {int NDSTLENGTH; // Unicode wide character number Wchar wchar [128]; // unicode buffer // String -> Unicode string ndstlength = :: MultibyTetowideChar (CP_ACP, 0, PSRC, NSRCLENGTH, WCHAR, 128); // High and low byte calls, output For (int i = 0; i * PDST = Wchar [i] >> 8; // Output low byte * PDST = wchar [i] & 0xff;} // Return to the target coding string length return ndstlength * 2;} // uCS2 decoding // psrc: source code string pointer // PDST: Target string pointer // nsrclength: Source Code String Length // Return : Target string length INT GSMDECodeucs2 (const unsigned char * psrc, char * pdst, int nsrclength) {int NDSTLENGTH; // Unicode wide character number Wchar wchar [128]; // unicode buffer // High and low byte calls, Unicode for (INT i = 0; I Wchar [i] = * psrc << 8; // Lower Laying byte Wchar [i] | = * psrc ;} // unicode string -> String ndstlength = :: widechartomultibyte (CP_ACP, 0, Wchar, NSRCLENGTH / 2, PDST, 160, NULL, NULL); // Output string adds an end conference PDST [NDSTLENGTH] = '/ 0'; // Returns the length of the target string Return NDSTLENGTH; PDU strings need to be formatted, no direct The user information in the PDU string decodes as a short message string because it is still a link to each other between the printable string and byte data. Circular call SSCANF and The Sprintf function implements this transformation. The following is provided with algorithms that do not have these functions, and they also apply to microcontrollers. DSP programming environment. // Printing string to convert to byte data // Such as: "C8329BFD0E01" -> {0xc8, 0x32, 0x9b, 0xfd, 0x0e, 0x01} // psrc: Source string pointer // PDST: Target Data Pointer // nsrclength: Source string length // Return : Target data length INT GSMString2bytes (const char * psrc, unsigned char * pdst, int nsrclength) {for (int i = 0; i 4 bit IF (* psrc> = '0' && * psrc <= '9') {* PDST = (* psrc - '0') << 4;} else {* pdst = (* psrc - 'a' 10) << 4;} psrc ; // low output 4 bit IF (* psrc> = '0' && * psrc <= '9') {* pdst | = * psrc - '0';} else {* pdst | = * psrc - 'a' 10;} PSRC ; PDST ;} // Return to the target data length ReturnNSRCLENGTH / 2;} // byte data Conversion to the printable string // Such as: {0xC8, 0x32, 0x9b, 0xfd, 0x0e, 0x01} -> "c8329bfd0e01" // psrc: source data pointer // PDST: Target string pointer // nsrclength: source data length // Return : Target string length INT GSMBYTES2STRING (Const unsigned char * psrc, char * pdst, int nsrclength) {const char Tab [] = "0123456789abcdef"; // 0x0-0xf character lookup table For (int i = 0; i 4 bit * PDST = Tab [* psrc >> 4]; // output high 4 bit * PDST = Tab [* psrc & 0x0f]; PSRC ;} // Output string adds a end value * PDST = '/ 0'; // Return to the target string length Return nsrclength * 2; The compression algorithm in GSM 03.42 has not found it so far, and we will not discuss this. If you are interested, you can study it in depth. [related resources ] ◆ ETSI official website: http://www.etsi.org ◆ BHW98 column: http://www.9cbs.net/develop/author/netauthor/bhw98/------------------------------ ------------------------------------------------Initial Release : 2003-03-14 Last revision: 2003-03-26 Title Transceive short messages through serial port (under BHW98 (original) Keyword short message Serial port , The core coding method of SMS, PDU, EMS Q PDU has been clear, how to implement The AT command transmits and receives short messages? A in the upper part, we have discussed 7-bit, 8bit and Several UCS2 The encoding mode of the PDU user information is given. Now, key description PDU stronger coding and decoding process, and GSM 07.05 AT command implementation method. These are the core code of the underlying, in order to ensure the transplantability of the code, we don't have to use it as much as possible MFC class, if necessary ANSI C Standard Library Function. First, define the following constants and structures: // User information encoding method #define GSM_7bit 0 # Define GSM_8bit 4 # define GSM_UCS2 8 // Short message parameter structure, encoding / decoding shared // where the string is 0 end Typedef struct {char SCA [16]; // Short Message Service Center Number (SMSC address CHAR TPA [16]; // Target number or reply number (TP-DA or TP-RA) CHAR TP_PID; // User Information Protocol Identification (TP-PID) CHAR TP_DCS; // User Information Coding Method (TP-DCS) Char TP_SCTS [16]; // Service Timestamp String (TP_SCTS), used in reception CHAR TP_UD [161]; // Original user information (After encoding or decoding TP-UD) CHAR INDEX; // Short message number, used in reading } SM_PARAM; everyone has noticed The numbers and time in the PDU string are both two-two strings. Using the following two functions can be positive and reverse transform: / / The normal sequence string is converted to two or two strings, if the length is odd, supplemented 'F' makes an even number // Such as: "8613851872468" -> "683158812764f8" // psrc: Source string pointer // PDST: Target string pointer // nsrclength: Source string length // Return : Target string length INT GSMINVERTNUMBERS (const char * psrc, char * pdst, int nsrclength) {int ndstlength; // target string length Char ch; // Used to save a character // Copy string length ndstlength = nsrclength; // Two two times For (int i = 0; i * PDST = * psrc ; // The character appeared after copying * PDST = ch; // Copy the character appeared first } // Source string length is odd? IF (nsrclength & 1) {* (PDST-2) = 'f'; // 'F' NDSTLENGTH ; // Target string length plus 1} // Output string adds an end conference * PDST = '/ 0'; // Return to the target string length Return NDSTLENGTH;} // Two-two-reversed strings converted to normal sequence // Such as: "683158812764F8" -> "8613851872468" // psrc: Source string pointer // PDST: Target string pointer // nsrclength: Source string length // Return : Target string length INT GSMSERIALIZENUMBERS (const char * psrc, char * pdst, int nsrclength) {int ndstlength; // target string length Char ch; // Used to save a character // Copy string length NdstLength; // two two muttonback FOR (int i = 0; I * PDST = * psrc ; // The character appeared after copying * PDST = ch; // Copy the character appeared first } // The last character is Is 'f'? IF (* (PDST-1) == 'f') {pdst-; ndstlength-; // Target string length reduction 1} // Output string adds an end conference * PDST = '/ 0'; // Return to the target string length Return ndstlength;} The following is PDU stronger codec module. To simplify programming, some fields use a fixed value. // PDU encoding, used to prepare, send short messages // psrc: source PDU parameter pointer // PDST: Target PDU string pointer // Return : aims PDU string length INT GSMENCODEPDU (const SM_PARAM * PSRC, CHAR * PDST) {INT NLENGTH; / / String length Int ndstlength; // target PDU string length Unsigned char buf [256]; // internal buffer // SMSC address information NLENGTH = Strlen (PSRC-> SCA); // SMSC address string length BUF [0] = (char) (NLENGTH & 1) == 0? Nlength: NLENGTH 1) / 2 1; // SMSC address information length BUF [1] = 0x91; // fixed : Use international format numbers Ndstlength = GSMBYTES2STRING (BUF, PDST, 2); // Conversion 2 bytes to goals PDU string NDSTLENGTH = GSMINVERTNUMBERS (PSRC-> SCA, & PDST [NDSTLENGTH], NLENGTH); // Conversion SMSC to goals PDU string // TPDU segment basic parameters, target address, etc. NLENGTH = STRLEN (PSRC-> TPA); // TP-DA address string length BUF [0] = 0x11; // is sending a text message (TP-MTI = 01), TP-VP with relative format (TP-VPF = 10) BUF [1] = 0; // TP-MR = 0 BUF [2] = (char) NLENGTH; // Target Address Digital Number (TP-DA address string real length BUF [3] = 0x91; // fixed : Use international format numbers NDSTLENGTH = GSMBYTES2STRING (BUF, & PDSTLENGTH], 4); // Conversion 4 bytes to goals PDU string NDSTLENGTH = GSMINVERTNUMBERS (PSRC-> TPA, & PDST [NDSTLENGTH], NLENGTH); // Conversion TP-DA to the target PDU string // TPDU segment protocol identification, encoding method, user information, etc. NLENGTH = Strlen (PSRC-> tp_UD); // User information string length BUF [0] = PSRC-> TP_PID; // Protocol Identification (TP-PID) BUF [1] = psrc-> tp_dcs; // User information encoding method (TP-DCS) BUF [2] = 0; // Validity (TP-VP) 5 minutes IF (PSRC-> TP_DCS == GSM_7bit) {// 7-bit encoding method BUF [3] = NLENGTH; / / The length of the coding NLENGTH = GSMENCODE7BIT (PSRC-> TP_UD, & BUF [4], NLENGTH 1) 4; // Conversion TP-DA to the target PDU string } Else if (psrc-> tp_dcs == gsm_ucs2) {// ucs2 encoding method BUF [3] = GSMENCODEUCS2 (PSRC-> TP_UD, & BUF [4], NLENGTH); // Conversion TP-DA to the target PDU string NLENGTH = BUF [3] 4; // Nlength is equal to this segment data length } Else {// 8-bit encoding method BUF [3] = gsmencode8bit (psrc-> tp_ud, & buf [4], nlength); // conversion TP-DA to the target PDU string NLENGTH = BUF [3] 4; // Nlength is equal to this segment data length } Ndstlength = gsmbytes2string (buf, & pdst [ndstlength], nlength); // Convert this data to the target PDU string / / Return to the target string length Return ndstlength;} // PDU decoding for receiving, reading short messages // psrc: source PDU string pointer // PDST: Target PDU parameter pointer // Return : User information string length INT GSMDECodEpdu (const char * psrc, sm_param * pdst) {int NDstlength; // Target PDU string length Unsigned char TMP; // Interim byte variable Unsigned char buf [256]; // internal buffer // SMSC address information GSMString2bytes (PSRC, & TMP, 2); // Take the length TMP = (TMP - 1) * 2; // SMSC number string length PSRC = 4; // Remove the pointer GSMSerializenumBers (PSRC, PDST-> SCA, TMP); // Conversion SMSC number to the target PDU string PSRC = TMP; / / Movement // TPDU segment basic parameters, reply address, etc. GSMSTRING2BYTES (PSRC, & TMP, 2); // Take basic parameters PSRC = 2; // Remove the pointer IF (TMP & 0x80) {// contains a reply address, retrieved the address information GSMString2bytes (PSRC, & TMP, 2); // Take the length IF (TMP & 1) TMP = 1; // Adjust parity PSRC = 4; // Move after the pointer GSMSerializenumBers (PSRC, PDST-> TPA, TMP); // Take TP-RA number PSRC = TMP; / / Movement } // TPDU segment protocol identification, encoding method, user information, etc. GSMSTRING2BYTES (PSRC, (unsigned char *) & pdst-> tp_pid, 2); // Take the protocol identification (TP-PID) PSRC = 2; // Remove the pointer GSMSTRING2BYTES (PSRC, (unsigned char *) & pdst-> tp_dcs, 2); // Take the encoding method (TP-DCS) PSRC = 2; // Remove the pointer GSMSerializenumBers (PSRC, PDST-> TP_SCTS, 14); // Service Timestamp String (TP_SCTS) PSRC = 14; // Remove the pointer GSMSTRING2BYTES (PSRC, & TMP, 2); // User Information Length (TP-UDL) PSRC = 2; // Remove the pointer IF (PDST-> TP_DCS == GSM_7bit) {// 7-bit decoding NDSTLENGTH = GSMSTRING2BYTES (PSRC, BUF, TMP & 7? (int) TMP * 7/4 2: (int) TMP * 7/4); // Format Conversion GSmdecode7bit (buf, pdst-> tp_ud, ndstlength); // Convert to TP-du ndstlength = TMP;} else if (pdst-> tp_dcs == GSM_UCS2) {// ucs2 decoding ndstlength = GSMString2bytes (PSRC, BUF, TMP * 2); // Format Conversion ndstlength = GSMDecodeucs2 (BUF, PDST-> TP_UD, NDSTLENGTH); // Convert to TP-DU} else {// 8-bit decoding ndstlength = GSMString2bytes (PSRC, BUF, TMP * 2); // Format Conversion ndstlength = GSmDecode8bit (buf, pdst-> tp_ud, ndstlength); // Convert to TP-DU} // Returns the length of the target string Return ndstlength;} GSM 07.05, send short messages AT cmgs command, read short message AT cmgr command, list short messages AT cmgl command, delete short messages AT cmgd command. but The AT cmgl command can read all short messages, so we use it to read short message function, but useless AT CMGR. Here is the implementation code for sending, reading, and deleting short messages: // Send a short message // psrc: source PDU parameter pointer Bool GsmsendMessage (const sm_param * psrc) {int npduLength; // PDU string length Unsigned char nsmsclength; // SMSC string length INT NLENGTH; / / The data length received by the serial port Char cmd [16]; // Command string CHAR PDU [512]; // PDU string CHAR ANS [128]; // Answering NpduLength = Gsmencodepdu (PSRC, PDU); // PDU parameters, encoding PDU string STRCAT (PDU, "/ X01A"); // Ctrl-z end GSMSTRING2BYTES (PDU, & nsmsclength, 2); // Take PDU string SMSC information length NSMSCLENGTH ; // plus the length byte itself // The length in the command does not include SMSC information length, data byte count Sprintf (CMD, "AT CMGS =% D / R", NPDulength / 2 - nsmsClength; // Generate Commands WriteComm (CMD, Strlen (CMD)); // Pre-output command string NLENGTH = Readcomm (ANS, 128); // Read answering data / / If you can find it "/ r / n>" decided to success or not IF (NLENGTH == 4 && Strncmp (ANS, "/ R / N>", 4) == 0) {WriteComm (PDU, Strlen (PDU)); // Get affirmative answer, continue to output PDU string NLENGTH = Readcomm (ANS, 128); // Read answering data / / If you can find it " CMS Error" decided to success or not IF (NLENGTH> 0 && Strncmp (ANS, " CMS Error", 10)! = 0) {Return True;}} Return False;} // Read short messages // use Cmgl instead CMGR, read all short messages in one time // PMSG: Short message buffer must be large enough // Return : Short message INT GSMREADMESSAGE (SM_PARAM * PMSG) {INT NLENGTH; / / The data length received in serial port INT NMSG; // short message count value CHAR * PTR; / / internal data pointer Char cmd [16]; // Command string CHAR ANS [1024]; // Answering NMSG = 0; PTR = ANS; Sprintf (cmd, "at cmgl / r"); // Generate Commands WriteComm (CMD, Strlen (CMD)); // Output Command String NLENGTH = Readcomm (ANS, 1024); // Read answer data / / If you can find it " CMS Error" decided to success or not IF (NLENGTH> 0 && Strncmp (ANS, " CMS ERROR", 10)! = 0) {// Loop reads each short message, " Cmgl:" While (ptr = strstr (PTR, " cmgl:"))! = null) {PTR = 6; // Skip " Cmgl:" SSCANF (PTR, "% D", & PMSG-> index); // Read the serial number Trace ("index =% d / n", pmsg-> index); PTR = strstr (PTR, "/ r / n"); // Look for a row PTR = 2; // Skip "/ r / n" gsmdecodepdu (PTR, PMSG); // PDU string PMSG ; // Prepare to read a short message NMSG ; // short message count 1}} return nmsg;} // Delete short message // Index: short message number, from 1 start Bool gsmdeleteMessage (const INDEX) {INT NLENGTH; / / Serial port received Char cmd [16]; // Command string CHAR ANS [128]; // Answering Sprintf (CMD, "AT CMGD =% D / R", INDEX); // Generate Commands / / Output command string WriteComm (cmd, strlen (cmd)); // read answering data NLENGTH = Readcomm (ANS, 128); // According to whether it can find " CMS Error" decided to success or not IF (NLENGTH> 0 && Strncmp (ANS, " CMS ERROR", 10)! = 0) {Return True;} Return False;} The AT command is used during the process. WriteComm and The READCOMM function, which is used to read and write serial ports, depending on the specific operating system. in In addition to using the Windows environment Mscomm control, as well as some ready-made serial communication classes, you can also simply call some Windows API is implemented. The following is the use The main code implemented by the API, pay attention to the synchronization of timeout control (block )mode. // Serial port equipment handle Handle hcomm; // Open the serial port // pport: serial port name or device path, available "COM1" or "//./Com1" two ways, it is recommended to use the latter // nbaudrate: baud rate // nparity: parity // NBYTESIZE: Data byte width // nstopbits: Stop bit Bool OpenComm (Const Char * Pport, Int NbaudRate, Int nstopbits) {DCB DCB; / / Serial Pit Control Block CommTIMEOUTS TIMEOUTS = {// Serial port timeout control parameter 100, // read character interval timeout time : 100 ms 1, // read the time of each character : 1 ms (n characters N ms) 500, // Basic (additional Read time : 500 ms 1, // Time for each character during writing : 1 ms (n characters N ms) 100}; // Basic (additional Wait timeout : 100 ms hcomm = createfile (pport, // serial port name or device path Generic_read | generic_write, // Read and write 0, // Sharing method: exclusive NULL, / / Default security descriptor Open_existing, // creation method 0, // Do not set file properties NULL); // Do not need to refer to the template file IF (hcomm == invalid_handle_value) return false; // Open serial port failed Getcommstate (hcomm, & dcb); // DCB dcb.baudrate = nbaudrate; dcb.bytesize = nbytesize; dcb.parity = nParity; dcb.stopbits = nstopbits; setcommstate (hcomm, & dcb); // Setting DCB SetupComm (HCOMM, 4096, 1024); // Setting the input and output buffer size Setcommtimeouts (hcomm, & timeouts); // Set timeout Return True;} // Close the serial port Bool Closecomm () {Return CloseHandle (HCOMM);} // Write serial port // PDATA: Data buffer pointer to be written // Nlength: The data length to be written Void WriteComm (void * pdata, int NLENGTH) {DWORD DWNUMWRITE; / / The data length issued by the serial port Writefile (HCOMM, PDATA, (DWORD) NLENGTH, & DWNUMWRITE, NULL);} // Read Serial Port // PDATA: The data buffer pointer to be read // Nlength: The maximum data length to be read // Return : Data length read in INT Readcomm (void * pdata, int nlength) {dWord dwnumread; // Series received data length Readfile (HCOMM, PDATA, (DWORD) NLENGTH, & DWNUMREAD, NULL; RETURN (Int) dwnumread;} q What questions do you need to pay attention to when communicating with your mobile phone? Annection The AT command is sent to the phone, it may return success or fail. For example, use When the at cmgs command sends a short message, if it is just that the phone is ringing or talking, it will return one. " CMS Error". Therefore, after sending the command, the response of the phone should be detected, and then reissue after failure. Moreover, since only one communication port, transmission and reception cannot be performed simultaneously. If the serial port communication timeout control synchronization (blocking ) Mode, general practice is specially sent / Receive processing package in a work subline. Because there are more code, it will not be detailed here. Attached In Demo, a complete sub-thread and send / Receive the source code of the application interface. Q Is the AT command not to support all manufacturers? A ETSI GSM 07.05 specification until 1998 is finally formed RELEASE version (Ver 7.0.1), before and after, it does not rule out the manufacturers DTE-DCE short message The AT command has different possibilities. Several we use PDU mode The AT command is the basic command, from the principle, the mobile phone and The GSM module should be supported, but there may be fine differences. Q user information (TP-UD) In addition to short messages in the general sense, it can also be pictures and sound data. What are the norms about the phone ringtones and pictures formats? A is a unified ringtone, picture format, Motorola and Ericsson, Siemens, Alcatel, etc. EMS (Enhanced Messaging Service) standard, and year 2002 Announced in February. These manufacturers have the same format. But another mobile phone giant NOKIA did not participate in standard development, ringtones, and picture formats. So there is no unified specification. EMS is actually do not transcend GSM 07.05, just The TP-UD data section contains a certain format. The phone ringtones, picture format of each manufacturer can check the relevant website. Q user information (TP-UD) Can actually be any custom data, is it? A Yes, although there will be garbled on the phone. In this case, there is no meaning of the encoding method. But pay attention to still have to comply with the specification. For example, if specified 7-bit encoding method, TP-UDL should be equal to the actual data length 8/7 (with the letter, not the four ). Use SMS can transmit a variety of custom data in the application of point or multi-point to a point or more, such as GPS information, environmental monitoring information, encrypted personal information, etc. If you want to send a normal short message while transmitting custom data, the easiest way is to add an identification sign in front of the data, such as "Ffff" to distinguish custom data and normal short messages. The core coding method of Q PDU has been clear. How do I implement short messages with the AT command? A In the above, we have discussed the encoding mode of the 7-bit, 8bit, and ucs2, and give the code. Now, focus on the PDU stroner coding and decoding process, and the AT command implementation method for GSM 07.05. These are the core code of the underlying, in order to ensure the portability of the code, we don't have to use the MFC class as much as possible, use ANSI C standard library functions. First, define the following constants and structures: // User information encoding method #define GSM_7bit 0 #define GSM_8bit 4 #define GSM_UCS2 8 // Short message parameter structure, encoding / decoding shared // where the string ends in 0 Typedef struct { Char SCA [16]; // Short Message Service Center Number (SMSC Address) CHAR TPA [16]; // Target number or reply number (TP-DA or TP-RA) Char TP_PID; // User Information Protocol Identifier (TP-PID) CHAR TP_DCS; // User Information Coding Method (TP-DCS) Char tp_scts [16]; // Service time stamp string (TP_SCTS), used in reception CHAR TP_UD [161]; / / Original user information (TP-UD before code or decoding) CHAR INDEX; // Short message number, used in reading } SM_PARAM; Everyone has noticed the number and time in the PDU string, both two-two strings. The following two functions can be positive and reverse transform: // The normal sequence string is converted to two two-reversed strings. If the length is odd, then add 'F' to even // such as "8613851872468" -> "683158812764f8" // psrc: Source string pointer // PDST: Target string pointer // nsrclength: Source string length // Return: Target String Length INT GSMINVERTNUMBERS (Const Char * PSRC, Char * PDST, INT NSRCLENGTH) { INT NDSTLENGTH; / / Target String Length Char ch; // Used to save a character // Copy string length Ndstlength = nsrclength; // Two two times For (int i = 0; i { CH = * psrc ; // Save the first character appearing first * PDST = * psrc ; // The character appeared after copying * PDST = ch; // Copy the character appeared first } // Source string length is odd? IF (Nsrclength & 1) { * (PDST-2) = 'f'; // 补 'f' NDSTLENGTH ; // Target string length plus 1 } // Output string adds an end conference * PDST = '/ 0'; / / Return to the target string length Return ndstlength; } // Two-two strings are converted to a normal sequential string // 如: "683158812764f8" -> "8613851872468" // psrc: Source string pointer // PDST: Target string pointer // nsrclength: Source string length // Return: Target String Length INT GSMSERIALIZENUMBERS (Const Char * PSRC, Char * PDST, INT NSRCLENGTH) { INT NDSTLENGTH; / / Target String Length Char ch; // Used to save a character // Copy string length Ndstlength = nsrclength; // Two two times For (int i = 0; i { CH = * psrc ; // Save the first character appearing first * PDST = * psrc ; // The character appeared after copying * PDST = ch; // Copy the character appeared first } // The last character is 'f'? IF (* (PDST-1) == 'f') { PDST -; ndstlength -; // Target string length minus 1 } // Output string adds an end conference * PDST = '/ 0'; / / Return to the target string length Return ndstlength;} The following is a full string of PDUs. To simplify programming, some fields use a fixed value. // PDU encoding, used to prepare, send short messages // psrc: Source PDU parameter pointer // PDST: Target PDU string pointer // Return: Target PDU Strings Length INT GSMENCODEPDU (Const Sm_Param * Psrc, Char * PDST) { INT NLENGTH; / / String length INT NDSTLENGTH; / / Target PDU String Length Unsigned char buf [256]; // internal buffer // SMSC address information NLENGTH = Strlen (PSRC-> SCA); // SMSC address string length BUF [0] = (char) (NLENGTH & 1) == 0? Nlength: NLENGTH 1) / 2 1; // SMSC address information length BUF [1] = 0x91; // Fixed: with international format numbers NdstLength = GSMBytes2String (buf, pdst, 2); // Convert 2 bytes to the target PDU string NDSTLENGTH = GSMINVERTNUMBERS (PSRC-> SCA, & PDST [NDSTLENGTH], NLENGTH); // Convert SMSC to Target PDU Strings // TPDU segment basic parameters, target address, etc. NLENGTH = STRLEN (PSRC-> TPA); // TP-DA address string length BUF [0] = 0x11; // Yes Send SMS (TP-MTI = 01), TP-VP with relative format (TP-VPF = 10) BUF [1] = 0; // TP-MR = 0 BUF [2] = (char) NLENGTH; / / Target Address Digital Number (TP-DA Address String Real length) BUF [3] = 0x91; // Fixed: with international format numbers NDSTLENGTH = GSMBYTES2STRING (BUF, & PDSTLENGTH], 4); // Convert 4 bytes to the target PDU string NDSTLENGTH = GSMINVERTNUMBERS (PSRC-> TPA, & PDST [NDSTLENGTH], NLENGTH); // Convert TP-DA to the target PDU string // TPDU segment protocol identification, encoding method, user information, etc. NLENGTH = Strlen (PSRC-> TP_UD); // The length of the user information string BUF [0] = PSRC-> TP_PID; // Protocol Identification (TP-PID) BUF [1] = PSRC-> TP_DCS; // User Information Coding Method (TP-DCS) BUF [2] = 0; // Validity (TP-VP) is 5 minutes IF (psrc-> tp_dcs == GSM_7bit) { // 7-bit encoding method BUF [3] = NLENGTH; / / The length of the coding NLENGTH = GSMENCODE7BIT (PSRC-> TP_UD, & BUF [4], NLENGTH 1) 4; // Convert TP-DA to Target PDU Strings } ELSE IF (psrc-> tp_dcs == GSM_UCS2) { // UCS2 encoding method BUF [3] = GSMENCODEUCS2 (PSRC-> TP_UD, & BUF [4], NLENGTH); // Convert TP-DA to Target PDU Strings NLENGTH = BUF [3] 4; // Nlength is equal to this segment data length } Else { // 8-bit encoding method BUF [3] = Gsmencode8bit (PSRC-> TP_UD, & BUF [4], NLENGTH); // Convert TP-DA to the target PDU string NLENGTH = BUF [3] 4; // Nlength is equal to this segment data length } NDSTLENGTH = GSMBYTES2STRING (BUF, & PDSTLENGTH], NLENGTH); // Convert this section data to the target PDU string / / Return to the target string length Return ndstlength; } // PDU decoding for receiving, reading short messages // psrc: Source PDU string pointer // PDST: Target PDU parameter pointer // Return: User Information String Length INT gsmdecodepdu (const char * psrc, sm_param * pdst) { INT NDSTLENGTH; / / Target PDU String Length Unsigned char TMP; // Interim byte variable Unsigned char buf [256]; // internal buffer // SMSC address information GSMString2bytes (PSRC, & TMP, 2); // Take the length TMP = (TMP - 1) * 2; // SMSC number string length PSRC = 4; // Remove the pointer GSMSerializenumBers (PSRC, PDST-> SCA, TMP); // Convert SMSC number to target PDU string PSRC = TMP; / / Movement // TPDU segment basic parameters, reply address, etc. GSMSTRING2BYTES (PSRC, & TMP, 2); // Take basic parameters PSRC = 2; // Remove the pointer IF (TMP & 0x80) { / / Contain the reply address, retrieve the address information GSMString2bytes (PSRC, & TMP, 2); // Take the length IF (TMP & 1) TMP = 1; // Adjust parity PSRC = 4; // Remove the pointer GSMSERIALIZENUMBERS (PSRC, PDST-> TPA, TMP); // Take the TP-RA number PSRC = TMP; / / Movement } // TPDU segment protocol identification, encoding method, user information, etc. GSMString2bytes (psrc, (unsigned char *) & pdst-> tp_pid, 2); // Take the protocol identifier (TP-PID) PSRC = 2; // Remove the pointer GSMString2bytes (PSRC, (unsigned char *) & pdst-> tp_dcs, 2); // Take the encoding method (TP-DCS) PSRC = 2; // Remove the pointer GSMSerializenumBers (PSRC, PDST-> TP_SCTS, 14); // Service Timestamp String (TP_SCTS) PSRC = 14; // Remove the pointer GSMSTRING2BYTES (PSRC, & TMP, 2); // User Information Length (TP-UDL) PSRC = 2; // Remove IF (PDST-> TP_DCS == GSM_7bit) { // 7-bit decoding NDSTLENGTH = GSMSTRING2BYTES (PSRC, BUF, TMP & 7? (int) TMP * 7/4 2: (int) TMP * 7/4); // Format Conversion GSMDecode7bit (buf, pdst-> tp_ud, ndstlength); // Convert to TP-DU NDSTLENGTH = TMP; } Else IF (pdst-> tp_dcs == GSM_UCS2) { // UCS2 decoding ndstlength = GSMString2bytes (PSRC, BUF, TMP * 2); // Format Conversion NDSTLENGTH = GSMDECodeucs2 (BUF, PDST-> TP_UD, NDSTLENGTH); // Convert to TP-DU } Else { // 8-bit decoding ndstlength = GSMString2bytes (PSRC, BUF, TMP * 2); // Format Conversion NDSTLENGTH = GSMDECode8bit (buf, pdst-> tp_ud, ndstlength); // Convert to TP-DU } / / Return to the target string length Return ndstlength; } According to GSM 07.05, send a short message to use the AT CMGS command, read the short message with the at cmgr command, list short messages with the at cmgl command, delete the short message with the AT CMGD command. However, the AT cmgl command can read all short messages, so we use it to read the short message function without using AT CMGR. Here is the implementation code for sending, reading, and deleting short messages: // Send a short message // psrc: Source PDU parameter pointer Bool GsmsendMessage (const sm_param * psrc) { Int npduLength; // PDU string length Unsigned char nsmsclength; // SMSC string length INT NLENGTH; / / The data length received by the serial port Char cmd [16]; // Command string CHAR PDU [512]; // PDU string CHAR ANS [128]; // Answering npduLength = Gsmencodepdu (PSRC, PDU); // According to PDU parameters, encoded PDU strings STRCAT (PDU, "/ x01a"); // Ended Ctrl-Z GSMString2bytes (PDU, & nsmsclength, 2); // Take the SMSC information length in the PDU string NSMSCLENGTH ; // plus the length byte itself // The length in the command does not include the length of the SMSC information, with a data byte count Sprintf (CMD, "AT CMGS =% D / R", NPDulength / 2 - nsmsClength; // Generate Commands WriteComm (CMD, Strlen (CMD)); // Pre-output command string NLENGTH = Readcomm (ANS, 128); // Read answering data / / According to the "/ R / N>" determined to be successful or not (NLENGTH == 4 && Strncmp (ANS, "/ R / N>", 4) == 0) { WriteComm (PDU, Strlen (PDU)); // Get affirmative answers, continue to output a PDU string NLENGTH = Readcomm (ANS, 128); // Read answering data / / Determine the success of " CMS ERROR" according to Can I find it? IF (NLENGTH> 0 && Strncmp (ANS, " CMS Error", 10)! = 0) { Return True; } } Return False; } // Read short messages // Use cmgl instead of cmgr, you can read all short messages in one time // PMSG: Short message buffer must be large enough // Return: Short message INT GSMReadMessage (SM_PARAM * PMSG) { INT NLENGTH; / / The data length received by the serial port INT NMSG; // short message count value CHAR * PTR; / / internal data pointer Char cmd [16]; // Command string CHAR ANS [1024]; // Answering NMSG = 0; PTR = ANS; Sprintf (CMD, "AT CMGL / R"); // Generate Commands WriteComm (CMD, Strlen (CMD)); // Output Command Strings NLENGTH = Readcomm (ANS, 1024); // Read answer data / / Determine the success of " CMS ERROR" according to Can I find it? IF (NLENGTH> 0 && Strncmp (ANS, " CMS Error", 10)! = 0) { // Recycled each short message to " cmgl:" While (PTR = strstr (PTR, " CMGL:"))! = null) { PTR = 6; // Skip " CMGL:" SSCANF (PTR, "% D", & PMSG-> index); // Read the serial number Trace ("INDEX =% D / N", PMSG-> index); PTR = strstr (PTR, "/ r / n"); // Look for a row PTR = 2; // Skip "/ R / N" GSmDecodePdu (PTR, PMSG); // PDU string PMSG ; // Prepare to read a short message NMSG ; // short message count plus 1 } } Return NMSG; } // Delete short messages // Index: Short message number, starting from 1 Bool GsmdeeeteMessage (Const Int Index) { INT NLENGTH; / / The data length received by the serial port Char cmd [16]; // Command string CHAR ANS [128]; // Answering Sprintf (CMD, "AT CMGD =% D / R", INDEX); // Generate Commands / / Output command string WriteComm (cmd, strlen (cmd)); // read answering data NLENGTH = Readcomm (ANS, 128); / / Determine the success of " CMS ERROR" according to Can I find it? IF (NLENGTH> 0 && Strncmp (ANS, " CMS Error", 10)! = 0) { Return True; } Return False; } The WriteComm and READCOMM functions are used above the AT command, which is used to read and write the serial port, depending on the specific operating system. In the Windows environment, in addition to the MSCOMM control, and some ready-made serial communication classes, some Windows APIs can be simply invoked. The following is the main code implemented using the API, pay attention to the synchronization (blocking) mode of the timeout control. // Serial port equipment handle Handle HCOMM; // Open the serial port // pport: serial port name or device path, available "COM1" or "//./com1", recommended the latter // nbaudrate: baud rate // nparity: parity // NBYTESIZE: Data byte width // nstopbits: Stop bit Bool OpenComm (Const Char * Pport, Int Nbaudrate, Int NPARITY, INT NBYTESIZE, INT NSTOPBITS) { DCB DCB; // Serial Pull CommTIMEOUTS TIMEOUTS = {// Serial port timeout control parameters 100, // Read characters interval timeout: 100 ms 1, // read the time of each character: 1 ms (n characters for N ms) 500, // Basic (extra) Read time: 500 ms 1, // Write the time of each character: 1 ms (n characters for N ms) 100}; // Basic (additional) Writing timeout: 100 ms hcomm = cretefile (pport, // serial port name or device path Generic_read | generic_write, // Read and write 0, // Sharing method: exclusive NULL, / / Default security descriptor Open_existing, // creation method 0, // Do not set file properties NULL); // Do not need to refer to the template file IF (hcomm == invalid_handle_value) return false; // Open serial port failed Getcommstate (hcomm, & dcb); // Take DCB Dcb.baudrate = NBAUDRATE DCB.BYTESIZE = NBYTESIZE; DCB.PARITY = NPARITY; DCB.Stopbits = NStopbits; Setcommstate (HCOMM, & DCB); // Set DCB SetupComm (hcomm, 4096, 1024); // Setting the input and output buffer size Setcommtimeouts (hcomm, & timeouts); // Set timeout Return True; } // Turn off the serial port Bool closecomm () { Return CloseHandle (HCOMM); } // write serial port // PDATA: Data buffer pointer to be written // Nlength: The data length of the data to be written void writecomm (void * pdata, int NLENGTH) { DWORD DWNUMWRITE; / / The data length issued by the serial port Writefile (HCOMM, PDATA, (DWORD) NLENGTH, & DWNUMWRITE, NULL } // Read the serial port // PDATA: The data buffer pointer to be read // Nlength: The maximum data length to be read // Return: Data length actually read Int Readcomm (void * pdata, int NLENGTH) { DWORD DWNUMREAD; / / The data received by the serial port Readfile (HCOMM, PDATA, (DWORD) NLENGTH, & DWNUMREAD, NULL Return (int) DWNumRead; } Q What questions need to pay attention to when using the AT command to communicate with a mobile phone? A No AT command is sent to the phone, it may return success or fail. For example, when sending a short message with the AT CMGS command, if it is just that the phone is ringing or talking, it will return a " cms error". Therefore, after sending the command, the response of the phone should be detected, and then reissue after failure. Moreover, since only one communication port, transmission and reception cannot be performed simultaneously. If the serial pass-through credit timeout control synchronization (blocking) mode, the general practice is to package the send / receive processing in a work subline. Because there are more code, it will not be detailed here. In the attached DEMO, the complete sub-thread and the source code of the application interface are included. Q Is the AT command, is it supported by all manufacturers? A ETSI GSM 07.05 specification until 1998 to form the final Release version (Ver 7.0.1), before and later, it does not rule out the possibility of different manufacturers in DTE-DCE's short message AT commands. The AT commands in several PDU patterns we use are basic commands. From the principle, each manufacturer's mobile phone and the GSM module should be supported, but there may be fine differences. Q User Information (TP-UD) In addition to short messages in the general sense, it can also be pictures and sound data. What are the norms about the phone ringtones and pictures formats? A is a unified ringtone, picture format, Motorola and Ericsson, Siemens, Alcatel, and the like, and announced in February 2002. These manufacturers have the same format. But another mobile phone giant Nokia did not participate in standard development, ringtone, picture formats different from them. So there is no unified specification. EMS did not exceed GSM 07.05, just the TP-UD data section contains a certain format. The phone ringtones, picture format of each manufacturer can check the relevant website. Q User Information (TP-UD) can actually be any custom data, is it? A Yes, although there will be garbled on the phone. In this case, there is no meaning of the encoding method. But pay attention to still have to comply with the specification. For example, if the 7-bit encoding method is specified, the TP-UDL should be equal to 8/7 of the actual data length (in the one, not a round). In applications with SMS, point-to-point or multi-point to a point of data communication, various custom data, such as GPS information, environmental monitoring information, encrypted personal information, and so on. If you want to send a normal short message while transmitting custom data, the easiest way is to add an identification flag in front of the data, such as "ffff" to distinguish custom data and normal short messages.