Chinaunix首页 | 论坛 | 博客
  • 博客访问: 393240
  • 博文数量: 87
  • 博客积分: 1171
  • 博客等级: 少尉
  • 技术积分: 1068
  • 用 户 组: 普通用户
  • 注册时间: 2012-09-19 14:34
文章分类

全部博文(87)

文章存档

2014年(10)

2013年(24)

2012年(53)

我的朋友

分类: 嵌入式

2012-10-12 21:20:41

contiki 手册 (不全)

定义文档:

1.

 

PROCESS(hello_world_process, "Hello world process");


PROCESS_THREAD(hello_world_process, ev, data)
{

/*所有的C变量声明在ROCESS_BEGIN()之前完成。以后每次调度,都是从RPOCESS_BEGIN()开始执行了*/

 

/*这里有点问题,手册上说的是几个handler函数必须放在RPOCESS_BEGIN之前,我的是说有声明,再找找,确定下*/
  PROCESS_BEGIN();

  printf("Hello, world\n");
  
  PROCESS_END();
}

 

      先声明一个过程,然后开启一个线程,在线程里面,RPOCESS_BEGIN() 和 PROCESS_END必须出现,而且是成对出现的。

*

 

 

 

2  #define PROCESS_CONTEXT_BEGIN(p)

    #deine  PROCESS_CONTEXT_END(p);

  这两个宏可以实现process切换,一个process运行到某个地方,需要让另外一个process来运行时,调用这两个API。

 

 

3 #define PROCESS_EXITHANDLER(handler)

 

   当一个process退出的时候,会执行这个操纵,但是必须在PROCESS_BEGIN()之前声明。

    exithandler(void)

    {

    printf("Process exited\n");

   }  

 

   PROCESS_THREAD(example_exithandler,ev,data)

   {

     PROCESS_EXITHANDLER(exithandler());

      PROCESS_BEGIN();

      while(1)  {

    。。。。。

    }

   PROCESS_END();

}

 

 

4  #define PROCESS_POLLHANDLER(hander)

   这个API和 PROCESS_EXITHANDLER()类似,

 

 

5  #define PROCESS_PT_SPAWN(pt,thread)

    在当前process里面 spawn 一个新的线程。这个函数只能在protoThread里面调用,父protoThread只有在子线程执行完毕之后才能运行。

 

6 #define PROCESS_THREAD(name,ev,data)

 

       定义一个process的实体。

      这个宏用来定义一个process的实体(protoThread),这个process将会在任何事件发生的时候被调用,

 

 

 

7  #define PROCESS_WAIT_EVENT()

 #define PROCESS_WAIT_EVENT_UNTIL(c)     

   两个都是阻塞当前process直到一个事件发生,不过后者要求 c必须为真。

 

8:#define PROCESS_WAIT_UNTIL(c)

    等待一个条件发生。

    #define PROCESS_YIELD_UNTIL(c)

    阻塞当前运行的process 直到condition为真。

 

 

 

函数文档:

 

 1  process_event_t process_alloc_event(void)

     分配一个全局的事件号。

      在contiki中,事件号大于128的是全局事件号,可以从一个process中post到另一个process中,

 

2  CCIF void process_exit(struct process *p)

     终止一个process

 

     可以终止当前执行的process 以及当前运行process(我觉得currently running  类似与就绪的意思)

 

 3,void process_init(void)

 初始化一个process module,

 在main()函数里面被调用。

 

 

4   int process_nevents(void)

 

     返回当前等待被processed 的事件数目。

 

5  CCIF void process_poll(struct process *p)

 

      轮询process ,这个函数一般是在中断函数里面,引起一个process被轮询

 

6 CCIF int process_post(struct process *p,process_event_t ev,process_data_t data)

  

     post 一个同步事件

     post一个同步事件到一个或者多个processs ,处理此事件的操作将会在目标process被内核调度的时候被处理。一个事件可以被广播到所有的process,此时,所有的process都会被调度去处理这个事件。
       参数p ,可以是目标process 或者PROCESS_BROADCASE。

 

 

 

7void process_post_synch(struct process *p,process_event_t ev,process_data_t data)

 

投递一个同步事件到一个process。

 

 只在tcpip_input()中被应用。

 

 

8: int process_run(void)

  

  运行一次系统   -------调用poll 函数 并且处理一个事件

 

   这个函数应该被main()函数反复的调用来真正的运行contiki 操作系统,它会调用需要轮询的服务函数,然后处理一个事件,这个函数将会返回在事件队列里面等待处理的事件个数,以便当队列里面没有等待事件时,可以让cpu休眠。

 

 

 

9,void process_start(struct process *p ,char *arg)

   启动一个process。

   在process_post(),和PT_INIT里面被调用。

 

 

 

三;时间事件

      时间事件提供了一种参数时间的事件的方式(听上去有点绕口!!)

      

     当时间流逝到规定的值,将会有一个时间事件被投递到这个process。

     

 

 

     系统在时钟中断里面会调用的函数:

    

    void  etimer_request_poll(void)

             让时间时间感知时钟的变化        一般在时钟中断里面,当tick增加的时候,

    void  etimer_pending(void)

             查看是否有有过期的时间事件

 

     clock_timer_t etimer_next_expiration_time(void)

              得到下一个时间事件流逝的时间

 

 

 

      应用程序调用的函数接口:

      

       void etimer_set(struct etimer *et,clock_timer_t interval)

          设置一个时间事件

      void etimer_reset(struct etimer *et)

          重置一时间事件,以先前设置的时间间隔

       void  etimer_restart(struct etimer *et)

          重新开始一个时间事件,从当前的时间点 

 

         void etimer_adjust(struct etimer *et int timediff)

        调整一个时间事件的间隔时间

    

         int  etimer_expired(struct etimer *et)

        检查是时间事件是否超时

      

        clock_time_t  etimer_expiration_time(struct etimer*et)

       得到当前时间事件流逝的时间

        clock_time_t etimer_start_time(struce etimer *et)

       得到时间事件的起始时间

 

       void  etimer_stop(struct etimer *et)

       停止挂起的时间事件 

  

 

四:Argument buffer

    

      argument buffer 是静态分配的,全局的,任何process都可以访问的。

     

     函数:

       char *arg_alloc(char size)

        分配一个argument buffer

       arg_free(char *arg)

       回收....

      

       arg_alloc 分配不能超过128字节。

       arg_free  回收空间。如果给予的是其他指针,也是安全的。

 

  五:contiki program loader

         contiki program loader 适用于装载和开启程序的一个抽象接口。

 

 

    模型: The contiki  ElF  loader

      contiki program loader 链接,重定位,装载ELF格式的目标文件到一个正在运行的contiki系统。

    

     数据结构:  struct dsc

     

    定义:#define DSC(dscname,description,prgname,process,icon) CLIF const struct dsc dscname={ description,prgname,icon}

 

      The program description  structure

     DSC 结构是用来描述程序的,它包括一个描述程序的串,在硬盘上文件的名字,一个位图图标,还有一个文本版的同样的icon。

   DSC被保存在一个可以被程序加载的文件里,如“Directory”应用,它读取所有的硬盘上的所有DSC文件,并且呈现出一个图标和描述在一个窗口里。

 

     

 

 

六:protothread semaphores

        

      定义了一组信号量操作,值得注意的是,所有的信号量相关数据要声明为全局的变量,protoThread是不保存局部变量的。

 

 

七: 时钟库

      

    时钟库是介于contiki和平台特定时钟功能的接口。

   

    时钟库实现了一个简单功能:衡量时间,另外,时钟库提供了一个宏,CLOCK_SECOND,代表一秒的系统时间。

   

    时钟库很多时候并不是直接使用的,而是在时间事件和时间库里面会用到。

 

    void clock_init(void)

   初始化时钟库,在main()函数里面调用。

    

    clock_time_t clock_time(void)

   得到当前的时钟时间,单位是ticks,

 

八:多线程库

 

     基于事件驱动的contiki核不直接支持多线程,而是将可抢占的多线程被设计为一个库,是可选择的部分链接到应用上去。

    这个库有两部分组成,平台无关的部分,对于所有的平台都是一样的;和平台相关的部分,这部分必须根据平台编写,才能使多线程运行。

 

    函数: void mt_init(void)

             初始化多线程库

               void  mt_remove(void)

               卸载和清空 库

       

              void mt_start(struct mt_thread *thread,void(*function)(void*),void *data)

          开启一个多线程

 

         void mt_exec(struct mt_thread *thread)

           执行部分现成???

         void mt_yield(void)

          自愿的放弃处理器

          void mt_exit(void)

           线程退出

          void mt_stop(struct mt_thread *thread)

          停止一个线程。

 

 

   void mt_exec(struct mt_thread *thread)

   

    这个函数被contiki process 调用去执行一个线程,这个函数不会返回直到线程退出或者被抢占。

 

 

 九:   Architecture support  for multi-threading

      contiki 的多线程库需要一些architecture specific 支持去seting up 和切换栈,这种支持需要四个栈操作函数:

       mtarch_start():为一个新线程开辟栈结构

       mtarch_exec():  在一个线程的栈里面切换

       mtarch_yield(): 在一个线程栈里面恢复内核栈

       mtarch_stop(): 清空一个线程的栈

     

      另外,两个控制抢占的函数必须实现:

      mtarch_pstart()  和 mtarch_pstop(),如果不需要抢占,这两个函数可以被实现为空函数,最后mtarch_init() 被mt_init()调用。并且可以用于初始化时钟中断??or any other mechanisms required for correct operation of the architecture specific support funcions while mtarch_remove()is called by mt_remove() to clean up those resources.

  

  

         函数: void mtarch_init(void)

         为多线程初始化相应的architecture specific support functions

          

               void mtarch_remove(void)

               卸载函数库并清空

               mtarch_start(struct mtarch_thread *thread,void(*function)(void*data),void *data)

              当线程开始的时候,为其setup 栈结构

 

              void mtarch_exec(struct mtarch_thread*thread)

              开始执行一个线程

              void  mtarch_yield(void)

              放弃cpu

              void mtarch_stop(struct mtarch_thread *thread)

              清空一个线程的栈空间

  

 

 

           函数文档:

       void mtarch_exec(struct mtarch_thread *thread)

       启动一个线程

       这个函数被mt_exec()调用,开启一个多线程服务,这个函数应该切换线程的栈,并且不会返回直到明确的调用yielded( mt_yield())或者直到被抢占。

 

       

         void mtarch_init(void)

         mt_init() 调用此函数,

    

        。。。。。。。

        多线程函数库提供的是接口,下面是需要自己实现的部分,这些接口会调用你实现的部分,这个多线程函数库的构架。

 

 

十:EEPROM API 

 

      EEPROM API 为EERPOM access on contiki platforms 提供了一个通用的接口。

     一个带有EERPOM的平台必须实现这些API。

      

     函数:

     void eeprom_write(eeprom_addr_t addr,unsigned char *buf,int size)

      向EEPROM 写入buffer

     void eeprom_read(eeprom_addr_t addr,unsigned char *buf,int size)

      从EEPROM中读取数据

     void eeprom_init(void)

     初始化EEPROM 模型

 

 

十一:Radio API

      无线模型定义了一些了的函数,无线设备驱动必须要实现的。

 

 

十二:contiki ELF loader

     

        contiki ELF loader  链接 、重定位、装载ELF 目标文件到一个运行的contiki系统中。

        

     一个ELF文件包含了一个单独可执行文件或者一个编程模型。这个文件包含了程序代码和程序数据,还有一些信息关于怎样连接 重定位 装载 这个程序到运行的系统中。

 

  ELF文件是由一系列的域组成的,包括 代码域  数据域  重定位信息 也包括一些调试信息。

 

  为了连接和重定位一个ELF文件,contiki ELF loader 首先擦除ELF文件结构去找到合适ELF域,然后分别为程序代码和数据在ROM和RAM上分配内存,分配内存后,contiki ELF loader开始重定位ELF文件中的代码。

 

    

     函数:elfloader_init(void)

               elfloader 初始化函数

               elflooader_load(int fd)

              装载和重定位一个ELF文件。此ELF文件必须用cfs_open()打开。

 

   

 

十三:architecture specific functionality for the ELF loader

 

    The architecture specific functionality for the ELF loader has to be implemented for each processor type contiki runs on.

 

     由于ELF格式对不同的处理器有细微的差别,contiki的ELFloader分成两部分,

真正的ELF装载器模型 和与结构相关的部分。与体系结构相关的部分来处理内存分配,代码和数据重定位,将重定位的ELF代码写到代码空间。

     将contiki的ELF 装载移植到新的处理器,这个部分是必须实现的。

 

     函数: void *elfloader_arch_allocate_ram(int size)

                 allocate RAM for a new module

    

                 void *elflloader_arch_allocate_rom(int size)

                 allocate program memory for a new module.

 

                 void  elfloader_arch_relocate(int fd,unsigned int sectionoffset,char *sectionaddr,struct elf32_rela *rela,char *ddr)

                  实现重定位。

            

                 void elfloader_arch_write_rom(int fd,unsigned short textoff,unsigned int size,char *mem)   

                 写入只读内存(如代码段)

 

  

      函数文档:

     void *elfloader_arch_allocate_ram(int size)

     为新的模型分配RAM空间

     这个函数被contiki ELF loader 调用为模型的装入分配RAM空间 。

    

     void *elflloader_arch_allocate_rom(int size)

 

      这个函数被contiki ELF loader 调用为模型的装入分配ROM空间

 

 

         void  elfloader_arch_relocate(int fd,unsigned int sectionoffset,char *sectionaddr,struct elf32_rela *rela,char *ddr)

         contiki ELF loader 调用此函数为代码或数据实现重定位。重定位的地址是由contiki ELF loader 根据ELF文件中的信息计算出来的。

        这个函数的职责是patch 执行代码,contiki 传递一个指针到ELF32结构,这个结构包含了怎样去patch 代码的信息,这些信息在不同的处理器上是不同的。

 

         void elfloader_arch_write_rom(int fd,unsigned short textoff,unsigned int size,char *mem)  

        contiki ELF loader 调用这个函数将代码段写到内存空间,这个函数是当所有的重定位完成的时候才调用的。

 

 

 

十四:ProtoThread

         ProtoThread 是一中轻量级无栈线程,示威内存严重受限的系统设计的,如deeply 嵌入式系统,或者传感器网络节点。

         ProtoThread为事件驱动的系统提供了线性的代码执行,ProtoThread可以在有和没有RTOS的情况下使用。

         ProtoThread 是种极端轻量级,无栈的线程 ,它能提供一个阻塞的切换在事件驱动机制的系统上,不需要在每个任务栈上,ProtoThread的目的是实现一系列连续的操作在没有付诸的状态机的情况下或full multi-threading  ,protoThread提供了条件阻塞。

         

        处在一个纯的事件驱动的系统上的ProtoThread优势是:它提供了连续的代码结构运行阻塞功能,在纯的事件驱动机制系统上,阻塞必须手动的实现通过将函数分成两半。一半是阻塞前部分,另一半是用于阻塞后调用。这使得使用控制结构如if() 条件 和 while()循环很难实现。

        ProtoThread 优越于普通线程在于:它不需要一个单独的栈,在资源受限的系统里,分配多个任务栈会消耗掉很多可用的内存空间,相反,每个protoThread只需要2到12字节,依据不同的体系结构。

        主要特点:

          没有与体系结构相关的代码,是纯C实现的

          不要是使用error-prone(易于出错) 函数,如:longjmp()

          使用很少ram空间,每个protoThread只需要2个字节

          可用于有或无 OS的场所

          Provides blocking wait without full multi-thread or stack-switch

    

       

          protoThread  API由四个基本的操作组成:

   初始化:PT_INIT();

          执行:    PT_BEGIN();

          条件阻塞:PT_WAIT_UNTIL()

          退出:     PT_END()

           在这几个操作之上,产生了两个方便的函数,reversed 条件阻塞 PT_WAIT_WHILE(),和protoThread 阻塞 PT_WAIT_THREAD()

   

          所有的protoThread运行在同一个栈上,protoThread之间的切换是通过栈的rewinding(回卷)实现的,((应该是压栈,弹栈实现的))。

         

          一个protoThread在运行在一个单独的c函数里面,不能跨越到其他函数里面。一个protoThread可以调用普通的c函数,但是不能阻塞在里面,Blocking inside nested function call is instead made by spawping a separate protothread for each potentially blocking function.这样做的优势是阻塞是很明确的:程序确切的知道哪些函数是阻塞的,哪些是不阻塞的。

 

           protoThreads  类似与非对称的协程,主要的不同点在于协程为每个协程分配一个单独的栈。而protoThread是没有栈的。

 

     

 

调度部分:

        protoThread 是由它所在的函数里面反复调用驱动起来的。每次函数被调用,这个protoThread就会运行,直到它被阻塞或者退出,protoThread的调度是由应用程序使用protoThread完成的。

 

实现:

      protoThread 是用local   continuations 实现的。一个 local continuation 代表在程序里面一个特定的执行状态,但是不提供任何调用历史和局部变量。一个local continuation 可以被设置在特定的函数里面去捕获这个函数的状态。在一个local continuation被设置后,可以被唤醒,去恢复到local continuation 被设置地方的状态。

    

      local continuation 可以使用多种方式实现:

      1,使用与机器相关的汇编代码

      2,使用标准的c结构

      3,使用编译器扩展 (by using compiler  externsions)

   

      第一种方法通过保存和恢复处理器状态,除了堆栈指针外,每个protoThread还需要16到32字节的内存空间,准确需要的内存大小是由体系结构决定的。

      

       标准C实现,每个protoThread需要两个字节state .利用c switch() 声明以一种不明显的方式,然而这种方式将会对代码产生一点限制:在使用protoThread的代码里面,不能使用switch()声明它本身。(????)

       特定的编译器有C扩展性,GCC支持label pointers 可用于这个目的,通过这种方式,每个protoThread需要4个字节。

      

 

 

         初始化:  #define  PT_INIT(pt)

                          初始化protoThread

        

                          #define  PT_THREAD(name_args)

                            声明一个protoThread

                           #define PT_BEGIN(pt)

                           声明一个里面包含c函数的protoThread的起始。

                           #define  PT_END(pt)

      

                           阻塞等待:

                           #define PT_WAIT_UNTIL(pt,condition)

                            阻塞等待直到条件为真。

                            #define PT_WAIT_WHILE(pt,cond)

                            当条件为真时,阻塞等待。

                            

                            分层 protoThreads:

                            #define PT_WAIT_THREAD(pt,thread)

                            阻塞等待直到子protoThread完成
                            #define PT_SPAWN(pt,child,thread)

                            卵生一个子线程,并等待直到它退出。

 

 

                            退出和重启:

                            #define PT_RESTART(pt)

                            重启一个protoThread

                            #define PT_EXIT(pt)

                            退出protoThread

 

                            调用一个 protoThread                            

                            #define PT_SCHEDULE(f)

                            调度一个protoThread

 

                            yielding from a protothread

                           #define PT_YILELD(pt)

                           yield  当前protoThread

                             #define PT_YIELD_UNTIL(pt,cond)

                            yield  当前线程直到条件发送。

 

 

                            #define PT_RESTART(pt)

                            这个宏将会阻塞并导致当前运行的protoThread 重新从PT_BEGIN()处执行。

                            #define PT_SECHEDULE(f)

                             调度一个protoThread,返回非零表示protoThread在运行,0 表示protoThread已经退出。

 

 

 

 

十五:contiki文件系统接口

          contiki 文件系统接口定义了一组抽象的API为读取目录 读取文件和写文件。

          CFS API   接口比较简单,根据POSIX  file API 为模型,做了少量的改变。

 

         函数:

        CCIF int    cfs_open(const char *name,int flags)

        CCIF void cfs_close(int fd)

        CCIF int    cfs_read(int fd,char *buf,unsigned int len)

        CCIF int    cfs_wirte(int fd,char *buf,unsigned int len)

        CCIF int    cfs_seek(int fd, unsigned int offset)

        CCIF int    cfs_opendir(struct cfs_dir *dirp,const,char *name)

         为读取目录项打开目录。

       CCIF int   cfs_closedir(struct cfs_dir *dirp)

 

 

十六:CTK application functions

 

            对此不了解,先略过

 

十七: Timer  library

         contiki 内核不为timed tevents 提供支持。

         而是,当一个应用需用使用timers,需要明确的使用timer library

       

       timer— library  提供了 设置 重置  重启 定时器,已经测试一个定时器是否超时的函数,应用程序必须手动的检测它的定时器是否超时,而不是自动检测的。

     

十八:uip 配置函数

 

十九:Protosocket library

           protoSocket library 为uIP提供了一个接口,类似与传统的BSD套接字接口。不想普通的uip 事件驱动接口,使用protoSocket library 的程序 可以连续的执行,而不必有明确的状态机。

          protoSocket 只工作在TCP连接中。

          protoSocket 使用Protothreads protothreads 提供连续的控制flow,这使得protosocket 在内存方面是轻量级的,并且继承了protothread 有限的功能。每个protosocket lives only within a single function block。Automatic variables (stack variables) are not necessarily retained across a protosocket library function call.

 

        由于protosocket library 使用了protothread,局部变量will not always be saved across a call to a protosocket library function ,所以在处理局部变量时要特别小心。

      

         protosocket library 为发送数据提供了一些函数,使得其不用考虑重传和确认,以及读取数据的函数,不用考虑数据的TCP分段。

        由于每个protosocket 都是作为一个protothread来运行,protosocket 需要调用PSOCK_BEGIN()在函数的开始的部分,同样,在结束的时候需要调用PSOCK_EXIT();

 

 

 

{

小结:process  protosocket 都是使用protothread 来实现的。

#define PSOCK_BEGIN(psock) PT_BEGIN(&((psock)->pt))  

}

 

 

二十: 匿名尽最大努力交付 本地广播

 

   

 

       未完,东西有点多,看了这么多还有很多没有理解,先弄懂了再继续。

 

 

 

阅读(5360) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~