最近有个项目,涉及到通过SS或者USSD信道完成数据的交互。以下是SS和USSD的说明:
SS
Supplementary Service,补充服务,比如控制号码显示,呼叫转移等服务的号码串。这些号码串是每部GSM/UMTS/LTE手机中的固定服务号码,运营商是不能对它进行修改的。当手机系统接受到这些服务号码后,先在手机内部进行处理后,再传给网络。比如你随便拿个手机,在拨号盘输入*21*123456789#然后点击发送,这个时候你所有的来电都会直接转移到123456789。
USSD
与SS相对应的是Unstructured Supplementary Service Data。从字面上看,是非结构化的补充字符,曾经我以为字符串格式上的不同是SS和USSD间最大的区别,后来发现自己大错特错了:单从字符串格式上是没法区分的。那他俩到底有啥区别?一,USSD基本都是运营商根据自己的服务自己定制的,而SS就像上面说的是每个手机固有的;二,SS在发送给网络前,手机首先会自己处理一下,而USSD是完全透明的传送给网络。
SS和USSD都必须点击发送后才能生效,而Manufacturer defined MMI codes和SIM control codes都不需要点击,输入后直接生效。
基于定义,USSD基本上是通过手机拨号键盘发送的,所以只支持0-9以及*,#这12个字符。怎么把Hex编码转化为USSD字符承载呢?我想到了Base64编码的原理,无非就是通过bit切割将数据值域切为有效字符的个数范围内,并通过查表映射为有效字符。代码如下,有类似需求的朋友说不定可以复用一下:package com.broadthinking.alg;
/**
* 将编码字节以3个8位字节一组,转化为8个3位的字节,并查表得到8个字符('0'-'7')。
* 如果编码字节不足3个字节,则用0填充。并在输出字符末尾填充'8'来指示有几个填充字节。
* -------------------------------
* 数值 字符
* -------------------------------
* 0 '0'
* 1 '1'
* 2 '2'
* 3 '3'
* 4 '4'
* 5 '5'
* 6 '6'
* 7 '7'
* -------------------------------
* @author caesarzou
*
*/
public class Base8 {
public static void main(String [] args) throws Exception {
byte [][] test = {
{(byte)0x1F},
{(byte)0xFE,(byte)0xDE},
{(byte)0xFE,(byte)0x10,(byte)0xDE},
{(byte)0xFF,(byte)0x10,(byte)0x00,(byte)0x11,(byte)0x22,(byte)0x33,(byte)0xFF}};
for(int i=0;i<test.length;i++) {
byte [] resb = test[i];
for(int j=0;j<resb.length;j++) {
System.out.print(Integer.toHexString(resb[j]&0x00FF));
}
System.out.println();
char [] res = Base8.encode(resb, 0, resb.length);
System.out.println(String.valueOf(res));
resb = Base8.decode(res);
for(int j=0;j<resb.length;j++) {
System.out.print(Integer.toHexString(resb[j]&0x00FF));
}
System.out.println();
System.out.println();
}
}
public static char [] encode(byte [] data, int offset, int length) {
int pad = (3-length%3);
if(pad == 3) {
pad = 0;
}
int oplength = length+pad;
int opblock = oplength/3;
byte [] opdata = new byte[oplength];
char [] rsdata = new char[8*opblock];
System.arraycopy(data, offset, opdata, 0, length);
for(int i=0;i<opblock;i++) {
int tmpdata = ((opdata[i*3]<<16) & 0x00FF0000)
| ((opdata[i*3+1]<<8) & 0x0000FF00)
| (opdata[i*3+2] & 0x000000FF);
rsdata[i*8] = (char)(0x30 | ((tmpdata>>21) & 0x07));
rsdata[i*8+1] = (char)(0x30 | ((tmpdata>>18) & 0x07));
rsdata[i*8+2] = (char)(0x30 | ((tmpdata>>15) & 0x07));
rsdata[i*8+3] = (char)(0x30 | ((tmpdata>>12) & 0x07));
rsdata[i*8+4] = (char)(0x30 | ((tmpdata>>9) & 0x07));
rsdata[i*8+5] = (char)(0x30 | ((tmpdata>>6) & 0x07));
rsdata[i*8+6] = (char)(0x30 | ((tmpdata>>3) & 0x07));
rsdata[i*8+7] = (char)(0x30 | (tmpdata & 0x07));
}
for(int i=0;i<pad;i++) {
rsdata[rsdata.length-1-i] = (char)0x38;
}
return rsdata;
}
public static byte [] decode(char [] code) {
int pad = 0;
if(code[code.length-1] == (char)0x38) {
if(code[code.length-2] == (char)0x38) {
pad = 2;
} else {
pad = 1;
}
}
int opblock = code.length/8;
byte [] rsdata = new byte[opblock*3];
for(int i=0;i<opblock;i++) {
int tmpdata = 0;
tmpdata |= (code[i*8] & 0x07)<<21;
tmpdata |= (code[i*8+1] & 0x07)<<18;
tmpdata |= (code[i*8+2] & 0x07)<<15;
tmpdata |= (code[i*8+3] & 0x07)<<12;
tmpdata |= (code[i*8+4] & 0x07)<<9;
tmpdata |= (code[i*8+5] & 0x07)<<6;
tmpdata |= (code[i*8+6] & 0x07)<<3;
tmpdata |= (code[i*8+7] & 0x07);
rsdata[i*3] = (byte)(tmpdata>>16);
rsdata[i*3+1] = (byte)(tmpdata>>8);
rsdata[i*3+2] = (byte)(tmpdata);
}
byte [] crsdata = new byte[rsdata.length-pad];
System.arraycopy(rsdata, 0, crsdata, 0, crsdata.length);
return crsdata;
}
}