2008年12月26日星期五

开始二维显示模块的编码

昨天开始简单的二维显示模块的编码。
用python写PyQt的代码就是爽啊!同样是对XML文件的解析,同样是用dom方式,感觉用python的ElementTree就是比用Java来的方便~一个小巧的Ulipad就可以完成Eclipse里功能,limodou真是干实事的人啊~~
二维显示分为四个部分:地图解析,地图显示,组播监听,动态显示。目前完成了前两个部分,组播监听以前用python做过,把代码集成到模块中即可,动态显示也就是简单的更新车辆item的位置和信号item的颜色(如果需要的话),今天应该就可以完成了。
然后就是JTSS中的ResultReporter将收集到的系统中的agent的信息发送到组播端口,将显示模块与JTSS主模块连接起来,这样调试起来就方便多了~
没几天这个月就结束了,调试JTSS要在这个礼拜内完成,下面还有用COPS对数据分类训练TS模型的任务要尽快完成呢!

2008年12月17日星期三

完全在Linux下进行ARM开发

在linux下开发ARM早就是业界公认的了,编写代码,编译代码,早就不是难题了,当然下载到ARM板上也不是难题,但如我等菜鸟一直都不太明了如何操作,单单把下载操作放在Windows环境下用DNW或者其他串口工具来完成。
由于实验室的台式机装的是双系统,而不是虚拟机,在两个系统间切换就尤为不便,于是下定决心要在Linux环境下实现下载操作!
看看DNW的功能,主要有两个:串口交互界面和USB传输文件。在我的Ubuntu系统中,通常知道的串口交互使用命令行工具minicom,但是命令行工具用起来毕竟不是那么方便,于是又找到一款使用minicom作为后端的图形界面程序——cutecom。使用起来非常方便,所有的功能都用按钮放在界面上,不用找来找去。至于USB传输文件的程序,在Ubuntu中文论坛里找到了usb2ram这个小程序,不知道是谁写的,正好针对s3c2410,小胡甚至怀疑是优龙公司出的~:)这个小程序带源代码、makefile文件和二进制文件。其中二进制文件执行有问题,自己在Makefile文件中定义一下CC=gcc,重新make一下,生成新的可执行文件即可。用"sudo ./usb2ram 30200000 filename"执行,注意别漏了sudo哦,不然会出现权限问题。30200000是下载到RAM中的地址,filename可以是内核文件,或者根文件系统,记得下载后不要立即执行(选择n),要再写入到NAND flash中才算完成。会提示你是内核还是根文件系统的,别看错就行~

2008年12月12日星期五

每天都有新的bug

今天发现两个bug! 一处是在MatchUpdate中,没有使用与fillContent匹配的extractContent函数;另一处是增加了IP处理注册请求结束后的回复信息,使得CA可以继续进行流程!

2008年12月3日星期三

当爸爸真不容易啊!

昨天我家孩子终于出生了!多等了一个礼拜,才肯从娘胎里出来~出来的时候可活泼了,哭声响亮,两只黑黝黝的大眼睛睁得溜圆,头发不太多,五官端正,比他爹强,以后八成是个帅哥~~
5点11出生,7点多进了病房,白天我回家补觉,没睡踏实,晚饭后又杀了过了,小家伙在睡觉,喊他也不醒,好不容易醒了,却是因为拉了一泡屎~这家伙能吃能拉,一晚上拉了5次,两次量不多,三次超大量,作为一个连尿不湿也不会换的初级爸爸,忙得我几乎没有活下去的勇气了~~
老婆的伤口很疼,没法帮我,最后发现小家伙喝奶太频繁了,干脆放在床上和妈妈一起睡,效果还真不错,让我们睡了一个小时的好觉~之后开始三番两次的哭,看看尿不湿,没有拉屎,给他喂奶,吃得那叫个欢啊!老婆非说是遗传的我,没办法,承认吧~~
天亮了,在第N次吃完奶后,小家伙终于沉沉的睡去了,我也该回家补觉去了~可怜我家老婆,晚上和我一样没睡好,还要忍受伤口的疼痛,白天还要受小家伙的折磨,当爸爸真不容易,当妈妈更不容易啊!

2008年11月30日星期日

笑来真是一个好老师

一直在看李笑来的博客,感觉他写的东西都是大实话,把自己的一些学习、做事的经历贴出来与大家分享,尤其是与广大的学生分享,对于那些孩子们的成长是大有裨益的!他所强调的耐心,和遇到困难时的态度,都值得反复去体会,学习~
以后让我家孩子也经常上去看看~:)

修改ontology

发现用protege生成的代码是符合规范的,但fillContent后得到的内容却是不符合规范的!其中Concept和Predicate是正常的,AgentAction却是错误的!也没时间仔细研究错误在哪里,干脆先把AgentAction都变成Predicate,能跑起来再说,以后再来调试这个bug~
昨天写了一个摘要,开始想从已有的一个改改,发现不行,思路很混乱。和lp聊了一下,把自己做的工作一说,用大陆上次教的方法一分析,找到了思路,用最简单明了的话把思路表达出来,搞定!可惜后来又发现还有字数要求,并且要求用中文表述一遍。用中文写了一遍出来,发现还是中文表达的更顺畅,毕竟是母语呀~再依据中文把英文的修改了一下,搞定!

2008年11月28日星期五

问题解决了

找到问题了,不怪行为古怪,要怪就怪我给并行行为的其中一个子行为实现为了OntShotBehaviour,结果运行一次就结束了,而并行行为又设置成了WHEN_ANY,所以整个agent的行为都结束了,但在RMA中看agent却还在,把我迷惑了~改成SimpleBehaviour,添加done函数就解决了~

2008年11月27日星期四

古怪的行为

今天去医院检查,一切正常,但下个月还不出来的话就要住院观察了~
下午就开始调试程序,很奇怪,用AgentAction就是不行,非要把Register定义为其他的,如Concept,然后用现成的Action才可以!仔细观察了一下message的content,发现果然是有个地方不对劲,难道是JADE的bug?找了半天也没发现自己错在哪里了!不管了,先用这种方法吧,以后再说~
成功建立起分布在各个host上的container及静态agent之后,TSM也接收到了所有时间相关agent的注册消息,成功注册后开始仿真,向每个事件相关agent发送step消息。消息发出了,可那些agent却没能做出反应,似乎是没有收到。在sniffer中查看确实是发送过去了,在接收step消息处加断点,没有触发!现在怀疑是setup处设置行为时出了问题,还没看出来哪里有问题。串行行为好像没有问题,在onEnd处打印信息,在控制台也看到了,说明它是正常的。并行行为应该两个行为都能接收到message的,至少我原来是这么想的,但现在看来,似乎只有一个可以接收到!这就麻烦了!
今天不行就要等到明早来看了。真是古怪的行为啊!

2008年11月26日星期三

换一种布置agent的方式

昨晚搞了许久都没有解决创建SourceGenerator的问题,十分怀疑是由于arguments的内容太大,用message传递出的问题。苦于用命令行方式启动的jvm无法看到调试信息,一切都只是猜测。但时间不等人啊!
于是决定换一种布置agent的方法来试试。在每一个host中都有完整的map和deployment文件,首先启动MySimulation,用Simulator启动主container和TSM,TSM不再负责创建其他的agent,但是仍有一个initital行为,等待所有的静态agent启动完毕,才开始推进仿真。在其他每个host中,单独启动一个外部程序,这个外部程序根据输入的值确定自己负责启动的子container,然后启动一个agent,由它负责具体静态agent的创建。该agent采用昨天看到的那种简单方式来创建新的agent,避免向AMS发送消息这种方式。
在调试期间,可以用eclipse的debug来启动所有的程序,这样可以解决调试不方便的问题。
今天26号了,下午有事要出门,要开始写摘要了,月底要截止了~

2008年11月25日星期二

创建新的agent

原来是从外部创建agent,后来要在multi-host上配置,就改用了向AMS发送请求的方式,但这种方式要在消息内传递底层的数据,效率确实不高。今晚在网上搜到一个blog,博主也是从06年开始使用JADE,看了几篇文章,发现其中一篇讲到从一个agent创建另一个agent,用的是类似外部创建的方式,但由于是在agent内执行,效率很高,代码很简洁,很受启发,决定在SourceGenerator里使用这种方式。这种方式的限制是只能在本地container中创建 agent,不过由于SourceGenerator是TSM用向AMS发送请求的方式创建的,是分布在各个host中的,因此正好解决了这个问题。

2008年11月21日星期五

进度有点慢了

前两天生了点病——咽炎,差不多快好的时候头又开始疼了,这两天就没有怎么干正事。现在问题来了,进度有点拖慢了!

今天看了笑来的博客,最新的一篇博文又是讲“提高效率的最有效方法——克服拖拉”,里面提到了拖拉“最重要的原因应该在于大多数人喜欢先做甚至只做自己喜欢的……很多人实际上根本不知道自己所谓的“喜欢做某件事情”实际上更可能只不过是因为那件事情相对简单、容易获得奖励而已”。很有道理,至少对于我是正确的。

如果早上起床先做了今天计划中我认为最难的部分,那么这一天就会过得很愉快,工作就会进行的更加顺利一些。所以下面几天每天早上起床吃完饭后要立马开始工作,这样才能完成计划~

2008年11月16日星期日

终于完成一件事

这些天一直在忙这篇小论文,今天总算赶在截止日期前投了出去,本以为来不及了,后来发现12点后还可以,仔细想想明白了,人家是国际会议,时间上当然是以GMT为准,中国是GMT+8,提前了8个小时了~~:)

虽说这件事完了,但后续的事情还没有完,还要继续把仿真平台完善,并做出模拟数据采集系统,这些都要尽快完成。待程序完善后还要写篇中文的投投,也向国内的朋友推荐一下~

该睡觉了,老婆还在等着呢~:)

2008年11月8日星期六

测试一下Google Doc的博客发布功能






测试一下Google Doc的博客发布功能


试一下各种效果

粗体

斜体

下划线

链接

  • 第一
  • 第二
  • 第三

2008年11月7日星期五

时间只有细分才能充分利用

昨日深感浪费时间之危害,回想笑来的文章,决定动手规划一下自己今天的时间安排。

与以往的规划不同的是,这次结合今天要干的事情——写英文句子,将规划细化到每一个句子要花费多少时间,这也许是我唯一可以估计的偏差不太大的东西了。同时顺手将自己避免不了的发散项目——看邮件、看blog、写blog等等明确的列出来,给每一项分配时间,把24小时安排的满满的,当然睡觉也安排进去了~

安排下来,有一种时间就在手中的感觉~下面就看执行力了!这次要严格按照计划来做,同时,先做最困难的事情!

2008年11月6日星期四

发散的紧

今天起床的时候想着要把引言写完,结果到了晚上,目标变成了要把引言的思路理清楚!

看了李笑来的一篇博文,大致的意思是大多数人想到了要干什么(what),为什么要去干(why),唯独在如何去干(how)上没有想清楚。将how细分再细分,直到自己确信确实已经知道要如何安排时间为止,这时会发现要比开始想象的要复杂困难的多!

晚上花了点时间看Google Earth与GPS互联的东西,有个叫GooPs的免费软件很好,可以将GPS信息实时显示在Google Earth上,可惜现在主页出了点问题,无法访问了(不免怀点恶意的想是不是因为抢了Google的生意~),还好在上帝之眼论坛可以下到中英文版。
程序很小,900多K,试用了一下Demo,果然比较好用,选项也很丰富,界面简单实用。仔细观察了一下,发现其原理就是在本地建立了一个服务器,然后从GE中打开一个指向该服务器地址的KML文件,向服务器动态发送GET请求,返回包含新内容的kml格式文件,文件中包含最新的位置坐标,就达到了动态显示的效果~
各种选项其实就是KML文件中的各个tag的内容,尝试用Python来实现服务器,看了BaseHTTPServer和SimpleHTTPServer的源代码,心里有底了~不过现在是没时间搞这个了,以后买车了需要导航时再自己DIY一个出来用吧~

一点多了了,想起老罗说过的夜里两点出来散散步,头脑比较清醒,现在才深有同感~赶紧整点正事睡觉吧!

2008年11月1日星期六

还有十来天了

15号截止,是指15号0点之前还是24点之前呢?为了保险起见,我还是在0点之前投出去吧~那么算起来就只有14天了,这还是包括今天在内的!
东西就是这么多,就看如何条理清晰的讲出来,同时还要引人入胜,表达准确,此外还是用非母语,时间就十来天,对我来说难度不小啊!
还好可以参考别人的文章,仔细看看其实也就几块:摘要,引言,理论基础,自己的模型,实验验证,结论。如果一天能写一块,6天也就搞定了!来分析分析这几个部分。
摘要是非常重要的,审稿的上来就是看它,写的不好就直接pass了!看下来似乎都是分为5大句:研究的背景(研究这个不是吃饱了撑的),研究的对象(对于解决问题很有帮助),本文的工作重点(In this paper, we focus on ...),提出的模型/方法(具体的技术细节,突出特点),实验验证(通过实验数据验证模型/方法的有效性)。
引言是摘要中前两点的展开论述,同时要回顾相关领域中已经做了哪些工作,在此基础上还有哪些不足,这就是我们要重点解决的~基本上也就是三大段:研究背景,实际需求;对现存模型/方法的review;本文提出的模型/方法,相关特性,所做的工作,以及后文的安排。
理论基础里简单介绍后面介绍自己的模型时所涉及到的一些基础理论知识,或者是对于数据来源的解释,总之就是介绍自己的模型/方法前的热身(有人也称之为前戏~)。
做足了准备工作,下面才开始讲述重点:自己的模型。这和一般讲故事或是将笑话类似,看来,从小培养孩子讲故事好处多多啊~如何抽丝剥茧地一步步将模型展示出来,是需要很高水平的,只有边写边改了~
实验验证需要数据,这数据可以是从实际系统中采集来的,也可以是在仿真系统中采集来的,实际系统的数据当然更真实,但是采集过程往往很麻烦,甚至是不可能的,所以很多都是从仿真系统中来的数据,只要能说明问题,也就OK啦~

以前想的东西

今天看参考文献,思考了我的仿真平台,也就是大论文要写一些什么内容。
首要主题当然是微观交通仿真平台,特点是基于多智能体,可扩展,分布式,可以仿真复杂的真实交通环境。
除了建模,还有模型的标定。可以采用两种方式采集标定数据:一是进行实际的跑车实验,使用精密的GPS仪器进行测量,采集数据;二是就用我的仿真平台,单独设计一个场景,前面放辆引导车,让testee用键盘或者游戏手柄控制车辆进行跟驰,这样方便很多,还环保,更能充分发挥仿真平台的优势!而且通过设定交通场景,可以采集到各种不同环境下不同测试者的反应。缺点是暂时不可能采用虚拟现实技术,只能让testee以俯视全局的方式来观察,这与真实情况很不一样。另外,在仿真平台上进行测试可能使testee更加大胆,超出正常的驾驶行为,这需要通过事先提醒testee来避免。第二种方法的效果可以通过让方法一中的驾驶者作为方法二中的testee来测试,看两种方法的结果的不同。
模型标定的方法也有很多,这里主要针对模糊推理决策模块的标定方法进行研究。佳点集等东西都可以拿出来放在这里看看效果如何。
模型的应用是最后一个主题。机场场面监控是一个不错的例子。首先,场面的交通环境很复杂,需要遵守更多的规则。其次,场面上的信号灯、标志牌很多,可以充分检验模型中附加设施的有效性。另外,机场在大部分气象条件下都可以运行,这也可以检验模型的适应性。和一般驾驶行为不同的是这里的司机都是专职的,受过严格训练的,对于各种情况的反应是可预期的。不过肯定也存在不同驾驶者之间的区别,可以检验驾驶决策模块中的个性因素。

2008年10月22日星期三

Zotero真是好用

发现Zotero真是好用!尤其是对像ScienceDirect这样提供网页全文的网站,可以在保存文献信息的同时保存下网页快照,然后用Zotero自带的注释和高亮功能写下阅读时的感想,真是太方便了!值得注意的是在网页的左半边是文章内容,右半边是留白,正好可以加上注释,比在pdf中加入注释还要方便~
中文的网站这方面就欠缺不少!以CNKI为例(现在只有支持CNKI的转换器),没有网络全文不说,一段时间不用还要自动注销,显得很是小气。尤其是在暂时没解决translator自动下载pdf全文的情况下,没有网络全文就显得特别不方便了!
另外,Zotero中的便签也很好用,我常用便签来记录对整篇文章的读后感,或者记录下这篇文章的用处等与文章内容关系不大的东西,方便以后再看时可以迅速上手~

2008年10月19日星期日

房子

下个礼拜就要选房子了,明天去看看房子。
今天就看了些文献,找找感觉。
晚上不带笔记本回家了,但是还是可以设计一下需要写什么东西~

2008年10月10日星期五

工作重心转移

前一阵在看三维编程方面的东西,找到了Python+Pygame+Panda3D的组合,学了一点Blender,搞懂了egg文件的格式,正要放开手脚大干一场的时候,反省了一下当前的形势,发现工作重心该转移了!
这些东西应该放在下一个月来做,当前的主要任务是完成JTSS,这是三维编程的基础~
今天已经10号了,这两天就要赶紧完成它,不然这个月来不及写东西了。花了两天的时间重构了车辆与道路之间的通讯方式,简化了很多,真正感觉到了Simple is Beauty!
今天的任务是写更多的模糊推理规则,参数先自己看着定吧,调整就是下一步要做的工作了~

我自己的svn服务器

有个自己的svn服务器感觉真是不错~哈哈
但是有时候没有网络,不能说就不做事吧~所以日常的工作还是放在我的SD卡上的svn中,每隔一段时间(如一周),就把东西再commit到网络服务器上。
这样有一点不方便的就是要在机器上保存两份工作拷贝,一份对应SD的svn,一份对应服务器上的svn,commit到服务器前从SD的工作拷贝把文件拷贝到服务器的工作拷贝里,还好svn能自动识别有修改的文件,用红色图标标记出来,不过这样也要多保存一份拷贝了。只有用多一份拷贝多一份安全来安慰自己了~

2008年10月7日星期二

能自动生成三维模型吗?

今天在看Blender的视频和文字教程,发现有个问题。Blender里要精确的控制模型的大小有点麻烦,尤其是象我所需要的根据不同的交通场景进行建模时,不同的场景如果每次都从头来做的话那是相当的麻烦!能不能找到一个更方便的手段,根据给定的地图来进行建模呢?要知道车辆模型是可以与场景模型分开的,不同的场景可以利用相同的几种车辆模型,而场景需要根据地图的不同,分别进行建模,而且最重要的是要与地图中的完全一致,道路的长度、宽度,车道的变化,交通灯的布局,各种交通设施的放置等等。交通设施还好办,根据地图中的指示放在那里就行了,关键是道路的布置,这是要求最高,并且最麻烦的一类。

我现在的想法是能不能解析地图中的信息,然后自动生成道路的egg文件,然后用blender导入,在里面再添加其他的交通设施,加以润色,最后导出为egg文件,供panda3d使用。这就要求我熟悉egg文件的格式,尤其是plate这一块的东西,可以现在blender里做一个出来,然后导出为egg文件,然后仔细研究一下~

那么其他blender的高级功能就不用再花时间看了,只要会modeling,UVmapping就差不多了,主要的精力放在自动生成道路和放置已有的交通设施在道路边上。具体说来,下面的任务就有如下几个:
  1. 学会从blender中导入导出egg文件;
  2. 学会在blender中构建道路模型;
  3. 了解egg文件的格式;
  4. 解析地图文件,构建egg文件中的道路模型信息;
  5. 在blender中导入包含道路模型的egg文件,添加其他交通设施;
  6. 导出为egg文件,在Panda3D中查看(用pview)。

2008年10月6日星期一

三维模型转换的一点心得

昨天晚上尝试将用wings3d构建的模型转换到Panda3D的egg格式,中间遇到一些小问题,其中一个到今早才解决,记录在这里,备忘。

正如我在上一篇blog里所说的,x文件是目前Panda3D支持最好的格式,先用wings3d将模型导出为x格式文件,然后用x2egg file.x file.egg将x格式文件转为egg格式,很简单,至少看起来是这样。模型的大小对速度影响很大,简单的模型在导出和转换步骤都很快,复杂的模型在两个环节都会很慢,甚至出现内存不足的错误!这个其实是可以解决的,我后面再讲,先说说x文件转换为egg文件常会遇到的问题。

最常见的两个问题是大小写和非法字符。导出的x文件中一般都有图片文件的路径,图片文件名一般都是大写的,而x2egg命令好像是大小写敏感的,而实际的文件名一般都是小写的,因此会出现找不到指定文件的错误。解决方法很简单,用文本编辑器打开x文件,找到图片文件名(一般在开头部分),修改为小写即可。非法字符主要是x文件中的frame或者material中的命名有时候会出现“()”等字符,甚至是乱码。乱码就要手动一个个找出来,随便改个名字就行,其他的非法字符用查找替换去掉就行。需要注意的是,有时候x文件很大,好几M,有的文本编辑器(如PSPad)打开速度会很慢,有的打开速度很快(如记事本),但保存时会写入其他东西(BOM),也不敢用,最后还是用Ulipad比较靠谱,当然也可以用其他的,不过我机子上目前就这几个了~

再来说说内存不足的问题。其实一般的电脑上都不会出现这个问题的,因为有虚拟内存嘛~我恰好昨天装了一个TrueCrypt,它在安装时禁用了虚拟内存,我当时没在意。后来转换大一点的x文件时老是抱怨内存不足,我查看了一下,x2egg果然很耗内存,当时以为无解了,心想图形图像处理果然是耗内存啊!今早突然想到可能是禁用了虚拟内存的问题,马上恢复过来,再一试,果然就可以了~

还有一个问题没解决,有一个模型转换没问题,但在用pview查看egg文件时出错。暂时不管它了,其实那些复杂的模型虽然我也转换了,但鉴于导入后太占内存,以后使用的机会也不多,更多的是使用那些简单的模型,毕竟我对模型的细节要求不高~

另外,发现用egg2bam将egg文件转为二进制的bam文件导入速度果然提高了,但是之后再用pview查看egg文件导入速度也很快,怀疑是不是pview会自动将查看过的egg文件缓存,抑或是自动先找有没有相同文件名的bam文件?

下面的任务就是自己写程序构建一个简单的三维场景,放入车辆,运动起来。还是那句话,程序不复杂,难点还是在三维场景的建模上~加油吧!

2008年10月5日星期日

panda3d是个好东西

从Java3d开始,对场景图(Scene Graph)就一直抱有好感,对直接操作OpenGL深恶痛绝!也正是因为这个原因,虽然python+pygame对于二维的操作非常好,但三维却是直接操作OpenGL,使得我一度倾向于使用java+xith3d,尽管与Python相比,Java让我看着就神经衰弱~

还好发现了Panda3D!它支持python和C++,使用场景图来放置对象,底层功能是用C++写的,但是程序的编写却是鼓励用python,几乎所有的文档和例子都是针对python的。python+pygame+panda3d,简直就是绝配啊~~

好像是从前天开始开始看panda3d的manual,因为有个中文翻译的版本,虽然和最新的手册有些出入,但大致该说的都讲到了,其他一些高级的特性我也用不到,再看了看例子,现在有点感觉了。场景图的概念和Java3d、Xith3D里的差不多,简单易学,我感觉以后这就是3D程序的趋势了。操纵3D对象也很简单,另外还支持动画,这个很有意思,以前我没有关心过,这次看了例子,发现很简单,只要是egg模型文件里有动画就行,都不用编程实现~整个流程就是先建立一个World对象(从DirectObject继承,这样才能响应事件),在__init__函数里导入模型,添加到render上,设置好键盘、鼠标处理函数,用OnscreenText在屏幕上写上提示,再多就是添加几个actor(动画模型)和interval(动画播放),添加几个在每一帧都要调用的task函数,然后建立一个World的实例,调用run函数就OK啦~

当然如果要和pygame联合使用,就要处理Pygame里的鼠标、键盘、游戏手柄等检测事件,这也不难,建立一个task来检查就是了~

所以今天中午感觉使用Panda3D一个关键的环节就是建立3D模型!我以前用wings3d建立的模型如何转换到Panda3D所支持的文件格式是今天主要研究的问题。研究的结果是目前Panda3D对于非egg文件支持最好的就是x文件(DirectX文件),而我用的wings3d可以直接导出为x文件!看上去没什么问题了,不过在完成转换工作并进行测试之前,我仅能持谨慎乐观的态度。今晚的任务就是转换已有的3D模型,并进行测试。

2008年9月19日星期五

终于用上IBus了~

前几天看到有个号称下一代的输入法iBus,linux下用的,正好觉得scim不太好用,就想着哪天有空了试试看。昨天下午调试完程序,心情不错,就试着安装一个iBus。先是从主页下了一个deb安装包,安装时提示新立得里有,就直接从新立得里安装了。很顺利的安装完成,下面就开始折腾人了~
在配置里选择自动启动,引擎里选择了拼音(只装了拼音,另一个太大了,也用不着),OK,没反应!心想可能是和scim有冲突,就卸载了scim,还是不行。在网上找到文章说要sm-switch -s ibus,试了,还是不行,有点崩溃了,又装上scim,结果连scim也不能用了!
今早过来想再试试吧,又上ubuntu的论坛找解决方案,还真找到了!
如果出现能启动ibus 但不能激活输入法或者输入法没有光标跟随到情况,可以下载新的包重新安装或者如下设置:
sudo cp /usr/lib/gtk-2.0/immodules/* /usr/lib/gtk-2.0/2.10.0/immodules/
编辑/usr/lib/gtk-2.0/2.10.0/immodule-files.d/libgtk2.0-0.immodules
sudo vi /usr/lib/gtk-2.0/2.10.0/immodule-files.d/libgtk2.0-0.immodules
在文件到最后添加两行:
"/usr/lib/gtk-2.0/2.10.0/immodules/im-ibus.so"
"ibus" "X Input Method" "gtk20" "/usr/share/locale" "zh"
重新登录即可。

想依葫芦画瓢,第一条命令就遇到问题了,提示说找不到“/usr/lib/gtk-2.0/immodules/”,不管了,继续下面吧,添加上两行后,注销再登录,嘿嘿,可以了~~
看来还是iBus的安装过程少做点事情,希望作者以后可以改进,不然如吾等这样的菜鸟就有的麻烦了~~

BTW,漏掉了一个步骤,在iBus作者的帖子里看到的,使用 sudo im-switch -c 选择 ibus 输入法。由于我已经卸载了scim,因此这条命令的结果是告诉我对于zh-cn只有一个输入法,就是iBus,没得选择~嘿嘿

2008年9月18日星期四

移动C#程序到服务器上

由于需要在服务器上跑监控中心程序,得把笔记本上写的代码拿到服务器上继续开发。
服务器上装的是Server2003,机器自带的,正版,一直没敢换。监控中心的程序是用C#2008速成版开发的,服务器上没有开发环境,要现装一个。期间遇到点问题,主要是无法升级SP,后来解决了,这里就不赘述了。
由于牵扯到MapX、db4o和SQLite,比较麻烦,这里记录一下移动C#程序要注意的东西。
  • 首先是安装C# .NET 2008速成版,2003上安装这个要至少安装Service Pack 1;
  • 然后装DB4O,我装的是7.2版,其他的应该也没问题;
  • 然后装MapX5,也没什么问题,但需要注意的是自定义的图标文件别忘了拷到安装目录的对应目录下;
  • 然后装SQLite,这是SQLite在.NET环境下使用SQLite的设计时工具,蛮好用的~
  • 最后把程序文件夹拷贝到服务器硬盘上,打开后会提示有错误。看了一下,主要是MapX的几个引用找不到了。没关系,删除了,然后重新添加引用,再重新生成解决方案就OK啦~~

2008年7月18日星期五

[转]lftp乱码解决

原文链接:http://hi.baidu.com/smashell/blog/item/e918d83d48e4d204bba16778.html

gedit ~/.lftp/rc
set ftp:charset "gbk"
set file:charset "UTF-8"
alias cn "set ftp:charset gbk; set file:charset UTF-8"
alias utf8 "set ftp:charset UTF-8; set file:charset UTF-8"
默认支持简体中文编码的文件名;两个别名在中文和UTF8设置间来回切换。

2008年7月16日星期三

Flickr

This is a test post from flickr, a fancy photo sharing thing.

发现Zotero和Flock

今天从python-cn邮件列表里发现了Zotero,看了一下教程,好像很好用的样子,目前就是不知道对IEEE及中文的CNKI之类能不能很好的支持,要是可以的话就完美了~~

Flock是由Zotero顺藤摸瓜发现的,支持视频、图片上传方面做得不错,另外还有编辑blog的功能,有点类似Live Writer,内置了对Blogger的支持,就是目前的这个了,哈哈,还挺方便的~

刚才测试了一下,对于IEEE的支持没问题,对国内的CNKI之类支持不够,还要自己添加,不过中文的文章自己处理起来还算轻松,希望以后可以加上相应的支持~

ps: 这两个软件都是OpenSource的,很好很强大!
Blogged with the Flock Browser

2008年7月10日星期四

[转]Linux 串口编程 中英文简体对照 beta 版(第四章)

Chapter 4, Advanced Serial Programming
第四章,高级串口编程

Carol: 已获原作者简体中文翻译授权。
为避免重复劳动,愿意参与翻译的朋友请直接与我联系 puccacarol AT hotmail DOT com
原文名称:Serial Programming Guide for POSIX Operating Systems
<
http://www.easysw.com/~mike/serial/>
此翻译为初稿,语言较粗糙,不断完善中。。。 欢迎大家提出宝贵意见。

This chapter covers advanced serial programming techniques using the ioctl(2) and select(2) system calls.

Serial Port IOCTLs

In Chapter 2, Configuring the Serial Port we used the tcgetattr and tcsetattr functions to configure the serial port. Under UNIX these functions use the ioctl(2) system call to do their magic. The ioctl system call takes three arguments:
int ioctl(int fd, int request, ...);
The fd argument specifies the serial port file descriptor. The request argument is a constant defined in the
header file and is typically one of the constants listed in Table 10.

本章主要谈论使用ioctl(2)和select(2)系统调用的高级串口编程技术。

串行端口 IOCTLs

在第二章,配置串口中我们使用了 tcgetattr 和 tcsetattr 函数来做串口的设置。在 UNIX 下,这些函数都是使用 ioctl(2) 系统调用来完成他们的任务的。ioctl 系统调用有如下三个参数:

int ioctl(int fd, int request, ...);

参数 fd 指定了串行端口的文件描述符。
参数 request 是一个定义在 头文件里的常量,它的一些常用值都在 表10 里面定义了。

Table 10 - IOCTL Requests for Serial Ports
表10 - IOCTL 的串口调用

Request

Description

POSIX Function

TCGETS

Gets the current serial port settings.

读取当前的串口属性

tcgetattr

TCSETS

Sets the serial port settings immediately

设置串口属性并立即生效

tcsetattr(fd, TCSANOW, &options)

TCSETSF

Sets the serial port settings after flushing the input and output buffers.

设置串口属性,等到输入输出缓冲区都清空了再生效

tcsetattr(fd, TCSAFLUSH, &options)

TCSETSW

Sets the serial port settings after allowing the input and output buffers to drain/empty.

设置串口属性,等到允许清空输入输出缓冲区了或数据传完后设置生效

tcsetattr(fd, TCSADRAIN, &options)

TCSBRK

Sends a break for the given time.

在指定时间后发送break

tcsendbreak, tcdrain

TCXONC

Controls software flow control.

控制软件流控

tcflow

TCFLSH

Flushes the input and/or output queue.

将输入输出队列全部发出

tcflush

TIOCMGET

Returns the state of the "MODEM" bits.

返回 “MODEM” 位的状态

None

TIOCMSET

Sets the state of the "MODEM" bits.

设置“MODEM”位的状态

None

FIONREAD

Returns the number of bytes in the input buffer.

返回输入缓冲区内的字节数

None

Getting the Control Signals

The TIOCMGET ioctl gets the current "MODEM" status bits, which consist of all of the RS-232 signal lines except RXD and TXD, listed in Table 11.
To get the status bits, call ioctl with a pointer to an integer to hold the bits, as shown in Listing 5.

获得控制信号
TIOCMGET - ioctl 获得当前“MODEM”的状态位,其中包括了除 RXD 和 TXD 之外,所有的RS-232 信号线,见列表 11。
为了获得状态位,使用一个包含比特位的整数的指针来调用 ioctl,见清单5。

Listing 5 - Getting the MODEM status bits.
清单 5 - 读取 DODEM 的状态位.
#include
#include
int fd;
int status;
ioctl(fd, TIOCMGET, &status);

Table 11 - Control Signal Constants
表 11 - 控制信号常量

Constant

Description

TIOCM_LE

DSR (data set ready/line enable)

TIOCM_DTR

DTR (data terminal ready)

TIOCM_RTS

RTS (request to send)

TIOCM_ST

Secondary TXD (transmit)

TIOCM_SR

Secondary RXD (receive)

TIOCM_CTS

CTS (clear to send)

TIOCM_CAR

DCD (data carrier detect)

TIOCM_CD

Synonym for TIOCM_CAR

TIOCM_RNG

RNG (ring)

TIOCM_RI

Synonym for TIOCM_RNG

TIOCM_DSR

DSR (data set ready)

Setting the Control Signals
The TIOCMSET ioctl sets the "MODEM" status bits defined above. To drop the DTR signal you can use the code in Listing 6.

设置控制信号
TIOCMSET - ioctl 设置“MODEM”上述定义的状态位。可以使用 清单6 的代码来给DTR信号置低。

Listing 6 - Dropping DTR with the TIOCMSET ioctl.
清单 6 - 使用 TIOCMSET ioctl 置低 DTR 信号
#include
#include
int fd; int status;
ioctl(fd, TIOCMGET, &status);
status &= ~TIOCM_DTR;
ioctl(fd, TIOCMSET, &status);

The bits that can be set depend on the operating system, driver, and modes in use. Consult your operating system documentation for more information.

能进行设置的比特位有操作系统,驱动以及使用的模式决定。查询你的操作系统的档案可以获取更多的信息。

Getting the Number of Bytes Available
The FIONREAD ioctl gets the number of bytes in the serial port input buffer. As with TIOCMGET you pass in a pointer to an integer to hold the number of bytes, as shown in Listing 7.

获取可供读取的字节数
FIONREAD - ioctl 读取串行端口输入缓冲区中的字节数。与 TIOCMGET 一起传递一个包含字节数的整数的指针,如 清单7 所示。

Listing 7 - Getting the number of bytes in the input buffer.
清单7 - 读取串行端口输入缓冲区中的字节数
#include
#include
int fd;
int bytes;
ioctl(fd, FIONREAD, &bytes);

This can be useful when polling a serial port for data, as your program can determine the number of bytes in the input buffer before attempting a read.
在查询串口是否有数据到来的时候这一段是很有用的,可以让程序在准备读取之前用来确定输入缓冲区里面的可读字节数。

Selecting Input from a Serial Port
While simple applications can poll or wait on data coming from the serial port, most applications are not simple and need to handle input from multiple sources.
UNIX provides this capability through the select(2) system call. This system call allows your program to check for input, output, or error conditions on one or more file descriptors. The file descriptors can point to serial ports, regular files, other devices, pipes, or sockets. You can poll to check for pending input, wait for input indefinitely, or timeout after a specific amount of time, making the select system call extremely flexible.
Most GUI Toolkits provide an interface to select; we will discuss the X Intrinsics ("Xt") library later in this chapter.

从串行端口选择输入
虽然简单的程序可以通过poll串口或者等待串口数据到来读取串口,大多数的程序却并不这么简单,有时候需要处理来自多个源的输入。
UNIX 通过 select(2) 系统调用提供了这种能力。这个系统调用允许你的程序从一个或多个文件描述符获取输入/输出或者错误信息。文件描述符可以指向串口,普通文件,其他设备,管 道,或者socket 。你可以查询待处理的输入,等待不确定的输入,或者在一指定的超时到达后超时退出,这些都使得 select 系统调用非常的灵活。
大多数的 GUI 工具提供一个借口指向 select,我们会在本章后面的部分讨论 X Intrinsics 库(“Xt”)。


The SELECT System Call
The select system call accepts 5 arguments:
int select(int max_fd, fd_set *input, fd_set *output, fd_set *error, struct timeval *timeout);
The max_fd argument specifies the highest numbered file descriptor in the input, output, and error sets. The input, output, and error arguments specify sets of file descriptors for pending input, output, or error conditions; specify NULL to disable monitoring for the corresponding condition. These sets are initialized using three macros:
FD_ZERO(fd_set);
FD_SET(fd, fd_set);
FD_CLR(fd, fd_set);
The FD_ZERO macro clears the set entirely. The FD_SET and FD_CLR macros add and remove a file descriptor from the set, respectively.
The timeout argument specifies a timeout value which consists of seconds (timeout.tv_sec) and microseconds (timeout.tv_usec). To poll one or more file descriptors, set the seconds and microseconds to zero. To wait indefinitely specify NULL for the timeout pointer.
The select system call returns the number of file descriptors that have a pending condition, or -1 if there was an error.

SELECT 系统调用
Select 系统调用可以接受 5 个参数:

int select(int max_fd, fd_set *input, fd_set *output, fd_set *error, struct timeval *timeout);

参数 max_fd 定义了所有用到的文件描述符(input, output, error集合)中的最大值。
参数 input, output, error 定义了待处理的输入,输出,错误情况;置 NULL 则代表不去监查相应的条件。这几个集合用三个宏来进行初始化
FD_ZERO(fd_set);
FD_SET(fd, fd_set);
FD_CLR(fd, fd_set);
宏 FD_ZERO 清空整个集合; FD_SET 和 FD_CLR 分别从集合中添加、删除文件描述符。
参数 timeout 定义了一个由秒(timeout.tv_sec)和毫秒(timeout.tv_usec)组成的一个超时值。要查询一个或多个文件描述符,把秒和毫秒置为 0 。要无限等待的话就把 timeout 指针置 NULL 。
select 系统调用返回那个有待处理条件的文件描述符的值,或者,如果有错误发生的话就返回 -1。

Using the SELECT System Call
Suppose we are reading data from a serial port and a socket. We want to check for input from either file descriptor, but want to notify the user if no data is seen within 10 seconds. To do this we'll need to use the select system call, as shown in Listing 8.

使用 select 系统调用
假设我们正在从一个串口和一个socket 读取数据。我们想确认来自各文件描述符的输入,又希望如果10秒钟内都没有数据的话通知用户。要完成这些工作,我们可以像 清单8 这样使用select系统调用:

Listing 8 - Using SELECT to process input from more than one source.
清单8 - 使用select 处理来自多个源的输入
#include
#include
#include
#include
int n;
int socket;
int fd;
int max_fd;
fd_set input;
struct timeval timeout; /* Initialize the input set 初始化输入集合*/
FD_ZERO(input);
FD_SET(fd, input);
FD_SET(socket, input);
max_fd = (socket > fd ? socket : fd) + 1; /* Initialize the timeout structure 初始化 timeout 结构*/
timeout.tv_sec = 10;
timeout.tv_usec = 0;
/* Do the select */
n = select(max_fd, &input, NULL, NULL, &timeout);
/* See if there was an error 看看是否有错误发生*/
if (n < 0)
perror("select failed");
else if (n == 0)
puts("TIMEOUT");
else { /* We have input 有输入进来了*/
if (FD_ISSET(fd, input))
process_fd();
if (FD_ISSET(socket, input))
process_socket();
}

You'll notice that we first check the return value of the select system call. Values of 0 and -1 yield the appropriate warning and error messages. Values greater than 0 mean that we have data pending on one or more file descriptors.
To determine which file descriptor(s) have pending input, we use the FD_ISSET macro to test the input set for each file descriptor. If the file descriptor flag is set then the condition exists (input pending in this case) and we need to do something.

你会发现,我们首先检查select系统调用的返回值。如果是 0 和 -1 则表示相应的警告和错误信息。大于 0 的值代表我们在一个或多个文件描述符上有待处理的数据。
要知道是哪个文件描述符有待处理的输入,我们要使用 FDISSET 宏来测试每个文件描述符的输入集合。如果文件描述符标志被设置了,则符合条件(这时候就有待处理的输入了)我们需要进行一些操作。

Using SELECT with the X Intrinsics Library
The X Intrinsics library provides an interface to the select system call via the XtAppAddInput(3x) and XtAppRemoveInput(3x) functions:
int XtAppAddInput(XtAppContext context, int fd, int mask, XtInputProc proc, XtPointer data);
void XtAppRemoveInput(XtAppContext context, int input);
The select system call is used internally to implement timeouts, work procedures, and check for input from the X server. These functions can be used with any Xt-based toolkit including Xaw, Lesstif, and Motif.
The proc argument to XtAppAddInput specifies the function to call when the selected condition (e.g. input available) exists on the file descriptor. In the previous example you could specify the process_fd or process_socket functions.
Because Xt limits your access to the select system call, you'll need to implement timeouts through another mechanism, probably via XtAppAddTimeout(3x).

在X Intrinsics library 中使用select
X Intrinsics library 提供了一个接口,通过 XtAppAddInput(3x) 和 XtAppRemoveInput(3x) 函数来使用 select 系统调用。
int XtAppAddInput(XtAppContext context, int fd, int mask, XtInputProc proc, XtPointer data);
void XtAppRemoveInput(XtAppContext context, int input);
select 系统调用是用来实现内部的超时,工作过程,并且检查来自 X Server 的输入。这些函数可以在任何 基于Xt 的工具上使用,包括Xaw, Lesstif, 和 Motif。
XtAppAddInput 的参数 proc 定义了当某一个文件描述符上的select条件满足时函数的调用(比如有输入进来)。在之前的例子里,你可以定义process_fd 或 processs_socket 函数。
由于 Xt 限制了你对 select 系统调用的访问,你需要通过其他机制实现超时,可以通过 XtAppAddTimeout(3x)。

[转]Linux 串口编程 中英文简体对照 beta 版(第三章)

3. Program Examples 示例程序

All examples have been derived from miniterm.c. The type ahead buffer is limited to 255 characters, just like the maximum string length for canonical input processing ( or ).

See the comments in the code for explanation of the use of the different input modes. I hope that the code is understandable. The example for canonical input is commented best, the other examples are commented only where they differ from the example for canonical input to emphasize the differences.

The descriptions are not complete, but you are encouraged to experiment with the examples to derive the best solution for your application.

Don't forget to give the appropriate serial ports the right permissions (e. g.: chmod a+rw /dev/ttyS1)!

所有的示例来自于 miniterm.c. The type ahead 缓存器限制在 255 字节的大小, 这与标准输入(canonical input)进程的字符串最大长度相同 ( 或 ).

代码中的注释解释了不同输入模式的使用以希望这些代码能够易于理解。标准输入程序的示例做了最详细的注解, 其它的示例则只是在不同于标准输入示例的地方做了强调。

叙述不是很完整, 但可以激励你对这范例做实验, 以延生出合于你所需应用程序的最佳解.

不要忘记赋予串口正确的权限 (也就是: chmod a+rw /dev/ttyS1)!
3.1. Canonical Input Processing 标准输入模式

#include
#include
#include
#include
#include

/* baudrate settings are defined in , which is included by */
// 波特率的设置定义在 . 包含在 里
#define BAUDRATE B38400

/* change this definition for the correct port */
// 定义您所需要的串口号
#define MODEMDEVICE "/dev/ttyS1"

#define _POSIX_SOURCE 1 /*POSIX compliant source POSIX系统兼容*/

#define FALSE 0
#define TRUE 1

volatile int STOP=FALSE;

main() {
int fd,c, res;
struct termios oldtio,newtio;
char buf[255];
/* Open modem device for reading and writing and not as controlling
tty because we don't want to get killed if linenoise sends CTRL-C.
开启设备用于读写,但是不要以控制 tty 的模式,因为我们并不希望在发送 Ctrl-C
后结束此进程
*/
fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY );
if (fd <0) {perror(MODEMDEVICE); exit(-1); }
tcgetattr(fd,&oldtio); /* save current serial port settings */
// 储存当前的串口设置
bzero(&newtio, sizeof(newtio)); /* clear struct for new port settings */
// 清空新的串口设置结构体
/*
BAUDRATE: Set bps rate. You could also use cfsetispeed and cfsetospeed.
CRTSCTS : output hardware flow control (only used if the cable has all
ecessary lines. See sect. 7 of Serial-HOWTO)
CS8 : 8n1 (8bit,no parity,1 stopbit)
CLOCAL : local connection, no modem contol
CREAD : enable receiving characters
BAUDRATE: 设置串口的传输速率bps, 也可以使用 cfsetispeed 和 cfsetospeed 来设置
CRTSCTS : 输出硬件流控(只能在具完整线路的缆线下工作,参考 Serial-HOWTO 第七节)
CS8 : 8n1 (每一帧8比特数据,无奇偶校验位,1 比特停止位)
CLOCAL : 本地连接,无调制解调器控制
CREAD : 允许接收数据
*/
newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;

/*
IGNPAR : ignore bytes with parity errors
ICRNL : map CR to NL (otherwise a CR input on the other computer will not
terminate input) otherwise make device raw (no other input processing)
IGNPAR : 忽略奇偶校验出错的字节
ICRNL : 把 CR 映像成 NL (否则从其它机器传来的 CR 无法终止输入)或者就把设备设
为 raw 状态(没有额外的输入处理)
*/
newtio.c_iflag = IGNPAR | ICRNL;

/*
Raw output. Raw 模式输出
*/
newtio.c_oflag = 0;

/*
ICANON : enable canonical input
disable all echo functionality, and don't send signals to calling program
ICANON : 启动 标准输出, 关闭所有回显echo 功能,不向程序发送信号
*/
newtio.c_lflag = ICANON;

/*
initialize all control characters
default values can be found in /usr/include/termios.h, and
are given in the comments, but we don't need them here
初始化所有的控制字符, 默认值可以在 /usr/include/termios.h 找到,
并且做了注解,不过这里我们并不需要考虑这些
*/
newtio.c_cc[VINTR] = 0; /* Ctrl-c */
newtio.c_cc[VQUIT] = 0; /* Ctrl-\ */
newtio.c_cc[VERASE] = 0; /* del */
newtio.c_cc[VKILL] = 0; /* @ */
newtio.c_cc[VEOF] = 4; /* Ctrl-d */
newtio.c_cc[VTIME] = 0; /* inter-character timer unused */
/* 不使用字符间的计时器 */
newtio.c_cc[VMIN] = 1; /* blocking read until 1 character arrives */
/* 阻塞,直到读取到一个字符 */
newtio.c_cc[VSWTC] = 0; /* '\0' */
newtio.c_cc[VSTART] = 0; /* Ctrl-q */
newtio.c_cc[VSTOP] = 0; /* Ctrl-s */
newtio.c_cc[VSUSP] = 0; /* Ctrl-z */
newtio.c_cc[VEOL] = 0; /* '\0' */
newtio.c_cc[VREPRINT] = 0; /* Ctrl-r */
newtio.c_cc[VDISCARD] = 0; /* Ctrl-u */
newtio.c_cc[VWERASE] = 0; /* Ctrl-w */
newtio.c_cc[VLNEXT] = 0; /* Ctrl-v */
newtio.c_cc[VEOL2] = 0; /* '\0' */

/*
now clean the modem line and activate the settings for the port
清空数据线,启动新的串口设置
*/
tcflush(fd, TCIFLUSH);
tcsetattr(fd,TCSANOW,&newtio);

/*
terminal settings done, now handle input
In this example, inputting a 'z' at the beginning of a line will
exit the program.
终端设置完成,现在就可以处理数据了
在本程序中,在一行的开始输入一个 'z' 会终止该程序
*/
while (STOP==FALSE) { /* loop until we have a terminating condition */
// 循环直到满足终止条件
/* read blocks program execution until a line terminating character is
input, even if more than 255 chars are input. If the number
of characters read is smaller than the number of chars available,
subsequent reads will return the remaining chars. res will be set
to the actual number of characters actually read
即使输入超过 255 个字节,读取的程序段还是会一直等到行结束符出现才会停止。
如果读到的字符少于应刚获得的字符数,则剩下的字符串会在下一次读取时读到。
res 用来获得每次真正读到的字节数
*/
res = read(fd,buf,255);
buf[res]=0; /* set end of string, so we can printf */
// 设置字符串结束符,从而可以顺利使用 printf
printf(":%s:%d\n", buf, res);
if (buf[0]=='z') STOP=TRUE;
}
/* restore the old port settings 恢复旧的串口设置 */
tcsetattr(fd,TCSANOW,&oldtio);
}
3.2. Non-Canonical Input Processing 非标准输入模式

In non-canonical input processing mode, input is not assembled into lines and input processing (erase, kill, delete, etc.) does not occur. Two parameters control the behavior of this mode: c_cc[VTIME] sets the character timer, and c_cc[VMIN] sets the minimum number of characters to receive before satisfying the read.

If MIN > 0 and TIME = 0, MIN sets the number of characters to receive before the read is satisfied. As TIME is zero, the timer is not used.

If MIN = 0 and TIME > 0, TIME serves as a timeout value. The read will be satisfied if a single character is read, or TIME is exceeded (t = TIME *0.1 s). If TIME is exceeded, no character will be returned.

If MIN > 0 and TIME > 0, TIME serves as an inter-character timer. The read will be satisfied if MIN characters are received, or the time between two characters exceeds TIME. The timer is restarted every time a character is received and only becomes active after the first character has been received.

If MIN = 0 and TIME = 0, read will be satisfied immediately. The number of characters currently available, or the number of characters requested will be returned. According to Antonino (see contributions), you could issue a fcntl(fd, F_SETFL, FNDELAY); before reading to get the same result.

By modifying newtio.c_cc[VTIME] and newtio.c_cc[VMIN] all modes described above can be tested.



在非标准输入模式中,输入的数据并不组合成行,也不会进行 erase, kill, delete 等输入处理。我们只是用两个参数来控制这种模式的输入行为: c_cc[VTIME] 设定字符输入间隔时间的计时器,而 c_cc[VMIN] 设置满足读取函数的最少字节数。



MIN > 0, TIME = 0 : 读取函数在读到了 MIN 值的字符数后返回。



MIN = 0, TIME > 0 : TIME 决定了超时值,读取函数在读到一个字节的字符,或者等待读取时间超过 TIME (t = TIME * 0.1s)以后返回,也就是说,即使没有从串口中读到数据,读取函数也会在 TIME 时间后返回。



MIN > 0, TIME > 0 : 读取函数会在收到了 MIN 字节的数据后,或者超过 TIME 时间没收到数据后返回。此计时器会在每次收到字符的时候重新计时,也只会在收到第一个字节后才启动。



MIN = 0, TIME = 0 : 读取函数会立即返回。实际读取到的字符数,或者要读到的字符数,会作为返回值返回。根据 Antonino(参考 conditions), 可以使用 fcntl(fd, F_SETFL, FNDELAY), 在读取前获得同样的结果。



改变了 nettio.c_cc[VTIME] 和 newtio.c_cc[VMIN], 就可以测试以上的设置了。



#include
#include
#include
#include
#include
#define BAUDRATE B38400
#define MODEMDEVICE "/dev/ttyS1"

#define _POSIX_SOURCE 1 /* POSIX compliant source */

#define FALSE 0
#define TRUE 1

volatile int STOP=FALSE;

main() {
int fd,c, res;
struct termios oldtio,newtio;
char buf[255];
fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY );
if (fd <0) {perror(MODEMDEVICE); exit(-1); }

tcgetattr(fd,&oldtio); /* save current port settings */
bzero(&newtio, sizeof(newtio));
newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
newtio.c_iflag = IGNPAR;
newtio.c_oflag = 0;
/* set input mode (non-canonical, no echo,...) */
// 设置输入模式为非标准输入
newtio.c_lflag = 0;
newtio.c_cc[VTIME] = 0; /* inter-character timer unused */
// 不是用字符间隔计时器
newtio.c_cc[VMIN] = 5; /* blocking read until 5 chars received */
//收到5个字符数以后,read 函数才返回
tcflush(fd, TCIFLUSH);
tcsetattr(fd,TCSANOW,&newtio);
while (STOP==FALSE) { /* loop for input */
res = read(fd,buf,255); /* returns after 5 chars have been input */
buf[res]=0; /* so we can printf... */
printf(":%s:%d\n", buf, res);
if (buf[0]=='z') STOP=TRUE;
}
tcsetattr(fd,TCSANOW,&oldtio);
}
3.3. Asynchronous Input 异步输入模式

#include
#include
#include
#include
#include
#include

#define BAUDRATE B38400
#define MODEMDEVICE "/dev/ttyS1"

#define _POSIX_SOURCE 1 /* POSIX compliant source */
#define FALSE 0
#define TRUE 1

volatile int STOP=FALSE;
void signal_handler_IO (int status); /* definition of signal handler */
// 定义信号处理程序
int wait_flag=TRUE; /* TRUE while no signal received */
// TRUE 代表没有受到信号,正在等待中
main() {
int fd,c, res;
struct termios oldtio,newtio;
struct sigaction saio;
/* definition of signal action */
// 定义信号处理的结构
char buf[255];

/* open the device to be non-blocking (read will return immediatly) */
// 是用非阻塞模式打开设备 read 函数立刻返回,不会阻塞
fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fd <0) {perror(MODEMDEVICE); exit(-1); }

/* install the signal handler before making the device asynchronous */
// 在进行设备异步传输前,安装信号处理程序
saio.sa_handler = signal_handler_IO;
saio.sa_mask = 0;
saio.sa_flags = 0;
saio.sa_restorer = NULL;
sigaction(SIGIO,&saio,NULL);

/* allow the process to receive SIGIO */
// 允许进程接收 SIGIO 信号
fcntl(fd, F_SETOWN, getpid());
/* Make the file descriptor asynchronous (the manual page says only
O_APPEND and O_NONBLOCK, will work with F_SETFL...) */
// 设置串口的文件描述符为异步,man上说,只有 O_APPEND 和 O_NONBLOCK 才能使用F_SETFL
fcntl(fd, F_SETFL, FASYNC);
tcgetattr(fd,&oldtio); /* save current port settings */

/* set new port settings for canonical input processing */
// 设置新的串口为标准输入模式
newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
newtio.c_iflag = IGNPAR | ICRNL;
newtio.c_oflag = 0;
newtio.c_lflag = ICANON;
newtio.c_cc[VMIN]=1;
newtio.c_cc[VTIME]=0;
tcflush(fd, TCIFLUSH);
tcsetattr(fd,TCSANOW,&newtio);

/* loop while waiting for input. normally we would do something
useful here 循环等待输入,通常我们会在这里做些其它的事情 */
while (STOP==FALSE) {
printf(".\n");usleep(100000);
/* after receiving SIGIO, wait_flag = FALSE, input is availableand can be read */
// 在收到 SIGIO 信号后,wait_flag = FALSE, 表示有输入进来,可以读取了
if (wait_flag==FALSE) {
res = read(fd,buf,255);
buf[res]=0;
printf(":%s:%d\n", buf, res);
if (res==1) STOP=TRUE; /* stop loop if only a CR was input */
wait_flag = TRUE; /* wait for new input 等待新的输入*/
}
}
/* restore old port settings */
tcsetattr(fd,TCSANOW,&oldtio);
}

/***************************************************************************
* signal handler. sets wait_flag to FALSE, to indicate above loop that *
* characters have been received. *
***************************************************************************/

// 信号处理函数,设置 wait_flag 为 FALSE, 以告知上面的循环函数串口收到字符了
void signal_handler_IO (int status) {
printf("received SIGIO signal.\n");
wait_flag = FALSE;
}
3.4. Waiting for Input from Multiple Sources 等待来自多个源的输入

This section is kept to a minimum. It is just intended to be a hint, and therefore the example code is kept short. This will not only work with serial ports, but with any set of file descriptors.

The select call and accompanying macros use a fd_set. This is a bit array, which has a bit entry for every valid file descriptor number. select will accept a fd_set with the bits set for the relevant file descriptors and returns a fd_set, in which the bits for the file descriptors are set where input, output, or an exception occurred. All handling of fd_set is done with the provided macros. See also the manual page select(2).

这一部分的内容很少,只是作为一个提示,因此这段代码也很简短。而且这部分内容不仅适用于串口编程,而且适用于任意的一组文件描述符。

select 调用及其相应的宏,使用 fd_set. 这是一个比特数组,其中每一个比特代表了一个有效的文件描述符号。 select 调用接收一个有效的文件描述符结构,并返回 fd_set 比特数组,如果此比特数组中有某一个位设为1,就表示对应的文件描述符发生了输入,输出或者有例外事件。所有 fg_set 的处理都由宏提供了,具体参考 man select 2 。



#include

#include

#include



main()

{

int fd1, fd2; /* input sources 1 and 2 输入源 1 和 2 */

fd_set readfs; /* file descriptor set */

int maxfd; /* maximum file desciptor used用到的文件描述符的最大值 */

int loop=1; /* loop while TRUE 循环标志 */



/* open_input_source opens a device, sets the port correctly, and

returns a file descriptor */

// open_input_source 函数打开一个设备,正确设置端口,并返回文件描述符

fd1 = open_input_source("/dev/ttyS1"); /* COM2 */

if (fd1<0) exit(0);

fd2 = open_input_source("/dev/ttyS2"); /* COM3 */

if (fd2<0) exit(0);

maxfd = MAX (fd1, fd2)+1; /* maximum bit entry (fd) to test */



/* loop for input */

while (loop) {

FD_SET(fd1, &readfs); /* set testing for source 1 */

FD_SET(fd2, &readfs); /* set testing for source 2 */

/* block until input becomes available 阻塞直到有输入进来 */

select(maxfd, &readfs, NULL, NULL, NULL);

if (FD_ISSET(fd1)) /* input from source 1 available源1有输入*/

handle_input_from_source1();

if (FD_ISSET(fd2)) /* input from source 2 available 源2有输入*/

handle_input_from_source2();

}

}



The given example blocks indefinitely, until input from one of the sources becomes available. If you need to timeout on input, just replace the select call by:

这个例子会导致未知的阻塞,知道其中一个源有数据输入。如果你需要为输入设置一个超时值,就用下面的select 替代:

int res;

struct timeval Timeout;



/* set timeout value within input loop 在输入循环中设置超时值 */

Timeout.tv_usec = 0; /* milliseconds 设置毫秒数*/

Timeout.tv_sec = 1; /* seconds 设置秒数 */

res = select(maxfd, &readfs, NULL, NULL, &Timeout);

if (res==0)

/* number of file descriptors with input = 0, timeout occurred. 所有的文件描述符都没有得到输入,超时退出返回0 */





This example will timeout after 1 second. If a timeout occurs, select will return 0, but beware that Timeout is decremented by the time actually waited for input by select. If the timeout value is zero, select will return immediatly.



这个例子会在1秒以后超时退出,如果发生超时,select 返回0,请注意 Timeout 是根据select实际等待输入的时间递减的,如果把timeout 设为0, select 函数会立刻退出。
Other Sources of Information 其它资源信息

· The Linux Serial-HOWTO describes how to set up serial ports and contains hardware information.

Linux Serial HOWTO 介绍了如何安装串口,并包括了硬件信息。

· Serial Programming Guide for POSIX Compliant Operating Systems, by Michael Sweet.

POSIX 兼容的操作系统上的串口编程

· The manual page termios(3) describes all flags for the termios structure.

man termios 3 介绍了所有 termios 结构里的设置。

[转]Linux 串口编程 中英文简体对照 beta 版(一、二章)

Serial Programming HOWTO

Linux 串口编程 中英文简体对照 beta 版

翻译:Carol Li

原作:Gary Frerking gary@frerking.org
Peter Baumann

This document describes how to program communications with devices over a serial port on a Linux box.

本文档记述了如何在Linux设备上通过串口进行通信的程序开发

中文简体版以英文 1.01 为原文,同时参考了繁体中文的串口编程HOWTO

1. Introduction 简介

This is the Linux Serial Programming HOWTO. All about how to program communications with other devices / computers over a serial line under Linux. Different techniques are explained: Canonical I/O (only complete lines are transmitted/received), asyncronous I/O, and waiting for input from multiple sources.

This is the first update to the initial release of the Linux Serial Programming HOWTO. The primary purpose of this update is to change the author information and convert the document to DocBook format. In terms of technical content, very little if anything has changed at this time. Sweeping changes to the technical content aren't going to happen overnight, but I'll work on it as much as time allows.

If you've been waiting in the wings for someone to take over this HOWTO, you've gotten your wish. Please send me any and all feedback you have, it'd be very much appreciated.

All examples were tested using a i386 Linux Kernel 2.0.29.

本文是为 Linux 串口程序编写的 HOWTO. 主要讨论如何在 Linux 环境下,编写串口与其它计算机设备进行通讯的程序。文中所谈到的技术包括: 标准的 I/O (只具备 传送/接收 线的), 异步 I/O, 以及 等待来自多信号源输入 的程序。

本文是初始的 linux serial programming howto 的第一个升级版。主要升级了一些作者信息,把文件转换为 DocBook 格式。就技术内容而言,几乎没什么大的改变。大规模的技术内容的改变是不可能一夜之间发生的,如果时间允许,我会尽量做一些工作。

如果你正在一边等着有谁来接管这份 HOWTO,那你的心愿达成了。我会感谢你发来的任何反馈信息。

所有的示例都在 i386 Linux Kernel 2.0.29 下测试通过。

1.1. Copyright Information 版权信息

This document is copyrighted (c) 1997 Peter Baumann, (c) 2001 Gary Frerking and is distributed under the terms of the Linux Documentation Project (LDP) license, stated below.

Unless otherwise stated, Linux HOWTO documents are copyrighted by their respective authors. Linux HOWTO documents may be reproduced and distributed in whole or in part, in any medium physical or electronic, as long as this copyright notice is retained on all copies. Commercial redistribution is allowed and encouraged; however, the author would like to be notified of any such distributions.

Linux Serial-Programming-HOWTO 的版權(C) 1997 归 Peter Baumann 所有,(C) 2001 归 Gary Frerking 所有,并且以 LDP lisence (附后)发布。

除非另做申明,Linux HOWTO 文件的版权归各自的作者所有。Linux HOWTO 文件可以完整或部份的以實物或電子版形式复制或者发布, 只要能在所有的拷贝中保留版權申明即可。我们鼓励允许商業的发布,不過, 如果以此形式发布的话,请告知作者。

All translations, derivative works, or aggregate works incorporating any Linux HOWTO documents must be covered under this copyright notice. That is, you may not produce a derivative work from a HOWTO and impose additional restrictions on its distribution. Exceptions to these rules may be granted under certain conditions; please contact the Linux HOWTO coordinator at the address given below.

In short, we wish to promote dissemination of this information through as many channels as possible. However, we do wish to retain copyright on the HOWTO documents, and would like to be notified of any plans to redistribute the HOWTOs.

If you have any questions, please contact <linux-howto@metalab.unc.edu>

所有的翻譯, 以及其他派生的工作, 或整合合併任何 Linux HOWTO 文件都必須在此版權申明的規範下进行. 也就是说, 你不可以在从 HOWTO 所衍生的工作中, 散佈的文件上附加額外的限制條款。 除了這些規則,都可获得某種條件的授與; 請见后面的地址来聯絡 Linux HOWTO 協調員。

簡而言之, 我們希望儘可能得透過各種渠道来促進這份资料的流通, 不過, 我们強烈希望將此版權宣告置於 HOWTO 的文件上, 并且希望任何重新发佈 HOWTO 的人可以通知我們一下。

如果你有問題, 請通过 email linux-howto@metalab.unc.edu 进行联系.

1.2. Disclaimer 申明

No liability for the contents of this documents can be accepted. Use the concepts, examples and other content at your own risk. As this is a new edition of this document, there may be errors and inaccuracies, that may of course be damaging to your system. Proceed with caution, and although this is highly unlikely, the author(s) do not take any responsibility for that.

All copyrights are held by their by their respective owners, unless specifically noted otherwise. Use of a term in this document should not be regarded as affecting the validity of any trademark or service mark.

Naming of particular products or brands should not be seen as endorsements.

You are strongly recommended to take a backup of your system before major installation and backups at regular intervals.

使用本文的概念,例子及其他内容的风险由您自己承担,我们对此造成的后果不负责任。由于这是份新的文档,可能存在着错误或误差,而有可能导致对您的系统的损害。请小心操作,虽然这是几乎不可能发生的,作者不对此承担任何责任。

除非特别标注,所有的版权归其各自的作者。使用此文档不可标住任何商标或服务标记。

特定的产品或品牌的命名不可被理解为是认可的。(晕,这一段应该请律师来翻)。

强烈推荐您在重大的安装前备份系统,并且做到定期备份。

1.3. New Versions 版本更新

As previously mentioned, not much is new in terms of technical content yet.

如前面所提到的,此版本在技术内容上较前一版本并没有什么大的更新。

1.4. Credits 感谢

The original author thanked Mr. Strudthoff, Michael Carter, Peter Waltenberg, Antonino Ianella, Greg Hankins, Dave Pfaltzgraff, Sean Lincolne, Michael Wiedmann, and Adrey Bonar.

原作者感谢 Strudthoff, Michael Carter, Peter Waltenberg, Antonino Ianella, Greg Hankins, Dave Pfaltzgraff, Sean Lincolne, Michael Wiedmann, and Adrey Bonar 诸位先生。

1.5. Feedback 意见反馈

Feedback is most certainly welcome for this document. Without your submissions and input, this document wouldn't exist. Please send your additions, comments and criticisms to the following email address : <gary@frerking.org>.

非常欢迎对此文档提出反馈意见。有任何补充,评论,批评请发信到: gary@frerking.org

2. Getting started 入门

2.1. Debugging 调试

The best way to debug your code is to set up another Linux box, and connect the two computers via a null-modem cable. Use miniterm (available from the LDP programmers guide (ftp://sunsite.unc.edu/pub/Linux/docs/LDP/programmers-guide/lpg-0.4.tar.gz in the examples directory) to transmit characters to your Linux box. Miniterm can be compiled very easily and will transmit all keyboard input raw over the serial port. Only the define statement #define MODEMDEVICE "/dev/ttyS0" has to be checked. Set it to ttyS0 for COM1, ttyS1 for COM2, etc.. It is essential for testing, that all characters are transmitted raw (without output processing) over the line. To test your connection, start miniterm on both computers and just type away. The characters input on one computer should appear on the other computer and vice versa. The input will not be echoed to the attached screen.

调试代码最好的方法,是另外建立一台Linux主机(Linux box),采用非调制解调器的串口线(null-modem)连接两台机器。还可以使用minicom (可以从 LDP 编程指南上获得:ftp://sunsite.unc.edu/pub/Linux/docs/LDP/programmers-guide/lpg-0.4.tar.gz 里的examples 目录)来传输字符到你的 Linux 主机。Miniterm 很容易编译而且会直接把键盘的输入不做处理(raw 方式)地传到串口。只需要把 定义申明 #define MODEMDIVICE “/dev/ttyS0” 改一下。 COM1 口就设置成 ttyS0, COM2 口就是 ttyS1, 以此类推测试是必需的,所有的字符直接通过缆线传输,不进行任何输出处理。为了测试你的连接,在你的两台机器上开启minicom,然后随意输入一些字符。从一台电脑中输入的字符应该能显示在另一台设备上,反之亦然。输入的字符不会回显(echo) 在本地的屏幕上.

To make a null-modem cable you have to cross the TxD (transmit) and RxD (receive) lines. For a description of a cable see sect. 7 of the Serial-HOWTO.

自制非调制解调器的串口连接线(null-modem cable)时,你需要将一端的传送端(TxD)与另一端的接收端(RxD)连接,一端的接收端与另外一端的传送端连接,详情见Serial-HOWTO第七节。

It is also possible to perform this testing with only one computer, if you have two unused serial ports. You can then run two miniterms off two virtual consoles. If you free a serial port by disconnecting the mouse, remember to redirect /dev/mouse if it exists. If you use a multiport serial card, be sure to configure it correctly. I had mine configured wrong and everything worked fine as long as I was testing only on my computer. When I connected to another computer, the port started loosing characters. Executing two programs on one computer just isn't fully asynchronous.

如果你的电脑有两个空闲的串口端口的话,那么只要使用一台机器就可以做这些试验了,你可以在两个虚拟控制台上各运行一个miniterm,分别用来发送和接收结果。如果你使用串口鼠标,记得在试验前将 /dev/mouse 重定向。如果你使用多端口的串口卡(multiport serial card,一定要确保此设备配置正确,我的电脑就曾因为配置错误,而出现这样的问题:当我在自己的机器上测试的时候一切正常,而连接到其他电脑上的时候,端口开始丢失数据。注意,在一台机器上运行两个串口应用程序,并不是完全异步的。

2.2. Port Settings 端口设置

The devices /dev/ttyS* are intended to hook up terminals to your Linux box, and are configured for this use after startup. This has to be kept in mind when programming communication with a raw device. E.g. the ports are configured to echo characters sent from the device back to it, which normally has to be changed for data transmission.

设备 /dev/ttyS* 会被当作连接到你的 Linux 机器的终端设备,而且在系统启动后就已经配置好了。這一点是在你寫 raw 设备的串口通信程式時必需牢記的. 举例来说,這個串口被設定為回显(echo)所有自此设备送出的字符, 通常在做数据传输时,需要改變這種工作模式。

All parameters can be easily configured from within a program. The configuration is stored in a structure struct termios, which is defined in :

#define NCCS 19
        struct termios {
                tcflag_t c_iflag;         /* input mode flags */
                tcflag_t c_oflag;        /* output mode flags */
                tcflag_t c_cflag;        /* control mode flags */
                tcflag_t c_lflag;        /* local mode flags */
                cc_t c_line;             /* line discipline */
                cc_t c_cc[NCCS];         /* control characters */
}

所有的参数都可以在程序中轻松配置。配置保存在结构体 struct termios 中,这个结构是在 中定义的

#define NCCS 19
        struct termios {
                tcflag_t c_iflag;         /* 输入模式标志 */
               tcflag_t c_oflag;        /* 输出模式标志 */
                tcflag_t c_cflag;        /* 控制模式标志 */
                tcflag_t c_lflag;        /* 本地模式标志 */
                cc_t c_line;             /* 行控制 line discipline */
                cc_t c_cc[NCCS];         /* 控制字符 control characters */
        }

This file also includes all flag definitions. The input mode flags in c_iflag handle all input processing, which means that the characters sent from the device can be processed before they are read with read. Similarly c_oflag handles the output processing. c_cflag contains the settings for the port, as the baudrate, bits per character, stop bits, etc.. The local mode flags stored in c_lflag determine if characters are echoed, signals are sent to your program, etc.. Finally the array c_cc defines the control characters for end of file, stop, etc.. Default values for the control characters are defined in . The flags are described in the manual page termios(3). The structure termios contains the c_line (line discipline) element, which is not used in POSIX compliant systems.

这个文件也包括了所有标志 (flag) 的定义。c_iflag 中的输入模式标志,进行所有的输入处理,也就是说从其他设备传来的字符,在被read函数读入之前,会先按照标志进行预处理。同样的,c_oflag 定义了所有的输出处理。c_cflag 包括了对端口的设置,比如波特率,停止符号等等。c_lflag 包括了,决定了字符是否回显,信号是否发送到你的程序,等等所有的本地工作方式。c_cc 定义了所有的控制符号,例如文件结束符和停止符等等,所有的这些参数的默认值都定义在中,man手册页termios(3)中有这些参数的具体描述。termio结构体中还包括在不能在 POSIX 系统中使用的c_line参数(行控制)

2.3. Input Concepts for Serial Devices 串口设备的输入概念

Here three different input concepts will be presented. The appropriate concept has to be chosen for the intended application. Whenever possible, do not loop reading single characters to get a complete string. When I did this, I lost characters, whereas a read for the whole string did not show any errors.

这里将介绍串行设备三种不同的输入方式,你需要为你的程序选择合适的工作方式。任何可能的情况下,不要采用循环读取单字符的方式来获取一个字符串。我以前这样做的时候,就丢失了字符,而读取整个字符串的 read 方法,则没有这种错误。

2.3.1. Canonical Input Processing 标准输入模式

This is the normal processing mode for terminals, but can also be useful for communicating with other dl input is processed in units of lines, which means that a read will only return a full line of input. A line is by default terminated by a NL (ASCII LF), an end of file, or an end of line character. A CR (the DOS/Windows default end-of-line) will not terminate a line with the default settings.

Canonical input processing can also handle the erase, delete word, and reprint characters, translate CR to NL, etc..

这是终端设备的标准处理模式, 在与其它 dl 的以行为单位的输入通讯中也很有用。这种方式中, read 会传回一整行完整的输入. 一行的结束,默认是以 NL (ASCII值 LF), 文件结束符, 或是一个行结束字符。默认设置中, CR ( DOS/Windows 里的默认行结束符) 并不是行结束标志。

标准的输入处理还可以处理 清除, 删除字, 重画字符, 转换 CRNL 等等功能。

2.3.2. Non-Canonical Input Processing 非标准输入模式

Non-Canonical Input Processing will handle a fixed amount of characters per read, and allows for a character timer. This mode should be used if your application will always read a fixed number of characters, or if the connected device sends bursts of characters.

非标准输入处理可以用于需要每次读取固定数量字符的情况下, 并允许使用字符接收时间的定时器。这种模式可以用在每次读取固定长度字符串的程序中, 或者所连接的设备会突然送出大量字符的情况下。

2.3.3. Asynchronous Input 异步输入模式

The two modes described above can be used in synchronous and asynchronous mode. Synchronous is the default, where a read statement will block, until the read is satisfied. In asynchronous mode the read statement will return immediatly and send a signal to the calling program upon completion. This signal can be received by a signal handler.

前面敘述的兩種模式都可以用在同步與异步的傳輸模式。默认是在同步的模式下工作的, 也就是在尚未讀完数据之前, read 的狀態會被阻塞(block)。而在异步模式下,read 的狀態會立即返回並送出一个信号到所调用的程式直到完成工作。這個信号可以由信号处理程式 handler來接收。

2.3.4. Waiting for Input from Multiple Sources 等待来自多信号源的输入

This is not a different input mode, but might be useful, if you are handling multiple devices. In my application I was handling input over a TCP/IP socket and input over a serial connection from another computer quasi-simultaneously. The program example given below will wait for input from two different input sources. If input from one source becomes available, it will be processed, and the program will then wait for new input.

The approach presented below seems rather complex, but it is important to keep in mind that Linux is a multi-processing operating system. The select system call will not load the CPU while waiting for input, whereas looping until input becomes available would slow down other processes executing at the same time.

本节介绍的不是另一个输入模式,不过如果你要处理来自多个设备的数据的话,可能会很有用。在我的应用程序中,我需要同时通过一个 TCP/IP socket 和一个串口来处理其它计算机传来的输入。下面给出的示例程序将等待来自两个不同输入源的输入。如果其中一个信号源出现, 程序就会进行相应处理, 同时程序会继续等待新的输入。

后面提出的方法看起来相当覆杂, 但请记住 Linux 是一个多进程的操作系统。 系统调用 select 并不会在等待输入信号时增加 CPU 的负担,而如果使用轮询方式来等待输入信号的话,则将拖慢其它正在执行的进程。