合宙lua库详解-sms

文章目录

  • 简介
  • 初始化
  • 发送

简介

短信是我们经常使用的,在手机上使用也就是直接编写文本就可以将内容发送出去。但是我们实际使用过程却是很复杂的。
短信有许多的编码,7bit,8bit,文本等等。下图就是PDU编码格式图:
MO短信PDU格式(模块端发送)
合宙lua库详解-sms_第1张图片

MT短信PDU格式(模块端接收)
合宙lua库详解-sms_第2张图片
第一眼看上去,一脸懵逼,下面我们一一道来。
合宙lua库的短消息收发是根据AT指令进行收发的,接下来就对照上图看下库里面是怎么处理的吧。

初始化

local function init()
    if cpinReady and smsUrcReady and netReady then
        --使用PDU模式发送,=0就是PDU格式,可以发送文本,=1的时候就是TEXT模式,但是只能发送ascii
        req("AT+CMGF=0")
        --设置短信TEXT 模式参数
        -- req("AT+CSMP=17,167,0,8")
        --设置AT命令的字符编码是UCS2,有"GSM","IRA"等等编码,这个主要通知DCE,DTE需要使用的字符集,
       	--确保他们那边能够按照这样正确转换,最常用还是"UCS2"
        req('AT+CSCS="UCS2"') 
        --设置存储区为SM,我的理解是短信会优先保存在什么地方,这里明显是SIM卡,短信来的时候我们只
        --需要去读取就行了
        req('AT+CPMS="SM"')
        -- 上报消息CMTI,具体可以查看CNMI的指令,主要设置上报形式
        req("AT+CNMI=2,1,0,0,0")
        --分发短信准备好消息
        publish("SMS_READY")
        --清空已读短信
        req("AT+CMGD=1,3")
    end
end

发送

lua调用短消息发送就是调用send接口,这个函数主要就是将待发送的号码和数据都插入到短信发送缓存表tsmsnd中。实际的发送函数是_send
刚一开始就判断是否大于140,这个140怎么来的尼?这就涉及到了长短信和短短信的区别:


普通短信UD区长度为140字节,超过140字节就得拆分成多条短信,拆分后的短信经过短信网关、短信中心的存储转发后到达终端的顺序可能和原发送顺序不同,这就使得接收方对于信息内容的理解出现困扰,1996年颁布的GSM03.40V4.13.0中定义了长短信(Concatenated Short Message),所谓的长短信就是由一组相互独立的不超过普通短信长度的子短信组成,在网络传输中被视为多条普通短信,而在终端上被合并显示。

短短信 长短信
PDU-Type的UDHI标识位 0 1
PDU-Type的MMS标识位 1 最后一条为1其余为0
UDL 短信内容长度 用户数据头长度+拆分后短信内容长度
UD 全部为短信内容 用户数据头+拆分后短信内容

上面表可以看出,短短信与长短信除了部分标识位不一样外,数据也多了一个用户数据头,这个数据头固定为6字节,所以长短信实际最多只能发送134字节。
有人要问,我发送一条长短信,运营商怎么收费尼?不好意思,运营商也想到了,按照你分包的个数进行计费。
长短信实际应用中比较少,短信一般只起到通知的作用,短短信如果以UCS2编码发送,最后可以发送140/2个字符,完全足够了,所以下面主要说下UCS2发送短短信。
具体的实例:
合宙lua库详解-sms_第3张图片
对照简介中的MO短信PDU格式,可以一一对应上。

这里有几个需要注意的点:

  1. 目的号码被转码了,转成了BCD编码,并且添加上了前缀。
  2. DCS表示该短信的编码格式,08表示UCS2
  3. User Data的长度是04,为什么数据有8个ascii码尼?这个长度表示的是字节数,而这串ascii表示的是十六进制字符串,实际上只有4个字节,底层会进行转换。

主要看下号码的编码,顺便也奉上C的实现:
lua代码-转BCD编码

--[[
函数名:numtobcdnum
功能  :号码ASCII字符串 转化为 BCD编码格式字符串,仅支持数字和+,例如"+8618126324567" -> 91688121364265f7 (表示第1个字节是0x91,第2个字节为0x68,......)
参数  :
num:待转换字符串
返回值:转换后的字符串
]]
local function numtobcdnum(num)
    local len, numfix, convnum = slen(num), "81", ""
	--区号判断,+86代表的是中国的国际区号,上面的例子就是中国国际区号,一般用于拨打国际长途
    if ssub(num, 1, 1) == "+" then 
        numfix = "91"
        len = len - 1
        num = ssub(num, 2, -1)
    end
	--如果号码长度是奇数填充一个F
	--我们正常号码是11个字节,加上中国国际区号之后正好变成偶数就不需要填充了
    if len % 2 ~= 0 then --奇数位
        for i = 1, (len - (len % 2)) / 2 do
            convnum = convnum .. ssub(num, i * 2, i * 2) .. ssub(num, i * 2 - 1, i * 2 - 1)
        end
        convnum = convnum .. "F" .. ssub(num, len, len)
    else --偶数位
        for i = 1, (len - (len % 2)) / 2 do
            convnum = convnum .. ssub(num, i * 2, i * 2) .. ssub(num, i * 2 - 1, i * 2 - 1)
        end
    end
    return numfix .. convnum
end

C代码-转BCD编码

static void num_to_bcdnum(char *codeNum,char *bcdNum){
    uint8_t codeLen = strlen(codeNum);
    char numfix[3] = "81";
    char convnum[20] = {0};
    uint8_t i = 0;
    char *code = codeNum;
    if(*code == '+'){
        codeLen -= 1;
        code += 1; 
        memcpy(numfix,"91",2);
    }
    if(codeLen % 2 != 0){ //奇数
        for(i = 0;i < codeLen-1;i+=2){
            convnum[i] = *(code+i+1);
            convnum[i+1] = *(code+i);
        }
        convnum[codeLen-1] = 'F';
        convnum[codeLen] = code[codeLen-1];
    }else{
        for(i = 0;i < codeLen;i+=2){
            convnum[i] = *(code+i+1);
            convnum[i+1] = *(code+i);
        }
    }
    sprintf(bcdNum,"%s%s",numfix,convnum);
    DEBUG(bcdNum);
}

编码好后,lua也会调用CMGS指令进行短信的发送。

合宙lua库详解-sms_第4张图片

你可能感兴趣的:(Luat,短信,短信编码,lua发送短信,C发送短信,Air724)