a implementation of template class that is used for create event-driven task thread.

Actor.h

Committer:
mzta
Date:
2015-05-28
Revision:
1:7d11951c1fc0
Parent:
0:1f4516e81c1b

File content as of revision 1:7d11951c1fc0:

#ifndef ACTOR_H
#define ACTOR_H

#include <map>
#include "mbed.h"
#include "rtos.h"

#define MAX_MAIL_NUM    16
#define STACK_SIZE      1024 * 1
#define START_THREAD    -1

typedef uint32_t MessageID;

struct MailPacket {
    MessageID messageId;
    void *packet;
};

typedef Mail<MailPacket, MAX_MAIL_NUM> MailBox;

template <typename T>
class Actor
{
protected:
    typedef void (T::*Action)(void *);
    typedef std::map<MessageID, Action> ActionMap;

    Thread thread;
    ActionMap actions;
    MailBox mbox;

public:
    Actor(
        osPriority priority = osPriorityNormal,
        uint32_t stack_size = STACK_SIZE) :
            thread(&Actor::threadKicker, this, priority, stack_size)
    {
        thread.signal_set(START_THREAD);
    }

    virtual ~Actor(){};

    virtual void subscribe(MessageID msg, Action act) {
        actions[msg] = act;
    }

    virtual void unsubscribe(MessageID msg) {
        actions.erase(msg);
    }
    
    virtual void putMail(MessageID msg, void *pkt) {
        MailPacket *mail = mbox.alloc();
        mail->messageId  = msg;
        mail->packet     = pkt;
        mbox.put(mail);
    }

protected:
    virtual void threadMain() {
        osEvent event;
        while(true) {
            event = mbox.get();
            if (event.status == osEventMail) {
                MailPacket *mail = (MailPacket*)event.value.p;
                MessageID msg = mail->messageId;
                void *pkt     = mail->packet;
                if (actions[msg] != NULL) {
                    (reinterpret_cast<T*>(this)->*actions[msg])(pkt);
                }
                mbox.free(mail);
            }
        }
    }

    static void threadKicker(void const *actor) {
        Actor *instance = (Actor*)actor;
        instance->threadMain();
    }
};

template <typename T>
void sendMail(T *dest, MessageID msg, void *pkt) {
    dest->putMail(msg, pkt);
}

#endif