深圳市未来时代科技有限公司
标题:
c#实现wavecom短信收发设备发送长短信
[打印本页]
作者:
admin
时间:
2016-7-11 10:45
标题:
c#实现wavecom短信收发设备发送长短信
长短信是有规约的,协议头部分如果是0x40以下,则说明是普通短信,如果是0x40以上,则是长短信,然后在短信内容部分,有六个字节分别定义短信唯一标识以及该短信是第几条,所以长短信发送时每条实际为67个汉字。手机接收到之后,都会按照标准规约自动组合为一条短信,而不是显示多条。
我做了一个AT指令操作wavecom短信收发设备的类,可以接收和发送超长短信,并且接收到的短信会直接通知电脑。
超长短信:短信内容超过70个汉字,提交给网关时候需要分成多条,但是用户手机接收时候是一条(sp角度,手机发送长短信概念一样)。
在cmpp协议里,CMPP-_SUBMIT消息定义中有相应的参数配置:
TP_udhi :0代表内容体里不含有协议头信息 1代表内容含有协议头信息(长短信,push短信等都是在内容体上含有头内容的)当设置内容体包含协议头,需要根据协议写入相应的信息,长短信协议头有两种:
6位协议头格式:05 00 03 XX MM NN
byte 1 : 05, 表示剩余协议头的长度
byte 2 : 00, 这个值在GSM 03.40规范9.2.3.24.1中规定,表示随后的这批超长短信的标识位长度为1(格式中的XX值)。
byte 3 : 03, 这个值表示剩下短信标识的长度
byte 4 : XX,这批短信的唯一标志(被拆分的多条短信,此值必需一致),事实上,SME(手机或者SP)把消息合并完之后,就重新记录,所以这个标志是否唯
一并不是很 重要。
byte 5 : MM, 这批短信的数量。如果一个超长短信总共5条,这里的值就是5。
byte 6 : NN, 这批短信的数量。如果当前短信是这批短信中的第一条的值是1,第二条的值是2。
例如:05 00 03 39 02 01
7位的协议头格式:06 08 04 XX XX MM NN
byte 1 : 06, 表示剩余协议头的长度
byte 2 : 08, 这个值在GSM 03.40规范9.2.3.24.1中规定,表示随后的这批超长短信的标识位长度为2(格式中的XX值)。
byte 3 : 04, 这个值表示剩下短信标识的长度
byte 4-5 : XX XX,这批短信的唯一标志,事实上,SME(手机或者SP)把消息合并完之后,就重新记录,所以这个标志是否唯一并不是很重要。
byte 6 : MM, 这批短信的数量。如果一个超长短信总共5条,这里的值就是5。
byte 7 : NN, 这批短信的数量。如果当前短信是这批短信中的第一条的值是1,第二条的值是2。
例如:06 08 04 00 39 02 01
到此,长短信的发送设置基本完成,但是有一点要注意:Src_Id 协议里这个字段在一条长短信中必须要一样,不然手机会解析成三条,
并三条都 是错误短信。
对于sp来说,长短信上行,按照协议反过来解析:
1byte[] contentBytes = msg.getMsgContent();
2int headLen = contentBytes[0]; // 内容头的长度
3// 超长短信总条数
4int pk_total = contentBytes[headLen - 1];
5// 超长短信第几条
6int pk_num = contentBytes[headLen];
7// 超长短信序号
8byte serial = contentBytes[headLen - 2];
class DuanXin
{
public string phnum;
public string message;
public DuanXin()
{
}
public DuanXin(string ph, string msg)
{
phnum = ph;
message = msg;
}
}
class CDuanXin
{
public byte biaozhi;
public byte tiaoshu;
public byte dqtiaoshu;
public string dianhua;
public string msg;
public DateTime datetime;
public CDuanXin(byte bz, byte ts, byte dqts, string dh, string mg, DateTime dt)
{
biaozhi = bz;
tiaoshu = ts;
dqtiaoshu = dqts;
dianhua = dh;
msg = mg;
datetime = dt;
}
}
public class WaveComMsg
{
public int Port;
public int error;
readonly string zhongzhi = new string((char)26, 1);
const string head = "00";
const string quyu = "000D9168";
const string bianma = "000801";
const string shujutou = "050003";
const string ddx = "11";
const string cdx = "55";
StringBuilder fszifu = new StringBuilder(350);
Queue<DuanXin> duanxins = new Queue<DuanXin>(60);
Object listobj = new Object();
List<string> items = new List<string>(8);
public Action<int, string, string, int> Fsjieguo = null;
public Action<string, string, DateTime> RcvMsg = null;
public Action DuQu = null;
bool kongxian = true;
bool duqu = true;
Action<DuanXin> Sendmsg = null;
Random rd = new Random();
SerialPort sp = null;
List<CDuanXin> recvcd = new List<CDuanXin>(20);
public WaveComMsg(int port)
{
Port = port;
sp = new SerialPort("COM"+port);
sp.RtsEnable = true;
sp.DtrEnable = true;
DuQu = ksduqu;
sp.Open();
Sendmsg = sendmessage;
}
public bool Chushihua()
{
string ss = string.Empty;
try
{
sp.Write("AT+CMGF=0" + "\r");
while (true)
{
ss = sp.ReadLine();
if (ss.Contains("OK"))
break;
else if (ss.Contains("ERROR"))
return false;
}
}
catch
{
return false;
}
try
{
sp.Write("AT+CNMI=2,2,0,0,1" + "\r");
while (true)
{
ss = sp.ReadLine();
if (ss.Contains("OK"))
{
sp.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);
return true;
}
else if (ss.Contains("ERROR"))
return false;
}
}
catch
{
return false;
}
}
public void DoWork(string phnumber, string msg)
{
DuanXin dx = new DuanXin(phnumber, msg);
bool busy = false;
lock (listobj)
{
if (duanxins.Count > 0)
busy = true;
duanxins.Enqueue(dx);
}
if (!busy)
Sendmsg.BeginInvoke(dx, null, null);
}
void sendmessage(DuanXin dx)
{
byte[] msgs = Encoding.BigEndianUnicode.GetBytes(dx.message);
if (dx.message.Length <= 70)
{
fszifu.Append(head);
fszifu.Append(ddx);
fszifu.Append(quyu);
fszifu.Append(phonedecode(dx.phnum));
fszifu.Append(bianma);
fszifu.Append(Convert.ToString((dx.message.Length) * 2, 16).PadLeft(2, '0'));
for (int i = 0; i < msgs.Length; i++)
fszifu.Append(Convert.ToString(msgs[i], 16).PadLeft(2, '0'));
fszifu.Append(zhongzhi);
items.Add(fszifu.ToString());
fszifu.Clear();
}
else
{
string h = Convert.ToString(rd.Next(1, 127), 16);
int lnum = dx.message.Length / 67 + 1;
for (int i = 0; i < lnum; i++)
{
int sjl = i + 1 == lnum ? msgs.Length % 134 + 6 : 140;
fszifu.Append(head);
fszifu.Append(cdx);
fszifu.Append(quyu);
fszifu.Append(phonedecode(dx.phnum));
fszifu.Append(bianma);
fszifu.Append(Convert.ToString(sjl, 16).PadLeft(2, '0'));
fszifu.Append(shujutou);
fszifu.Append(h.PadLeft(2, '0'));
fszifu.Append(Convert.ToString(lnum, 16).PadLeft(2, '0'));
fszifu.Append(Convert.ToString(i + 1, 16).PadLeft(2, '0'));
for (int x = 0; x < sjl - 6; x++)
fszifu.Append(Convert.ToString(msgs[i * 134 + x], 16).PadLeft(2, '0'));
fszifu.Append(zhongzhi);
items.Add(fszifu.ToString());
fszifu.Clear();
}
}
string ss;
int success = 0;
kongxian = false;
for (int m = 0; m < items.Count; m++)
{
try
{
sp.Write("AT+CMGS=" + (items[m].Length / 2 - 1).ToString().PadLeft(3, '0') + "\r");
sp.Write(items[m]);
while (true)
{
ss = sp.ReadLine();
if (ss.StartsWith("0891"))
readmsg(ref ss);
else if (ss.Contains("OK"))
{
success = 1;
break;
}
else if (ss.Contains("ERROR"))
{
success = 0;
break;
}
}
}
catch
{
success = 0;
}
}
kongxian = true;
if (success == 0)
error++;
if (Fsjieguo != null)
Fsjieguo.BeginInvoke(Port, dx.phnum, dx.message, success, null, null);
items.Clear();
bool busy = false;
lock (listobj)
{
duanxins.Dequeue();
if (duanxins.Count > 0)
busy = true;
}
if (busy)
Sendmsg.BeginInvoke(duanxins.Peek(), null, null);
}
unsafe string phonedecode(string ph)
{
int x = ph.Length % 2 == 0 ? ph.Length : ph.Length + 1;
char* ca = stackalloc char[x];
for (int i = 0; i < x; i++)
if (i % 2 == 0)
*(ca + i) = (i + 1) == ph.Length ? 'F' : ph[i + 1];
else
*(ca + i) = ph[i - 1];
return new string(ca, 0, x);
}
unsafe string phoneencode(string ph)
{
int x = ph.Length;
char* ca = stackalloc char[x];
for (int i = 0; i < x; i++)
if (i % 2 == 0)
*(ca + i) = ph[i + 1];
else
*(ca + i) = ph[i - 1];
if (*(ca + x - 1) == 'F')
x--;
return new string(ca, 0, x);
}
unsafe DateTime fsshijian(string sj)
{
DateTime dt = new DateTime();
if (sj.Length == 10)
{
char* ca = stackalloc char[16];
ca[0] = '2';
ca[1] = '0';
ca[2] = sj[1];
ca[3] = sj[0];
ca[4] = '/';
ca[5] = sj[3];
ca[6] = sj[2];
ca[7] = '/';
ca[8] = sj[5];
ca[9] = sj[4];
ca[10] = ' ';
ca[11] = sj[7];
ca[12] = sj[6];
ca[13] = ':';
ca[14] = sj[9];
ca[15] = sj[8];
DateTime.TryParse(new string(ca, 0, 16), out dt);
}
return dt;
}
unsafe void ksduqu()
{
bool ydx = false;
string s = string.Empty;
while (true)
{
try
{
s = sp.ReadLine();
}
catch
{
ydx = false;
break;
}
if (s.StartsWith("0891"))
{
ydx = true;
break;
}
}
duqu = true;
if (ydx)
readmsg(ref s);
}
复制代码
void readmsg(ref string s)
{
s = s.Trim();
string mmsg = string.Empty;
int cd = Convert.ToInt32(s.Substring(18, 2), 16);
int hmcd = Convert.ToInt32(s.Substring(20, 2), 16);
if (hmcd % 2 == 1)
hmcd++;
string phonum = phoneencode(s.Substring(24, hmcd));
string bm = s.Substring(24 + hmcd, 4);
DateTime fssj = fsshijian(s.Substring(28 + hmcd, 10));
int len = Convert.ToByte(s.Substring(42 + hmcd, 2), 16);
if (cd < 64)
{
byte[] b = new byte[len];
if (bm == "0000")//text
{
byte y = 0;
int l = 0;
for (int t = 0; t < len; t++)
{
if (t % 8 == 7)
{
l++;
b[t] = y;
y = 0;
}
else
{
byte x = Convert.ToByte(s.Substring(2 * (t - l) + 44 + hmcd, 2), 16);
b[t] = (byte)((((byte)(x << ((t - l) % 7) + 1)) >> 1) + y);
y = (byte)(x >> (7 - ((t - l) % 7)));
}
}
mmsg = Encoding.ASCII.GetString(b);
}
else if (bm == "0008")//tpdu
{
for (int i = 0; i < len; i++)
b[i] = Convert.ToByte(s.Substring(44 + hmcd + i * 2, 2), 16);
mmsg = Encoding.BigEndianUnicode.GetString(b);
}
if (RcvMsg != null)
RcvMsg.BeginInvoke(phonum, mmsg, fssj, null, null);
}
else
{
byte[] b = new byte[len];
if (bm == "0000")//text
{
byte y = 0;
int l = 0;
for (int t = 0; t < len; t++)
{
if (t % 8 == 7)
{
l++;
b[t] = y;
y = 0;
}
else
{
byte x = Convert.ToByte(s.Substring(2 * (t - l) + 44 + hmcd, 2), 16);
b[t] = (byte)((((byte)(x << ((t - l) % 7) + 1)) >> 1) + y);
y = (byte)(x >> (7 - ((t - l) % 7)));
}
}
mmsg = Encoding.ASCII.GetString(b, 7, len - 7);
}
else if (bm == "0008")//tpdu
{
for (int i = 0; i < len - 6; i++)
b[i] = Convert.ToByte(s.Substring(56 + hmcd + i * 2, 2), 16);
mmsg = Encoding.BigEndianUnicode.GetString(b, 0, len - 6);
}
byte bz = Convert.ToByte(s.Substring(50 + hmcd, 2), 16);
byte ts = Convert.ToByte(s.Substring(52 + hmcd, 2), 16);
byte dqts = Convert.ToByte(s.Substring(54 + hmcd, 2), 16);
recvcd.Add(new CDuanXin(bz, ts, dqts, phonum, mmsg, DateTime.Now));
var cx = (from c in recvcd where c.biaozhi == bz && c.dianhua == phonum orderby c.dqtiaoshu select c).Distinct();
if (cx.Count() == ts)
{
string hjmsg = null;
foreach (var m in cx)
{
hjmsg += m.msg;
recvcd.Remove(m);
}
if (RcvMsg != null)
RcvMsg.BeginInvoke(phonum, hjmsg, fssj, null, null);
}
var ccx = from c in recvcd where (DateTime.Now - c.datetime).Minutes > 30 select c;
foreach (var n in ccx)
recvcd.Remove(n);
}
}
void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
if (kongxian)
{
if (duqu)
{
duqu = false;
DuQu.BeginInvoke(null, null);
}
}
}
public void release()
{
sp.Close();
}
}
复制代码
欢迎光临 深圳市未来时代科技有限公司 (http://inextera.com/)
Powered by Discuz! X3.1