用于 GSM 调制解调器设备的串行端口 AT 命令不在循环中工作
Serial Port AT Commands for GSM Modem Device not working on loop
我目前一直致力于通过 GSM 调制解调器设备发送 SMS 消息的 .net 项目。我可以很好地发送单个 SMS 消息,但是当我开始循环 AT 命令以向多个收件人发送 SMS 时,应用程序的行为变得非常笨拙。有时它只能将 SMS 发送给它能找到的第一个收件人,大多数情况下根本 none。
以下是我向多个收件人发送短信的方法的源代码:
String MessageBody = String.Format("Everyone,\n\nEquipment Current Reading: {0} tph\nCurrent Status: {1}\n\n".Replace("\n",Environment.NewLine), CurrentValue, EqValue);
SerialPort SP = new SerialPort();
SP.PortName = "COM3";
using (TestEntities TE = new TestEntities())
{
List<vwRecipient_MasterList> RecipientList = TE.vwRecipient_MasterList.Where(r => r.Group_id == R_Group).Select(r => r).ToList();
foreach (vwRecipient_MasterList Recipient in RecipientList)
{
SP.Open();
String formattedRecipientNo = Char.ConvertFromUtf32(34) + Recipient.MobileNo + Char.ConvertFromUtf32(34);
SP.Write("AT+CMGF=1" + Char.ConvertFromUtf32(13));
SP.Write("AT+CMGS=" + formattedRecipientNo + Char.ConvertFromUtf32(13));
SP.Write(MessageBody + Char.ConvertFromUtf32(26) + Char.ConvertFromUtf32(13));
SP.Close();
}
}
所以我根据 MSDN 参考资料(针对串行端口)和 SO 上的一些文章对如何使用串行端口 class 做了更多的研究,我想出了这个非正统的解决方案涉及使用由 SerialPort class 提供的 SerialDataReceivedEventHandler 和无限 while 循环。
首先,我在 class 范围内创建了两个属性,它们对 SendSMS(WebMethod) 和 DataRecieved(Event) 的两种方法都可见:
// Holds the text output from the SerialPort
public string spReadMsg { get; set; }
// Used as a fail-safe terminator of the infinite loop used in the Web Method.
public DateTime executionTime { get; set; }
下面是DataRecievedHandler事件。基本上,所有此事件所做的就是将来自 SerialPort 的文本响应存储在 SendSMS 方法
的 spReadMsg 属性 中
private void DataRecievedHandler(object sender, SerialDataReceivedEventArgs e)
{
try
{
SerialPort sp = (SerialPort)sender;
string indata = sp.ReadExisting();
Debug.Print("Data Received:");
Debug.Print(indata);
// Store to class scope property spReadMsg for the sendSMS method to read.
spReadMsg = indata;
}
catch (Exception ex)
{
Debug.Print(ex.Message);
}
}
最后,我在我的 Web 方法中添加了几行代码,以便在成功发送所需的 SMS 消息响应时侦听 DataRecieved 事件。
根据这篇关于对调制解调器设备使用 AT 命令的文章:http://www.smssolutions.net/tutorials/gsm/sendsmsat。
SerialPort 应该 return 一个 +CMGS: # 响应来标识消息发送已经完成。
所以我所要做的就是等待 +CMGS: 响应,这将使程序知道消息已发送并准备好将下一条消息发送到下一个收件人。我使用无限 while 循环为 Web 方法制作了一个临时监听器,一旦从串行端口读取响应 +CMGS: 或需要超过 30 秒才能获取响应,该循环就会终止所需的响应。
[WebMethod]
public void sendSMSMessage_inHouse(String Recipients, String MessageBody)
{
String sanitizedRecipient = Recipients.Replace(" ", "");
var RecipientList = Recipients.Split(',').ToList();
String sanitizedMessage = MessageBody.Replace(@"\n", Environment.NewLine);
SerialPort SP = new SerialPort();
SP.PortName = "COM3";
SP.DataReceived += new SerialDataReceivedEventHandler(DataRecievedHandler);
SP.Open();
// Initally set property to the "condtion" value to allow first message to be
// run without the datarecieved response from the serial port
spReadMsg = "+CMGS:";
// Set executionTime inital value for comparison
executionTime = DateTime.Now;
foreach (String Recipient in RecipientList)
{
// Infinite Loop listens to the response from the serial port
while (true)
{
// If the +CMGS: response was recieved continue with the next message
// Use Contains comparison for substring check since some of the +CMGS: responses
// contain carriage return texts along with the repsonse
// Then empty the spReadMsg property to avoid the loop from prematurely
//sending the next message when the latest serial port response has not yet been
//updated from the '+CMGS:' response
if (!string.IsNullOrEmpty(spReadMsg) && spReadMsg.Contains("+CMGS:"))
{
spReadMsg = string.Empty;
break;
}
// If takes longer than 30 seconds to get the response since the last sent
//message - break.
if (DateTime.Now > executionTime.AddSeconds(30))
{
break;
}
}
// Once the while loop breaks proceed with sending the next message.
String formattedRecipientNo = Char.ConvertFromUtf32(34) + Recipient + Char.ConvertFromUtf32(34);
SP.Write("AT+CMGF=1" + Char.ConvertFromUtf32(13));
//Thread.Sleep(800);
SP.Write("AT+CMGS=" + formattedRecipientNo + Char.ConvertFromUtf32(13));
//Thread.Sleep(800);
SP.Write(sanitizedMessage + Char.ConvertFromUtf32(26) + Char.ConvertFromUtf32(13));
//Thread.Sleep(1000);
//Thread.Sleep(2000);
// Get the Datetime when the current message was sent for comparison in
// the next while loop
executionTime = DateTime.Now;
}
SP.Close();
}
我目前一直致力于通过 GSM 调制解调器设备发送 SMS 消息的 .net 项目。我可以很好地发送单个 SMS 消息,但是当我开始循环 AT 命令以向多个收件人发送 SMS 时,应用程序的行为变得非常笨拙。有时它只能将 SMS 发送给它能找到的第一个收件人,大多数情况下根本 none。
以下是我向多个收件人发送短信的方法的源代码:
String MessageBody = String.Format("Everyone,\n\nEquipment Current Reading: {0} tph\nCurrent Status: {1}\n\n".Replace("\n",Environment.NewLine), CurrentValue, EqValue);
SerialPort SP = new SerialPort();
SP.PortName = "COM3";
using (TestEntities TE = new TestEntities())
{
List<vwRecipient_MasterList> RecipientList = TE.vwRecipient_MasterList.Where(r => r.Group_id == R_Group).Select(r => r).ToList();
foreach (vwRecipient_MasterList Recipient in RecipientList)
{
SP.Open();
String formattedRecipientNo = Char.ConvertFromUtf32(34) + Recipient.MobileNo + Char.ConvertFromUtf32(34);
SP.Write("AT+CMGF=1" + Char.ConvertFromUtf32(13));
SP.Write("AT+CMGS=" + formattedRecipientNo + Char.ConvertFromUtf32(13));
SP.Write(MessageBody + Char.ConvertFromUtf32(26) + Char.ConvertFromUtf32(13));
SP.Close();
}
}
所以我根据 MSDN 参考资料(针对串行端口)和 SO 上的一些文章对如何使用串行端口 class 做了更多的研究,我想出了这个非正统的解决方案涉及使用由 SerialPort class 提供的 SerialDataReceivedEventHandler 和无限 while 循环。
首先,我在 class 范围内创建了两个属性,它们对 SendSMS(WebMethod) 和 DataRecieved(Event) 的两种方法都可见:
// Holds the text output from the SerialPort
public string spReadMsg { get; set; }
// Used as a fail-safe terminator of the infinite loop used in the Web Method.
public DateTime executionTime { get; set; }
下面是DataRecievedHandler事件。基本上,所有此事件所做的就是将来自 SerialPort 的文本响应存储在 SendSMS 方法
的 spReadMsg 属性 中private void DataRecievedHandler(object sender, SerialDataReceivedEventArgs e)
{
try
{
SerialPort sp = (SerialPort)sender;
string indata = sp.ReadExisting();
Debug.Print("Data Received:");
Debug.Print(indata);
// Store to class scope property spReadMsg for the sendSMS method to read.
spReadMsg = indata;
}
catch (Exception ex)
{
Debug.Print(ex.Message);
}
}
最后,我在我的 Web 方法中添加了几行代码,以便在成功发送所需的 SMS 消息响应时侦听 DataRecieved 事件。
根据这篇关于对调制解调器设备使用 AT 命令的文章:http://www.smssolutions.net/tutorials/gsm/sendsmsat。 SerialPort 应该 return 一个 +CMGS: # 响应来标识消息发送已经完成。
所以我所要做的就是等待 +CMGS: 响应,这将使程序知道消息已发送并准备好将下一条消息发送到下一个收件人。我使用无限 while 循环为 Web 方法制作了一个临时监听器,一旦从串行端口读取响应 +CMGS: 或需要超过 30 秒才能获取响应,该循环就会终止所需的响应。
[WebMethod]
public void sendSMSMessage_inHouse(String Recipients, String MessageBody)
{
String sanitizedRecipient = Recipients.Replace(" ", "");
var RecipientList = Recipients.Split(',').ToList();
String sanitizedMessage = MessageBody.Replace(@"\n", Environment.NewLine);
SerialPort SP = new SerialPort();
SP.PortName = "COM3";
SP.DataReceived += new SerialDataReceivedEventHandler(DataRecievedHandler);
SP.Open();
// Initally set property to the "condtion" value to allow first message to be
// run without the datarecieved response from the serial port
spReadMsg = "+CMGS:";
// Set executionTime inital value for comparison
executionTime = DateTime.Now;
foreach (String Recipient in RecipientList)
{
// Infinite Loop listens to the response from the serial port
while (true)
{
// If the +CMGS: response was recieved continue with the next message
// Use Contains comparison for substring check since some of the +CMGS: responses
// contain carriage return texts along with the repsonse
// Then empty the spReadMsg property to avoid the loop from prematurely
//sending the next message when the latest serial port response has not yet been
//updated from the '+CMGS:' response
if (!string.IsNullOrEmpty(spReadMsg) && spReadMsg.Contains("+CMGS:"))
{
spReadMsg = string.Empty;
break;
}
// If takes longer than 30 seconds to get the response since the last sent
//message - break.
if (DateTime.Now > executionTime.AddSeconds(30))
{
break;
}
}
// Once the while loop breaks proceed with sending the next message.
String formattedRecipientNo = Char.ConvertFromUtf32(34) + Recipient + Char.ConvertFromUtf32(34);
SP.Write("AT+CMGF=1" + Char.ConvertFromUtf32(13));
//Thread.Sleep(800);
SP.Write("AT+CMGS=" + formattedRecipientNo + Char.ConvertFromUtf32(13));
//Thread.Sleep(800);
SP.Write(sanitizedMessage + Char.ConvertFromUtf32(26) + Char.ConvertFromUtf32(13));
//Thread.Sleep(1000);
//Thread.Sleep(2000);
// Get the Datetime when the current message was sent for comparison in
// the next while loop
executionTime = DateTime.Now;
}
SP.Close();
}