#ifndef __OMW_RTOS_H__
#define __OMW_RTOS_H__

#ifdef OMW_RTOS_LITE_SCH
#include "omw_sch.h"
#endif

#define OMW_CTRL_TASK_SP_SS  1024
#define OMW_HOST_TASK_SP_SS  1024
#define OMW_APP_TASK_SP_SS   1024

#define OMW_EVENT_QUEUED_FLAG       (0x7FE28AD0)
#define OMW_EVENT_BUF_FREE_FLAG     (0x8DC64B00)
#define OMW_IS_EVENT_Q_EMPTY(evq)   ((evq)->tail == (struct omw_rtos_event *)(OMW_EVENT_QUEUED_FLAG))

struct omw_rtos_mutex {
    volatile uint8_t ref_cnt;
    volatile uint8_t task_id;
    volatile uint8_t flag;
    uint8_t  rsved;
};

struct omw_rtos_sem {
    volatile uint8_t count;
    uint8_t  rsved[3];
};

struct omw_rtos_event;
typedef void omw_rtos_event_fn(struct omw_rtos_event *ev);
struct omw_rtos_event{
    void * next;

    omw_rtos_event_fn *cb;
    void *arg;
};

typedef struct{
    struct omw_rtos_event * head;
    struct omw_rtos_event * tail;
}omw_rtos_event_queue_t;

extern uint8_t   g_cur_task_idx;
extern struct omw_rtos_mutex os_critical_mutex;

static inline uint8_t
omw_rtos_mutex_init(struct omw_rtos_mutex *mu)
{
    #ifdef OMW_HAS_SCH
    mu->task_id = 0xFF;
    #endif
    return 0;
}

static inline uint8_t
omw_rtos_sem_init(struct omw_rtos_sem *sem, uint16_t tokens)
{
    sem->count = tokens;
    return 0;
}

static inline uint16_t
omw_rtos_sem_get_count(struct omw_rtos_sem *sem)
{
    return (uint16_t)(sem->count);
}

static inline uint8_t
omw_rtos_is_in_critical(void)
{
    return os_critical_mutex.flag;
}

uint8_t omw_rtos_mutex_release(struct omw_rtos_mutex *mu);
uint8_t omw_rtos_mutex_pend(struct omw_rtos_mutex *mu, uint32_t timeout);

static inline uint32_t
omw_rtos_enter_critical(void)
{
    return omw_rtos_mutex_pend(&os_critical_mutex, 1);
}

static inline void
omw_rtos_exit_critical(uint32_t ctx)
{
    omw_rtos_mutex_release(&os_critical_mutex);
}

static inline uint8_t
omw_rtos_get_cur_task_id()
{
    return g_cur_task_idx;
}

static inline void
omw_rtos_eventq_init(omw_rtos_event_queue_t *evq)
{
    evq->head = evq->tail = (struct omw_rtos_event *)(OMW_EVENT_QUEUED_FLAG);
}

static inline void
omw_rtos_event_run(struct omw_rtos_event *ev)
{
    ev->cb(ev);
}

static inline void
omw_rtos_event_init(struct omw_rtos_event *ev, omw_rtos_event_fn *fn, void *arg)
{
    ev->next = NULL;
    ev->cb = fn;
    ev->arg = arg;
}

static inline uint8_t
omw_rtos_event_is_queued(struct omw_rtos_event *ev)
{
    return (ev->next != NULL);
}

static inline void *
omw_rtos_event_get_arg(struct omw_rtos_event *ev)
{
    return ev->arg;
}

static inline void
omw_rtos_event_set_arg(struct omw_rtos_event *ev, void *arg)
{
    ev->arg = arg;
}

void omw_rtos_eventq_put(omw_rtos_event_queue_t *evq, struct omw_rtos_event *ev);
struct omw_rtos_event * omw_rtos_eventq_get(omw_rtos_event_queue_t *evq);
void omw_rtos_eventq_remove(omw_rtos_event_queue_t *evq, struct omw_rtos_event *ev);

typedef void (* omw_task_entry)(void);

//when app call this API, arg must set to NULL
//when more than 1 APP tasks, need to change total stack size: ld file and sch_def.h
//also check value of OMW_CTRL_TASK_SP_SS/OMW_HOST_TASK_SP_SS/OMW_APP_TASK_SP_SS defined
int  omw_rtos_add_task(omw_task_entry e, uint8_t p, uint16_t ss, void * arg);

void omw_rtos_low_pri_free_cpu(void * arg);
void omw_rtos_start_sch(void);
void omw_rtos_free_cpu(void);

uint8_t omw_rtos_sem_pend(struct omw_rtos_sem *sem, uint32_t timeout);
uint8_t omw_rtos_sem_release(struct omw_rtos_sem *sem);

omw_rtos_event_queue_t * omw_rtos_get_task_evq(uint8_t tsk_id);

void omw_rtos_mailbox_send(uint8_t dst_task_id, uint32_t param1, uint32_t param2);
//-1: no msg, >=0: the send task id
int omw_rtos_mailbox_rcv(uint32_t * param1, uint32_t * param2);

#endif