<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>rubynroll</title>
    <description></description>
    <link>http://rubynroll.javaeye.com</link>
    <language>UTF-8</language>
    <copyright>Copyright 2003-2008, JavaEye.com</copyright>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
    <generator>JavaEye - 做最棒的软件开发交流社区</generator>
      <item>
        <title>Ruby'陷阱'之: '||=' 的真正展开式</title>
        <author>rubynroll</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://rubynroll.javaeye.com">rubynroll</a>&nbsp;
          链接：<a href="http://rubynroll.javaeye.com/blog/208806" style="color:red;">http://rubynroll.javaeye.com/blog/208806</a>&nbsp;
          发表时间: 2008年06月27日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <em>前一段时间,我在这里<a href="http://rubynroll.javaeye.com/blog/192547" target="_blank">http://rubynroll.javaeye.com/blog/192547</a>展示了一个空格带来的'陷阱', 今天又见到另一个'陷阱'(http://dablog.rubypal.com/2008/3/25/a-short-circuit-edge-case by David).</em><br /><br />之所以为陷阱加引号, 是因为大部分情况下我们都没有机会掉进去 :)<br /><br /><strong>大多数Ruby教科书在解释 "a ||= b" 这个复合操作时,都说她等效于: "a = a || b", 实际上真的如此么?</strong><br /><br />让我们在irb里面来看看:<br /><br /><pre name="code" class="ruby">h = Hash.new(1)  # 生成一个新的Hash,缺省值为1
=> {}
h[:x]
=> 1    # h[:x]未定义,所以返回1
h[:x] ||= 2
=> 1
h
=> {}   # 啊? '陷阱'?
h[:x] = h[:x] || 2
=> 1
h
=> {:x=>1}  # 啊!</pre><br /><br />David提到,<strong>Matz在RubyConf 2007上的解释是"a ||= b"真实的等价应该是: "a or a = b", 但是David后来认为"a || a = b"应该更恰当些</strong>.<br /><br />果真的如此么? 不!<br /><br />一个简单的例子可以反驳, 如果a未定义,则:<br /><br /><pre name="code" class="ruby">irb(main):001:0> a || a = 2
NameError: undefined local variable or method `a' for main:Object
        from (irb):1
        from :0</pre><br /><br />所以, <strong>看来"a ||= b"正确的展开应该是: "a = b unless a"</strong><br /><br />对了么? 还是不对!<br /><br />"a ||= b"表达式最终返回的是a, 而"a = b unless a"在a非真时返回nil.<br /><br />所以, <span style="font-size: large">"a ||= b"的正确展开式应该为: "if a then a else a = b end"<br /></span><br /><br />想不到吧?
          <br/>
          <span style="color:red;">
            <a href="http://rubynroll.javaeye.com/blog/208806#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 27 Jun 2008 20:14:52 +0800</pubDate>
        <link>http://rubynroll.javaeye.com/blog/208806</link>
        <guid>http://rubynroll.javaeye.com/blog/208806</guid>
      </item>
      <item>
        <title>SVN+GIT=鱼与熊掌兼得</title>
        <author>rubynroll</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://rubynroll.javaeye.com">rubynroll</a>&nbsp;
          链接：<a href="http://rubynroll.javaeye.com/blog/203133" style="color:red;">http://rubynroll.javaeye.com/blog/203133</a>&nbsp;
          发表时间: 2008年06月13日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          使用git已经有一段时间了,从使用git的第一天开始,就计划逐步放弃svn.<br /><br />svn有的功能,git都能做到,而且做得更出色,况且git还有很多特性svn望尘莫及,还有什么理由继续使用svn呢? <br /><br />well,理由很多. 比如,git在windows上的性能问题, TortoiseGIT还没有开发出来(或者根本没有这个计划?),团队中其它人员不习惯用git....等等.<br /><br />那么,鱼与熊掌,能否兼得?<br /><br />=== SVN 之痛与痒 ===<br /><br />svn的最大问题是不支持分布式开发. 分布式并不一定就是指象Linux Kernel那样的大型协作开发场景. <br /><br />例如,你想把没做完的工作带回家做,但是家里又不能连线到公司的svn服务器,那么你就不能commit. 实际上,这也是一种分布式开发的场景.<br /><br />你会说,那你就不要commit啊 ... 我办不到, 我有个坏习惯,经常做些小改动,但是十分钟后就后悔了想改回来,只有经常commit我才能找回上次,上上次变更.<br /><br />当然,我有坏习惯因此我不会commit到trunk或主branch上,否则会被扁死 :-)<br />所以,我经常有很多临时branch要merge,频率非常之高...在svn中的merge并不好玩.<br /><br />不得不说,svn的repository设计很糟糕. 慢, 特别是在项目规模上去,开发周期长时,repository迅速膨胀.项目树中到处都是.svn也是很讨厌.<br /><br />但是, TortoiseSVN实在是方便, 很多人使用SVN就是因为图这个方便.<br />支持SVN的IDE也数不胜数.<br /><br />SVN,既痛又痒....<br /><br />=== GIT 的威力 ===<br /><br />git很快,真的很快,比小李飞刀还快...(当然是在Linux下).<br />试试checkout Linux Kernel的各个tag,那个速度,不得不佩服,呵呵~<br /><br />其实对于小项目来说,速度倒无所谓,不差那么几秒,git还有很多cool things.<br /><br />git diff很强大,真的很强大.比较任何两个历史版本,速度飞快.<br /><br />git中做branch简直太简单了,branch merge也是非常的爽,更不用说three way merge了. 当然还有很多很cool的特性,例如,与别人的git tree进行merge ... 其实这些或多或少都是由于分布式的特性带来的.<br /><br />还有那些通过email commit等等一般小团队开发用不到的功能,就不多说了.<br /><br />=== 鱼与熊掌兼得 ===<br /><br />首先,svn照用,主版本管理用svn(照顾团队嘛).<br /><br />然后在项目目录下建git repository: git init.<br />这只在项目根目录下多出一个.git目录,不会象svn或cvs那样,每个子目录都有它的垃圾.<br /><br />接下来,建立.gitignore文件,把不需要git管理的文件,加入此表,例如.svn. 或者进入.git/info编辑exclude文件.<br /><br />加入git: git add .<br /><br />完成了,就这么简单.<br /><br />从此以后,小的,临时的改动,通通用git来管理,又快又准,还不影响别人. 因为你只用到本地git repository,与其他人无关.<br /><br />各人建各人自己的git tree,互不干扰. 当然,如果你想日后某一天可以merge别人的tree,那么还是建一个bare public tree吧, 各人clone一个,然后工作在自己的branch下,平时还是照样离线commit,需要时push.<br /><br />在家里工作?没问题,照样可以commit,git是分布式的.<br /><br />回到公司后,想commit到svn?没问题,在git中checkout你想要的"working code"版本,再在svn中commit, 然后git再checkout HEAD,继续前行 :)<br /><br />=== 结论 ===<br /><br />svn和git结合, 可以带来以下好处:<br />1) 与单独使用svn的其它组员不冲突<br />2) 享受git分布式带来的好处<br />3) 可以满足svn commit working code的需求<br />4) svn大粒度管理,减轻svn repository的压力.<br />5) svn继续发挥GUI便利的优势.<br /><br />所以, SVN + GIT = 鱼与熊掌兼得<br /><br /><br /><em>有趣的是,Linus当时设计git的时候,说:"...当碰到一个特性不确定应该采取什么样的设计时,就只要照着svn的反方向设计就对了..."<br /></em>
          <br/>
          <span style="color:red;">
            <a href="http://rubynroll.javaeye.com/blog/203133#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 13 Jun 2008 22:45:36 +0800</pubDate>
        <link>http://rubynroll.javaeye.com/blog/203133</link>
        <guid>http://rubynroll.javaeye.com/blog/203133</guid>
      </item>
      <item>
        <title>动态模块加载和ELF Loader</title>
        <author>rubynroll</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://rubynroll.javaeye.com">rubynroll</a>&nbsp;
          链接：<a href="http://rubynroll.javaeye.com/blog/202461" style="color:red;">http://rubynroll.javaeye.com/blog/202461</a>&nbsp;
          发表时间: 2008年06月12日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          很早很早以前就想在嵌入式系统上实现动态模块加载的功能了，期间走了些弯路，直到最近，才完整地在嵌入式系统上实现动态模块加载。<br /><br />=== 动态模块加载的好处 ===<br /><br />动态模块加载的好处很多，例如，当你升级一个系统的时候，可以只升级一个模块，而不必升级整个系统。你可以把不同的模块放在不同的介质上，并实施不同等级的保护，例如BIOS部分进行写保护。<br /><br />有些系统允许用户进行二次开发，这个时候几乎一定是需要动态加载功能的，因为你不希望用户需要链接整个系统才能够进行二次开发，而且你可能希望支持多个用户模块，彼此不相互依赖，彼此不干扰。<br /><br />=== Background ===<br /><br />一般来说，C的编译器编译出来的代码，由以下几个重要的部分：<br />.code: 代码段<br />.data: 有初值的数据段<br />.bss： 无初值的数据段<br /><br />通常还有.rodata，是只读的数据段，在嵌入式系统中经常可以合并到.code段中.<br /><br />注： .code, .data 和.bss这些段的命名不同的编译器可能会有不同。<br /><br />由于不同段在实际运行的时候可能会被加载到不同的介质，例如.code和.rodata可以放在NOR FLASH上而.data,.bss放入RAM中，或者要满足所谓的scatter loading，因此编译器会努力使段可以自由移动。<br /><br />但是要做到这一点，并不容易。<br /><br />在代码段中运行的指令，要获取数据段中的数据，方法有：<br />a) 通过当前PC值＋偏移量<br />b) 通过绝对地址<br />c) 通过中间寄存器，寄存器里面：<br />   c.1) 存放绝对地址<br />   c.2) 偏移量<br /><br />方法b通常只在CISC中存在，许多RISC机器由于指令长度受限制，并不存在方法b。<br /><br />因此，从这里可以看出，要做到各段可以自由移动,有几种方法：<br />1) 保留一个寄存器专门用于指示数据段的起始地址<br />2) 运行前修改指令<br />3) 保留一小块数据段和代码段的相对位置不变，此片数据段作为指向实际数据段的入口表， 运行前修改此表。<br /><br />方法1和方法3通常会结合起来一起用，动态链接库就是用了这种技术。<br />方发2是一种通用的方法，实际上连接器就是这样生成可执行文件的。<br /><br />=== ARM AIF ===<br /><br />ARM公司的编译器有一项特殊的功能，即可以产生一种可自我重定位的可执行文件，即AIF格式。<br />在AIF文件中，包含了一个AIF头和一小段由编译器产生的重定位代码。运行AIF格式的文件，只需要告诉它起始地址，这段重定位代码就会负责修改余下的一些必要的信息达到重定位目的。目前还没有充分的公开的文档解释AIF内部的详细工作机制。<br /><br />在我过去的一些项目中，AIF工作的很好，但是运行时外部无法获取AIF文件的更多信息，例如你无法去调用AIF映像中的某一个函数，因为你不知道它的地址。另外，AIF的执行映像中，.data必须紧跟在.code之后，对于想重定位到FLASH中执行的嵌入式系统就行不通了。<br /><br />=== ELF ===<br /><br />ELF文件是最常见的目标文件格式，它可能有很多扩展名，例如.o，.so,或者最终的可执行文件也是ELF。<br /><br />ELF有几种：<br />* 可重定位<br />* 可动态链接<br />* 可执行<br />* 可执行＋可重定位<br /><br />可执行的ELF如果没有可重定位信息，那就只能靠虚拟内存系统来支持它运行。但是对于许多嵌入式系统，有可能连MMU都不具备，因此我们只关心可重定位的ELF。（可动态链接ELF实际上也是可重定位的一种，附加很多额外信息）<br /><br />有关ELF的详细信息，请参阅：http://www.skyfree.org/linux/references/ELF_Format.pdf<br /><br />=== ELF Loader ===<br /><br />我花了不少时间寻找小型的ELF Loader实现，但是真正适合嵌入式系统的却不多。<br /><br />+Contiki OS:<br />在Contiki OS里面，有一个很有趣的ELF Loader实现，嗯，其实Contiki OS有很多有意思的东西 :)<br /><br />+ucLinux:<br />ucLinux也是一个很有意思的例子。由于ucLinux没有启用虚拟内存系统，因此它在加载可执行文件的时候，就要进行重定位。为了加速重定位和减小ELF文件的体积，ucLinux提供了特殊的工具链，在产生ELF之前进行部分的“预重定位”，最后ELF中只需要携带很小体积的重定位信息。<br /><br />+其它RTOS：<br />其它嵌入式OS，如VxWorks也实现了ELF Loader, eCos的ELF Loader看起来尚未完整。<br /><br />+Linux Kernel:<br />哦，差点忘了一个最重要的，Linux Kernel。<br /><br />Linux Kernel的模块是可以通过insmod动态地加入内核。虽然Linux的用户空间程序运行在虚拟内存中，整个内核的空间确只有一个。一些奉行micro kernel的人批评Linux的这种方式，但是一个单一空间的内核运行效率却是最高的。<br /><br />在2.6内核中，模块重定位工作不再由insmod来完成，而是由内核来做所有的重定位工作。实现代码在：kernel/module.c中。<br /><br />剥去那些处理特殊section的代码，Linux内核模块加载部分的代码其实是非常简单明了的，而且Linux支持数十种架构意味着你几乎不要担心架构移植的问题。<br /><br />=== 结论 ===<br /><br />在嵌入式系统中实现动态模块加载的技术是成熟的，可靠的，可以借鉴的开发源码的实现例子也有不少。一个参考数据： 我最近在一个嵌入式RTOS上实现的ELF Loader，运行在ARM7 CPU上，从NAND FLASH中加载一个400K左右的ELF，耗时大约0.5秒。<br /><br /><br />=== THE END ===
          <br/>
          <span style="color:red;">
            <a href="http://rubynroll.javaeye.com/blog/202461#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 12 Jun 2008 13:09:17 +0800</pubDate>
        <link>http://rubynroll.javaeye.com/blog/202461</link>
        <guid>http://rubynroll.javaeye.com/blog/202461</guid>
      </item>
      <item>
        <title>嵌入式Linux下常用的交叉编译方法</title>
        <author>rubynroll</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://rubynroll.javaeye.com">rubynroll</a>&nbsp;
          链接：<a href="http://rubynroll.javaeye.com/blog/195374" style="color:red;">http://rubynroll.javaeye.com/blog/195374</a>&nbsp;
          发表时间: 2008年05月21日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          要在嵌入式Linux下使用动态语言，首先要解决的是语言解释器或执行引擎的交叉编译问题。<br /><br />交叉编译通常有以下几种途径：<br /><br />1. 直接通过交叉编译工具，手工配置交叉编译。交叉编译工具可以利用这个脚本来自动生成：<br />http://kegel.com/crosstool/<br />此方法的好处是简便快捷，一旦crosstool做好以后，需要什么包直接编译即可，而且可控性很强。缺点是对各种配置参数要很了解，而且自己需要考虑包依赖，以及包安装问题。对于要编译包依赖比较多的软件，比如我要编译ruby解释器，以及许多ext包，那就比较麻烦了，一般不推荐。<br /><br />2. 利用scratchbox工具：http://www.scratchbox.org/<br />scratchbox是一个很不错的交叉编译系统，而且可以在qemu的支持下在pc上直接仿真运行。scratchbox的使用也相当简单。唯一缺憾的是，1.x版本需要切换用户来编译，而且各种库不够优化，需要自己仔细慢慢地调整才行。2.x版目前文档缺乏，不够成熟。<br /><br />3. 利用OpenEmbedded工具：http://www.openembedded.org/<br />OE是属于比较重量型的交叉编译系统工具，有很多成熟的Linux设备都是用它来构建，如Sharp Zarus, Nokia 770, OpenMoko等。OE采用了较‘特别’的包管理工具和版本管理工具，有很多先进的特性。虽然OE可以很方便的交叉编译出象OPIE这样复杂的GUI系统，但如果要在OE下配置和定制软件包却不是一件容易的事。另外，如果你要编译OE提供的所有软件包的话，要有心理准备，它可能会吃掉近20G的硬盘，花费十几个小时的编译！<br /><br />4. 利用buildroot工具：http://buildroot.uclibc.org/<br />buildroot是一个相当小巧灵活的一个交叉编译工具。在buildroot中定制和调整软件包十分的方便，而且buildroot提供类似 Linux kernel配置采用的‘图形化’的配置菜单，非常容易使用。buildroot的一个缺点是，它的交叉编译工具使用了绝对路径位置，不可更改。虽然可以配置成使用‘外部工具链’,但实际上那个‘外部工具链’也需要另一个buildroot副本才行，我曾经试过使用自己用crosstool脚本生成的工具链，只有在编译象busybox这样简单的包才行，编译ruby失败（可能是因为buildroot没有正确处理依赖包的连接路径）。<br /><br />以上四种方法各有优缺点，要依据你的实际情况而选择。以上四种方法我都在实际工作种应用过。针对动态语言工具的交叉编译，我比较推荐buildroot，而且buildroot足够灵活，可以很容易地增加软件包，可以适应大部分的需要。<br /><br />获取buildroot:<br />svn co svn://uclibc.org/trunk/buildroot<br /><br />当前的svn trunk中，已经有配置好的ruby,python,lua和micro perl，编译十分方便。<br /><br />有一点需要注意，当前svn trunk中的配置的ruby版本是1.8.2，在有些平台下编译时会出现提示fake.rb文件语法错误，这时只要到 buildroot/build_&lt;ARCH>/package/ruby-1.8.2下，修改fake.rb，加上漏掉的‘;'，然后回到 buildroot下make就可以了。不过，更方便的修正方法是，到buildroot/package/ruby下，修改ruby.mk文件，把 1.8.2改成1.8.6，这样编译一次就能通过，而且还升级到1.8.6版本:)<br />编译python和lua则很顺利，没什么问题。
          <br/>
          <span style="color:red;">
            <a href="http://rubynroll.javaeye.com/blog/195374#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 21 May 2008 17:47:33 +0800</pubDate>
        <link>http://rubynroll.javaeye.com/blog/195374</link>
        <guid>http://rubynroll.javaeye.com/blog/195374</guid>
      </item>
      <item>
        <title>可以使用Python编程的嵌入式无线模块！</title>
        <author>rubynroll</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://rubynroll.javaeye.com">rubynroll</a>&nbsp;
          链接：<a href="http://rubynroll.javaeye.com/blog/195372" style="color:red;">http://rubynroll.javaeye.com/blog/195372</a>&nbsp;
          发表时间: 2008年05月21日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          Telit 是一家专业设计和生产无线模块产品的公司，值得注意的是，它几乎在所有的最新产品中集成了嵌入式Python解释器，这样使用者就可以使用Python脚本快速地开发应用，这些Python脚本可以保存在模块内部运行，而不用另外的MCU去和模块进行AT命令交互。<br /><br />想起以前在WaveCom的OpenAT平台上开发应用，那个叫郁闷....<br /><br />以下链接是Telit的一个4频GSM/GPRS模块的flyer：<br />http://www.telit.com/module/infopool/download.php?id=166
          <br/>
          <span style="color:red;">
            <a href="http://rubynroll.javaeye.com/blog/195372#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 21 May 2008 17:45:42 +0800</pubDate>
        <link>http://rubynroll.javaeye.com/blog/195372</link>
        <guid>http://rubynroll.javaeye.com/blog/195372</guid>
      </item>
      <item>
        <title>空格的 ”陷阱“</title>
        <author>rubynroll</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://rubynroll.javaeye.com">rubynroll</a>&nbsp;
          链接：<a href="http://rubynroll.javaeye.com/blog/192547" style="color:red;">http://rubynroll.javaeye.com/blog/192547</a>&nbsp;
          发表时间: 2008年05月13日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          今天无意中碰到一个空格带来的“陷阱”：<br /><br /><pre name="code" class="ruby">def a
  10
end

b = a+1
=> 11

b = a + 1
=> 11

b = a+ 1
=> 11

b = a +1
ArgumentError: wrong number of arguments (1 for 0)
        from (irb):8:in `a'
        from (irb):8
</pre>
          <br/>
          <span style="color:red;">
            <a href="http://rubynroll.javaeye.com/blog/192547#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 13 May 2008 12:27:31 +0800</pubDate>
        <link>http://rubynroll.javaeye.com/blog/192547</link>
        <guid>http://rubynroll.javaeye.com/blog/192547</guid>
      </item>
      <item>
        <title>ubuntu 8.04 意外惊喜</title>
        <author>rubynroll</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://rubynroll.javaeye.com">rubynroll</a>&nbsp;
          链接：<a href="http://rubynroll.javaeye.com/blog/187047" style="color:red;">http://rubynroll.javaeye.com/blog/187047</a>&nbsp;
          发表时间: 2008年04月26日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          刚安装了ubuntu8.04，没想到给我了个惊喜－－我的AIT Xpress 200居然可以跑compiz了！<br /><br />用ubuntu 7.10的时候无论怎么折腾，compiz就是起不来，现在好了，哈哈，哈哈，哈哈～<br /><br />如果你的机器也象我的一样，只有一块底端显卡，不凡试试ubuntu 8.04，说不定也会给你个惊喜哦!
          <br/>
          <span style="color:red;">
            <a href="http://rubynroll.javaeye.com/blog/187047#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sat, 26 Apr 2008 13:12:12 +0800</pubDate>
        <link>http://rubynroll.javaeye.com/blog/187047</link>
        <guid>http://rubynroll.javaeye.com/blog/187047</guid>
      </item>
      <item>
        <title>除了Web开发，Ruby还能作点什么</title>
        <author>rubynroll</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://rubynroll.javaeye.com">rubynroll</a>&nbsp;
          链接：<a href="http://rubynroll.javaeye.com/blog/177020" style="color:red;">http://rubynroll.javaeye.com/blog/177020</a>&nbsp;
          发表时间: 2008年03月27日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          一提到Ruby就Rails，你大概腻了吧？ 没关系，看看除了Web开发，Ruby还能作点什么 :)<br /><br />＝＝＝<br />如果你熟悉嵌入式开发，如果你用C/C++的话，估计离开不了交叉编译工具。虽然网上能下载到编译好的交叉编译工具，但是不一定能满足你的需求，经常不得不自己手动从源代码开始自己编译交叉工具。虽然这不是什么难题，但是就我自己而言，每每碰到这样的问题，都需要到网上google一番，参考一些别人写好的脚本，然后按自己的需要修改，然后再编译...由于步骤有好几步，一一修改配置参数....输错了参数还要重来...太烦人了！<br /><br />＝＝＝<br />一直很怕写shell脚本，简单的任务尚可，一旦碰到复杂些的，可就犯难了（看看著名的autoconf里面的configure你就知道一个复杂的shell脚本有多么恐怖！）。Ruby简洁灵活强大的语法，丰富的库功能，用来写教本简直太完美了～<br /><br />＝＝＝<br />于是便写了个制作arm-elf交叉工具的小脚本，练练手，如果恰巧有搞嵌入式的同好者需要，算你运气好了 :)))<br /><br />＝＝＝<br />使用：<br /><br />0. 解压缩附件文件。<br />1. 先安装rbuild:<br />    gem install rbuild<br />2. 配置：<br />    rake menuconfig<br />   (配置完按S保存，按Q退出)<br />3. 编译：<br />    rake all<br /><br /><br />《《《 不让我上传.tar.gz文件？？？ What a ... 算了，需要者可以直接到rbuild的gem安装目录下的example2目录中找到这个脚本 》》》
          <br/>
          <span style="color:red;">
            <a href="http://rubynroll.javaeye.com/blog/177020#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 27 Mar 2008 18:54:37 +0800</pubDate>
        <link>http://rubynroll.javaeye.com/blog/177020</link>
        <guid>http://rubynroll.javaeye.com/blog/177020</guid>
      </item>
      <item>
        <title>Rbuild, 让你的项目立即可配置</title>
        <author>rubynroll</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://rubynroll.javaeye.com">rubynroll</a>&nbsp;
          链接：<a href="http://rubynroll.javaeye.com/blog/175935" style="color:red;">http://rubynroll.javaeye.com/blog/175935</a>&nbsp;
          发表时间: 2008年03月25日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          虽然工作中在用Ruby，却也想在业余的时候用Ruby作点什么东西。<br /><br />以前用C/C++写东西的时候就有过困扰，一个产品系列总是有那么些差异，需要对一个基础软件进行定制，这个型号的要把这个功能编译进去，那个型号的，需要把另外一个功能编译进去...很羡慕Linux内核有一个好用的基于菜单配置的工具，要是在我的项目中也能用它来管理不同模块的配置该多好啊.....不过要想把Linux内核配置那一套拿出来用，并不简单。<br /><br />看过一些Ruby DSL方面的文章，觉得用Ruby来作这个东西真是在合适不过了，于是便有了Rbuild.<br /><br />Rbuild刚刚发布了第一个版本，0.1.0，已经可以用了，内部实现丑陋了些，但是功能却不赖，Rbuild的DSL也很简单，编写RConfig文件与Linux内核的Kconfig文件比起来方便，自由许多。<br /><br />Rbuild现在已经用于一个嵌入式操作系统的配置管理，效果非常好:)<br /><br />为了演示Rbuild也可以应用于非C/C++项目，我准备写一个交叉编译arm-elf的工具来作为下一个Rbuild应用的例子，当然，依惯例，GPL之。<br /><br />Rbuild hosted at sourceforge:<br />http://www.sourceforge.net/projects/rbuild
          <br/>
          <span style="color:red;">
            <a href="http://rubynroll.javaeye.com/blog/175935#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 25 Mar 2008 17:47:59 +0800</pubDate>
        <link>http://rubynroll.javaeye.com/blog/175935</link>
        <guid>http://rubynroll.javaeye.com/blog/175935</guid>
      </item>
      <item>
        <title>A simple inter-process lock</title>
        <author>rubynroll</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://rubynroll.javaeye.com">rubynroll</a>&nbsp;
          链接：<a href="http://rubynroll.javaeye.com/blog/151742" style="color:red;">http://rubynroll.javaeye.com/blog/151742</a>&nbsp;
          发表时间: 2007年12月29日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          Linux程序员通常喜欢用文件锁来做进程间的同步，或简单地用文件锁指示程序进程是否还健在。在ruby里面可以很简单的实现文件锁：<br /><pre name="code" class="java">
=begin
 file lock for inter-process sync.
 usage:
  FSLock('mylock') do
    # protected by lock,
    # do your job here ...
  end
=end 
class FSLock
  def initialize(name=nil)
    name ||= 'global'
    @fname = name + '.lock'
    if block_given?
      lock()
      yield
      unlock()
    end
  end

  def critical
    lock()
    yield() if block_given?
    unlock()
  end

  def lock
    @f = File.new(@fname, "ab")
    @f.flock(File::LOCK_EX) if @f
  end

  def unlock
    @f.close if @f
  end
end
</pre><br /><br />测试代码：<br /><pre name="code" class="java">
if $0 == __FILE__
  unless fork
    # child process
    3.times do |i|
      FSLock.new('/tmp/myapp') do
        sleep 2   # child process sleep while holding the lock
        puts "#{Time.now.to_s}: Ping !"
      end
    end
  else
    # parent process
    sleep 0.1
    6.times do
      FSLock.new('/tmp/myapp') do   # parent process will be blocked while child holding the lock
        puts "#{Time.now.to_s}: Pong !"
      end
      sleep 0.1
    end
    Process.wait
  end
end
</pre><br /><br />父子进程通过文件锁来同步，子进程持有锁后休眠2秒导致父进程企图获取锁时休眠。最后子进程不在持有锁的时候，父进程不再block。<br /><br />Win32用户可以在Cygwin下运行此代码。
          <br/>
          <span style="color:red;">
            <a href="http://rubynroll.javaeye.com/blog/151742#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sat, 29 Dec 2007 11:44:35 +0800</pubDate>
        <link>http://rubynroll.javaeye.com/blog/151742</link>
        <guid>http://rubynroll.javaeye.com/blog/151742</guid>
      </item>
      <item>
        <title>A Simple pseudo keyboard driver for Linux</title>
        <author>rubynroll</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://rubynroll.javaeye.com">rubynroll</a>&nbsp;
          链接：<a href="http://rubynroll.javaeye.com/blog/150588" style="color:red;">http://rubynroll.javaeye.com/blog/150588</a>&nbsp;
          发表时间: 2007年12月24日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          如果你想把从串口或者其他地方接收到的数据当作是从键盘输入，该如何实现？<br /><br />我最近写了个简单的Pseudo Keyboard (称之为：伪键盘）内核模块来实现这个功能，很简单但很有趣 :)<br /><br />把以下代码存成pkbd.c，编译成模块pkbd.ko，然后用insmod pkbd.ko插入内核。<br /><br />模块插入成功后，会在/proc下建立pkbd文件，以及在/dev下自动建立输入设备（如果你用udev的话）。<br /><br />用法：<br /><br />    比如我想让从/dev/ttyS1来的数据模拟成键盘输入，最简单的方法是运行：<br />        cp /dev/ttyS1 /proc/pkbd &<br /><br />当然，更正式点的用法是按需要的设置打开串口，读取数据，让后写入/proc/pkbd。<br /><br />以下是source，适合Linux 2.6.15或之后的版本。<br /><br />Enjoy it !<br /><br /><pre name="code" class="java">
/*
 *	Pseudo Keyboard driver	
 *
 *	Change Logs:
 *		5 Jun, 2006 Created by ricky &lt;ricky_gz_zheng@yahoo.co.nz>
 */

#include &lt;linux/module.h>
#include &lt;linux/config.h>
#include &lt;linux/types.h>
#include &lt;linux/fs.h>
#include &lt;linux/init.h>
#include &lt;asm/uaccess.h>
#include &lt;linux/proc_fs.h>
#include &lt;linux/kernel.h>
#include &lt;linux/mm.h>
#include &lt;linux/cdev.h>
#include &lt;linux/list.h>
#include &lt;asm/io.h>
#include &lt;linux/input.h>



static int dbg = 0;
MODULE_PARM(dbg, "i");
MODULE_PARM_DESC(dbg, "set dbg=1 enable debug message output to stdout, dbg=0 disable it");

#define DEBUG_PKBD

#ifdef DEBUG_PKBD

#define DBG(x...) \
	do { \
		if(dbg) \
			printk(KERN_INFO PFX x ); \
	} while(0)
#else
#define DBG(x...)
#endif

#define PFX "PKBD: "

static unsigned char m_mapedMin = 1;
static unsigned char m_mapedMax = 0;
static int ascii_to_key[] ={	
  /* 00: ^@ */ 0,
  /* 01: ^A */ (KEY_LEFTCTRL &lt;&lt; 16) | KEY_A,
  /* 02: ^B */ (KEY_LEFTCTRL &lt;&lt; 16) | KEY_B,
  /* 03: ^C */ (KEY_LEFTCTRL &lt;&lt; 16) | KEY_C,
  /* 04: ^D */ (KEY_LEFTCTRL &lt;&lt; 16) | KEY_D,
  /* 05: ^E */ (KEY_LEFTCTRL &lt;&lt; 16) | KEY_E,
  /* 06: ^F */ (KEY_LEFTCTRL &lt;&lt; 16) | KEY_F,
  /* 07: ^G */ (KEY_LEFTCTRL &lt;&lt; 16) | KEY_G,
  /* 08: ^H */ (KEY_LEFTCTRL &lt;&lt; 16) | KEY_H,
  /* 09: ^I */ (KEY_LEFTCTRL &lt;&lt; 16) | KEY_I,
  /* 0a: ^J */ (KEY_LEFTCTRL &lt;&lt; 16) | KEY_J,
  /* 0b: ^K */ (KEY_LEFTCTRL &lt;&lt; 16) | KEY_K,
  /* 0c: ^L */ (KEY_LEFTCTRL &lt;&lt; 16) | KEY_L,
  /* 0d: ^M */ (KEY_LEFTCTRL &lt;&lt; 16) | KEY_M,
  /* 0e: ^N */ (KEY_LEFTCTRL &lt;&lt; 16) | KEY_N,
  /* 0f: ^O */ (KEY_LEFTCTRL &lt;&lt; 16) | KEY_O,
  /* 10: ^P */ (KEY_LEFTCTRL &lt;&lt; 16) | KEY_P,
  /* 11: ^Q */ (KEY_LEFTCTRL &lt;&lt; 16) | KEY_Q,
  /* 12: ^R */ (KEY_LEFTCTRL &lt;&lt; 16) | KEY_R,
  /* 13: ^S */ (KEY_LEFTCTRL &lt;&lt; 16) | KEY_S,
  /* 14: ^T */ (KEY_LEFTCTRL &lt;&lt; 16) | KEY_T,
  /* 15: ^U */ (KEY_LEFTCTRL &lt;&lt; 16) | KEY_U,
  /* 16: ^V */ (KEY_LEFTCTRL &lt;&lt; 16) | KEY_V,
  /* 17: ^W */ (KEY_LEFTCTRL &lt;&lt; 16) | KEY_W,
  /* 18: ^X */ (KEY_LEFTCTRL &lt;&lt; 16) | KEY_X,
  /* 19: ^Y */ (KEY_LEFTCTRL &lt;&lt; 16) | KEY_Y,
  /* 1a: ^Z */ (KEY_LEFTCTRL &lt;&lt; 16) | KEY_Z,
  /* 1b: ^[ */ (KEY_LEFTCTRL &lt;&lt; 16) | KEY_LEFTBRACE,
  /* 1c: ^\ */ (KEY_LEFTCTRL &lt;&lt; 16) | KEY_BACKSLASH,
  /* 1d: ^] */ (KEY_LEFTCTRL &lt;&lt; 16) | KEY_RIGHTBRACE,
  /* 1e: ^^ */ (KEY_LEFTCTRL &lt;&lt; 16) | KEY_6,
  /* 1f: ^_ */ (KEY_LEFTCTRL &lt;&lt; 16) | KEY_MINUS,
  /* 20: SP */ KEY_SPACE,
  /* 21: ! */ (KEY_LEFTSHIFT &lt;&lt; 16) | KEY_1,
  /* 22: " */ (KEY_LEFTSHIFT &lt;&lt; 16) | KEY_APOSTROPHE,
  /* 23: # */ (KEY_LEFTSHIFT &lt;&lt; 16) | KEY_3,
  /* 24: $ */ (KEY_LEFTSHIFT &lt;&lt; 16) | KEY_4,
  /* 25: % */ (KEY_LEFTSHIFT &lt;&lt; 16) | KEY_5,
  /* 26: & */ (KEY_LEFTSHIFT &lt;&lt; 16) | KEY_7,
  /* 27: ' */ KEY_APOSTROPHE,
  /* 28: ( */ (KEY_LEFTSHIFT &lt;&lt; 16) | KEY_9,
  /* 29: ) */ (KEY_LEFTSHIFT &lt;&lt; 16) | KEY_0,
  /* 2a: * */ (KEY_LEFTSHIFT &lt;&lt; 16) | KEY_8,
  /* 2b: + */ (KEY_LEFTSHIFT &lt;&lt; 16) | KEY_EQUAL,
  /* 2c: , */ KEY_COMMA,
  /* 2d: - */ KEY_MINUS,
  /* 2e: . */ KEY_DOT,
  /* 2f: / */ KEY_SLASH,
  /* 30: 0 */ KEY_0,
  /* 31: 1 */ KEY_1,
  /* 32: 2 */ KEY_2,
  /* 33: 3 */ KEY_3,
  /* 34: 4 */ KEY_4,
  /* 35: 5 */ KEY_5,
  /* 36: 6 */ KEY_6,
  /* 37: 7 */ KEY_7,
  /* 38: 8 */ KEY_8,
  /* 39: 9 */ KEY_9,
  /* 3a: : */ (KEY_LEFTSHIFT &lt;&lt; 16) | KEY_SEMICOLON,
  /* 3b: ; */ KEY_SEMICOLON,
  /* 3c: &lt; */ (KEY_LEFTSHIFT &lt;&lt; 16) | KEY_COMMA,
  /* 3d: = */ KEY_EQUAL,
  /* 3e: > */ (KEY_LEFTSHIFT &lt;&lt; 16) | KEY_DOT,
  /* 3f: ? */ (KEY_LEFTSHIFT &lt;&lt; 16) | KEY_SLASH,
  /* 40: @ */ (KEY_LEFTSHIFT &lt;&lt; 16) | KEY_2,
  /* 41: A */ (KEY_LEFTSHIFT &lt;&lt; 16) | KEY_A,
  /* 42: B */ (KEY_LEFTSHIFT &lt;&lt; 16) | KEY_B,
  /* 43: C */ (KEY_LEFTSHIFT &lt;&lt; 16) | KEY_C,
  /* 44: D */ (KEY_LEFTSHIFT &lt;&lt; 16) | KEY_D,
  /* 45: E */ (KEY_LEFTSHIFT &lt;&lt; 16) | KEY_E,
  /* 46: F */ (KEY_LEFTSHIFT &lt;&lt; 16) | KEY_F,
  /* 47: G */ (KEY_LEFTSHIFT &lt;&lt; 16) | KEY_G,
  /* 48: H */ (KEY_LEFTSHIFT &lt;&lt; 16) | KEY_H,
  /* 49: I */ (KEY_LEFTSHIFT &lt;&lt; 16) | KEY_I,
  /* 4a: J */ (KEY_LEFTSHIFT &lt;&lt; 16) | KEY_J,
  /* 4b: K */ (KEY_LEFTSHIFT &lt;&lt; 16) | KEY_K,
  /* 4c: L */ (KEY_LEFTSHIFT &lt;&lt; 16) | KEY_L,
  /* 4d: M */ (KEY_LEFTSHIFT &lt;&lt; 16) | KEY_M,
  /* 4e: N */ (KEY_LEFTSHIFT &lt;&lt; 16) | KEY_N,
  /* 4f: O */ (KEY_LEFTSHIFT &lt;&lt; 16) | KEY_O,
  /* 50: P */ (KEY_LEFTSHIFT &lt;&lt; 16) | KEY_P,
  /* 51: Q */ (KEY_LEFTSHIFT &lt;&lt; 16) | KEY_Q,
  /* 52: R */ (KEY_LEFTSHIFT &lt;&lt; 16) | KEY_R,
  /* 53: S */ (KEY_LEFTSHIFT &lt;&lt; 16) | KEY_S,
  /* 54: T */ (KEY_LEFTSHIFT &lt;&lt; 16) | KEY_T,
  /* 55: U */ (KEY_LEFTSHIFT &lt;&lt; 16) | KEY_U,
  /* 56: V */ (KEY_LEFTSHIFT &lt;&lt; 16) | KEY_V,
  /* 57: W */ (KEY_LEFTSHIFT &lt;&lt; 16) | KEY_W,
  /* 58: X */ (KEY_LEFTSHIFT &lt;&lt; 16) | KEY_X,
  /* 59: Y */ (KEY_LEFTSHIFT &lt;&lt; 16) | KEY_Y,
  /* 5a: Z */ (KEY_LEFTSHIFT &lt;&lt; 16) | KEY_Z,
  /* 5b: [ */ KEY_LEFTBRACE,
  /* 5c: \ */ KEY_BACKSLASH,
  /* 5d: ] */ KEY_RIGHTBRACE,
  /* 5e: ^ */ (KEY_LEFTSHIFT &lt;&lt; 16) | KEY_6,
  /* 5f: _ */ (KEY_LEFTSHIFT &lt;&lt; 16) | KEY_MINUS,
  /* 60: '  */ KEY_APOSTROPHE,
  /* 61: a */ KEY_A,
  /* 62: b */ KEY_B,
  /* 63: c */ KEY_C,
  /* 64: d */ KEY_D,
  /* 65: e */ KEY_E,
  /* 66: f */ KEY_F,
  /* 67: g */ KEY_G,
  /* 68: h */ KEY_H,
  /* 69: i */ KEY_I,
  /* 6a: j */ KEY_J,
  /* 6b: k */ KEY_K,
  /* 6c: l */ KEY_L,
  /* 6d: m */ KEY_M,
  /* 6e: n */ KEY_N,
  /* 6f: o */ KEY_O,
  /* 70: p */ KEY_P,
  /* 71: q */ KEY_Q,
  /* 72: r */ KEY_R,
  /* 73: s */ KEY_S,
  /* 74: t */ KEY_T,
  /* 75: u */ KEY_U,
  /* 76: v */ KEY_V,
  /* 77: w */ KEY_W,
  /* 78: x */ KEY_X,
  /* 79: y */ KEY_Y,
  /* 7a: z */ KEY_Z,
  /* 7b: { */ (KEY_LEFTSHIFT &lt;&lt; 16) | KEY_LEFTBRACE,
  /* 7c: | */ (KEY_LEFTSHIFT &lt;&lt; 16) | KEY_BACKSLASH,
  /* 7d: } */ (KEY_LEFTSHIFT &lt;&lt; 16) | KEY_RIGHTBRACE,
  /* 7e: ~ */ 0,

  /* TODO: add more keymap here ... */
  /* 7f: ?? */ 0,
  /* 80: ?? */ 0,
  0,	/* end with 0 */
};
static struct input_dev *pkbd_dev = NULL;
static int pkbd_write_proc(struct file *file, const char __user *buffer, unsigned long count, void *data)
{
  #define MAX_INPUT_LEN	64
  unsigned char buf[MAX_INPUT_LEN];
  int i;
  if (pkbd_dev) {
    memset(buf, 0, MAX_INPUT_LEN);
    if(count > 0 && count &lt; MAX_INPUT_LEN) {
      copy_from_user(buf, buffer, count);
      for (i = 0; i &lt; count; i++) {
        if (buf[i] >= m_mapedMin &&	buf[i] &lt;= m_mapedMax) {
          input_report_key(pkbd_dev, ascii_to_key[buf[i]], 1);
          input_report_key(pkbd_dev, ascii_to_key[buf[i]], 0);
        }
     	}
    }
  }
  return count;
}
static int __init pkbddev_init(void)
{	
  struct proc_dir_entry * pkbd_proc = NULL;	
  int i;	
  dbg = dbg;	
  pkbd_proc = create_proc_entry("pkbd", 0, NULL);	
  if(pkbd_proc) {		
    pkbd_proc->write_proc = pkbd_write_proc;	
  }
  else {
    printk (KERN_ERR PFX "Can't create proc entry for pkbd driver.\n");		
    return -EBUSY;	
  }	
  pkbd_dev = input_allocate_device();	
  if (pkbd_dev == NULL) {		
    return -ENODEV;	
  }    
  init_input_dev(pkbd_dev);	
  pkbd_dev->name = "pkbd";	
  set_bit(EV_KEY, pkbd_dev->evbit);	
  for(i = 1; ; i++) {		
    if(ascii_to_key[i] == 0) break;		
    set_bit(ascii_to_key[i], pkbd_dev->keybit);	
  }	
  m_mapedMax = i - 1;	
  input_register_device(pkbd_dev);	
  return 0;
}
static void __exit pkbddev_exit(void)
{	
  if (pkbd_dev) input_unregister_device(pkbd_dev);	
  remove_proc_entry("pkbd", NULL);
}
module_init(pkbddev_init);
module_exit(pkbddev_exit);
MODULE_AUTHOR("Ricky Zheng, &lt;ricky_gz_zheng@yahoo.co.nz>");
MODULE_DESCRIPTION("Pseudo Keyboard Driver");
MODULE_LICENSE("GPL");

</pre>
          <br/>
          <span style="color:red;">
            <a href="http://rubynroll.javaeye.com/blog/150588#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 24 Dec 2007 21:04:25 +0800</pubDate>
        <link>http://rubynroll.javaeye.com/blog/150588</link>
        <guid>http://rubynroll.javaeye.com/blog/150588</guid>
      </item>
      <item>
        <title>OO Programing in C (3)</title>
        <author>rubynroll</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://rubynroll.javaeye.com">rubynroll</a>&nbsp;
          链接：<a href="http://rubynroll.javaeye.com/blog/150581" style="color:red;">http://rubynroll.javaeye.com/blog/150581</a>&nbsp;
          发表时间: 2007年12月24日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <strong>OO Programing in C is not only POSSIBLE but also PRACTICAL</strong><br />--------------------------------------------------------------------------------<br /><br />OO的一个亮点是类的"继承"，通过"继承"，可以重用许多代码。而且"继承"也是现实生活中非常自然的一种关系。但是很不幸，C没有class，更没有提供"继承"的表达方式。既然能用C的struct来仿真class, 那能不能继续来仿真"继承"呢？答案是:possible。就像&lt;&lt;Inside the C++ Object Modal>>书中所叙述的那样——你可以用C来达到所有C++能做到的事。但这种仿真显然毫无实际应用价值。<br /><br />"继承"是一种表达方式，代码重用才是目的。<br /><br />为了重用代码，C++可以用"继承"的方式来巧妙的达到目的，但是也必须付出代价：你必须非常仔细地设计你的类族谱，要有前瞻性，要有可扩展性，要决定分多少个层次....这些都不是容易做到的事。<br /><br />C别无选择，模块化设计，函数，宏....只能通过巧妙的设计才能达到代码可重用的目的。还是举个例子来说明C是如何做到"殊途同归"的吧。<br /><br />"链表"是一个非常常用的数据结构，常用于管理无序的数据(对象)集合。链表操作，特别是双向链表操作很容易出错。重用一套通用操作链表的代码可以为我们省不少事。在C++中，我们可以用经典的STL中的list类。为了适应各种数据类型，list类用模板来实现。list类实现的很巧妙，功能很强，但是，不得不说，很少人用。其实不仅list类很少用，STL都很少人用。（希望这是我的一家之言，反正我所熟悉的C++程序员都不怎么用STL :-）当然在C++中你还有另外一个选择：实现一个List基类完成链表操作，要放入链表的类从List类继承而来，就拥有了一套操作list的方法。<br /><br />Linux内核中用C提供了一套非常巧妙的方法操作链表，位于.../linux/include/linux/list.h，只用一些宏和inline函数来实现双向链表。摘抄一部分出来：<br /><br /><pre name="code" class="java">
....
struct list_head {
    struct list_head *next, *prev;
};


#define LIST_HEAD_INIT(name) { &(name), &(name) }

#define LIST_HEAD(name) \
    struct list_head name = LIST_HEAD_INIT(name)

#define INIT_LIST_HEAD(ptr) do { \
    (ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while (0)

/*
 * Insert a new entry between two known consecutive entries.
 *
 * This is only for internal list manipulation where we know
 * the prev/next entries already!
 */
static inline void __list_add(struct list_head *new,
                  struct list_head *prev,
                  struct list_head *next)
{
    next->prev = new;
    new->next = next;
    new->prev = prev;
    prev->next = new;
}

/**
 * list_add - add a new entry
 * @new: new entry to be added
 * @head: list head to add it after
 *
 * Insert a new entry after the specified head.
 * This is good for implementing stacks.
 */
static inline void list_add(struct list_head *new, struct list_head *head)
{
    __list_add(new, head, head->next);
}

.....

/**
 * list_entry - get the struct for this entry
 * @ptr:    the &struct list_head pointer.
 * @type:    the type of the struct this is embedded in.
 * @member:    the name of the list_struct within the struct.
 */
#define list_entry(ptr, type, member) \
    container_of(ptr, type, member)

/**
 * list_for_each    -    iterate over a list
 * @pos:    the &struct list_head to use as a loop counter.
 * @head:    the head for your list.
 */
#define list_for_each(pos, head) \
    for (pos = (head)->next; prefetch(pos->next), pos != (head); \
            pos = pos->next)

......
</pre><br /><br />其中 container_of 宏如下：<br /><br /><pre name="code" class="java">
/**
 * container_of - cast a member of a structure out to the containing structure
 * @ptr:    the pointer to the member.
 * @type:    the type of the container struct this is embedded in.
 * @member:    the name of the member within the struct.
 *
 */
#define container_of(ptr, type, member) ({            \
        const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
        (type *)( (char *)__mptr - offsetof(type,member) );})

</pre><br /><br />这里使用了GCC特有的 "typeof" 关键字，如果想用其他编译器也想编译通过的话，可以修改成：<br /><br /><pre name="code" class="java">#define container_of(ptr, type, member) (            \
        (type *)( (char *)ptr - offsetof(type,member) ) )
</pre><br />为了便于说明，prefetch定义成：<br /><pre name="code" class="java">static inline void prefetch(const void *x) {;}</pre><br /><br />offsetof的一个简单版本：<br /><pre name="code" class="java">#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)</pre><br />好了，让我们看看怎么用：<br /><pre name="code" class="java">struct my_data {
    int x;
    int y;
    struct list_head list;
}

/* 链表头 */
LIST_HEAD(my_listhead);

void my_function()
{
    ...
    /* 节点对象 */
    struct my_data *node_1 = (struct my_data *) malloc(sizeof(struct my_data));
    struct my_data *node_2 = (struct my_data *) malloc(sizeof(struct my_data));
    ...
    /* 加入链表 */
    list_add (node_1->list, &my_listhead);
    list_add (node_2->list, &my_listhead);
    ...
    /* 遍历链表 */
    struct my_data * node;
    struct list_head *pos;
    list_for_each (pos, &my_listhead) {
       node = list_entry (pos, struct my_data, list);
       ...
    }
</pre><br /><br />其中最精彩的部分是遍历链表的表达方式：<br />    list_for_each (...) {<br />       ...<br />    }<br />这种表达方式另我想起了Ruby，C++ STL中的到处出现的iterator，和VB中的for each...in...next语句。<br /><br />从内部结构角度来看，Linux的list实现方式有点类似C++中的"组合类"——在需要放入链表的对象内部放入list类（struct list_head）。但是从遍历链表的时候，可以根据list指针得到包含list节点的对象指针来看，又有点超出了"组合类"的范畴。能否把 struct my_data看成继承了struct list_head呢？从内存映像来看倒有点像（C++子类对象的内存映像是父类对象的超级）。当然，这种强行联系完全没有必要，C就是C，何必去往C+ +套呢？C自有C的表达方式 :D<br /><br />--THE END--<br /><br />注：这几篇是我原来在MSN SPACE的老blog，实在受不了MSN SPACE的速度，于是搬到了javaeye。写这些东西，只是想和使用C的同志分享自己的体验，也想告诉新学习C的同志，C语言也是很有魅力的:)
          <br/>
          <span style="color:red;">
            <a href="http://rubynroll.javaeye.com/blog/150581#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 24 Dec 2007 20:22:55 +0800</pubDate>
        <link>http://rubynroll.javaeye.com/blog/150581</link>
        <guid>http://rubynroll.javaeye.com/blog/150581</guid>
      </item>
      <item>
        <title>OO Programing in C (2)</title>
        <author>rubynroll</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://rubynroll.javaeye.com">rubynroll</a>&nbsp;
          链接：<a href="http://rubynroll.javaeye.com/blog/150578" style="color:red;">http://rubynroll.javaeye.com/blog/150578</a>&nbsp;
          发表时间: 2007年12月24日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <strong>OO Programing in C is not only POSSIBLE, but also PRACTICAL.</strong><br />--------------------------------------------------------------------------------<br /><br />“class“是很多OO编程语言里的关键字，它来源于OO鼻祖Smalltalk。class（类），是对一群有相同特性的对象的抽象概括，对象称为类的实例。在class里面可以存放有状态(变量)，行为(函数/方法)....有关OO概念、方法的文章太多了，不再啰嗦。在C里面，唯一可以实现自定义类型的是struct，struct是C的OO编程最重要的工具。<br /><br /><br />一个最常见的技巧，就是用struct来"仿真"class: 在struct里面放入变量，函数指针，嵌入其他struct等。<br /><br />以下例子摘自我最近刚开发完成的一个USB Firmware项目:<br /><br /><pre name="code" class="java">
struct usb_device;
struct usb_ctl;

struct usb_iobuf {
  int len;				/* data length in the buffer */
	unsigned char buf[USBEPFIFO_SIZE];	/* data buffer itself */
};

struct usb_endpoint {	int type;		/* endpoint type: BULKIN, BULKOUT, CTL, ISO ... */
	int qlen;		/* queue length */

	xQueueHandle lock;	/* semaphore lock */
	xQueueHandle q;		/* data queue (pointer of bulk_buf) */

	int idx;		/* endpoint index */
	int epx;		/* endpoint mark bit */
	int cfg;		/* endpoint configure */
	int bank;		/* current operation bank (for ping-pong mode) */
	int txCount;		/* used for ping-pong mode */	/* endpoint data process function */		void (*ep_process) (struct usb_device *dev,			 struct usb_endpoint *ep,			 xISRStatus *pxMessage);
};

struct usb_descriptor {
	int type;		/* descriptor type: device, conf, string or endpoint */
	int idx;		/* descriptor index (for string descriptor) */
	int size;		/* descriptor size */
	void * data;		/* descriptor data */
	struct list_head list;	/* link list of descriptors */
};

struct usb_deviceOps {
	int (*init)(struct usb_device *dev);		/* called when framework init usb device, add device descriptors, init private data ... etc. */
	int (*reset)(struct usb_device *dev);		/* called when reseted by host */
	int (*switch_in)(struct usb_device *dev);	/* called when switch in */
	int (*switch_out)(struct usb_device *dev);	/* called when swithc out */	/* called when HOST request class interface data */
	void (*class_interface_req)(struct usb_device *dev, xUSB_REQUEST *pxRequest);	/* called when HOST complete the data sending stage */		int (*ctl_data_comp)(struct usb_device *dev,					 xCONTROL_MESSAGE *pxMessage);
};

struct usb_ctlOps {
	void (*ctl_transmit_null)(struct usb_ctl *ctl);
	void (*ctl_send_stall)(struct usb_ctl *ctl);
	void (*ctl_reset_ep0)(struct usb_ctl *ctl);
	void (*ctl_detach_usb)(struct usb_ctl *ctl);
	void (*ctl_attach_usb)(struct usb_ctl *ctl);
	void (*ctl_send_data)(struct usb_ctl *ctl, unsigned char *data,
			int req_len,
			int send_len,
			int is_des);
};


struct usb_ctl {
	int addr;			/* address alloced by host */
	int conf;			/* configuration set by host */
	eDRIVER_STATE state;		/* current status */
	xCONTROL_MESSAGE tx;		/* control transmit message */
	xCONTROL_MESSAGE rx;		/* control receive message */
	struct ubufm *bufmn;		/* 'usb_iobuf' buffer manager, shared by all usb devices */
	int prio;			/* the main task priority */
	xTaskHandle task_handle;	/* the main task handler */
	struct usb_ctlOps *ctlOps;	/* control endpoint operations */
};

struct usb_device {
	char name[16];			/* device name, e.g. "usbser" */
	struct usb_deviceOps *ops;	/* usb device callback functions */

	struct usb_ctl *ctl;		/* usb control enpoint, provided by framework */
	struct list_head desc_list;	/* usb descriptors */
	struct usb_endpoint *ep[MAX_ENDPOINTS];	/* endpoints */
	int active;			/* whether the device is active */
	xQueueHandle ready;		/* notify this queue when usb device ready */
	void *private;			/* device private data */
	struct list_head list;		/* link list of usb device */
};
</pre><br />在这个例子，我用struct分别描述了USB设备，USB控制通道，USB端点，USB描述符和USB缓冲区对象。USB设备对象包含了若干个USB端点，一个USB控制通道指针，一个USB描述符表的表头(指向若干个USB描述符)，和一个USB缓冲区管理对象。而且，USB设备对象还包含了name属性，一个由USB Framework调用的回调函数集，还有一个用于连接其他USB设备的链表节点。<br /><br />值得一提的是，USB设备对象中有一个void *private 成员，可以指向任何数据。实际上在我的程序里，我实现了usb-serial和usb-mass-storage两个USB设备，对于usb-serial对象，private我弃之不用，而在usb-mass-storage对象中，private指向一个Mass storage对象，usb-mass-storage正是通过这个Mass storage对象访问外部大容量存储的（在我的程序里，Mass storage对象和一个MMC Card对象绑定，外部存储是SD/MMC卡）。由于对于每一种设备的具体实现来说，它知道private指向的是何种类型的设备，因此不会引起混乱。而外部程序根据需要在初始化USB设备对象前赋予private有意义的值——运行时动态绑定。<br /><br />这一系列struct基本上如实地反映了USB DEVICE硬件逻辑和规范要求: "一个USB设备包含若干个端点，其中有一个固定的控制端点(端点0)。在枚举阶段USB设备要根据HOST的请求应答相应的描述符..."<br /><br />现在回到OO的话题，这个例子中体现了"组合类"：USB设备对象包含了USB端点对象，USB描述符对象...。还有动态绑定 (private成员)。从严格的OO意义上来看，好像有点"怪"，不过我认为这恰恰是C的特点——简洁，直接。不信你用C++表达试试？也许会更漂亮，很OO，但是不一定会如此清爽！<br /><br />P.S. : 熟悉USB Firmware开发的人可能对struct usb_endpoint中的epx,cfg,bank和txCount四个成员有异议，因为这些成员是和特定的硬件相关，并不是所有的USB硬件都支持ping-pong mode，所以bank和txCount不一定用得上，epx, cfg也可能因硬件的不同而不同。没错！更理想的设计是把与硬件相关的部分分离出来，用void *private指向各自的与硬件相关的配置——就像struct usb_device所采用方法，所以更好的版本应该是：<br /><br /><pre name="code" class="java">struct usb_endpoint {
  int type;		/* endpoint type: BULKIN, BULKOUT, CTL, ISO ... */
  int qlen;		/* queue length */
  xQueueHandle lock;	/* semaphore lock */
  xQueueHandle q;	/* data queue (pointer of bulk_buf) */
  int idx;		/* endpoint index */
  
  /* endpoint data process function */
  void (*ep_process)(struct usb_device *dev,	struct usb_endpoint *ep, xISRStatus *pxMessage);
  void *private;	/* endpoint private data (hardware relevant) */
};</pre><br /><br />tips: 用C表达的一个关键处就是要很好地应用struct来描述模型。<br /><br /><br />--TO BE CONTINUTED--
          <br/>
          <span style="color:red;">
            <a href="http://rubynroll.javaeye.com/blog/150578#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 24 Dec 2007 20:03:22 +0800</pubDate>
        <link>http://rubynroll.javaeye.com/blog/150578</link>
        <guid>http://rubynroll.javaeye.com/blog/150578</guid>
      </item>
      <item>
        <title>OO Programing in C (1)</title>
        <author>rubynroll</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://rubynroll.javaeye.com">rubynroll</a>&nbsp;
          链接：<a href="http://rubynroll.javaeye.com/blog/150575" style="color:red;">http://rubynroll.javaeye.com/blog/150575</a>&nbsp;
          发表时间: 2007年12月24日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <strong>OO Programing in C is not only POSSIBLE but also PRACTICAL.</strong><br />--------------------------------------------------------------------------------<br /><br /> <br />经常看到关于OO编程的讨论，C++, Java, C#...还有最近很流行的动态语言Python,Ruby等，但很少看到有C的份。<br /><br /><br />在我看来，OO编程的核心是OO的思想，用什么语言倒是其次。但是，不可否认，那些专门为OO编程设计的语言可以比较方便和自然地表达OO思想，有些语言甚至强制使用OO特性。<br /><br /><br />C，作为最贴近底层的高级语言，拥有简洁的语法和直接内存操作能力（指针），大量运用于系统级编程，如操作系统内核，驱动程序等。而在嵌入式系统中，由于资源有限等因素，更倾向于用C编程。<br /><br />C虽然在语言特性上并没有体现OO特性，但是依然可以通过各种编程技巧来体现OO的思想。由于C的高度自由的特点，在OO编程方面还能体现有别于其他语言的特殊韵味。<br /><br /><br />OO思想在Unix世界中很早就有：UNIX把设备抽象成文件，这样就可以用一套相同的方法(open, read, write, close, ... )去访问不同的设备和文件——尽管设备之间的差异很大。用OO的观点来看，这些“设备”对象都实现了"文件操作接口"，可以想象有一个叫"文件"的基类，定义了"文件操作接口"，“设备”对象继承了“文件”对象....。在实现角度看，在内核里面，设备驱动提供了自己的read, write等实现，并用它们去填充文件操作结构体里面的函数指针....这和C++里面的虚函数运行时绑定的道理是一样的。( C++虚函数是其实是运行时静态绑定，而文件操作接口可以运行时动态绑定 :-)<br /><br />Linux内核中则处处体现了OO的思想。2.6内核的Device Driver Modal是一套层次分明又错综复杂的机制，其中体现了许多OO设计理念。虽然可能设备驱动程序开发者觉察不到，但所有的设备驱动对象内部都隐藏了一个叫KObject的对象。内核把这些KObjects互相联系在一起，并通过KObject的相互关系构造了/sys文件系统。/sys就是内核中各种设备对象的映射图，如果把/sys全部展开，我们可以清楚地看到各种对象的关系。<br /><br />实践证明，C也可以很好地用于OO编程，而且可以用于构造很复杂的系统，而且C在表达OO思想的时候并不会显得蹩脚，而是可以很简单，很自然。<br /><br /><br /> <br />--TO BE CONTINUED--
          <br/>
          <span style="color:red;">
            <a href="http://rubynroll.javaeye.com/blog/150575#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 24 Dec 2007 19:56:12 +0800</pubDate>
        <link>http://rubynroll.javaeye.com/blog/150575</link>
        <guid>http://rubynroll.javaeye.com/blog/150575</guid>
      </item>
      <item>
        <title>Ruby: GUI编程的利器 </title>
        <author>rubynroll</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://rubynroll.javaeye.com">rubynroll</a>&nbsp;
          链接：<a href="http://rubynroll.javaeye.com/blog/148310" style="color:red;">http://rubynroll.javaeye.com/blog/148310</a>&nbsp;
          发表时间: 2007年12月14日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <strong>ruby语言由于其灵活优雅的表达方式和优秀的OO的特性，是GUI编程语言的有力竞争者。特别是其Closure特性，能够使GUI编程时遇到的很多头痛的问题迎刃而解。<br /></strong><br /><br />最近手上的一个项目刚好需要做一个Windows平台的GUI程序，以前是用VB，虽然VB是Windows GUI的经典工具，能够快速进行GUI原型开发，但是一旦GUI元素多起来，且UI元素存在复杂关系，就很难维护....特别在后期，一旦需求有什么变化，再去调整UI，那个叫痛苦啊。因此就想用ruby试试,加上此次项目设计很多网络通讯方面的需求，因此更加坚定了使用ruby的决心。现在项目基本完工，再回过头看，以前用VB开发时碰到的种种问题在新项目中都被很好地解决了。特别地，体会到了Closure对于GUI编程的重要性。不管未来在的GUI编程领域ruby是否能成为主流，但是可以预见那种语言一定是具备Closure（或类似）功能的。（或者只是我的美好愿望？）<br /><br /><br />GUI库选型：<br />ruby发行包自带TK库，用于简单的程序还可以，但是一旦有复杂界面需求时就难以满足。目前比较成熟的GUI绑定库有RubyFox，wxRuby 和 RubyGnome. 鉴于GTK用的人比较多，加上GTK在Windows上的Runtime也是比较稳定，GTK应用的代表GIMP看起来也比较漂亮，因此就选择了RubyGnome作为GUI库。<br /><br />关于RubyGnome我也不多介绍，其项目主页上的文档和教程非常不错。<br />Ruby-Gnome项目的首页： http://ruby-gnome2.sourceforge.jp/<br /><br /><br />1. Closure 作为响应GUI消息事件<br />在MFC中，响应消息通常需要定义OnXXX（）虚函数，而且需要在消息传递宏里面与某个消息挂上勾，然后在实现OnXXX（）函数。<br />在VB中，IDE为你为某个控件的消息生成消息响应函数。<br />那么在Ruby-Gnome里面，这么做：<br /><br /><pre name="code" class="java">
button = Gtk::Button.new("Button A")
button.signal_connect("clicked") do
  # ... when button clicked ...
  msgbox "Button clicked !"
end
</pre><br /><br />在这一点上，MFC最为繁琐不用说了。VB由IDE为你预先做了很多工作。ruby用代码关联“clicked”事件，用Closure作为消息响应，干净利落。<br />表面上看，似乎ruby的方式也未必好很多，但是且慢，看下一个....<br /><br />2. Closure 里面可以访问当前上下文<br />GUI编程经常面临的一个头痛的问题是，UI元件通常需要是全局的，至少是窗口类内全局。例如，希望button被按下的时候改变label的内容，那么就要求在响应button事件的代码内要能够访问label。在MFC中，label被迫成为全局。在VB中，你不能控制。在界面元素很多的时候，这可能会成为一个问题－－你不得不仔细地为每一个UI元件命名以防止名称冲突。<br /><br />而在ruby中，由于Closure能够访问当前上下文，因此正好可以完美解决这个问题：<br /><br /><pre name="code" class="java">
button = Gtk::Button.new("Button A")
label = Gtk::Label.new("Hello")
button.signal_connect("clicked") do
  label.text += "click "
end
</pre><br /><br />ruby的Closure使得代码“内聚”了，即相互关联的元素的作用域可以被限定在一个很小的范围，这样对于代码的维护和应付变化都是具有非凡的意义。<br /><br /><br />3. 动态打开一个类的能力使得扩展基类的功能变得简单<br /><br />ruby能够动态地打开一个类并往里面增加method的能力已经不是什么新鲜事，对于这个特性也有很多争议。但对于GUI编程来说，这确实是提供了很大的方便。<br /><br />在GUI编程中，msgbox是很常用的一个工具。在RubyGnome中，Gtk::Window没有msgbox这个接口，下面的例子就是封装了一个易用的Msgbox类，并打开Gtk::Window类，增加msgbox函数，这样所有基于Gtk::Window的类都可以随时调用msgbox：<br /><br /><br /><pre name="code" class="java">
require 'gtk2'

=begin
 Msgbox: an easy message box based on Gtk::MessageDialog
 usage:
  example 1:
    Msgbox.new("This is a simple message box !").show
    
  example 2:
    if Msgbox.new("Yes or No ?", :type => :QUESTION, :buttons => :YES_NO).show
      puts "Your answer is: 'yes'"
    else
      puts "Your answer is not 'yes'"
    end
    
  example 3:
    Msgbox.new("OK or cancel ?", :type => :QUESTION, :buttons => :OK_CANCEL) do
      puts "Your answer: ok"
    end
    
  example 4, from within Gtk::Window or subclass:
    msgbox "Hello"
    msgbox! "warning infomation !"
    msgbox_err "error !"
    msgbox? "answer the question ...", :buttons=>:YES_NO
    
=end

class Msgbox
  
  def initialize(text = nil, param = {}, &block)
    @param = {}
    @param[:block] ||= block                    
    if @param[:block]
      show(text, param)
    else
      set_params(text, param)
    end
  end

  def set_params(text = nil, param = {})
    @param[:parent] ||= param[:parent]
    @param[:text] ||= text
    @param[:buttons] = case param[:buttons]
                      when :CANCEL, :cancel, "CANCEL", "cancel"
                        Gtk::MessageDialog::BUTTONS_CANCEL
                      when :CLOSE, :close, "CLOSE", "close"
                        Gtk::MessageDialog::BUTTONS_CLOSE
                      when :OK,:ok, "OK", "ok"
                        Gtk::MessageDialog::BUTTONS_OK
                      when :OK_CANCEL,:ok_cancel, "OK_CANCEL", "ok_cancel"
                        Gtk::MessageDialog::BUTTONS_OK_CANCEL
                      when :YES_NO, :yes_no, "YES_NO", "yes_no"
                        Gtk::MessageDialog::BUTTONS_YES_NO
                      when :NONE, :none, "NONE", "none"
                        Gtk::MessageDialog::BUTTONS_NONE
                      else
                        @param[:buttons] || Gtk::MessageDialog::BUTTONS_OK
                      end
    @param[:flags] ||= Gtk::Dialog::MODAL
    @param[:title] ||= param[:title]
    @param[:type] =  case param[:type]
                    when :ERROR
                      @param[:title] ||= "Error"
                      Gtk::MessageDialog::ERROR
                    when :INFO
                      @param[:title] ||= "Information"
                      Gtk::MessageDialog::INFO
                    when :QUESTION
                      @param[:title] ||= "Question"
                      Gtk::MessageDialog::QUESTION
                    when :WARNING
                      @param[:title] ||= "Warning"
                      Gtk::MessageDialog::WARNING
                    else
                      @param[:title] ||= "Information"
                      @param[:type] || Gtk::MessageDialog::INFO
                    end
  end  
  
  def show(text = nil, param = {}, &block)
    set_params(text, param)
    dialog = Gtk::MessageDialog.new(@param[:parent], @param[:flags], @param[:type], @param[:buttons], @param[:text])
    dialog.title = @param[:title]
    dialog.signal_connect('response') do |w, response|
      @response = case response
                  when Gtk::Dialog::RESPONSE_ACCEPT, Gtk::Dialog::RESPONSE_OK, Gtk::Dialog::RESPONSE_APPLY, Gtk::Dialog::RESPONSE_YES
                    true
                  else
                    false
                  end
      dialog.destroy
    end
    if @param[:parent]
      x, y = @param[:parent].position
      w, h = @param[:parent].size
      dw, dh = dialog.size
      dialog.move x + (w - dw) / 2, y + (h - dh) / 2
    end
    dialog.run
    @param[:block] ||= block
    block.call if @param[:block] && @response
    @response
  end
  
end

class Gtk::Window
  def msgbox(text = nil, param = {}, &block)
    param[:parent] ||= self
    param[:block] ||= block
    Msgbox.new(text, param).show
  end
  
  def msgbox!(text = nil, param = {}, &block)
    msgbox(text, param.merge!({:type=>:WARNING, :block=>block}))
  end
  
  def msgbox_err(text = nil, param = {}, &block)
    msgbox(text, param.merge!({:type=>:ERROR, :block=>block}))
  end
  
  def msgbox?(text = nil, param = {}, &block)
    msgbox(text, param.merge!({:type=>:QUESTION, :block=>block}))
  end
  
end


if $0 == __FILE__

class TestWin &lt; Gtk::Window
  def initialize
    super("Message Box Test")
    
    box = Gtk::HButtonBox.new
    buts = []
    ["Info", "Warn", "Error", "Question"].each do |t|
      buts &lt;&lt; (but = Gtk::Button.new(t))
      box.pack_start but
    end
    
    buts[0].signal_connect("clicked") do 
      msgbox "Hello"
    end
    
    buts[1].signal_connect("clicked") do 
      msgbox! "Hello !"
    end
    
    buts[2].signal_connect("clicked") do 
      msgbox_err "Hello, Hello, Hello !!", :title=>"Error happens !"
    end
    
    buts[3].signal_connect("clicked") do 
      if msgbox? "Hello ?", :buttons=>:YES_NO
        msgbox "you select 'YES'"
      else
        msgbox "you don't select 'YES'"
      end
    end
    
    signal_connect("delete-event") do
      Gtk.main_quit
      false
    end
    add(box)    
  end 
    
end

win = TestWin.new
win.show_all
GC.start
Gtk.main

end

</pre><br /><br />上面的例子来源于实际项目，为了使用方便做了很多封装，后面还有一段测试代码，所以有点长。如果你也用RubyGnome开发GUI，那么这个简易的Msgbox将会带来很多方便 :)<br /><br /><br /><strong>Ruby作为GUI编程语言现在还不会成为主流，但是其动态特性将有助于解决传统GUI编程中遇到的问题，而且随着GUI binding lib的成熟，稳定，Ruby，有望在又一个领域成为编程利器。<br /></strong>
          <br/>
          <span style="color:red;">
            <a href="http://rubynroll.javaeye.com/blog/148310#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 14 Dec 2007 12:38:58 +0800</pubDate>
        <link>http://rubynroll.javaeye.com/blog/148310</link>
        <guid>http://rubynroll.javaeye.com/blog/148310</guid>
      </item>
  </channel>
</rss>