Event-driven mechanism is widely used in embedded systems, similar to the interrupt mechanism, when an event arrives (such as a key, data arrives), the system responds to and processes the event. With respect to the polling mechanism, the event mechanism has the advantage of being a star, with low power consumption (the system is in hibernation and is awakened when an event arrives) and MCU utilization is high.
Contiki the event mechanism into the protothreads mechanism, where each event binds to a process (the broadcast event exception), and the messages between processes are passed through events. Signs an event with an unsigned character type. The event structure Body event_data is defined as follows:
struct event_data { process_event_t ev; process_data_t data; struct process *charvoid * process_data_t;
Identifies an event with an unsigned character type, Contiki defines 10 events (0x80~0x8a), and others are used by the user.
#define Process_event_none 0x80#define process_event_init 0x81#define process_event_poll 0x82#define process_event_exit 0x83#define process_event_service_removed 0x84#define process_event_continue 0x85#define process_event_msg 0x86#define Process_ event_exited 0x87#define process_event_timer 0x88#define process_event_com 0x89#define Process_event_max 0x8a
Each event binds to a process, if p is null, indicating that the event binds all processes (that is, broadcast event Process_broadcast). In addition, events can carry data that can be used to communicate between processes (passing events with data to another process).
Static process_num_events_t nevents, fevent; Static struct Event_data events[process_conf_numevents]; #define Process_conf_numevents 32
Contiki holds events with a global static array, which means that the number of events is specified before the system is run (the user can process_conf_numevents the configuration size) and the array subscript provides quick access to events. The system also defines another two global static variables nevents and fevent, respectively, to record the total number of unhandled events and the next pending location. The event logic consists of a ring queue, stored in an array. Such as:
It can be seen that for Contiki systems, there is no priority for the event, but a first-to-first service strategy, and a global variable fevent records the next subscript for the next event to be processed.
Event generation
Contiki has two ways of generating events, namely, synchronous and asynchronous. Synchronization events are generated by the process_post_synch function, which is processed directly after the event is triggered (calling the call_process function). Asynchronous event generation is generated by Process_post , and is not processed in a timely manner, but into the event queue waiting for processing,process_post flowchart as follows:
1 intProcess_post (structProcess *p, process_event_t ev, process_data_t data)2 {3 Staticprocess_num_events_t Snum;4 5 if(process_current () = =NULL) {6PRINTF ("Process_post:null Process posts event%d to process '%s ', nevents%d\n",7 ev,process_name_string (P), nevents);8 } 9 Else {TenPRINTF ("process_post:process '%s ' posts event%d to process '%s ', nevents%d\n", One process_name_string (Process_current ()), Ev, Ap = = Process_broadcast?"<broadcast>": Process_name_string (P), nevents); - } - /*nevents Number of unhandled events, event queue full, return process_err_full*/ the if(Nevents = =process_conf_numevents) { - #ifDEBUG - if(p = =process_broadcast) { -printf"Soft panic:event queue is full when broadcast event%d were posted from%s\n", Ev, process_name_string (process_current)); +}Else { -printf"Soft panic:event queue is full if event%d was posted to%s frpm%s\n", Ev, process_name_string (p), process_name_string (process_current)); + } A #endif/* DEBUG */ at returnProcess_err_full; - } - //Event queue is not full, continue -Snum = (process_num_events_t) (fevent + nevents)% Process_conf_numevents;//get the next idle position in the loop queue -Events[snum].ev = EV;//joining events to a queue -Events[snum].data =data; inEVENTS[SNUM].P =p; -++nevents; to + #ifProcess_conf_stats - if(Nevents >process_maxevents) { theProcess_maxevents =nevents; * } $ #endif/* Process_conf_stats */Panax Notoginseng - returnProcess_err_ok; the}
process_post First determine if the event queue is full, if the full return error, otherwise get the next idle position (because the ring queue, need to do the remainder), and then set the event and the total number of unhandled events plus 1.
Event scheduling
Events do not have a priority, with a first-to-first service policy, and each system poll (Process_run function) handles only one event, and thedo_event function handles the event with the following flowchart:
1 /*2 * Process The next event in the event queue and deliver it to3 * Listening processes.4 */5 /*---------------------------------------------------------------------------*/6 Static void7Do_event (void)8 {9 Staticprocess_event_t ev;Ten Staticprocess_data_t data; One Static structProcess *receiver; A Static structProcess *p; - - /* the * If There is any events in the queue, take the first one and walk - * Through the list of processes to see if the event should be - * delivered to any of them. If So, we call the event handler - * function for the process. We only process one event at a time and + * Call the poll handlers inbetween. - */ + A if(Nevents >0) { at - /*There is events that we should deliver.*/ - /*Remove Pending Events*/ -EV =Events[fevent].ev; - -data =Events[fevent].data; inReceiver =EVENTS[FEVENT].P; - to /*Since We have seen the new event, we move pointer upwards + and Decrese the number of events.*/ - /*update fevent and nevents*/ theFevent = (fevent +1) %process_conf_numevents; *--nevents; $ Panax Notoginseng /*If This is a broadcast event, we deliver it to all events, in - order of their priority.*/ the /*whether the event is broadcast*/ + if(Receiver = =process_broadcast) { A for(p = process_list; p! = NULL; p = p->next) { the + /*If We have been requested to poll a process - between processing the broadcast event.*/ $ /*a high-priority process that runs all high-priority processes*/ $ if(poll_requested) { - Do_poll (); - } theCall_process (p, Ev, data);//Handling Events - }Wuyi } the Else { - /*broadcast event, so we deliver it to the Wu specified process. Not broadcast events, provided to specific processes*/ - /*If The event is an INIT event, we should also update the About state of the process. If it is an initialization event, set the process status to running*/ $ if(EV = =process_event_init) { -Receiver->state =process_state_running; - } - A /*Make sure, the process actually is running.*/ +Call_process (receiver, Ev, data);//Handling Events the } - } $}
do_event First takes out the event (that is, copies the value of the event to a new variable), updates the total number of unhandled events, and an array subscript for the next pending event (the ring queue, which requires a remainder operation). Then determine whether the event is a broadcast event Process_broadcast, if, considering the processing of broadcast events may take more time, in order to ensure system real-time, first run a high-priority process, and then to handle the event (call call_process function). If the event is an initialization event Process_event_init(This event is triggered when the process is created), the process state needs to be set to process_state_running.
Event handling
The actual event handling is the body threadof the function in the process, as described above,call_process calls the thread function to execute the process. The key code is as follows:
ret = P->thread (&p->pt, Ev, data);
Reference jelline Great God blog: http://jelline.blog.chinaunix.net
contiki-Event Scheduling