1 引言

多媒体通信技术的发展为信息的获取和传输提供了丰富的手段,视频数据是其中不可缺少的重要组成部分,而视频数据的获取离不开视频采集系统。目前,视频采集系统的应用极为广泛,许多产品和设施,例如远程监控、可视电话、会议电视等等,都需要采集视频信息。而且,随着PC机的普及,人们可以直接利用PC机进行视频采集,采集到的视频数据经过处理后保存在本地或者发送到远方。由于视频的采集、处理和传输都在一台PC机上完成,因此可以大大降低系统的复杂度和价格。

我们设计的视频采集系统是基于Intel x86平台和实时操作系统VxWorks,由视频采集卡和驱动程序两部分组成,如图1所示。视频采集卡完成视频数据采集和格式转换,驱动程序在系统启动时对硬件进行初始化,在系统启动之后实现硬件和应用软件之间的数据交互。考虑到视频的数据量极大,视频采集卡通过PCI高速总线与计算机相连。

VxWorks Video Framework

2 视频采集卡的设计

为了将由摄像头输入的模拟视频转换为计算机能够接受和处理的数字视频,需要经过模数转换、同步提取、亮色分离等多个步骤。而为了将数字视频传送到PC机的内存中,还需要一定数量的FIFO、总线接口和相应的控制逻辑。这原本是一个比较复杂的过程,但是随着半导体技术的发展,各半导体生产厂家通过不断创新和改进,目前已经能够在单个芯片上实现所有这些功能。Conexant公司的Bt848就是这样的一种芯片,图2给出了其功能框图。

VxWorks Video BT848

对于在PCI总线上进行NTSC/PAL/SECAM视频捕获的应用来说,Bt848是一种完整的低价格解决方案。作为一种总线主控设备,Bt848不需要任何本地缓存来存储视频像素数据,这样就极大地降低了硬件价格。Bt848能够充分利用基于PCI总线的系统的高带宽和固有的多媒体功能,并且能够与其他多媒体设备实现互操作,这样就能够以模块的方式在系统中添加视频采集和叠加功能,而花费甚少。Bt848的使用与PCI系统总线的拓扑结构无关,可以用于各种系统总线的组织结构,既可以直接集成在主板上,也可以作成插卡插在PCI总线插槽内。

Bt848的主要特点是:与PCI 2.1 规范全兼容,拥有辅助的GPIO数据端口和视频数据端口,支持的图像分辨率高达768×576,支持复杂的裁剪功能,零等待状态的PCI突发写操作,支持场/帧屏蔽以减少带宽,在输出方面支持多种YCbCr和RGB像素格式,支持NTSC/SECAM/PAL模拟输入,可以使用垂直/水平方面的插值滤波将图像尺寸缩小到图标大小,具有多个复合和S视频输入,支持奇偶场不同的目的地址,支持奇偶场不同的颜色空间/缩放因子,支持225个颜色调色板的视频映射,具有用于图文电视的VBI视频捕获功能。这些特点使Bt848适用于PC电视、桌面可视电话、运动视频捕获、静止图像采集和VBI数据服务等应用领域。

Bt848高度集成的结构使其外围电路极其简单,也便于在同一块插卡上增加更多的功能,例如视频数据加密。视频采集卡的结构如图3所示。一块Bt848最多支持4路模拟视频输入,其中3路是复合视频信号,1路是S视频信号。4路视频输入在Bt848内部完成复用。Bt848通过内部的PCI接口直接与PCI总线相连。单片机通过FIFO与Bt848的GPIO端口相连,单片机软件与主机上的软件一起实现视频采集系统的加密。控制逻辑控制Bt848和FIFO的时序,同步PCI总线、Bt848与单片机的操作。

VxWorks Video Acquisition

3 驱动程序的编写

应用程序必须通过驱动程序才能与硬件进行数据通信,而驱动程序的编写又是与操作系统密切相关的。本系统所使用的操作系统是实时操作系统VxWorks。

刘玉宾

关键词:VxWorks,嵌入式TCP/IP协议栈,增强型网络驱动,自动切换,冗余备份

引言

随着网络技术的成熟,具有价格低廉、连接方便等优点的以太网己成为各种控制系统接口互联的主要媒介,它作为一种通用网络数据通讯系统,在全球的计算机网络领域已经得到了广泛的应用。把这种成熟、高速、抗干扰能力强的通讯技术应用在实时信息系统,其具有组建成本低、开发手段多样、物理协议及数据协议完善、传输速率高等明显的优越性。而实时信息系统不但要求信息传输速度快,抗干扰能力强,还要求网络具有高稳定性和高可靠性。在网络局部故障或受损时,全系统不至于瘫痪失效。但是,目前各种网络通讯设备与技术的发展都已经基本趋于稳定,要仅仅通过提高任何一种设备自身的可靠性从而提高整个系统的可靠性是难以实现的。采用冗余的思想设计一种冗余网络信息系统来提高整个系统的稳定性、可靠性是切实可行的。

本控制系统使用VxWorks系统提供的功能强大的TCP/IP协议栈实现在双冗余以太网上的高速信息传递功能。本论文针对双冗余以太网在VxWorks下的驱动开发及热切换技术进行了深入的研究,并提出了一个切实可行的解决方案。经过实验验证,很好的解决了这一技术问题。

1 VxWorks下的网络协议栈、MUX接口及END驱动程序

1.1 网络协议栈

VxWorks中的网络协议栈叫作SENS(Scalable Enhanced Network Stack),即可裁减增强网络协议栈。SENS是基于4.4BSD TCP/IP协议栈发展而来的,包含了许多4.4BSD TCP/IP协议栈没有的协议;而且SENS在实现一些协议功能时增加了许多新特性,如在IP协议实现时增加了多播功能。SENS协议栈层次如图1-1所示。

VxWorks Network Redundant

图1-1 SENS网络协议栈

SENS的基本特征和传统的TCP/IP网络协议栈相似,但从图1-1中可以看出SENS最大的特点是在数据链路层和网络协议层之间多了MUX层。在SENS中,网络接口的驱动程序是叫作END(Enhanced Network Driver),即增强型网络驱动程序,它处于数据链路层。IP层和TCP/UDP层合称为网络协议层。在数据链路层和网络协议层之间有应用程序接口(API),这个接口在SENS中叫作MUX(Multiplexer)接口。

1.2 MUX接口

MUX接口如图1-2所示,在网络协议层VxWorks典型地使用TCP/IP协议(也支持其它协议);在数据链路层典型地使用Ethernet,也支持其它数据传输的物理媒体,例如远距离连接使用的串行线路接入方式,如PPP等。但是,无论使用什么物理媒体,网络接口驱动都要用到MUX去与网络协议层通信(数据链路层是一个抽象概念,网络接口驱动程序则是这种抽象概念所描述的功能实现的代码)。

 
 
#include "vxWorks.h" 
#include "stdio.h" 
#include "inetLib.h" 
#include "string.h" 
#include "stdlib.h" 
#include "sockLib.h" 
#include "ioLib.h" 
 
/*本地ip地址*/ 
#define LOCAL_IP_ADDR3 "192.168.1.10" 
#define LOCAL_PORT_NUM3 5500 
 
/*组播ip地址*/ 
#define REMOTE_IP_ADDR3 "224.2.2.2" 
#define REMOTE_PORT_NUM3 5000 
 
int tid10,tid11; 
 
int sockFd3; 
 
int sockAddrLen3; 
 
struct sockaddr_in local3; 
 
struct sockaddr_in remote3; 
 
struct ip_mreq mcAddr; 
 
struct sockaddr_in from3; 
 
char sendBuf3[100]={"hello vxworks,I am WelBet..ZuBo!!!"},recvBuf3[100]; 
 
/********************************************************************************/ 
STATUS udp_zubo_init(void) 
{ 
 
    if((sockFd3=socket(AF_INET,SOCK_DGRAM,0))==ERROR) /*创建套接字*/ 
    { 
        printf("OPEN SOCKET failed!!\n");  
        return ERROR; 
    } 
     logMsg("sockfd3 is: %d\n",sockFd3); 
 
     sockAddrLen3=sizeof(struct sockaddr_in); 
 
     local3.sin_family=AF_INET; 
     local3.sin_len=(u_char)sockAddrLen3; 
     local3.sin_port=htons(LOCAL_PORT_NUM3); 
     local3.sin_addr.s_addr=INADDR_ANY; 
  
     remote3.sin_family=AF_INET; 
     remote3.sin_len=(u_char)sockAddrLen3; 
     remote3.sin_port=htons(REMOTE_PORT_NUM3); 
     remote3.sin_addr.s_addr=inet_addr(REMOTE_IP_ADDR3);  
      
     if((bind(sockFd3,(struct sockaddr *)&local3,sockAddrLen3))==ERROR) 
        { 
            close(sockFd3);  
            printf("bind SOCKET failed!!\n"); 
            return ERROR;  
        }  
     
    /******** 设置组播路由 非常重要 **********/ 
    mRouteAdd(REMOTE_IP_ADDR3,LOCAL_IP_ADDR3,0xffffff00,0,0); 
     /**** 设定并加入多组播 *****/ 
    mcAddr.imr_multiaddr.s_addr=inet_addr(REMOTE_IP_ADDR3);  
    mcAddr.imr_interface.s_addr=inet_addr(LOCAL_IP_ADDR3);  
 
    if(setsockopt(sockFd3,IPPROTO_IP,IP_ADD_MEMBERSHIP,(char*)&mcAddr,sizeof(struct ip_mreq))==ERROR) 
    { 
        close(sockFd3); 
        printf("add group failed\n"); 
        return ERROR; 
    } 
     
    return OK; 
} 
 
/*******************************************************************************/ 
void task10(void) 
{ 
    while(1) 
    {  
    sendto(sockFd3,sendBuf3,50,0,(struct sockaddr *)&remote3,sockAddrLen3); /*组播发送数据*/ 
    taskDelay(100); 
    } 
} 
 
void task11(void) 
{ 
    int fromLen4; 
    /*sockAddrLen4=sizeof(from3);*/ 
    while(1) 
    {  
    logMsg("zubo \n"); 
    recvfrom(sockFd3,recvBuf3,50,0,(struct sockaddr *)&from3,&fromLen4); /*组播接受数据*/ 
    logMsg("recv data is:%s..time is:%d\n",recvBuf3,tickGet()); 
    } 
} 
 
int main3(void) 
{ 
    udp_zubo_init(); 
 
    tid10=taskSpawn("task10",100,0,1024,(FUNCPTR)task10,0,0,0,0,0,0,0,0,0,0); 
    tid11=taskSpawn("task11",105,0,1024,(FUNCPTR)task11,0,0,0,0,0,0,0,0,0,0); 
    return 1; 
} 
 

摘要:由于我国的空间技术的迅速发展,航天嵌入式系统的复杂性急剧增加。在航天领域要求对嵌入式操作系统vxWorks进行剪裁工作以适应航天设计的要求,而剪裁掉文件系统的VxWorks操作系统存在地面不能对星上的事件进行有效干预的问题。文中在“龙芯”计算机平台上通过对VxWorks操作系统进行配置,设计了一种可在轨编程的方案,并针对其中的出现的修改后的函数中全局变量和调用函数的链接地址发生变化的问题提出了解决方案并完成了软件实现该功能。文中CPU采用wh1770,通过修改原被调用函数的初始代码实现对于新函数的调用,并针对全局变量以及调用函数在更新函数中链接地址发生变化设计了在轨更新接口函数和更新代码提取工具,从而实现函数的在轨更新,给出了部分设计流程图以及代码提取工具的测试结果。测试结果显示该工具实现了设计目的,在航天工程领域具备一定的利用价值。

在航天领域,由于软件设计的复杂程序越来越高,尽管软件在研制过程中已发现和解决了大量软件问题,但难免在轨飞行时仍发现少量软件存在缺陷;同时某些需要载荷根据在轨飞行应用情况调整某些算法。基于以上等方面原因越来越需要软件具有在轨更新能力。一方面可保证航天应用的可靠运行,另一方面可提高软件维修性。同时由于嵌入式操作系统为了符合航天领域的应用需要进行剪裁,本文所采用的基于“龙芯”计算机平台的vxWorks操作系统为适应航天领域的需求剪裁掉了文件系统,所以无法使用动态加载模块的方式实现函数的在轨更新,需要使用新的方法来实现在轨编程。同时更新函数中如果有函数调用则其调用的函数和全局变量的链接地址可能会发生变化,需要对函数和全局变量的调用指令做出修改。

结合这些背景,本文提出了针对“龙芯”体系结构的函数在轨更新方案以及设计了可调整调用指令的更新代码提取工具,以满足软件具有在轨更新能力的航天任务要求。

1 函数在轨更新方案简介

文中基于“龙芯”平台的VxWorks操作系统由于要符合航天系统操作系统尽量小的要求,剪裁掉了文件系统,所以不能直接使用动态加载模块的方式实现函数在轨更新,本文的在轨更新基于RAM进行,系统软件在RAM中保留了一片区域,专用来保存在轨更新注入的函数代码。龙芯计算机平台下使用“JAL指令+函数名”的方式完成函数调用,在链接时,函数名会被链接器替换为函数的地址。JAL指令在执行时,会将自身地址写入到寄存器ra中。通常JAL指令之后会跟延迟槽,因此返回地址为原函数调用指令地址+8。

若将待更新函数的前几条指令进行替换,修改为“JAL指令+新函数的地址”,这样调用该函数后,替换的JAL指令会调用新的函数。从新函数返回后,将回到原函数的代码继续执行。因此需要将原函数第三条指令修改为返回指令,返回到原函数的调用处。

由于JAL指令调用新函数时,会当前地址写入寄存器ra中,故会将原函数的返回地址(之前寄存器ra中的内容)覆盖掉,因此在JAL指令之前,须将寄存器ra中的内容保存到堆栈中。在从新函数返回后,接着将堆栈中的原函数返回地址写回到ra中,并通过返回指令回到原函数调用指令地址+8处,即回到原函数调用处的下一指令。

VxWorks的任务有优先级的概念,其任务调度也是基于优先级考虑的,是抢占式的,VxWorks的任务有256个等级,0—255,数目越小表示优先级越高。高优先级的任务可以打断低优先级的任务而抢先执行,只有在高优先级的任务执行完后,低优先级的任务才可以执行。其调度算法有两种:完全抢占式的和循环分配式的。完全抢占式的是除了高优先级任务可以打断低优先级任务外,在相同优先级的任务之间,不可以相互打断,并且同优先级任务不是同时执行的,只有等该任务执行完后,与其相同优先级的任务才可以执行;循环分配式除了具有抢占功能之外,相同优先级的任务是可以同时执行的,即系统时间片是在它们之间平均分配的,这样,相同优先级的任务可以同时执行。可以调用kernelTimeSlice()函数来设定该调度方式,并且参数是相同优先级任务执行的时间片。

VxWorks中任务具有很多种状态,如下表所示:

状态 描述
READY 此任务状态在等待执行
PEND 此任务状态是由于一些资源不可用而被阻塞
DELAY 此任务状态是休眠一段时间
SUSPEND 此任务状态是挂起
BREAK 此任务状态是停止(暂停),通常是在任务中设置了断点。
各种状态的组合 详细请见原文档