πŸ“œ ⬆️ ⬇️

We send SMS from .Net applications to C #


All we need to send SMS is a 3G USB modem, SIM card, Visual Studio and a little time. My goal is not to describe all the possible settings for the COM port or PDU format. I would like to provide you with a turnkey solution that you can use as a snippet in your projects.
As an example, consider 2 console applications. Why console? Yes, because there is nothing superfluous in them and it is easier to disassemble the code. Why two? Because there are two common options for sending messages. The easiest option is to send messages in text mode. The disadvantage of this option is that it does not support sending Cyrillic. Plus the fact that it is possible to send 160 characters. The second option, more complex, allows you to send text up to 70 characters in Unicode format.

Send messages in text mode.


So, create a console application and, first of all, add a namespace:
using System.IO.Ports; 

Next, let's declare a variable of type SerialPort
 static SerialPort port; 

It is static because the application is a console.

Inside the main application procedure static void Main (string [] args), initialize the variable using the constructor new SerialPort ()
 port = new SerialPort(); 

We'll install the port settings and open it in a separate procedure:
  private static void OpenPort() { port.BaudRate =2400; //   4800, 9600, 28800  56000 port.DataBits = 7; //   8, 9 port.StopBits = StopBits.One; //   StopBits.Two StopBits.None  StopBits.OnePointFive port.Parity = Parity.Odd; //   Parity.Even Parity.Mark Parity.None  Parity.Space port.ReadTimeout = 500; //     port.WriteTimeout = 500; //     port.Encoding = Encoding.GetEncoding("windows-1251"); port.PortName = "COM5"; //      if (port.IsOpen) port.Close(); //        try { port.Open(); } catch (Exception e) { } } 

Settings may be specific to different modems. I conducted tests on the model of Huawei E150, and at the same time the sending was made in almost any settings.
All settings are available in MSDN at this link.
The port number is determined using the device manager. In the following example, this is COM4 port:

After the port is open, you can start sending a message using AT commands.
We send the command to the modem using port.WriteLine. Between sending commands, be sure to pause - System.Threading.Thread.Sleep (500)

Send the first two commands:
  port.WriteLine("AT \r\n"); //  !   System.Threading.Thread.Sleep(500); port.Write("AT+CMGF=1 \r\n"); //       System.Threading.Thread.Sleep(500); 

The first command asks the modem to go into ready mode. The second command sets the text message sending mode. Please note that after the commands there are characters of the line break \ r \ n. In various examples of sending messages that can be found on the network, various hyphenations are indicated. Somewhere only \ r, somewhere \ n, and sometimes even \ n \ r. According to official information from MSDN:
Environment.NewLine is a string containing "\ r \ n" for non-Unix platforms, or a string containing "\ n" for Unix platforms. That is, in our case, use \ r \ n.
')
For simplicity, disable the PIN code on the SIM card. This can be done using the application supplied with the modem, or using a mobile phone.
The phone number that will be transferred to the modem as a parameter of the command must not contain any characters except numbers and the β€œ+” sign. That is, it must be transmitted in an international format. We send the command with the phone number of the SMS recipient:
 port.Write("AT+CMGS=\"+375123456789\"" + "\r\n"); System.Threading.Thread.Sleep(500); 

And then send the message text itself:
 port.Write("Hello from modem!" + char.ConvertFromUtf32(26) + "\r\n"); System.Threading.Thread.Sleep(500); 

Please note that after the text of the message, the character char.ConvertFromUtf32 (26) is transmitted
When sending AT commands, it is after the transmission of the message text itself that the CTRL-Z combination must be sent. This combination is the 26th character of UTF32.
After the message is sent, it would be correct to close the port.
 port.Close(); 

After the transfer of the command, the modem, as a rule, gives its answer with confirmation or error. You can read this data using the port.ReadExisting () method, which returns the string value of the modem response.
In the procedure for opening a port, you can add registration of the event that the port receives data:
 port.DataReceived += SerialPortDataReceived; 

And further implement data processing:
  private void SerialPortDataReceived(object sender, SerialDataReceivedEventArgs e) { //       } 

The program works in one thread. It is even recommended to work with COM ports in one stream. To do this, you can mark the class / code attribute [STAThread] . If someone is aware of the details about the multi-threaded work with ports COM, I will be glad to comment.

Github link
You can download the link

Sending a text message is a fairly popular topic on the net. And if everything is clear with sending text, then when sending messages in PDU mode, questions arise that are not always disclosed.

Sending messages in PDU mode (Protocol data unit)


The opening of the port is completely identical to the opening of the port from the above example.
The first two commands are also similar to the previous example, except that in the second command, the parameter is 0.
 port.WriteLine("AT\r\n"); //  "!"   System.Threading.Thread.Sleep(500); port.Write("AT+CMGF=0\r\n"); //    PDU    System.Threading.Thread.Sleep(500); 

When sending a message in the form of a PDU, the mobile phone number must not contain anything other than numbers. If the number of digits is odd, then you need to add to the end of the number F. Plus, the adjacent numbers of the number should be rearranged. For example, the recipient's SMS number is 1234567, the number of digits is odd, which means we add F. We make a permutation and we get 214365F7.
The following function will help us to make this transformation:
  //      PDU public static string EncodePhoneNumber(string PhoneNumber) { string result = ""; if ((PhoneNumber.Length % 2) > 0) PhoneNumber += "F"; int i = 0; while (i < PhoneNumber.Length) { result += PhoneNumber[i + 1].ToString() + PhoneNumber[i].ToString(); i += 2; } return result.Trim(); } 

The message itself must also be encoded in UCS2 format. This format is an outdated version of the UTF-16 format. The difference is that UCS2 cannot be used for compatible representation of additional characters. FAQ link
Simply put: the UTF-16 and UCS2 codes are mostly the same.
The character code can be viewed or checked by the symbol table, which is located in the Start menu - All Programs - Accessories - System Tools - Symbols Table

The code for the letter "e" - 0435
In some examples from the network, the conversion of a letter into a code occurs by matching the letter with the code. That is, an array with letters is created, and an array with codes corresponding to letters. Each letter of the message text is replaced with a code. This example works, but I preferred another:
 //     UCS2 public static string StringToUCS2(string str) { UnicodeEncoding ue = new UnicodeEncoding(); byte[] ucs2 = ue.GetBytes(str); int i = 0; while (i < ucs2.Length) { byte b = ucs2[i + 1]; ucs2[i + 1] = ucs2[i]; ucs2[i] = b; i += 2; } return BitConverter.ToString(ucs2).Replace("-", ""); } 

It would seem that everything is relatively simple, but it was not there! Along with the encrypted phone number and message, we need to transfer a lot more information.

Suppose we have a string variable telnumber with a phone number (only numbers without the β€œ+” symbol in the international format). We form the code for the phone number:
 telnumber = "01"+"00" + telnumber.Length.ToString("X2") + "91" + EncodePhoneNumber(telnumber); 

β€œ01” is a PDU Type or sometimes called SMS-SUBMIT. 01 means the message is transmitted, not received
β€œ00” is TP-Message-Reference means that the phone / modem can set the number of successful messages automatically.
telnumber.Length.ToString ("X2") will give us long numbers in hexadecimal format
"91" means international phone number format is used.
Well, EncodePhoneNumber is the function mentioned above.

Now let's take the textsms variable with the message text and get the code for the message itself:
 textsms = StringToUCS2(textsms); 

Next we need to get the length of this message in hex format. Get it like this:
 string leninByte = (textsms.Length / 2).ToString("X2"); 


Let us combine the code of our phone number, the length of the message, the code of the message and add to all this intermediate code symbols:
 textsms = telnumber + "00"+"0"+"8" + leninByte + textsms; 

β€œ00” means the message format is implicit. This is the protocol ID. Other options are telex, fax, voice message, etc.
β€œ0” if instead of 0 you specify 1, then the message will not be saved on the phone. Get a popup flash message.
"8" means UCS2 format - 2 bytes per character.

Earlier we considered the length of the phone number and the text of the message. Now we need to calculate the length for the third time, this time for the entire PDU message. We will send this length with the AT command:
 double lenMes = textsms.Length / 2; //       port.Write("AT+CMGS=" + (Math.Ceiling(lenMes)).ToString() + "\r\n"); System.Threading.Thread.Sleep(500); 

In the second line, rounding up is used. For example, even if we get 15.5 octets, then we transmit the data in a packet of 16 octets.

This terribly confusing PDU code ends with the fact that we need to transmit the sms-center number of our telecom operator. Since almost all SIM cards in our time already contain a β€œwired” center number, we will transmit the code β€œ00” instead, which will mean that the number should be taken automatically from the SIM card data.
This code "00" should be at the very beginning of the message. Strangely enough, even though these symbols are at the very beginning of the message, they should be added at the last step. The reason lies in the fact that we needed to calculate the length of the message without taking into account this code.
 textsms = "00" + textsms; 

Everything. Now you can send the AT PDU code with the command:
 port.Write(textsms + char.ConvertFromUtf32(26) + "\r\n"); //     CTRL-Z   System.Threading.Thread.Sleep(500); 

Github link

Source: https://habr.com/ru/post/256687/


All Articles