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();
        }
    }


短信设备二次开发 2022-04-07 0 0

admin

  • 注册时间 : 2022-03-30 04:08:47
  • 邮箱地址 : admin@tenghengkeji.com
  • 此页面用于展示用户的基本上资料信息

回帖 ( 0 )