基于UML的嵌入式软件实现自动取款机系统模型的设计

作者:倪红军;赵绍刚;朱美强
引言
随着嵌入式应用的不断增长 , 嵌入式系统需求的复杂性、不确定性不断提高 , 系统规模也逐步扩大;而产品的研发周期又在很快地缩短 , 给嵌入式应用软件的开发带来了新的挑战 。同时 , 嵌入式软件的开发者必须面对由于芯片性能的增长、嵌入式操作系统平台等技术方面不断变化所带来的各种压力 。嵌入式软件开发环境的发展 , 使一直“深埋”于系统的嵌入式应用软件变得开放而易于开发 , 从而促进了嵌入式技术的广泛应用 。
1 基于UML的嵌入式软件开发环境结构
图1所示为一种支持基于UML(Unified Modeling Language , 统一建模语言)的迭代式开发方法的开发环境的结构 , 虚框部分为基于UML的软件开发环境 。

基于UML的嵌入式软件实现自动取款机系统模型的设计
文章插图
图1 基于UML嵌入式软件开发环境的结构
系统分析和设计用UML来描述 , 对系统建模;实现过程利用代码自动生成技术来实现;测试过程将依赖于生成的代码 , 通过在代码中拆装一些用于支持模型调试的调试信息来实现;而代码的编译、链接则采用目标系统的操作系统开发环境来完成 , 代码的运行与源程序级的调试仍然采用一般的嵌入式软件调试环境 。
Rhapsody是一个基于UML的面向嵌入式实时应用开发的集成、可视化环境 。软件开发者可以在这个环境里进行分析、设计、实现及验证 。Rhapsody支持基于模型的调试;提供专门为实时嵌入式应用设计的可执行的框架 , 可以产生基于VxWorks、POS、OSE等多种操作系统的C++语言、C++语言、Java语言的源程序 。本文所给出的自动取款机系统的模型正是基于Rhapsody设计的 。
2 自动取款机系统模型的设计
2.1 需求分析
我们设计的自动取款机系统要满足如下要求:
在自动取款机系统中 , 当顾客在自动取款机操作面板上插入信用卡并输入密码和现金支取数额(每次最多只能取一千元)后 , 由自动取款机读取卡上的内容 , 并把相应信息传送到银行 。银行把自动取款机送来的信息与银行帐号上的信息进行比较 , 如果两者一致 , 则银行传送确认信息到自动取款机 , 由自动取款机输出现金 , 然后顾客取出卡和现金;如果两者不一致 , 则要求顾客再次输入密码和现金支取数额 , 然后重复上述操作;若密码输入三次不正确 , 自动取款机就会吞掉信用卡 , 顾客就不能取出信用卡和现金 。
该自动取款机系统包括1个键盘(10个数字键、ENTER键和CANCEL键)、1个LCD液晶显示屏、1个插卡孔和1个现金出口;通过双绞线与银行中的电脑进行串行通信 。该自动取款机系统不包括银行中的电脑 , 只是通过软件与银行中的上位机进行串行通信 。
2.2 可视化建模
建模是面向对象分析和设计的核心 , 也是分析和设计过程中最基本和最关键的活动之一 。UML不仅适用于以面向对象技术描述的任何类型的系统 , 而且适用于系统开发的不同阶段 。根据开发过程中不同阶段的具体要求 , 利用UML不同类型的图来描述系统的各种静态结构模型和动态行为模型 。下面介绍如何利用基于UML的面向嵌入式实时应用开发的集成可视化环境Rhapsody创建自动取款机系统的模型 。
第一步:根据要求建立用例图 。
图2所示为用例图 。图中给出了自动取款机系统的主要用途 , 并表明由谁使用自动取款机系统 。有一个主要成员——顾客 。一个用例图应该具有这样的系统功能:对操作者而言 , 它返回可观察的结果但并不显示系统的内在结构 。

基于UML的嵌入式软件实现自动取款机系统模型的设计
文章插图
图2 自动取款机系统的用例图
自动取款机系统的主要用途是“取出现金” 用例 。顾客参与其中的两个实例是“输入密码”和“取出现金” 。这两个实例都包含了另一个用例“读取卡上内容并验证” 。对每一个用例而言 , 我们都可以增加文本描述 。假如需要的话 , 这些用例能够被细化成另一张更多用例的图 。这些用例并没有显示任何内在的结构 , 仅是一个功能性的视图 。
第二步:设计黑匣子场景 。
建立了一个用例图后 , 下一步便是细化用例 , 即设计一些黑匣子场景 。这些黑匣子场景的主要作用是表明模型和对象之间的相互关系 。把整个系统看作一个整体 , 对 “取出现金” 用例 , 我们细化为图3所示的场景 。(由于每次最多只能取一千元 , 所以最多只需要按键4次 。)

基于UML的嵌入式软件实现自动取款机系统模型的设计
文章插图
图3 取出现金的黑匣子场景
图3所示的场景能被MSD(消息序列表)捕获 , 用来描述在顾客和自动取款机系统之间的通信行为 。当创建这样的图表时 , 关于系统的更多细节被隐藏了;同时 , 这些场景帮助我们更好地理解使用者如何使用报警系统以及需要做哪些事情 。总而言之 , 每一用例都有很多的场景需要捕获 , 每一个场景都是用例的一个有效的实例 。
第三步:设计子系统图 。
下一步是如何把模型分割成子系统 。在UML中 , 一个子系统作为一个封装显示 , 即主要是一个类的集合 。图4的子系统图表明自动取款机系统已经被分解成两个基本的部分:自动柜员机封装(AtmerPkg)和硬件封装(HardharePkg) 。同时也表明:自动柜员机封装是完全独立于实际的硬件和硬件封装的 , 并且实现了Ihardware接口能够用于连接自动柜员机封装 。接口类Ihardware描述了对自动柜员机封装的所有必需的操作 , 实现了应用与硬件环境的隔离 。

基于UML的嵌入式软件实现自动取款机系统模型的设计
文章插图
图4 自动取款机系统的子系统
一旦在自动柜员机封装和硬件封装之间定义了接口类 , 每一个子系统就能同步和独立地细化为更多的子系统 。每一个子系统都知道它和其它子系统之间的接口 。例如 , 我们可以开始分析自动柜员机子系统图 , 而不需要知道关于硬件的更多情况 。
第四步:设计对象模型图 。
对自动柜员机封装而言 , 我们设想有一个AtmerController类 , 其中包含Keypad类、Card类、LCD类和Cash类 , 这些类表示如图5所示 。

基于UML的嵌入式软件实现自动取款机系统模型的设计
文章插图
图5 AtmerController类的对象模型
图5表明:AtmerController类作为一个聚合类 , 包含了其它类的实例 。我们也能看出 , 我们能选择显示“Keypad”类的不同的操作和属性 。在上面的例子中 , 假如一个实例被AtmerControlle类创建 , 那么它将创建Keypad类的一个实例theKeypad、LCD类的一个实例theLCD、Cash类的一个实例theCash以及Card类的一个实例theCard 。假如AtmerController类的实例被删除 , 这些包含的实例也同时被删除 。
Ihardware类也有一些纯虚函数 , 所以为了测试AtmerController类 , 必须忽略这些操作 。图6表示:ATM包含了 AtmerController类的一个实例和从Ihardware类继承并忽略了其操作的Hw类的一个实例 。

基于UML的嵌入式软件实现自动取款机系统模型的设计
文章插图
图6 ATM对象模型图
第五步:生成白匣子场景 。
生成了一个新类AtmerController后 , 就可以开始为每一个黑匣子场景生成白匣子场景 。消息序列表将用于获取以上不同场景的类的实例之间的通信行为 。例如 , 图7消息序列描述了顾客输入支取现金数额并取出现金的场景 。

基于UML的嵌入式软件实现自动取款机系统模型的设计
文章插图
图7 顾客输入支取现金数额并取出现金的场景
消息通常对应于对象模型中操作和操作的返回值 。消息值对应于类的属性或是类操作的返回值 。消息可以是同步的 , 也可以是异步的 。从图中可以看出 , 这些类都有动态行为:它们正在处理定时事件;调用其它类的操作;接受事件 。对UML来说 , 这些动态行为都可以用一个状态图来表示 。
第六步:创建状态图 。
以顾客输入密码过程为例 , 创建状态图 , 如图8所示 。通常 , 当一个问题很复杂时 , 它往往被分解成一些简单的问题 , 这也正是对顾客输入密码过程要做的事情 。图8所示的状态图描述了顾客输入密码过程中的行为 。

基于UML的嵌入式软件实现自动取款机系统模型的设计
文章插图
图8 顾客输入密码过程的状态图
2.3 属性、操作和事件
属性来源于需求文档中定义的数据 , 应该简单 , 不考虑设计和实现的细节 。每个类都可能有定义在其上的事件和操作 。事件对应于明确的瞬时发生的影响类的动态行为 。操作对应于类的服务和功能 。Rhapsody中有3种事件 。
① 信号事件:对应于实例间的异步通信 。
② 时间事件:这种事件在进入一个状态并且经过一个指定的时间后触发 。
③ 触发操作:触发操作是同步的操作 , 通过能够迅速得到响应的事件得到执行 。触发操作没有实现代码 , 却可以作为类的状态图转移的触发器 。当调用触发操作时 , 同时产生响应的事件 。
2.4 生成代码
一般嵌入式应用中有60%~90%的代码用于内务处理(如状态图的实现、任务间的通信等) , 这些代码在设计新的系统时一般都可以重用 。这种重用一般是通过实时框架来实现的 。Rhapsody就提供了这样一个实时框架 , 它提供了一套嵌入式和实时应用专门选择和优化的设计模板 。嵌入式应用程序一般都运行在嵌入式操作系统的平台上 , 而实时框架就是一个在操作系统之上应用程序之下的中间件 。应用程序的编写或自动产生都基于有统一接口的实时框架 , 这样就使应用软件的开发与具体的平台无关 , 解决了嵌入式应用软件的移植问题 。
一旦画出其余的图表并创建好不同类的实例后 , 就能进行代码的生成和模型的测试工作 。在Rhapsody中 , 需要进行一些配置 , 以告诉 Rhapsody从哪些类生成代码及使用什么样的环境 。首先 , 使用Microsoft环境(Windows操作环境和Visual C++编译器) 。然后 , 代码在Rhapsody中生成和编译 , 以产生可执行程序 。
2.5 使UML模型有效
Rhapsody能使用自动生成的代码 , 所以 , 当实际的代码运行时 , 它能返回一些信息给调试工具 , 以便Rhapsody进行模型的测试 。通过模型级调试、验证 , 可以尽早发现系统的设计错误或缺陷 , 从而较早地确定或降低项目的风险 。
2.6 测试模型
一旦自动柜员机封装被手工产生的事件测试通过并观察发生的情况后 , 就可以利用如微软的Visual C++产生一个GUI 。用于创建GUI的类从Ihardware类继承而来 , 选中set选项 , 当按钮被按下时 , 调用ON操作 。GUI也能促使模型在模型级再次被调试 。
3 在VxWorks上运行
模型是系统整体的抽象 。软件开发的最终形式必须生成程序代码 , 模型毕竟是一些漂亮的蓝图 。虽然它对软件的设计有很大的作用 , 但用户的最终目的是希望得到可执行的程序 。对于嵌入式实时系统 , 代码与系统要求(时间约束、资源的限制等)是紧密联系的 , 用最终形式的源程序验证系统的模型更准确 。
Rhapsody可利用软件自动生成技术的成果 , 根据模型可以自动生成具有产品质量的代码 。这种代码既可以作为系统模型验证的代码 , 也是系统最后提交的代码 。所以产生的代码是基于某个具体平台的代码 , 通过编译即可运行在该平台上 。本文采用的是美国 Wind River System 公司推出的一个实时操作系统VxWorks 。它是一个运行在目标机上的高性能、可裁剪的嵌入式实时操作系统 。
从Ihardware类继承而来并选中set选项而创建新类HwIrq 。这些操作的实例可以被写进Rhapsody中 。为了写到I/O板中 , 使用VxWorks系统的操作sysOutByte 。
HwIrq类已经被设置成一个活动类 , 所以它能在自己的线程运行 , 线程的参数被配置如下:线程名为tRhpHw , 堆栈长度为4096字节 , 优先级为180 。
HwIrq.cpp的部分程序见本文附件 。
4 结论
本文运用基于UML的嵌入式实时应用软件开发环境Rhapsody来设计和实现自动取款机系统的模型 。与传统的嵌入式软件开发方法相比 , 具有明显的优势 。它大大缩短了产品的开发周期 , 解决了嵌入式应用软件的移植问题 , 使软件的开发工作主要集中在高层的建模和模型的测试及验证上 , 从而使软件开发工作的焦点从编码转到了设计上 。
【基于UML的嵌入式软件实现自动取款机系统模型的设计】 责任编辑:gt

    推荐阅读