Skip to content

Commit 07371fe

Browse files
committed
reading messages
1 parent 643bc7e commit 07371fe

6 files changed

Lines changed: 311 additions & 10 deletions

File tree

SmsTools/Commands/ATCommand.cs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,33 @@ public enum ATCommand
7676
/// AT+CMGS=
7777
/// </summary>
7878
[ATCommand(Command = "AT+CMGS=", HasParameters = true, HasSteps = true)]
79-
MessageSend
79+
MessageSend,
80+
81+
/// <summary>
82+
/// AT+CPMS?
83+
/// </summary>
84+
[ATCommand(Command = "AT+CPMS?")]
85+
MessageStorageInfo,
86+
/// <summary>
87+
/// AT+CPMS=
88+
/// </summary>
89+
[ATCommand(Command = "AT+CPMS=", HasParameters = true)]
90+
MessageStorage,
91+
92+
/// <summary>
93+
/// AT+CMGL=
94+
/// </summary>
95+
[ATCommand(Command = "AT+CMGL=", HasParameters = true)]
96+
MessageList,
97+
/// <summary>
98+
/// AT+CMGR=
99+
/// </summary>
100+
[ATCommand(Command = "AT+CMGR=", HasParameters = true)]
101+
MessageRead,
102+
/// <summary>
103+
/// AT+CMGD=
104+
/// </summary>
105+
[ATCommand(Command = "AT+CMGD=", HasParameters = true)]
106+
MessageDelete
80107
}
81108
}

SmsTools/Constants.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.ComponentModel;
34
using System.Linq;
45
using System.Text;
56
using System.Threading.Tasks;
@@ -37,5 +38,27 @@ public enum MessageFormat
3738
{
3839
Pdu, Text
3940
}
41+
42+
public enum MessageStorage
43+
{
44+
Unspecified,
45+
[Description("\"MT\"")]
46+
MobileAssociated,
47+
[Description("\"ME\"")]
48+
MobileEquipment,
49+
[Description("\"SM\"")]
50+
Sim,
51+
[Description("\"SR\"")]
52+
StateReport
53+
}
54+
55+
public enum MessageStatus
56+
{
57+
Unread,
58+
Read,
59+
Unsent,
60+
Sent,
61+
Any
62+
}
4063
}
4164
}

SmsTools/Extensions.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using SmsTools.Commands;
22
using System;
33
using System.Collections.Generic;
4+
using System.ComponentModel;
45
using System.Linq;
56
using System.Text;
67
using System.Threading.Tasks;
@@ -34,5 +35,17 @@ public static string ToValueString(this Enum value)
3435
return Convert.ToInt32(value).ToString();
3536
}
3637

38+
public static string Description(this Enum value)
39+
{
40+
return value.GetEnumAttributeValue<DescriptionAttribute, string>(a => a.Description);
41+
}
42+
43+
public static Constants.MessageStorage ToMessageStorage(this string value)
44+
{
45+
if (string.IsNullOrWhiteSpace(value))
46+
return Constants.MessageStorage.Unspecified;
47+
48+
return Enum.GetValues(typeof(Constants.MessageStorage)).Cast<Constants.MessageStorage>().FirstOrDefault(e => e.Description().Equals(value));
49+
}
3750
}
3851
}

SmsTools/MessageStorage.cs

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
using SmsTools.Commands;
2+
using SmsTools.Operations;
3+
using SmsTools.PduProfile;
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using System.Text;
8+
using System.Text.RegularExpressions;
9+
using System.Threading.Tasks;
10+
11+
namespace SmsTools
12+
{
13+
public class MessageStorage
14+
{
15+
private PduProfileManager _manager = new PduProfileManager();
16+
private ICommandParameter _empty = null;
17+
private IATCommand _storageQuery = null;
18+
private IATCommand _listQuery = null;
19+
private IATCommand _mfCmd = null;
20+
21+
22+
public MessageStorage()
23+
{
24+
init();
25+
}
26+
27+
private void init()
28+
{
29+
_empty = CommandParameter.CreateEmpty(Constants.BasicSuccessfulResponse);
30+
_storageQuery = new SimpleATCommand(ATCommand.MessageStorageInfo.Command(), _empty);
31+
32+
var listParam = new CommandParameter(Constants.MessageStatus.Any.ToValueString(), Constants.BasicSuccessfulResponse);
33+
_listQuery = new ParamATCommand(ATCommand.MessageList.Command(), listParam);
34+
35+
var mfParam = new CommandParameter(Constants.MessageFormat.Pdu.ToValueString(), Constants.BasicSuccessfulResponse);
36+
_mfCmd = new ParamATCommand(ATCommand.MessageFormat.Command(), mfParam);
37+
}
38+
39+
public async Task<bool> SelectStorage(IPortPlug port, Constants.MessageStorage readStore = Constants.MessageStorage.MobileEquipment, Constants.MessageStorage writeStore = Constants.MessageStorage.Unspecified, Constants.MessageStorage receivedStore = Constants.MessageStorage.Unspecified)
40+
{
41+
if (readStore == Constants.MessageStorage.Unspecified)
42+
return false;
43+
44+
var storageParam = new CommandParameter(getStorageParam(readStore, writeStore, receivedStore), Constants.BasicSuccessfulResponse);
45+
var storageCmd = new ParamATCommand(ATCommand.MessageStorage.Command(), storageParam);
46+
47+
await storageCmd.ExecuteAsync(port);
48+
49+
return storageCmd.Succeeded();
50+
}
51+
52+
public async Task<IEnumerable<MessageStorageState>> StorageState(IPortPlug port)
53+
{
54+
var result = Enumerable.Empty<MessageStorageState>();
55+
56+
await _storageQuery.ExecuteAsync(port);
57+
if (_storageQuery.Succeeded())
58+
{
59+
result = getStorageState(_storageQuery.Response);
60+
}
61+
62+
return result;
63+
}
64+
65+
public async Task<IEnumerable<MessageStorageItem>> List(IPortPlug port)
66+
{
67+
var result = Enumerable.Empty<MessageStorageItem>();
68+
69+
if (await setFormat(port))
70+
{
71+
await _listQuery.ExecuteAsync(port);
72+
if (_listQuery.Succeeded())
73+
{
74+
result = getStorageItems(_listQuery.Response);
75+
}
76+
}
77+
78+
return result;
79+
}
80+
81+
public async Task<MessageInfo> Read(IPortPlug port, MessageStorageItem item)
82+
{
83+
MessageInfo result = new MessageInfo();
84+
85+
if (item == null || !item.IsValid || !_manager.ContainsProfile("default-receive"))
86+
return result;
87+
88+
if (await setFormat(port))
89+
{
90+
var readParam = new CommandParameter(item.Index.ToString(), Constants.BasicSuccessfulResponse);
91+
var readCmd = new ParamATCommand(ATCommand.MessageRead.Command(), readParam);
92+
93+
await readCmd.ExecuteAsync(port);
94+
if (readCmd.Succeeded())
95+
{
96+
result = getMessage(readCmd.Response);
97+
}
98+
}
99+
100+
return result;
101+
}
102+
103+
104+
private MessageInfo getMessage(string response)
105+
{
106+
MessageInfo result = new MessageInfo();
107+
108+
try
109+
{
110+
var lengthMatch = Regex.Match(response, @"^\S*(?:cmgr:.+,(\d+)\s*)$", RegexOptions.IgnoreCase | RegexOptions.Multiline);
111+
var pduMatch = Regex.Match(response, @"^(?:\s*([a-fA-F0-9]+)\s*)$", RegexOptions.IgnoreCase | RegexOptions.Multiline);
112+
113+
if (lengthMatch.Success && lengthMatch.Groups.Count > 1 && pduMatch.Success && pduMatch.Groups.Count > 1)
114+
{
115+
int length = int.Parse(lengthMatch.Groups[1].Value.Trim());
116+
string pdu = pduMatch.Groups[1].Value.Trim();
117+
118+
var profile = _manager["default-receive"];
119+
120+
result = profile.GetMessage(pdu, length);
121+
}
122+
}
123+
catch { }
124+
125+
return result;
126+
}
127+
128+
private IEnumerable<MessageStorageItem> getStorageItems(string response)
129+
{
130+
var result = Enumerable.Empty<MessageStorageItem>();
131+
132+
try
133+
{
134+
var matches = Regex.Matches(response, @"^\S*(?:cmgl:(.+))$", RegexOptions.IgnoreCase | RegexOptions.Multiline);
135+
if (matches.Count > 0)
136+
{
137+
var items = new List<MessageStorageItem>();
138+
139+
for (int m = 0; m < matches.Count; ++m)
140+
{
141+
var match = matches[m];
142+
if (!match.Success || match.Groups.Count < 2)
143+
throw new Exception();
144+
145+
var itemValue = match.Groups[1].Value.Trim();
146+
var itemValues = itemValue.Split(',');
147+
int value = 0;
148+
if (itemValues.Length < 3 || itemValues.Any(v => !int.TryParse(v, out value)))
149+
throw new Exception();
150+
151+
var item = itemValues.Select(v => int.Parse(v)).ToArray();
152+
153+
items.Add(new MessageStorageItem() { Index = item[0], Status = (Constants.MessageStatus)item[1], Length = item.Last() });
154+
}
155+
156+
result = items;
157+
}
158+
}
159+
catch { }
160+
161+
return result;
162+
}
163+
164+
private IEnumerable<MessageStorageState> getStorageState(string response)
165+
{
166+
var result = Enumerable.Empty<MessageStorageState>();
167+
168+
try
169+
{
170+
var state = Regex.Match(response, $@"(?:cpms:(.+){Constants.BasicSuccessfulResponse})", RegexOptions.IgnoreCase);
171+
if (state.Success && state.Groups.Count > 1)
172+
{
173+
var stateValue = state.Groups[1].Value.Trim();
174+
var stateValues = stateValue.Split(',');
175+
if (stateValues.Length % 3 == 0 && stateValues.All(s => !string.IsNullOrWhiteSpace(s)))
176+
{
177+
var storages = new List<MessageStorageState>();
178+
179+
for (int i = 0; i < stateValues.Length; i += 3)
180+
{
181+
var storageValue = stateValues[i];
182+
var countValue = stateValues[i + 1];
183+
var limitValue = stateValues[i + 2];
184+
185+
int count = 0, limit = 0;
186+
if (!int.TryParse(countValue, out count) || !int.TryParse(limitValue, out limit))
187+
throw new Exception();
188+
189+
storages.Add(new MessageStorageState() { Storage = storageValue.ToMessageStorage(), Count = count, Limit = limit });
190+
}
191+
192+
result = storages;
193+
}
194+
}
195+
}
196+
catch { }
197+
198+
return result;
199+
}
200+
201+
private string getStorageParam(Constants.MessageStorage readStore, Constants.MessageStorage writeStore, Constants.MessageStorage receivedStore)
202+
{
203+
var param = new StringBuilder(readStore.Description());
204+
205+
if (writeStore != Constants.MessageStorage.Unspecified)
206+
{
207+
param.Append(",").Append(writeStore.Description());
208+
}
209+
210+
if (receivedStore != Constants.MessageStorage.Unspecified)
211+
{
212+
param.Append(",").Append(receivedStore.Description());
213+
}
214+
215+
return param.ToString();
216+
}
217+
218+
private async Task<bool> setFormat(IPortPlug port)
219+
{
220+
await _mfCmd.ExecuteAsync(port);
221+
return _mfCmd.Succeeded();
222+
}
223+
}
224+
225+
226+
public class MessageStorageState
227+
{
228+
public Constants.MessageStorage Storage { get; set; }
229+
public int Count { get; set; }
230+
public int Limit { get; set; }
231+
public bool IsFull { get { return Count == Limit; } }
232+
public bool IsEmpty { get { return Count == 0; } }
233+
}
234+
235+
public class MessageStorageItem
236+
{
237+
public int Index { get; set; }
238+
public Constants.MessageStatus Status { get; set; }
239+
public int Length { get; set; }
240+
public bool IsValid { get { return Index >= 0 && Length >= 0; } }
241+
}
242+
}

SmsTools/Operations/SerialPortPlug.cs

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -88,18 +88,13 @@ private void _port_DataReceived(object sender, SerialDataReceivedEventArgs e)
8888
{
8989
_buffer.Append((sender as SerialPort).ReadExisting());
9090

91-
if (e.EventType == SerialData.Eof)
91+
if (e.EventType == SerialData.Eof
92+
|| (e.EventType == SerialData.Chars
93+
&& (Regex.IsMatch(_buffer.ToString(), @"\s*(ok|>)\s*$", RegexOptions.IgnoreCase)
94+
|| Regex.IsMatch(_buffer.ToString(), @"error", RegexOptions.IgnoreCase))))
9295
{
9396
_wait.Set();
9497
}
95-
else if (e.EventType == SerialData.Chars)
96-
{
97-
if (Regex.IsMatch(_buffer.ToString(), @"\s*(ok|>)\s*$", RegexOptions.IgnoreCase)
98-
|| Regex.IsMatch(_buffer.ToString(), @"error", RegexOptions.IgnoreCase))
99-
{
100-
_wait.Set();
101-
}
102-
}
10398
}
10499

105100
private void _port_ErrorReceived(object sender, SerialErrorReceivedEventArgs e)

SmsTools/SmsTools.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
<Compile Include="Commands\ICommandParameter.cs" />
5555
<Compile Include="Commands\ParamATCommand.cs" />
5656
<Compile Include="Commands\SimpleATCommand.cs" />
57+
<Compile Include="MessageStorage.cs" />
5758
<Compile Include="Operations\IPortPlug.cs" />
5859
<Compile Include="Operations\SerialPortPlug.cs" />
5960
<Compile Include="Operations\SerialPortConfig.cs" />

0 commit comments

Comments
 (0)