A. 如何在VMWare上安装VxWorks操作系统
准备工作
我们假设您有一台普通配置的PC机,并安装了Windows2000操作系统。其次您需要安装Tornado 2.2 for pcPentium开发环境。缺省安装的Tornado 2.2 for pcPentium可能不包括pcPentium的BSP组件,但该组件可以从风河公司(Windriver)的网站免费下载。
我们将在下文以WIND_BASE引用Tornado的安装路径。
其次是要安装VMWare软件,这里我们使用4.0的版本。如果您还没有该软件,也可以从VMWare的网站下载试用版。
最后,由于Tornado自带的PC-NET网卡驱动有问题,所以需要下载AMD的PC-NET网卡的VxWorks系统驱动,可以从AMD网站免费下载。
一张1.44M的软盘,用于制作系统引导盘。
准备并安装好以上软件后,就可以开始下一步的工作了。
开始安装
编译网卡驱动程序
VMWare为运行于其上的操作系统提供虚拟网卡支持,该网卡类型即为AMD的PC-NET。实际上,在Tornado开发包中已经包含了该类型网卡的驱动程序,但经过测试,对于VMWare无法正常工作,所以您需要从AMD的网站下载最新的驱动程序。
下载得到的是一个可执行的安装程序,运行该程序将得到一个压缩包和一个帮助文件,按照该帮助的要求,将压缩包直接释放到Tornado目录下。如果提示是否允许覆盖文件,则选择允许。
此后按如下步骤完成驱动程序的编译和替换:
打开一个控制台窗口,运行批处理程序:$(WIND_BASE)\host\x86-win32\bin\ torVars.bat;
重新定位到$(WIND_BASE)\target\src\drv\end目录,运行:
make CPU=PENTIUM tool=gnu ln97xend.o
其间会产生一些警告,但这不会影响我们的工作。
重新定位到$(WIND_BASE)\target\lib\pentium\PENTIUM\common目录,并将上一步生成的文件ln97xend.o复制到此目录下。备份此目录下的文件libdrv.a;
运行命令arpentium -d libdrv.a ln97xEnd.o,删除libdrv.a中原有的ln97xEnd模块,然后再运行命令:
arpentium -ra iOlicomEnd.o libdrv.a ln97xEnd.o
将我们刚刚创建的新模块添加进去。
到此有关网卡驱动的设置就完成了。注意不要关闭这个窗口,后面还要使用。修改配置文件
在这一节中,我们要修改编译VxWorks的配置头文件Config.h中定义的一些参数,使编译出来的系统引导程序和VxWorks的映象符合我们的要求;同时还要修改sysLn97xEnd.c这个文件,以使系统的网络功能正常运行。
定位目录到$(WIND_BASE)\target\config\pcPentium并打开该目录下Config.h文件;
我们首先要修改VxWorks的启动参数。先查找到定义DEFAULT_BOOT_LINE宏的地方,修改预处理条件CPU == PENTIUM分支下的定义如下:
#define DEFAULT_BOOT_LINE \
"lnPci(0,0)your_host_name:d:\\vxWorks h=192.168.80.169 e=192.168.80.254 u=target pw=vxworks tn=target"
其中:
lnPci(0,0)指定了使用第0个网卡和第0个处理器,lnPci这个标识会因为使用的驱动程序不同而有所不同,但这里用lnPci就可以了;
your_host_name指定您的主机的名字,使用Windows系统的主机名就可以;
d:\\vxWorks指定了VxWorks映象下载的完整路径;
h=192.168.80.169是主机的IP地址,就是您当前正在使用的系统的IP地址;
e=192.168.80.254是目标机的IP地址,也就是未来VxWorks操作系统的IP地址,您只要任意指定一个不冲突的IP地址即可,这里我们假设您的目标机IP地址和主机IP地址在同一个网段内;
u=target指定了FTP服务器的用户名,这个FTP就是用来下载VxWorks映象的,后面还会提到;
pw=vxwroks是用户名对应的口令;
tn=target指定目标机的名字,任意指定即可;
您可以参考Tornado自带的手册以获取更多信息;
下面我们要指定使用什么样的网卡驱动程序。首先查找“Network driver options”这段文字,之后您可以看到在该注释后面定义了一系列的有关网卡驱动的宏定义。注意保证INCLUDE_END和INCLUDE_LN_97X_END这两个宏处于定义状态(define),其他的宏都处于未定义状态(undef);
缺省情况下,VxWorks系统是不接受外部输入设备(如键盘)的输入,也不向外部输出设备(如显示器)输出数据。为了便于调试,我们必须改变它的这种缺省状态。我们查找定位宏INCLUDE_PC_CONSOLE,然后保证其处于定义状态(define)即可;
到此为止,对config.h文件的修改就完成了,保存修改,然后再打开同一目录下的sysLn97xEnd.c文件;
这一步修改的目的是要使网卡正常工作。我们先定位到“memory-mapped IO base”这段文字,然后将其前面的参数由pciRsrc[endUnit].bar[1]修改为NONE,这样就可以了。最后别忘了保存。
到此为止,全部的修改工作都完成了,下一步就可以开始编译连接了。编译程序
这一节我们要编译生成bootrom引导程序和VxWorks运行映象。
打开您的Tornado开发工具,在Build菜单下选择Build Boot ROM,弹出如下对话框:
在BSP列表中选择pcPentium,而在Image to build列表中分别选择bootrom和gnu。完成选择后,点击OK按钮就开始引导程序的编译了。编译产生的文件bootrom将保存在$(WIND_BASE)\target\config\pcPentium目录下。
编译生成bootrom后,还要创建一个VxWorks映象(image),也就是VxWorks操作系统本身的代码。
创建一个“bootable VxWorks image”的工程;
选择您需要的VxWorks组件。这一步是可选的,如果您只想使用缺省的配置,那根本就不需要这一步;但如果您想使用额外的组件,例如,您可能想通过telnet连接VxWorks系统,这时就需要在Workspace窗口的VxWorks选项卡中选择telnet sever对应的组件,如下图:
在这个例子中我们选择了两个重要的组件:Telnet server 和 Target shell 。前者使我们可以通过Telnet协议登录到VxWorks操作系统中;后者则可以让我们通过命令行控制VxWorks系统。
完成选择后,即可开始编译程序;
到此我们已经生成了VxWorks的系统引导程序和运行时的代码映象。这里还要提醒读者,在您每次修改完系统的配置信息(如:config.h)后,都要重新创建一个工程来编译VxWorks映象,以免出现代码不一致的问题。
将生成的名为“vxworks”的文件复制到D盘根目录下。这个路径是由上面我们所设置的DEFAULT_BOOT_LINE宏中的路径参数决定的,必须保持二者一致。
制作引导磁盘
现在开始制作VxWorks系统引导磁盘,用于引导装载VxWorks运行映象。
我们回到“编译网卡驱动程序”一节中所打开的控制台窗口,定位目录到$(WIND_BASE)\target\config\pcPentium,插入您已经格式化好的软盘,然后运行:
mkboot a: bootrom
该命令将在软盘上建立VxWorks系统引导分区,并将引导程序复制到软盘上。
这里再额外向您介绍一个虚拟软盘的工具:RamDiskNT,它可以在内存中建立一个虚拟的软盘,对于提高VxWorks的启动速度有很大帮助。配置FTP服务器
这里的FTP服务器用于在系统成功引导后,下载VxWorks的运行时映象。我们这里使用Tornado开发环境自带的FTP服务器。
打开Tornado FTP Server,选择“Security”菜单下的“Users/Rights”子菜单,弹出如下对话框:
当User Name为“target”时,修改“Home Directory”为D盘根目录(此路径由上面的DEFAULT_BOOT_LINE参数决定),同时修改口令为“vxworks”,最后点击“Done”按钮完成修改;
为了便于调试,我们还要打开FTP Server的日志功能。选择“Logging”菜单下的“Logging Options”子菜单,弹出如下对话框,其中除了“Winsock Calls”外,让其他选项全都处于开启状态。
保持FTP Server窗口处于打开状态(这样FTP服务器就处于运行状态)。
创建VxWorks系统
打开您的VMWare Workstation,在File->New菜单下选择创建一个新的虚拟机(Virtual Machine),按照其向导帮助,完成虚拟机的配置。在选择操作系统类型时,选择“Other”,其余选项均使用缺省值就可以了。
完成以上配置后,点击右侧窗口中的“Start this virtual machine”,系统即开始引导运行,如下图所示:
在引导过程中,您会遇到一个7秒钟的等待,以决定是使用缺省的引导参数,还是手动输入引导参数。这里我们选择前者,所以不需要做任何工作。
成功引导后,系统会自动从FTP Server下载映象,并开始运行,得到如下画面:
到此,我们已经成功的在VMWare上安装了VxWorks操作系统。
需要注意的是,上面的画面会因为选择组件的不同而略微有所不同(例如,如果您没有选择target shell,就不会出现命令行提示符),但一般不会影响后续操作。
配置联机调试环境
装好系统后,您肯定还希望将自己编写的应用程序下载到目标机进行调试,下面我们就完成这一部分的配置工作。
打开您的Tornado开发环境,选择“Tools->Target Server->Configure”菜单,弹出如下对话框:
在“Description”中任意填写一个名字,这里是“net00”;在“Available Back”中选择“wdbrpc”,并在下面的IP地址框中填写目标机的IP地址,这里是“192.168.80.254”(由DEFAULT_BOOT_LINE参数决定);将“Target Server Properties”下拉框更改至“Core File and Symbols”,并在“File Path”一项中选择您的映象的完整路径,这里是“D:\vxWorks”(由DEFAULT_BOOT_LINE参数决定)。
完成以上两项配置,点击“Launch”按钮,就可以启动Target Server了。
再回到Tornado开发环境,在工具条上的Target Server下拉框列表中选择“192.168.80.254@your_host_name”。这时您会发现工具条中一些原先处于“禁用”状态的工具按钮,现在都已经处于“激活”状态了。
现在您就可以开始联机调试您的VxWorks应用程序了。
B. 为什么vxworks系统可以通过shell直接调用c函数而linux系统不能
系统调用是程序的事情
shell是人机接口,是你输入命令的地。
这两个完全无关。
你在shell里面输入命令,shell会根据你的命令执行程序,
执行的程序有可能调用系统的功能。
但是执行系统功能的指令,并不一定是通过shell发出的,
通过shell发出的命令也不一定会执行系统调用。
C. 如何在我现在用的pc机上安装Vxworks系统,我现在用的pc机是windows xp系统。并且要两个系统并存。
你要在启动的时候看见选择操作系统的菜单,我觉得可以用LILO之类的Linux操作系统提供的BootLoader软件弄,但是这个真的没有意义。因为Vxwork启动之后只有命令行,人机界面一点也不友好(因为VxWorks不是桌面操作系统,也不是干这个用的),操作系统配置不当的话,启动之后连Shell命令行也没有。
建议你不要直接安装,还使用虚拟机玩吧。上“Tony嵌入式论坛”上面去找吧,在PC上面玩VxWorks有很多文章。
D. Vxworks 网络实时调试
总结的vxworks常用调试命令,学习vxworks这些东西是必须的。 1.与任务相关的命令 sp ,[arg1],...,[arg9] -启动任务,最多接受9个参数,默认的优先级100、堆栈20000字节 period n,,[arg1],...,[arg8] -创建一个周期调用的任务,周期为n秒,最多接受8个参数 repeat m,,[arg1],...,[arg8] -创建一个反复调用的任务,调用次数为m,m=0时永久调用,最多也是8个参数 ts tidX -挂起任务 tr tidX -恢复挂起的任务 td tidX -删除任务 i tidX -显示任务基本信息,参数为0时显示全部任务 ti tidX -显示任务详细信息,包括寄存器、堆栈等 tt tidX -显示任务的函数调用关系 checkStack tidX -显示任务堆栈使用的历史统计,参数为0时显示全部任务 [其中tidX可以为任务ID 也可以为任务名] 2、系统信息 lkup ["string"] -在系统符号表中查找并列出含有"string"字符的函数及全局变量,有两个特殊参数: 0,给出符号表统计;""(空字符串),列出全部符号 lkAddr addr -显示addr地址附近的符号表 l addr,[n] -显示addr地址开始的n条指令的反汇编,n省略时默认为10条指令 h [n] -n为0时列出最近执行的shell命令,默认20条;n非0时,设定shell记录的历史命令的数目 d [addr,[number],[width]] -显示addr地址开始的number个单元的内容,width定制每个单元的宽度,可以是1、2、4、8 m addr,[width] -按width宽度修改addr地址的内容,width可以是1、2、4、8 memShow 1 -显示系统分区上空闲和已分配空间的总数等 printErrno value -打印系统定义的错误码的宏 3、与网络相关的命令 ifShow ["ifname"] - show info about network interfaces inetstatShow - show all Internet protocol sockets tcpstatShow - show statistics for TCP udpstatShow - show statistics for UDP ipstatShow - show statistics for IP icmpstatShow - show statistics for ICMP arpShow - show a list of known ARP entries mbufShow - show network stack data pool statistics netStackSysPoolShow - show network stack system pool statistics routeShow - display all IP routes (summary information) mRouteShow - display all IP routes (verbose information) routestatShow - display routing statistics routeAdd "destaddr","gateaddr" - add route to route table routeDelete "destaddr","gateaddr" - delete route from route table 说明:上述大多数命令都可以在help、netHelp中查到
E. 关于VxWorks系统调用,有没有封装好的C++库
VxWorks下采用C++构建Application可以使得程序更加利于维护,利用其提供的STL支持,可以省去大量的底层工作,大大加速软件的开发进度。
1 异常类VxError
首先封装异常类VxError,当程序出现异常时,向外层调用者抛出一个该类的对象,调用者采用try-catch clause捕获该异常对象,进行异常处理。
由于该类针对的是系统运行时产生的异常,故考虑由C++标准异常类中的runtime_error类派生;VxWorks内核采用设置全局变量errno的方式记录系统运行中产生的错误,所以将int errNum 作为该类的成员变量,用以记录异常发生时的errno值。源代码如下:
#include<stdexcept>
#include"errnoLib.h"
classVxRunTimeError:publicruntime_error{
protected:
interrNum;
public:
VxRunTimeError(conststringmsg=""):runtime_error(msg),errNum(errnoGet())
{
}
intgetErrNum(void)
{
returnerrNum;
}
};
2 任务类VxTask
任务类VxTask用以封装VxWorks的task,本来考虑将任务的入口函数作为该类的纯虚成员函数,用户只要在该类的派生类中重载该纯虚函数就能实现自己的VxWorks task,但由于taskSpawn()的入口函数的参数类型是FUNCPTR(typedef int (*FUNCPTR) (...)),而指向VxTask类成员函数的指针类型为int (VxTask:: *ptr)(…),编译器不支持这两种类型之间的强制类型转换,所以只能换种思路——用一个名为Runnable的类专门封装task的入口函数,同时提供一个静态成员函数完成对该入口函数的调用,而该静态成员函数地址可以转换成FUNCPTR类型,供taskSpawn()调用。在VxTask类中实现关于task的系统调用。部分源代码如下:
classRunnable{
protected:
virtualvoidrun()=0;
public:
staticvoidentry(Runnable*Run)
{
Run->run();
}
virtual~Runnable()
{
}
};
classVxTask{
protected:
char*name;
inttid;
public:
VxTask(char*Name,intArg1,FUNCPTREntry=(FUNCPTR)Runnable::entry,intPri=150,intOpt=VX_FP_TASK,intStackSize=2000000,
intArg2=0,intArg3=0,intArg4=0,intArg5=0,intArg6=0,intArg7=0,intArg8=0,intArg9=0,intArg10=0):name(Name)
{
if(Entry==NULL){
throw(VxRunTimeError("TaskCreatFail:EntryCan'tbeNULL!"));
}
tid=taskSpawn(Name,Pri,Opt,StackSize,Entry,Arg1,Arg2,Arg3,Arg4,Arg5,Arg6,Arg7,Arg8,Arg9,Arg10);
if(tid==ERROR){
throw(VxRunTimeError("TaskSpawnFail!"));
}
}
~VxTask()
{
if(taskDelete(tid)==ERROR){
throw(VxRunTimeError("TaskDeleteError:Taskdeletefail!"));
}
}
voidsuspend()
{
if(taskSuspend(tid)==ERROR){
throw(VxRunTimeError("TaskSuspendError:Tasksuspendfail!"));
}
}
voidresume()
{
if(taskResume(tid)==ERROR){
throw(VxRunTimeError("TaskResumeError:Taskresumefail!"));
}
}
intgetTid()
{
returntid;
}
};
使用时首先派生Runnable的子类,重载其run()成员函数,然后将该子类的对象指针赋给VxTask的构造函数,用户task就跑起来了:
classMyRunnable:publicRunnable
{
voidrun(){
while(1){
cout<<"HelloVxWorksTaskWorld!"<<endl;
taskDelay(sysClkRateGet());
}
}
};
voidmyMain()
{
MyRunnablemyRun;
VxTasktask(“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)(...);
classVxInt{
protected:
intintNum;
public:
VxInt(intIntNum,intArg=0,VOIDFUNCPTREntry=(VOIDFUNCPTR)Runnable::entry):intNum(IntNum)
{
if(intConnect((VOIDFUNCPTRPTR)INUM_TO_IVEC(intNum),Entry,Arg)==ERROR){
throw(VxRunTimeError("InterruptConnectFail!"));
}
}
};
与task不同,中断服务程序(ISR)中不能调用可能被阻塞的函数,这点需要在重载Runnable派生类中的run()成员函数时引起注意。
4 看门狗类 VxWatchDog
VxWorks中的看门狗实际上是利用系统时钟中断来定时执行某个函数的,所以被看门狗执行的函数是运行在中断的上下文(Context)中,而不是任务的上下文中,故该函数中也不能调用带有阻塞功能的函数。所以VxWatchDog的实现与中断类VxInt类似:
classVxWatchDog{
WDOG_IDid;
intdelay;
public:
VxWatchDog(intDelay,Runnable*EntryObj):delay(Delay)
{
id=wdCreate();
if(id==NULL){
throw(VxRunTimeError("WatchDogCreatFail!"));
}
if(wdStart(id,delay,(FUNCPTR)Runnable::entry,(int)EntryObj)!=OK){
throw(VxRunTimeError("WatchDogStartFail!"));
}
}
voidcancel()
{
if(wdCancel(id)!=OK){
throw(VxRunTimeError("WatchDogCancelFail!"));
}
}
WDOG_IDgetId()
{
return(id);
}
~VxWatchDog()
{
if(wdDelete(id)!=OK){
throw(VxRunTimeError("WatchDogDeleteFail!"));
}
}
};
wdStart(WDOG_ID Id, int Delay, FUNCPTR Ptr, int Para )只会让函数Ptr在延时Delay ticks后执行一次,要周期性地执行Ptr,需要在Ptr中递归调用wdStart()。那能否这样实现呢:
classWdRun:publicRunnable{
protected:
voidrun(){
logMsg("HelloWatchDogWorld!",0,0,0,0,0,0);
VxWatchDogwtDog(sysClkRateGet(),this);
}
};
上述程序试图在入口函数中产生一个VxWatchDog类的对象,并用this指针初始化该对象,以期达到每秒钟执行一次入口函数的目的。但是不要忘了该入口函数是运行在中断的上下文中的,不允许动态地产生或删除对象,所以采用这种方法实现周期性执行作业并不可行。
为了在入口函数中调用wdStart(),且要避免动态地生成VxWatchDog对象,需要在Runnable派生类的成员变量中包含一个VxWatchDog指针,通过该指针调用所指对象的wdStart()。为此,需要在VxWatchDog类中增加成员函数:
VxWatchDog::VxWatchDog(intDelay):id(wdCreate()),delay(Delay)
{
if(id==NULL){
throw(VxRunTimeError("WatchDogCreatFail!"));
}
}
voidVxWatchDog::start(Runnable*EntryObj)
{
if(wdStart(id,delay,(FUNCPTR)Runnable::entry,(int)EntryObj)!=OK){
throw(VxRunTimeError("WatchDogStartFail!"));
}
}
classWdRun:publicRunnable{
protected:
VxWatchDog*dog;
virtualvoidrun(){
logMsg("HelloWatchDogWorld!",0,0,0,0,0,0);
dog->start(this);
}
public:
WdRun(VxWatchDog*Dog):dog(Dog)
{
}
};
voidmyMain()
{
VxWatchDogwtDog(sysClkRateGet());
WdRunrun(&wtDog);
wtDog.start(&run);
while(1){
taskDelay(sysClkRateGet());
cout<<"InMain!"<<endl;
}
}
在shell中输入sp myMain,可以看到预期输出。
5 信号量类 VxSem
VxWorks信号量包括互斥信号量、二进制信号量和计数信号量,这三种信号量除了创建时调用各自的创建函数,其它操作具有相同的接口,所以考虑采用VxSem类作为信号量基类,提供统一的信号量操作接口,VxSemM、VxSemB、VxSemC三个派生类分别封装了三种信号量的创建函数:
classVxSem{
protected:
SEM_IDid;
public:
VxSem(SEM_IDId):id(Id)
{
}
virtual~VxSem()
{
if(semDelete(id)==ERROR){
throw(VxRunTimeError("SemaphoreDeleteFail!"));
}
}
voidtake(intTimeOut=WAIT_FOREVER)
{
if(semTake(id,WAIT_FOREVER)==ERROR){
throw(VxRunTimeError("SemaphoreTakeFail!"));
}
}
voidgive()
{
if(semGive(id)==ERROR){
throw(VxRunTimeError("SemaphoreGiveFail!"));
}
}
voidflush()
{
if(semFlush(id)==ERROR){
throw(VxRunTimeError("SemaphoreFlushFail!"));
}
}
SEM_IDgetId()
{
returnid;
}
};
classVxSemB:publicVxSem{
public:
VxSemB(intOpts=SEM_Q_FIFO,SEM_B_STATEState=SEM_EMPTY):VxSem(semBCreate(Opts,State))
{
if(id==0){
throw(VxRunTimeError("BinarySemaphoreCreatFail!"));
}
}
};
classVxSemM:publicVxSem{
public:
VxSemM(intOpts=SEM_Q_PRIORITY|SEM_INVERSION_SAFE|SEM_DELETE_SAFE):VxSem(semMCreate(Opts))
{
if(id==0){
throw(VxRunTimeError("Mutual-exclusionSemaphoreCreatFail!"));
}
}
};
classVxSemC:publicVxSem{
public:
VxSemC(intOpts,intCnt):VxSem(semCCreate(Opts,Cnt))
{
if(id==0){
throw(VxRunTimeError("CountingSemaphoreCreatFail!"));
}
}
};
F. VxWorks上tShell和hostshell的区别
VxWorks上支持2种shell,一种叫tshell(target shell)一种叫host shell
tshell是VxWorks镜像中的一个任务,用“-〉”做提示符,可以在超级终端中用“i”显示任务列表并看到对应的tshell任务,或者用taskNameToId(“tshell”)获取任务的Id,任务Id是指向TCB的指针。
tshell是一个C语言的parser,可以对变量赋值,显示变量的值,变量的数值运算,调用函数等,但不支持if,for,while等的逻辑指令,比如
-〉aa=1在tshell中给变量aa赋值为1(如果aa不存在,则创建它,并加入到符号表,新创建的变量都是32的整形变量!!)
tshell是使用YACC实现的。
Hostshell是主机上的一个程序他既可以解析C语言,又可以解析tcl语言
G. vxworks rreboot调用什么程序
Ctrl+X,Ctrl+C都是在ty中处理的,分别需要通过ioctl设置OPT_MON_TRAP和OPT_ABORT选项(默认是打开的),ctrl+c调用shellRestart实现shell重启,ctrl+x直接调用reboot实现系统重启。
H. vxworks m命令使用方法
输入m命令选择对象,指定基点,鼠标往需要移动对象的方向移动一下,输入需要移动的距离就可以了。
什么是命令? 命令就是必须强制执行。具体的内容和事项有命令下达者说明,也就是执行具体的事项,也叫做任务。
I. 怎么看vxworks的版本,用CMD命令可以吗
shell下输入 version ,这个是系统自带的,当然你也可以自己定义一个查询系统版本的函数。
J. vxworks 任务创建成功,但实际函数未执行
你是用vxsim吗?应该是打印到虚拟终端了,而不是直接输出到shell