EventFramework library allows the creation of an event-driven infrastructure in which small "threads" can handle events in a multithreaded execution context. The EventFramework can be configured to act as a cooperative or a fully-preemptive kernel with fixed-priority scheduling. Furthermore, this kernel matches run-to-completion semantics, and hence a single-stack configuration is enough to keep running this multithreaded execution environment. As running threads shares global stack, a huge quantity of RAM is saved in contrast with traditional RTOSes.

Dependents:   sensors_KL46Z_xmn

Revision:
0:9d09acc8f9d9
Child:
1:ec12f2e32faf
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EventFramework.cpp	Mon Oct 01 10:38:45 2012 +0000
@@ -0,0 +1,238 @@
+/* mbed EventFramework Library 
+ * Copyright (c) 2012 raulMrello
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "EventFramework.h"
+#include "../Node/Node.h"
+
+void EmptyFn(void){}
+
+EventFramework::EventFramework(uint32_t schpol, void (*cbEI)(void), void (*lock)(void), void (*unlock)(void)){
+    currPrio = 0xFFFF;
+    nesting = 0;
+    cbLock = EmptyFn;
+    cbUnlock = EmptyFn;
+    cbEnableInterrupts = EmptyFn;
+    list = NULL;
+    queue = NULL;
+    event = NULL;
+    ctflags |= (EventFramework::SCHED_KEY & schpol);
+    if(cbEI){
+        cbEnableInterrupts = cbEI;
+    }
+    if(lock){
+        cbLock = lock;
+    }
+    if(unlock){
+        cbUnlock = unlock;
+    }
+}
+
+EventFramework::~EventFramework(){
+    if(list)
+        delete list;
+    if(queue)
+        delete queue;
+}
+   
+void EventFramework::AddEvent(Event* ev){
+    cbLock();
+    if(!list){
+        list = new List(ev);
+        return;
+    }
+    AddEventToList(ev,list);
+    cbUnlock();
+}    
+   
+void EventFramework::AddPendingEvent(Event* ev){
+    cbLock();
+    if(!queue){
+        queue = new List(ev);
+        return;
+    }
+    AddEventToList(ev,queue);
+    cbUnlock();
+}    
+
+void EventFramework::AddEventToList(Event* ev, List* plist){
+   Node* node = plist->GetFirstNode();
+   Event* data = (Event*)node->GetData();
+    while(data->GetPrio() <= ev->GetPrio()){
+        Node* next = node->GetNext();
+        if(!next){
+            plist->AddAfter(node, ev);
+            return;
+        }
+        data = (Event*)next->GetData();
+        node = next;
+    }
+    Node* newHead = plist->AddBefore(node, ev);
+    if(newHead){
+        plist->SetFirstNode(newHead);
+    }
+}
+    
+void EventFramework::RemoveEvent(Event* ev){
+    cbLock();
+    list->RemoveItem(ev);
+    cbUnlock();
+}
+
+void EventFramework::AddEventListener(Event* ev, EventHandler* hnd, EventDispatchingRoutine* func){
+    if(func){
+        hnd->Attach(func);
+    }
+    ev->Subscribe(hnd);
+}
+
+void EventFramework::RemoveEventListener(Event* ev, EventHandler* hnd){
+    ev->Unsubscribe(hnd);
+}
+
+void EventFramework::RemovePendingEvent(Event* ev){
+    cbLock();
+    queue->RemoveItem(ev);
+    cbUnlock();
+    delete ev;
+}
+
+void EventFramework::PublishEvent(Event* evt, void* args){
+    Event* raised = new Event(evt->GetPrio());
+    raised->SetData(args);
+    raised->SetBase(evt);
+    cbLock();
+    AddPendingEvent(raised);
+    if(nesting){
+        cbUnlock();
+        return;
+    }
+    cbUnlock();
+    if(IsPreemptive()){
+        Schedule();
+    }
+}
+
+void EventFramework::Configure(uint32_t key, uint32_t value){
+    ctflags &= ~key;
+    ctflags |= (key & value);
+}
+
+Event* EventFramework::GetEvent(void){
+    return event;
+}
+
+bool EventFramework::IsPreemptive(void){
+    if((ctflags & SCHED_KEY) == SCHED_VALUE_PREEMPTIVE)
+        return true;
+    return false;
+}
+
+void EventFramework::SaveContext(void){
+    cbLock();
+    nesting++;
+    cbUnlock();
+}
+
+void EventFramework::RestoreContext(void){
+    cbLock();
+    if(nesting > 1){
+        cbUnlock();
+        return;
+    }
+    nesting = 0;
+    cbUnlock();
+    if(cbEnableInterrupts){
+        cbEnableInterrupts();
+    }
+    Schedule();
+}
+
+void EventFramework::Schedule(void){
+    volatile static uint16_t curr = 0xFFFF;
+    volatile uint16_t prev;
+    volatile uint16_t next;
+
+    for(;;){
+        cbLock();
+        // if no pending events, then quit
+        if(!queue){
+            cbUnlock();
+            return;
+        }
+        // extract most priority event
+        Node* firstNode = queue->GetFirstNode();
+        Event* rdyEvent = (Event*)firstNode->GetData();
+        next = rdyEvent->GetPrio();
+
+        // if worst then exit
+        if(next >= currPrio){
+            cbUnlock();
+            return;
+        }
+
+        // else update context
+        prev = curr;
+        curr = next;
+        currPrio = curr;
+
+        // extract event from queue, if no more events, the free queue
+        queue->Remove(firstNode);
+        if(!queue->GetFirstNode()){
+            delete queue;
+            queue = NULL;
+        }
+
+        // get event
+        Node* nodeHnd = rdyEvent->GetBase()->GetList()->GetFirstNode();
+        while(nodeHnd){
+            EventHandler* hnd = (EventHandler*)nodeHnd->GetData();
+            cbUnlock();
+            hnd->Execute(rdyEvent->GetData());
+            cbLock();
+            nodeHnd = nodeHnd->GetNext();
+        }
+        delete rdyEvent;
+        curr = prev;
+        currPrio = curr;
+        cbUnlock();
+    }
+//    // extract most priority event
+//    Node* firstNode = queue->GetFirstNode();
+//    this->event = (Event*)firstNode->GetData();
+//    queue->Remove(firstNode);
+//    // if no more events, then free queue
+//    if(!queue->GetFirstNode()){
+//        delete queue;
+//        queue = NULL;
+//    }
+//    // get event
+//    Node* nodeHnd = this->event->GetBase()->GetList()->GetFirstNode();
+//    while(nodeHnd){
+//        EventHandler* hnd = (EventHandler*)nodeHnd->GetData();
+//        hnd->Execute();
+//        nodeHnd = nodeHnd->GetNext();
+//    }
+
+}
+
+
+