IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    利用iPhone基带发送短信息

    谌启亮 (shenqiliang@xcodev.com)发表于 2014-03-07 23:57:30
    love 0

    在我的文章《初识iPhone基带通讯》中简单的介绍了如何利用iPhone基带进行通讯,接着我又写了《利用iPhone基带读写SIM卡联系人》,介绍了SIM卡数据读写的一些基带功能。下面我将进行关于iPhone基带的最后一篇介绍:《利用iPhone基带发送短信息》。阅读本文前,请先阅读一下之前的那两篇关于基带的介绍。

    AT+CMGF

    进行短信发送前,我们要设置短信发送的模式。短信发送模式分两种:文本模式和PDU(Protocol Data Unit)模式。文本模式中短信字符串可以直接放到AT指令中,但它不可以发中文等非ASCII字符。PDU模式是移动设备的基本短信模式,它同时可以支持中文的发送。

    AT+CMGF命令用来设置短信的发送模式:

    result = sendATCommand(baseband, @"AT+CMGF=0\r");
    

    可以通过AT+CMGF=0指令设置发送模式为PDU模式,而AT+CMGF=1则为文本模式。本例将主要以PDU模式进行介绍,PDU模式也更加复杂一些,但它能支持中文。

    AT+CMGS

    AT+CMGS指令用于发送短信,文本模式下发送流程比较简单,比如向“10010” 发送“1”。

    AT+CMGS="10010"
    > 1 
    OK
    

    而PDU模式就比较复杂了,具体流程如下:

    AT+CMGS=[length]
    > [PDU] 
    OK
    

    其中length是PDU除消息中心设置部分的长度,PDU就是PDU串内容,它是一个十六进制的字符串。

    PDU(Protocol Data Unit)

    PDU是对短消息中心、发送目的手机号码以及短信内容等进行的一些特殊编码,它是十六进制的字符串,具体格式为:

    [短信息中心地址长度][短信息中心号码类型][短信息中心号码][文件头字节][信息类型][发送目的手机号码长度][发送目的手机号码类型][发送目的手机号码][协议标识][数据编码方案][有效期][用户数据长度][用户数据]
    

    可以看出这个结构是蛮复杂的,一共由13项数据组成,如果是超过70个字符的长短信还需要更多字段。

    手机号码的编码

    从上面的编码格式可以看出,无论是短消息中心,还是发送目的手机号码,他们的编码都为:长度+类型+号码。长度就是手机号的实际长度,类型可以为91或81,91表示带国际区号号码,比如前面+86的,81表示号码不带国际区号。由于PDU编码中规定十六进制的数据字符都是一对一对的,单数的号码位数末尾将补一个字符“F”,如10010只有5位数字,将表示为6位的10010F。同时手机号码中奇数和偶数的位数还要翻转。我写的翻转方法如下(NSString+Catagory):

    - (NSString*)hexSwipString{
        unichar *oldBuf = malloc([self length]*sizeof(unichar));
        unichar *newBuf = malloc([self length]*sizeof(unichar));
        [self getCharacters:oldBuf range:NSMakeRange(0, [self length])];
        for (int i = 0; i < [self length]; i+=2) {
            newBuf[i] = oldBuf[i+1];
            newBuf[i+1] = oldBuf[i];
        }
        NSString *result = [NSString stringWithCharacters:newBuf length:[self length]];
        free(oldBuf);
        free(newBuf);
        return result;
    }
    

    那么10010的最终编码为:810110F。

    整体编码

    发送短信时,可以将短消息中心长度设置为00,那么就可以不用填写短消息中心了,它会自动采用手机默认设置,数据编码方案字段用08,即“UCS2”编码方式,为了可以支持中文。过期时间一般为“AA”,表示过期时间为一天,其实这个感觉好像没效果。其他一些字段可以直接采用默认的即可。整体编码函数如下。

    NSString *PDUEncodeSendingSMS(NSString *phone, NSString *text){
        NSMutableString *string = [NSMutableString stringWithString:@"001100"];
        [string appendFormat:@"%02X", (int)[phone length]];
        if ([phone length]%2 != 0) {
            phone = [phone stringByAppendingString:@"F"];
        }
        [string appendFormat:@"81%@",[phone hexSwipString]];
        [string appendString:@"0008AA"];//数据编码方案08,过期AA
        NSString *ucs2Text = [text ucs2EncodingString];
        [string appendFormat:@"%02x%@", (int)[ucs2Text length]/2, ucs2Text];
        return [NSString stringWithString:string];
    }
    

    短信发送过程

    上面介绍了短信发送相关的一些编码问题,下面来说下短信发送流程和相关代码。

    短信AT指令发送流程函数:

    BOOL sendSMSWithPDUMode(NSFileHandle *baseband, NSString *phone, NSString *text){
        NSString *pduString = PDUEncodeSendingSMS(phone, text);
        NSString *result = sendATCommand(baseband, [NSString stringWithFormat:@"AT+CMGS=%d\r", (int)[pduString length]/2-1]);
        result = sendATCommand(baseband, [NSString stringWithFormat:@"%@\x1A", pduString]);
        if ([result hasSuffix:@"OK\r\n"]) {
            return YES;
        }
        else{
            return NO;
        }
    }
    

    发送短信前,需要进行一些必要的设置

    NSString *result = sendATCommand(baseband, @"AT+CSCS=\"UCS2\"\r");
    result = sendATCommand(baseband, @"ATE0\r");
    result = sendATCommand(baseband, @"AT+CMGF=0\r");
    

    OK,我们就可以向10010发送一个“测试”了。

    sendSMSWithPDUMode(baseband, @"10010", @"测试");
    

    试试把10010换成你自己的号码,看看能否收到自己发的短信。

    源码地址:https://gist.github.com/shenqiliang/9415355



沪ICP备19023445号-2号
友情链接