Chinaunix首页 | 论坛 | 博客
  • 博客访问: 26862
  • 博文数量: 12
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 82
  • 用 户 组: 普通用户
  • 注册时间: 2015-11-30 14:36
文章分类

全部博文(12)

文章存档

2016年(7)

2015年(5)

我的朋友

分类: 嵌入式

2016-09-11 18:08:54

一 main函数

点击(此处)折叠或打开

  1. #include "app_uart_fifo.h"
  2. #include <stdint.h>
  3. #include <stdio.h>
  4. #include <sys/process.h>
  5. #include <sys/procinit.h>
  6. #include <etimer.h>
  7. #include <sys/autostart.h>
  8. #include <clock.h>
  9. #include "bsp_imp.h"

  10. static void CtimerTest_Callback(void *p)
  11. {
  12.         printf("Ctimer Callback running\r\n");
  13. }



  14. static process_event_t event_data_ready;

  15. PROCESS(print_hello_process, "Hello");
  16. PROCESS(print_world_process, "world");

  17. AUTOSTART_PROCESSES(&print_hello_process, &print_world_process);


  18. PROCESS_THREAD(print_hello_process, ev, data)
  19. {
  20.         PROCESS_BEGIN();
  21.         static struct etimer timer;
  22.         
  23.         etimer_set(&timer, CLOCK_CONF_SECOND*5);
  24.         printf("***print hello process start***\r\n");

  25.         event_data_ready = process_alloc_event();
  26.         while (1)
  27.         {
  28.                 
  29.                 PROCESS_WAIT_EVENT_UNTIL(ev == PROCESS_EVENT_TIMER);

  30.                 printf("Hello\r\n");

  31.                 process_post(&print_world_process, event_data_ready, NULL);

  32.                 etimer_reset(&timer);
  33.         }

  34.         PROCESS_END();
  35. }

  36. PROCESS_THREAD(print_world_process, ev, data)
  37. {
  38.         PROCESS_BEGIN();

  39.         printf("***print world process start***\r\n");
  40.         

  41.         while (1)
  42.         {
  43.                 PROCESS_WAIT_EVENT_UNTIL(ev == event_data_ready);
  44.                 printf("world\r\n");
  45.         }

  46.         PROCESS_END();
  47. }


  48. unsigned int idle_count = 0;

  49. int main()
  50. {
  51.         Bsp_Init();
  52.         printf("Initialising\r\n");

  53.         clock_init();
  54.         
  55.         ctimer_init();
  56.         
  57.         process_init();
  58.         process_start(&etimer_process, NULL);
  59.         autostart_start(autostart_processes);
  60.         printf("Processes running\r\n");
  61.         
  62.         while(1) {
  63.                 do {
  64.                         
  65.                 } while(process_run() > 0);
  66.                 idle_count++;
  67.         }
  68. }
main函数创建两个进程,print_hello_process进程定时5S打印hello,同时发送事件给print_world_process打印world,并重启etimer定时器。

二 数据结构

2.1 进程数据结构

进程的数据结构为链表,代码中所有的进程使用进程链表管理。

点击(此处)折叠或打开

  1. struct process {
  2.   struct process *next;
  3. #if PROCESS_CONF_NO_PROCESS_NAMES
  4. #define PROCESS_NAME_STRING(process) ""
  5. #else
  6.   const char *name;
  7. #define PROCESS_NAME_STRING(process) (process)->name
  8. #endif
  9.   PT_THREAD((* thread)(struct pt *, process_event_t, process_data_t));
  10.   struct pt pt;
  11.   unsigned char state, needspoll;
  12. };
next 指向下一进程控制块,name为进程名,thred为进程的实体(函数指针),pt保存该进程执行的行数,实现进程切换,state为进程的运行状态,needpoll为进程的优先级。
进程创建完成后,需要其运行需要调用process_start,将进程控制块,挂载到进程链表中。注意每次挂载,从头开始挂载。


2.2 etimer数据结构

etimer也是用时间列表管理,结构代码如下。

点击(此处)折叠或打开

  1. struct etimer {
  2.   struct timer timer;
  3.   struct etimer *next;
  4.   struct process *p;
  5. };
  6. struct timer {
  7.   clock_time_t start;
  8.   clock_time_t interval;
  9. }
由timer确定定时时间,next指向下一个etimer节点,p为绑定与etimer相关联的任务,在contiki中谁调用etimer_set函数,该进程绑定到p.
用户调用etimer_set -> add_timer将etimer挂载到时间管理链表,并将etimer与该进程关联起来,该链表的插入也是从头开始插入。

main函数启动一个etimer定时器,初始化后链表如下,

2.3 evt 事件结构


点击(此处)折叠或打开

  1. struct event_data {
  2.   process_event_t ev;
  3.   process_data_t data;
  4.   struct process *p;
  5. };
ev为产生的事件,data产生事件所带的数据, p绑定获取该事件的进程。时间事件也是一个事件。事件管理使用一个环形FIFO队类管理,nevents表示队列里事件的总数(放入事件++,取出事件--),fevent表示取事件时下一个事件的下标(取事件++)。process_post_synch()向事件队列里发送一个事件,do_event()从事件队列中取出事件并处理绑定的进程。

2.3.1 广播事件

在事件中,会绑定获取该事件进程的指针,如果未绑定进程指针,则该事件是广播事件,所谓广播事件是所有进程均会获取该事件,所有进程均执行该事件。


点击(此处)折叠或打开

  1. if(receiver == PROCESS_BROADCAST) {
  2.       for(p = process_list; p != NULL; p = p->next) {

  3.     /* If we have been requested to poll a process, we do this in
  4.      between processing the broadcast event. */
  5.     if(poll_requested) {
  6.      do_poll();
  7.     }
  8.     call_process(p, ev, data);
  9.       }
  10.     }

2.4 进程,时间事件,事件关系

在contiki中etimer也会触发一个时间事件,在本工程中,etimer的数据结构如下,绑定该等待定时器事假的进程,这个etimer绑定print_hello_process进程。

当定时时间到,etimer进程调用process_post_synch将定时事件和绑定进程发送到事件队列,事件队列结构如下:
主函数通过do_event获取事件队列的事件,通过函数指针执行进程。


三 进程执行描述

process_start -> process_post_synch -> call_process(该函数中调用函数指针p->thread,执行具体的线程)。下面以etimer中的etimer_process线程分析。

点击(此处)折叠或打开

  1. PROCESS_THREAD(etimer_process, ev, data)
  2. {
  3.   struct etimer *t, *u;
  4.     
  5.   PROCESS_BEGIN();

  6.   timerlist = NULL;
  7.   
  8.   while(1) {
  9.     PROCESS_YIELD();

  10.     if(ev == PROCESS_EVENT_EXITED) {
  11.       struct process *p = data;

  12.       while(timerlist != NULL && timerlist->p == p) {
  13.     timerlist = timerlist->next;
  14.       }

  15.       if(timerlist != NULL) {
  16.     t = timerlist;
  17.     while(t->next != NULL) {
  18.      if(t->next->p == p) {
  19.      t->next = t->next->next;
  20.      } else
  21.      t = t->next;
  22.     }
  23.       }
  24.       continue;
  25.     } else if(ev != PROCESS_EVENT_POLL) {
  26.       continue;
  27.     }

  28.   again:
  29.     
  30.     u = NULL;
  31.     
  32.     for(t = timerlist; t != NULL; t = t->next) {
  33.       if(timer_expired(&t->timer)) {
  34.     if(process_post(t->p, PROCESS_EVENT_TIMER, t) == PROCESS_ERR_OK) {
  35.     
  36.      /* Reset the process ID of the event timer, to signal that the
  37.      etimer has expired. This is later checked in the
  38.      etimer_expired() function. */
  39.      t->p = PROCESS_NONE;
  40.      if(u != NULL) {
  41.      u->next = t->next;
  42.      } else {
  43.      timerlist = t->next;
  44.      }
  45.      t->next = NULL;
  46.      update_time();
  47.      goto again;
  48.     } else {
  49.      etimer_request_poll();
  50.     }
  51.       }
  52.       u = t;
  53.     }
  54.     
  55.   }
  56.   
  57.   PROCESS_END();
  58. }
每次进入线程均要从PROCESS_BEGIN开始执行,该函数实现跳转功能,可以跳转到上次被打断点执行。该线程第一次运行到PROCESS_YIELD处会被挂起,该宏展开如下:

点击(此处)折叠或打开

  1. #define PT_YIELD(pt)                \
  2.   do {                        \
  3.     PT_YIELD_FLAG = 0;                \
  4.     LC_SET((pt)->lc);                \
  5.     if(PT_YIELD_FLAG == 0) {            \
  6.       return PT_YIELDED;            \
  7.     }                        \
  8.   } while(0)
第一次运行PROCESS_YIELD时,根据上面代码分析会return PT_YIELDED,此时该线程运行结束,函数被挂起,并保存此次运行的位置,本次保存到LC_SET((pt)->lc);。下次再运行etimer_process,运行原因为:SysTick_Handler -> etimer_request_poll -> process_run() -> do_poll() -> call_process() -> p->thread(函数指针,指向etimer_process)。本次运行依旧从PROCESS_BEGIN开始运行,并跳转到第一次运行保存的位置。在 if(PT_YIELD_FLAG == 0)判断为假,函数继续执行(在PROCESS_BEGIN中将PT_YIELD_FLAG 置1)。在etimer_process,先判断事件类型,如果是退出事件类型,则将与该事件有关的定时器移除;在again后表示是定时时间到,将该定时器PROCESS_EVENT_TIMER放入事件队列,放入的信息包括事件类型,进程指针,在主函数查询事件队列,取出进程指针执行。例如当定时时间到执行print_hello_process进程。print_hello_process进程执行后,向事假队列post事件,该事件post给print_world_process进程。主函数 process_run() -> do_poll() -> call_process() -> p->thread执行print_world_process进程。

四 etimer注意事项

4.1 事件

contiki事件包含以下事件,包含定义事件的最大数目等,该部分可参看http://blog.chinaunix.net/uid-9112803-id-2976348.html

点击(此处)折叠或打开

  1. #ifndef PROCESS_CONF_NUMEVENTS
  2. #define PROCESS_CONF_NUMEVENTS 32
  3. #endif /* PROCESS_CONF_NUMEVENTS */

  4. #define PROCESS_EVENT_NONE 0x80
  5. #define PROCESS_EVENT_INIT 0x81
  6. #define PROCESS_EVENT_POLL 0x82
  7. #define PROCESS_EVENT_EXIT 0x83
  8. #define PROCESS_EVENT_SERVICE_REMOVED 0x84
  9. #define PROCESS_EVENT_CONTINUE 0x85
  10. #define PROCESS_EVENT_MSG 0x86
  11. #define PROCESS_EVENT_EXITED 0x87
  12. #define PROCESS_EVENT_TIMER 0x88
  13. #define PROCESS_EVENT_COM 0x89
  14. #define PROCESS_EVENT_MAX 0x8a


etimer 哪一个进程调用etimer_set在etimer管理中就绑定该进程,如果在main函数中调用,则绑定为NULL,可时间广播方式。
阅读(397) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~