两周高强度的工作之后,这个设备驱动终于能够正常工作了。当然,它是buggy的——谁能指望两周就编写出健壮性、稳定性俱佳的设备驱动程序呢?尤其是硬件的连接有数个重大的bug。幸亏有硬件修理实验室和电路图,还有硬件供货商的大力支持。
在week08的时候,我接到个活,需要做出一个Demo版的设备驱动程序,以便公司选择该设备硬件的供货方。此时,公司的硬件部门和供货商已经有了较多的接触,因此在我开始着手准备开发的时候,已经错过了很多信息。
由于硬件供货商希望能够拿下这个单子,而我们设备的OS又是封闭的,因此,供货商便极力推动我快速开发争取把demo尽早做出来;而我本人由于办公室政治的原因(详见这里),希望用这次机会,自己把自己从坑里面拽出来。这两个原因叠加在一起,就形成了两周的高强度工作——本来有3周的时间,但由于wk09有三天参加培训,因此,只剩下两周,这也给我带来了不小的压力。事实上,在压力下,这个demo的开发取得了不错的效果。——算上上周末两天,到今天正好使用了10天。
首先是硬件环境的问题。硬件供货商与公司硬件部门的讨论结果是:供电电压和中断输出电压均为2.8V,并且中断pin需要串联一个10K欧的上拉电阻。然而,好像公司硬件部门内部沟通出了问题,导致上述要求全部没有得倒满足。另外,由于该硬件的i2c读写采用16位的地址,而我们设备驱动所使用已封装好的i2c操作都只能针对8位的地址,因此,在该驱动的开发过程中经历了重重困难。幸好在硬件供货商的支持工程师的支持下,用了两个整天的时间发现并解决了所有的问题。
好了,扯了这么多,回到正题:状态机建模。
手持设备的大部分设备驱动在系统中的生命期基本上是与系统相同的:系统启动时加载设备驱动,系统退出时退出。在大部分时候都是处在工作状态。那么,无论何种设备驱动,都应该具有如下几种状态:
- 创建
- 初始化
- 就绪
- 响应中断
- 响应命令
- 销毁
其中,初始化、响应中断、响应命令有可以包含数个状态。以我所做的这个驱动为例子,其初始化分为如下状态:
- 重置
- 初始化数据就绪
- 设备参数校验
- 重新配置设备参数
- 保存新参数
- 软件重置
- 清理中断垃圾数据
这些状态都是自动进行迁移的,也就是说,并不需要外界的命令,根据当前的状态以及一些标志信息,在响应某个事件之后自动发送状态迁移命令。如:
响应设备参数校验完成的事件时,根据校验结果,自动发送进入下一个状态的迁移命令,要么是清理中断垃圾数据,要么是重新配置参数。
而响应中断和响应命令有分别有各自的状态。响应中断的状态有:
- 正在处理中断
- 中断数据处理请求已排队
- 无中断
- 处理排队请求
当驱动处于无中断状态时,可以响应中断;而正在处理中断时,是不能响应中断的;等等。
至于响应命令的状态视实际设备所完成的功能而定。例如,触摸屏的响应命令的状态有如下五个:
- 一个触摸点
- 多个触摸点
- 触摸点已释放
- 启用
- 禁用
前两个状态就包括了触摸点在触摸屏上的滑动。响应命令的状态并不是自动迁移的,它需要用户命令以及中断来驱动它的迁移。在手持设备上的触摸屏就会涉及到一个问题:当有触摸点时,用户发送禁用命令,此时状态的迁移便有了跳跃:需要先迁移到释放状态,然后才能迁移到禁用状态。
好了,既然已经勾勒出来了设备驱动的状态及迁移路径,那么,用状态机建模就是理所当然的事情。状态迁移路径看起来应该像这样:
- class StatePath
- {
- private:
- State startState;
- State intermediateState;
- State endState;
- public:
- virtual void OnStateTransferred(void* data);
- virtual bool ToNextState(const State &s);
- };
其实更为复杂、更为灵活的做法是增加寻路算法,而不是简单地使用一个中间状态。这样的话,状态迁移过程中可以一次性迁移多个状态。
那么,我们的状态机应该看起来像这样:
- class StateMachine
- {
- private:
- list<StatePath> pathList;
- list
stateList - State currentState;
- public:
- virtual bool SetNextState(const State& state);
- };