Search code examples
c#smssendmodem

Cannot send SMS more then 140 via HUAWEI USB stick modem


I use HUAWEI USB stick modem and code below to send SMS successfully but under 140 of length (see the code pls -- double lenMes = textsms.Length / 2;).

But nowdays I see the really big SMS messages.

So I am wondering what's wrong with AT commnds or may me hardware is old so I cannot send big SMS.

Please any clue?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO.Ports;


namespace sendSMSPDU
{
    class Program
    {
        static SerialPort port;

        static void Main(string[] args)
        {
            port = new SerialPort();

            Console.WriteLine("Sending SMS");

            OpenPort();
            bool result;

            result = sendSMS("Some text that less 140 is gonna sending OK", " +75434355544");

            if (result == true)
            {
                Console.WriteLine("OK");
            }
            else
            {
                Console.WriteLine("ERROR");
            }
            Console.ReadLine();

            port.Close();
        }



        private static bool sendSMS(string textsms, string telnumber)
        {
            if (!port.IsOpen) return false;

            try
            {
                System.Threading.Thread.Sleep(500);
                port.WriteLine("AT\r\n");  
                System.Threading.Thread.Sleep(500);

                port.Write("AT+CMGF=0\r\n"); 
                System.Threading.Thread.Sleep(500);
            }
            catch
            {
                return false;
            }

            try
            {
                telnumber = telnumber.Replace("-", "").Replace(" ", "").Replace("+", "");


                telnumber = "01" + "00" + telnumber.Length.ToString("X2") + "91" + EncodePhoneNumber(telnumber);

                textsms = StringToUCS2(textsms);

                string leninByte = (textsms.Length / 2).ToString("X2");
                textsms = telnumber + "00" + "08" + leninByte + textsms;


                double lenMes = textsms.Length / 2;

                if (lenMes < 140) // It sends OK
                {
                    port.Write("AT+CMGS=" + (Math.Ceiling(lenMes)).ToString() + "\r\n");
                    System.Threading.Thread.Sleep(500);


                    textsms = "00" + textsms;

                    port.Write(textsms + char.ConvertFromUtf32(26) + "\r\n");
                    System.Threading.Thread.Sleep(500);
                }
                else
                {
                    return false;
                }
            }
            catch
            {
                return false;
            }

            try
            {
                string recievedData;
                recievedData = port.ReadExisting();

                if (recievedData.Contains("ERROR"))
                {
                    return false;
                }

            }
            catch { }

            return true;
        }


        private static void OpenPort()
        {

            port.BaudRate = 9600;  
            port.DataBits = 7;  

            port.StopBits = StopBits.One;          
            port.Parity = Parity.Odd;  

            port.ReadTimeout = 500;  
            port.WriteTimeout = 500;  

            //port.Handshake = Handshake.RequestToSend;
            //port.DtrEnable = true;
            //port.RtsEnable = true;
            //port.NewLine = Environment.NewLine;

            port.Encoding = Encoding.GetEncoding("windows-1252");

            port.PortName = "COM7";


            if (port.IsOpen)
                port.Close();
            try
            {
                port.Open();
            }
            catch { }

        }




        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();
        }



        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("-", "");
        }


    }
}

Solution

  • Single SMS message is limited to 160 (or 152 in PDU mode) symbols in GSM-7 encoding. More than that, if there is any symbol not listed here you need to use UCS-2 encoding and your messages now limit to 67 symbols. If you need to send longer messages, you are welcome to the "bright and shiny world" of SMS PDU mode.

    So sending a long sms is as easy as:

    1. Split it to parts of 67 (or 152) symbols;
    2. Convert this parts to UCS-2 or GSM-7 encoding;
    3. Transform them to PDU messages;
    4. Send them sequentially with use of additional AT-command (AT+CMGF=0)

    Edit

    The one who designed a PDU format is a true evil person. It is really mind breaking thing and I don't want to write a convertion code, sorry. But, I can point you with this stub:

    protected void SendMessage(string phoneNumber, string message)
    {
        const char CR = '\r'; // "Carage Return"
        const char CtrlZ = (char)26; // Ctrl+Z character
    
        var header = GeneratePDUHeader(phoneNumber);
        foreach (var messagePart in SplitSMSMessage(message))
        {
            SendToCOM("AT+CMGF=0" + CR);
            SendToCOM("AT+CMGS=42" + CR);
            SendToCOM($"{header}{messagePart}" + CtrlZ);
        }
    }
    
    // should return something like "0041000B910000000000F000088C"
    protected string GeneratePDUHeader(string phoneNumber) { }
    
    // split long message to parts
    protected IEnumerable<string> SplitSMSMessage(string message)
    {
        var useUCSEncoding = IsUCSEncodingNeeded(message);
        var partLength = useUCSEncoding ? 67 : 152;
    
        var messageParts = Enumerable.Range(0, message.Length / partLength)
            .Select(i => message.Substring(i * partLength, partLength))
            .ToArray();
    
        var referenceNumber = $"{GenerateReferenceNumber():X2}"; // convert to HEX, i.e. "01"
        var totalMessagesCount = $"{messageParts.Length:X2}";    // convert to HEX, i.e. "01"
        var udhBase = $"050003{referenceNumber}{totalMessagesCount}";
    
        var messageNumber = (char)0;
        foreach (var messagePart in messageParts)
        {
            var udh = $"{udhBase}{++messageNumber}";
            var messagePartText = useUCSEncoding ? StringToUCS(messagePart) : StringToGSM7(messagePart);
            yield return $"{udh}{messagePartText}";
        }
    }
    
    private void SendToCOM(string message) { } // writes message to COM port
    private bool IsUCSEncodingNeeded(string message) { } // determine if UCS-2 convert is required
    private char GenerateReferenceNumber() { } // random number 0-255
    private string StringToUCS(string message) { } // convert string to UCS encoding
    private string StringToGSM7(string message) { } // convert string to GSM7 encoding (don't forget about padding!)
    

    You may also find this links are useful: