semm7

VxWorks下采用C++构建Application可以使得程序更加利于维护,利用其提供的STL支持,可以省去大量的底层工作,大大加速软件的开发进度。

1 异常类VxError

首先封装异常类VxError,当程序出现异常时,向外层调用者抛出一个该类的对象,调用者采用try-catch clause捕获该异常对象,进行异常处理。

由于该类针对的是系统运行时产生的异常,故考虑由C++标准异常类中的runtime_error类派生;VxWorks内核采用设置全局变量errno的方式记录系统运行中产生的错误,所以将int ?errNum 作为该类的成员变量,用以记录异常发生时的errno值。源代码如下:

#include?<stdexcept>

#include?"errnoLib.h"

class?VxRunTimeError?:?public?runtime_error?{

protected:

int?errNum;

public:

VxRunTimeError(const?string?msg?=?"")?:?runtime_error(msg),?errNum(errnoGet?())

{

}

int?getErrNum(void)

{

return?errNum;

}

};

2 任务类VxTask

任务类VxTask用以封装VxWorks的task,本来考虑将任务的入口函数作为该类的纯虚成员函数,用户只要在该类的派生类中重载该纯虚函数就能实现自己的VxWorks task,但由于taskSpawn()的入口函数的参数类型是FUNCPTR(typedef ?int (*FUNCPTR) (...)),而指向VxTask类成员函数的指针类型为int (VxTask:: *ptr)(…),编译器不支持这两种类型之间的强制类型转换,所以只能换种思路——用一个名为Runnable的类专门封装task的入口函数,同时提供一个静态成员函数完成对该入口函数的调用,而该静态成员函数地址可以转换成FUNCPTR类型,供taskSpawn()调用。在VxTask类中实现关于task的系统调用。部分源代码如下:

class?Runnable?{

protected:

virtual?void?run()?=?0;

public:

static?void?entry(Runnable?*?Run)

{

Run->run();

}

virtual?~Runnable()

{

}

};

class?VxTask?{

protected:

char?*name;

int?tid;

public:

VxTask(char*?Name,?int?Arg1?,?FUNCPTR?Entry?=?(FUNCPTR)Runnable::entry,?int?Pri?=?150,?int?Opt?=?VX_FP_TASK,?int?StackSize?=?2000000,

int?Arg2?=?0,?int?Arg3?=?0,?int?Arg4?=?0,?int?Arg5?=?0,?int?Arg6?=?0,?int?Arg7?=?0,?int?Arg8?=?0,?int?Arg9?=?0,?int?Arg10?=?0)?:?name(Name)

{

if(Entry?==?NULL)?{

throw(VxRunTimeError("Task?Creat?Fail:?Entry?Can't?be?NULL!"));

}

tid=taskSpawn(Name,Pri,Opt,StackSize,Entry,Arg1,Arg2,?Arg3,Arg4,Arg5,Arg6,Arg7,Arg8,Arg9,Arg10);

if(tid?==?ERROR)?{

throw(VxRunTimeError("Task?Spawn?Fail!"));

}

}

~VxTask()

{

if(taskDelete(tid)?==?ERROR)?{

throw(VxRunTimeError("Task?Delete?Error:?Task?delete?fail!"));

}

}

void?suspend()

{

if(taskSuspend(tid)?==?ERROR)?{

throw(VxRunTimeError("Task?Suspend?Error:?Task?suspend?fail!"));

}

}

void?resume()

{

if(taskResume(tid)?==?ERROR)?{

throw(VxRunTimeError("Task?Resume?Error:?Task?resume?fail!"));

}

}

int?getTid()

{

return?tid;

}

};

使用时首先派生Runnable的子类,重载其run()成员函数,然后将该子类的对象指针赋给VxTask的构造函数,用户task就跑起来了:

class?MyRunnable?:?public?Runnable

{

void?run()?{

while(1)?{

cout<<"Hello?VxWorks?Task?World!"<<endl;

taskDelay(sysClkRateGet());

}

}

};

void?myMain()

{

MyRunnable?myRun;

VxTask?task(“tMyRun”,?(int)&myRun);

While(1)?{

taskDelay(sysClkRateGet());

}

}

在shell中sp myMain可以看到预期效果,但如果myMain()中去掉最后的while(1)循环,就只会在输出窗口中看一次Hello VxWorks Task World!输出。Why?(提示:VxTask的析构函数!)

3 中断类VxInt

中断类VxInt与VxTask类似,同样用Runnable的派生类封装入口函数,VxInt类实现中断系统调用:

typedefvoid?(**VOIDFUNCPTRPTR)?(...);

class?VxInt?{

protected:

int?intNum;

public:

VxInt(int?IntNum,?int?Arg?=?0,?VOIDFUNCPTR?Entry?=?(VOIDFUNCPTR)Runnable::entry)?:?intNum(IntNum)

{

if(intConnect((VOIDFUNCPTRPTR)INUM_TO_IVEC(intNum),?Entry,?Arg)?==?ERROR)?{

throw(VxRunTimeError("Interrupt?Connect?Fail!"));

}

}

};

与task不同,中断服务程序(ISR)中不能调用可能被阻塞的函数,这点需要在重载Runnable派生类中的run()成员函数时引起注意。

4 看门狗类 VxWatchDog

VxWorks中的看门狗实际上是利用系统时钟中断来定时执行某个函数的,所以被看门狗执行的函数是运行在中断的上下文(Context)中,而不是任务的上下文中,故该函数中也不能调用带有阻塞功能的函数。所以VxWatchDog的实现与中断类VxInt类似:

class?VxWatchDog?{

WDOG_ID?id;

int?delay;

public:

VxWatchDog(int?Delay,?Runnable?*EntryObj)?:?delay(Delay)

{

id?=?wdCreate();

if(id?==?NULL)?{

throw(VxRunTimeError("Watch?Dog?Creat?Fail!"));

}

if(wdStart(id,?delay,?(FUNCPTR)Runnable::entry,(int)EntryObj)?!=?OK)?{

throw(VxRunTimeError("Watch?Dog?Start?Fail!"));

}

}

void?cancel()

{

if(wdCancel(id)?!=?OK)?{

throw(VxRunTimeError("Watch?Dog?Cancel?Fail!"));

}

}

WDOG_ID?getId()

{

return(id);

}

~VxWatchDog()

{

if(wdDelete(id)?!=?OK)?{

throw(VxRunTimeError("Watch?Dog?Delete?Fail!"));

}

}

};

wdStart(WDOG_ID Id, int Delay, FUNCPTR Ptr, int Para )只会让函数Ptr在延时Delay ticks后执行一次,要周期性地执行Ptr,需要在Ptr中递归调用wdStart()。那能否这样实现呢:

class?WdRun?:?public?Runnable?{

protected:

void?run()?{

logMsg("Hello?Watch?Dog?World!",0,0,0,0,0,0);

VxWatchDog?wtDog(sysClkRateGet(),?this);

}

};

上述程序试图在入口函数中产生一个VxWatchDog类的对象,并用this指针初始化该对象,以期达到每秒钟执行一次入口函数的目的。但是不要忘了该入口函数是运行在中断的上下文中的,不允许动态地产生或删除对象,所以采用这种方法实现周期性执行作业并不可行。

为了在入口函数中调用wdStart(),且要避免动态地生成VxWatchDog对象,需要在Runnable派生类的成员变量中包含一个VxWatchDog指针,通过该指针调用所指对象的wdStart()。为此,需要在VxWatchDog类中增加成员函数:

VxWatchDog?::VxWatchDog(int?Delay)?:?id(wdCreate()),?delay(Delay)

{

if(id?==?NULL)?{

throw(VxRunTimeError("Watch?Dog?Creat?Fail!"));

}

}

void?VxWatchDog?::start(Runnable?*EntryObj)

{

if(wdStart(id,?delay,?(FUNCPTR)Runnable::entry,?(int)EntryObj)?!=?OK)?{

throw(VxRunTimeError("Watch?Dog?Start?Fail!"));

}

}

class?WdRun?:?public?Runnable?{

protected:

VxWatchDog?*dog;

virtual?void?run()?{

logMsg("Hello?Watch?Dog?World!",0,0,0,0,0,0);

dog->start(this);

}

public:

WdRun(VxWatchDog?*Dog)?:?dog(Dog)

{

}

};

void?myMain()

{

VxWatchDog?wtDog(sysClkRateGet());

WdRun?run(&wtDog);

wtDog.start(&run);

while(1)?{

taskDelay(sysClkRateGet());

cout<<"In?Main!"<<endl;

}

}

在shell中输入sp myMain,可以看到预期输出。

5 信号量类 VxSem

VxWorks信号量包括互斥信号量、二进制信号量和计数信号量,这三种信号量除了创建时调用各自的创建函数,其它操作具有相同的接口,所以考虑采用VxSem类作为信号量基类,提供统一的信号量操作接口,VxSemM、VxSemB、VxSemC三个派生类分别封装了三种信号量的创建函数:

class?VxSem?{

protected:

SEM_ID?id;

public:

VxSem(SEM_ID?Id)?:?id(Id)

{

}

virtual?~VxSem()

{

if(semDelete(id)?==?ERROR)?{

throw(VxRunTimeError("Semaphore?Delete?Fail!"));

}

}

void?take(int?TimeOut?=?WAIT_FOREVER)

{

if(semTake(id,WAIT_FOREVER)?==?ERROR)?{

throw(VxRunTimeError("Semaphore?Take?Fail!"));

}

}

void?give()

{

if(semGive(id)?==?ERROR)?{

throw(VxRunTimeError("Semaphore?Give?Fail!"));

}

}

void?flush()

{

if(semFlush(id)?==?ERROR)?{

throw(VxRunTimeError("Semaphore?Flush?Fail!"));

}

}

SEM_ID?getId()

{

return?id;

}

};

class?VxSemB?:?public?VxSem?{

public:

VxSemB(int?Opts?=?SEM_Q_FIFO,?SEM_B_STATE?State?=?SEM_EMPTY)?:?VxSem(semBCreate?(Opts,?State))

{

if(id?==?0)?{

throw(VxRunTimeError("Binary?Semaphore?Creat?Fail!"));

}

}

};

class?VxSemM?:?public?VxSem?{

public:

VxSemM(int?Opts?=?SEM_Q_PRIORITY?|?SEM_INVERSION_SAFE?|?SEM_DELETE_SAFE)?:?VxSem(semMCreate?(Opts))

{

if(id?==?0)?{

throw(VxRunTimeError("Mutual-exclusion?Semaphore?Creat?Fail!"));

}

}

};

class?VxSemC?:?public?VxSem?{

public:

VxSemC(int?Opts,?int?Cnt)?:?VxSem(semCCreate?(Opts,?Cnt))

{

if(id?==?0)?{

throw(VxRunTimeError("Counting?Semaphore?Creat?Fail!"));

}

}

};