CC2538之Contiki3.0实验:2-PROCESS 你永远不懂阅读C代码的伤悲
来源:互联网 发布:婚纱照相册排版软件 编辑:程序博客网 时间:2024/04/30 21:14
相信不少朋友在学习Contiki查阅了不少帖子和资料,但是我只能说一句,貌似没多大用啊,看了很多的帖子发现还是理解不了Contiki的设计;真心很麻烦的东东,本科生们就更加痛苦了,这个OS是这么麻烦,为什么这么说呢,没记错我本科的时候的C语言基本知识就是会点结构体;也许时代进步很多学生的专业知识很扎实!回想一下TinyOS,代码的阅读是那么舒心,整个代码也根本谈不上OS,任务本质就是对Task函数按照序号一次分配一个全局ID,从0开始;POST在全局的sheude数组元素中存下ID号,POLL执行取出ID号,然后调用SWITCH(ID);case下面是ID号对应的函数,代码分析简单;看不懂nesC也可以通过转成app.c后从main函数查看任务是怎样调度的;Contiki对于新手则不像TinyOS那么简单,C语言的技巧应用的淋漓尽致;C不过关的朋友们可以正好充电;
下面还是就先前第一个例程开始阅读代码;test_null.c中:
1,PROCESS(test_null, "我是菜鸟");
core/sys/process.h中定义:#if PROCESS_CONF_NO_PROCESS_NAMES#define PROCESS(name, strname)\ PROCESS_THREAD(name, ev, data);\ struct process name = { NULL, \ process_thread_##name }#else#define PROCESS(name, strname)\ PROCESS_THREAD(name, ev, data);\ struct process name = { NULL, strname,\ process_thread_##name }#endif
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;};
2,PROCESS_THREAD(test_null, ev, data)
core/sys/process.h中定义:
#define PROCESS_THREAD(name, ev, data) \static PT_THREAD(process_thread_##name(struct pt *process_pt,\ process_event_t ev,\ process_data_t data))
现在咱们需要看的是PT_THREAD宏定义了:(core/sys/pt.h)
#define PT_THREAD(name_args) char name_args
上面展开
static char process_thread_##name(struct pt *process_pt,\ process_event_t ev,\ process_data_t data)
好了,现在我们清楚了这些玩意的意思,当然我就不分析了,大家在使用Contiki之前必须是C语言功底深厚
不清楚的朋友提示一下函数指针;
3,AUTOSTART_PROCESSES(&test_null);
core/sys/autostart.h文件中定义:
#if ! CC_NO_VA_ARGS#if AUTOSTART_ENABLE#define AUTOSTART_PROCESSES(...)\struct process * const autostart_processes[] = {__VA_ARGS__, NULL}#else /* AUTOSTART_ENABLE */#define AUTOSTART_PROCESSES(...)\extern int _dummy#endif /* AUTOSTART_ENABLE */#else#error "C compiler must support __VA_ARGS__ macro"#endif
在contiki_main中调用:
autostart_start(autostart_processes);
看一下core/sys/autostart.c:
voidautostart_start(struct process * const processes[]){ int i; for(i = 0; processes[i] != NULL; ++i) { process_start(processes[i], NULL); PRINTF("autostart_start: starting process '%s'\n", processes[i]->name); }}
4,现在让我们来看一下,
PROCESS_BEGIN();
根据core/sys/process.h
#define PROCESS_BEGIN() PT_BEGIN(process_pt)根据core/sys/pt.h
#define PT_BEGIN(pt) { char PT_YIELD_FLAG = 1; if (PT_YIELD_FLAG) {;} LC_RESUME((pt)->lc)core/sys/lc.h中
#define LC_RESUME(lc)简写成
#define PT_BEGIN(pt) { char PT_YIELD_FLAG = 1; if (PT_YIELD_FLAG) {;} (pt)->lc
注意符号'{'
PROCESS_END();
根据core/sys/process.h
#define PROCESS_END() PT_END(process_pt)根据core/sys/pt.h
#define PT_END(pt) LC_END((pt)->lc); PT_YIELD_FLAG = 0; \ PT_INIT(pt); return PT_ENDED; }
#define PT_INIT(pt) LC_INIT((pt)->lc) <span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"> </span>core/sys/lc.h中
#define LC_END(lc)#define LC_INIT(lc)
和上面的注意一样是符号‘}’
呵呵,不多说了,大家应该清楚这两个玩意应该是配合使用了
更多的WAIT,YIELD,WAITWHILE,EXIT,不做介绍,代码的阅读真心累人,朋友们可以自己去阅读代码
这是没有办法的事情,没有文档能够说清楚它的设计思想,最好是自己去理解!
5,通过contiki-main.c文件,查看int main(void)函数,简化一下main函数,去除烦人的代码
intmain(void){ //省去初始化 process_init(); process_start(&etimer_process, NULL); ctimer_init();#if NETSTACK_CONF_WITH_IPV6 memcpy(&uip_lladdr.addr, &linkaddr_node_addr, sizeof(uip_lladdr.addr)); queuebuf_init(); process_start(&tcpip_process, NULL);#endif /* NETSTACK_CONF_WITH_IPV6 */ process_start(&sensors_process, NULL); autostart_start(autostart_processes); while(1) { process_run(); }}
比较重要的函数就是
process_init();
process_start(...);
ctimer_init();
queuebuf_init();
autostart_start(autostart_processes);
process_run();
先抛开
queuebuf_init(以后必须学习,至少也应该提供内存的申请使用和释放)
ctimer_init();这些
剩下
process_init();
在core/sys/process.c中
voidprocess_init(void){ lastevent = PROCESS_EVENT_MAX; nevents = fevent = 0;#if PROCESS_CONF_STATS process_maxevents = 0;#endif /* PROCESS_CONF_STATS */ process_current = process_list = NULL;}
process_start(...);
voidprocess_start(struct process *p, process_data_t data){ struct process *q; /* First make sure that we don't try to start a process that is already running. */ for(q = process_list; q != p && q != NULL; q = q->next); /* If we found the process on the process list, we bail out. */ if(q == p) { return; } /* Put on the procs list.*/ p->next = process_list; process_list = p; p->state = PROCESS_STATE_RUNNING; PT_INIT(&p->pt); PRINTF("process: starting '%s'\n", PROCESS_NAME_STRING(p)); /* Post a synchronous initialization event to the process. */ process_post_synch(p, PROCESS_EVENT_INIT, data);}
process_post_synch和process_post的区别我就不介绍了,自己可以对照代码阅读;概念那些我最不擅长,一句话,想学会这个系统,就得不断的去啃代码
下面我们看一下主循环的while中的最重要的函数:
在core/sys/process.c中
intprocess_run(void){ /* Process poll events. */ if(poll_requested) { do_poll(); } /* Process one event from the queue */ do_event(); return nevents + poll_requested;}
do_poll和do_event的代码自行阅读,但是本质是在处理结构体值后调用了
call_process(...)这个才是正主了
在core/sys/process.c中
static voidcall_process(struct process *p, process_event_t ev, process_data_t data){ int ret;#if DEBUG if(p->state == PROCESS_STATE_CALLED) { printf("process: process '%s' called again with event %d\n", PROCESS_NAME_STRING(p), ev); }#endif /* DEBUG */ if((p->state & PROCESS_STATE_RUNNING) && p->thread != NULL) { PRINTF("process: calling process '%s' with event %d\n", PROCESS_NAME_STRING(p), ev); process_current = p; p->state = PROCESS_STATE_CALLED; ret = p->thread(&p->pt, ev, data); if(ret == PT_EXITED || ret == PT_ENDED || ev == PROCESS_EVENT_EXIT) { exit_process(p, p); } else { p->state = PROCESS_STATE_RUNNING; }}
其中的ret = p->thread(&p->pt, ev, data);大家参考test_null.c的PROCESS的写法和我提示的函数指针
是不是应该能知道这个家伙干什么了;
不知不觉都写了这么多字了,算了,下一次再带来编程事件的理解;至少让我先理解Contiki是怎么设计思想
然后再去编写代码;现在已经战战兢兢了,这个系统说是pure c,但是还是不太理解他的所谓的thread,现在就已经接触了不少编程禁忌了,大家知道在最后编写复杂应用如果吃不透他的设计思想一旦代码有BUG,后果是不堪设想的;怀念TinyOS,哪有这么多禁忌!
1 0
- CC2538之Contiki3.0实验:2-PROCESS 你永远不懂阅读C代码的伤悲
- CC2538之Contiki3.0实验:3-event
- CC2538之Contiki3.0实验:4-Sensor
- CC2538之Contiki3.0实验:1-Contiki初探-新建空工程 编译
- 视频: 第六部视频CC2538之Contiki3.0CoAP协议例程(使用边界路由器,Firefox)
- CC2538之TinyOS例程实验:2-printf
- 你的柔情我永远不懂--陈琳
- 巴神的世界,你永远不懂
- 你的柔情我永远不懂(程序员面试100题之八求1+2+n)
- 代码之谜 - 其实,你不懂代码
- 代码之谜-其实,你不懂代码
- 三月不减肥,四月徒伤悲,五月徒伤悲,六月徒伤悲,一整年都徒伤悲……胖子,放下你手里的美食~
- CC2538之TinyOS例程实验:5-Adc_Temp片内温度读取实验 TinyOS如何直接使用C文件
- CC2538之TinyOS例程实验:6-CCM(AES)实验
- CC2538之TinyOS例程实验:8-RPL(roll)路由实验
- CC2538之TinyOS例程实验:9-Ppprouter边界路由实验
- 其实,你不懂代码
- 代码之谜(零) - 其实,你不懂代码
- 注解形式开发Controller方法的返回值类型
- 在困境中成长
- PHP读取MySQL显示中文乱码
- LeetCode:Valid Sudoku
- MySQL创建用户与授权方法
- CC2538之Contiki3.0实验:2-PROCESS 你永远不懂阅读C代码的伤悲
- 迷茫的旅行商——一个无处不在的计算机算法问题
- ARM4开发板的EMWIN设计
- 虚拟机安装Ubuntu黑屏解决方法(分区问题)
- 生成N个二进制位的组合
- 最短排序子数组
- 一个简单的爬虫(1)
- Android Material Design学习之RecyclerView代替 ListView
- JNI & NDK 实例讲解二 (通过NDK创建JNI项目)