/*
 * Copyright (C) 2019-2020 Alibaba Group Holding Limited
 */

#ifndef AOS_KERNEL_H
#define AOS_KERNEL_H

#include <stdlib.h>
#include <stddef.h>
#include <sys/types.h>
#include <stdint.h>
#include <assert.h>

#ifdef __cplusplus
extern "C" {
#endif

#define AOS_WAIT_FOREVER    0xffffffffu
#define AOS_NO_WAIT         0x0

#ifndef AOS_DEFAULT_APP_PRI
#define AOS_DEFAULT_APP_PRI 32
#endif

#ifndef AOS_MAX_APP_PRI
#define AOS_MAX_APP_PRI     60
#endif

#define AOS_EVENT_AND              0x02u
#define AOS_EVENT_AND_CLEAR        0x03u
#define AOS_EVENT_OR               0x00u
#define AOS_EVENT_OR_CLEAR         0x01u

/// Status code values returned by CSI-kernel functions. 0 - success, negative represents error code ,see errno.h
typedef int32_t k_status_t;

/// Entry point of a timer call back function.
typedef void (*aos_timer_cb_t)(void *, void *);

typedef struct {
    void *hdl;
} aos_hdl_t;

typedef aos_hdl_t aos_task_t;
typedef aos_hdl_t aos_mutex_t;
typedef aos_hdl_t aos_sem_t;
typedef aos_hdl_t aos_queue_t;
typedef aos_hdl_t aos_timer_t;
typedef aos_hdl_t aos_work_t;
typedef aos_hdl_t aos_event_t;

typedef struct {
    void *hdl;
    void *stk;
} aos_workqueue_t;

typedef unsigned int aos_task_key_t;

#define MS2TICK(ms) krhino_ms_to_ticks(ms)
int32_t aos_irq_context(void);

// #define aos_assert(x)                             assert(x)

/**
 * Reboot AliOS.
 */
void aos_reboot(void);

/**
 * Get HZ(ticks per second).
 *
 * @return  RHINO_CONFIG_TICKS_PER_SECOND.
 */
int aos_get_hz(void);

/**
 * Get kernel version.
 *
 * @return  SYSINFO_KERNEL_VERSION.
 */
const char *aos_version_get(void);

/**
 * Create a task.
 *
 * @param[in]  name       task name.
 * @param[in]  fn         function to run.
 * @param[in]  arg        argument of the function.
 * @param[in]  stacksize  stack-size in bytes.
 *
 * @return  0: success.
 */
int aos_task_new(const char *name, void (*fn)(void *), void *arg, int stack_size);

/**
 * Create a task.
 *
 * @param[in]  task        handle.
 * @param[in]  name        task name.
 * @param[in]  fn          task function.
 * @param[in]  arg         argument of the function..
 * @param[in]  stack_buf   stack-buf: if stack_buf==NULL, provided by kernel.
 * @param[in]  stack_size  stack-size in bytes.
 * @param[in]  prio        priority value, the max is RHINO_CONFIG_USER_PRI_MAX(default 60).
 *
 * @return  0: success.
 */
int aos_task_new_ext(aos_task_t *task, const char *name, void (*fn)(void *), void *arg,
                     int stack_size, int prio);

/**
 * show all tasks info.
 *
 */
void aos_task_show_info(void);

void aos_task_yield();

/**
 * Exit a task.
 *
 * @param[in]  code  not used now.
 */
void aos_task_exit(int code);


void aos_task_wdt_attach(void (*will)(void *), void *args);
void aos_task_wdt_detach();
void aos_task_wdt_feed(int time);

aos_task_t aos_task_self();

/**
 * Get task name.
 *
 * @return  the name of the task
 */
const char *aos_task_name(void);


const char *aos_task_get_name(aos_task_t *task);

/**
 * Create a task key.
 *
 * @param[in]  key  pointer of key object.
 *
 * @return  0: success, -EINVAL: error.
 */
int aos_task_key_create(aos_task_key_t *key);

/**
 * Delete a task key.
 *
 * @param[in]  key  key object.
 */
void aos_task_key_delete(aos_task_key_t key);

/**
 * Associate a task-specific value with a key.
 * Support this functiong need set RHINO_CONFIG_TASK_INFO 1 at k_config.h
 *
 * @param[in]  key  key object.
 * @param[in]  vp   pointer of a task-specific value.
 *
 * @return  the check status, 0 is OK, -1 indicates invalid.
 */
int aos_task_setspecific(aos_task_key_t key, void *vp);

/**
 * Get the value currently bound to the specified key.
 * Support this functiong need set RHINO_CONFIG_TASK_INFO 1 at k_config.h
 *
 * @param[in]  key  key object.
 */
void *aos_task_getspecific(aos_task_key_t key);

/**
 * Alloc a mutex.
 *
 * @param[in]  mutex  pointer of mutex object, mutex object must be alloced,
 *                    hdl pointer in aos_mutex_t will refer a kernel obj internally.
 *
 * @return  0: success.
 */
int aos_mutex_new(aos_mutex_t *mutex);

/**
 * Free a mutex.
 *
 * @param[in]  mutex  mutex object, mem refered by hdl pointer in aos_mutex_t will
 *                    be freed internally.
 */
void aos_mutex_free(aos_mutex_t *mutex);

/**
 * Lock a mutex.
 *
 * @param[in]  mutex    mutex object, it contains kernel obj pointer which aos_mutex_new alloced.
 * @param[in]  timeout  waiting until timeout in milliseconds.
 *
 * @return  0: success.
 */
int aos_mutex_lock(aos_mutex_t *mutex, unsigned int timeout);

/**
 * Unlock a mutex.
 *
 * @param[in]  mutex  mutex object, it contains kernel obj pointer which oc_mutex_new alloced.
 *
 * @return  0: success.
 */
int aos_mutex_unlock(aos_mutex_t *mutex);

/**
 * This function will check if mutex is valid.
 *
 * @param[in]  mutex  pointer to the mutex.
 *
 * @return  0: invalid, 1: valid.
 */
int aos_mutex_is_valid(aos_mutex_t *mutex);

/**
 * This function will check if mutex is locked.
 *
 * @param[in]  mutex  pointer to the mutex.
 *
 * @return  0: no lock, 1: locked.
 */
int aos_mutex_is_locked(aos_mutex_t *mutex);

/**
 * Alloc a semaphore.
 *
 * @param[out]  sem    pointer of semaphore object, semaphore object must be alloced,
 *                     hdl pointer in aos_sem_t will refer a kernel obj internally.
 * @param[in]   count  initial semaphore counter.
 *
 * @return  0:success.
 */
int aos_sem_new(aos_sem_t *sem, int count);

/**
 * Destroy a semaphore.
 *
 * @param[in]  sem  pointer of semaphore object, mem refered by hdl pointer
 *                  in aos_sem_t will be freed internally.
 */
void aos_sem_free(aos_sem_t *sem);

/**
 * Acquire a semaphore.
 *
 * @param[in]  sem      semaphore object, it contains kernel obj pointer which aos_sem_new alloced.
 * @param[in]  timeout  waiting until timeout in milliseconds.
 *
 * @return  0: success.
 */
int aos_sem_wait(aos_sem_t *sem, unsigned int timeout);

/**
 * Release a semaphore.
 *
 * @param[in]  sem  semaphore object, it contains kernel obj pointer which aos_sem_new alloced.
 */
void aos_sem_signal(aos_sem_t *sem);

/**
 * This function will check if semaphore is valid.
 *
 * @param[in]  sem  pointer to the semaphore.
 *
 * @return  0: invalid, 1: valid.
 */
int aos_sem_is_valid(aos_sem_t *sem);

/**
 * Release all semaphore.
 *
 * @param[in]  sem  semaphore object, it contains kernel obj pointer which aos_sem_new alloced.
 */
void aos_sem_signal_all(aos_sem_t *sem);

/**
 * This function will create an event with an initialization flag set.
 * This function should not be called from interrupt context.
 *
 * @param[in]  event    event object pointer.
 * @param[in]  flags    initialization flag set(provided by caller).
 *
 * @return  0: success.
 */

int aos_event_new(aos_event_t *event, unsigned int flags);

/**
 * This function will free an event.
 * This function shoud not be called from interrupt context.
 *
 * @param[in]  event    memory refered by hdl pointer in event will be freed.
 *
 * @return  N/A.
 */

void aos_event_free(aos_event_t *event);

/**
 * This function will try to get flag set from given event, if the request flag
 * set is satisfied, it will return immediately, if the request flag set is not
 * satisfied with timeout(RHINO_WAIT_FOREVER,0xFFFFFFFF), the caller task will be
 * pended on event until the flag is satisfied, if the request flag is not
 * satisfied with timeout(RHINO_NO_WAIT, 0x0), it will also return immediately.
 * Note, this function should not be called from interrupt context because it has
 * possible to lead context switch and an interrupt has no TCB to save context.
 *
 * @param[in]  event        event object pointer.
 * @param[in]  flags        request flag set.
 * @param[in]  opt          operation type, such as AND,OR,AND_CLEAR,OR_CLEAR.
 * @param[out] actl_flags   the internal flags value hold by event.
 * @param[in]  flags        request flag set.
 * @param[in]  timeout      max wait time in millisecond.
 *
 * @return  0: success.
 */

int aos_event_get(aos_event_t *event, unsigned int flags, unsigned char opt,
                  unsigned int *actl_flags, unsigned int timeout);

/**
* This function will set flag set to given event, and it will check if any task
* which is pending on the event should be waken up.
*
* @param[in]  event    event object pointer.
* @param[in]  flags    flag set to be set into event.
* @param[in]  opt      operation type, such as AND,OR.
*
* @return  0: success.
*/

int aos_event_set(aos_event_t *event, unsigned int flags, unsigned char opt);

/**
 * This function will check if event is valid.
 *
 * @param[in]  sem  pointer to the semaphore.
 *
 * @return  0: invalid, 1: valid.
 */
int aos_event_is_valid(aos_event_t *event);

/**
 * This function will create a queue.
 *
 * @param[in]  queue    pointer to the queue(the space is provided by user).
 * @param[in]  buf      buf of the queue(provided by user).
 * @param[in]  size     the bytes of the buf.
 * @param[in]  max_msg  the max size of the msg.
 *
 * @return  0: success.
 */

int aos_queue_new(aos_queue_t *queue, void *buf, unsigned int size, int max_msg);

/**
 * This function will delete a queue.
 *
 * @param[in]  queue  pointer to the queue.
 */
void aos_queue_free(aos_queue_t *queue);

/**
 * This function will send a msg to the front of a queue.
 *
 * @param[in]  queue  pointer to the queue.
 * @param[in]  msg    msg to send.
 * @param[in]  size   size of the msg.
 *
 * @return  0: success.
 */
int aos_queue_send(aos_queue_t *queue, void *msg, unsigned int size);

/**
 * This function will receive msg from a queue.
 *
 * @param[in]   queue  pointer to the queue.
 * @param[in]   ms     ms to wait before receive.
 * @param[out]  msg    buf to save msg.
 * @param[out]  size   size of the msg.
 *
 * @return  0: success.
 */
int aos_queue_recv(aos_queue_t *queue, unsigned int ms, void *msg, unsigned int *size);

/**
 * This function will check if queue is valid.
 *
 * @param[in]  queue  pointer to the queue.
 *
 * @return  0: invalid, 1: valid.
 */
int aos_queue_is_valid(aos_queue_t *queue);

/**
 * This function will return buf ptr if queue is inited.
 *
 * @param[in]  queue  pointer to the queue.
 *
 * @return  NULL: error.
 */
void *aos_queue_buf_ptr(aos_queue_t *queue);

/**
 * Get number of queued messages in a message queue.
 *
 * @param[in]  queue  message queue handle to operate.
 *
 * @return  number of queued messages.negative indicates error code.
 */
int aos_queue_get_count(aos_queue_t *queue);

/**
 * This function will create a timer and run auto.
 *
 * @param[in]  timer   pointer to the timer.
 * @param[in]  fn      callbak of the timer.
 * @param[in]  arg     the argument of the callback.
 * @param[in]  ms      ms of the normal timer triger.
 * @param[in]  repeat  repeat or not when the timer is created.
 *
 * @return  0: success.
 */
int aos_timer_new(aos_timer_t *timer, void (*fn)(void *, void *),
                  void *arg, int ms, int repeat);

/**
 * This function will create a timer.
 *
 * @param[in]  timer   pointer to the timer.
 * @param[in]  fn      callbak of the timer.
 * @param[in]  arg     the argument of the callback.
 * @param[in]  ms      ms of the normal timer triger.
 * @param[in]  repeat  repeat or not when the timer is created.
 * @param[in]  auto_run  run auto or not when the timer is created.
 *
 * @return  0: success.
 */
int aos_timer_new_ext(aos_timer_t *timer, void (*fn)(void *, void *),
                      void *arg, int ms, int repeat, unsigned char auto_run);

/**
 * This function will delete a timer.
 *
 * @param[in]  timer  pointer to a timer.
 */
void aos_timer_free(aos_timer_t *timer);

/**
 * This function will start a timer.
 *
 * @param[in]  timer  pointer to the timer.
 *
 * @return  0: success.
 */
int aos_timer_start(aos_timer_t *timer);

/**
 * This function will stop a timer.
 *
 * @param[in]  timer  pointer to the timer.
 *
 * @return  0: success.
 */
int aos_timer_stop(aos_timer_t *timer);

/**
 * This function will change attributes of a timer.
 *
 * @param[in]  timer  pointer to the timer.
 * @param[in]  ms     ms of the timer triger.
 *
 * @return  0: success.
 */
int aos_timer_change(aos_timer_t *timer, int ms);

/**
 * This function will change attributes of a timer.
 *
 * @param[in]  timer  pointer to the timer.
 * @param[in]  ms     ms of the timer triger.
 *
 * @return  0: success.
 */
int aos_timer_change_once(aos_timer_t *timer, int ms);

/**
 * This function will check if timer is valid.
 *
 * @param[in]  timer  pointer to the timer.
 *
 * @return  0: success.
 */
int aos_timer_is_valid(aos_timer_t *timer);

/**
 * This function will creat a workqueue.
 *
 * @param[in]  workqueue   the workqueue to be created.
 * @param[in]  pri         the priority of the worker.
 * @param[in]  stack_size  the size of the worker-stack.
 *
 * @return  0: success.
 */
int aos_workqueue_create(aos_workqueue_t *workqueue, int pri, int stack_size);

/**
 * This function will delete a workqueue.
 *
 * @param[in]  workqueue  the workqueue to be deleted.
 */
void aos_workqueue_del(aos_workqueue_t *workqueue);

/**
 * This function will initialize a work.
 *
 * @param[in]  work  the work to be initialized.
 * @param[in]  fn    the call back function to run.
 * @param[in]  arg   the paraments of the function.
 * @param[in]  dly   ms to delay before run.
 *
 * @return  0: success.
 */
int aos_work_init(aos_work_t *work, void (*fn)(void *), void *arg, int dly);

/**
 * This function will destroy a work.
 *
 * @param[in]  work  the work to be destroied.
 */
void aos_work_destroy(aos_work_t *work);

/**
 * This function will run a work on a workqueue.
 *
 * @param[in]  workqueue  the workqueue to run work.
 * @param[in]  work       the work to run.
 *
 * @return  0: success.
 */
int aos_work_run(aos_workqueue_t *workqueue, aos_work_t *work);

/**
 * This function will run a work on the default workqueue.
 *
 * @param[in]  work  the work to run.
 *
 * @return  0: success.
 */
int aos_work_sched(aos_work_t *work);

/**
 * This function will cancel a work on the default workqueue.
 *
 * @param[in]  work  the work to cancel.
 *
 * @return  0: success.
 */
int aos_work_cancel(aos_work_t *work);

/**
 * Realloc memory.
 *
 * @param[in]  mem   current memory address point.
 * @param[in]  size  new size of the mem to remalloc.
 *
 * @return  NULL: error.
 */
void *aos_realloc(void *mem, unsigned int size);
void *aos_realloc_check(void *mem, unsigned int size);

/**
 * Alloc memory.
 *
 * @param[in]  size  size of the mem to malloc.
 *
 * @return  NULL: error.
 */
void *aos_malloc(unsigned int size);
void *aos_malloc_check(unsigned int size);

/**
 * Alloc memory and clear to zero.
 *
 * @param[in]  size  size of the mem to malloc.
 *
 * @return  NULL: error.
 */
void *aos_zalloc(unsigned int size);
void *aos_zalloc_check(unsigned int size);

void *aos_calloc(unsigned int size, int num);
void *aos_calloc_check(unsigned int size, int num);

/**
 * Trace alloced mems.
 *
 * @param[in]  addr       pointer of the mem alloced by malloc.
 * @param[in]  allocator  buildin_address.
 */
void aos_alloc_trace(void *addr, size_t allocator);

/**
 * Free memory.
 *
 * @param[in]  ptr  address point of the mem.
 */
void aos_free(void *mem);

/**
 * Free memory and set NULL.
 *
 * @param[in]  *ptr  address point of the mem.
 */
void aos_freep(char **ptr);

/**
 * Get current time in nano seconds.
 *
 * @return  elapsed time in nano seconds from system starting.
 */
long long aos_now(void);

/**
 * Get current time in mini seconds.
 *
 * @return  elapsed time in mini seconds from system starting.
 */
long long aos_now_ms(void);

/**
 * Msleep.
 *
 * @param[in]  ms  sleep time in milliseconds.
 */
void aos_msleep(int ms);

/**
 * Initialize system
 */
void aos_init(void);

/**
 * Start system
 */
void aos_start(void);

/// System enter interrupt status.
/// \return execution status code. \ref k_status_t
k_status_t aos_kernel_intrpt_enter(void);

/// System exit interrupt status.
/// \return execution status code. \ref k_status_t
k_status_t aos_kernel_intrpt_exit(void);

/**
 * Get aos memory used info.
 *
 * @param[out]  total   the total memory can be use.
 * @param[out]  used    the used memory by malloc.
 * @param[out]  mfree   the free memory can be use.
 * @param[out]  peak    the peak memory used.
 *
 * @return  execution status code.
 */
int aos_get_mminfo(int32_t *total, int32_t *used, int32_t *mfree, int32_t *peak);

/**
 * Dump aos memory .
 *
 * @return  execution status code.
 */
int aos_mm_dump(void);

/// Suspend the scheduler.
void aos_kernel_sched_suspend(void);

/// Resume the scheduler.
void aos_kernel_sched_resume(void);

uint64_t aos_kernel_tick2ms(uint32_t ticks);

uint64_t aos_kernel_ms2tick(uint32_t ms);

int32_t aos_kernel_suspend(void);

void aos_kernel_resume(int32_t ticks);

typedef void (*except_process_t)(int errno, const char *file, int line, const char *func_name, void *caller);
void aos_set_except_callback(except_process_t except);
void aos_set_except_default();


#ifdef __cplusplus
}
#endif

#endif /* AOS_KERNEL_H */

