Monday, July 05, 2010

买了个空间 lytsing.org

上 blogspot都得代理,买办法,只好买个空间,安装wordpress,博客域名为 http://blog.lytsing.org

Thursday, August 13, 2009

用C++写ruby扩展

为了测试CDMA短信的发送方便,于是想到编译成lib,提供ruby使用。

SmsObject.h:
void SendSms(const char* msg, const char* number, char* out);

main.cpp:
//
// by deli 2009.6.11
//
#include <ruby.h>
#include "SmsObject.h"

static VALUE makepdu(VALUE self, VALUE arg1, VALUE arg2) {
    VALUE s;
    char pdu[512] = {0};
    char* msg = RSTRING(arg1)->ptr;
    char* number = RSTRING(arg2)->ptr;

    SendSms(msg, number, pdu);
    s = rb_str_new2(pdu);

    return s;
}

extern "C"
void __declspec(dllexport) Init_sms() {
    VALUE myModule = rb_define_module("CDMA");

    VALUE myClass = 
        rb_define_class_under(myModule, "SMS", rb_cObject);

    int arg_count = 2;
    rb_define_method(myClass, "makepdu", RUBY_METHOD_FUNC(makepdu), arg_count);
}



注意: C++要加上RUBY_METHOD_FUNC, C不用加。不然就会出现类似的错误:
error C2664: 'rb_define_method' : cannot convert parameter 3 from
'unsigned long (unsigned long,unsigned long,unsigned long)' to 'unsigned long (_
_cdecl *)(...)'
        None of the functions with this name in scope match the target type


test.rb:

require 'sms'

include CDMA

obj = SMS.new
pdu = obj.makepdu('什么都可以想,什么都可以不想,便觉得是个自由的人', '15338896034')

puts pdu

D:\Ruby\ruby-serial\sms>ruby test.rb
0000021002040702c54ce225a8d008420003200000013220c27602724487ea9f7a772b079ff86276
02724487ea9f7a772a706b079ff8627dfc4e4afcbb317a71540f53a98bb42275d00501a70801c00d
0101

大概就是这样。

Saturday, July 11, 2009

用gsmmux 测试via cdma多路复用功能

现在杭州的威盛已实现了GSM协议07.10 multiplexer。
gsmmux 可以在 developer.berlios.de/projects/gsmmux/ 上获得.按照说明安装就可以了。
代码默认用的是AT+CMUX开启功能,而CMUX在CDMA另有别用,所以他们就用VMUX来替代,在代码里,把CMUX改为VMUX,重新编译。

运行 mux,得到两个虚拟逻辑串口 /dev/mux0 /dev/mux1,
开一个终端1 cat /dev/mux0 观察数据
再开一个终端2输入 echo -e "AT\r\n" > /dev/mux0
终端1有 "OK" 响应就行了。
同样的方法测试 mux1.

核心代码在 gsm0710.c

简单说明一下。
1190 行的 main函数,读取命令行参数, 
1272 行 daemonize(_debug) 设置为unix下经典后台程序,下来是设置信号中断机制。 

openDevicesAndMuxMode 函数 打开modem 初始化,发 "AT+VMUX=0" 进入mux模式。 

MUX启动过程 
主机发: AT+VMUX=0 
模块回复:OK /*进入MUX模式*/ 
主机发:  F9033F011CF9 /*建立DLC0*/ 
模块回复:F9037301D7F9 
主机发:  F9073F01DEF9 /*建立DLC1*/ 
模块回复:F907730115F9 
        F901EF09E305070D9AF9 /*DLC1 MSC 命令*/ 
主机发:  F90B3F0159F9 /*建立DLC2*/ 
模块回复:F90B730192F9
        F901EF09E3050B0D9AF9 /*DLC2 MSC 命令*/ 

 /*…开始进行MUX协议的数据传输…*/ 

在 1106行的openDevicesAndMuxMode,
三次(一般是三次,可以设置)打开 /dev/ptmx ,得到三对主从终端,通过符号链接,创建两个虚拟串口

/dev/mux0 /dev/mux1 这时就可以像正常访问串口一样访问它们,一般 /dev/mux0
用来专门发AT, /dev/mux1 用来发送数据业务,比如pppd 拨号上网。 

数据流大概是这样的 
/dev/ttyS0 <---> | /dev/pmux <----> /dev/mux0 | <----> at command 
/dev/ttyS0 <---> | /dev/pmux <----> /dev/mux1 | <----> cdma pppd


 下面
1162行 - 1166行 
 for (i = 1; i <= numOfPorts; i++) 
 { 
     sleep(1);
     write_frame(i, NULL, 0, SABM | PF); 
     syslog(LOG_INFO, "Connecting %s to virtual channel %d on %s\n", ptsname(mux_fd[i-1]), i, serportdev);
 } 

write_frame(i, NULL, 0, SABM | PF); 实现的就是发 
F9033F011CF9 /*建立DLC0*/ 
F9073F01DEF9 /*建立DLC1*/ 
F90B3F0159F9 /*建立DLC2*/ 

 然后进入 while循环,用selelct 实现 i/o 多路复用, 
(1)检查物理串口,如果有可读的数据,读取放到buffer,然后解析数据帧,并发送到虚拟逻辑串口 
(2)检查虚拟逻辑串口,如果有可读的数据,构造数据帧,写入物理串口。 

 就这样,基本原理是数据分组打包与解包。  

Sunday, May 10, 2009

Android CDMA

Android CDMA

cdma-import分支由Teleca CDMA团队开发。

Teleca's contribution covers all required extensions in the application framework of the telephony stack, the application domain and user interface. In order to support existing applications the application interface is backward compatible, but extended to include CDMA specific methods, parameters or notifications to make the new features accessible by new applications.


取出cdma-import版本
$ mkdir ~/android_cdma
$ cd ~/android_cdma
$ repo init -u git://android.git.kernel.org/platform/manifest.git -b cdma-import
$ repo sync

(3)后面 -b cdma-import 指定分支,还有其他分支:
cupcake
donut
master
release-1.0
如果不加以指定,则取出的是master分支。
(4) 全部取出。我发现很慢,速度1-4k,下一个晚上也下不完。网上查了一圈,原来可以令开两个终端同时下载,分别取出 kernel, prebuild,这两个目录都比较大。
$ repo sync kernel
$ repo sync prebuild

我们主要分析cdma模组,取出 ril目录的代码即可
$ repo sync hardware/ril

代码结构如下:
ril
|-- include
| `-- telephony
| |-- ril.h
| `-- ril_cdma_sms.h
|-- libril
| |-- ril.cpp
| |-- ril_commands.h
| |-- ril_event.cpp
| |-- ril_event.h
| `-- ril_unsol_commands.h
|-- reference-cdma-sms
| |-- reference-cdma-sms.c
| `-- reference-cdma-sms.h
|-- reference-ril
| |-- at_tok.c
| |-- at_tok.h
| |-- atchannel.c
| |-- atchannel.h
| |-- misc.c
| |-- misc.h
| `-- reference-ril.c
`-- rild
|-- radiooptions.c
`-- rild.c

reference-ril目录通俗易懂,at_tok.h 提供AT响应的解析函数,atchannel.h提供AT的发送函数,misc.h就只是一个字符串匹配函数。
reference-ril.c提供许多函数,在函数内实现发送AT,解析AT响应字符串。在代码里直接写AT,看到有些失望,特别是用at_tok.h里的函数
一个参数一个参数的解析,不如写一个类似于sscanf专门处理AT响应字符串的函数AtScanf,这样代码看起来就清爽多了。

大概的看看,没什么改动,很多代码还放在Teleca的网站上,没有合并进来。
atchannel.h
/include/telephony/ril.h
在gsm一些枚举类型里额外添加对uim的支持。

其他请参看it168熊猫哥哥的《深入详解Android GSM驱动模块》
http://tech.it168.com/a2009/0323/269/000000269394.shtml
http://tech.it168.com/a2009/0331/270/000000270151.shtml

Thursday, May 07, 2009

提笔就老:回文判断(C++)

最近复习C++,在看《Accelerated C++》时,对回文的例子印象很深刻,代码简洁明了,令人惊叹:

bool is_parlindrome(const string& s)
{
return equal(s.begin(), s.end(), s.rbegin());
}
也可以这么写:


return equal(s.begin(), s.begin() + s.length() / 2, s.rbegin());


撇开STL的用法,用原始的手工写法,一般人都会这么写的:

bool is_palindrome(const char* s)
{
int len;
len = strlen(s);

for (int i = 0; i < (len / 2); ++i) {
if (s[i] != s[len-i-1])
return false;
}

return true;
}


我觉得,果真如此,用两个指针判断更佳:

bool is_parlindrome(const char* src)
{
assert(src != NULL);
const char *end = src;

while (*end)
++end; // has pointed to '\0'
--end;

while (src < end) {
if (*src++ != *end--)
return false;
}

return true;
}


当然,还可以用递归方法,就不多说了。

Tuesday, May 05, 2009

从写Makefile谈起

最近一段时间,有所想,故整理成文。

上上个星期,去一家网络公司面试,面试官问我Makefile文件熟悉不?我说,很熟,现在工具很多了,automake一下子就搞定,听说cmake更厉害了。他不同意我的观点,说手写的Makefile要精通,了解各个文件,包的依赖关系,如果给你写一个类似于automake的工具,你会怎么写?我一时懵了,从没想过这个问题,只好瞎掰一番。

确实,在Linux下,普遍用automake,cmake工具。结合我现在的项目,mtk,via平台都是手写的Makefile,这么大的工程,automake,cmake等无法达到完美的方案。其重要原因是代码目录繁多,对于不同客户定制的,不同目标版本,要定义很多很多的宏。

昨晚把c++ primer 3th关于STL algorithm的例子代码编译一下,从12点开始,后面发现竟然花了1个小时,震撼啊!睡之前,想想,干嘛要花那么多的时间啊!明儿要找到原因。

首先,从网上找一个万能的Makefile文件,不过那个Makefile的功能是把所有的.c或.cpp文件编译成为一个bin文件,要动手对其修改.

ls *.C >> Makefile

OBJECTS= \
alg0.exe \
alg10.exe \
alg11.exe \
alg12.exe

CC = g++

CCFLAGS = -ansi -W -Wall

all: $(OBJECTS)

%.o:%.C
$(CC) $(CCFLAGS) -c $< -o $@
%.exe: %.o
$(CC) $(CCFLAGS) $< -o $@

clean:
rm -rf *.o

clobber: clean
rm -rf *.exe istream_iter

一共50多个.C文件,
然后手动一个个
(1) 把 *.C 改为 *.exe
(2) 在*.exe前面加一个tab
(3) 还有在除了末尾一个exe外,其他 *.exe后加tab,再加\符号

而且还是用 vim的 . 重复操作,觉得没什么.

今天想想,实在是太费时间了。
(1) :%s/\>.C/.exe/g
(2) 无意中浏览了水木社区的vi版FAQ才恍然大悟,写代码的时候,缩进时会用>,可是写Makefile文件时,却不会用了。
(3) :m,ns/$\t\\/g



C++ primer 3th 一些内容不是C++标准,那时C++标准还没出来。


(1)
#include <iostream.h> 要改为
#include <iostream>

using namespace std;

一些C库头文件 xxxx.h 改为 cxxxx

我不厌其烦的输入 using namespace std;
输入到到 spaces时,我还特意按了 tab,一下子就自动补充了,很爽啊。
可是,为什么不弄个单词缩写呢。
:abbr usn using namespace std

输入 usn后面再加; 不是很好么?

(2)
vector<int, allocator>
vector<string, allocator>
list<string, allocator>
改为
vector<int>
vecotr<string>
list<string>
就是把 , allocator 去掉. 我一边make,一边看error,一边修改。

三行shell,搞定:

for file in *.C
sed -i 's/, allocator//g' $file
done


总结:
1. 弄清楚,自己在干啥,宁可用错的方法去做对的事情,也不要用对的方法去做错误的事情。
2. 想想自己做的到底是不是重复的劳动?找到解决策略。
3. 节约时间,早点休息。

Friday, May 01, 2009

via cdma 代码目录结构

via cdma 代码目录结构(版本号:0.21)

Abbreviations and Acronyms


HAL Hardware Abstraction Layer
VAL VIA Abstraction Layer
VTUI VIA Telecom UI
ASL Application Support Layer
PS Protocol Stack
ResEditor Resource Editor
Resgen Resource Generator
MS Mobile Station

cp:各种底层文件的集合,包括协议栈,DSPM/DSPV,L1D/L1A软件。
cp下目录及文件:
ai
app
bm
boot
boot.lnk
build_201c.bat
build_grace.bat
build_muse.bat
build_ourea.bat
build_selle.bat
cat.exe
cp2
cp3
CP.LN
cp2.lnk
cp3.lnk
cpflash.LNK
cpflash_16_4.LNK
cpflash_16_4_NoDS.LNK
cpflash_16_8.LNK
cpflash_16_8_G.LNK
cpflash_16_8_NoDS.LNK
cpflash_16_8_NoDS_G.LNK
cpflash_4_2_NoDS.LNK
cpflash_4_2_NoDS_O.LNK
cpflash_8_4.LNK
cpflash_8_4_NoDS.LNK
cpflash_NoDS.LNK
cpsim.lnk
cpver.c
cust
dbm
exe
fsm
hl
hwd
image
inc
iop
ipc
jt
l1d
lmd
CP_Targets.mak
Makefile
makefile_end
makefile_feature
makefile_feature_def
makefile_hdr
media
mkdate.exe
mon
nu
nucleus
obj
pde
ps
pst
res
resource.bat
rlp
rom
runit.exe
shared
sys
tst
ui
uim
val

下面对代码进行分类:
CP 代码主要有下面一些模块(目录),
1. 协议相关(ai/dbm/hl/l1a/l1d/lmd/ps/rlp/ipc)
2. 应用相关(ui/app/res/val/brew/vaawab)
3. 驱动相关(bm/boot/hwd/media/uim)
4. 文件系统相关(fsm)
5. 操作系统相关(nu/nucleus/sys/exe)
6. 公共头文件(inc)
7. 测试调试相关(pst/tst/jt/mon/iop)
8. 客户化相关(cust)

其他文件
Makefile文件

CP_Targets.mak
Makefile
makefile_end
makefile_feature
makefile_feature_def
makefile_hdr

编译批处理命令
build_201c.bat
build_grace.bat
build_muse.bat
build_ourea.bat
build_selle.bat

201c,grace,muse,ourea,selle是不同的平台,他们的UI配置,Flash类型,LCD尺寸等不同。

FLASH
cpflash.LNK
cpflash_16_4.LNK
cpflash_16_4_NoDS.LNK
cpflash_16_8.LNK
cpflash_16_8_G.LNK
cpflash_16_8_NoDS.LNK
cpflash_16_8_NoDS_G.LNK
cpflash_4_2_NoDS.LNK
cpflash_4_2_NoDS_O.LNK
cpflash_8_4.LNK
cpflash_8_4_NoDS.LNK
cpflash_NoDS.LNK

lnk文件命名规则 cpflash_大小_无数据业务.lnk

三个EXE文件
cat.exe
mkdate.exe
runit.exe

前两个就不用解释了,
runit.exe RunIt Executable with Cat parameter

资源批处理文件
resource.bat
添加新的运用程序,添加一些资源后,要先运行这个脚本。

单一的C文件
cpver.c
不言自明了,定义软件版本号

代码编译完后会生成boot.axf、cp.axf、 boot.rom和cp.rom ,
具体目录会根据CBP硬件版本的不同目录文件名会有不同(如ram_revc2或rom_revd0等)。
boot.axf、cp.axf用于audio等一些调试,boot.rom和cp.rom用于手机或模块。

最后,简单讲下与AT相关的内容。


ai | |- aic
- isotel -|- aie
|- aiw


ai,AT interpret。isotel 是ISOTEL Corp. 大概代码被VIA拿用就是了。
isotel分为三个目录:
aic 是给客户可定制的AT,
aie Ai engine for kerkel process,提供解析AT,数据结构,宏等头文件。
aiw Ai wrapper to interactive with other module.

与AT相关的文件还有 val\ValATCmd.c,常用上报命令默认开关和常用命令的默认设置都在这文件里设置,里面还提供了短信编码相关的函数等。

VIA CDMA也没什么好写的了,人家文档也写的很好,花点时间针对性的看看,就很快能上手。工作1年多,接触了4个手机平台,broncho(我们的项目Linux+gtk,已宣告失败),mtk,via,android,都是从事与AT打交道的活,有时间,该总结一下这方面的设计。