版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
目录第1章操作系统根本概念4实时操作系统和分时操作系统的区别4嵌入式操作系统VxWorks简介41.3VxWorks的特点5可靠性5实时性51.3.3可裁减性6对一个实时内核的要求61.4VxWorks的整体构架7第2章vxWorks驱动开发预备72.1VxWorks映像82.2BSP主要文件目录的组成及作用:11系统启动顺序142.4Vxworks驱动概要17第3章vxWorks网络驱动开发21驱动类别223.2Vxworks下网络驱动开发243.3VxWorks网络驱动配置及分析60第4章VxWorks系统中常见问题65前言在通信,电子领域,目前主流的嵌入式操作系统为linux和vxworks。Linux多用于消费电子产品,像大家熟悉的andriod,原始系统就是linux,也就是说andriod也是一种linux系统。还有大家熟悉的MP3,也是使用linux操作系统的。Linux因为价格廉价〔开源的,不需要付licence〕,稳定性好占据了一定的市场份额。Vxworks是风河系统1983开发的一款嵌入式实时操作系统,多用于通信,导航,航天等领域。因为这些领域对实时性要求非常高,比方现在LTE系统就是使用vxworks系统,因为是采用TDD模式,而这种模式,显然对实时性要求非常高。也就注定了vxwroks在这些领域的特有优势。选择linux还是vxworks看自己的专业方向,还有自己的兴趣所有。每个领域只要研究透彻,都是很有前途的。既然两者都是主流的嵌入式操作系统,其还是有很多相似性。小编也初步接触过linux,发现具备一定的linux根底对日后深入学习vxworks很有好处,很多思想都是相似的。另外,本人系小硕,目前的研究领域是vxworks驱动开发,主攻网络驱动开发。在平常的日常学习中,结合各位网友提供的资料〔自己在百度上收集的〕,还有workbench提供的document〔自己翻译,特别是针对网络驱动局部〕,希望对广阔嵌入式驱动开发者有所帮助。声明:此文档并不适合于vxworks初学者,因为这里,小编省去了很多vxworks下的根本知识,包括内核中常用的进程,信号量等等支持。也没有提及集成开发环境tornado/vworkbench.这里的探索重点是vxwroks底层的东西,包括启动过程,BSP开发等。附录:Vxworks的应用领域嵌入式Vxworks系统的主要应用领域主要有以下几方面:1.数据网络:如:以太网交换机、路由器、远程接入效劳器等2.远程通讯:如:电信用的专用分组交换机和自动呼叫分配器,蜂窝系统等3.医疗设备:如:放射理疗设备4.消费电子:如:个人数字助理等5.交通运输:如:导航系统、高速火车控制系统等6.工业:如:机器人7.航空航天:如:卫星跟踪系统8.多媒体:如:电视会议设备9.计算机外围设备:如:X终端、I/O系统等总之,VxWorks的系统结构是一个相当小的微内核的层次结构。内核仅提供多任务环境、进程间通信和同步功能。这些功能模块足够支持VxWorks在较高层次所提供的丰富的性能的要求。第1章操作系统根本概念实时操作系统和分时操作系统的区别从操作系统能否满足实时性要求来区分,可把操作系统分成分时操作系统和实时操作系统。分时操作系统按照相等的时间片调度进程轮流运行,分时操作系统由调度程序自动计算进程的优先级,而不是由用户控制进程的优先级。这样的系统无法实时响应外部异步事件。实时操作系统能够在限定的时间内执行完所规定的功能,并能在限定的时间内对外部的异步事件作出响应。分时系统主要应用于科学计算和一般实时性要求不高的场合。实时性系统主要应用于过程控制、数据采集、通信、多媒体信息处理等对时间敏感的场合。VxWorks简介VxWorks操作系统是美国WindRiver公司于1983年设计开发的一种嵌入式实时操作系统〔RTOS〕,是嵌入式开发环境的关键组成局部。良好的持续开展能力、高性能的内核以及友好的用户开发环境,在嵌入式实时操作系统领域占据一席之地。它以其良好的可靠性和卓越的实时性被广泛地应用在通信、军事、航空、航天等高精尖技术及实时性要求极高的领域中,如卫星通讯、军事演习、弹道制导、飞机导航等。在美国的F-16、FA-18战斗机、B-2隐形轰炸机和爱国者导弹上,甚至连1997年4月在火星外表登陆的火星探测器上也使用到了VxWorks。VxWorks操作系统是一个嵌入式实时操作系统〔RTOS〕。VxWorks与其它实时OS一样,基于以下两个重要机制:多任务环境及任务间通信。硬件中断处理。VxWorks多任务内核完成的功能是:实时调度,任务间通信及互斥。其它功能那么作为系统库围绕在内核周围,它们可根据需要进行剪裁。VxWorks与非实时系统的不同之处在于:VxWorks的优先抢占机制基于调度,VxWorks对外部事件的反响和处理快,VxWorks容量小并且可配置〔微内核结构〕1.3VxWorks的特点可靠性操作系统的用户希望在一个工作稳定,可以信赖的环境中工作,所以操作系统的可靠性是用户首先要考虑的问题。而稳定、可靠一直是VxWorks的一个突出优点。自从对中国的销售解禁以来,VxWorks以其良好的可靠性在中国赢得了越来越多的用户。实时性
实时性是指能够在限定时间内执行完规定的功能并对外部的异步事件作出响应的能力。实时性的强弱是以完成规定功能和作出响应时间的长短来衡量的。
VxWorks的实时性做得非常好,其系统本身的开销很小,进程调度、进程间通信、中断处理等系统公用程序精练而有效,它们造成的延迟很短。VxWorks提供的多任务机制中对任务的控制采用了优先级抢占〔PreemptivePriorityScheduling〕和轮转调度〔Round-RobinScheduling〕机制,也充分保证了可靠的实时性,使同样的硬件配置能满足更强的实时性要求,为应用的开发留下更大的余地。1.3.3可裁减性用户在使用操作系统时,并不是操作系统中的每一个部件都要用到。例如图形显示、文件系统以及一些设备驱动在某些嵌入系统中往往并不使用。VxWorks由一个体积很小的内核及一些可以根据需要进行定制的系统模块组成。VxWorks内核最小为8kB,即便加上其它必要模块,所占用的空间也很小,且不失其实时、多任务的系统特征。由于它的高度灵活性,用户可以很容易地对这一操作系统进行定制或作适当开发,来满足自己的实际应用需要。1.3.4对一个实时内核的要求一个实时操作系统内核需满足许多特定的实时环境所提出的根本要求,这些包括:多任务:由于真实世界的事件的异步性,能够运行许多并发进程或任务是很重要的。多任务提供了一个较好的对真实世界的匹配,因为它允许对应于许多外部事件的多线程执行。系统内核分配CPU给这些任务来获得并发性。抢占调度:真实世界的事件具有继承的优先级,在分配CPU的时候要注意到这些优先级。基于优先级的抢占调度,任务都被指定了优先级,在能够执行的任务〔没有被挂起或正在等待资源〕中,优先级最高的任务被分配CPU资源。换句话说,当一个高优先级的任务变为可执行态,它会立即抢占当前正在运行的较低优先级的任务。任务间的通讯与同步:在一个实时系统中,可能有许多任务作为一个应用的一局部执行。系统必须提供这些任务间的快速且功能强大的通信机制。内核也要提供为了有效地共享不可抢占的资源或临界区所需的同步机制。任务与中断之间的通信:尽管真实世界的事件通常作为中断方式到来,但为了提供有效的排队、优先化和减少中断延时,我们通常希望在任务级处理相应的工作。所以需要杂任务级和中断级之间存在通信。1.4VxWorks的整体构架VxWorks支持多种处理器,对硬件不做假设,可支持ARM.PPC,MPIS架构处理器。第2章vxWorks驱动开发预备BSP定义:Boardsupportpacket,为各种目标板的硬件功能提供了统一的软件接口它们包括:硬件初始化中断处理和产生硬件时钟和定时器管理内存映射和分配BSP还包括bootRom和其它启动机制,sysLib和sysALib库是VxWorks可移植的核心,BSP库是硬件与软件的接口,处理硬件的初始化、中断处理与产生、硬件时钟与定时管理、局部和总线内存空间的映射、内存大小定义,等等2.1VxWorks映像用户通过定制VxWorks组件和进行应用程序开发所生成映像包括wind多任务微内核,也包括BSP的引导代码Vxworks映像的三局部组成BSS段〔BlockStartedbySymbol,未手动初始化的数据〕代码段数据段两大类BootRom类型映像VxWorks类型BootRom类型映像最小化、专用的VxWorks引导映像,实现最少的系统初始化用于启动装载VxWorks映像,功能类似于PC机的BIOS。BootRom运行时建立起多任务环境usrRoot任务、网络任务〔tNettask〕、TFFS任务和FTP任务等。运行地点可能在ROM/Flash中执行(例如ROM驻留型引导映像),也可能在RAM中执行。在系统中其对应的编译规那么文件是BootRom类型分为三种BootRom_res一直运行在rom中的映象,只把data段拷贝到ram里面。BootRom_uncmp非压缩方式的映象,data段和text段都要拷贝到ram里面,并在ram里面运行。BootRom压缩方式的映象,生成的时候编译器会把除掉romlnit.s和之外的目标文件压缩并“汇编〞成一个,最后和,,进行链接,生成bootrom映像。要全部拷贝到ram中,并必须要进行解压缩的工作。而这些工作根本上都是在中进行的。VxWorks类型映像系统的主映像,是系统最终要运行的映像该映像在运行时至少有一局部(如:数据段和BSS段)需要在RAM中运行。在系统中其对应的编译规那么文件是Vxworks类型映像运行环境RAM运行的压缩的ROM运行的非压缩的VxWorks类型四种映像VxWorks:RAM运行的VxWorks映像不包含引导程序,需要独立的引导程序从本地存储器或者经由网络获取该映像,然后将其下载到RAM中的RAM_LOW_LADRS处运行VxWorks_romROM自动RAM运行的VxWorks映像,不需要BootRom辅助VxWorks_romResidentROM启动ROM运行的VxWorks映像,不需要BootRom辅助。包含引导代码,在重启时清空RAM,引导代码只将data段拷贝到RAM中的RAM_LOW_ADRS处,系统的运行是在ROM中进行的,启动速度快,需要的RAM空间少,但是运行速度慢。VxWorks_romCompressVxWorks_rom的压缩形式VxWorks型vsBootROM型映像对于没有自启动功能的VxWorks类型映像(如VxWorks型),映像运行前需一段程序将该映像拷贝到RAM中运行,BootRom类型映像完成VxWorks系统下载,完毕后BootRom的任务就结束了二者在系统初始化的时候,所做的功能根本相同,BootRom类型映像调用,而VxWorks类型映像调用映像链接方式可被静态或动态链接VxWorks在开发阶段可动态地下载目标文件,并与操作系统及其它目标文件动态链接。链接以后是浮动的,只在装载时才与绝对物理地址相对应。静态VxWorks成品阶段是采用静态链接的。要对系统底层驱动清楚,也就是对CPU及相关的硬件有所了解.主要是32微处理器(上电启动过程,downloadimage的方式方法,读写ROM,地址空间分配,MMU,存放器,中断定义,..).参照硬件资料,多读一些源码会有所帮助.Tornado2开发调试环境协议框图主机开发(HostDevelopmentSystem)目标机(TargetSystem)Tornado工具WTX协议通信<==========>EditorProjectShellDebuggerBrowserWindviewTargetServer|TargetAgentVxWorksTargetSimulatorWDB协议通信
<==========>ApplicationVxWorksOSVxWorksTarget(WDB)Agent两个主要两个协议WTX协议(WindRiverTooleXchange):用于开发机内部Tornado工具与TargetServer之间通信.WDB协议(WindDeBug):用于主机TargetServer与目标机之间的通信.2.2BSP主要文件目录的组成及作用:Install_direction/target/config/All:这个目录下的文件是所有BSP文件共享的,不是特别需要不要更改里面的任何文件.configAll.h:缺省定义了所有VxWorks的设置.如果不用缺省的设置,可在BSP目录下的文件中用#define或#undef方式来更改设置.bootInit.c:在ro后,完成BootROM的第二步初始化.程序从中的romInit()跳到这个文件中的romStart().来执行必要的解压和ROMimage的放置.bootConfig.c:完成BootROMimage的初始化和控制.usrConfig.c:VxWorksimage的初始化代码.Install/target/config/comps/src:.intasll/target/config/bspname:包含系统或硬件相关的BSP文件.Makefile一些命令行控制images的生成,参见BSP设置局部及生成下载READMEBSP发布纪录,版本,总的文档包括所有涉及CPU主板的设置及定义(includes,definations),参见BSP设置文件及生成下载网络驱动的主要设置文件,主要对END驱动设置.汇编语言文件,是VxWorksBootROM和ROMbasedimage的入口,参见系统启动局部汇编语言文件,程序员可以把自己的汇编函数放在这个文件里,在上层调用.VxWorksimage的入口点_sysInit在这个文件里,是在RAM中执行的第一个函数。包含一些系统相关的函数例程,提供了一个board-level的接口,VxWorks和应用程序可以以system-indepent的方式生成.这个文件还能包含目录target/config/comps/src的驱动.可选文件用于Scsi设备设置和初始化.sys可选文件用于所有的串口设置和初始化.ASIC文件包含VxWorksBootROM代码VxWorks运行在目标机上,完整的,连结后的VxWorks二进制文件.VxWorks.sym完全的,连结后带有符号表的VxWorks二进制文件完全的,连结后,standalone,带有符号表的VxWorks二进制文件BSP用"make"来编译连接生成(Created),而不是用Tornado的工具.BSP和应用程序都可以在"make"或"tornade"上开发(developed)。BSP被设置包括以下驱动:中断控制interruptcontroller计时器timer(sys/aux)串口UART(serial)显示屏LCD键盘Keyboard(opt)触摸屏touch-screen(opt).系统启动顺序VxWorksimage分为在ROM中运行和在RAM中运行两种.两者启动顺序的区别在于sysInit()函数的调用.该函数在RAM运行的VxWorks中初始化RAM.ROM中运行的VxWorksVxWorks在ROM中运行,即写入ROM中的VxWorks是非压缩的,不需要解压,系统直接跳到ROM的首地址,运行VxWorks.注意:ROM运行的VxWorks并不支持所有的主扳,应以主扳手册为准.文件中的romInit()>文件中的romStart()-->文usrConfigusrInit()>sysHwInit()>usrKernelInit()>KernelInit(usrRoot,...)。Vxwroks在ROM中运行的优势VxWorksVxWorksimage的data段复制到RAM的LOCAL_LOW_ADRS,text局部留在ROM并在ROM中执行.。ROM中运行的VxWorks缺点是运行速度慢.RAM中运行的VxWorksVxWorks在RAM中运行,即写入ROM中的Boot或VxWorksImage是压缩的,需要先解压copy所有的text和data到RAM的LOCAL_LOW_ADRS中,下面sysInit()主要是初始化RAM用的,系统直接跳到RAM的首地址,运行VxWorksusrInit()前面不压缩,即romInit(),romStart()不能压缩.启动过程文件中的romInit()>文件中的中的sysInit()>文件中的usrInit()>sysHwInit()>usrKernelInit()>KernelInit(usrRoot,...)。RAM运行的Boot或VxWorksimage的text段或data段会从ROM复制到RAM,在RAM中运行。其中usrRoot()是VxWorks启动的第一个任务,由它来初始化driver,network等。BootROMimage的启动过程最少的系统初始化,主要用于启动装载VxWorksimage.一般有压缩和不压缩两种形式,如bootrom和boot_uncmp.与VxWorksimage的区别在于一个Bootrom调用bootConfig.c,而VxWorks调用usrConfig.c.启动顺序文件中的romInit()>文件中的romStart()>文件bootConfig中的usrInit()>sysHwInit()>usrKernelInit()>KernelInit(usrRoot,...)其中是BootROM设置模块.用于通过网络加载VxWorksimage.usrRoot()>bootCmdLoop(void)命令行选择,或autobooting>bootLoad(pLine,&entry)载模块到内存(网络,TFFS,TSFS...)>netifAttach()>go(entry)>(entry)()从入口开始执行,不返回.系统启动中几个很重要的函数及其作用romInit()powerup,disableinterrupt,putboottypeonthestack,clearscaches.romStart()loadImageSegmentsintoRAM.usrInit()Interruptlockout,saveimformationaboutboottype,handlealltheInitializationbeforethekernelisactuallystarted,thenstartsthekernelexecutiontocreateaninitialtaskusrRoot().Thistaskcompletesthestartup.sysHwInit()Interruplocked,Initializeshardware,registers,activationkernel.KernelInit(usrRoot,...)Initializesandstartsthekernel.Definessystemmemorypartition.ActivatesatasktUsrRoottocompleteinitalization.Unlocksinierrupts.UsesusrInit()initatestack.usrRoot()初始化内存分区表(memorypartitionlibrary),初始化系统系统时钟(systemclock)。初始化输入输出系统(I/Osystem)可选Createdevices可选设置网络(Configurenetwork)可选激活WDB目标通信(ActivateWDBagent)可选调用程序(Activateapplication)VxWorksImage在RAM中解压的位置RAMLowAddressRAMHighAddressVxWorks运行的位置Bootimage由ROM解压后Copy的位置,即bootRom区BSP配置文件及生成下载VxWorks在ROM中的情况ROM低高地址位ROM低地址位压缩的VxWorksImgage没有压缩的romInit.s和romStart()在ROM的起始位置,系统powerup后,从这个起始位开始执行,即执行romInit(),起始位置由硬件定义,一般为0x00000000注:浅蓝色为整个VxWorksImage.BSP配置文件及生成下载2.4Vxworks驱动概要总线类型PLB〔processorlocalbus〕,VME,PCI,PCI-Express,RapidIO,Mii,Virtual,MF〔multifunctiondevicebus〕,USB,IIC,SPI.驱动可以提供的效劳配置配置资源例如ns83902VxbEnd.c设备驱动中有这么一段devResourceGet(pHcf,"regWidth",HCF_RES_INT,(void*)®isterWidth;这里的registerwidth就是资源配置参数vxbInstParamByNameGet(pInst,"jumboEnable",VXB_PARAM_INT32,&val);这句话的意思是支持大包处理,jumboenable.这个就是参数配置又如:中有这么一段LOCALVXB_PARAMETERSrtgParamDefaults[]={{"rxQueue00",VXB_PARAM_POINTER,{(void*)&rtgRxQueueDefault}},{"txQueue00",VXB_PARAM_POINTER,{(void*)&rtgTxQueueDefault}},{"jumboEnable",VXB_PARAM_INT32,{(void*)0}},{NULL,VXB_PARAM_END_OF_LIST,{NULL}}};内存管理系统启动过程中分配内存。当系统早期启动的过程中,那些最初被初始化的设备驱动是不能使用malloc,calloc.memPartAlloc()等函数分配内存的,因为这些方法要使用信号量等操作。这时,只能使用如下函数分配内存hwMemAlloc()从一个静态池中分配N个字节,并清零。hwMemFree()将内存分配给静态池。注意hwMemAlloc()和hmMemFree()是在系统启动初期分配和释放内存,一旦系统完成初始化,就可以使用标准的内存分配哈数进行分配。malloc(),calloc(),memPartAlloc(),这里怎么没有memalign〔〕硬件访问读写硬件存放器vxbRead8()vxbRead16()vxbRead32()vxbRead64()vxbWrite8()vxbWrite16()vxbWrite32()vxbWrite64()使用vxbus访问存放器的宏定义在下面的路径installDir/vxWorks-6.x/target/src/hwif/h/vxbus/vxbAccess.h采用vxbRegMap().进行映射/*findthememorymappedwindowforthedeviceregisters*/for(i=0;i<VXB_MAXBARS;i++){if(pInst->regBaseFlags[i]==VXB_REG_MEM)break;}pDrvCtrl->feiBar=pInst->pRegBase[i];/*storethebaseaddress*/vxbRegMap(pInst,i,&pDrvCtrl->feiHandle);/*mapthewindow*/这段程序完成的功能是首先查找空间,找到VXB_REG_MEM时,跳出,将地址存储到【pDrvCtrl】中,同时调用函数完成映射,返回句柄,供继续读写用。中断处理vxbIntConnect()vxbIntDisconnect()vxbIntEnable()vxbIntDisable()同步任务水平的同步采用信号量〔这里说mux〕,spinlock,中断锁。中断水平的同步采用信号量〔mux〕,添加item到消息队列。当使用后者时,在ISR中使用msgsend时,timeout应该为zero。中断水平的同步采用中断锁intCpulock,unCpuLockkey=intCpuLock();/*accessshareddatastructures.*/intCpuUnlock(key);注意虽然中断锁很简单,很有效,但是现在不怎么使用中断锁了,因为以下两个原因增加了系统开销。在多个CPU或vxwroksSMP模式下中断锁不起作用。第3章vxWorks网络驱动开发驱动说明风河早期的驱动采用legacydriver,在早期的版即vxWorks5.x中使用,在新的版本中已经不再提供legacydriver了,特别是使用SMP的用户,风河强烈建议采用vxbus模型的驱动。驱动开发可利用到的资源包含网络驱动,总线控制,定时器驱动,串行设备驱动。installDir/vxWorks-6.xinstallDir/vxWorks-6.xinstallDir/vxWorks-6.xinstallDir/vxWorks-6.x/target/src关于定时器驱动installDir/vxWorks-6.x这里的驱动采用vxbus模型开发,是从legacydriver迁移到vxbus的。installDir/vxWorks-6.x提供了PPC8260的定时器驱动,采用legacydriver开发。驱动类别注意开发驱动对vxWorks的I/O系统也要有所了解。通用类别:串行设备。软件提供open〔〕,write〔〕,ioctl〔〕调用。串行设备驱动例程存放路径installDir/vxWorks-6.x/target/src/hwif/sio存储设备管理ram,taperam,及其板上的flash设备,ATA盘,串行ata盘,scsi盘,usbflash盘等。路径:installDir/vxWorks-6.x/target/src/hwif/storage网络接口驱动MAC层驱动installDir/vxWorks-6.x/target/src/hwif/endMAC驱动与MUX相连。物理层驱动installDir/vxWorks-6.x/target/src/hwif/miiPHY与MAC之间由MII相连。NVRAM〔非易失性RAM〕驱动installDir/vxWorks-6.x/target/src/hwif/nvram定时器驱动installDir/vxWorks-6.x/target/src/hwif/timer定时器驱动的作用:告诉CPU某事件已经消耗了指定时间提供加减计数DMA驱动installDir/vxWorks-6.x/target/src/hwif/dmaBusControllerDrivers〔总线控制器驱动〕为不同的总线之间提供接口每一个CPU在设计的时候都提供了一个与外界相连的接口,称为总线接口。一般情况下,不考虑CPU类型,直接与总线相连,称为PLB〔processorlocalbus〕。在某些情况下,需要将不同的总线之间进行桥接,用到PCE或VME.installDir/vxWorks-6.x/target/src/hwif/busCtlr作用:总线控制器确定系统当前是那种总线在工作。2.总线控制器负责配置下行设备,使之能够工作。3.总线控制器负责管理地址映射。USB驱动USB主机设配驱动installDir/vxWorks-6.x/target/src/hwif/busCtlr/usb/hcdUSB类驱动installDir/vxWorks-6.x/target/src/drv/usbInterruptControllerDrivers〔中断控制器驱动〕作用:当设备产生中断时,中断控制器负责将中断传递个处理器,并且保证其他中断源不再送往CPU当其正在处理当前中断时。installDir/vxWorks-6.x/target/src/hwif/intCtlrMultifunctionDriversRemoteProcessingElementDriversinstallDir/vxWorks-6.x/target/src/hwif/cpuconsole驱动installDir/vxWorks-6.x/target/src/hwif/consoleResourceDriversinstallDir/vxWorks-6.x/target/src/hwif/resource资源驱动的功能是为外围设备及其配置资源其他类A/DD/A要写驱动,首先要知道驱动文件所在位置,这里有三个路径存放与驱动有关的文件installDir/vxWorks-6.x/target/3rdpartyVxBusmodeldevicedriverswrittenbythirdpartydevelopersthatareinstalledasadd-onstoanexistingVxWorksinstallation.installDir/vxWorks-6.x/target/src/hwifDriverswrittenincompliancewiththeVxBusdevicemodel,distributedandsupportedbyWindRiver,andprovidedaspartofastandardproduct,installationorpatch.installDir/vxWorks-6.x/target/src/drvWindRiverlegacydrivers(notinVxBuscompliance).这里的驱动是采用legacy,模型〔区别于vxbus模型〕,Legacy模型用于驱动开发是应用在vxworks早期版本中。驱动源文件提供某些实体的逻辑实现DriversourcefileinstallDir/vxWorks-6.x/target/src/hwifThird-partydriversarefoundunder:installDir/vxWorks-6.x/target/3rdpartyTheexampleinthissectiondiscussesthefilelocations3.2Vxworks下网络驱动开发说明:vxworks下网络驱动开发,是本文档要讲述的重点。在本章节中,将重点介绍vxworks下驱动开发要完成的工作,熟悉驱动开发有关的源文件及其头文件,根据具体情况进行修改和配置。理解使用vxbus开发模型进行驱动开发的一般流程。知道在系统初始化过程系统是如何对网络驱动进行初始化的,包括网络驱动的声明,注册等。在本章节中,读者要重点关注与网络驱动有关的头文件,源文件〔对于命名中有end这样字眼的程序要多加留意〕,可以仔细研读,发现其中的一般性。最后结合风河代码,给出一款网卡驱动的开发方法。vxWorks网络协议栈与windows下TCP/IP协议栈相比,vxWorks增加了MUX层。VxWorks下网络驱动的开发要掌握的根本概念网络驱动包括MAC层驱动和PHY驱动。MAC层和PHY层通过MII连接。MII是meidiaindependentinterface的缩写,是一种连接机制。其他媒介还有SGMII,GMII,PLB等等。可以通过配置MAC相关的存放器实现。Vworks下网络驱动分为END模型驱动和BSD模型驱动。现在比拟流行的还是END模型驱动。写vxWorks下的驱动只要实现模板函数完成的功能即可,如endload(),endunload(),endpollsend(),endpollreceive()等。具体函数看数据结构netfun,有需要实现的函数接口。这些接口在系统初始化硬件的过程中有mux层调用实现。驱动开发者只需关心底层的这几个函数实现,无须关心mux层的实现方法。Socket与vxWorks网络驱动的关系Socket是在应用层调用。起始在vxworks下表现为一种文件。通过socket在不同进程之间传递信息。Socket的发送接收功能,说到底最后还是调用底层的驱动send,receive实现。对vxwroks网络驱动有一点了解之后,我们来重点学习END驱动了解什么是MUX这个图说明MUX在协议栈中的位置,与传统TCP/IP协议栈相比,增加了一层MUX,是数据链路层与IP层之间的接口。这里的协议层是与传输层及其往上应用层的接口。与其他TCP/IP协议相比VxWorks网络协议栈增加一层MUX层。MUX层是VxWorks为方便在网络接口硬件上实现多种协议而增加的一层。它主要用于管理底层的多种硬件的设备驱动,向上层不同协议提供统一的接口,降低了上层协议与底层物理硬件的藕合,使得网络驱动和上层协议彼此保持独立,既方便在现有硬件根底上实现新的上层协议,也利于用新的硬件支持原有的上层协议。MUX与END的交互是通过提供一套可供底层调用接口效劳来实现的,实现END驱动必须遵循这套接口关系。如下图。MUX与END的接口关系图3中右边框中列出的函数是驱动需要实现的函数,供MUX层调用在必要的时间调用,如当上层使用该网卡发送数据时,MUX会调用该网卡END驱动提供的Send函数,将数据提交给网卡芯片硬件。缓冲池数据结构网络设备驱动与上层协议进行数据交换需要相应的内存缓冲,并且管理这些缓冲也需要相应的函数。VxWorks提供了netBufLib函数库用于创立和管理网络设备用到的内存缓冲池,网络设备驱动可以直接使用也可以在此根底上设计自己特定的内存缓冲池。数据以簇的形式保存,数据结构mBlks〔内存块〕和clBlks〔簇块〕形成的数据链结构那么用于指定各个簇。在clBlk之上是mBlk结构。该结构存储一个到clBlk的连接,也可以存储一个到另一个mBlk的连接。通过mBlk的连接,可以引用任意数量的数据,如图4所示。图4mBlks和clBlks的数据结构装载及启动END设备的系统函数主要用到以下几个:(1).muxDevLoad()该函数装载指定设备的驱动程序装载函数。如果要装载END设备,系统必须调用muxDevLoad()函数。(2).muxDevStart()启动设备函数(3).muxBind()muxBind()可以将协议绑定到指定的END设备上。其调用过程是系统调用ipAttach()函数,而该函数调用muxBind()函数,绑定协议堆栈到MUX上的一个指定的网络接口。当一个网络接口被关闭时,ipAttach()函数将释放网络接口所关联的TCP/IP堆栈模块。装载及启动END设备驱动程序的流程如下:使用指定的END设备驱动程序的BSP引导VxWorks系统时,在引导过程中,系统将执行任务tUsrRoot来完成如下各项:(1)初始化网络任务的工作队列;(2)创立tNetTask任务来处理网络任务工作队列的条目;(3)调用muxDevLoad()装载指定的网络驱动程序;(4)调用muxDevStart()启动指定的网络驱动程序。tUsrRoot任务调用MUX设备装载函数muxDevLoad()和设备启动函数muxDevStart(),通过这两个函数来装载和启动设备驱动程序。muxDevLoad()函数会根据网络设备表endDevTbl[]中的定义逐一调用各网络设备的装载函数,其中这个函数是muxDevLoad()的一个输入参数。muxDevStart()函数也会根据endDevTbl[]逐一调用网络设备所定义的设备开始函数。至此MUX的初始化以及END驱动程序的初始化工作已经完成。但是网络设备还是不可以使用,因为还需要将协议绑定到指定的END指定的设备上,这一步需要用muxBind()函数实现。在VxWorks中,系统通过usrRoot()函数调用usrNetInit()函数完成MUX的初始化、装载网络设备表endDevTbl[]中描述的所有设备并将IP协议绑定到网络引导设备上等工作。网络设备驱动程序的安装过程即图5所示的网络初始化顺序。图5网络初始化顺序发送数据在VxWorks网络系统中,发送数据的流程如图6。图6数据发送通过对图6分析,主要包含以下几个处理。(1)用户调用write()函数,通过套接字访问网络。(2)网络协议拷贝需要发送的数据到网络缓冲区中,并调用协议驱动程序的发送程序。(3)协议驱动程序调用muxSend()启动发送循环。(4)muxSend()通过调用send()回调函数,把缓冲区传递给END。(5)数据发送程序把数据拷贝到设备缓冲区中,并把它放置到设备的发送队列中。(6)当产生发送中断时,驱动程序的中断效劳程序调度程序丢弃已发送的数据包,彻底清理发送队列。接收数据在VxWorks网络系统中,接收数据的流程如图7。通过对图7进行分析,它主要包含以下几个处理。(1)设备接收到数据包后直接把数据存放到预先分配的簇中。(2)当接收到中断时,驱动程序的中断效劳程序调度任务级接收程序进行如下操作。①clBlk结构和簇连接;mBlk和clBlk连接;最后构成缓冲区。②通过调用receiveRtn()函数,把缓冲区传递给更高级别的协议。(3)muxReceive()调用协议的stackRcvRtn()函数,把成列的缓冲区传递给应用。用户使用read()函数,通过套接字访问网络中的成列缓冲区驱动程序的中断处理中断处理函数fei82557INT()处理设备中断。根据中断状态调用相应的中断处理程序,如接收终端程序、发送中断程序等。当网络接口产生中断时,系统调用中断效劳程序。为了将中断阻塞减到最小,中断驱动程序只处理那些需要最小时间的工作,把其他耗时的任务排列到网络任务的工作队列中。为了排列任务级的包接收处理工作,网络驱动程序中断效劳程序必须调用netJobAdd()函数。在调用netJobAdd()函数时,应当指定任务级处理数据包的驱动程序入口。然后由netJobAdd()把函数指派到网络系统任务——tNetTask的工作队列中。VxWorks通过tNetTask处理任务级的网络处理。tNetTask调用队列中处理程序如下:〔1〕包接收程序:把接收到的数据包上传到网络缓冲区的堆栈中,通过一个调用上传给MUX。〔2〕释放所有发送帧程序:程序调用netClFree()函数释放发送缓冲区中所有已经发送的数据帧。协议层执行以下入口点stackShutdownRtn()stackError()stackRcvRtn()stackTxRestartRtn()Mux与网络驱动之间的接口这局部学习可以参考风河代码MuxLibmux执行的函数有muxbind〔〕,muxDevload〔〕等。Mux相关API详解muxDevLoad()将设备装载到MUXmuxDevStart()从MUX启动设备muxBind()绑定协议层到MUX〔hook〕muxSend()从协议层接收数据包,然后发往设备muxDataPacketGet()获取一个只包含包数据的mblk,不包含链路层次的头部信息〔omitted.〕muxAddressForm()将包地址放入指定的buffer.muxIoctl()访问控制函数muxMCastAddrAdd()为设备中的表添加一个多播地址muxMCastAddrDel()删除一个多播表muxMCastAddrGet()获取设备中的多播地址表muxUnbind()断开协议层与MUX层的链接muxDevStop()停止设备muxDevUnload()卸载设备muxPacketDataGet()提起一个submittedmblk中的包数据,并将它写入一个新的mblkmuxPacketAddrGet()从一个submittedmblk中提取数据包中的源地址和目的地址,并将每个地址写入它们自己的mblk。如果本地源/目的地址与END源/目的地址不同,函数将吸入足够多的mblk。Ifthelocalsource/destinationaddressesdifferfromtheendsource/destinationaddresses,thisroutinewritestoasmanyasfourmBlks.muxTxRestart()由stackTxRestartRtn()调用,往底层发送数据包。muxReceive()接收来自设备的包发往MUXmuxShutdown()关闭与设备有关的所有协议。muxAddrResFuncAdd()添加一个地址解决函数muxAddrResFuncGet()从列表中获取一个特别的地址解决函数muxAddrResFuncDel()从列表中删除一个特别的地址解决函数这个图说明了三个层次之间的关系,对于驱动开发者来说,只需关心实现END的相关接口即可。注意这里有一个问题,我们发现在protocol层上并没有调用muxsend的接口。不是没有,而是在标准的API之外〔风河文档说明〕协议层(protocol)的数据结构Mux使用该数据结构存储于协议有关的信息typedefstructnet_protocol{NODEnode;/*Howwestayinalist.*/charname[32];/*Stringnameforthisprotocol.*/longtype;/*ProtocoltypefromRFC1700*/intflags;/*Isprotocolinapromiscuousmode?*/BOOL(*stackRcvRtn)(void*,long,M_BLK_ID,M_BLK_ID,void*);/*Theroutinetocallwhenweget*//*apacket.*/STATUS(*stackShutdownRtn)(void*,void*);/*Theroutinetocalltoshutdown*//*theprotocolstack.*/STATUS(*stackTxRestartRtn)(void*,void*);/*Callbackforrestartingonblockedtx.*/void(*stackErrorRtn)(END_OBJ*,END_ERR*,void*);/*Callbackfordeviceerrors.*/void*pSpare;/*Sparepointerthatcanbepassedto*//*theprotocol.*/}NET_PROTOCOL;接收数据包发往协议层stackRcvRtn()voidstackRcvRtn(void*pCookie,/*returnedbymuxBind()call*/longtype,/*protocoltypefromRFC1700*/M_BLK_IDpNetBuff,/*packetwithlinklevelinfo*/LL_HDR_INFO*pLinkHdr,/*link-levelheaderinfostructure*/void*pSpare/*avoid*theprotocolcanusetogetinfo*//*onreceive.ThiswaspassedtomuxBind().*/)返回错误信息voidstackError(END_OBJ*pEnd,/*pointertoEND_OBJ*/END_ERR*pError,/*pointertoEND_ERR*/void*pSpare/*pointertoprotocolprivatedatapassedinmuxBind*/)typedefstructend_err{INT32errCode;/*errorcode,seeabove*/char*pMesg;/*NULL-terminatederrormessage,canbeNULL*/void*pSpare;/*pointertouserdefineddata,canbeNULL*/}END_ERR;关闭协议层voidstackShutdownRtn(void*pCookie/*ReturnedbymuxBind()call.*/void*pSpare/*avoid*thatcanbeusedbytheprotocoltoget*//*infoonreceive.ThiswaspassedtomuxBind().*/)重新发送voidmuxTxRestart(void*pCookie/*ReturnedbymuxBind()call.*/)网络层往链路层地址解决STATUSmuxAddrResFuncAdd(longifType,/*Mediainterfacetypefromm2Lib.h*/longprotocol,/*ProtocoltypefromRFC1700*/FUNCPTRaddrResFunc/*Functiontocall.*/)STATUSmuxAddrResFuncDel(longifType,/*Mediainterfacetypefromm2Lib.h*/longprotocol/*ProtocoltypefromRFC1700*/)FUNCPTRmuxAddrResFuncGet(longifType,/*ifTypefromm2Lib.h*/longprotocol/*protocolfromRFC1700*/)Vxbus驱动初始化过程驱动初始化顺序驱动实例理解1.驱动在vxwroks中注册,使用如下数据结构。LOCALstructdrvBusFuncscn3xxxTimerDrvFuncs={cn3xxxTimerInstInit,/*devInstanceInit*/cn3xxxTimerInstInit2,/*devInstanceInit2*/cn3xxxTimerInstConnect/*devConnect*/};2.描述驱动支持的方法。LOCALstructvxbDeviceMethodcn3xxxTimerDrv_methods[]={DEVMETHOD(vxbTimerFuncGet,cn3xxxTimerFuncGet),{0,NULL}};3.提供驱动注册信息LOCALstructvxbDevRegInfocn3xxxTimerDrvRegistration={NULL,/*reservedforVxBususe*/VXB_DEVID_DEVICE,/*devID*/VXB_BUSID_PLB,/*busID=PLB*/VXB_VER_4_0_0,/*vxbVersion*/"cn3xxxTimerDev",/*drvName*/&cn3xxxTimerDrvFuncs,/*pDrvBusFuncs*/NULL/*pMethods*/NULL/*devProbe*/};。Vxwroks在启动过程中,将驱动与特定的硬件相连。voidvxbCn3xxxTimerDrvRegister(void){vxbDevRegister(&cn3xxxTimerDrvRegistration);}驱动在vxbus注册后,vxwroks使用驱动配置文件中的相关文件找到vxbus中注册的驱动函数的入口。特别说明VXBUS的驱动初始化过程在每一个驱动程序的最前面都可以看到,读者可以翻开intalldirection\target\src\hwif\不管是网络驱动还是其他的串口驱动,都可以首先看到驱动初始化相关的这四个函数。以下是风河文档的截屏这里有一些限制系统启动时iInstInit()由sysHwInit()调用。因为这个时候系统刚刚启动,堆的初始化还没完成。所以这里不能分配内存等。所以这里只是初步初始化,只能访问硬件存放器。在InstInit2()过程中,系统根本初始化完成,可以调用系统内核中的内核如信号量,可以使用malloc和free在堆中分配内存。添加vxbus驱动方法例程这个nicinstconnect是vxbus初始化的第三个步骤,直到这里才可以连接中断。添加vxbus驱动之后,要做的就是更新源文件中的名称〔name〕;Ingeneral,youcanchangeallotherroutinestoLOCAL.VxWorks操作系统接口介绍驱动如何是与操作系统接口的,即操作系统如何lauch驱动,如何把驱动添加到操作系统中的,如何管理分配内存资源的。通过操作系统中tNetTask任务完成的,开始由tNet0.取代。VxWorks如何lauch驱动系统启动后,系统执行任务tUsrRoot,处理以下事情初始化网络工作任务队列。执行tNetTask,处理网络工作队列上的条目〔item〕。调用muxDevLoad()加载网络驱动,把驱动装载到MUX层。〔之后有muxload调用endload〕调用muxDevStart()启动网络驱动。注册中断处理程序在endstart〔〕中调用sysIntConnect().。当muxload驱动时,它调用muxDevstart〔〕,然后调用endstart〔〕驱动入口点。使用tNetTask驱动操作系统直接使用网络驱动处理进来的包,直接将包分发处理交给应用程序,ThisoperationisdoneinthelowerhalfoftheOS,fromwithininterruptcontext.Therefore,muchofthenetworkstackisexecutedfromwithininterruptserviceroutines(ISRs).这个操作经常在低效率的操作系统中完成,由中断效劳函数完成。但是vxWorks是实时操作系统,ISR必须短,所以vxWorks没有使用长的ISR来处理包。因为这个原因,所有关于协议栈的包的处理,vxWroks都交给了tNettask来处理fromwithaISR。中断处理一旦接受到设备发送过来的中断,vxWorks立即唤醒之前注册的中断效劳函数执行,而且要尽快处理完成。所以这里中断效劳函数完成了最根本的事情:错误/状态改变。为了给包拒绝任务排队,ISR必须使用netjobAdd函数。使用tNetTask处理任务层次的网络处理。STATUSnetJobAdd(FUNCPTRroutine,/*routinetoaddtonetTaskworkqueue*/intparam1,/*firstargtoaddedroutine*/intparam2,/*secondargtoaddedroutine*/intparam3,/*thirdargtoaddedroutine*/intparam4,/*fourthargtoaddedroutine*/intparam5/*fifthargtoaddedroutine*/)中断处理往往提供三种功能,写驱动时必须注意处理接收中断。包发送出去后,将资源还给缓冲池。处理错误事件。如何添加网络接口驱动到vxWorks编译并include代码到vxWorksimage〔参考workbech使用方法或者内核编程〕。创立END驱动的配置表〔endDevTbl[]〕.信息,让MUX识别END驱动,往表里面添加具体的驱动信息,配置,要使用define包含某些信息。系统初始化过程中由usrNetInit()完成网络设备的初始化,默认情况下市自动调用的,所以宏定义中一般包含INCLUDE_NETWORK和INCLUDE_NET_INITsysDev.c,这个函数也要注意,包含驱动访问存放器相关定义及其代码。例如如果创立两种网络设备,一种支持bufferloaning,一种不支持。那么首先就必须修改中相关宏定义/*Parametersforloadingthedriversupportingbufferloaning.*/#defineLOAD_FUNC_0ln7990EndLoad#defineLOAD_STRING_0"0xfffffe0:0xffffffe2:0:1:1"#defineBSP_0NULL/*ParametersforloadingthedriverNOTsupportingbufferloaning.*/#defineLOAD_FUNC_1LOAD_FUNC_0#defineLOAD_STRING_1"0xffffee0:0xfffffee2:4:1:1"#defineBSP_1NULLEND_LOAD_FUNC确定驱动的入口点,例如如果你的驱动endLoad〔〕入口点是fei82557EndLoad(),,那么在必须做如下配置#defineEND_LOAD_FUNCfei82557EndLoadEND_LOAD_STRING传递给muxDevLoad的初始串参数。注意每一个END驱动的参数都不同,在写驱动的时候要仔细检查。编辑endTbl表中的信息,确保END驱动包含到镜像中。表在configNet.h中。END_TBL_ENTRYendTbl{{0,LOAD_FUNC_0,LOAD_STRING_0,BSP_0,FALSE},{1,LOAD_FUNC_1,LOAD_STRING_1,BSP_1,FALSE},{0,END_TBL_END,0,NULL},};注意这里的FALSE表示入口没有被处理。当系统成功加载了驱动,这里的FALSE将被改为TRUE。最后修改BSPconfig.hfiletodefineINCLUDE_END.这将告诉进程包含END驱动。当新的映像重新启动时,系统调用MuxDevLoad,完成相关设备的初始化。与END驱动有关的5中结构需要分配内存驱动控制结构END_Driver接收和发送描述符〔与DMA的操作有关,见文档〕相关列表Mblk,clblkClusterbuffers建立使用缓存来处理数据包mBlks,clBlks,andClusterBuffersvxWorks协议栈提供netBufLib,来管理内存,其使用的根本元素是mblk,clblk。Clusters包含mblk和clblk。我们称由mblk和clblk以某种方式相连的结构称为BufLib提供了两个重要函数netPoolCreate()创立一个网络池netPoolInit().风河强烈推荐开发者使用前者而非后者。通常的cluster大小是64,128,256,512,1024,2048。网络的最大传输单元(MTU)是1500字节。如何建立网络驱动池1.Allocatememoryforanetworkbufferconfigurationstructureandaddenoughspacetoalsohold8additionalbytesforthepDrvCtrl->pNetBufCfg->pNamefield.if(pDrvCtrl->pNetBufCfg=(NETBUF_CFG*)memalign(sizeof(long),(sizeof(NETBUF_CFG)+END_NAME_MAX))==NULL)return(ERROR);bzero(pDrvCtrl->pNetBufCfg,sizeof(NETBUF_CFG));2.InitializethepNamefield.pDrvCtrl->pNetBufCfg->pName=(char*)((int)pDrvCtrl->pNetBufCfg+sizeof(NETBUF_CFG));sprintf(pDrvCtrl->pNetBufCfg->pName,"%s%d","fei",pDrvCtrl->unit);3.Settheattributestobecached,cache-aligned,sharable,andISRsafe.pDrvCtrl->pNetBufCfg->attributes=ATTR_AC_SH_ISR;4.UseaNULLvaluetosetpDomaintokernel.ThisinstructsnetPoolCreate()toallocatememoryaccessibleinthekerneldomain.pDrvCtrl->pNetBufCfg->pDomain=NULL;5.SettheratioofmBlkstoclusters.pDrvCtrl->pNetBufCfg->ctrlNumber=pDrvCtrl->nClusters*10;6.UseaNULLvaluetosetthememorypartitionofmBlkstokernel.pDrvCtrl->pNetBufCfg->ctrlPartId=NULL;7.Fornow,setextramemorysizetozero.pDrvCtrl->pNetBufCfg->bMemExtraSize=0;8.Settheclustermemorypartitiontokernel,useNULL.pDrvCtrl->pNetBufCfg->bMemPartId=NULL;9.Allocatememoryforthenetworkclusterdescriptor.pDrvCtrl->pNetBufCfg->pClDescTbl=(NETBUF_CL_DESC*)memalign(sizeof(long),sizeof(NETBUF_CL_DESC));10.Initializetheclusterdescriptor.pDrvCtrl->pNetBufCfg->pClDescTbl->clSize=CLUSTER_SIZE;pDrvCtrl->pNetBufCfg->pClDescTbl->clNum=pDrvCtrl->nClusters*10;pDrvCtrl->pNetBufCfg->clDescTblNumEnt=1;11.CallnetPoolCreate()withthelinkpoolfunctiontable.if((pDrvCtrl->endObj.pNetPool=netPoolCreate((NETBUF_CFG*)pDrvCtrl->pNetBufCfg,_pLinkPoolFuncTbl))==NULL)return(ERROR);12.FreethepDrvCtrl->pNetBufCfgandpDrvCtrl->pNetBufCfg->pCIDescTbl.free(pDrvCtrl->pNetBufCfg->pClDescTbl);free(pDrvCtrl->pNetBufCfg);网络驱动中一种很重要的数据结构END_OBJtypedefstructend_object{NODEnode;/*rootofthedevicehierarchy*/DEV_OBJdevObject;/*accessesyourdevice’sctrlstruct*/FUNCPTRreceiveRtn;/*routinetocallonreception*/BOOLattached;/*indicatesunitisattached*/SEM_IDtxSem;/*transmittersemaphore*/longflags;/*variousflags*/structnet_funcs*pFuncTable;/*functiontable*/M2_INTERFACETBLmib2Tbl;/*MIBIIcounters*/structETHER_MULTI*pAddrList;/*headofthemulticastaddresslist*/intnMulti;/*numberofelementsinthelist*/LISTprotocols;/*protocolnodelist*/BOOLsnarfProto;/*issomeonesnarfingus?*/void*pMemPool;/*memorycookieusedbyMUXbufrmgr.*/M2_ID*pMib2Tbl;/*RFC2233MIBobjects*/}END_OBJ;这里这里的flag很有含义,说明网络的各种参数IFF_UP接口是开启的
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 品牌风格与消费者心理计划
- 西昌学院《平面广告设计与制作》2022-2023学年第一学期期末试卷
- 西北大学《数字图像处理实验》2023-2024学年第一学期期末试卷
- 西安邮电大学《现代邮政管理》2021-2022学年第一学期期末试卷
- 《时序逻辑电路小结》课件
- 项目7 7.1 主要农业气象灾害及防御(2)(课件)-《植物生产与环境》(高教版第4版)
- 视听语言(全彩微课版)课程思政案例库
- 《全新绿色商务罗盘》课件
- 贵州省贵阳市观山湖区2023-2024学年三年级上学期语文期末试卷
- 购买第三方服务的合同
- 智能环保监控施工合同
- 广东省惠州市2024-2025学年八年级上学期期中英语试卷
- 2024年度融资合同:创业公司Pre-A轮融资协议
- 《弘扬中华传统文化》课件
- 2024年河北省中考历史真题卷及答案解析
- 《重庆市建设工程施工现场安全资料管理规程》
- 产品质量知识培训课件
- 22G101三维图集解析
- 智能交通系统智慧树知到答案2024年山东大学
- 泛血管疾病抗栓治疗中国专家共识(2024版)
- (正式版)SHT 3225-2024 石油化工安全仪表系统安全完整性等级设计规范
评论
0/150
提交评论