2010-06-11 4 views
6

Ho scritto il codice per inviare un SMS utilizzando il mio telefono GSM che è collegato al computer tramite la porta COM. Il codice è sottoSMS per connettersi a un telefono da C# e ottenere una risposta

Il problema è che vedo che è nella posta in uscita del telefono e in realtà sembra essere stato inviato, ma quando contatto il destinatario dicono che non ho ricevuto il messaggio.

Testare il telefono e creo e invio un messaggio utilizzando solo il telefono e funziona perfettamente. Tuttavia, quando faccio questo con il mio codice, sembra essere stato inviato, e sto ricevendo tutte le risposte AT COMMAND corrette dal telefono, ma il messaggio NON è in realtà inviato.

Ecco il codice:

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Windows.Forms; 
using System.Threading; 
using System.IO.Ports; 

namespace WindowsFormsApplication1 
{ 
    public partial class Form1 : Form 
    { 
     SerialPort serialPort1; 
     int m_iTxtMsgState = 0; 
     const int NUM_MESSAGE_STATES = 4; 
     const string RESERVED_COM_1 = "COM1"; 
     const string RESERVED_COM_4 = "COM4"; 

     public Form1() 
     { 
      InitializeComponent(); 

      this.Closing += new CancelEventHandler(Form1_Closing); 
     } 

     private void Form1_Load(object sender, EventArgs e) 
     { 
      serialPort1 = new SerialPort(GetUSBComPort()); 

      if (serialPort1.IsOpen) 
      { 
       serialPort1.Close(); 
      } 

      serialPort1.Open(); 

      //ThreadStart myThreadDelegate = new ThreadStart(ReceiveAndOutput); 
      //Thread myThread = new Thread(myThreadDelegate); 
      //myThread.Start(); 

      this.serialPort1.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived); 
     } 

     private void Form1_Closing(object sender, System.ComponentModel.CancelEventArgs e) 
     { 
      serialPort1.Close(); 
     } 

     private void SendLine(string sLine) 
     { 
      serialPort1.Write(sLine); 
      sLine = sLine.Replace("\u001A", ""); 
      consoleOut.Text += sLine; 
     } 

     public void DoWork() 
     { 
      ProcessMessageState(); 
     } 

     public void ProcessMessageState() 
     { 
      switch (m_iTxtMsgState) 
      { 
       case 0: 
        m_iTxtMsgState = 1; 
        SendLine("AT\r\n"); //NOTE: SendLine must be the last thing called in all of these! 
       break; 

       case 1: 
        m_iTxtMsgState = 2; 
        SendLine("AT+CMGF=1\r\n"); 

       break; 

       case 2: 
        m_iTxtMsgState = 3; 
        SendLine("AT+CMGW=" + Convert.ToChar(34) + "+9737387467" + Convert.ToChar(34) + "\r\n"); 
       break; 

       case 3: 
        m_iTxtMsgState = 4; 
        SendLine("A simple demo of SMS text messaging." + Convert.ToChar(26)); 
       break; 

       case 4: 
        m_iTxtMsgState = 5; 

       break; 

       case 5: 
        m_iTxtMsgState = NUM_MESSAGE_STATES; 
       break; 
      } 
     } 

     private string GetStoredSMSID() 
     { 
      return null; 
     } 

     /* //I don't think this part does anything 
     private void serialPort1_DataReceived_1(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) 
     { 
      string response = serialPort1.ReadLine(); 
      this.BeginInvoke(new MethodInvoker(() => textBox1.AppendText(response + "\r\n"))); 
     } 
     */ 
     void sp_DataReceived(object sender, SerialDataReceivedEventArgs e) 
     { 
      try 
      { 
       Thread.Sleep(500); 

       char[] msg; 
       msg = new char[613]; 
       int iNumToRead = serialPort1.BytesToRead; 

       serialPort1.Read(msg, 0, iNumToRead); 

       string response = new string(msg); 

       this.BeginInvoke(new MethodInvoker(() => textBox1.AppendText(response + "\r\n"))); 
       serialPort1.DiscardInBuffer(); 

       if (m_iTxtMsgState == 4) 
       { 
        int pos_cmgw = response.IndexOf("+CMGW:"); 
        string cmgw_num = response.Substring(pos_cmgw + 7, 4); 
        SendLine("AT+CMSS=" + cmgw_num + "\r\n"); 
        //stop listening to messages received 
       } 

       if (m_iTxtMsgState < NUM_MESSAGE_STATES) 
       { 
        ProcessMessageState(); 
       } 
      } 
      catch 
      { } 
     } 

     private void button1_Click(object sender, EventArgs e) 
     { 
      m_iTxtMsgState = 0; 
      DoWork(); 
     } 

     private void button2_Click(object sender, EventArgs e) 
     { 
      string[] sPorts = SerialPort.GetPortNames(); 
      foreach (string port in sPorts) 
      { 
       consoleOut.Text += port + "\r\n"; 
      } 
     } 

     private string GetUSBComPort() 
     { 
      string[] sPorts = SerialPort.GetPortNames(); 
      foreach (string port in sPorts) 
      { 
       if (port != RESERVED_COM_1 
        && port != RESERVED_COM_4) 
       { 
        return port; 
       } 
      } 

      return null; 
     } 
    } 
+1

si dice che "non so a quale COM connettersi." 'Ma poi si dice' "in hyperterminal si vedono le risposte subito" 'così, si sa come connettersi, qual è il numero COM, o non lo collegheresti mai via HT. A proposito, è necessario chiudere tutti i COM (HT) prima di gestire il codice, poiché la porta COM è già aperta, non sarà più possibile riaprirla finché non si chiude la prima connessione ... – balexandre

risposta

2

Questo è il mio codice che funziona (testato) con U9 Telia modem cellulare:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Runtime.InteropServices; 
using System.Diagnostics; 
using System.Configuration; 

using UsbEject.Library; 
using Utils; 

namespace Hardware 
{ 
    public class TeliaModem : IDisposable 
    { 
     public delegate void NewSmsHandler(InboundSMS sms); 
     public event NewSmsHandler OnNewSMS; 

     #region private data 
     System.IO.Ports.SerialPort modemPort; 

     Timeouter _lastModemKeepAlive; 

     private delegate void DataReceivedDelegate(); 
     private DataReceivedDelegate dataReceivedDelegate; 

     Queue<OutboundSMS> _outSmses = new Queue<OutboundSMS>(); 

     enum ModemState 
     { 
      Error = -1, NotInitialized, PowerUp, Initializing, Idle, 
      SendingSMS, KeepAliveAwaitingResponse 
     }; 

     Timeouter ModemStateTimeouter = new Timeouter(timeout_s: 10, autoReset: false); 
     ModemState _modemState = ModemState.NotInitialized; 
     ModemState CurrentModemState 
     { 
      get 
      { 
       return _modemState; 
      } 
      set 
      { 
       _modemState = value; 
       ModemStateTimeouter.Reset(); 
       NihLog.Write(NihLog.Level.Debug, "State changed to: " + value.ToString()); 
      } 
     } 

     private System.Windows.Forms.Control _mainThreadOwnder; 
     #endregion 

     public TeliaModem(System.Windows.Forms.Control mainThreadOwnder) 
     { 
      _mainThreadOwnder = mainThreadOwnder; 

      dataReceivedDelegate = new DataReceivedDelegate(OnDataReceived); 
     } 

     public void SendSMS(string phone, string text) 
     { 
      _outSmses.Enqueue(new OutboundSMS(phone, text)); 
      HeartBeat(); 
     } 

     private void SendSmsNow() 
     { 
      OutboundSMS sms = _outSmses.Peek(); 
      sms.Attempt++; 
      if (sms.Attempt > sms.MaxTries) 
      { 
       NihLog.Write(NihLog.Level.Error, "Failure to send after " + sms.MaxTries + " tries"); 
       _outSmses.Dequeue(); 
       return; 
      } 

      NihLog.Write(NihLog.Level.Info, "Sending SMS: " + sms.ToString()); 
      WriteToModem("AT+CMGS=\"" + sms.Destination + "\"\r"); 
      System.Threading.Thread.Sleep(500); 
      WriteToModem(sms.Text); 

      byte[] buffer = new byte[1]; 
      buffer[0] = 26; // ^Z 
      modemPort.Write(buffer, offset:0, count:1); 

      CurrentModemState = ModemState.SendingSMS; 
     } 

     public void Dispose() 
     { 
      UninitModem(); 
     } 

     public void HeartBeat() 
     { 
      if (CurrentModemState == ModemState.NotInitialized) 
      { 
       TryInitModem(); 
       return; 
      } 

      if (IsTransitionalState(CurrentModemState) && ModemStateTimeouter.IsTimedOut()) 
      { 
       NihLog.Write(NihLog.Level.Error, "Modem error. Timed out during " + CurrentModemState); 
       CurrentModemState = ModemState.Error; 
       return; 
      } 

      if (CurrentModemState == ModemState.Idle && _lastModemKeepAlive.IsTimedOut()) 
      { 
       // Send keepalive 
       WriteToModem("AT\r"); 
       CurrentModemState = ModemState.KeepAliveAwaitingResponse; 
       return; 
      } 

      if (CurrentModemState == ModemState.Error) 
      { 
       NihLog.Write(NihLog.Level.Debug, "Reenumerating modem..."); 
       UninitModem(); 
       return; 
      } 

      if (_outSmses.Count != 0 && CurrentModemState == ModemState.Idle) 
      { 
       SendSmsNow(); 
       return; 
      } 
     } 

     private string pendingData; 
     private void OnDataReceived() 
     { 
      // Called in the main thread 

      string nowWhat = modemPort.ReadExisting(); 
      pendingData += nowWhat; 
      string[] lines = pendingData.Split(new string[] { "\r\n" }, StringSplitOptions.None); 
      if (lines.Length == 0) 
      { 
       pendingData = string.Empty; 
       return; 
      } 
      else 
      { 
       pendingData = lines[lines.Length - 1]; 
      } 

      // This happens in main thread. 
      for (int i = 0; i < lines.Length - 1; i++) 
      { 
       string line = lines[i]; 

       if (line.Length >= 5 && line.Substring(0, 5) == "+CMT:") 
       { 
        // s+= read one more line 
        if (i == lines.Length - 1) // no next line 
        { 
         pendingData = line + "\r\n" + pendingData; // unread the line 
         continue; 
        } 
        string line2 = lines[++i]; 
        NihLog.Write(NihLog.Level.Debug, "RX " + line); 
        NihLog.Write(NihLog.Level.Debug, "RX " + line2); 
        InboundSMS sms = new InboundSMS(); 
        sms.ParseCMT(line, line2); 
        if(OnNewSMS != null) 
         OnNewSMS(sms); 
       } 
       else // Not a composite 
        NihLog.Write(NihLog.Level.Debug, "RX " + line); 

       if (line == "OK") 
       { 
        OnModemResponse(true); 
       } 
       else if (line == "ERROR") 
       { 
        OnModemResponse(false); 
        NihLog.Write(NihLog.Level.Error, "Modem error"); 
       } 
      } 
     } 

     private void ProcessSmsResult(bool ok) 
     { 
      if (!ok) 
      { 
       OutboundSMS sms = _outSmses.Peek(); 
       if (sms.Attempt < sms.MaxTries) 
       { 
        NihLog.Write(NihLog.Level.Info, "Retrying sms..."); 
        return; 
       } 

       NihLog.Write(NihLog.Level.Error, "Failed to send SMS: " + sms.ToString()); 
      } 

      _outSmses.Dequeue(); 
     } 

     private void OnModemResponse(bool ok) 
     { 
      if (CurrentModemState == ModemState.SendingSMS) 
       ProcessSmsResult(ok); 

      if (!ok) 
      { 
       NihLog.Write(NihLog.Level.Error, "Error during state " + CurrentModemState.ToString()); 
       CurrentModemState = ModemState.Error; 
       return; 
      } 

      switch (CurrentModemState) 
      { 
       case ModemState.NotInitialized: 
        return; 

       case ModemState.PowerUp: 
        WriteToModem("ATE0;+CMGF=1;+CSCS=\"IRA\";+CNMI=1,2\r"); 
        CurrentModemState = ModemState.Initializing; 
        break; 

       case ModemState.Initializing: 
       case ModemState.SendingSMS: 
       case ModemState.KeepAliveAwaitingResponse: 
        CurrentModemState = ModemState.Idle; 
        break; 
      } 
     } 

     private void CloseU9TelitNativeApp() 
     { 
      bool doneSomething; 

      do 
      { 
       doneSomething = false; 

       Process[] processes = Process.GetProcessesByName("wirelesscard"); 
       foreach (Process p in processes) 
       { 
        p.CloseMainWindow(); 
        doneSomething = true; 
        NihLog.Write(NihLog.Level.Info, "Killed native U9 app"); 
        System.Threading.Thread.Sleep(1000); // Will not wait if no native app is started 
       } 
      } while (doneSomething); 
     } 

     void WriteToModem(string s) 
     { 
      modemPort.Write(s); 
      NihLog.Write(NihLog.Level.Debug, "TX " + s); 
     } 

     void UninitModem() 
     { 
      if (modemPort != null) 
       modemPort.Dispose(); 
      modemPort = null; 
      CurrentModemState = ModemState.NotInitialized; 
     } 

     private bool IsTransitionalState(ModemState ms) 
     { 
      return ms == ModemState.Initializing 
       || ms == ModemState.SendingSMS 
       || ms == ModemState.PowerUp 
       || ms == ModemState.KeepAliveAwaitingResponse; 
     } 

     Timeouter _initFailureTimeout = 
      new Timeouter(timeout_s: 10, autoReset:false, timedOut:true); 

     void TryInitModem() 
     { 
      // Try pistoning the modem with higher frequency. This does no harm (such as redundant logging) 
      PrepareU9Modem(); // Will do nothing if modem is okay 

      if (!_initFailureTimeout.IsTimedOut()) 
       return; // Don't try too frequently 

      if (modemPort != null) 
       return; 

      const string modemPortName = "Basecom HS-USB NMEA 9000"; 
      const int speed = 115200; 

      string portName = Hardware.Misc.SerialPortFromFriendlyName(modemPortName); 
      if (portName == null) 
      { 
       NihLog.Write(NihLog.Level.Error, "Modem not found (yet). "); 
       _initFailureTimeout.Reset(); 
       return; 
      } 

      NihLog.Write(NihLog.Level.Info, string.Format("Found modem port \"{0}\" at {1}", modemPortName, portName)); 
      modemPort = new System.IO.Ports.SerialPort(portName, speed); 
      modemPort.ReadTimeout = 3000; 
      modemPort.NewLine = "\r\n"; 

      modemPort.Open(); 

      modemPort.DiscardInBuffer(); 
      modemPort.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(delegate { _mainThreadOwnder.Invoke(dataReceivedDelegate); }); // called in different thread! 

      _lastModemKeepAlive = new Timeouter(60, true); 

      WriteToModem("AT+CFUN=1\r"); 
      CurrentModemState = ModemState.PowerUp; 
     } 

     void CheatU9Telit() 
     { 
      // U9 telit appears as USB CDrom on the bus, until disk eject is sent. 
      // Then, it reappears as normal stuff. 

      VolumeDeviceClass volumeDeviceClass = new VolumeDeviceClass(); 
      foreach (Volume device in volumeDeviceClass.Devices) 
      { 
       if (device.FriendlyName == "PCL HSUPA Modem USB Device") 
       { 
        NihLog.Write(NihLog.Level.Info, "Trying to initialize: " + device.FriendlyName); 
        device.EjectCDRomNoUI(); 
       } 
      } 
     } 

     void PrepareU9Modem() 
     { 
      CloseU9TelitNativeApp(); // Closes the autorun native app 
      CheatU9Telit(); 
     } 
    } 

    public class OutboundSMS 
    { 
     public string Destination; 
     public string Text; 
     public int MaxTries; 
     public int Attempt = 0; 

     public OutboundSMS(string dest, string txt) 
     { 
      Destination = dest; 
      Text = txt; 
      MaxTries = 3; 
     } 

     override public string ToString() 
     { 
      if(Attempt > 1) 
       return string.Format("\"{0}\" to {1}, attempt {2}", 
        Text, Destination, Attempt); 
      else 
       return string.Format("\"{0}\" to {1}", 
        Text, Destination); 
     } 
    } 

    public class InboundSMS 
    { 
     public string SourcePhone; 
     public DateTime ReceiveTime; 
     public string Text; 

     public void ParseCMT(string line1, string line2) 
     { 
      string[] fields = line1.Split(new char[] { ',', ' ', '/', ':', '"' }); 
      if (fields.Length < 12) 
       throw new ApplicationException("CMT message too short. Expected 2 fields"); 

      SourcePhone = fields[3]; 
      ReceiveTime = DateTime.Parse("20" + fields[7] + "-" + fields[8] + "-" + fields[9] + " " + fields[10] + ":" + fields[11] + ":" + fields[12].Substring(0, 2)); //test carefully 
      Text = line2; 
     } 
    }; 
} 

esempio di utilizzo in un'applicazione WinForms:

Hardware.TeliaModem _modem; 

public Form1() 
{ 
    InitializeComponent(); 

    _modem = new Hardware.TeliaModem(this); 

    _modem.OnNewSMS += new Hardware.TeliaModem.NewSmsHandler(ProcessNewSMS); 

     _timer.Interval = 1000; // milliseconds 
     _timer.Tick += new EventHandler(OnTimerTick); 
     _timer.Start(); 
} 

Per inviare uno SMS:

 _modem.SendSMS(sms.SourcePhone, "Aircon is now " + BoolToString.ON_OFF(_aircon.On)); 

Su evento timer, una volta al secondo:

private void OnTimerTick(object o, EventArgs e) 
{ 
    _modem.HeartBeat(); 
} 

Questa è registrata come gestore timer Winforms, in modo che il modem non avrà un thread.

Alcune classi di utilità utilizzate:

namespace Utils 
{ 
    public class StopWatch 
    { 
     protected DateTime _resetTime; 

     public StopWatch() { Reset(); } 
     public void Reset() { _resetTime = DateTime.Now; } 
     public double TotalSeconds { get { return (DateTime.Now - _resetTime).TotalSeconds; } } 
     public TimeSpan Time { get { return DateTime.Now - _resetTime; } } 
    }; 

    public class Timeouter : StopWatch 
    { 
     private bool _autoReset; 
     private double _timeout_s; 

     public Timeouter(double timeout_s, bool autoReset, bool timedOut = false) 
     { 
      _timeout_s = timeout_s; 
      _autoReset = autoReset; 

      if (timedOut) 
       _resetTime -= TimeSpan.FromSeconds(_timeout_s + 1); // This is surely timed out, as requested 
     } 

     public bool IsTimedOut() 
     { 
      if (_timeout_s == double.PositiveInfinity) 
       return false; 

      bool timedout = this.TotalSeconds >= _timeout_s; 

      if (timedout && _autoReset) 
       Reset(); 

      return timedout; 
     } 

     public void Reset(double timeout_s) { _timeout_s = timeout_s; Reset(); } 
     public double TimeLeft { get { return _timeout_s - TotalSeconds; } } 
    } 
} 

ho implementato questo al fine di attivare il condizionatore d'aria con SMS (sì, io vivo in un paese caldo). Funziona. Sentiti libero di usare qualsiasi di questo codice.

Divertiti.

+0

download e compilazione, se si desidero: http://dl.dropbox.com/u/616350/out/aircon%20r75.rar (soluzione VS2010 completa in C#) –

+0

spasibo bolshoe, pensi che funzionerà con il mio telefono tmobile? è collegato tramite USB –

+1

Penso che dovrebbe .. I comandi AT dovrebbero essere gli stessi. In caso contrario, sono ansioso di sapere perché e di correggere il codice. –

0

Microsoft fornisce un esempio abbastanza decente VB.Net in un articolo KB "How to access serial and parallel ports by using Visual Basic .NET". Non sono sicuro di quello che le vostre dichiarazioni del telefono, tuttavia, se si modifica il ciclo buffer nel esempio, si può almeno stampare la risposta:

MSComm1.Output = "AT" & Chr(13) 
Console.WriteLine("Send the attention command to the modem.") 
Console.WriteLine("Wait for the data to come back to the serial port...") 
' Make sure that the modem responds with "OK". 
' Wait for the data to come back to the serial port. 
Do 
    Buffer = Buffer & MSComm1.Input 
    Console.WriteLine("Found: {0}", Buffer) 
Loop Until InStr(Buffer, "OK" & vbCrLf) 
0

GSMComm è una libreria C# che consente di interagire facilmente con un cellulare GSM in modalità testo o PDU. (Il sito ha anche un sacco di utility di test)

-1

Lavorare con il modem GSM per inviare SMS non è mai stata una buona idea in quanto tale. Ecco una lista di controllo per assicurarti che il tuo SMS sia inviato correttamente.

  • Si sta inviando l'SMS in modalità testo. Prova a inviarlo in modalità PDU.
  • Prova questa libreria http://phonemanager.codeplex.com/
  • si fa a cambiare numero SMSC prima di inviare l'SMS, se in modo da assicurarsi lo SMSC è corretta.
  • Assicurati inoltre che la tua carta SIM abbia abbastanza crediti per consentire l'invio di SMS in uscita.
  • Verificare lo stato della rete soprattutto quando si inviano SMS dal programma. Questo potrebbe essere un problema.

vi consiglio di checkout la Lite edition of NowSMS gateway che viene fornito gratuitamente e consente di lavorare con modem GSM molto continently. NowSMS ti darà l'astrazione api su una connessione modem GSM, quindi dovrai solo chiamare l'Http Api del gateway NowSMS, il resto sarà curato dal gateway NowSMS.

Soprattutto, se gli utenti finali rimarranno connessi a Internet durante l'utilizzo dell'applicazione o se la tua applicazione è basata sul Web e ospitata su Internet, mi raccomando con urgenza di eliminare l'opzione modem GSM e opt- in per provider di servizi di gateway SMS Http affidabili.

Problemi correlati