星期二, 五月 16, 2006

Ajax来了

我对这个新的技术本来是没有什么想法的。原因是很早以前写JavaScript的时候一定会伴随着IE左下角黄色的感叹号的网页总是不是那么让人感到放心。后来Google的缘故开始看了看Ajax的介绍,就是异步方式的HTTP请求,JS处理DOM的系统。我总是对Js的编写存在疑虑,一是如何调试,而且现在的Ajax还牵扯到前后台两部分同时进行分析和设计的问题。二是兼容的问题,浏览器太多了,鬼也就见多了,总不能像C编写程序一样到处都是#ifdef-#else-#endif的奇怪语法。
最早的时候先找到了SAjax,这是一个PHP(还有其他语言)的一个简单的Ajax框架,将Ajax调用便成类似异步RPC的方式进行。然后看见了DOJO,一个庞大内容也无比丰富的纯Js库,包含非常强大的组件,但是不包括服务器端。网上最推荐的是Prototype,比较DOJO它的工作非常的底层,但是对Js语言来说却是一个非常伟大的进步,大大改善了Js薄弱的面对对象开发能力。唯一的问题就是文档的缺乏和组织上的不明确,让我这样的入门者实在是找不到东南西北,所以到现在还在摸索中。
为什么要使用Ajax呢?难道就是模仿Google?这个肯定不是原因。我看这个是受同学实际需要的启发:如何让网站增进客户的互动能力,从而得到更多客户的信息,或者让客户得到我们更多的信息。这对於变化万千的市场需求波动是非常有力的工具。以往留言簿和评论这样的措施解决了一些问题,但是对于客户的要求还是过高。直白、及时、响应、变化的面对面交流是柜台服务的特点也是网络销售需要学习的。别忘了中国有多少人会使用Email呢?我怀疑有没有两千万。
但是Ajax的缺陷也一一暴露出来。特别是开发的时候需要框架上设计有前瞻性,可实施性。调试需要的时间很长,而且问题很难在简单的Alpha测试中全部体现。逻辑和代码覆盖测试也很难进行。这一切和缺少适当的Js调试、测试工具有一定的关系。运行中,由于Js请求往往要求及时快速,所以对服务器的要求很高。比如GMail中鼠标移动中需要经常性的发出请求。而且以GET发出的XMLHTTPRequest对log的占用很高,几天的运行就会有很大的日志文件,对服务器日志分析工作的压力也是蛮大的。

星期一, 五月 01, 2006

移植uC/OS-II到DSP(TMS320LF2407)

主要的问题就是如何知道堆栈的变化情况。
  1. C函数调用前后的堆栈变化 。(看看编译后的汇编就知道了)
  2. 中断中堆栈的变化,特别是C编写中断程序时的情况。(看看I$$SAVE 和 I$$REST )
  3. 一个刚开始运行,但是还没有进入的C函数堆栈情况。(编一个用汇编调用C的例子看看)
只要知道了这些就可以进行移植的工作了。

其实来,主要的难点时对OS实现原理的理解。比如什么时候发生调度,调度的时候需要那些工作。这一部分主要在OSCtxSw()实现的软件中断,和定时器中断中调用的OSIntExit()->OSIntCtxSw()的过程中发生。而OSIntCtxSw和OSCtxSw的不同在DSP上只有栈顶位置的不同。所以,问题都归咎到了堆栈的处理上了。没有办法,只有汇编重要部分的代码,看看到底压入了什么内容,计算好距离即可。


这里先说一说DSP初始化堆栈的情况,也就是最前面说的第三种堆栈情况-当中断发生在写入了参数也调用了CALL,但是还没有执行这个C函数的那一刻,堆栈到底有什么内容。这就是函数OSTaskStkInit需要处理的内容了。
// -- 模拟C函数运行时堆栈的情况 --
*stk++ = (UWORD)pdata; // 入口参数
*stk++ = (UWORD)c_int0; // 旧PC

// -- CPU寄存器内容备份 --
*stk++ = (UWORD)0x2000; // ST1
*stk++ = (UWORD)0x2200; // ST0
*stk++ = (UWORD)0x0000; // 累加器ACC高16位
*stk++ = (UWORD)0x0000; // 累加器ACC低16位
*stk++ = (UWORD)0x0000; // 乘法寄存器高16位
*stk++ = (UWORD)0x0000; // 乘法寄存器低16位
*stk++ = (UWORD)0x0000; // 临时寄存器TREG

*stk++ = (UWORD)ptos + 4; // AR0
*stk++ = (UWORD)0x0000; // AR2
*stk++ = (UWORD)0x0000; // AR3
*stk++ = (UWORD)0x0000; // AR4
*stk++ = (UWORD)0x0000; // AR5
*stk++ = (UWORD)0x0000; // AR6
*stk++ = (UWORD)0x0000; // AR7

// -- 硬件堆栈备份--
*stk++ = (UWORD)task; // 中断返回地址 = 任务其始地址
*stk++ = (UWORD)c_int0;
*stk++ = (UWORD)c_int0;
*stk++ = (UWORD)c_int0;
*stk++ = (UWORD)c_int0;
*stk++ = (UWORD)c_int0;
*stk++ = (UWORD)c_int0;
这里完成第三种堆栈情况的仿真工作,此时stk就是这个任务需要的AR1(SP)数值。(这里面的c_int0是调试种为了防止堆栈错误写的C语言入口,便于在出错的时候系统重新初始化。)

剩下的任务就非常简单了,只需要看着那本RMB$79的书,完全按照要求编写OSCtxSw函数即可。值得注意的就是保存和返回任务我们需要使用“CALL I$$SAVE”和“B I$$REST”来实现。而OSIntCtxSw的实现则更加简单,只需要参照你的定时器中断函数调用时栈顶到I$$SAVE调用后栈顶之间的距离,用AR1减去这个值,然后跳入到OSCtxSw在“CALL I$$SAVE”之后的内容即可。

接下来的事情就是编写你的C语言主函数和任务等等东西了。非常的简单,不过定时器的周期需要按照OS_TICKS_PER_SEC的设定设置好。然后顺序调用
OSTimeTick(); // uC/OS的系统定时
OSIntEnter();
OSIntExit(); // OSIntCtxSw包含enable()调用
这三个函数即可。
值得注意的地方是:OSIntExit()将直接从中断处理中通过I$$REST进入到优先级最高、准备好的任务中,所以之后的代码不会被执行。

其他的就和x86平台上没有什么区别了。不过这里你只能通过一些二极管什么的显示一下活动的任务,比较惨吧!