2017年3月29日 星期三

事件驅動多工系統設計

規劃很久了,直到另一個功能出現才有動力去寫。寫出來程式不大。
系統只有二個檔案,測試一個,模擬一個。
event_drive.h 如下
extern void OS_ENTER_CRITICAL(void);
extern void OS_EXIT_CRITICAL(void);
extern void SimInit(void);

#define INIT_DEVICE() SimInit()
#define DIS_INTR() OS_ENTER_CRITICAL()
#define ENA_INTR() OS_EXIT_CRITICAL()

#define MAX_EVENT 8
#define MAX_TIMER 32

extern void execute(void);
extern void setTimeout(void (*p_func)(void), unsigned int tick);
extern void ISR_setTimeout(void (*p_func)(void), unsigned int tick);
extern void timerAction(void);

使用者可以設定同時執行的事件數目及要管理的延時事件數

event_drive.c 如下
#include "event_drive.h"

unsigned int eventInCnt = 0;
unsigned int eventOutCnt = 0;
void (*eventFunc[MAX_EVENT])(void);
void (*delayFunc[MAX_TIMER])(void);
unsigned int delayCnt[MAX_TIMER];

void execute(void)
{
    // FIFO function array
    if (eventInCnt != eventOutCnt)
    {
        eventFunc[eventOutCnt % MAX_EVENT]();
        eventOutCnt++;
    }
}

void setTimeout(void (*p_func)(void), unsigned int tick)
{
    int i;

    if (!tick)
        tick = 1;
    DIS_INTR();
    for (i = 0; i < MAX_TIMER; i++)
    {
        if (delayCnt[i] == 0)
            break;
    }
    delayFunc[i] = p_func;
    delayCnt[i] = tick;
    ENA_INTR();
}

void ISR_setTimeout(void (*p_func)(void), unsigned int tick)
{
    int i;

    if (!tick)
        tick = 1;
    for (i = 0; i < MAX_TIMER; i++)
    {
        if (delayCnt[i] == 0)
            break;
    }
    delayFunc[i] = p_func;
    delayCnt[i] = tick;
}

void timerAction(void)
{
    int i;
    for (i = 0; i < MAX_TIMER; i++)
    {
        if (delayCnt[i])
        {
            delayCnt[i]--;
            if (!delayCnt[i])
            {
                eventFunc[eventInCnt % MAX_EVENT] = delayFunc[i];
                eventInCnt++;
            }
        }
    }
}

只有4個函式:
execute()是執行的地方,放在main()中的while(1)內就可以了。
timerAction()放在時間中斷內,用來管理延遲執行的函式何時要回復執行。
setTimeout()是使用者註冊一個延遲執行的函式。
ISR_setTimeout()是使用者用於中斷內的函式。

Sim.c windows下的模擬界面
#include <windows.h>
#include <winbase.h>

#include "event_drive.h"

HANDLE OSSemaphore;
DWORD WINAPI OSTickW32(LPVOID lpParameter);
HANDLE OSTick32Handle;

void SimInit(void)
{
    DWORD dwID;

    OSSemaphore = CreateSemaphore(NULL11NULL);
    OSTick32Handle = CreateThread(NULL0, OSTickW32, 00, &dwID);
    SetPriorityClass(OSTick32Handle, THREAD_PRIORITY_HIGHEST);
    SetThreadPriority(OSTick32Handle, THREAD_PRIORITY_HIGHEST);
}

DWORD WINAPI OSTickW32(LPVOID lpParameter)
{
    while (1)
    {
        timerAction();
        Sleep(1);
    }
    return 0;
}

void OS_SLEEP(unsigned int count)
{
    Sleep(count);
}

void OS_INIT_CRITICAL(void)
{
    return;
}

void OS_ENTER_CRITICAL(void)
{
    WaitForSingleObject(OSSemaphore, INFINITE);
}

void OS_EXIT_CRITICAL(void)
{
    ReleaseSemaphore(OSSemaphore, 1NULL);
}

測試用程式


#include <stdio.h>
#include "event_drive.h"

void print_dot(void);
void print_0(void);

void main()
{
    INIT_DEVICE();
    setTimeout(print_dot, 1);
    setTimeout(print_0, 1);
    while (1)
    {
        execute();
    }
}

void print_dot(void)
{
    printf(".");
    setTimeout(print_dot, 7);
}

void print_0(void)
{
    printf("0");
    setTimeout(print_0, 10);
}