2008年11月21日星期五

IMS SDS4.1 training

19,20号参加了Ericsson的IMS SDS4.1的培训。虽然目前还找不到那个公司需要用到这些技术,但是当听着黎巴嫩帅哥老师讲这以前看过的IMS术语心里还是有些开心。
==== 用一句话总结我还记得的术语吧。=======
UA: user agent。
UAC, UAS,C,S分别代表client, server。UAC UAS是相对的。
IMS Core network: 内部使用SIP协议。RTP...这些视频流走的不是ISM网络通道。
SIP 建立会话时使用SDP。SDP放在SIP的body中。
SIP 很像HTTP,有header, 有body。做练习时把SIP的request类型(message reqeust)小写了,结果发出的消息没有收到。
HSS 存放registered User信息,以及用户可以使用的服务(IP/port ...)。Service profile. 其中ifc决定了用户使用特定服务的特定条件。
ifc: Initial Filter Criteria
C-CSCF 从HSS中获得用户的service profile,然后去寻找service application server,比如PoC, WE-Share, IMS-MSG...
P-CSCF 用户终端(UA)不是直接与C-CSCF talking的。每个UA都固化了P-CSCF 的地址。P-CSCF是与域相关的。
每个电信运营商有自己的domain。比如,chinamobile, vodafone...
Application Server通过SIP servlet处理SIP请求,进行response。SIP servlet像及了HttpServlet。
很遗憾,其它的IMS节点老师就没有再讲了。(Ericsson内部五天的课程,现在压缩成2天。)
==== SDS =====
SDS非常好用。熟悉eclipse的,学习曲线很平坦。SDS menu item提供了几个perspective。DNS, HSS, CSCF的设置很直观。比较炫的一个功能是可以把来来回回的SIP 请求以sequence图的形式画出来。非常直观,见图。
安装glassfish后,一直不能很好的启动glassfish。后来发现是防火墙的原因。同时,启动glassfish之前最好要把DNS, CSCF Server也启动了。
==== 一些规范 =====
  • ICP java API: 用于windows/symbian UIQ3
  • ICP C++ API: 用于S-60
  • IJCU API: 用于J2me
  • JSR 281 : 用于java phone。 IJCU是JSR281的subset. 针对的是IMS core。
  • JSR 325: 还没有finalise。定义了OMA规范了的service, 针对的是IMS service那层。 比如IMPS,PoC...
  • JSR116, SIP Servlet 1.0 JSR289,SIP Servlet 1.1

    有个术语“IMS Client Framework”。这个framwork是手机的功能集。以上的API规范是IMS Client Framework之上的一层。

    针 对android, iPhone, windows mobile平台的API现在还没有。移动终端太混乱了。虽然moto不自己玩自己了、Nokia买了Symbian和Qt、索爱不玩UIQ了,但是还是 有micrisoft, google, apple。以后不知道谁会被整合到谁的手里。

2008年9月24日星期三

RICO notes

1, 设置Rico.TabbedPanel某个tab为选中状态。 tabs.openByIndex(); tabs.selectionSet.select($$('div.panelHeader'[2]));


2, 删除Rico.LiveGrid 中的一行。
<script type='text/javascript'>
var gridA;
Rico.loadModule('LiveGrid','LiveGridMenu','greenHdg.css');
Rico.onLoad( function() {
var buffer = new Rico.Buffer.Base($('licenseePayloadDG').tBodies[0]);
var grid_options = {
columnSpecs: [ {width:280},
{width:280},
{width:180},
{width:200}
]
};
gridA = new Rico.LiveGrid('licenseePayloadDG', buffer, grid_options);
});


function deleteCurrentRow(obj){
var cell = obj.parentNode;
gridA.selectCell(cell);
var row = gridA.SelectIdxStart.row; // SelectIdxStart.row 表示了当前选中的行的index。
var col = gridA.SelectIdxStart.column; // SelectIdxStart.column 表示了当前选中的列的index。
var cols = gridA.headerColCnt; // headerColCnt 表示了列的总数,是个常量。

gridA.selectRow(row); // selectRow(row) 高亮某行。row是行的索引。

// buffer 是Rico LiveGrid的数据模型对象。baseRows是数组格式的数据。baseRows.splice(row, count) 就把数据从数据模型中删除了。
gridA.buffer.baseRows.splice(row, 1);

// 删除数据后需要刷新页面才能看出效果。
gridA.refreshContents(0);
}


function removeCellzRow(row) {
for( var c=0; c < gridA.headerColCnt; c++ ) {
// LiveGrid的表格形式并不是由HTML table 表示的由<div> + css表现的。columns[]表示了所有的列。columns[c].cell(row)定位到了一个cell.
var cell=gridA.columns[c].cell(row);

// 选择一个单元格。
gridA.selectCell(cell);

// 清空一个单元格的内容。注意: 设置innerHTML=""只是把表现层的东西清空了。后台的数据模型gridA.buffer.baseRows并没有改变。
cell.innerHTML = "";
}
}
</script>

对应的HTML: <a href="#" onclick='javascript: {if(confirm("deleteRow?")) {deleteCurrentRow(this); }else {}}'>DelRow</a>




2008年9月7日星期日

运行时

以前的datamodel过于复杂,而且对于未来的计划是早晚要替换掉旧代码,那么如何隔离旧的接口给新的API呢?
我的方法是:定义一个新接口、新的一些class,用旧的class实现这个新接口。外面的模块使用旧的Class的地方,都用新接口引用。
Willie则直接了当的用了extends。
Willie把FConnector继承Thread的关系掐掉了。Connector确实没必要以thread的方式运行。因为其下的session是个thread。牛人终归是牛人,下手就是地方。
总的说来,脑袋里有个动态的系统运行某型至关重要,静态的类图是不够全面的,从某种意义上来说动态模型才是一个真正的程序模型。
最为一个senior的programmer 每个UseCase的call sequences,一定要能在脑袋里流出来,这都搞不定,别提可靠性。
对于高手,代码就是设计。这句话的含义就是对于高手来说,它的大脑就是一个JVM,他知道一个程序从某点执行下去到某点,这个JVM里有几个class,每个class有几个instance, 有多少个线程。
没这水平,就先用UML画点图,自己琢磨琢磨吧。
Spring这个东西得到了公认。除了其中的IoC、AOP这些概念外,其配置文件的功能--装配,不就是强制让你考虑了系统启动时的个对象、实例的各种关系(静态/动态)么?

2008年6月5日星期四

Qt environment for Marvell board.

用于Marvell的板子。
=============== 安装toolchain 以及 Qt
1, create diretory /CMMB

2, cp PlatformRel_Linux2.6.21_MHLV.tgz into the /CMMB

3, tar xvzf PlatformRel_Linux2.6.21_MHLV.tgz
this step create dir pxalinux.

4, cd /CMMB/pxalinux/toolchain
tar xvzf arm-iwmmxt-linux-gnueabi-4.1.1-gpl-lgpl.tgz
This stup create toolchain files in dir /CMMB/pxalinux/toolchain/arm-linux-4.1.1

5, modify the /root/.bashrc to add the path /CMMB/pxalinux/toolchain/arm-linux-4.1.1/bin
into the env var PATH.
export PATH=/CMMB/pxalinux/toolchain/arm-linux-4.1.1/bin:$PATH

6, cd /CMMB/pxalinux/package/usage-model-7.0.5
tar xvzf qtopia-src-gpl.tgz
After this step, the dir qtopia_2.2.0 is created.

7, cd /CMMB/pxalinux/package/usage-model-7.0.5/qtopia_2.2.0
and run the shell: yes | ./build_qtopia.sh > build.log

8,
// 设定 qmake路径。
export PATH=/CMMB/pxalinux/package/usage-model-7.0.5/qtopia_2.2.0/work/qtopia-free-2.2.0/dqt/bin:$PATH
export QMAKESPEC=/CMMB/pxalinux/package/usage-model-7.0.5/qtopia_2.2.0/work/qtopia-free-2.2.0/qtopia/mkspecs/qws/linux-arm-g++

cd /CMMB/pxalinux/package/usage-model-7.0.5/qtopia_2.2.0/work/qtopia-free-2.2.0
chmod +x setQpeEnv
./setQpeEnv


=============== 配置Qt开发环境

1, Create account for development
groupadd cmmbdev
adduser cmmb -g cmmbdev
passwd cmmb

2, Create a shell setDevEnv.sh, including:
# 导入Qtopia环境变量
source /CMMB/pxalinux/package/usage-model-7.0.5/qtopia_2.2.0/work/qtopia-free-2.2.0/setQpeEnv

# 设置toolchain路径
export PATH=/CMMB/pxalinux/toolchain/arm-linux-4.1.1/bin:$PATH

# 设置qmake路径
export PATH=/CMMB/pxalinux/package/usage-model-7.0.5/qtopia_2.2.0/work/qtopia-free-2.2.0/dqt/bin:$PATH

# 设置qmake环境变量配置路径
export QMAKESPEC=/CMMB/pxalinux/package/usage-model-7.0.5/qtopia_2.2.0/work/qtopia-free-2.2.0/qtopia/mkspecs/qws/linux-arm-g++


3, add . ./setDevEnv.sh into the cmmb user's .bashrc

4, chmod -R +r /CMMB/pxalinux
cd /CMMB
mkdir tvp
chown -R cmmb tvp

5, qmake -project
modify tvp.pro to include:
QMAKE_LIBS_QT += -ljpeg -luuid -lts -lqpe

6, qmake
7, make



通用的QT安装
1) 升级Kernel
rpm -ql | grep kern
yum intall kern*
2) 修改grub.conf使console支持FrameBuffer。在引导界面可以看到小企鹅。/dev目录下有设备fb0。 这样从console中就可以直接运行GUI程序了。



试图生成 libqte-mt.so, 用于QThread.
2) qt2
./configure -qt2 '-no-xft -thread -I/usr/include -I/usr/include/freetype2 -I/usr/include/freetype'
ln -sf /pub/qtopia-free-2.2.0/dqt/lib/libqt-mt.so.3.3.5 /pub/qtopia-free-2.2.0/qtopia/lib/libqte-mt.so

3)
./configure -qt2 '-no-xft -thread -I/usr/include -I/usr/include/freetype2 -I/usr/include/freetype'

以上步骤都不能生成libqte-mt.so
通过修改config.cache,可以生成libqte-mt.so了。
QPEDIR=/pub/qtopia-free-2.2.0/qtopia
QTOPIA_DEPOT_PATH=/pub/qtopia-free-2.2.0/qtopia
TMAKEDIR=/pub/qtopia-free-2.2.0/tmake
DQTDIR=/pub/qtopia-free-2.2.0/dqt
QT2DIR=/pub/qtopia-free-2.2.0/qt2
QTEDIR=/pub/qtopia-free-2.2.0/qt2
QPE_CFG="-edition pda -displaysize 240x320 -no-qtopiadesktop -release -platform 'linux-g++' -xplatform 'linux-generic-g++'"
QTE_CFG="-embedded -no-xft -qconfig qpe -qvfb -thread -depths 4,8,16,32 -system-jpeg -gif -D QT_TRANSFORM_VFB -release -platform 'linux-g++' -xplatform 'linux-generic-g++'"
QT2_CFG="-no-opengl -no-xft -no-sm -platform 'linux-g++'"
DQT_CFG="-thread -qt-gif -fast -platform 'linux-g++'"
USE_CACHE="no"
这样,Qt2的线程包没有生成,估计要设置-thread 到QT2_CFG中.

虽然这样做生成了libqte-mt.so, 但是把QThread用于QTopia程序(带GUI)时仍旧发生段错误. 普通的QT程序使用QThread时就没有问题.

后来通过配置qtopia的编译发现了这段警告. 看来在qtopia2.2下使用QThread是不稳定的.
[root@localhost qtopia]# ./configure -debug -thread -I/usr/include:/usr/include/freetype:/usr/include/freetype2 -qvfb -qtopia
QPEDIR = /pub/qtopia-free-2.2.0/qtopia
DEPOT = /pub/qpe2.2/qtopia
The following configuration values have been guessed or autodetected:
-arch generic
-displaysize 240-320
-edition pda
-fontfamilies helvetica fixed micro smallsmooth smoothtimes
-fontsizes all
-fontstyles 50 50i 75 75i
-languages en_US
-platform linux-g++
-xplatform linux-generic-g++

WARNING: Trolltech does not support building Qtopia against a multi-threaded Qt.
While it should work, Trolltech can make no guarantees about the ability
of Qtopia to operate correctly when Qt is multi-threaded. If you wish to
use threads in your own apps, you should consider using pthreads directly.

Symlinking header files to include directory
Creating qmake.......



因为以上Qtopia2.2中QThread的问题,这两天改用qtopia-opensource-4.3.1了. 感觉不错。
Qtopia-opensource-4.3.1的安装。
1)安装。
./configure 过程中有警告和错误提示如下。但是不用管它们,依旧可以编译通过。
Project ERROR: This is a dummy profile to be used for translations ONLY.
WARNING: Failure to find: qvfbhdr.h
在gmake的过程中,提示缺少库libXtst, libXmu,而不能继续。此时需要使用 yum install libXtst*, yum install libXmu*进行安装。

2)gmake install。
这一步会生成image。所有要运行的程序都要放在image/bin目录下。这是完整的Qtopia运行环境。

3)样例程序。
把example的样例程序随便copy到某个目录里。通过qtopiamake生成Makefile. 用make install INSTALL_ROOT="imagePath" 进行编译安装。



gstreamer 库与Qtopia的结合。
把利用gstreamer播放mp3的函数封装到动态库libmyGstLib.so中。Qtopia的GUI程序直接库中的函数。遇到的问题及解决如下:
1)段错误。
写了一个很简单的动态库供qtopia程序适用,一切正常。 排除了qtopia的问题。
int startPlayer (int argc, char *argv[]); 方法中有: gst_init (&argc, &argv); 而在Qtopia对其的调用中传递的是startPlayer(1, NULL);
怀疑gstreamer使用了argc, argv参数。于是就把NULL改为了一个字符串数组。问题解决了。但是又说没有找到"mad"插件。

又写了一个只有main函数,调用动态库的程序,却没有mad插件的错误。播放mp3没有问题。
察看了一下编译main函数使用的gcc参数。
libtool --mode=link gcc `pkg-config --cflags --libs gstreamer-0.10` -o gstTestApp test.c
gcc -pthread -I/usr/local/include/gstreamer-0.10 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -pthread -o myprog test.c -L/usr/local/lib -L/lib /usr/local/lib/libgstreamer-0.10.so -lrt -lgobject-2.0 -lgmodule-2.0 -ldl -lgthread-2.0 -lxml2 -lz -lm -lglib-2.0 -Wl,--rpath -Wl,/usr/local/lib -Wl,--rpath -Wl,/usr/local/lib

而libmad安装后也提示:
If you ever happen to want to link against installed libraries
in a given directory, LIBDIR, you must either use libtool, and
specify the full pathname of the library, or use the `-LLIBDIR'
flag during linking and do at least one of the following:
- add LIBDIR to the `LD_LIBRARY_PATH' environment variable
during execution
- add LIBDIR to the `LD_RUN_PATH' environment variable
during linking
- use the `-Wl,--rpath -Wl,LIBDIR' linker flag
- have your system administrator add LIBDIR to `/etc/ld.so.conf'

See any operating system documentation about shared libraries for
more information, such as the ld(1) and ld.so(8) manual pages.
通过把这些库和编译选项加入到了myGstLib的编译文件中后,程序就可以播放mp3了.

2) Qt中的Singal-slot机制是同步的.如果某个signal没有处理完毕,界面就会冻结。所以需要使用线程进行播放。




2008年4月24日星期四

VS2008创建wxwidget 项目

尝试用vs2008 express版学习wxwidget。建立了一个helloworld都没能链接成功。照网上的文章做了也不行。最后还是参照其自带的samples把项目属性设置成功了。至于以前设置的错误,希望随着时间的积累能够原因。步骤大致如下:
1,把wxWidget安装到 D:\wxWidgets-2.8.7。设置环境变量WXWIN=D:\wxWidgets-2.8.7。
2,用vs2008打开D:\wxWidgets-2.8.7\build\msw\wx.dsw,编译所有代码。
3,可以另起一个solution,创建一个空项目。
4,把helloworld程序past进去。
5,设置项目属性:
additional include directories: "$(WXWIN)\lib\vc_lib\mswd";"$(WXWIN)\include"
preprocessor: WIN32;_DEBUG;__WXMSW__;__WXDEBUG__;_WINDOWS;NOPCH
additional library directories: $(WXWIN)\lib\vc_lib

错误的版本加入了一些其它头文件路径。

2008年4月18日星期五

对google BLOG HTML代码的修改。

1)使用默认的模版代码,不能在IE下浏览。据说是因为编码的问题。把<$BlogMetaData$>放到head标签后面。


2)现在都是宽屏的显示器了。模版中的正文宽度太狭窄了,调宽:
把所有width:700px的地方都换成900px, 因为模版中content图片的宽度是固定的 900所以去调下面粗体部分。
#main-content {
width:900px;
background:#FFF3DB url("http://www.blogblog.com/scribe/bg_paper_mid.jpg") repeat-y;
margin:0;
text-align:left;
display:block;
}

@media all {
#main {
width:630px; // 由原来的430改为630。
float:right;
padding:8px 0;
margin:0;
}
这样整个content布局宽度增加了200pix。

理解libjingle的ThreadManager

Thread Local Storage(TLS)的作用。
进程中的所有线程共享进程的虚拟地址空间。方法中的局部变量对于每个运行这个方法的线程是独立唯一的。但是,全局的静态变量是被这个进程中的所有线程共享的。通过使用TLS你可以为每个线程提供独立的数据。

一般在process初始化时分配tls Index。这样随后这个process中的线程就可以通过这个index存储与每个线程自己相关的数据了。
msdn关于TlsAlloc()的说明:
Allocates a thread local storage (TLS) index. Any thread of the process can subsequently use this index to store and retrieve values that are local to the thread, because each thread receives its own slot for the index.
If the function succeeds, the return value is a TLS index. The slots for the index are initialized to zero.
The threads of the process can use the TLS index in subsequent calls to the TlsFree, TlsSetValue, or TlsGetValue functions. The value of the TLS index should be treated as an opaque value; do not assume that it is an index into a zero-based array
TLS indexes are typically allocated during process or dynamic-link library (DLL) initialization. After a TLS index has been allocated, each thread of the process can use it to access its own TLS storage slot. To store a value in its TLS slot, a thread specifies the index in a call to TlsSetValue. The thread specifies the same index in a subsequent call to TlsGetValue, to retrieve the stored value.
TLS indexes are not valid across process boundaries. A DLL cannot assume that an index assigned in one process is valid in another process.


libjingel中的ThreadManager。
这个类完成对所有Thread实例线程的管理。其中就分配了一个slot index用于保存current thread。

ThreadManager使用ScriticalSecion,ScriticalSection相当于java中的synchronize中使用的锁。
windows使用CRITICAL_SECTION 定义锁。POSIX使用pthread_mutex_t。
相应的方法分别是:
windows: InitializeCriticalSection(&crit_)、EnterCriticalSection(&crit_)、 LeaveCriticalSection(&crit_)、DeleteCriticalSection(&crit_)。
POSIX: pthread_mutex_init()、pthread_mutex_lock(&mutex_)、 pthread_mutex_destroy(&mutex_)、 pthread_mutex_unlock(&mutex_)
ScriticalScope则相当于java中的synchronize块。

CreateThread
Widows 下创建线程的签名。 HANDLE CreateThread( LPSECURITY_ATTRIBUTES lpsa, DWORD cbStack, LPTHREAD_START_ROUTINE lpStartAddr, LPVOID lpvThreadParam, DWORD fdwCreate, LPDWORD lpIDThread);
lpStartAddr是线程运行起始地址,函数指针。lpvThreadParam为函数的参数。
thread_ = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PreRun, this, flags, NULL);
void *Thread::PreRun(void *pv) {
Thread *thread = (Thread *)pv;
ThreadManager::SetCurrent(thread); // 此处把thread放到了TLS中了。
thread->Run();
return NULL;
}


[都怀疑java的native code是不是都是用了ACE的东西了,至少思路该是一样的吧。]

2008年4月13日星期日

sigslot in libjingle

The libjingle depends on the sigslot very much. From the Pattern's view, the signal-slot follows the Observer pattern.
To use the sigslot, there are 3 steps.
1) Define a Sender. The sender has a signal.
2) Of course, there's a Receiver which extends from the sigslot::slot. The receiver is the slot.
3) Somewhere, there must be a method that will connect the Sender's signal to the Receiver's slot(s) by calling the signal's connect method.
SignalA maybe is defined like this: sigslot::signal2 SignalA;
aReceiver is an object whose class inherits from sigslot::has_slots<>
aFunctionPointer is the processor of a signal. In this case, this processor method need two parameters.
Connect the signalA with the receiver's function just like this:
SignalA.connect(aReceiver , aFunctionPointer);

Reviewed these C++ keywords/concept today.
extern explicit "const member function"