Transceive short message through serial port (below)

zhaozj2021-02-16  47

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. Using the following two functions can be positive and reverse transform:

/ / The normal sequence string is converted to two two-reversal strings. If the length is odd, the 'F' is even more

// 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, coding 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 the 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 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

}

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

/ / Determine if "/ R / N>" can be found

IF (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 answer 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 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.

[Related resources] ◆ This article Demo Source: SMSTEST.ZIP (31 KB) ◆ ETSI official website: http://www.etsi.org ◆ Aidide Download Center: http://www.ascend-tech.com. CN / DOWNLOAD.HTML ◆ BHW98 column: http://www.9cbs.net/develop/author/netauthor/bhw98/

First release: 2003-03-23 ​​Last revision: 2003-03-26

转载请注明原文地址:https://www.9cbs.com/read-23672.html

New Post(0)