Colabora .NET

Envío de Mensajes SMS y Lectura de los Mensajes Almacenados en C# 2.0

 

Fecha: 17/Ago/2006 (16-08-06)
Autor: Mauro Maximiliano Melgar

 


 

Nombre: Mauro Maximiliano Melgar

Ocupación: Desarrollador

Ubicación: Buenos Aires, Argentina

 

 

Envío de Mensajes SMS y Lectura de los Mensajes Almacenados en C# 2.0

 

 

Antes de comenzar a explicar un poco el funcionamiento, quiero aclarar, que vengo de muchos años de programar con Visual Basic, he decidido cambiar a C#, y seguramente puedo tener algún error en el código, ya sea de performance o de concepto, si así lo fuere, le pido disculpas al lector y se que con el tiempo y la practica mejorare en el lenguaje.

 

 

Proyecto:

                 Utilizar la clase SerialPort del Framework 2.0 para comunicarnos mediante comandos AT con el modem de un celular GSM.

 

Equipo Utilizado para el desarrollo y el testing:

                MOTOROLA E398

CABLE DE DATOS USB

 

 

Celulares Compatibles:

                                       Todo celular GSM que tenga modem incorporado (hoy en día, por lo general, todos los celulares lo traen) y conexión usb.

 

Repaso General del Proyecto:

 

El proyecto se compone de 2 clases, una llamada Gsm y la otra Sms.

Gsm, comprende las funciones básicas para la comunicación con el celular, ya sea, desde abrir el puerto de comunicaciones, leer o enviar los mensajes y cerrar el puerto.

Y Sms, es una clase que posee propiedades Get y Set para los mensajes de texto.

 

En la clase Gsm, los 2 rasgos más importantes, seguramente son, que implementa la interfaz IEnumerable para que la propiedad Buzon, pueda devolver un objeto del tipo Sms y que utiliza una lista genérica del tipo Sms para almacenar los mensajes que se encuentran en el celular.

 

 

Documentación del Proyecto:

 

Acá podemos ver que el constructor de la clase GSM asigna los valores por default

 

  public Gsm()

        {

                _PuertoCom="";

                _BitsDeParada=StopBits.One;

                _Paridad=Parity.None;

                _DataBits=8;

                _Baudios=Baudios.BPS_115200;

                _PuertoAbierto=false;

        }

 

 

 

Definimos las variables a utilizar en nuestra clase para manejar el puerto COM a donde se va a conectar, los Baudios, etc.

           

        private string _PuertoCom;

        private StopBits _BitsDeParada;

        private Parity _Paridad;

        private int _DataBits;

        private int _Baudios;

        private Boolean _PuertoAbierto;

 

Creamos la variable Puerto del tipo SerialPort, la cual, utilizaremos en todo el proyecto

 

        private SerialPort Puerto = new SerialPort();

 

 

Esta estructura es algo importante, ya que aca definimos cual es el comando AT que vamos a enviar para obtener el tipo de mensaje que necesitemos.

 

        public struct TipoMensaje

        {

            public const string Recibidos_Leidos = "REC READ";

            public const string Recibidos_No_Leidos = "REC UNREAD";

            public const string Enviados = "STO UNSEND";

            public const string Escritos_Sin_Enviar = "STO SENT";

            public const string Todos = "ALL";

        }

 

Definición de la estructura para configurar la velocidad de los baudios

 

        public struct Baudios

        {

            public const int BPS_1200=1200;

            public const int BPS_9600=9600;

            public const int BPS_28800=28800;

            public const int BPS_57600=57600;

            public const int BPS_115200=115200;

     }

 

Una manera sencilla de especificar algunos de los puertos COM que tengamos disponibles en la PC.

 

        public struct PuertoComunicacion

        {

            public const string COM1 = "COM1";

            public const string COM2 = "COM2";

            public const string COM3 = "COM3";

            public const string COM4 = "COM4";

            public const string COM5 = "COM5";

            public const string COM6 = "COM6";

            public const string COM7 = "COM7";

            public const string COM8 = "COM8";

            public const string COM9 = "COM9";

            public const string COM10 = "COM10";

}

 

 

Esta propiedad la vamos a utilizar para especificar el tipo de mensaje (TipoMensaje) que vamos a buscar cuando comencemos a utilizar la clase en una aplicación.

 

        public string TipoDeMensaje

        {

            get

            {

                return _TipoDeMensaje;

            }

            set

            {

                _TipoDeMensaje = value;

            }

        }

 

Variable de uso interno de la clase donde almacenamos el TipoMensaje

 

        private string  _TipoDeMensaje;

 

Propiedad para especificar el DataBit

 

        public int DataBits

        {

            get

            {

                return _DataBits;

            }

 

            set

            {

                _DataBits = value;

            }

        }

 

Propiedad para especificar la Paridad, donde el valor es del tipo Parity, por ejemplo: Parity.None

 

        public Parity Paridad

        {

            get

            {

                return _Paridad;

            }

 

            set

            {

                _Paridad = value;

            }

        }

 

Propiedad a la cual le especificamos el puerto de comunicacion

 

        public string PuertoCom

        {

            get

            {

                return _PuertoCom;

            }

 

            set

            {

                _PuertoCom = value;

            }

 

        }

 

Propiedad a la cual le especificamos el Bit de Stop

 

        public StopBits BitsDeStop

        {

            get

            {

                return _BitsDeParada;

            }

 

            set

            {

_BitsDeParada = value;

            }

        }

 

Propiedad que recibe como parametro un valor de la estructura Baudios

 

        public int Velocidad

        {

            get

            {

                return _Baudios;

            }

 

            set

            {

                _Baudios = value;

            }

        }

 

Propiedad de tipo boolean donde sabremos si el puerto COM esta abierto o no

 

        public Boolean PuertoAbierto

        {

            get

            {

                return _PuertoAbierto;

            }

        }

 

 

Funcion que establece los parametros principales para el uso de SerialPort, establecer que procedimiento se utilizara como evento para la recepcion de los datos y devolver true si se pudo abrir el puerto, en caso contrario, devuelve false

 

        public Boolean AbrirPuerto()

        {

 

            try

            {

                Puerto.PortName = _PuertoCom;

                Puerto.Parity = _Paridad;

                Puerto.BaudRate = _Baudios;

                Puerto.StopBits = _BitsDeParada;

Puerto.DataReceived += new SerialDataReceivedEventHandler(RecibiendoDatos);

 

                Puerto.Open();

                _PuertoAbierto = true;

                return true;

            }

            catch

            {

_PuertoAbierto = false;

                return false;

            }

        }

 

Devuelve tru si el puerto esta abrierto y lo cerro, false en el caso de que no este abierto

 

      public Boolean CerrarPuerto()

        {

            if (_PuertoAbierto)

            {

Puerto.Close();

                return true;

            }

            else

            {

                return false;

            }

        }

 

La propiedad buzon, devuelve un objeto del tipo Sms para poder recorrerlo desde nuestra aplicación mediante un foreach

 

        public IEnumerable<Sms> Buzon

        {

            get

            {

                BuscarMensajes(_TipoDeMensaje);

 

                for (int i = 0; i <= (BandejaEntrada.Count-1); i++)

                {

                    yield return BandejaEntrada[i];

                }

            }

 

        }

 

 

Funcion que nos permite enviar un mensaje de texto y devolver true si el envio fue satisfactorio.

 

        public Boolean EnviarMensaje(string NroTelefono, string Mensaje)

        {

 

            try

            {

 

Puerto.WriteLine("AT\r");

                Puerto.WriteLine("AT+CMGF=1\r");

Puerto.WriteLine("AT+CMGS=\"" + NroTelefono.Trim() + "\"\r");

Puerto.WriteLine(Mensaje.Trim() + '\x001a');

 

                return true;

            }

            catch (Exception Error)

            {

                return false;

            }

 

        }

 

El procedimiento BuscarMensajes recibe como parametro un string, se debe utilizar algunos de los valores de la estructura TipoMensaje

 

        private void BuscarMensajes(string TipoDeMensaje)

        {

           

Puerto.WriteLine("AT+CMGF=1\r");

            Thread.Sleep(50);

Puerto.WriteLine("AT+CPMS=\"MT\"\r");

            Thread.Sleep(50);

            Puerto.WriteLine("AT+CMGL=\"" + TipoDeMensaje +"\"\r");

            Thread.Sleep(1000);

        }

 

 

Este es el procedimiento que se utiliza como evento para la busqueda de los mensajes cuando se envia el comando AT en especifico, podemos notar que solamente esta implemantado los del tipo “+CMGL” que son los de SMS almacenados en el celular, aunque es totalmente modificable y adaptable a todas las necesidades.

 

        private void RecibiendoDatos(object sender, SerialDataReceivedEventArgs e)

        {

 

            String Linea;

            int Indice = 0;

 

            SerialPort Serie = (SerialPort)sender;

 

            Thread.Sleep(200);

 

            Linea = Serie.ReadExisting();

 

 

            while (Linea.IndexOf("+CMGL:", Indice) > 0)

            {

 

                int Comienzo = Linea.IndexOf("+CMGL:", Indice);

                int Final = Linea.IndexOf("+CMGL:", Comienzo + 1);

 

                if (Final <= 0) { Final = Linea.Length; }

 

                string Mensaje;

 

                Mensaje = Linea.Substring(Comienzo, Final - Comienzo);

 

                string[] Componentes = Mensaje.Split(',');

                string Tel = Componentes[2];

                string IndiceMensaje = Componentes[0];

 

                int IIndice = 0;

                int FIndice = 0;

 

                IIndice = IndiceMensaje.IndexOf("+CMGL:") + "+CMGL:".Length;

                FIndice = IndiceMensaje.Length - IIndice;

 

                IndiceMensaje = IndiceMensaje.Substring(IIndice, FIndice);

 

                int FinalIndice = Tel.IndexOf("\r\n");

 

                if (FinalIndice <= 0) { FinalIndice = Tel.Length; }

 

                Tel = Tel.Substring(0, FinalIndice);

 

                int ComienzoMsgIdx = Mensaje.IndexOf("\r\n");

 

                int FinalMsgIdx = Mensaje.IndexOf("\r\n", ComienzoMsgIdx + 1);

 

                if (FinalMsgIdx <= 0) { FinalMsgIdx = Mensaje.Length; }

 

                string Msg = Mensaje.Substring(ComienzoMsgIdx, FinalMsgIdx - ComienzoMsgIdx);

 

              

                Sms _Mensaje = new Sms();

               

                _Mensaje.IDSms = IndiceMensaje.Trim();

                _Mensaje.Telefono = Tel.Trim();

                _Mensaje.Mensaje = Msg.Trim();

 

                BandejaEntrada.Add(_Mensaje);

 

                Indice = Comienzo + 1;

 

            }

        }

 

 

Espero que este ejemplo les halla sido de utilidad y que le saquen el mayor probecho posible para los que desean realizar un desarrollo con caracteristicas similares o implementando estas mismas.

 

 


Código de ejemplo (ZIP):

 

Fichero con el código de ejemplo: mauro_melgar_envio_sms.zip - 86,48 KB

(MD5 checksum: 35CAEE5F7B0C95EDE6E8A20984A7F1E1)

 


ir al índice principal del Guille