在《初识iPhone基带通讯》文章中,我们初步了解到了如何在iPhone中进行基带通讯,和基本的通讯方式(GSM网络AT指令),并介绍了一些比较简单AT指令。本文将进一步介绍如何利用iPhone基带读写手机SIM卡联系人。本文简要介绍一下SIM卡的一些常识,AT指令中中文字符的相关处理,并介绍如果读写SIM卡中的联系人数据。
SIM卡虽小,但每个SIM卡都有一定的存储空间。SIM也有容量,有32K,64K,甚至128K的都有。容量小的SIM卡一般可以存储200条联系人。SIM不仅可以存储联系人,也可以存储若干条短信,这取决于SIM卡的容量,这些容量信息在一些老式手机中可以看到。然而如今进入智能手机时代,SIM卡的容量已经显得太小了,比如在iPhone中,我们已经没法将联系人存储到SIM卡。iPhone OS 2.0开始,系统设置里加入一个将SIM卡的联系人全部导入到iPhone的功能。你可以在“设置” > “邮件、通讯录、日历”页面看到“导入SIM卡通讯录”。除此似乎再没有其他方式访问SIM卡数据。
SIM卡联系人数据结构很简单,只包括名字和电话号码这两个最基本字段。
为了方便进行我们的SIM存储,我们需要进行一些配置。包括存储位置的设定,中文的支持,回显的设定。下面一一介绍一下。
首先我们要设定我们进行联系人操作存储单元为SIM卡:
NSString *result = sendATCommand(baseband, @"AT+CPBS=\"SM\"\r");
选择联系人存储单元的AT指令为:AT+CPBS
,它的值可以为“ME”(手机)或“SM”(SIM卡)。旧式手机一般可以选择联系人保存位置是手机还是SIM卡,就是通过此命令进行设置。这里我们设置为“SM”(SIM卡)。
由于AT指令中只能用ASCII码,中文的话是不支持的,这就需要我们对中文进行一些特殊的编码。目前大多数AT指令都支持UCS2编码,即Unicode两字节编码。AT指令中要把一个Unicode转换为一个4个字节的16进制表示来进行传输。比如“简体中文”要转换为“7B804F534E2D6587”。为了实现UCS2编码传输。我们需要对AT终端进行编码设置,即执行AT+CSCS="UCS2"
指令:
result = sendATCommand(baseband, @"AT+CSCS=\"UCS2\"\r");
同时我也写了一个NSString的Catagory,来支持UCS2编码的转换:
@implementation NSString(UCS2Encoding)
- (NSString*)ucs2EncodingString{
NSMutableString *result = [NSMutableString string];
for (int i = 0; i < [self length]; i++) {
unichar unic = [self characterAtIndex:i];
[result appendFormat:@"%04hX",unic];
}
return [NSString stringWithString:result];
}
- (NSString*)ucs2DecodingString{
NSUInteger length = [self length]/4;
unichar *buf = malloc(sizeof(unichar)*length);
const char *scanString = [self UTF8String];
for (int i = 0; i < length; i++) {
sscanf(scanString+i*4, "%04hX", buf+i);
}
return [[NSString alloc] initWithCharacters:buf length:length];
}
@end
每条AT指令执行的结果默认都会返回一遍所执行的AT指令,这个是AT指令终端的回显功能,为了减少不必要的处理,我们就把它关闭,执行ATE0
:
result = sendATCommand(baseband, @"ATE0\r");
增加联系人需要使用AT+CPBW
指令,此命令格式为
AT+CPBW=序号,号码,类型,名字
序号是存储位置,不能超过手机存储容量。如果为空,则会在最低存储位存储。号码就是手机号码,类型一般设置为空即可。名字为联系人的姓名。如果只有序号,其他都是空,那么将删除序号下的联系人,如AT+CPBW=5
将删除存储序号为5的联系人。
我写了一个addNewSIMContact
函数来插入一个联系人,相应的代码如下:
BOOL addNewSIMContact(NSFileHandle *baseband, NSString *name, NSString *phone){
NSString *result = sendATCommand(baseband, [NSString stringWithFormat:@"AT+CPBW=,\"%@\",,\"%@\"\r", phone, [name ucs2EncodingString]]);
if ([result hasSuffix:@"OK\r\n"]) {
return YES;
}
else{
return NO;
}
}
读取联系人需要使用AT+CPBR
指令。首先我们要查看系统能够存储多少个联系人,使用AT+CPBR=?
可以返回存储容量信息。返回结果为:
+CPBR:(起始序号-最大序号), 电话长度, 名字长度
OK
要读取联系人需要用下面指令
AT+CPBR=起始序号,终止序号
这样就会读取从起始序号到终止序号的所有联系人,返回的格式为:
+CPBR: 序号1,电话,类型,名字
+CPBR: 序号2,电话,类型,名字
OK
因此,先用AT+CPBR=?
获取容量,然后用AT+CPBR=1,最大容量
就能返回所有的联系人记录了。然后在进行一些必要的解析即可。相应的代码如下:
NSArray *readAllSIMContacts(NSFileHandle *baseband){
NSString *result = sendATCommand(baseband, @"AT+CPBR=?\r");
if (![result hasSuffix:@"OK\r\n"]) {
return nil;
}
int max = 0;
sscanf([result UTF8String], "%*[^+]+CPBR: (%*d-%d)", &max;);
result = sendATCommand(baseband, [NSString stringWithFormat:@"AT+CPBR=1,%d\r",max]);
NSMutableArray *records = [NSMutableArray array];
NSScanner *scanner = [NSScanner scannerWithString:result];
[scanner scanUpToString:@"+CPBR:" intoString:NULL];
while ([scanner scanString:@"+CPBR:" intoString:NULL]) {
NSString *phone = nil;
NSString *name = nil;
[scanner scanInt:NULL];
[scanner scanString:@",\"" intoString:NULL];
[scanner scanUpToString:@"\"" intoString:☎];
[scanner scanString:@"\"," intoString:NULL];
[scanner scanInt:NULL];
[scanner scanString:@",\"" intoString:NULL];
[scanner scanUpToString:@"\"" intoString:&name;];
[scanner scanUpToString:@"+CPBR:" intoString:NULL];
if ([phone length] > 0 && [name length] > 0) {
[records addObject:@{@"name":[name ucs2DecodingString], @"phone":phone}];
}
}
return [NSArray arrayWithArray:records];
}
AT+CPBR=?
获取这些信息,本文就不再详细介绍了。