您的位置:首页 > 其它

CC2538之Contiki3.0实验:3-event

2016-01-11 16:35 204 查看
通过对PEOCESS的一些乱讲,应该有一点可以知道就是我们每编写一个PROCESS_THREAD(...)实际就是弄出了一个 (struct)process;大家可以理解是不是每一个[b]PROCESS_THREAD或者其他的都会在cmpile的时候产生一个全局的struct变量;回忆一下:[/b]

struct process {  
  struct process *next;  
#if PROCESS_CONF_NO_PROCESS_NAMES  
#define PROCESS_NAME_STRING(process) ""  
#else  
  const char *name;  
#define PROCESS_NAME_STRING(process) (process)->name  
#endif  
  PT_THREAD((* thread)(struct pt *, process_event_t, process_data_t));  
  struct pt pt;  
  unsigned char state, needspoll;  
};


至此我们至少可以CTRL+C/CTRL+V写出自己的小的测试程序,我们不管是学习TinyOS或者Contiki实际并不是只是make然后下载,验证结果就完事了,应该掌握代码的编写;鱼和渔的基本区别是我写这些文档的意义所在;

TinyOS和Contiki都是event驱动;RIOT在Contiki介绍完后会重点去介绍;个人还是比较喜欢他的风格一点;


回忆TinyOS的event是很简单的,采用signal抛出事件,使用者处理;

Contiki的event咱们慢慢来看;我们现在在test_null基础上再编写一次,达到事件处理的目的;

首先在:core/sys/process.h中:

typedef unsigned char process_event_t;
typedef void *        process_data_t;
typedef unsigned char process_num_events_t;


我们这次需要用到的函数为:

process_post

在core/sys/process.c中


int
process_post(struct process *p, process_event_t ev, process_data_t data)
{
  static process_num_events_t snum;

  if(PROCESS_CURRENT() == NULL) {
    PRINTF("process_post: NULL process posts event %d to process '%s', nevents %d\n",
	   ev,PROCESS_NAME_STRING(p), nevents);
  } else {
    PRINTF("process_post: Process '%s' posts event %d to process '%s', nevents %d\n",
	   PROCESS_NAME_STRING(PROCESS_CURRENT()), ev,
	   p == PROCESS_BROADCAST? "<broadcast>": PROCESS_NAME_STRING(p), nevents);
  }
  
  if(nevents == PROCESS_CONF_NUMEVENTS) {
#if DEBUG
    if(p == PROCESS_BROADCAST) {
      printf("soft panic: event queue is full when broadcast event %d was posted from %s\n", ev, PROCESS_NAME_STRING(process_current));
    } else {
      printf("soft panic: event queue is full when event %d was posted to %s from %s\n", ev, PROCESS_NAME_STRING(p), PROCESS_NAME_STRING(process_current));
    }
#endif /* DEBUG */
    return PROCESS_ERR_FULL;
  }
  
  snum = (process_num_events_t)(fevent + nevents) % PROCESS_CONF_NUMEVENTS;
  events[snum].ev = ev;
  events[snum].data = data;
  events[snum].p = p;
  ++nevents;

#if PROCESS_CONF_STATS
  if(nevents > process_maxevents) {
    process_maxevents = nevents;
  }
#endif /* PROCESS_CONF_STATS */
  
  return PROCESS_ERR_OK;
}


下面修改test_null.c文件

#include "contiki.h"
#include "dev/leds.h"

static process_event_t event_xxoo;

PROCESS(test_null, "我是菜鸟");
PROCESS(test_event, "我还是菜鸟");
AUTOSTART_PROCESSES(&test_null, &test_event);

PROCESS_THREAD(test_null, ev, data)
{
  PROCESS_BEGIN();
  event_xxoo = process_alloc_event();
  process_post(&test_event, event_xxoo, NULL);
  PROCESS_END();
}

PROCESS_THREAD(test_event, ev, data)
{
  PROCESS_BEGIN();

  PROCESS_WAIT_EVENT_UNTIL(ev == event_xxoo);
  leds_on(LEDS_ALL);

  PROCESS_END();
}


看到不认识的家伙了 process_alloc_event();

在core/sys/process.c中:


process_event_t
process_alloc_event(void)
{
  return lastevent++;
}

PROCESS_WAIT_EVENT_UNTIL在core/sys/process.h中:

#define PROCESS_YIELD_UNTIL(c)      PT_YIELD_UNTIL(process_pt, c)
#define PROCESS_WAIT_EVENT_UNTIL(c) PROCESS_YIELD_UNTIL(c)


PT_TIELD_UNTIL在core/sys/pt.h中:

<pre name="code" class="cpp">#define PT_YIELD_UNTIL(pt, cond)		\
  do {						\
    PT_YIELD_FLAG = 0;				\
    LC_SET((pt)->lc);				\
    if((PT_YIELD_FLAG == 0) || !(cond)) {	\
      return PT_YIELDED;			\
    }						\
  } while(0)




我们的设计思想是,test_null抛出事件,test_event获取该事件后亮灯,编译烧写到板子进行一下测试:

烧写到cc2538cb节点后,contiki-main先将三个led灯fade,流水灯效果;然后咱们发现三个led灯点亮了

说明test_event的leds_on(LEDS_ALL);得到了执行,事件的测试OK;貌似现在也只是最基础的写法测试

在此大家可以再去想一下Contiki的thread模型,PROCESS_WAIT_EVENT_UNTIL到底干了什么?


Contiki是否支持咱们回溯事件的抛出者是谁?

有一个例程我们最好去学习参考,以便以后写出自己的应用,那就是er_timer;可以参考2530的代码或者cc2538cb目录下的blink_hello.c

#include "contiki.h"
#include "dev/leds.h"

#include <stdio.h> /* For printf() */
/*---------------------------------------------------------------------------*/
static struct etimer et_hello;
static struct etimer et_blink;
static uint16_t count;
static uint8_t blinks;
/*---------------------------------------------------------------------------*/
PROCESS(hello_world_process, "Hello world process");
PROCESS(blink_process, "LED blink process");
AUTOSTART_PROCESSES(&hello_world_process, &blink_process);
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(hello_world_process, ev, data)
{
  PROCESS_BEGIN();

  etimer_set(&et_hello, CLOCK_SECOND * 4);
  count = 0;

  while(1) {
    PROCESS_WAIT_EVENT();

    if(ev == PROCESS_EVENT_TIMER) {
      printf("Sensor says #%u\n", count);
      count++;

      etimer_reset(&et_hello);
    }
  }

  PROCESS_END();
}
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(blink_process, ev, data)
{
  PROCESS_BEGIN();

  blinks = 0;

  while(1) {
    etimer_set(&et_blink, CLOCK_SECOND);

    PROCESS_WAIT_EVENT_UNTIL(ev == PROCESS_EVENT_TIMER);

    leds_off(LEDS_ALL);
    leds_on(blinks & LEDS_ALL);
    blinks++;
    printf("Blink... (state %0.2X)\n", leds_get());
  }

  PROCESS_END();
}
/*---------------------------------------------------------------------------*/
其中的代码可以自己去阅读,参考process阅读;我们看到两种事件等待的写法:

1;

PROCESS_WAIT_EVENT();
if(ev == PROCESS_EVENT_TIMER){
...
}


2;

PROCESS_WAIT_EVENT_UNTIL(ev == PROCESS_EVENT_TIMER);


这些都不重要,那么我们来看一下 PROCESS_EVENT_TIMER这个东东,在core/sys/er_timer.h中

PROCESS_THREAD(etimer_process, ev, data)
{
  struct etimer *t, *u;
	
  PROCESS_BEGIN();

  timerlist = NULL;
  
  while(1) {
    PROCESS_YIELD();

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

      while(timerlist != NULL && timerlist->p == p) {
	timerlist = timerlist->next;
      }

      if(timerlist != NULL) {
	t = timerlist;
	while(t->next != NULL) {
	  if(t->next->p == p) {
	    t->next = t->next->next;
	  } else
	    t = t->next;
	}
      }
      continue;
    } else if(ev != PROCESS_EVENT_POLL) {
      continue;
    }

  again:
    
    u = NULL;
    
    for(t = timerlist; t != NULL; t = t->next) {
      if(timer_expired(&t->timer)) {
	if(process_post(t->p, PROCESS_EVENT_TIMER, t) == PROCESS_ERR_OK) {
	  
	  /* Reset the process ID of the event timer, to signal that the
	     etimer has expired. This is later checked in the
	     etimer_expired() function. */
	  t->p = PROCESS_NONE;
	  if(u != NULL) {
	    u->next = t->next;
	  } else {
	    timerlist = t->next;
	  }
	  t->next = NULL;
	  update_time();
	  goto again;
	} else {
	  etimer_request_poll();
	}
      }
      u = t;
    }
    
  }
  
  PROCESS_END();
}


貌似有了PROCESS_EVENT_TIMER的影子,大家可以自己去思考一下,do_poll和do_event

PROCESS_EVENT_TIMER的定义在core/sys/process.h中

#define PROCESS_EVENT_TIMER           0x88


在这里我们基本上能够总算接触到了Contiki的event,更多的自己去看代码理解,也许你需要一个sourceinghit来阅读代码,而不用像我一样一个一个文件打开查看;

虽然还是觉得有点模棱两可;只能说再此我并没有感觉到C语言的Contiki的优势!并不是我黑Contiki,我移植TinyOS很多地方也是参考的Contiki;现在能体会到的就是编写应用还是相对要复杂;可以自己结合前面几篇文档对照代码形成自我的理解;现在的作者也只是Contiki的菜鸟;但是应用神马的就得从基础做起;

不得不说的是cc2538dk平台本质是TI的SmartRF06EB板子,我的cc2538cb的代码(驱动部分)主要是参考他修改而来,3.0代码和2.7代码部分在底层变动较大;高手们可以互相印证,至少我比较喜欢2.7的启动文件的写法;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: