VxWorks 输入输出重定向

from:http://blog.chinaunix.net/uid-22237530-id-1781882.html

VxWorks操作系统是美国WindRiver公司于1983年设计开发的一种嵌入式实时操作系统(RTOS),是嵌入式开发环境的关键组成部分。良好的持续发展能力、高性能的内核以及友好的用户开发环境,在嵌入式实时操作系统领域占据一席之地。它以其良好的可靠性和卓越的实时性被广泛地应用在通信、军事、航空、航天等高精尖技术及实时性要求极高的领域中,如卫星通讯、军事演习、弹道制导、飞机导航等。实时嵌入式操作系统VxWorks已经在国内的嵌入式系统开发中占据着重要的地位,特别是在通信行业中。
   在通信设备中,一般都是无头设备,所谓无头设备是指不外接显示器,也不外挂键盘的,那么这个时候一般采用串口作为其输入输出的用户操作接口。怎么将串口转换为标准输入输出的用户操作接口,此时就出现了标准输入输出的重定向问题,笔者在VxWorks的开发中,曾多次碰到此问题,并就此问题进行了一些研究,也有一些心得。
   VxWorks5.4中的输入输出重定向
   在VxWorks5.4 for X86的开发中,缺省输入输出是PC console,也即通过VGA的标准输出和键盘的标准输入。
   那么此时怎么将其输入输出定向到串口上来呢?
   a)、BootRom中的重定向
   打开target\config\all\bootConfig.c文件,可以找到这样一行代码:
   consoleFd = NONE;
   此consoleFd变量即标准输入输出句柄,此时为空。
   同样,可以找到如下的三行代码:
   ioGlobalStdSet (STD_IN, consoleFd);
   ioGlobalStdSet (STD_OUT, consoleFd);
   ioGlobalStdSet (STD_ERR, consoleFd);
   此三行代码的意思是将标准输入输出定向到consoleFd。
   在这两段代码之间有打开诸如串口、PC console等过程,并将其打开的句柄赋给了consoleFd,这样就将其标准输入输出定向到PC console等。
   同样,如果在定向之前,即ioGlobalStdSet函数之前打开别的I/O设备,如socket、文件、管道等的话,那么标准输入输出就定向到socket、文件、管道等。
一般情况下,用户采用串口作为输入输出操作接口,所以我们一般将标准输入输出定向到串口。
   那么,怎么将标准输入输出定向到串口呢?按照以上原理,只要在ioGlobalStdSet函数之前打开相应的串口并将所打开的串口句柄赋给consoleFd就可以了。
实现代码如下:
   /*打开串口,输入输出重定向到超级终端*/
   if((consoleFd=open("/tyCo/0",O_RDWR,0))==ERROR)
   logMsg("open /tyCo/0 error! \n",0,0,0,0,0,0);
   (void)ioctl(consoleFd,FIOBAUDRATE,9600);
   (void)ioctl(consoleFd,FIOSETOPTIONS,OPT_TERMINAL&~OPT_ECHO);
   (void)ioctl(consoleFd,FIOWFLUSH,0);
   (void)ioctl(consoleFd,FIORFLUSH,0);
   b)、VxWorks中的重定向
   在BootRom中将标准输入输出已经定向到串口,但是在VxWorks中,当BootRom起来将VxWorks引导后,将执行权交给了VxWorks,而此时VxWorks会将BootRom中对硬件初始化的过程重新初始化,故其定向会重新按照缺省方式定向到PC console,标准VGA输出和键盘输入。
   那么又怎么将其定向回串口呢?
   打开target\config\comps\src\usrPcConsole.c文件
在其代码中也同样可以看到其定向过程,那么我们也可以按照BootRom的方式将串口打开并定向。
   VxWorks5.5中的输入输出定向
   在VxWorks5.5中,已经将其标准输入输出直接定向到串口,并且其标准输入输出更简单,直接通过target\config\bspName\config.h文件中的宏定义就可以实现。
怎么样切换回PC console的输入输出模式呢?
   在target\config\bspName\config.h文件中,可以找到如下定义:
   #undef INCLUDE_PC_CONSOLE /* PC keyboard and VGA console */
   #ifdef INCLUDE_PC_CONSOLE
   # define PC_CONSOLE (0) /* console number */
   # define N_VIRTUAL_CONSOLES (2) /* shell / application */
   #endif /* INCLUDE_PC_CONSOLE */
   /* PS/2 101-key default keyboard type (use PC_XT_83_KBD for 83-key) */
   #define PC_KBD_TYPE (PC_PS2_101_KBD)
   从上可以看出,缺省情况下,宏INCLUDE_PC_CONSOLE是关闭的,所以我们在制作BootRom后,启动时在显示器上会出现如下的输出:
V1.6+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++……
并且此时会停在这里不动,感觉好象是系统不能启动,其实,系统已经启动起来了,并且其打印信息已经输出到串口,如果你插上串口线的话,可以从超级终端看到打印输出的。
   定义宏INCLUDE_PC_CONSOLE后,同时也定义了PC_CONSOLE和键盘类型,这样就可以通过键盘接受标准输入,通过显示器有标准输出。
   实际开发中的应用
   在实际产品开发中,用户可能会开发适合自己风格的用户操作接口,包括Telnet、console等,console即串口的超级终端输入输出,按照以上方法实现其定向,但是Telnet时可能就需要随时将标准输入输出定向到打开的相应的Telnet socket。WindRiver公司有一套制作用户接口(CLI)工具——RapidControl,利用此工具可以很快开发出类CISCO风格的Telnet、console。此工具提供了将输入输出定向到Telnet socket的API 函数,但是有很多VxWorks的系统函数如ping、inetstatShow、ipstatShow其输出还是标准的printf,故在Telnet 中调用这些函数时,就需要随时实行标准输入输出的定向。
   假如某Telnet打开的socket为sock:
   ioGlobalStdSet(STD_OUT,sock);
   ioGlobalStdSet(STD_IN,sock);
   ioGlobalStdSet(STD_ERR,sock);
   ipstatShow();
   ioGlobalStdSet(STD_OUT,consoleFd);
   ioGlobalStdSet(STD_IN,consoleFd);
   ioGlobalStdSet(STD_ERR,consoleFd);
   先将输入输出定向到sock,调用相关的函数,再将输入输出定向回来,如果不定向回来的话,那么console和别的Telnet就无法操作了。
   结束语:
   在VxWorks for PPC的系统中,不支持PC console模式,其标准输入输出缺省就是串口,故不存在输入输出的定向问题.

 

<think> 嗯,用户想要了解VxWorks 7.0标准输入的使用方法和特性。用户明确提到了"标准输入",结合之前的对话历史,需要特别注意VxWorks嵌入式实时系统的特性,与通用操作系统不同。 用户可能正在开发VxWorks应用程序,需要处理键盘或串行端口输入。考虑到VxWorks的实时性要求,应该着重强调任务阻塞、轮询等关键机制。 关于标准输入的使用方法,准备从三个层面展开:设备层(consoleDrv)、文件描述符层(STDIN_FILENO)、标准库层(stdio)。特性方面需要突出实时性相关设计,比如非缓冲模式、任务阻塞机制等。 注意到用户特别询问了"特性",这可能意味着用户需要评估该功能是否符合项目需求。因此需要包含多任务环境下的注意事项,比如多个任务同时读取时的行为。 代码示例很重要,但应该保持简洁。准备展示最基本的read()调用示例,并注明需要设备初始化。同时提醒用户注意不同启动配置可能影响默认标准输入设备。 安全性相关的提示也不能少,特别是输入验证和缓冲区溢出防护,这对嵌入式系统尤为重要。最后考虑补充常见问题点,比如设备未初始化时的错误码,这样可以帮助用户调试。 </think> 好的,VxWorks 7.0 中的标准输入(通常记为 `stdin`)是应用程序用于从默认输入设备(通常是控制台终端)读取数据的关键接口。它的使用方法和特性与通用操作系统有相似之处,但也具有嵌入式实时系统的独特考虑。 **使用方法:** 1. **`stdio`库函数:** * 最常用的是通过标准C库函数操作 `stdin`。 * **读取数据:** * `char* fgets(char *s, int size, FILE *stream);`:从 `stdin` (`stream` 设置为 `stdin`) 读取一行文本到缓冲区 `s`,最多读取 `size-1` 个字符,并在末尾自动添加 `'\0'`。遇到换行符 `'\n'` 或 EOF 时停止。这是读取行输入最安全的方式。 * `int scanf(const char *format, ...);`:从 `stdin` 读取格式化输入。需要小心处理输入缓冲区溢出和格式匹配错误。 * `int getchar(void);`:从 `stdin` 读取单个字符。 * `size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);`:从 `stdin` 读取二进制数据块。 * **检查状态:** * `int ferror(FILE *stream);`:检查 `stdin` 上的错误标志。 * `int feof(FILE *stream);`:检查 `stdin` 是否已到达文件结束(EOF)。 * **清空缓冲区:** * `int fflush(FILE *stream);`:对于输出流有效。对于输入流 `stdin`,其行为由 C 库实现定义,**通常不用于清空输入缓冲区**。在 VxWorks 中,如果需要丢弃未读的输入,可能需要使用底层 I/O 或特定于控制台驱动的方法(如 `ioctl`)。 2. **低级 I/O 函数:** * 可以使用 POSIX 标准的低级文件描述符操作。 * `int read(int fd, char *buffer, size_t maxbytes);`:从文件描述符读取数据。标准输入的文件描述符是 `STDIN_FILENO` (通常定义为 0)。 ```c char buf[128]; int bytesRead = read(STDIN_FILENO, buf, sizeof(buf) - 1); // 留一个位置给 '\0' if (bytesRead > 0) { buf[bytesRead] = '\0'; // 手动添加字符串结束符 printf("Read: %s\n", buf); } else if (bytesRead == 0) { printf("EOF reached.\n"); } else { perror("read error"); } ``` * `ioctl`:可用于控制设备的特定行为(如设置终端模式)。 3. **底层驱动访问(高级):** * 对于需要更精细控制或访问非标准输入设备的情况,可以直接操作 VxWorks 的 **`tyLib` (终端 I/O 库)** 和 **`consoleDrv`(控制台驱动)** 提供的 API(如 `tyRead()` 等)。这在创建自定义输入通道或处理原始输入时可能用到。 **关键特性:** 1. **设备抽象:** `stdin` 是对底层物理输入设备(如串口、Telnet/SSH 虚拟终端、USB CDC ACM 设备)的抽象。VxWorks 启动时通过 `console=` 引导行参数或运行时配置确定默认的控制台设备。 2. **任务阻塞:** 默认情况下,当任务调用 `fgets()`、`scanf()`、`getchar()` 或 `read(STDIN_FILENO, ...)` 从 `stdin` 读取数据时: * 如果输入缓冲区中有数据可用,调用立即返回。 * 如果输入缓冲区为空,则调用任务会被阻塞(挂起),直到有数据到达(用户按键或通过网络连接发送数据)。 * 这是嵌入式实时系统中需要特别注意的地方,长时间阻塞可能会影响其他高优先级任务的执行。在设计时需要评估任务优先级和阻塞时间。 3. **缓冲模式:** VxWorks 的 `stdio` 库通常对 `stdin` 使用**行缓冲(line buffered)** 或**无缓冲(unbuffered)** 模式: * **行缓冲 (`_IONBF` 或 `_IOLBF`):** 这是常见默认设置(尤其是连接到终端时)。输入被缓冲,直到遇到换行符 `'\n'` 或缓冲区满,然后数据才可供读取函数使用。`fgets()` 会感知到这个缓冲。 * **无缓冲 (`_IONBF`):** 使用 `setvbuf(stdin, NULL, _IONBF, 0)` 设置。输入字符立即可供读取函数使用。这在需要即时响应单个按键的场景有用,但会产生更高的系统调用开销。 * **全缓冲 (`_IOFBF`):** 对 `stdin` 很少使用,因为它会等待缓冲区填满才可用,不符合交互式输入预期。 4. **重定向:** VxWorks shell (`cmd`) 支持输入重定向(例如 `myApp < input.txt`),此时应用程序的 `stdin` 将从指定文件读取,而不是控制台。应用程序本身无需修改。 5. **多任务环境:** * **非共享:** `stdin` 本身是一个全局资源。**多个任务同时尝试从 `stdin` 读取可能导致数据竞争和混乱**。需要应用程序设计者通过互斥锁(如 `semMutex`)或其他同步机制来协调对 `stdin` 的访问,确保同一时间只有一个任务在读取。 * **独立流:** 每个任务可以有自己的 `stdin`、`stdout`、`stderr` 流(通过 `taskFd` 系列函数或 `fdOpen()` 创建),这是 VxWorks 的特性之一。但默认的 `stdin` (fd 0) 通常是全局共享的。 6. **EOF 处理:** 当输入通道被关闭(例如 Telnet/SSH 会话断开)时,后续的读取操作将返回 0(表示 EOF)。应用程序应能正确处理这种情况。 7. **控制台驱动特性:** 底层 `consoleDrv` 可能支持行编辑功能(如退格键删除)、历史记录(上下箭头)、特殊字符处理(如 Ctrl+C 发送 `SIGINT`),这些都影响 `stdin` 的行为。可以通过 `ioctl` 或特定于 `tyCo/Drv` 的 API 配置这些特性。 8. **实时性考虑:** 虽然 `stdin` 操作是阻塞的,但 VxWorks 内核的抢占机制保证了高优先级任务不会被长时间阻塞在 I/O 上的低优先级任务所延迟。但设计者仍需合理安排任务优先级和 I/O 等待时间。 **总结与最佳实践:** * **首选 `fgets()`:** 读取行输入时,优先使用 `fgets()` 代替 `scanf()` 或 `gets()`,因为它能安全地限制输入长度,避免缓冲区溢出安全问题。 * **小心阻塞:** 明确意识到读 `stdin` 可能导致任务阻塞。评估这对系统实时性的影响。 * **同步访问:** 在多任务应用中读取全局 `stdin` 时,**必须使用互斥锁**进行保护。 * **考虑缓冲:** 了解默认缓冲模式,必要时使用 `setvbuf()` 调整以满足应用需求(如即时按键响应)。 * **错误处理:** 始终检查函数返回值(如 `read` 的返回值,`fgets` 是否返回 `NULL`)以处理错误或 EOF 条件。 * **输入验证:** 对从 `stdin` 读取的任何数据进行严格的验证和清理,尤其是涉及命令执行或内存操作的场景。 **相关问题** 1. 如何在 VxWorks 7.0 中安全地从 `stdin` 读取密码而不回显输入字符? 2. VxWorks 7.0 中如何配置串口作为默认 `stdin/stdout` 设备? 3. 在多任务 VxWorks 应用中,如何设计一个安全的、非阻塞的命令行接口(CLI)来处理来自 `stdin` 的用户输入? 4. 使用 `ioctl` 如何禁用 VxWorks 控制台输入的行编辑功能(如回显和退格)? 5. VxWorks 7.0 的 `stdin` 是否支持超时(`select` 或 `poll`)?如何实现非阻塞读取?
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值