GSM MODEM JAVA解码PDU短信

未解决
一共3个问题:1.PDU短信是什么;2.为什么要用pdu;3.如何用java解码

1.pdu短信是什么?

短信的一种方式,被所有手机支持,可以使用任何字符集,这也是手机默认的编码方式;
PDU相当于一个数据包,它由构成消息(SMS)的信息组成。作为一种数据单元,它必须包含源/目的地址、保护(有效)时间、数据格式、协议类型和正文,正文长度可达140字节,它们都以十六进制表示。PDU结构根据短消息由移动终端发起或以移动终端为目的而不同。每条消息可以发送140个字节,由于本系统中最长的数据串没有超过140个字节,因此数据均可以用一条消息来发送;
其中又分7bit-160,8bit-140,16bit-70的方式,我们中文用16bit70的方式。

范例
发送:SMSC号码是+8613800250500,对方号码是13851872468,消息内容是“Hello!”。
从手机发出的PDU串可以是08 91 68 31 08 20 05 05 F0 11 00 0D 91 68 31 58 81 27 64 F8 00 00 00 06 C8 32 9B FD 0E 01

对照规范,具体分析:  
08  SMSC地址信息的长度     共8个八位字节(包括91)
91  SMSC地址格式(TON/NPI)   用国际格式号码(在前面加‘+’)
68 31 08 20 05 05 F0  SMSC地址   8613800250500,补‘F’凑成偶数个
11  基本参数(TP-MTI/VFP)   发送,TP-VP用相对格式
00  消息基准值(TP-MR)  0
0D  目标地址数字个数  共13个十进制数(不包括91和‘F’)
91  目标地址格式(TON/NPI)   用国际格式号码(在前面加‘+’)
68 31 58 81 27 64 F8  目标地址(TP-DA)   8613851872468,补‘F’凑成偶数个,BCD编码方式,低位-高位方式

00   协议标识(TP-PID)  是普通GSM类型,点到点方式
00   用户信息编码方式(TP-DCS)   7-bit编码

00   有效期(TP-VP)   5分钟

06   用户信息长度(TP-UDL)    实际长度6个字节

C8 32 9B FD 0E 01   用户信息(TP-UD)    “Hello!”



0891683108100005F0 31 00 0B 81 3129503323F1 00 08 A8 0C 4F6060F3776189C94E865427

分析一下
分段
含义
说明

08
SMSC地址信息的长度
共8个八位字节(包括91)

91
SMSC地址格式(TON/NPI)
用国际格式号码(在前面加‘+’),81表示没有+

683108100005F0
SMSC地址
8613800100500,补‘F’凑成偶数个bcd编码
31
基本参数(TP-MTI/VFP)
发送,TP-VP用相对格式。标志

00
消息基准值(TP-MR)
0

0D
目标地址数字个数
共13个十进制数(不包括91和‘F’)

81
目标地址格式(TON/NPI)
用国际格式号码(在前面加‘+’),81表示没有‘+’

3129503323F1
目标地址(TP-DA)
8613851872468,补‘F’凑成偶数个,BCD编码方式,低位-高位方式

00
协议标识(TP-PID)
是普通GSM类型,点到点方式

08
用户信息编码方式(TP-DCS)
16-bit编码,UCS2编码

A8
有效期(TP-VP)
2天

0C
用户信息长度(TP-UDL)
实际长度12个字节

4F6060F3776189C94E865427
用户信息(TP-UD)
“你睡觉了吧!”



2.为什么要用pdu?
被所有手机支持
通用的十六进制


3.如何用java解码?
暂时只展示了7-bit和16bit(UCS2,UCS2编码用于发送Unicode字符)的解码代码

7-bit

public static String hexString7ToString(String s){
                if (StringUtils.isEmpty(s))
                        throw new IllegalArgumentException("this hexString must not be empty");
                byte[] dataArray = hexStr2ByteArray(s);
                String str = decode7bit(dataArray);
                return  str;
                
        }
 
 
/**
        * 7-bit解码
        * @param data
        * @return
        */
        public static String decode7bit(byte[] d){
        byte[] other_mask ={(byte) 0x80,(byte) 0xc0,(byte) 0xe0,(byte) 0xf0,(byte) 0xf8,(byte) 0xfc,(byte) 0xfe};
        byte[] my_mask = {0x7f,0x3f,0x1f,0x0f,0x07,0x03,0x01};
        byte other = 0;
        byte temp = 0;
        StringBuffer sb = new StringBuffer();
        for(int i=0;i<d.length;i++){
        int index = i%7;
        temp = d[i];
        //得到我的数据
        d[i] = (byte) (d[i]&my_mask[index]);
        d[i] = (byte) (d[i] << index);
        if(index != 0){
        d[i] = (byte) (d[i]&other_mask[7-index]);
        other = (byte) (other>>(8-index));
        other = (byte) (other&my_mask[7-index]);
        d[i] = (byte) (d[i] | other);
        }
        //先把下一个数据信息拿走
        other = (byte) (temp&other_mask[index]);
        sb.append((char)d[i]);
        if(index == 6){
        other = (byte) (other>>1);
        other = (byte) (other & 0x7f);
        sb.append((char)other);
        }
        }
        return sb.toString();
        }
 
public static byte[] hexStr2ByteArray(String hexString) {
                //TODO Hex.decode(hexString);
                if (StringUtils.isEmpty(hexString))
                        throw new IllegalArgumentException("this hexString must not be empty");
 
                hexString = hexString.toLowerCase();
                final byte[] byteArray = new byte[hexString.length() / 2];
                int k = 0;
                for (int i = 0; i < byteArray.length; i++) {
                                                //因为是16进制,最多只会占用4位,转换成字节需要两个16进制的字符,高位在先
                                                //将hex 转换成byte   "&" 操作为了防止负数的自动扩展
                                                // hex转换成byte 其实只占用了4位,然后把高位进行右移四位
                                                // 然后“|”操作  低四位 就能得到 两个 16进制数转换成一个byte.
                                                //
                        byte high = (byte) (Character.digit(hexString.charAt(k), 16) & 0xff);
                        byte low = (byte) (Character.digit(hexString.charAt(k + 1), 16) & 0xff);
                        byteArray[i] = (byte) (high << 4 | low);
                        k += 2;
                }
//                System.out.println("16进制明文字符串转成16进制字节数组:"+byteArray);

16-bit

public static String DecodeUCS2(String src) {
                byte[] bytes = new byte[src.length() / 2];
 
                for (int i = 0; i < src.length(); i += 2) {
                        try {
                                bytes[i / 2] = (byte) (Integer
                                                .parseInt(src.substring(i, i + 2), 16));
                        } catch (Exception e) {
                                System.out.println("异常字符:"+src.substring(i, i + 2));
                        }
                }
                String reValue="";
                try {
                        reValue = new String(bytes, "UTF-16BE");
                } catch (UnsupportedEncodingException e) {
                        e.printStackTrace();
                }
                return reValue;
 
        }

GSM MODEM短信功能开发的,可以使用smslib的java短信二次开发包的,已经封装好AT命令和常用GSM PDU协议的编解码

其他参考链接:
http://www.cnblogs.com/heiyue/p/7008499.html
http://blog.csdn.net/yangfeiyang/article/details/5526649

————————————————
版权声明:本文为CSDN博主「Cal_Smith」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/a510750/article/details/77447650

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

admin

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

回帖 ( 0 )