-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathSmsSender.cs
243 lines (209 loc) · 7.96 KB
/
SmsSender.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
//-----------------------------------------------------------------------
// <copyright file="SmsSender.cs" company="https://github.com/marcogrcr/NET-SMS-Sender">
// License of use:
//
// 1. You may use and modify this file as you see fit.
// 2. Please credit the original author by preserving this header :)
// </copyright>
//-----------------------------------------------------------------------
namespace NetSmsSender
{
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO.Ports;
using System.Threading;
/// <summary>
/// Sends SMS messages by issuing AT commands on a serial port.
/// </summary>
/// <remarks>
/// For more information see:
/// http://circuitfreak.blogspot.com/2013/03/c-programming-sending-sms-using-at.html
/// https://github.com/CircuitFreakCoder/CSharp_SMS
/// http://mobiletidings.com/2009/01/12/sending-out-an-sms-in-pdu-mode/
/// http://developer.nokia.com/Community/Discussion/showthread.php/21237-CMS-ERROR-301-problem
/// http://www.developershome.com/sms/resultCodes2.asp
/// </remarks>
public sealed class SmsSender : IDisposable
{
/// <summary>
/// The baud rate of the serial port.
/// </summary>
private const int BaudRate = 115200;
/// <summary>
/// The initial sleep time after opening the serial port.
/// </summary>
private const int InitialSleepTime = 500;
/// <summary>
/// The PDU formatted SMS messages to send.
/// </summary>
private IEnumerable<PduSmsMessage> pduMessages;
/// <summary>
/// The serial port.
/// </summary>
private SerialPort port;
/// <summary>
/// Initializes a new instance of the <see cref="SmsSender" /> class.
/// </summary>
/// <param name="portName">The name of the serial port.</param>
/// <param name="countryCode">The number's country code.</param>
/// <param name="localNumber">The number in local format.</param>
/// <param name="text">The text to send.</param>
public SmsSender(string portName, short countryCode, long localNumber, string text)
{
if (string.IsNullOrWhiteSpace(portName))
{
throw new ArgumentException("A port name must be specified.", "portName");
}
if (string.IsNullOrWhiteSpace(text))
{
throw new ArgumentNullException("text", "A text must be specified.");
}
// Port creation.
this.port = new SerialPort(portName, SmsSender.BaudRate);
this.port.DataReceived += this.DataReceived;
// Number composition.
var numberOfDigits = localNumber.ToString(CultureInfo.InvariantCulture).Length;
var fullNumber = ((long)(countryCode * Math.Pow(10, numberOfDigits))) + localNumber;
this.pduMessages = text.Length <= PduSmsMessage.MaximumSmsTextLength ? new[] { new PduSmsMessage(fullNumber, text) } : PduSmsMessage.GetConcatenatedMessages(fullNumber, text);
}
/// <summary>
/// Gets or sets a value indicating whether debug mode is activated.
/// </summary>
public static bool Debug { get; set; }
/// <summary>
/// Closes the serial port.
/// </summary>
public void Dispose()
{
if (this.port != null)
{
this.port.Dispose();
}
}
/// <summary>
/// Sends the SMS message.
/// </summary>
public void Send()
{
lock (this.port)
{
this.OpenPort();
this.SetPduMode();
foreach (var pduMessage in this.pduMessages)
{
this.SetSize(pduMessage);
this.SetContent(pduMessage);
}
}
}
/// <summary>
/// Notifies waiting threads that there is data available.
/// </summary>
private void DataReceived(object sender, SerialDataReceivedEventArgs e)
{
lock (this.port)
{
Monitor.Pulse(this.port);
}
}
/// <summary>
/// Blocking call that returns a non-null/non-empty response from the serial port.
/// </summary>
private string GetPortResponse()
{
string result;
do
{
Monitor.Wait(this.port);
}
while (string.IsNullOrWhiteSpace(result = this.port.ReadExisting()));
return result;
}
/// <summary>
/// Opens the serial port.
/// </summary>
private void OpenPort()
{
this.port.Open();
Thread.Sleep(SmsSender.InitialSleepTime);
}
/// <summary>
/// Sets the PDU formatted SMS message content.
/// </summary>
/// <param name="pduMessage">The PDU formatted SMS message to send.</param>
private void SetContent(PduSmsMessage pduMessage)
{
// Set the content.
this.port.Write(string.Format(CultureInfo.InvariantCulture, "{0}\x1A", pduMessage));
// Validate response.
while (true)
{
var response = this.GetPortResponse();
if (response.IndexOf("ERROR", StringComparison.OrdinalIgnoreCase) != -1)
{
throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Got error response '{0}'.", response));
}
if (SmsSender.Debug)
{
Console.WriteLine("SetContent() got response: '{0}'.", response.Trim());
}
if (response.IndexOf("+CMGS:", StringComparison.OrdinalIgnoreCase) != -1)
{
break;
}
}
}
/// <summary>
/// Sets the mode to PDU.
/// </summary>
private void SetPduMode()
{
// Set the mode.
this.port.Write("AT+CMGF=0\r\n");
// Validate response.
while (true)
{
var response = this.GetPortResponse();
if (response.IndexOf("ERROR", StringComparison.OrdinalIgnoreCase) != -1)
{
throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Got error response '{0}'.", response));
}
if (SmsSender.Debug)
{
Console.WriteLine("SetContent() got response: '{0}'.", response.Trim());
}
if (response.IndexOf("OK", StringComparison.OrdinalIgnoreCase) != -1)
{
break;
}
}
}
/// <summary>
/// Sets the size of the PDU.
/// </summary>
/// <param name="pduMessage">The PDU formatted SMS message to send.</param>
private void SetSize(PduSmsMessage pduMessage)
{
// Set the size.
this.port.Write(string.Format(CultureInfo.InvariantCulture, "AT+CMGS={0}\r\n", pduMessage.Length));
// Validate response.
while (true)
{
var response = this.GetPortResponse();
if (response.IndexOf("ERROR", StringComparison.OrdinalIgnoreCase) != -1)
{
throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Got error response '{0}'.", response));
}
if (SmsSender.Debug)
{
Console.WriteLine("SetContent() got response: '{0}'.", response.Trim());
}
if (response.IndexOf(">", StringComparison.OrdinalIgnoreCase) != -1)
{
break;
}
}
}
}
}