Question

I am using a GSM modem "SIM900" I have tested it with hyper terminal and main command is ok.

Then I burnt the code to send the AT command to dial a number on the Microcontroller to the GSM modem using UART and it works fine.

But I'm having a problem with the response. The GSM replies with stream of characters but it doesn't end with Null '\0' !

How can I get the whole response in array to parse it later? And, how can I detect the end of response?

AT\r\n response is ==> OK

AT+CMGR=1 response is ==> +CMGR: "REC UNREAD" ,"+2347060580383","10/10/27,18:54:32+04"

Thanks in advance.

Was it helpful?

Solution

You can use \r\nOK for the ending, because phones use \n only for NewLine. But there's a more reliable way (I did that once) to make sure you don't get the wrong ending, for example when the incoming text message had the exact \r\nOK in it. In order to do that, I suggest that you change the Character Set to UCS2, so you will get the message text and sender number in UnicodeArray (It's like it is been escaped.)

Here's the class I used for my purpose (The extra check modules (AT\r command) are used to prevent getting stuck in error, in case there's an unexpected error or something like that! And the module I had sometimes went unresponsive, so with this I could make it again responsive! Doesn't seem logical, but saved me! Works perfectly for me now!):

public class SMSController
{
    public event EventHandler StatusChanged;
    protected virtual void OnStatusChanged()
    {
        if (StatusChanged != null)
        {
            StatusChanged(this, EventArgs.Empty);
        }
    }

    SerialPort serial;
    public SMSController(SerialPort serialPort)
    {
        this.serial = serialPort;
    }

    string readLine(int timeout = -1)
    {
        int oldTo = serial.ReadTimeout;
        serial.ReadTimeout = timeout;
        string str = serial.ReadTo("\n").Replace("\n", "").Replace("\r", "");
        serial.ReadTimeout = oldTo;
        return str;
    }

    void writeLine(string str)
    {
        serial.Write(str + "\r\n");
    }

    bool waitForString(string str, int timeout = -1)
    {
        if (readLine(timeout).Contains(str))
        {
            return true;
        }
        return false;
    }

    bool waitForOK(int timeout = -1, bool repeat = true)
    {
        if (repeat)
        {
            readUntilFind("OK", timeout);
            return true;
        }
        else
            return waitForString("OK", timeout);
    }

    void readUntilFind(string str, int timeout = -1)
    {
        while (!waitForString(str, timeout)) ;
    }

    void writeCommand(string command)
    {
        serial.DiscardInBuffer();
        writeLine(command);
    }

    bool applyCommand(string command, int timeout = -1)
    {
        writeCommand(command);
        return waitForOK(timeout);
    }

    private string lastStatus = "Ready";
    public string LastStatus
    {
        get { return lastStatus; }
        private set
        {
            lastStatus = value;
            OnStatusChanged();
        }
    }

    public void InitModule()
    {
        try
        {
            LastStatus = "Checking SIM900...";
            applyCommand("ATE0", 2000); //Disable echo
            applyCommand("AT", 5000); //Check module

            LastStatus = "Initializing SIM900...";
            applyCommand("AT+CMGF=1", 1000); //Set SMS format to text mode

            LastStatus = "Operation successful!";
        }
        catch (TimeoutException)
        {
            LastStatus = "Operation timed-out";
        }
        catch (Exception ex)
        {
            LastStatus = ex.Message;
        }
    }

    public static string ConvertToUnicodeArray(string str)
    {
        byte[] byt = Encoding.Unicode.GetBytes(str);           
        string res = "";
        for (int i = 0; i < byt.Length; i+=2)
        {
            res += byt[i + 1].ToString("X2");
            res += byt[i].ToString("X2");
        }
        return res;
    }

    public void SendMessage(string destinationNumber, string text, bool isUnicode = false)
    {
        try
        {
            LastStatus = "Initiating to send...";
            applyCommand("AT+CSMP=17,167,2,25", 1000);
            if (isUnicode)
            {
                if (!applyCommand("AT+CSCS=\"UCS2\"", 5000))
                    throw new Exception("Operation failed!");
                writeCommand("AT+CMGS=\"" + ConvertToUnicodeArray(destinationNumber) + "\"");
            }
            else
            {
                if (!applyCommand("AT+CSCS=\"GSM\"", 5000))
                    throw new Exception("Operation failed!");
                writeCommand("AT+CMGS=\"" + destinationNumber + "\"");
            }

            waitForString("> ", 5000);

            LastStatus = "Sending...";
            serial.DiscardInBuffer();
            serial.Write(isUnicode ? ConvertToUnicodeArray(text) : text);
            serial.Write(new byte[] { 0x1A }, 0, 1);

            if (waitForOK(30000))
            {
                LastStatus = "Message sent!";
            }
            else
                LastStatus = "Sending failed!";
        }
        catch (TimeoutException)
        {
            LastStatus = "Operation timed-out";
        }
        catch (Exception ex)
        {
            LastStatus = ex.Message;
        }
    }

    private string readTo(string str, int timeout)
    {
        int to = serial.ReadTimeout;
        serial.ReadTimeout = timeout;
        string strread = serial.ReadTo(str);
        serial.ReadTimeout = to;
        return strread;
    }

    public static byte[] StringToByteArray(string hex)
    {
        return Enumerable.Range(0, hex.Length)
                 .Where(x => x % 2 == 0)
                 .Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
                 .ToArray();
    }

    public static string ConvertUnicodeToText(string bytes)
    {
        byte[] bt = StringToByteArray(bytes);
        for (int i = 0; i < bt.Length; i+=2)
        {
            byte swap = bt[i];
            bt[i] = bt[i + 1];
            bt[i + 1] = swap;
        }
        return Encoding.Unicode.GetString(bt);
    }

    public SMS[] GetUnreadMessages()
    {
        List<SMS> lst = new List<SMS>();
        try
        {
            LastStatus = "Initializing...";
            applyCommand("AT+CSMP=17,167,2,25", 1000);
            applyCommand("AT+CSCS=\"UCS2\"", 2000);

            LastStatus = "Fetching text messages...";
            writeCommand("AT+CMGL=\"REC UNREAD\"");
            string texts = readTo("OK\r\n", 10000);
            string[] packets = texts.Split(new string[] { "\r\n\r\n" }, StringSplitOptions.RemoveEmptyEntries);
            for (int i = 0; i < packets.Length; i++)
            {
                if (!packets[i].Contains("+CMGL"))
                    continue;
                string num = packets[i].Split(new string[] { "," },
                    StringSplitOptions.RemoveEmptyEntries)[2].Replace("\"", "");
                string txt = packets[i].Split(new string[] { "\r\n" },
                    StringSplitOptions.RemoveEmptyEntries)[1].Replace("\"", "");
                lst.Add(new SMS(ConvertUnicodeToText(num), ConvertUnicodeToText(txt)));
            }

            applyCommand("AT+CMGDA=\"DEL READ\"", 10000);
            LastStatus = "Operation successful!";
        }
        catch (TimeoutException)
        {
            LastStatus = "Operation timed-out";
        }
        catch (Exception ex)
        {
            LastStatus = ex.Message;
        }

        return lst.ToArray();
    }
}

OTHER TIPS

Test for a new-line, which typical is \n or \r\n.

A NUL (0 or '\0') is only used in C to terminate a character array, a "string".

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top