rel_1.6.0 init

This commit is contained in:
guocheng.kgc 2020-06-18 20:06:52 +08:00 committed by shengdong.dsd
commit 27b3e2883d
19359 changed files with 8093121 additions and 0 deletions

View file

@ -0,0 +1,479 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include <string.h>
#include <stdlib.h>
#include <sys/time.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/semphr.h>
#include <aos/aos.h>
#define ms2tick(ms) (((ms)+portTICK_PERIOD_MS-1)/portTICK_PERIOD_MS)
void aos_reboot(void)
{
}
int aos_get_hz(void)
{
return 100;
}
const char *aos_version_get(void)
{
return "aos-linux-xxx";
}
#define AOS_MAGIC 0x20171020
typedef struct {
StaticTask_t fTask;
uint32_t key_bitmap;
void *keys[4];
void *stack;
char name[32];
uint32_t magic;
} AosStaticTask_t;
struct targ {
AosStaticTask_t *task;
void (*fn)(void *);
void *arg;
};
static void dfl_entry(void *arg)
{
struct targ *targ = arg;
void (*fn)(void *) = targ->fn;
void *farg = targ->arg;
free(targ);
fn(farg);
vTaskDelete(NULL);
}
void vPortCleanUpTCB(void *pxTCB)
{
AosStaticTask_t *task = (AosStaticTask_t *)pxTCB;
if (task->magic != AOS_MAGIC)
return;
free(task->stack);
free(task);
}
int aos_task_new(const char *name, void (*fn)(void *), void *arg,
int stack_size)
{
xTaskHandle xHandle;
AosStaticTask_t *task = malloc(sizeof(AosStaticTask_t));
struct targ *targ = malloc(sizeof(*targ));
void *stack = malloc(stack_size);
bzero(stack, stack_size);
bzero(task, sizeof(*task));
task->key_bitmap = 0xfffffff0;
task->stack = stack;
strncpy(task->name, name, sizeof(task->name)-1);
task->magic = AOS_MAGIC;
targ->task = task;
targ->fn = fn;
targ->arg = arg;
stack_size /= sizeof(StackType_t);
xHandle = xTaskCreateStatic(dfl_entry, name, stack_size, targ,
10, stack, &task->fTask);
if (xHandle == NULL) {
free(task);
free(stack);
free(targ);
}
return xHandle ? 0 : -1;
}
int aos_task_new_ext(aos_task_t *task, const char *name, void (*fn)(void *), void *arg,
int stack_size, int prio)
{
return aos_task_new(name, fn, arg, stack_size);
}
void aos_task_exit(int code)
{
vTaskDelete(NULL);
}
const char *aos_task_name(void)
{
AosStaticTask_t *task = (AosStaticTask_t *)xTaskGetCurrentTaskHandle();
if (task->magic != AOS_MAGIC)
return "unknown";
return task->name;
}
int aos_task_key_create(aos_task_key_t *key)
{
AosStaticTask_t *task = (AosStaticTask_t *)xTaskGetCurrentTaskHandle();
int i;
if (task->magic != AOS_MAGIC)
return -1;
for (i=0;i<4;i++) {
if (task->key_bitmap & (1 << i))
continue;
task->key_bitmap |= 1 << i;
*key = i;
return 0;
}
return -1;
}
void aos_task_key_delete(aos_task_key_t key)
{
AosStaticTask_t *task = (AosStaticTask_t *)xTaskGetCurrentTaskHandle();
if (task->magic != AOS_MAGIC)
return;
task->key_bitmap &= ~(1 << key);
}
int aos_task_setspecific(aos_task_key_t key, void *vp)
{
AosStaticTask_t *task = (AosStaticTask_t *)xTaskGetCurrentTaskHandle();
if (key >= 4)
return -1;
if (task->magic != AOS_MAGIC)
return -1;
task->keys[key] = vp;
return 0;
}
void *aos_task_getspecific(aos_task_key_t key)
{
AosStaticTask_t *task = (AosStaticTask_t *)xTaskGetCurrentTaskHandle();
if (key >= 4)
return NULL;
if (task->magic != AOS_MAGIC)
return NULL;
return task->keys[key];
}
int aos_mutex_new(aos_mutex_t *mutex)
{
SemaphoreHandle_t mux = xSemaphoreCreateMutex();
mutex->hdl = mux;
return mux != NULL ? 0 : -1;
}
void aos_mutex_free(aos_mutex_t *mutex)
{
vSemaphoreDelete(mutex->hdl);
}
int aos_mutex_lock(aos_mutex_t *mutex, unsigned int ms)
{
if (mutex) {
xSemaphoreTake(mutex->hdl, ms == AOS_WAIT_FOREVER ? portMAX_DELAY : ms2tick(ms));
}
return 0;
}
int aos_mutex_unlock(aos_mutex_t *mutex)
{
if (mutex) {
xSemaphoreGive(mutex->hdl);
}
return 0;
}
int aos_mutex_is_valid(aos_mutex_t *mutex)
{
return mutex->hdl != NULL;
}
int aos_sem_new(aos_sem_t *sem, int count)
{
SemaphoreHandle_t s = xSemaphoreCreateCounting(128, count);
sem->hdl = s;
return 0;
}
void aos_sem_free(aos_sem_t *sem)
{
if (sem == NULL) {
return;
}
vSemaphoreDelete(sem->hdl);
}
int aos_sem_wait(aos_sem_t *sem, unsigned int ms)
{
if (sem == NULL) {
return -1;
}
int ret = xSemaphoreTake(sem->hdl, ms == AOS_WAIT_FOREVER ? portMAX_DELAY : ms2tick(ms));
return ret == pdPASS ? 0 : -1;
}
void aos_sem_signal(aos_sem_t *sem)
{
if (sem == NULL) {
return;
}
xSemaphoreGive(sem->hdl);
}
int aos_sem_is_valid(aos_sem_t *sem)
{
return sem && sem->hdl != NULL;
}
void aos_sem_signal_all(aos_sem_t *sem)
{
aos_sem_signal(sem);
}
int aos_queue_new(aos_queue_t *queue, void *buf, unsigned int size, int max_msg)
{
xQueueHandle q;
q = xQueueCreate(size / max_msg, max_msg);
queue->hdl = q;
return 0;
}
void aos_queue_free(aos_queue_t *queue)
{
vQueueDelete(queue->hdl);
}
int aos_queue_send(aos_queue_t *queue, void *msg, unsigned int size)
{
return xQueueSend(queue->hdl, msg, portMAX_DELAY) == pdPASS ? 0 : -1;
}
int aos_queue_recv(aos_queue_t *queue, unsigned int ms, void *msg,
unsigned int *size)
{
return xQueueReceive(queue->hdl, msg, ms == AOS_WAIT_FOREVER ? portMAX_DELAY : ms2tick(ms))
== pdPASS ? 0 : -1;
}
int aos_queue_is_valid(aos_queue_t *queue)
{
return queue && queue->hdl != NULL;
}
void *aos_queue_buf_ptr(aos_queue_t *queue)
{
return NULL;
}
int aos_timer_new(aos_timer_t *timer, void (*fn)(void *, void *),
void *arg, int ms, int repeat)
{
return -1;
}
void aos_timer_free(aos_timer_t *timer)
{
}
int aos_timer_start(aos_timer_t *timer)
{
return -1;
}
int aos_timer_stop(aos_timer_t *timer)
{
return -1;
}
int aos_timer_change(aos_timer_t *timer, int ms)
{
return -1;
}
int aos_workqueue_create(aos_workqueue_t *workqueue, int pri, int stack_size)
{
return -1;
}
struct work {
void (*fn)(void *);
void *arg;
int dly;
};
int aos_work_init(aos_work_t *work, void (*fn)(void *), void *arg, int dly)
{
struct work *w = malloc(sizeof(*w));
w->fn = fn;
w->arg = arg;
w->dly = dly;
work->hdl = w;
return 0;
}
void aos_work_destroy(aos_work_t *work)
{
free(work->hdl);
}
int aos_work_run(aos_workqueue_t *workqueue, aos_work_t *work)
{
return aos_work_sched(work);
}
static void worker_entry(void *arg)
{
struct work *w = arg;
if (w->dly) {
usleep(w->dly * 1000);
}
w->fn(w->arg);
}
int aos_work_sched(aos_work_t *work)
{
struct work *w = work->hdl;
return aos_task_new("worker", worker_entry, w, 8192);
}
int aos_work_cancel(aos_work_t *work)
{
return -1;
}
void *aos_zalloc(unsigned int size)
{
return calloc(size, 1);
}
void *aos_malloc(unsigned int size)
{
return malloc(size);
}
void *aos_realloc(void *mem, unsigned int size)
{
return realloc(mem, size);
}
void aos_alloc_trace(void *addr, size_t allocator)
{
}
void aos_free(void *mem)
{
free(mem);
}
#ifndef timercmp
#define timercmp(a, b, op) ({ \
unsigned long long _v1 = (a)->tv_sec * 1000000ULL + (a)->tv_usec; \
unsigned long long _v2 = (b)->tv_sec * 1000000ULL + (b)->tv_usec; \
_v1 op _v2; \
})
void timersub(struct timeval *a, struct timeval *b, struct timeval *res)
{
res->tv_usec = a->tv_usec - b->tv_usec;
res->tv_sec = a->tv_sec - b->tv_sec;
if (res->tv_usec < 0) {
res->tv_usec += 1000000;
res->tv_sec -= 1;
}
}
#endif
static struct timeval sys_start_time;
long long aos_now(void)
{
struct timeval tv;
long long ns;
gettimeofday(&tv, NULL);
timersub(&tv, &sys_start_time, &tv);
ns = tv.tv_sec * 1000000LL + tv.tv_usec;
return ns * 1000LL;
}
long long aos_now_ms(void)
{
struct timeval tv;
long long ms;
gettimeofday(&tv, NULL);
timersub(&tv, &sys_start_time, &tv);
ms = tv.tv_sec * 1000LL + tv.tv_usec / 1000;
return ms;
}
void aos_msleep(int ms)
{
usleep(ms * 1000);
}
void aos_init(void)
{
gettimeofday(&sys_start_time, NULL);
}
void aos_start(void)
{
}
void dumpsys_task_func(void)
{
#if configUSE_TRACE_FACILITY
TaskStatus_t *pxTaskStatusArray;
volatile UBaseType_t uxArraySize, x;
uint32_t ulTotalRunTime, ulStatsAsPercentage;
uxArraySize = uxTaskGetNumberOfTasks();
pxTaskStatusArray = malloc( uxArraySize * sizeof( TaskStatus_t ) );
if( pxTaskStatusArray == NULL )
return;
uxArraySize = uxTaskGetSystemState( pxTaskStatusArray, uxArraySize, &ulTotalRunTime );
// For percentage calculations.
ulTotalRunTime /= 100UL;
// Avoid divide by zero errors.
if( ulTotalRunTime > 0 )
{
// For each populated position in the pxTaskStatusArray array,
// format the raw data as human readable ASCII data
for( x = 0; x < uxArraySize; x++ )
{
// What percentage of the total run time has the task used?
// This will always be rounded down to the nearest integer.
// ulTotalRunTimeDiv100 has already been divided by 100.
ulStatsAsPercentage = pxTaskStatusArray[ x ].ulRunTimeCounter / ulTotalRunTime;
if( ulStatsAsPercentage > 0UL )
{
printf("%s\t\t%u\t\t%u%%\r\n", pxTaskStatusArray[ x ].pcTaskName, pxTaskStatusArray[ x ].ulRunTimeCounter, ulStatsAsPercentage );
}
else
{
printf("%s\t\t%u\t\t<1%%\r\n", pxTaskStatusArray[ x ].pcTaskName, pxTaskStatusArray[ x ].ulRunTimeCounter );
}
}
}
free( pxTaskStatusArray );
#endif
}

View file

@ -0,0 +1,436 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include <sys/prctl.h>
#include <pthread.h>
#undef WITH_LWIP
#undef WITH_SAL
#include <aos/aos.h>
#include <poll.h>
void aos_reboot(void)
{
exit(0);
}
int aos_get_hz(void)
{
return 100;
}
const char *aos_version_get(void)
{
return "aos-linux-xxx";
}
struct targ {
const char *name;
void (*fn)(void *);
void *arg;
};
static void *dfl_entry(void *arg)
{
struct targ *targ = arg;
void (*fn)(void *) = targ->fn;
void *farg = targ->arg;
prctl(PR_SET_NAME, (unsigned long)targ->name, 0, 0, 0);
free(targ);
fn(farg);
return 0;
}
int aos_task_new(const char *name, void (*fn)(void *), void *arg,
int stack_size)
{
int ret;
pthread_t th;
struct targ *targ = malloc(sizeof(*targ));
targ->name = strdup(name);
targ->fn = fn;
targ->arg = arg;
ret = pthread_create(&th, NULL, dfl_entry, targ);
if (ret == 0) ret = pthread_detach(th);
return ret;
}
int aos_task_new_ext(aos_task_t *task, const char *name, void (*fn)(void *), void *arg,
int stack_size, int prio)
{
return aos_task_new(name, fn, arg, stack_size);
}
void aos_task_exit(int code)
{
pthread_exit((void *)code);
}
const char *aos_task_name(void)
{
static char name[16];
prctl(PR_GET_NAME, (unsigned long)name, 0, 0, 0);
return name;
}
int aos_task_key_create(aos_task_key_t *key)
{
return pthread_key_create(key, NULL);
}
void aos_task_key_delete(aos_task_key_t key)
{
pthread_key_delete(key);
}
int aos_task_setspecific(aos_task_key_t key, void *vp)
{
return pthread_setspecific(key, vp);
}
void *aos_task_getspecific(aos_task_key_t key)
{
return pthread_getspecific(key);
}
int aos_mutex_new(aos_mutex_t *mutex)
{
pthread_mutex_t *mtx = malloc(sizeof(*mtx));
pthread_mutex_init(mtx, NULL);
mutex->hdl = mtx;
return 0;
}
void aos_mutex_free(aos_mutex_t *mutex)
{
pthread_mutex_destroy(mutex->hdl);
free(mutex->hdl);
}
int aos_mutex_lock(aos_mutex_t *mutex, unsigned int timeout)
{
if (mutex) {
pthread_mutex_lock(mutex->hdl);
}
return 0;
}
int aos_mutex_unlock(aos_mutex_t *mutex)
{
if (mutex) {
pthread_mutex_unlock(mutex->hdl);
}
return 0;
}
int aos_mutex_is_valid(aos_mutex_t *mutex)
{
return mutex->hdl != NULL;
}
#include <semaphore.h>
int aos_sem_new(aos_sem_t *sem, int count)
{
sem_t *s = malloc(sizeof(*s));
sem_init(s, 0, count);
sem->hdl = s;
return 0;
}
void aos_sem_free(aos_sem_t *sem)
{
if (sem == NULL) {
return;
}
sem_destroy(sem->hdl);
free(sem->hdl);
}
int aos_sem_wait(aos_sem_t *sem, unsigned int timeout)
{
int sec;
int nsec;
if (sem == NULL) {
return -EINVAL;
}
if (timeout == AOS_WAIT_FOREVER) {
return sem_wait(sem->hdl);
} else if (timeout == 0) {
return sem_trywait(sem->hdl);
}
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
sec = timeout / 1000;
nsec = (timeout % 1000) * 1000;
ts.tv_nsec += nsec;
sec += (ts.tv_nsec / 1000000000);
ts.tv_nsec %= 1000000000;
ts.tv_sec += sec;
return sem_timedwait(sem->hdl, &ts);
}
void aos_sem_signal(aos_sem_t *sem)
{
if (sem == NULL) {
return;
}
sem_post(sem->hdl);
}
int aos_sem_is_valid(aos_sem_t *sem)
{
return sem && sem->hdl != NULL;
}
void aos_sem_signal_all(aos_sem_t *sem)
{
sem_post(sem->hdl);
}
struct queue {
int fds[2];
void *buf;
int size;
int msg_size;
};
int aos_queue_new(aos_queue_t *queue, void *buf, unsigned int size, int max_msg)
{
struct queue *q = malloc(sizeof(*q));
pipe(q->fds);
q->buf = buf;
q->size = size;
q->msg_size = max_msg;
queue->hdl = q;
return 0;
}
void aos_queue_free(aos_queue_t *queue)
{
struct queue *q = queue->hdl;
close(q->fds[0]);
close(q->fds[1]);
free(q);
}
int aos_queue_send(aos_queue_t *queue, void *msg, unsigned int size)
{
struct queue *q = queue->hdl;
write(q->fds[1], msg, size);
return 0;
}
int aos_queue_recv(aos_queue_t *queue, unsigned int ms, void *msg,
unsigned int *size)
{
struct queue *q = queue->hdl;
struct pollfd rfd = {
.fd = q->fds[0],
.events = POLLIN,
};
poll(&rfd, 1, ms);
if (rfd.revents & POLLIN) {
int len = read(q->fds[0], msg, q->msg_size);
*size = len;
return len < 0 ? -1 : 0;
}
return -1;
}
int aos_queue_is_valid(aos_queue_t *queue)
{
return queue->hdl != NULL;
}
void *aos_queue_buf_ptr(aos_queue_t *queue)
{
struct queue *q = queue->hdl;
return q->buf;
}
int aos_timer_new(aos_timer_t *timer, void (*fn)(void *, void *),
void *arg, int ms, int repeat)
{
return -1;
}
void aos_timer_free(aos_timer_t *timer)
{
}
int aos_timer_start(aos_timer_t *timer)
{
return -1;
}
int aos_timer_stop(aos_timer_t *timer)
{
return -1;
}
int aos_timer_change(aos_timer_t *timer, int ms)
{
return -1;
}
int aos_workqueue_create(aos_workqueue_t *workqueue, int pri, int stack_size)
{
return -1;
}
struct work {
void (*fn)(void *);
void *arg;
int dly;
};
int aos_work_init(aos_work_t *work, void (*fn)(void *), void *arg, int dly)
{
struct work *w = malloc(sizeof(*w));
w->fn = fn;
w->arg = arg;
w->dly = dly;
work->hdl = w;
return 0;
}
void aos_work_destroy(aos_work_t *work)
{
free(work->hdl);
}
int aos_work_run(aos_workqueue_t *workqueue, aos_work_t *work)
{
return aos_work_sched(work);
}
static void worker_entry(void *arg)
{
struct work *w = arg;
if (w->dly) {
usleep(w->dly * 1000);
}
w->fn(w->arg);
}
int aos_work_sched(aos_work_t *work)
{
struct work *w = work->hdl;
return aos_task_new("worker", worker_entry, w, 8192);
}
int aos_work_cancel(aos_work_t *work)
{
return -1;
}
void *aos_zalloc(unsigned int size)
{
return calloc(size, 1);
}
void *aos_malloc(unsigned int size)
{
return malloc(size);
}
void *aos_realloc(void *mem, unsigned int size)
{
return realloc(mem, size);
}
void aos_alloc_trace(void *addr, size_t allocator)
{
}
void aos_free(void *mem)
{
free(mem);
}
static struct timeval sys_start_time;
long long aos_now(void)
{
struct timeval tv;
long long ns;
gettimeofday(&tv, NULL);
timersub(&tv, &sys_start_time, &tv);
ns = tv.tv_sec * 1000000LL + tv.tv_usec;
return ns * 1000LL;
}
long long aos_now_ms(void)
{
struct timeval tv;
long long ms;
gettimeofday(&tv, NULL);
timersub(&tv, &sys_start_time, &tv);
ms = tv.tv_sec * 1000LL + tv.tv_usec / 1000;
return ms;
}
void aos_msleep(int ms)
{
usleep(ms * 1000);
}
void aos_init(void)
{
gettimeofday(&sys_start_time, NULL);
}
void aos_start(void)
{
while (1) {
usleep(1000 * 1000 * 100);
}
}
#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
void dumpsys_task_func(void)
{
DIR *proc = opendir("/proc/self/task");
while (1) {
struct dirent *ent = readdir(proc);
if (!ent) {
break;
}
if (ent->d_name[0] == '.') {
continue;
}
char fn[128];
snprintf(fn, sizeof fn, "/proc/self/task/%s/comm", ent->d_name);
FILE *fp = fopen(fn, "r");
if (!fp) {
continue;
}
bzero(fn, sizeof fn);
fread(fn, sizeof(fn) - 1, 1, fp);
fclose(fp);
printf("%8s - %s", ent->d_name, fn);
}
closedir(proc);
}

View file

@ -0,0 +1,926 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include <k_api.h>
#include <errno.h>
#include <aos/aos.h>
#include "errno_mapping.h"
#if (RHINO_CONFIG_KOBJ_DYN_ALLOC == 0)
#warning "RHINO_CONFIG_KOBJ_DYN_ALLOC is disabled!"
#endif
#define MS2TICK(ms) krhino_ms_to_ticks(ms)
static unsigned int used_bitmap;
static int error_mapping(int ret)
{
switch(ret) {
case RHINO_SYS_SP_ERR:
case RHINO_NULL_PTR:
case RHINO_MM_FREE_ADDR_ERR:
return -EFAULT;
case RHINO_INV_PARAM:
case RHINO_INV_ALIGN:
case RHINO_KOBJ_TYPE_ERR:
case RHINO_MM_POOL_SIZE_ERR:
case RHINO_MM_ALLOC_SIZE_ERR:
case RHINO_INV_SCHED_WAY:
case RHINO_TASK_INV_STACK_SIZE:
case RHINO_BEYOND_MAX_PRI:
case RHINO_BUF_QUEUE_INV_SIZE:
case RHINO_BUF_QUEUE_SIZE_ZERO:
case RHINO_BUF_QUEUE_MSG_SIZE_OVERFLOW:
case RHINO_QUEUE_FULL:
case RHINO_QUEUE_NOT_FULL:
case RHINO_SEM_OVF:
case RHINO_WORKQUEUE_EXIST:
case RHINO_WORKQUEUE_NOT_EXIST:
case RHINO_WORKQUEUE_WORK_EXIST:
return -EINVAL;
case RHINO_KOBJ_BLK:
return -EAGAIN;
case RHINO_NO_MEM:
return -ENOMEM;
case RHINO_KOBJ_DEL_ERR:
case RHINO_SCHED_DISABLE:
case RHINO_SCHED_ALREADY_ENABLED:
case RHINO_SCHED_LOCK_COUNT_OVF:
case RHINO_TASK_NOT_SUSPENDED:
case RHINO_TASK_DEL_NOT_ALLOWED:
case RHINO_TASK_SUSPEND_NOT_ALLOWED:
case RHINO_SUSPENDED_COUNT_OVF:
case RHINO_PRI_CHG_NOT_ALLOWED:
case RHINO_NOT_CALLED_BY_INTRPT:
case RHINO_NO_THIS_EVENT_OPT:
case RHINO_TIMER_STATE_INV:
case RHINO_BUF_QUEUE_FULL:
case RHINO_SEM_TASK_WAITING:
case RHINO_MUTEX_NOT_RELEASED_BY_OWNER:
case RHINO_WORKQUEUE_WORK_RUNNING:
return -EPERM;
case RHINO_TRY_AGAIN:
case RHINO_WORKQUEUE_BUSY:
return -EAGAIN;
default:
return -1;
}
}
extern void hal_reboot(void);
void aos_reboot(void)
{
hal_reboot();
}
int aos_get_hz(void)
{
return RHINO_CONFIG_TICKS_PER_SECOND;
}
const char *aos_version_get(void)
{
return SYSINFO_KERNEL_VERSION;
}
#if (RHINO_CONFIG_KOBJ_DYN_ALLOC > 0)
int aos_task_new(const char *name, void (*fn)(void *), void *arg,
int stack_size)
{
int ret;
ktask_t *task_handle = NULL;
ret = (int)krhino_task_dyn_create(&task_handle, name, arg, AOS_DEFAULT_APP_PRI, 0,
stack_size / sizeof(cpu_stack_t), fn, 1u);
if (ret == RHINO_SUCCESS) {
return 0;
}
return ERRNO_MAPPING(ret);
}
int aos_task_new_ext(aos_task_t *task, const char *name, void (*fn)(void *), void *arg,
int stack_size, int prio)
{
int ret;
ret = (int)krhino_task_dyn_create((ktask_t **)(&(task->hdl)), name, arg, prio, 0,
stack_size / sizeof(cpu_stack_t), fn, 1u);
if (ret == RHINO_SUCCESS) {
return 0;
}
return ERRNO_MAPPING(ret);
}
void aos_task_exit(int code)
{
(void)code;
krhino_task_dyn_del(NULL);
}
#endif
const char *aos_task_name(void)
{
return krhino_cur_task_get()->task_name;
}
int aos_task_key_create(aos_task_key_t *key)
{
int i;
for (i = RHINO_CONFIG_TASK_INFO_NUM - 1; i >= 0; i--) {
if (!((1 << i) & used_bitmap)) {
used_bitmap |= 1 << i;
*key = i;
return 0;
}
}
return -EINVAL;
}
void aos_task_key_delete(aos_task_key_t key)
{
if (key >= RHINO_CONFIG_TASK_INFO_NUM) {
return;
}
used_bitmap &= ~(1 << key);
}
#if (RHINO_CONFIG_TASK_INFO > 0)
int aos_task_setspecific(aos_task_key_t key, void *vp)
{
int ret;
ret = krhino_task_info_set(krhino_cur_task_get(), key, vp);
if (ret == RHINO_SUCCESS) {
return 0;
}
return ERRNO_MAPPING(ret);
}
void *aos_task_getspecific(aos_task_key_t key)
{
void *vp = NULL;
krhino_task_info_get(krhino_cur_task_get(), key, &vp);
return vp;
}
#endif
#if (RHINO_CONFIG_KOBJ_DYN_ALLOC > 0)
int aos_mutex_new(aos_mutex_t *mutex)
{
kstat_t ret;
kmutex_t *m;
if (mutex == NULL) {
return -EINVAL;
}
m = aos_malloc(sizeof(kmutex_t));
if (m == NULL) {
return -ENOMEM;
}
ret = krhino_mutex_create(m, "AOS");
if (ret != RHINO_SUCCESS) {
aos_free(m);
return ERRNO_MAPPING(ret);
}
mutex->hdl = m;
return 0;
}
void aos_mutex_free(aos_mutex_t *mutex)
{
if (mutex == NULL) {
return;
}
krhino_mutex_del(mutex->hdl);
aos_free(mutex->hdl);
mutex->hdl = NULL;
}
int aos_mutex_lock(aos_mutex_t *mutex, unsigned int timeout)
{
kstat_t ret;
if (mutex == NULL) {
return -EINVAL;
}
if (timeout == AOS_WAIT_FOREVER) {
ret = krhino_mutex_lock(mutex->hdl, RHINO_WAIT_FOREVER);
} else {
ret = krhino_mutex_lock(mutex->hdl, MS2TICK(timeout));
}
/* rhino allow nested */
if (ret == RHINO_MUTEX_OWNER_NESTED) {
ret = RHINO_SUCCESS;
}
if (ret == RHINO_SUCCESS) {
return 0;
}
return ERRNO_MAPPING(ret);
}
int aos_mutex_unlock(aos_mutex_t *mutex)
{
kstat_t ret;
if (mutex == NULL) {
return -EINVAL;
}
ret = krhino_mutex_unlock(mutex->hdl);
/* rhino allow nested */
if (ret == RHINO_MUTEX_OWNER_NESTED) {
ret = RHINO_SUCCESS;
}
if (ret == RHINO_SUCCESS) {
return 0;
}
return ERRNO_MAPPING(ret);
}
int aos_mutex_is_valid(aos_mutex_t *mutex)
{
kmutex_t *k_mutex;
if (mutex == NULL) {
return 0;
}
k_mutex = mutex->hdl;
if (k_mutex == NULL) {
return 0;
}
return 1;
}
#endif
#if ((RHINO_CONFIG_KOBJ_DYN_ALLOC > 0)&&(RHINO_CONFIG_SEM > 0))
int aos_sem_new(aos_sem_t *sem, int count)
{
kstat_t ret;
ksem_t *s;
if (sem == NULL) {
return -EINVAL;
}
s = aos_malloc(sizeof(ksem_t));
if (s == NULL) {
return -ENOMEM;
}
ret = krhino_sem_create(s, "AOS", count);
if (ret != RHINO_SUCCESS) {
aos_free(s);
return ERRNO_MAPPING(ret);
}
sem->hdl = s;
return 0;
}
void aos_sem_free(aos_sem_t *sem)
{
if (sem == NULL) {
return;
}
krhino_sem_del(sem->hdl);
aos_free(sem->hdl);
sem->hdl = NULL;
}
int aos_sem_wait(aos_sem_t *sem, unsigned int timeout)
{
kstat_t ret;
if (sem == NULL) {
return -EINVAL;
}
if (timeout == AOS_WAIT_FOREVER) {
ret = krhino_sem_take(sem->hdl, RHINO_WAIT_FOREVER);
} else {
ret = krhino_sem_take(sem->hdl, MS2TICK(timeout));
}
if (ret == RHINO_SUCCESS) {
return 0;
}
return ERRNO_MAPPING(ret);
}
void aos_sem_signal(aos_sem_t *sem)
{
if (sem == NULL) {
return;
}
krhino_sem_give(sem->hdl);
}
int aos_sem_is_valid(aos_sem_t *sem)
{
ksem_t *k_sem;
if (sem == NULL) {
return 0;
}
k_sem = sem->hdl;
if (k_sem == NULL) {
return 0;
}
return 1;
}
void aos_sem_signal_all(aos_sem_t *sem)
{
if (sem == NULL) {
return;
}
krhino_sem_give_all(sem->hdl);
}
#endif
#if (RHINO_CONFIG_EVENT_FLAG > 0)
int aos_event_new(aos_event_t *event, unsigned int flags)
{
int ret;
ret = (int)krhino_event_dyn_create((kevent_t **)(&(event->hdl)), "AOS", flags);
if (ret == RHINO_SUCCESS) {
return 0;
}
return ERRNO_MAPPING(ret);
}
void aos_event_free(aos_event_t *event)
{
if (event == NULL) {
return;
}
krhino_event_dyn_del(event->hdl);
event->hdl = NULL;
}
int aos_event_get
(
aos_event_t *event,
unsigned int flags,
unsigned char opt,
unsigned int *actl_flags,
unsigned int timeout
)
{
kstat_t ret;
if (event == NULL) {
return -EINVAL;
}
if (timeout == AOS_WAIT_FOREVER) {
ret = krhino_event_get(event->hdl, flags, opt, actl_flags, RHINO_WAIT_FOREVER);
} else {
ret = krhino_event_get(event->hdl, flags, opt, actl_flags, MS2TICK(timeout));
}
if (ret == RHINO_SUCCESS) {
return 0;
}
return ERRNO_MAPPING(ret);
}
int aos_event_set(aos_event_t *event, unsigned int flags, unsigned char opt)
{
kstat_t ret;
if (event == NULL) {
return -EINVAL;
}
ret = krhino_event_set(event->hdl, flags, opt);
if (ret == RHINO_SUCCESS) {
return 0;
}
return ERRNO_MAPPING(ret);
}
#endif
#if (RHINO_CONFIG_BUF_QUEUE > 0)
int aos_queue_new(aos_queue_t *queue, void *buf, unsigned int size, int max_msg)
{
kstat_t ret;
kbuf_queue_t *q;
if ((queue == NULL) || (buf == NULL)) {
return -EINVAL;
}
q = aos_malloc(sizeof(kbuf_queue_t));
if (q == NULL) {
return -ENOMEM;
}
ret = krhino_buf_queue_create(q, "AOS", buf, size, max_msg);
if (ret != RHINO_SUCCESS) {
aos_free(q);
return ERRNO_MAPPING(ret);
}
queue->hdl = q;
return 0;
}
void aos_queue_free(aos_queue_t *queue)
{
if (queue == NULL) {
return;
}
krhino_buf_queue_del(queue->hdl);
aos_free(queue->hdl);
queue->hdl = NULL;
}
int aos_queue_send(aos_queue_t *queue, void *msg, unsigned int size)
{
int ret;
if ((queue == NULL) || (msg == NULL)) {
return -EINVAL;
}
ret = krhino_buf_queue_send(queue->hdl, msg, size);
if (ret == RHINO_SUCCESS) {
return 0;
}
return ERRNO_MAPPING(ret);
}
int aos_queue_recv(aos_queue_t *queue, unsigned int ms, void *msg,
unsigned int *size)
{
int ret;
if (queue == NULL) {
return -EINVAL;
}
if (ms == AOS_WAIT_FOREVER) {
ret = krhino_buf_queue_recv(queue->hdl, RHINO_WAIT_FOREVER, msg, size);
} else {
ret = krhino_buf_queue_recv(queue->hdl, MS2TICK(ms), msg, size);
}
if (ret == RHINO_SUCCESS) {
return 0;
}
return ERRNO_MAPPING(ret);
}
int aos_queue_is_valid(aos_queue_t *queue)
{
kbuf_queue_t *k_queue;
if (queue == NULL) {
return 0;
}
k_queue = queue->hdl;
if (k_queue == NULL) {
return 0;
}
return 1;
}
void *aos_queue_buf_ptr(aos_queue_t *queue)
{
if (!aos_queue_is_valid(queue)) {
return NULL;
}
return ((kbuf_queue_t *)queue->hdl)->buf;
}
#endif
#if (RHINO_CONFIG_TIMER > 0)
int aos_timer_new(aos_timer_t *timer, void (*fn)(void *, void *),
void *arg, int ms, int repeat)
{
kstat_t ret;
if (timer == NULL) {
return -EINVAL;
}
if (repeat == 0) {
ret = krhino_timer_dyn_create(((ktimer_t **)(&timer->hdl)), "AOS", (timer_cb_t)fn, MS2TICK(ms), 0, arg, 1);
} else {
ret = krhino_timer_dyn_create(((ktimer_t **)(&timer->hdl)), "AOS", (timer_cb_t)fn, MS2TICK(ms), MS2TICK(ms),
arg, 1);
}
if (ret != RHINO_SUCCESS) {
return ERRNO_MAPPING(ret);
}
return 0;
}
int aos_timer_new_ext(aos_timer_t *timer, void (*fn)(void *, void *),
void *arg, int ms, int repeat, unsigned char auto_run)
{
kstat_t ret;
if (timer == NULL) {
return -EINVAL;
}
if (repeat == 0) {
ret = krhino_timer_dyn_create(((ktimer_t **)(&timer->hdl)), "AOS", (timer_cb_t)fn, MS2TICK(ms), 0, arg, auto_run);
} else {
ret = krhino_timer_dyn_create(((ktimer_t **)(&timer->hdl)), "AOS", (timer_cb_t)fn, MS2TICK(ms), MS2TICK(ms),
arg, auto_run);
}
if (ret != RHINO_SUCCESS) {
return ERRNO_MAPPING(ret);
}
return 0;
}
void aos_timer_free(aos_timer_t *timer)
{
if (timer == NULL) {
return;
}
krhino_timer_dyn_del(timer->hdl);
timer->hdl = NULL;
}
int aos_timer_start(aos_timer_t *timer)
{
int ret;
if (timer == NULL) {
return -EINVAL;
}
ret = krhino_timer_start(timer->hdl);
if (ret == RHINO_SUCCESS) {
return 0;
}
return ERRNO_MAPPING(ret);
}
int aos_timer_stop(aos_timer_t *timer)
{
int ret;
if (timer == NULL) {
return -EINVAL;
}
ret = krhino_timer_stop(timer->hdl);
if (ret == RHINO_SUCCESS) {
return 0;
}
return ERRNO_MAPPING(ret);
}
int aos_timer_change(aos_timer_t *timer, int ms)
{
int ret;
if (timer == NULL) {
return -EINVAL;
}
ret = krhino_timer_change(timer->hdl, MS2TICK(ms), MS2TICK(ms));
if (ret == RHINO_SUCCESS) {
return 0;
}
return ERRNO_MAPPING(ret);
}
#endif
#if (RHINO_CONFIG_WORKQUEUE > 0)
int aos_workqueue_create(aos_workqueue_t *workqueue, int pri, int stack_size)
{
kstat_t ret;
cpu_stack_t *stk;
kworkqueue_t *wq;
if (workqueue == NULL) {
return -EINVAL;
}
if (stack_size < sizeof(cpu_stack_t)) {
return -EINVAL;
}
stk = aos_malloc(stack_size);
if (stk == NULL) {
return -ENOMEM;
}
wq = aos_malloc(sizeof(kworkqueue_t));
if (wq == NULL) {
aos_free(stk);
return -ENOMEM;
}
ret = krhino_workqueue_create(wq, "AOS", pri, stk,
stack_size / sizeof(cpu_stack_t));
if (ret != RHINO_SUCCESS) {
aos_free(wq);
aos_free(stk);
return ERRNO_MAPPING(ret);
}
workqueue->hdl = wq;
workqueue->stk = stk;
return 0;
}
int aos_work_init(aos_work_t *work, void (*fn)(void *), void *arg, int dly)
{
kstat_t ret;
kwork_t *w;
if (work == NULL) {
return -EINVAL;
}
w = aos_malloc(sizeof(kwork_t));
if (w == NULL) {
return -ENOMEM;
}
ret = krhino_work_init(w, fn, arg, MS2TICK(dly));
if (ret != RHINO_SUCCESS) {
aos_free(w);
return ERRNO_MAPPING(ret);
}
work->hdl = w;
return 0;
}
void aos_work_destroy(aos_work_t *work)
{
kwork_t *w;
if (work == NULL) {
return;
}
w = work->hdl;
if (w->timer != NULL) {
krhino_timer_stop(w->timer);
krhino_timer_dyn_del(w->timer);
}
aos_free(work->hdl);
work->hdl = NULL;
}
int aos_work_run(aos_workqueue_t *workqueue, aos_work_t *work)
{
int ret;
if ((workqueue == NULL) || (work == NULL)) {
return -EINVAL;
}
ret = krhino_work_run(workqueue->hdl, work->hdl);
if (ret == RHINO_SUCCESS) {
return 0;
}
return ERRNO_MAPPING(ret);
}
int aos_work_sched(aos_work_t *work)
{
int ret;
if (work == NULL) {
return -EINVAL;
}
ret = krhino_work_sched(work->hdl);
if (ret == RHINO_SUCCESS) {
return 0;
}
return ERRNO_MAPPING(ret);
}
int aos_work_cancel(aos_work_t *work)
{
int ret;
if (work == NULL) {
return -EINVAL;
}
ret = krhino_work_cancel(work->hdl);
if (ret != RHINO_SUCCESS) {
return -EBUSY;
}
return 0;
}
#endif
#if (RHINO_CONFIG_MM_TLF > 0)
void *aos_zalloc(unsigned int size)
{
void *tmp = NULL;
if (size == 0) {
return NULL;
}
#if (RHINO_CONFIG_MM_DEBUG > 0u && RHINO_CONFIG_GCC_RETADDR > 0u)
if ((size & AOS_UNSIGNED_INT_MSB) == 0) {
tmp = krhino_mm_alloc(size | AOS_UNSIGNED_INT_MSB);
#ifndef AOS_BINS
#if defined (__CC_ARM)
krhino_owner_attach(g_kmm_head, tmp, __return_address());
#elif defined (__GNUC__)
krhino_owner_attach(g_kmm_head, tmp, (size_t)__builtin_return_address(0));
#endif /* __CC_ARM */
#endif
} else {
tmp = krhino_mm_alloc(size);
}
#else
tmp = krhino_mm_alloc(size);
#endif
if (tmp) {
memset(tmp, 0, size);
}
return tmp;
}
void *aos_malloc(unsigned int size)
{
void *tmp = NULL;
if (size == 0) {
return NULL;
}
#if (RHINO_CONFIG_MM_DEBUG > 0u && RHINO_CONFIG_GCC_RETADDR > 0u)
if ((size & AOS_UNSIGNED_INT_MSB) == 0) {
tmp = krhino_mm_alloc(size | AOS_UNSIGNED_INT_MSB);
#ifndef AOS_BINS
#if defined (__CC_ARM)
krhino_owner_attach(g_kmm_head, tmp, __return_address());
#elif defined (__GNUC__)
krhino_owner_attach(g_kmm_head, tmp, (size_t)__builtin_return_address(0));
#endif /* __CC_ARM */
#endif
} else {
tmp = krhino_mm_alloc(size);
}
#else
tmp = krhino_mm_alloc(size);
#endif
return tmp;
}
void *aos_realloc(void *mem, unsigned int size)
{
void *tmp = NULL;
#if (RHINO_CONFIG_MM_DEBUG > 0u && RHINO_CONFIG_GCC_RETADDR > 0u)
if ((size & AOS_UNSIGNED_INT_MSB) == 0) {
tmp = krhino_mm_realloc(mem, size | AOS_UNSIGNED_INT_MSB);
#ifndef AOS_BINS
#if defined (__CC_ARM)
krhino_owner_attach(g_kmm_head, tmp, __return_address());
#elif defined (__GNUC__)
krhino_owner_attach(g_kmm_head, tmp, (size_t)__builtin_return_address(0));
#endif /* __CC_ARM */
#endif
} else {
tmp = krhino_mm_realloc(mem, size);
}
#else
tmp = krhino_mm_realloc(mem, size);
#endif
return tmp;
}
void aos_alloc_trace(void *addr, size_t allocator)
{
#if (RHINO_CONFIG_MM_DEBUG > 0u && RHINO_CONFIG_GCC_RETADDR > 0u)
krhino_owner_attach(g_kmm_head, addr, allocator);
#endif
}
void aos_free(void *mem)
{
if (mem == NULL) {
return;
}
krhino_mm_free(mem);
}
#endif
long long aos_now(void)
{
return krhino_sys_time_get() * 1000 * 1000;
}
long long aos_now_ms(void)
{
return krhino_sys_time_get();
}
void aos_msleep(int ms)
{
krhino_task_sleep(MS2TICK(ms));
}
void aos_init(void)
{
krhino_init();
}
void aos_start(void)
{
krhino_start();
}

View file

@ -0,0 +1,13 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#ifndef ERRNO_MAPPING_H
#define ERRNO_MAPPING_H
#include <errno.h>
#include <aos/aos.h>
#define ERRNO_MAPPING(ret) error_mapping(ret)
#endif /* ERRNO_MAPPING_H */

View file

@ -0,0 +1,919 @@
/* ----------------------------------------------------------------------
* $Date: 5. February 2013
* $Revision: V1.02
*
* Project: CMSIS-RTOS API
* Title: cmsis_os.c
*
* Version 0.02
* Initial Proposal Phase
* Version 0.03
* osKernelStart added, optional feature: main started as thread
* osSemaphores have standard behavior
* osTimerCreate does not start the timer, added osTimerStart
* osThreadPass is renamed to osThreadYield
* Version 1.01
* Support for C++ interface
* - const attribute removed from the osXxxxDef_t typedef's
* - const attribute added to the osXxxxDef macros
* Added: osTimerDelete, osMutexDelete, osSemaphoreDelete
* Added: osKernelInitialize
* Version 1.02
* Control functions for short timeouts in microsecond resolution:
* Added: osKernelSysTick, osKernelSysTickFrequency, osKernelSysTickMicroSec
* Removed: osSignalGet
*
*
*----------------------------------------------------------------------------
*
* Portions Copyright <EFBFBD> 2016 STMicroelectronics International N.V. All rights reserved.
* Portions Copyright (c) 2013 ARM LIMITED
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*---------------------------------------------------------------------------*/
/**
******************************************************************************
* @file cmsis_os.c
* @author AliOS-Things Team
* @date 16-Mar-2018
* @brief CMSIS-RTOS API implementation for AliOS-Things
******************************************************************************
*/
#include <string.h>
#include <cmsis_os.h>
/*
* ARM Compiler 4/5
*/
#if defined ( __CC_ARM )
#define __ASM __asm
#define __INLINE __inline
#define __STATIC_INLINE static __inline
#include "cmsis_armcc.h"
/*
* GNU Compiler
*/
#elif defined ( __GNUC__ )
#define __ASM __asm /*!< asm keyword for GNU Compiler */
#define __INLINE inline /*!< inline keyword for GNU Compiler */
#define __STATIC_INLINE static inline
#include "cmsis_gcc.h"
/*
* IAR Compiler
*/
#elif defined ( __ICCARM__ )
#ifndef __ASM
#define __ASM __asm
#endif
#ifndef __INLINE
#define __INLINE inline
#endif
#ifndef __STATIC_INLINE
#define __STATIC_INLINE static inline
#endif
#include <cmsis_iar.h>
#endif
/* Convert from CMSIS type osPriority to Rhino priority number */
static uint8_t makeRhinoPriority (osPriority priority)
{
uint8_t fpriority = RHINO_IDLE_PRI;
if (priority != osPriorityError)
{
fpriority -= (priority - osPriorityIdle);
}
return fpriority;
#if 0
typedef enum {
osPriorityIdle = -3, -> 62 - ((-3) - (-3))= 62 ///< priority: idle (lowest)
osPriorityLow = -2, -> 62 - ((-2) - (-3))= 61 ///< priority: low
osPriorityBelowNormal = -1, -> 62 - ((-1) - (-3))= 60 ///< priority: below normal
osPriorityNormal = 0, -> 62 - (( 0) - (-3))= 59 ///< priority: normal (default)
osPriorityAboveNormal = +1, -> 62 - ((+1) - (-3))= 58 ///< priority: above normal
osPriorityHigh = +2, -> 62 - ((+2) - (-3))= 57 ///< priority: high
osPriorityRealtime = +3, -> 62 - ((+3) - (-3))= 56 ///< priority: realtime (highest)
osPriorityError = 0x84 ///< system cannot determine priority or thread has illegal priority
} osPriority;
#endif
}
/* Convert from Rhino priority number to CMSIS type osPriority */
static osPriority makeCmsisPriority (uint8_t fpriority)
{
osPriority priority = osPriorityError;
if ((RHINO_IDLE_PRI - fpriority) <= (osPriorityRealtime - osPriorityIdle))
{
priority = (osPriority)((int)osPriorityIdle + (int)(RHINO_IDLE_PRI - fpriority));
}
return priority;
}
/*********************** Kernel Control Functions *****************************/
/**
* @brief Initialize the RTOS Kernel for creating objects.
* @retval status code that indicates the execution status of the function.
* @note MUST REMAIN UNCHANGED: \b osKernelInitialize shall be consistent in every CMSIS-RTOS.
*/
osStatus osKernelInitialize (void)
{
(void)krhino_init();
return osOK;
}
/**
* @brief Start the RTOS Kernel with executing the specified thread.
* @param thread_def thread definition referenced with \ref osThread.
* @param argument pointer that is passed to the thread function as start argument.
* @retval status code that indicates the execution status of the function
* @note MUST REMAIN UNCHANGED: \b osKernelStart shall be consistent in every CMSIS-RTOS.
*/
osStatus osKernelStart (void)
{
krhino_start();
return osOK;
}
/**
* @brief Check if the RTOS kernel is already started
* @param None
* @retval (0) RTOS is not started
* (1) RTOS is started
* (-1) if this feature is disabled
* @note MUST REMAIN UNCHANGED: \b osKernelRunning shall be consistent in every CMSIS-RTOS.
*/
int32_t osKernelRunning(void)
{
if (g_sys_stat == RHINO_RUNNING)
return 1;
else
return 0;
}
#if (defined (osFeature_SysTick) && (osFeature_SysTick != 0)) // System Timer available
/**
* @brief Get the value of the Kernel SysTick timer
* @param None
* @retval None
* @note MUST REMAIN UNCHANGED: \b osKernelSysTick shall be consistent in every CMSIS-RTOS.
*/
uint32_t osKernelSysTick(void)
{
return (uint32_t)g_tick_count;
}
#endif // System Timer available
/*********************** Thread Management *****************************/
/**
* @brief Create a thread and add it to Active Threads and set it to state READY.
* @param thread_def thread definition referenced with \ref osThread.
* @param argument pointer that is passed to the thread function as start argument.
* @retval thread ID for reference by other functions or NULL in case of error.
* @note MUST REMAIN UNCHANGED: \b osThreadCreate shall be consistent in every CMSIS-RTOS.
*/
osThreadId osThreadCreate (const osThreadDef_t *thread_def, void *argument)
{
ktask_t* ptcb;
if (RHINO_SUCCESS != krhino_task_create(thread_def->ptcb, thread_def->name, argument,
makeRhinoPriority(thread_def->tpriority),
thread_def->ticks, thread_def->pstackspace,
thread_def->stacksize,
(task_entry_t)thread_def->pthread, 1))
{
return NULL;
}
else
{
ptcb = thread_def->ptcb;
}
return (osThreadId)ptcb;
}
/**
* @brief Return the thread ID of the current running thread.
* @retval thread ID for reference by other functions or NULL in case of error.
* @note MUST REMAIN UNCHANGED: \b osThreadGetId shall be consistent in every CMSIS-RTOS.
*/
osThreadId osThreadGetId (void)
{
return (osThreadId)krhino_cur_task_get();
}
/**
* @brief Terminate execution of a thread and remove it from Active Threads.
* @param thread_id thread ID obtained by \ref osThreadCreate or \ref osThreadGetId.
* @retval status code that indicates the execution status of the function.
* @note MUST REMAIN UNCHANGED: \b osThreadTerminate shall be consistent in every CMSIS-RTOS.
*/
osStatus osThreadTerminate (osThreadId thread_id)
{
#if (RHINO_CONFIG_TASK_DEL > 0)
if (RHINO_SUCCESS == krhino_task_del((ktask_t*)thread_id))
return osOK;
else
return osErrorOS;
#else
return osErrorOS;
#endif
}
/**
* @brief Pass control to next thread that is in state \b READY.
* @retval status code that indicates the execution status of the function.
* @note MUST REMAIN UNCHANGED: \b osThreadYield shall be consistent in every CMSIS-RTOS.
*/
osStatus osThreadYield (void)
{
krhino_task_yield();
return osOK;
}
/**
* @brief Change priority of an active thread.
* @param thread_id thread ID obtained by \ref osThreadCreate or \ref osThreadGetId.
* @param priority new priority value for the thread function.
* @retval status code that indicates the execution status of the function.
* @note MUST REMAIN UNCHANGED: \b osThreadSetPriority shall be consistent in every CMSIS-RTOS.
*/
osStatus osThreadSetPriority (osThreadId thread_id, osPriority priority)
{
#if (RHINO_CONFIG_TASK_PRI_CHG > 0)
if (RHINO_SUCCESS == task_pri_change((ktask_t*)thread_id, makeRhinoPriority(priority)))
return osOK;
else
return osErrorOS;
#else
return osErrorOS;
#endif
}
/**
* @brief Get current priority of an active thread.
* @param thread_id thread ID obtained by \ref osThreadCreate or \ref osThreadGetId.
* @retval current priority value of the thread function.
* @note MUST REMAIN UNCHANGED: \b osThreadGetPriority shall be consistent in every CMSIS-RTOS.
*/
osPriority osThreadGetPriority (osThreadId thread_id)
{
ktask_t * ptcb;
if (thread_id == NULL)
return osPriorityError;
ptcb = (ktask_t *)thread_id;
return makeCmsisPriority(ptcb->prio);
}
/*********************** Generic Wait Functions *******************************/
/**
* @brief Wait for Timeout (Time Delay)
* @param millisec time delay value
* @retval status code that indicates the execution status of the function.
*/
osStatus osDelay (uint32_t millisec)
{
tick_t ticks = millisec / (1000000/RHINO_CONFIG_TICKS_PER_SECOND);
krhino_task_sleep(ticks ? ticks : 1); /* Minimum delay = 1 tick */
}
#if (defined (osFeature_Wait) && (osFeature_Wait != 0)) /* Generic Wait available */
/**
* @brief Wait for Signal, Message, Mail, or Timeout
* @param millisec timeout value or 0 in case of no time-out
* @retval event that contains signal, message, or mail information or error code.
* @note MUST REMAIN UNCHANGED: \b osWait shall be consistent in every CMSIS-RTOS.
*/
osEvent osWait (uint32_t millisec);
#endif /* Generic Wait available */
/*********************** Timer Management Functions ***************************/
/**
* @brief Create a timer.
* @param timer_def timer object referenced with \ref osTimer.
* @param type osTimerOnce for one-shot or osTimerPeriodic for periodic behavior.
* @param argument argument to the timer call back function.
* @retval timer ID for reference by other functions or NULL in case of error.
* @note MUST REMAIN UNCHANGED: \b osTimerCreate shall be consistent in every CMSIS-RTOS.
*/
osTimerId osTimerCreate (const osTimerDef_t *timer_def, os_timer_type type, void *argument)
{
sys_time_t first = 1;
sys_time_t round;
/*
* we use the round to save information for : one-shot or periodic,
* when type == osTimerPeriodic, round is set to MAX_TIMER_TICKS - 1,
* when type == osTimerOnce, round is set to 0.
* osTimerStart() will set the right value for round again.
*
* also the parameter first will be set to 1 here for workround error
* in krhino_timer_create(), osTimerStart() will set the right value.
*/
if (type == osTimerPeriodic)
round = MAX_TIMER_TICKS - 1;
else
round = 0;
if (RHINO_SUCCESS == krhino_timer_create(timer_def->timer,
timer_def->name, (timer_cb_t)timer_def->cb,
first, round, argument, 0))
{
return (osTimerId)timer_def->timer;
}
else
{
return NULL;
}
}
#if (RHINO_CONFIG_TIMER > 0)
/**
* @brief Start or restart a timer.
* @param timer_id timer ID obtained by \ref osTimerCreate.
* @param millisec time delay value of the timer.
* @retval status code that indicates the execution status of the function
* @note MUST REMAIN UNCHANGED: \b osTimerStart shall be consistent in every CMSIS-RTOS.
*/
osStatus osTimerStart (osTimerId timer_id, uint32_t millisec)
{
osStatus result = osOK;
ktimer_t * ptimer = (ktimer_t *)timer_id;
tick_t ticks = millisec / (1000000/RHINO_CONFIG_TICKS_PER_SECOND);
if (ticks == 0)
{
ticks = 1;
}
ptimer->init_count = ticks;
/* check the type of timer, osTimerPeriodic or osTimerOnce*/
if ((MAX_TIMER_TICKS - 1) == ptimer->round_ticks)
{
ptimer->round_ticks = ticks;
}
if (RHINO_SUCCESS != krhino_timer_start(ptimer))
{
result = osErrorOS;
}
return result;
}
/**
* @brief Stop a timer.
* @param timer_id timer ID obtained by \ref osTimerCreate
* @retval status code that indicates the execution status of the function.
* @note MUST REMAIN UNCHANGED: \b osTimerStop shall be consistent in every CMSIS-RTOS.
*/
osStatus osTimerStop (osTimerId timer_id)
{
osStatus result = osOK;
if (RHINO_SUCCESS != krhino_timer_stop((ktimer_t *)timer_id))
{
result = osErrorOS;
}
return result;
}
/**
* @brief Delete a timer.
* @param timer_id timer ID obtained by \ref osTimerCreate
* @retval status code that indicates the execution status of the function.
* @note MUST REMAIN UNCHANGED: \b osTimerDelete shall be consistent in every CMSIS-RTOS.
*/
osStatus osTimerDelete (osTimerId timer_id)
{
osStatus result = osOK;
if (RHINO_SUCCESS != krhino_timer_del((ktimer_t *)timer_id))
{
result = osErrorOS;
}
return result;
}
#endif /* RHINO_CONFIG_TIMER */
#if (osFeature_Signals > 0)
/*************************** Signal Management ********************************/
/**
* @brief Set the specified Signal Flags of an active thread.
* @param thread_id thread ID obtained by \ref osThreadCreate or \ref osThreadGetId.
* @param signals specifies the signal flags of the thread that should be set.
* @retval previous signal flags of the specified thread or 0x80000000 in case of incorrect parameters.
* @note MUST REMAIN UNCHANGED: \b osSignalSet shall be consistent in every CMSIS-RTOS.
*/
int32_t osSignalSet (osThreadId thread_id, int32_t signal)
{
(void) thread_id;
(void) signal;
return 0x80000000; /* Task Notification not supported */
}
/**
* @brief Clear the specified Signal Flags of an active thread.
* @param thread_id thread ID obtained by \ref osThreadCreate or \ref osThreadGetId.
* @param signals specifies the signal flags of the thread that shall be cleared.
* @retval previous signal flags of the specified thread or 0x80000000 in case of incorrect parameters.
* @note MUST REMAIN UNCHANGED: \b osSignalClear shall be consistent in every CMSIS-RTOS.
*/
int32_t osSignalClear (osThreadId thread_id, int32_t signal);
/**
* @brief Wait for one or more Signal Flags to become signaled for the current \b RUNNING thread.
* @param signals wait until all specified signal flags set or 0 for any single signal flag.
* @param millisec timeout value or 0 in case of no time-out.
* @retval event flag information or error code.
* @note MUST REMAIN UNCHANGED: \b osSignalWait shall be consistent in every CMSIS-RTOS.
*/
osEvent osSignalWait (int32_t signals, uint32_t millisec)
{
osEvent ret;
(void) signals;
(void) millisec;
ret.status = osErrorOS; /* Task Notification not supported */
return ret;
}
#endif /* osFeature_Signals > 0 */
/**************************** Mutex Management ********************************/
/**
* @brief Create and Initialize a Mutex object
* @param mutex_def mutex definition referenced with \ref osMutex.
* @retval mutex ID for reference by other functions or NULL in case of error.
* @note MUST REMAIN UNCHANGED: \b osMutexCreate shall be consistent in every CMSIS-RTOS.
*/
osMutexId osMutexCreate (const osMutexDef_t *mutex_def)
{
if (RHINO_SUCCESS != krhino_mutex_create(mutex_def->mutex, mutex_def->name))
{
return NULL;
}
else
{
return (osMutexId)mutex_def->mutex;
}
}
/**
* @brief Wait until a Mutex becomes available
* @param mutex_id mutex ID obtained by \ref osMutexCreate.
* @param millisec timeout value or 0 in case of no time-out.
* @retval status code that indicates the execution status of the function.
* @note MUST REMAIN UNCHANGED: \b osMutexWait shall be consistent in every CMSIS-RTOS.
*/
osStatus osMutexWait (osMutexId mutex_id, uint32_t millisec)
{
tick_t ticks;
if (mutex_id == NULL)
{
return osErrorParameter;
}
ticks = 0;
if (millisec != 0)
{
ticks = millisec / (1000000/RHINO_CONFIG_TICKS_PER_SECOND);
}
if (RHINO_SUCCESS != krhino_mutex_lock((kmutex_t*)mutex_id, ticks))
{
return osErrorOS;
}
return osOK;
}
/**
* @brief Release a Mutex that was obtained by \ref osMutexWait
* @param mutex_id mutex ID obtained by \ref osMutexCreate.
* @retval status code that indicates the execution status of the function.
* @note MUST REMAIN UNCHANGED: \b osMutexRelease shall be consistent in every CMSIS-RTOS.
*/
osStatus osMutexRelease (osMutexId mutex_id)
{
if (RHINO_SUCCESS == krhino_mutex_unlock((kmutex_t*)mutex_id))
{
return osOK;
}
else
{
return osErrorOS;
}
}
/**
* @brief Delete a Mutex
* @param mutex_id mutex ID obtained by \ref osMutexCreate.
* @retval status code that indicates the execution status of the function.
* @note MUST REMAIN UNCHANGED: \b osMutexDelete shall be consistent in every CMSIS-RTOS.
*/
osStatus osMutexDelete (osMutexId mutex_id)
{
if (RHINO_SUCCESS == krhino_mutex_del((kmutex_t*)mutex_id))
{
return osOK;
}
else
{
return osErrorOS;
}
}
/******************** Semaphore Management Functions **************************/
#if (RHINO_CONFIG_SEM > 0)
/**
* @brief Create and Initialize a Semaphore object used for managing resources
* @param semaphore_def semaphore definition referenced with \ref osSemaphore.
* @param count number of available resources.
* @retval semaphore ID for reference by other functions or NULL in case of error.
* @note MUST REMAIN UNCHANGED: \b osSemaphoreCreate shall be consistent in every CMSIS-RTOS.
*/
osSemaphoreId osSemaphoreCreate (const osSemaphoreDef_t *semaphore_def, int32_t count)
{
if (RHINO_SUCCESS != krhino_sem_create(semaphore_def->sem,
semaphore_def->name, (sem_count_t)count))
{
return NULL;
}
else
{
return (osSemaphoreId)semaphore_def->sem;
}
}
/**
* @brief Wait until a Semaphore token becomes available
* @param semaphore_id semaphore object referenced with \ref osSemaphore.
* @param millisec timeout value or 0 in case of no time-out.
* @retval number of available tokens, or -1 in case of incorrect parameters.
* @note MUST REMAIN UNCHANGED: \b osSemaphoreWait shall be consistent in every CMSIS-RTOS.
*/
int32_t osSemaphoreWait (osSemaphoreId semaphore_id, uint32_t millisec)
{
tick_t ticks;
if (semaphore_id == NULL)
{
return osErrorParameter;
}
ticks = 0;
if (millisec != 0)
{
ticks = millisec / (1000000/RHINO_CONFIG_TICKS_PER_SECOND);
}
if (RHINO_SUCCESS != krhino_sem_take((ksem_t*)semaphore_id, ticks))
{
return osErrorOS;
}
return osOK;
}
/**
* @brief Release a Semaphore token
* @param semaphore_id semaphore object referenced with \ref osSemaphore.
* @retval status code that indicates the execution status of the function.
* @note MUST REMAIN UNCHANGED: \b osSemaphoreRelease shall be consistent in every CMSIS-RTOS.
*/
osStatus osSemaphoreRelease (osSemaphoreId semaphore_id)
{
if (RHINO_SUCCESS == krhino_sem_give((ksem_t*)semaphore_id))
{
return osOK;
}
else
{
return osErrorOS;
}
}
/**
* @brief Delete a Semaphore
* @param semaphore_id semaphore object referenced with \ref osSemaphore.
* @retval status code that indicates the execution status of the function.
* @note MUST REMAIN UNCHANGED: \b osSemaphoreDelete shall be consistent in every CMSIS-RTOS.
*/
osStatus osSemaphoreDelete (osSemaphoreId semaphore_id)
{
if (RHINO_SUCCESS == krhino_sem_del((ksem_t*)semaphore_id))
{
return osOK;
}
else
{
return osErrorOS;
}
}
#endif /* Use Semaphores */
/******************* Memory Pool Management Functions ***********************/
#if (defined (osFeature_Pool) && (osFeature_Pool != 0))
//TODO
//This is a primitive and inefficient wrapper around the existing AliOS memory management.
//A better implementation will have to modify heap_x.c!
typedef struct os_pool_cb {
void *pool;
uint8_t *markers;
uint32_t pool_sz;
uint32_t item_sz;
uint32_t currentIndex;
} os_pool_cb_t;
/**
* @brief Create and Initialize a memory pool
* @param pool_def memory pool definition referenced with \ref osPool.
* @retval memory pool ID for reference by other functions or NULL in case of error.
* @note MUST REMAIN UNCHANGED: \b osPoolCreate shall be consistent in every CMSIS-RTOS.
*/
osPoolId osPoolCreate (const osPoolDef_t *pool_def)
{
return NULL;
}
/**
* @brief Allocate a memory block from a memory pool
* @param pool_id memory pool ID obtain referenced with \ref osPoolCreate.
* @retval address of the allocated memory block or NULL in case of no memory available.
* @note MUST REMAIN UNCHANGED: \b osPoolAlloc shall be consistent in every CMSIS-RTOS.
*/
void *osPoolAlloc (osPoolId pool_id)
{
return NULL;
}
/**
* @brief Allocate a memory block from a memory pool and set memory block to zero
* @param pool_id memory pool ID obtain referenced with \ref osPoolCreate.
* @retval address of the allocated memory block or NULL in case of no memory available.
* @note MUST REMAIN UNCHANGED: \b osPoolCAlloc shall be consistent in every CMSIS-RTOS.
*/
void *osPoolCAlloc (osPoolId pool_id)
{
return NULL;
}
/**
* @brief Return an allocated memory block back to a specific memory pool
* @param pool_id memory pool ID obtain referenced with \ref osPoolCreate.
* @param block address of the allocated memory block that is returned to the memory pool.
* @retval status code that indicates the execution status of the function.
* @note MUST REMAIN UNCHANGED: \b osPoolFree shall be consistent in every CMSIS-RTOS.
*/
osStatus osPoolFree (osPoolId pool_id, void *block)
{
return osOK;
}
#endif /* Use Memory Pool Management */
/******************* Message Queue Management Functions *********************/
#if (defined (osFeature_MessageQ) && (osFeature_MessageQ != 0)) /* Use Message Queues */
/**
* @brief Create and Initialize a Message Queue
* @param queue_def queue definition referenced with \ref osMessageQ.
* @param thread_id thread ID (obtained by \ref osThreadCreate or \ref osThreadGetId) or NULL.
* @retval message queue ID for reference by other functions or NULL in case of error.
* @note MUST REMAIN UNCHANGED: \b osMessageCreate shall be consistent in every CMSIS-RTOS.
*/
osMessageQId osMessageCreate (const osMessageQDef_t *queue_def, osThreadId thread_id)
{
(void) thread_id;
if (RHINO_SUCCESS == krhino_fix_buf_queue_create(queue_def->queue,
queue_def->name, queue_def->pool,
queue_def->item_sz, queue_def->queue_sz))
{
return (osMessageQId)queue_def->queue;
}
else
{
return NULL;
}
}
/**
* @brief Put a Message to a Queue.
* @param queue_id message queue ID obtained with \ref osMessageCreate.
* @param info message information.
* @param millisec timeout value or 0 in case of no time-out.
* @retval status code that indicates the execution status of the function.
* @note MUST REMAIN UNCHANGED: \b osMessagePut shall be consistent in every CMSIS-RTOS.
*/
osStatus osMessagePut (osMessageQId queue_id, uint32_t info, uint32_t millisec)
{
(void)millisec;
if (RHINO_SUCCESS == krhino_buf_queue_send((kbuf_queue_t *)queue_id, &info, 4))
{
return osOK;
}
else
{
return osErrorOS;
}
}
/**
* @brief Get a Message or Wait for a Message from a Queue.
* @param queue_id message queue ID obtained with \ref osMessageCreate.
* @param millisec timeout value or 0 in case of no time-out.
* @retval event information that includes status code.
* @note MUST REMAIN UNCHANGED: \b osMessageGet shall be consistent in every CMSIS-RTOS.
*/
osEvent osMessageGet (osMessageQId queue_id, uint32_t millisec)
{
osEvent event;
tick_t ticks;
size_t size;
ticks = 0;
if (millisec == osWaitForever)
{
ticks = RHINO_WAIT_FOREVER;
}
else if (millisec != 0)
{
ticks = millisec / (1000000/RHINO_CONFIG_TICKS_PER_SECOND);
if (ticks == 0)
{
ticks = 1;
}
}
event.def.message_id = queue_id;
event.value.v = 0;
if (queue_id == NULL)
{
event.status = osErrorParameter;
return event;
}
if (RHINO_SUCCESS == krhino_buf_queue_recv((kbuf_queue_t *)queue_id,
ticks, &event.value.v, &size))
{
event.status = osEventMessage;
}
else
{
event.status = (ticks == 0) ? osOK : osEventTimeout;
}
return event;
}
#endif /* Use Message Queues */
/******************** Mail Queue Management Functions ***********************/
#if (defined (osFeature_MailQ) && (osFeature_MailQ != 0)) /* Use Mail Queues */
typedef struct os_mailQ_cb {
const osMailQDef_t *queue_def;
QueueHandle_t handle;
osPoolId pool;
} os_mailQ_cb_t;
/**
* @brief Create and Initialize mail queue
* @param queue_def reference to the mail queue definition obtain with \ref osMailQ
* @param thread_id thread ID (obtained by \ref osThreadCreate or \ref osThreadGetId) or NULL.
* @retval mail queue ID for reference by other functions or NULL in case of error.
* @note MUST REMAIN UNCHANGED: \b osMailCreate shall be consistent in every CMSIS-RTOS.
*/
osMailQId osMailCreate (const osMailQDef_t *queue_def, osThreadId thread_id)
{
return NULL;
}
/**
* @brief Allocate a memory block from a mail
* @param queue_id mail queue ID obtained with \ref osMailCreate.
* @param millisec timeout value or 0 in case of no time-out.
* @retval pointer to memory block that can be filled with mail or NULL in case error.
* @note MUST REMAIN UNCHANGED: \b osMailAlloc shall be consistent in every CMSIS-RTOS.
*/
void *osMailAlloc (osMailQId queue_id, uint32_t millisec)
{
return NULL;
}
/**
* @brief Allocate a memory block from a mail and set memory block to zero
* @param queue_id mail queue ID obtained with \ref osMailCreate.
* @param millisec timeout value or 0 in case of no time-out.
* @retval pointer to memory block that can be filled with mail or NULL in case error.
* @note MUST REMAIN UNCHANGED: \b osMailCAlloc shall be consistent in every CMSIS-RTOS.
*/
void *osMailCAlloc (osMailQId queue_id, uint32_t millisec)
{
return NULL;
}
/**
* @brief Put a mail to a queue
* @param queue_id mail queue ID obtained with \ref osMailCreate.
* @param mail memory block previously allocated with \ref osMailAlloc or \ref osMailCAlloc.
* @retval status code that indicates the execution status of the function.
* @note MUST REMAIN UNCHANGED: \b osMailPut shall be consistent in every CMSIS-RTOS.
*/
osStatus osMailPut (osMailQId queue_id, void *mail)
{
return osOK;
}
/**
* @brief Get a mail from a queue
* @param queue_id mail queue ID obtained with \ref osMailCreate.
* @param millisec timeout value or 0 in case of no time-out
* @retval event that contains mail information or error code.
* @note MUST REMAIN UNCHANGED: \b osMailGet shall be consistent in every CMSIS-RTOS.
*/
osEvent osMailGet (osMailQId queue_id, uint32_t millisec)
{
osEvent event;
return event;
}
/**
* @brief Free a memory block from a mail
* @param queue_id mail queue ID obtained with \ref osMailCreate.
* @param mail pointer to the memory block that was obtained with \ref osMailGet.
* @retval status code that indicates the execution status of the function.
* @note MUST REMAIN UNCHANGED: \b osMailFree shall be consistent in every CMSIS-RTOS.
*/
osStatus osMailFree (osMailQId queue_id, void *mail)
{
return osOK;
}
#endif /* Use Mail Queues */

View file

@ -0,0 +1,717 @@
/* ----------------------------------------------------------------------
* $Date: 5. February 2013
* $Revision: V1.02
*
* Project: CMSIS-RTOS API
* Title: cmsis_os.h template header file
*
* Version 0.02
* Initial Proposal Phase
* Version 0.03
* osKernelStart added, optional feature: main started as thread
* osSemaphores have standard behavior
* osTimerCreate does not start the timer, added osTimerStart
* osThreadPass is renamed to osThreadYield
* Version 1.01
* Support for C++ interface
* - const attribute removed from the osXxxxDef_t typedef's
* - const attribute added to the osXxxxDef macros
* Added: osTimerDelete, osMutexDelete, osSemaphoreDelete
* Added: osKernelInitialize
* Version 1.02
* Control functions for short timeouts in microsecond resolution:
* Added: osKernelSysTick, osKernelSysTickFrequency, osKernelSysTickMicroSec
* Removed: osSignalGet
*----------------------------------------------------------------------------
*
* Copyright (c) 2013-2017 ARM LIMITED
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*---------------------------------------------------------------------------*/
#ifndef _CMSIS_OS_H
#define _CMSIS_OS_H
/// \note MUST REMAIN UNCHANGED: \b osCMSIS identifies the CMSIS-RTOS API version.
#define osCMSIS 0x10002 ///< API version (main [31:16] .sub [15:0])
/// \note CAN BE CHANGED: \b osCMSIS_KERNEL identifies the underlying RTOS kernel and version number.
#define osCMSIS_KERNEL 0x10000 ///< RTOS identification and version (main [31:16] .sub [15:0])
/// \note MUST REMAIN UNCHANGED: \b osKernelSystemId shall be consistent in every CMSIS-RTOS.
#define osKernelSystemId "KERNEL V1.00" ///< RTOS identification string
/// \note MUST REMAIN UNCHANGED: \b osFeature_xxx shall be consistent in every CMSIS-RTOS.
/* Memory Pools, Mail Queues, Signal is not supported yet */
#define osFeature_MainThread 1 ///< main thread 1=main can be thread, 0=not available
/*not support yet*/
#define osFeature_Pool 0 ///< Memory Pools: 1=available, 0=not available
/*not support yet*/
#define osFeature_MailQ 0 ///< Mail Queues: 1=available, 0=not available
#define osFeature_MessageQ 1 ///< Message Queues: 1=available, 0=not available
/*not support yet*/
#define osFeature_Signals 0 ///< maximum number of Signal Flags available per thread
#define osFeature_Semaphore 30 ///< maximum count for \ref osSemaphoreCreate function
#define osFeature_Wait 0 ///< osWait function: 1=available, 0=not available
#define osFeature_SysTick 1 ///< osKernelSysTick functions: 1=available, 0=not available
#include <stdint.h>
#include <stddef.h>
#include <k_api.h> /* for rhino */
#ifdef __cplusplus
extern "C"
{
#endif
// ==== Enumeration, structures, defines ====
/// Priority used for thread control.
/// \note MUST REMAIN UNCHANGED: \b osPriority shall be consistent in every CMSIS-RTOS.
typedef enum {
osPriorityIdle = -3, ///< priority: idle (lowest)
osPriorityLow = -2, ///< priority: low
osPriorityBelowNormal = -1, ///< priority: below normal
osPriorityNormal = 0, ///< priority: normal (default)
osPriorityAboveNormal = +1, ///< priority: above normal
osPriorityHigh = +2, ///< priority: high
osPriorityRealtime = +3, ///< priority: realtime (highest)
osPriorityError = 0x84 ///< system cannot determine priority or thread has illegal priority
} osPriority;
/// Timeout value.
/// \note MUST REMAIN UNCHANGED: \b osWaitForever shall be consistent in every CMSIS-RTOS.
#define osWaitForever 0xFFFFFFFF ///< wait forever timeout value
/// Status code values returned by CMSIS-RTOS functions.
/// \note MUST REMAIN UNCHANGED: \b osStatus shall be consistent in every CMSIS-RTOS.
typedef enum {
osOK = 0, ///< function completed; no error or event occurred.
osEventSignal = 0x08, ///< function completed; signal event occurred.
osEventMessage = 0x10, ///< function completed; message event occurred.
osEventMail = 0x20, ///< function completed; mail event occurred.
osEventTimeout = 0x40, ///< function completed; timeout occurred.
osErrorParameter = 0x80, ///< parameter error: a mandatory parameter was missing or specified an incorrect object.
osErrorResource = 0x81, ///< resource not available: a specified resource was not available.
osErrorTimeoutResource = 0xC1, ///< resource not available within given time: a specified resource was not available within the timeout period.
osErrorISR = 0x82, ///< not allowed in ISR context: the function cannot be called from interrupt service routines.
osErrorISRRecursive = 0x83, ///< function called multiple times from ISR with same object.
osErrorPriority = 0x84, ///< system cannot determine priority or thread has illegal priority.
osErrorNoMemory = 0x85, ///< system is out of memory: it was impossible to allocate or reserve memory for the operation.
osErrorValue = 0x86, ///< value of a parameter is out of range.
osErrorOS = 0xFF, ///< unspecified RTOS error: run-time error but no other error message fits.
os_status_reserved = 0x7FFFFFFF ///< prevent from enum down-size compiler optimization.
} osStatus;
/// Timer type value for the timer definition.
/// \note MUST REMAIN UNCHANGED: \b os_timer_type shall be consistent in every CMSIS-RTOS.
typedef enum {
osTimerOnce = 0, ///< one-shot timer
osTimerPeriodic = 1 ///< repeating timer
} os_timer_type;
/// Entry point of a thread.
/// \note MUST REMAIN UNCHANGED: \b os_pthread shall be consistent in every CMSIS-RTOS.
typedef void (*os_pthread) (void const *argument);
/// Entry point of a timer call back function.
/// \note MUST REMAIN UNCHANGED: \b os_ptimer shall be consistent in every CMSIS-RTOS.
typedef void (*os_ptimer) (void const *argument);
// >>> the following data type definitions may shall adapted towards a specific RTOS
/// Thread ID identifies the thread (pointer to a thread control block).
/// \note CAN BE CHANGED: \b os_thread_cb is implementation specific in every CMSIS-RTOS.
typedef ktask_t *osThreadId;
/// Timer ID identifies the timer (pointer to a timer control block).
/// \note CAN BE CHANGED: \b os_timer_cb is implementation specific in every CMSIS-RTOS.
typedef ktimer_t *osTimerId;
/// Mutex ID identifies the mutex (pointer to a mutex control block).
/// \note CAN BE CHANGED: \b os_mutex_cb is implementation specific in every CMSIS-RTOS.
typedef kmutex_t *osMutexId;
/// Semaphore ID identifies the semaphore (pointer to a semaphore control block).
/// \note CAN BE CHANGED: \b os_semaphore_cb is implementation specific in every CMSIS-RTOS.
typedef ksem_t *osSemaphoreId;
/// Pool ID identifies the memory pool (pointer to a memory pool control block).
/// \note CAN BE CHANGED: \b os_pool_cb is implementation specific in every CMSIS-RTOS.
typedef void *osPoolId;
/// Message ID identifies the message queue (pointer to a message queue control block).
/// \note CAN BE CHANGED: \b os_messageQ_cb is implementation specific in every CMSIS-RTOS.
typedef kqueue_t *osMessageQId;
/// Mail ID identifies the mail queue (pointer to a mail queue control block).
/// \note CAN BE CHANGED: \b os_mailQ_cb is implementation specific in every CMSIS-RTOS.
typedef kqueue_t *osMailQId;
/// Thread Definition structure contains startup information of a thread.
/// \note CAN BE CHANGED: \b os_thread_def is implementation specific in every CMSIS-RTOS.
typedef struct os_thread_def {
char *name; ///< Thread name
os_pthread pthread; ///< start address of thread function
osPriority tpriority; ///< initial thread priority
uint32_t instances; ///< maximum number of instances of that thread function
uint32_t stacksize; ///< stack size requirements in bytes; 0 is default stack size
tick_t ticks;
ktask_t *ptcb;
cpu_stack_t *pstackspace;
} osThreadDef_t;
/// Timer Definition structure contains timer parameters.
/// \note CAN BE CHANGED: \b os_timer_def is implementation specific in every CMSIS-RTOS.
typedef struct os_timer_def {
char * name;
os_ptimer cb; ///< start address of a timer function
ktimer_t * timer;
} osTimerDef_t;
/// Mutex Definition structure contains setup information for a mutex.
/// \note CAN BE CHANGED: \b os_mutex_def is implementation specific in every CMSIS-RTOS.
typedef struct os_mutex_def {
char * name;
uint32_t dummy; ///< dummy value.
kmutex_t * mutex;
} osMutexDef_t;
/// Semaphore Definition structure contains setup information for a semaphore.
/// \note CAN BE CHANGED: \b os_semaphore_def is implementation specific in every CMSIS-RTOS.
typedef struct os_semaphore_def {
char * name;
uint32_t dummy; ///< dummy value.
ksem_t * sem;
} osSemaphoreDef_t;
/// Definition structure for memory block allocation.
/// \note CAN BE CHANGED: \b os_pool_def is implementation specific in every CMSIS-RTOS.
typedef struct os_pool_def {
uint32_t pool_sz; ///< number of items (elements) in the pool
uint32_t item_sz; ///< size of an item
void *pool; ///< pointer to memory for pool
} osPoolDef_t;
/// Definition structure for message queue.
/// \note CAN BE CHANGED: \b os_messageQ_def is implementation specific in every CMSIS-RTOS.
typedef struct os_messageQ_def {
char *name;
uint32_t queue_sz; ///< number of elements in the queue
uint32_t item_sz; ///< size of an item
void *pool; ///< memory array for messages
kbuf_queue_t *queue;
} osMessageQDef_t;
/// Definition structure for mail queue.
/// \note CAN BE CHANGED: \b os_mailQ_def is implementation specific in every CMSIS-RTOS.
typedef struct os_mailQ_def {
uint32_t queue_sz; ///< number of elements in the queue
uint32_t item_sz; ///< size of an item
void *pool; ///< memory array for mail
} osMailQDef_t;
/// Event structure contains detailed information about an event.
/// \note MUST REMAIN UNCHANGED: \b os_event shall be consistent in every CMSIS-RTOS.
/// However the struct may be extended at the end.
typedef struct {
osStatus status; ///< status code: event or error information
union {
uint32_t v; ///< message as 32-bit value
void *p; ///< message or mail as void pointer
int32_t signals; ///< signal flags
} value; ///< event value
union {
osMailQId mail_id; ///< mail id obtained by \ref osMailCreate
osMessageQId message_id; ///< message id obtained by \ref osMessageCreate
} def; ///< event definition
} osEvent;
// ==== Kernel Control Functions ====
/// Initialize the RTOS Kernel for creating objects.
/// \return status code that indicates the execution status of the function.
/// \note MUST REMAIN UNCHANGED: \b osKernelInitialize shall be consistent in every CMSIS-RTOS.
osStatus osKernelInitialize (void);
/// Start the RTOS Kernel.
/// \return status code that indicates the execution status of the function.
/// \note MUST REMAIN UNCHANGED: \b osKernelStart shall be consistent in every CMSIS-RTOS.
osStatus osKernelStart (void);
/// Check if the RTOS kernel is already started.
/// \note MUST REMAIN UNCHANGED: \b osKernelRunning shall be consistent in every CMSIS-RTOS.
/// \return 0 RTOS is not started, 1 RTOS is started.
int32_t osKernelRunning(void);
#if (defined (osFeature_SysTick) && (osFeature_SysTick != 0)) // System Timer available
/// Get the RTOS kernel system timer counter
/// \note MUST REMAIN UNCHANGED: \b osKernelSysTick shall be consistent in every CMSIS-RTOS.
/// \return RTOS kernel system timer as 32-bit value
uint32_t osKernelSysTick (void);
/// The RTOS kernel system timer frequency in Hz
/// \note Reflects the system timer setting and is typically defined in a configuration file.
#define osKernelSysTickFrequency 100000000
/// Convert a microseconds value to a RTOS kernel system timer value.
/// \param microsec time value in microseconds.
/// \return time value normalized to the \ref osKernelSysTickFrequency
#define osKernelSysTickMicroSec(microsec) (((uint64_t)microsec * (osKernelSysTickFrequency)) / 1000000)
#endif // System Timer available
// ==== Thread Management ====
/// Create a Thread Definition with function, priority, and stack requirements.
/// \param name name of the thread function.
/// \param priority initial priority of the thread function.
/// \param instances number of possible thread instances.
/// \param stacksz stack size (in bytes) requirements for the thread function.
/// \note CAN BE CHANGED: The parameters to \b osThreadDef shall be consistent but the
/// macro body is implementation specific in every CMSIS-RTOS.
#if defined (osObjectsExternal) // object is external
#define osThreadDef(name, priority, instances, stacksz) \
extern const osThreadDef_t os_thread_def_##name
#else // define the object
#define osThreadDef(name, priority, instances, stacksz) \
const osThreadDef_t os_thread_def_##name = \
{ (name), (priority), (instances), (stacksz) }
#endif
/// Access a Thread definition.
/// \param name name of the thread definition object.
/// \note CAN BE CHANGED: The parameter to \b osThread shall be consistent but the
/// macro body is implementation specific in every CMSIS-RTOS.
#define osThread(name) \
&os_thread_def_##name
/// Create a thread and add it to Active Threads and set it to state READY.
/// \param[in] thread_def thread definition referenced with \ref osThread.
/// \param[in] argument pointer that is passed to the thread function as start argument.
/// \return thread ID for reference by other functions or NULL in case of error.
/// \note MUST REMAIN UNCHANGED: \b osThreadCreate shall be consistent in every CMSIS-RTOS.
osThreadId osThreadCreate (const osThreadDef_t *thread_def, void *argument);
/// Return the thread ID of the current running thread.
/// \return thread ID for reference by other functions or NULL in case of error.
/// \note MUST REMAIN UNCHANGED: \b osThreadGetId shall be consistent in every CMSIS-RTOS.
osThreadId osThreadGetId (void);
/// Terminate execution of a thread and remove it from Active Threads.
/// \param[in] thread_id thread ID obtained by \ref osThreadCreate or \ref osThreadGetId.
/// \return status code that indicates the execution status of the function.
/// \note MUST REMAIN UNCHANGED: \b osThreadTerminate shall be consistent in every CMSIS-RTOS.
osStatus osThreadTerminate (osThreadId thread_id);
/// Pass control to next thread that is in state \b READY.
/// \return status code that indicates the execution status of the function.
/// \note MUST REMAIN UNCHANGED: \b osThreadYield shall be consistent in every CMSIS-RTOS.
osStatus osThreadYield (void);
/// Change priority of an active thread.
/// \param[in] thread_id thread ID obtained by \ref osThreadCreate or \ref osThreadGetId.
/// \param[in] priority new priority value for the thread function.
/// \return status code that indicates the execution status of the function.
/// \note MUST REMAIN UNCHANGED: \b osThreadSetPriority shall be consistent in every CMSIS-RTOS.
osStatus osThreadSetPriority (osThreadId thread_id, osPriority priority);
/// Get current priority of an active thread.
/// \param[in] thread_id thread ID obtained by \ref osThreadCreate or \ref osThreadGetId.
/// \return current priority value of the thread function.
/// \note MUST REMAIN UNCHANGED: \b osThreadGetPriority shall be consistent in every CMSIS-RTOS.
osPriority osThreadGetPriority (osThreadId thread_id);
// ==== Generic Wait Functions ====
/// Wait for Timeout (Time Delay).
/// \param[in] millisec \ref CMSIS_RTOS_TimeOutValue "time delay" value
/// \return status code that indicates the execution status of the function.
osStatus osDelay (uint32_t millisec);
#if (defined (osFeature_Wait) && (osFeature_Wait != 0)) // Generic Wait available
/// Wait for Signal, Message, Mail, or Timeout.
/// \param[in] millisec \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out
/// \return event that contains signal, message, or mail information or error code.
/// \note MUST REMAIN UNCHANGED: \b osWait shall be consistent in every CMSIS-RTOS.
osEvent osWait (uint32_t millisec);
#endif // Generic Wait available
// ==== Timer Management Functions ====
/// Define a Timer object.
/// \param name name of the timer object.
/// \param function name of the timer call back function.
/// \note CAN BE CHANGED: The parameter to \b osTimerDef shall be consistent but the
/// macro body is implementation specific in every CMSIS-RTOS.
#if defined (osObjectsExternal) // object is external
#define osTimerDef(name, function) \
extern const osTimerDef_t os_timer_def_##name
#else // define the object
#define osTimerDef(name, function) \
const osTimerDef_t os_timer_def_##name = \
{ (function) }
#endif
/// Access a Timer definition.
/// \param name name of the timer object.
/// \note CAN BE CHANGED: The parameter to \b osTimer shall be consistent but the
/// macro body is implementation specific in every CMSIS-RTOS.
#define osTimer(name) \
&os_timer_def_##name
/// Create a timer.
/// \param[in] timer_def timer object referenced with \ref osTimer.
/// \param[in] type osTimerOnce for one-shot or osTimerPeriodic for periodic behavior.
/// \param[in] argument argument to the timer call back function.
/// \return timer ID for reference by other functions or NULL in case of error.
/// \note MUST REMAIN UNCHANGED: \b osTimerCreate shall be consistent in every CMSIS-RTOS.
osTimerId osTimerCreate (const osTimerDef_t *timer_def, os_timer_type type, void *argument);
/// Start or restart a timer.
/// \param[in] timer_id timer ID obtained by \ref osTimerCreate.
/// \param[in] millisec \ref CMSIS_RTOS_TimeOutValue "time delay" value of the timer.
/// \return status code that indicates the execution status of the function.
/// \note MUST REMAIN UNCHANGED: \b osTimerStart shall be consistent in every CMSIS-RTOS.
osStatus osTimerStart (osTimerId timer_id, uint32_t millisec);
/// Stop the timer.
/// \param[in] timer_id timer ID obtained by \ref osTimerCreate.
/// \return status code that indicates the execution status of the function.
/// \note MUST REMAIN UNCHANGED: \b osTimerStop shall be consistent in every CMSIS-RTOS.
osStatus osTimerStop (osTimerId timer_id);
/// Delete a timer that was created by \ref osTimerCreate.
/// \param[in] timer_id timer ID obtained by \ref osTimerCreate.
/// \return status code that indicates the execution status of the function.
/// \note MUST REMAIN UNCHANGED: \b osTimerDelete shall be consistent in every CMSIS-RTOS.
osStatus osTimerDelete (osTimerId timer_id);
// ==== Signal Management ==== not support yet
/// Set the specified Signal Flags of an active thread.
/// \param[in] thread_id thread ID obtained by \ref osThreadCreate or \ref osThreadGetId.
/// \param[in] signals specifies the signal flags of the thread that should be set.
/// \return previous signal flags of the specified thread or 0x80000000 in case of incorrect parameters.
/// \note MUST REMAIN UNCHANGED: \b osSignalSet shall be consistent in every CMSIS-RTOS.
int32_t osSignalSet (osThreadId thread_id, int32_t signals);
/// Clear the specified Signal Flags of an active thread.
/// \param[in] thread_id thread ID obtained by \ref osThreadCreate or \ref osThreadGetId.
/// \param[in] signals specifies the signal flags of the thread that shall be cleared.
/// \return previous signal flags of the specified thread or 0x80000000 in case of incorrect parameters or call from ISR.
/// \note MUST REMAIN UNCHANGED: \b osSignalClear shall be consistent in every CMSIS-RTOS.
int32_t osSignalClear (osThreadId thread_id, int32_t signals);
/// Wait for one or more Signal Flags to become signaled for the current \b RUNNING thread.
/// \param[in] signals wait until all specified signal flags set or 0 for any single signal flag.
/// \param[in] millisec \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
/// \return event flag information or error code.
/// \note MUST REMAIN UNCHANGED: \b osSignalWait shall be consistent in every CMSIS-RTOS.
osEvent osSignalWait (int32_t signals, uint32_t millisec);
// ==== Mutex Management ====
/// Define a Mutex.
/// \param name name of the mutex object.
/// \note CAN BE CHANGED: The parameter to \b osMutexDef shall be consistent but the
/// macro body is implementation specific in every CMSIS-RTOS.
#if defined (osObjectsExternal) // object is external
#define osMutexDef(name) \
extern const osMutexDef_t os_mutex_def_##name
#else // define the object
#define osMutexDef(name) \
const osMutexDef_t os_mutex_def_##name = { 0 }
#endif
/// Access a Mutex definition.
/// \param name name of the mutex object.
/// \note CAN BE CHANGED: The parameter to \b osMutex shall be consistent but the
/// macro body is implementation specific in every CMSIS-RTOS.
#define osMutex(name) \
&os_mutex_def_##name
/// Create and Initialize a Mutex object.
/// \param[in] mutex_def mutex definition referenced with \ref osMutex.
/// \return mutex ID for reference by other functions or NULL in case of error.
/// \note MUST REMAIN UNCHANGED: \b osMutexCreate shall be consistent in every CMSIS-RTOS.
osMutexId osMutexCreate (const osMutexDef_t *mutex_def);
/// Wait until a Mutex becomes available.
/// \param[in] mutex_id mutex ID obtained by \ref osMutexCreate.
/// \param[in] millisec \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
/// \return status code that indicates the execution status of the function.
/// \note MUST REMAIN UNCHANGED: \b osMutexWait shall be consistent in every CMSIS-RTOS.
osStatus osMutexWait (osMutexId mutex_id, uint32_t millisec);
/// Release a Mutex that was obtained by \ref osMutexWait.
/// \param[in] mutex_id mutex ID obtained by \ref osMutexCreate.
/// \return status code that indicates the execution status of the function.
/// \note MUST REMAIN UNCHANGED: \b osMutexRelease shall be consistent in every CMSIS-RTOS.
osStatus osMutexRelease (osMutexId mutex_id);
/// Delete a Mutex that was created by \ref osMutexCreate.
/// \param[in] mutex_id mutex ID obtained by \ref osMutexCreate.
/// \return status code that indicates the execution status of the function.
/// \note MUST REMAIN UNCHANGED: \b osMutexDelete shall be consistent in every CMSIS-RTOS.
osStatus osMutexDelete (osMutexId mutex_id);
// ==== Semaphore Management Functions ====
#if (defined (osFeature_Semaphore) && (osFeature_Semaphore != 0)) // Semaphore available
/// Define a Semaphore object.
/// \param name name of the semaphore object.
/// \note CAN BE CHANGED: The parameter to \b osSemaphoreDef shall be consistent but the
/// macro body is implementation specific in every CMSIS-RTOS.
#if defined (osObjectsExternal) // object is external
#define osSemaphoreDef(name) \
extern const osSemaphoreDef_t os_semaphore_def_##name
#else // define the object
#define osSemaphoreDef(name) \
const osSemaphoreDef_t os_semaphore_def_##name = { 0 }
#endif
/// Access a Semaphore definition.
/// \param name name of the semaphore object.
/// \note CAN BE CHANGED: The parameter to \b osSemaphore shall be consistent but the
/// macro body is implementation specific in every CMSIS-RTOS.
#define osSemaphore(name) \
&os_semaphore_def_##name
/// Create and Initialize a Semaphore object used for managing resources.
/// \param[in] semaphore_def semaphore definition referenced with \ref osSemaphore.
/// \param[in] count number of available resources.
/// \return semaphore ID for reference by other functions or NULL in case of error.
/// \note MUST REMAIN UNCHANGED: \b osSemaphoreCreate shall be consistent in every CMSIS-RTOS.
osSemaphoreId osSemaphoreCreate (const osSemaphoreDef_t *semaphore_def, int32_t count);
/// Wait until a Semaphore token becomes available.
/// \param[in] semaphore_id semaphore object referenced with \ref osSemaphoreCreate.
/// \param[in] millisec \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
/// \return number of available tokens, or -1 in case of incorrect parameters.
/// \note MUST REMAIN UNCHANGED: \b osSemaphoreWait shall be consistent in every CMSIS-RTOS.
int32_t osSemaphoreWait (osSemaphoreId semaphore_id, uint32_t millisec);
/// Release a Semaphore token.
/// \param[in] semaphore_id semaphore object referenced with \ref osSemaphoreCreate.
/// \return status code that indicates the execution status of the function.
/// \note MUST REMAIN UNCHANGED: \b osSemaphoreRelease shall be consistent in every CMSIS-RTOS.
osStatus osSemaphoreRelease (osSemaphoreId semaphore_id);
/// Delete a Semaphore that was created by \ref osSemaphoreCreate.
/// \param[in] semaphore_id semaphore object referenced with \ref osSemaphoreCreate.
/// \return status code that indicates the execution status of the function.
/// \note MUST REMAIN UNCHANGED: \b osSemaphoreDelete shall be consistent in every CMSIS-RTOS.
osStatus osSemaphoreDelete (osSemaphoreId semaphore_id);
#endif // Semaphore available
// ==== Memory Pool Management Functions ==== not support yet
#if (defined (osFeature_Pool) && (osFeature_Pool != 0)) // Memory Pool Management available
/// \brief Define a Memory Pool.
/// \param name name of the memory pool.
/// \param no maximum number of blocks (objects) in the memory pool.
/// \param type data type of a single block (object).
/// \note CAN BE CHANGED: The parameter to \b osPoolDef shall be consistent but the
/// macro body is implementation specific in every CMSIS-RTOS.
#if defined (osObjectsExternal) // object is external
#define osPoolDef(name, no, type) \
extern const osPoolDef_t os_pool_def_##name
#else // define the object
#define osPoolDef(name, no, type) \
const osPoolDef_t os_pool_def_##name = \
{ (no), sizeof(type), NULL }
#endif
/// \brief Access a Memory Pool definition.
/// \param name name of the memory pool
/// \note CAN BE CHANGED: The parameter to \b osPool shall be consistent but the
/// macro body is implementation specific in every CMSIS-RTOS.
#define osPool(name) \
&os_pool_def_##name
/// Create and Initialize a memory pool.
/// \param[in] pool_def memory pool definition referenced with \ref osPool.
/// \return memory pool ID for reference by other functions or NULL in case of error.
/// \note MUST REMAIN UNCHANGED: \b osPoolCreate shall be consistent in every CMSIS-RTOS.
osPoolId osPoolCreate (const osPoolDef_t *pool_def);
/// Allocate a memory block from a memory pool.
/// \param[in] pool_id memory pool ID obtain referenced with \ref osPoolCreate.
/// \return address of the allocated memory block or NULL in case of no memory available.
/// \note MUST REMAIN UNCHANGED: \b osPoolAlloc shall be consistent in every CMSIS-RTOS.
void *osPoolAlloc (osPoolId pool_id);
/// Allocate a memory block from a memory pool and set memory block to zero.
/// \param[in] pool_id memory pool ID obtain referenced with \ref osPoolCreate.
/// \return address of the allocated memory block or NULL in case of no memory available.
/// \note MUST REMAIN UNCHANGED: \b osPoolCAlloc shall be consistent in every CMSIS-RTOS.
void *osPoolCAlloc (osPoolId pool_id);
/// Return an allocated memory block back to a specific memory pool.
/// \param[in] pool_id memory pool ID obtain referenced with \ref osPoolCreate.
/// \param[in] block address of the allocated memory block that is returned to the memory pool.
/// \return status code that indicates the execution status of the function.
/// \note MUST REMAIN UNCHANGED: \b osPoolFree shall be consistent in every CMSIS-RTOS.
osStatus osPoolFree (osPoolId pool_id, void *block);
#endif // Memory Pool Management available
// ==== Message Queue Management Functions ====
#if (defined (osFeature_MessageQ) && (osFeature_MessageQ != 0)) // Message Queues available
/// \brief Create a Message Queue Definition.
/// \param name name of the queue.
/// \param queue_sz maximum number of messages in the queue.
/// \param type data type of a single message element (for debugger).
/// \note CAN BE CHANGED: The parameter to \b osMessageQDef shall be consistent but the
/// macro body is implementation specific in every CMSIS-RTOS.
#if defined (osObjectsExternal) // object is external
#define osMessageQDef(name, queue_sz, type) \
extern const osMessageQDef_t os_messageQ_def_##name
#else // define the object
#define osMessageQDef(name, queue_sz, type) \
const osMessageQDef_t os_messageQ_def_##name = \
{ (queue_sz), sizeof (type) }
#endif
/// \brief Access a Message Queue Definition.
/// \param name name of the queue
/// \note CAN BE CHANGED: The parameter to \b osMessageQ shall be consistent but the
/// macro body is implementation specific in every CMSIS-RTOS.
#define osMessageQ(name) \
&os_messageQ_def_##name
/// Create and Initialize a Message Queue.
/// \param[in] queue_def queue definition referenced with \ref osMessageQ.
/// \param[in] thread_id thread ID (obtained by \ref osThreadCreate or \ref osThreadGetId) or NULL.
/// \return message queue ID for reference by other functions or NULL in case of error.
/// \note MUST REMAIN UNCHANGED: \b osMessageCreate shall be consistent in every CMSIS-RTOS.
osMessageQId osMessageCreate (const osMessageQDef_t *queue_def, osThreadId thread_id);
/// Put a Message to a Queue.
/// \param[in] queue_id message queue ID obtained with \ref osMessageCreate.
/// \param[in] info message information.
/// \param[in] millisec \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
/// \return status code that indicates the execution status of the function.
/// \note MUST REMAIN UNCHANGED: \b osMessagePut shall be consistent in every CMSIS-RTOS.
osStatus osMessagePut (osMessageQId queue_id, uint32_t info, uint32_t millisec);
/// Get a Message or Wait for a Message from a Queue.
/// \param[in] queue_id message queue ID obtained with \ref osMessageCreate.
/// \param[in] millisec \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
/// \return event information that includes status code.
/// \note MUST REMAIN UNCHANGED: \b osMessageGet shall be consistent in every CMSIS-RTOS.
osEvent osMessageGet (osMessageQId queue_id, uint32_t millisec);
#endif // Message Queues available
// ==== Mail Queue Management Functions ==== not support yet
#if (defined (osFeature_MailQ) && (osFeature_MailQ != 0)) // Mail Queues available
/// \brief Create a Mail Queue Definition.
/// \param name name of the queue
/// \param queue_sz maximum number of messages in queue
/// \param type data type of a single message element
/// \note CAN BE CHANGED: The parameter to \b osMailQDef shall be consistent but the
/// macro body is implementation specific in every CMSIS-RTOS.
#if defined (osObjectsExternal) // object is external
#define osMailQDef(name, queue_sz, type) \
extern const osMailQDef_t os_mailQ_def_##name
#else // define the object
#define osMailQDef(name, queue_sz, type) \
const osMailQDef_t os_mailQ_def_##name = \
{ (queue_sz), sizeof (type) }
#endif
/// \brief Access a Mail Queue Definition.
/// \param name name of the queue
/// \note CAN BE CHANGED: The parameter to \b osMailQ shall be consistent but the
/// macro body is implementation specific in every CMSIS-RTOS.
#define osMailQ(name) \
&os_mailQ_def_##name
/// Create and Initialize mail queue.
/// \param[in] queue_def reference to the mail queue definition obtain with \ref osMailQ
/// \param[in] thread_id thread ID (obtained by \ref osThreadCreate or \ref osThreadGetId) or NULL.
/// \return mail queue ID for reference by other functions or NULL in case of error.
/// \note MUST REMAIN UNCHANGED: \b osMailCreate shall be consistent in every CMSIS-RTOS.
osMailQId osMailCreate (const osMailQDef_t *queue_def, osThreadId thread_id);
/// Allocate a memory block from a mail.
/// \param[in] queue_id mail queue ID obtained with \ref osMailCreate.
/// \param[in] millisec \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out
/// \return pointer to memory block that can be filled with mail or NULL in case of error.
/// \note MUST REMAIN UNCHANGED: \b osMailAlloc shall be consistent in every CMSIS-RTOS.
void *osMailAlloc (osMailQId queue_id, uint32_t millisec);
/// Allocate a memory block from a mail and set memory block to zero.
/// \param[in] queue_id mail queue ID obtained with \ref osMailCreate.
/// \param[in] millisec \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out
/// \return pointer to memory block that can be filled with mail or NULL in case of error.
/// \note MUST REMAIN UNCHANGED: \b osMailCAlloc shall be consistent in every CMSIS-RTOS.
void *osMailCAlloc (osMailQId queue_id, uint32_t millisec);
/// Put a mail to a queue.
/// \param[in] queue_id mail queue ID obtained with \ref osMailCreate.
/// \param[in] mail memory block previously allocated with \ref osMailAlloc or \ref osMailCAlloc.
/// \return status code that indicates the execution status of the function.
/// \note MUST REMAIN UNCHANGED: \b osMailPut shall be consistent in every CMSIS-RTOS.
osStatus osMailPut (osMailQId queue_id, void *mail);
/// Get a mail from a queue.
/// \param[in] queue_id mail queue ID obtained with \ref osMailCreate.
/// \param[in] millisec \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out
/// \return event that contains mail information or error code.
/// \note MUST REMAIN UNCHANGED: \b osMailGet shall be consistent in every CMSIS-RTOS.
osEvent osMailGet (osMailQId queue_id, uint32_t millisec);
/// Free a memory block from a mail.
/// \param[in] queue_id mail queue ID obtained with \ref osMailCreate.
/// \param[in] mail pointer to the memory block that was obtained with \ref osMailGet.
/// \return status code that indicates the execution status of the function.
/// \note MUST REMAIN UNCHANGED: \b osMailFree shall be consistent in every CMSIS-RTOS.
osStatus osMailFree (osMailQId queue_id, void *mail);
#endif // Mail Queues available
#ifdef __cplusplus
}
#endif
#endif // _CMSIS_OS_H

View file

@ -0,0 +1,54 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include <k_api.h>
#include <stdio.h>
#include <stdlib.h>
#include <cmsis_os.h>
#define DEMO_TASK_STACKSIZE 256 //256*cpu_stack_t = 1024byte
#define DEMO_TASK_PRIORITY 20
extern void stm32_soc_init(void);
static ktask_t demo_task_obj;
static cpu_stack_t demo_task_buf[DEMO_TASK_STACKSIZE];
static osThreadDef_t thread;
static void demo_task(void *arg)
{
int count = 0;
stm32_soc_init();
printf("demo_task here!\n");
printf("rhino memory is %d!\n", krhino_global_space_get());
while (1)
{
printf("hello world! count %d\n", count++);
//sleep 1 second
osDelay(RHINO_CONFIG_TICKS_PER_SECOND*10000);
};
}
int main(void)
{
osKernelInitialize();
thread.name = "demo_task";
thread.pthread = (os_pthread)demo_task;
thread.tpriority = osPriorityNormal;
thread.stacksize = DEMO_TASK_STACKSIZE;
thread.ptcb = &demo_task_obj;
thread.pstackspace = demo_task_buf;
osThreadCreate (&thread, NULL);
osKernelStart();
return 0;
}

View file

@ -0,0 +1,108 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include <k_api.h>
#include <stdio.h>
#include <stdlib.h>
#include <cmsis_os.h>
#define DEMO_TASK_STACKSIZE 256 //256*cpu_stack_t = 1024byte
#define DEMO_TASK_PRIORITY 20
static ktask_t init_task_obj;
static ktask_t demo_task_obj1;
static ktask_t demo_task_obj2;
static cpu_stack_t init_task_buf[DEMO_TASK_STACKSIZE];
static cpu_stack_t demo_task_buf1[DEMO_TASK_STACKSIZE];
static cpu_stack_t demo_task_buf2[DEMO_TASK_STACKSIZE];
static osThreadDef_t thread_init;
static osThreadDef_t thread1;
static osThreadDef_t thread2;
static kbuf_queue_t buf_queue;
static osMessageQDef_t msg_queue_def;
static osMessageQId p_msgqueue;
static uint32_t msg_buf_space[32];
static void init_task(void *arg)
{
printf("init_task here!\n");
msg_queue_def.name = "buf_queue";
msg_queue_def.queue = &buf_queue;
msg_queue_def.queue_sz = 32;
msg_queue_def.item_sz = 4;
msg_queue_def.pool = msg_buf_space;
p_msgqueue = osMessageCreate (&msg_queue_def, (osThreadId)NULL);
if (p_msgqueue == NULL)
{
printf("osMessageCreate failed\n");
}
else
{
printf("osMessageCreate ok\n");
}
}
static void demo_task1(void *arg)
{
osEvent event;
while (1)
{
event = osMessageGet(p_msgqueue, osWaitForever);
if (event.status == osEventMessage)
{
printf("demo_task1 get msg %d\n", event.value.v);
}
else
{
printf("demo_task1 get msg failed\n");
}
};
}
static void demo_task2(void *arg)
{
uint32_t count = 0;
while (1)
{
osMessagePut(p_msgqueue,count,0xffffffff);
printf("demo_task2 put msg %d\n", count++);
osDelay(RHINO_CONFIG_TICKS_PER_SECOND*10000);
};
}
void cmsis_msgqueue_test(void)
{
thread_init.name = "init_task";
thread_init.pthread = (os_pthread)init_task;
thread_init.tpriority = osPriorityHigh;
thread_init.stacksize = DEMO_TASK_STACKSIZE;
thread_init.ptcb = &init_task_obj;
thread_init.pstackspace = init_task_buf;
thread1.name = "demo_task1";
thread1.pthread = (os_pthread)demo_task1;
thread1.tpriority = osPriorityNormal;
thread1.stacksize = DEMO_TASK_STACKSIZE;
thread1.ptcb = &demo_task_obj1;
thread1.pstackspace = demo_task_buf1;
thread2.name = "demo_task2";
thread2.pthread = (os_pthread)demo_task2;
thread2.tpriority = osPriorityNormal;
thread2.stacksize = DEMO_TASK_STACKSIZE;
thread2.ptcb = &demo_task_obj2;
thread2.pstackspace = demo_task_buf2;
osThreadCreate (&thread_init, NULL);
osThreadCreate (&thread1, NULL);
osThreadCreate (&thread2, NULL);
}

View file

@ -0,0 +1,95 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include <k_api.h>
#include <stdio.h>
#include <stdlib.h>
#include <cmsis_os.h>
#define DEMO_TASK_STACKSIZE 256 //256*cpu_stack_t = 1024byte
#define DEMO_TASK_PRIORITY 20
static ktask_t init_task_obj;
static ktask_t demo_task_obj1;
static ktask_t demo_task_obj2;
static cpu_stack_t init_task_buf[DEMO_TASK_STACKSIZE];
static cpu_stack_t demo_task_buf1[DEMO_TASK_STACKSIZE];
static cpu_stack_t demo_task_buf2[DEMO_TASK_STACKSIZE];
static osThreadDef_t thread_init;
static osThreadDef_t thread1;
static osThreadDef_t thread2;
static kmutex_t mutex;
static osMutexDef_t mutex_def;
static osMutexId pMutex;
static void init_task(void *arg)
{
mutex_def.name = "mutex";
mutex_def.mutex = &mutex;
pMutex = osMutexCreate (&mutex_def);
if (pMutex == NULL)
{
printf("osMutexCreate failed\n");
}
else
{
printf("osMutexCreate ok\n");
}
}
static void demo_task1(void *arg)
{
int count = 0;
while (1)
{
osMutexWait(pMutex, 0xffffffff);
printf("demo_task1 get mutex %d\n", count++);
};
}
static void demo_task2(void *arg)
{
int count = 0;
while (1)
{
osMutexRelease(pMutex);
printf("demo_task2 release mutex %d\n", count++);
osDelay(RHINO_CONFIG_TICKS_PER_SECOND*10000);
};
}
void cmsis_mutex_test(void)
{
thread_init.name = "init_task";
thread_init.pthread = (os_pthread)init_task;
thread_init.tpriority= osPriorityHigh;
thread_init.stacksize= DEMO_TASK_STACKSIZE;
thread_init.ptcb = &init_task_obj;
thread_init.pstackspace = init_task_buf;
thread1.name = "demo_task1";
thread1.pthread = (os_pthread)demo_task1;
thread1.tpriority= osPriorityNormal;
thread1.stacksize= DEMO_TASK_STACKSIZE;
thread1.ptcb = &demo_task_obj1;
thread1.pstackspace = demo_task_buf1;
thread2.name = "demo_task2";
thread2.pthread = (os_pthread)demo_task2;
thread2.tpriority= osPriorityNormal;
thread2.stacksize= DEMO_TASK_STACKSIZE;
thread2.ptcb = &demo_task_obj2;
thread2.pstackspace = demo_task_buf2;
osThreadCreate (&thread_init, NULL);
osThreadCreate (&thread1, NULL);
osThreadCreate (&thread2, NULL);
}

View file

@ -0,0 +1,95 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include <k_api.h>
#include <stdio.h>
#include <stdlib.h>
#include <cmsis_os.h>
#define DEMO_TASK_STACKSIZE 256 //256*cpu_stack_t = 1024byte
#define DEMO_TASK_PRIORITY 20
static ktask_t init_task_obj;
static ktask_t demo_task_obj1;
static ktask_t demo_task_obj2;
static cpu_stack_t init_task_buf[DEMO_TASK_STACKSIZE];
static cpu_stack_t demo_task_buf1[DEMO_TASK_STACKSIZE];
static cpu_stack_t demo_task_buf2[DEMO_TASK_STACKSIZE];
static osThreadDef_t thread_init;
static osThreadDef_t thread1;
static osThreadDef_t thread2;
static ksem_t sem;
static osSemaphoreDef_t sem_def;
static osSemaphoreId pSem;
static void init_task(void *arg)
{
sem_def.name = "sem";
sem_def.sem = &sem;
pSem = osSemaphoreCreate (&sem_def, 0);
if (pSem == NULL)
{
printf("osSemaphoreCreate failed\n");
}
else
{
printf("osSemaphoreCreate ok\n");
}
}
static void demo_task1(void *arg)
{
int count = 0;
while (1)
{
osSemaphoreWait(pSem, 0xffffffff);
printf("demo_task1 get sem %d\n", count++);
};
}
static void demo_task2(void *arg)
{
int count = 0;
while (1)
{
osSemaphoreRelease(pSem);
printf("demo_task2 release sem %d\n", count++);
osDelay(RHINO_CONFIG_TICKS_PER_SECOND*10000);
};
}
void cmsis_sem_test(void)
{
thread_init.name = "init_task";
thread_init.pthread = (os_pthread)init_task;
thread_init.tpriority = osPriorityHigh;
thread_init.stacksize = DEMO_TASK_STACKSIZE;
thread_init.ptcb = &init_task_obj;
thread_init.pstackspace = init_task_buf;
thread1.name = "demo_task1";
thread1.pthread = (os_pthread)demo_task1;
thread1.tpriority = osPriorityNormal;
thread1.stacksize = DEMO_TASK_STACKSIZE;
thread1.ptcb = &demo_task_obj1;
thread1.pstackspace = demo_task_buf1;
thread2.name = "demo_task2";
thread2.pthread = (os_pthread)demo_task2;
thread2.tpriority = osPriorityNormal;
thread2.stacksize = DEMO_TASK_STACKSIZE;
thread2.ptcb = &demo_task_obj2;
thread2.pstackspace = demo_task_buf2;
osThreadCreate (&thread_init, NULL);
osThreadCreate (&thread1, NULL);
osThreadCreate (&thread2, NULL);
}

View file

@ -0,0 +1,75 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include <k_api.h>
#include <stdio.h>
#include <stdlib.h>
#include <cmsis_os.h>
#define DEMO_TASK_STACKSIZE 256 //256*cpu_stack_t = 1024byte
#define DEMO_TASK_PRIORITY 20
static ktask_t demo_task_obj;
static cpu_stack_t demo_task_buf[DEMO_TASK_STACKSIZE];
static osThreadDef_t thread;
static osTimerDef_t timer_def;
static ktimer_t timer_space;
static int timer_cb_count = 0;
static void timer_function(void)
{
timer_cb_count ++;
printf("timer cb is called, timer_cb_count = %d\n");
}
static void demo_task(void *arg)
{
int count = 0;
osTimerId pTimerId = NULL;
timer_def.name = "testTimer";
timer_def.cb = (os_ptimer)timer_function;
timer_def.timer= &timer_space;
pTimerId = osTimerCreate (&timer_def, osTimerPeriodic, NULL);
if (pTimerId == NULL)
{
printf("osTimerCreate failed, MAX_TIMER_TICKS = %d\n",MAX_TIMER_TICKS);
}
else
{
printf("osTimerCreate ok\n");
}
osTimerStart (pTimerId, 1000000);
while (1)
{
printf("hello world! count %d\n", count++);
//sleep 1 second
osDelay(RHINO_CONFIG_TICKS_PER_SECOND*10000);
if (timer_cb_count > 10)
{
osTimerStop(pTimerId);
}
};
}
void cmsis_timer_test(void)
{
thread.name = "demo_task";
thread.pthread = (os_pthread)demo_task;
thread.tpriority= osPriorityNormal;
thread.stacksize= DEMO_TASK_STACKSIZE;
thread.ptcb = &demo_task_obj;
thread.pstackspace = demo_task_buf;
osThreadCreate (&thread, NULL);
}

View file

@ -0,0 +1,11 @@
menu "ESPOS"
config ESPOS
bool "Enable Espressif RTOS abstract API"
default y
help
If this feature is enabled, system will use Espressif RTOS abstract APIs instead of RTOS real APIs.
This option is not currently used anywhere.
endmenu

View file

@ -0,0 +1,14 @@
NAME := espos
GLOBAL_INCLUDES += include
$(NAME)_SOURCES := \
platform/rhino/espos_misc.c \
platform/rhino/espos_mutex.c \
platform/rhino/espos_queue.c \
platform/rhino/espos_scheduler.c \
platform/rhino/espos_semaphore.c \
platform/rhino/espos_spinlock.c \
platform/rhino/espos_task.c \
platform/rhino/espos_time.c \
platform/rhino/espos_timer.c

View file

@ -0,0 +1,26 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _ESPOS_ARCH_H_
#define _ESPOS_ARCH_H_
#if defined(ESPOS_FOR_ESP32)
#include "espos_esp32.h"
#elif defined(ESPOS_FOR_ESP8266)
#include "espos_esp8266.h"
#else
#error "no espressif platform"
#endif
#endif

View file

@ -0,0 +1,110 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _ESPOS_ESP32_H_
#define _ESPOS_ESP32_H_
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifndef CONFIG_FREERTOS_UNICORE
#define ESPOS_PROCESSORS_NUM 2u
#define CONFIG_ESPOS_SMP
#else
#define ESPOS_PROCESSORS_NUM 1u
#endif
typedef struct espos_spinlock_arch {
int lock;
} espos_spinlock_arch_t;
#define ESPOS_SPINLOCK_ARCH_UNLOCK_INITIALIZER \
{ \
0, \
}
static inline int espos_get_core_id(void)
{
int id;
__asm__ __volatile__ (
" rsr.prid %0\n"
" extui %0, %0, 13, 1\n"
:"=r"(id));
return id;
}
static inline void espos_spinlock_arch_init(espos_spinlock_arch_t *lock)
{
lock->lock = 0;
}
static inline void espos_spinlock_arch_deinit(espos_spinlock_arch_t *lock)
{
lock->lock = 0;
}
static inline void espos_spinlock_arch_lock(espos_spinlock_arch_t *lock)
{
unsigned long tmp;
__asm__ __volatile__(
" movi %0, 0\n"
" wsr %0, scompare1\n"
"1: movi %0, 1\n"
" s32c1i %0, %1, 0\n"
" bnez %0, 1b\n"
: "=&a" (tmp)
: "a" (&lock->lock)
: "memory");
}
static inline int espos_spinlock_arch_trylock(espos_spinlock_arch_t *lock)
{
unsigned long tmp;
__asm__ __volatile__(
" movi %0, 0\n"
" wsr %0, scompare1\n"
" movi %0, 1\n"
" s32c1i %0, %1, 0\n"
: "=&a" (tmp)
: "a" (&lock->lock)
: "memory");
return tmp == 0 ? 0 : 1;
}
static inline void espos_spinlock_arch_unlock(espos_spinlock_arch_t *lock)
{
unsigned long tmp;
__asm__ __volatile__(
" movi %0, 0\n"
" s32ri %0, %1, 0\n"
: "=&a" (tmp)
: "a" (&lock->lock)
: "memory");
}
#ifdef __cplusplus
}
#endif
#endif /* _ESPOS_ESP32_H_ */

View file

@ -0,0 +1,57 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _ESPOS_ESP8266_H_
#define _ESPOS_ESP8266_H_
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#define ESPOS_PROCESSORS_NUM 1u
#define ESPOS_SPINLOCK_ARCH_UNLOCK_INITIALIZER \
{ \
0, \
}
typedef int32_t esp_err_t;
typedef struct espos_spinlock_arch {
int lock;
} espos_spinlock_arch_t;
static inline uintptr_t espos_suspend_interrupt(void)
{
uintptr_t state;
__asm__ volatile ("RSIL %0, 5" : "=a" (state) :: "memory");
return state;
}
static inline void espos_resume_interrupt(uintptr_t state)
{
__asm__ volatile ("WSR %0, ps" :: "a" (state) : "memory");
}
#define espos_get_core_id() 0
#ifdef __cplusplus
}
#endif
#endif /* _ESPOS_ESP8266_H_ */

View file

@ -0,0 +1,17 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#ifndef _ESPOS_ERRNO_H_
#define _ESPOS_ERRNO_H_
#include <sys/errno.h>
#if defined(ESPOS_FOR_ESP32)
#include "esp_err.h"
#elif defined(ESPOS_FOR_ESP8266)
#endif
#endif

View file

@ -0,0 +1,20 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#ifndef ESPOS_INCLUDE_H
#define ESPOS_INCLUDE_H
#include "espos_errno.h"
#include "espos_mutex.h"
#include "espos_queue.h"
#include "espos_scheduler.h"
#include "espos_semaphore.h"
#include "espos_spinlock.h"
#include "espos_task.h"
#include "espos_time.h"
#include "espos_timer.h"
#include "espos_types.h"
#endif /* ESPOS_INCLUDE_H */

View file

@ -0,0 +1,142 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _ESPOS_MUTEX_H_
#define _ESPOS_MUTEX_H_
#include "espos_types.h"
#include "espos_errno.h"
#include "espos_time.h"
#ifdef __cplusplus
extern "C" {
#endif
/* use default option to create mutex */
typedef enum espos_mutex_opt {
/* AT this mode, deadlock detection shall not be provided. Attempting to relock the mutex causes deadlock.
*
* If a thread attempts to unlock a mutex that it has not locked or a mutex which is unlocked,
* undefined behavior results.
*/
ESPOS_MUTEX_NORMAL = 0,
ESPOS_MUTEX_RECURSIVE,
ESPOS_MUTEX_TYPE_MAX
} espos_mutex_type_t;
#define ESPOS_MUTEX_TYPE(type) (type & 0xFF)
/**
* @brief create a mutex
*
* @param mutex mutex handle point
* @param opt mutex option, if you don't know how to do, just use "ESPOS_MUTEX_NORMAL" here
*
* @return the result
* 0 : successful
* -ENOMEM : no enough memory
* -EINTR : you do this at interrupt state, and it is not supported
* -EINVAL : input parameter error
*/
esp_err_t espos_mutex_create(espos_mutex_t *mutex, espos_opt_t opt);
/**
* @brief set a mutex name
*
* @param mutex mutex handle
* @param name mutex's name
*
* @return the result
* 0 : successful
* -EINVAL : input parameter error
*/
esp_err_t espos_mutex_set_name(espos_mutex_t mutex, const char *name);
/**
* @brief lock a mutex
*
* @param mutex mutex handle
* @param wait_ticks sleep for system ticks if the locked mutex is not unlocked. Otherwise if someone
* else unlock the locked mutex, you will wake up.
* maximum time is "ESPOS_MAX_DELAY", no time is "ESPOS_NO_DELAY"
*
* @return the result
* 0 : successful
* -EINVAL : input parameter error
* -EINTR : you do this at interrupt state, and it is not supported
* -ETIMEDOUT : timeout and you have not locked it
*
* @note you can transform the millisecond to ticks by "espos_ms_to_ticks"
*/
esp_err_t espos_mutex_lock(espos_mutex_t mutex, espos_tick_t wait_ticks);
/**
* @bref try to lock a mutex and it will return immediately without being blocked
*
* @param m mutex handle
*
* @return the result
* 0 : successful
* -EINVAL : input parameter error
* -EINTR : you do this at interrupt state, and it is not supported
*/
#define espos_mutex_trylock(m) espos_mutex_lock(m, ESPOS_NO_DELAY)
/**
* @brief unlock a mutex
*
* @param mutex mutex handle
*
* @return the result
* 0 : successful
* -EINVAL : input parameter error
* -EINTR : you do this at interrupt state, and it is not supported
* -EPERM : current task don't lock the mutex
*/
esp_err_t espos_mutex_unlock(espos_mutex_t mutex);
/**
* @brief get task handle which lock the mutex
*
* @param mutex mutex handle
*
* @return the result
* 0 : successful
* -EINVAL : input parameter error
*/
espos_task_t espos_mutex_get_holder(espos_mutex_t mutex);
/**
* @brief delete the mutex
*
* @param mutex mutex handle
*
* @return the result
* 0 : successful
* -EINTR : you do this at interrupt state, and it is not supported
* -EINVAL : input parameter error
*
* @note if low-level module is YunOS, this function will awake all task blocked at the mutex
*/
esp_err_t espos_mutex_del(espos_mutex_t mutex);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,212 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _ESPOS_QUEUE_H_
#define _ESPOS_QUEUE_H_
#include "espos_types.h"
#include "espos_errno.h"
#include "espos_time.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum espos_queue_pos {
/* send message to the front of the queue */
ESPOS_QUEUE_SEND_FRONT = 0,
/* send message to the back of the queue */
ESPOS_QUEUE_SEND_BACK,
ESPOS_QUEUE_POS_MAX
} espos_queue_pos_t;
typedef enum espos_queue_send_opt {
/* send message with normal option */
ESPOS_QUEUE_SEND_OPT_NORMAL = 0,
ESPOS_QUEUE_SEND_OPT_MAX
} espos_queue_send_opt_t;
typedef enum espos_queue_recv_opt {
/* receive message with normal option */
ESPOS_QUEUE_RECV_OPT_NORMAL = 0,
ESPOS_QUEUE_RECV_OPT_MAX
} espos_queue_recv_opt_t;
/**
* @brief create a queue
*
* @param queue queue handle point
* @param msg_len queue internal message length (bytes)
* @param queue_len queue internal message maximum number
*
* @return the result
* 0 : successful
* -ENOMEM : no enough memory
* -EINTR : you do this at interrupt state, and it is not supported
* -EINVAL : input parameter error
*
* @note all input and out message length is fixedly "msg_len"
*/
esp_err_t espos_queue_create(espos_queue_t *queue, espos_size_t msg_len, espos_size_t queue_len);
/**
* @brief set a queue name
*
* @param queue queue handle
* @param name queue's name
*
* @return the result
* 0 : successful
* -EINVAL : input parameter error
*/
esp_err_t espos_queue_set_name(espos_queue_t queue, const char *name);
/**
* @brief send a message to the queue, it is suggested that you had better not use "espos_queue_send" directly,
* please use "espos_queue_send_front" or "espos_queue_send_back"
*
* @param queue queue handle
* @param msg message point
* @param wait_ticks sleep for system ticks if the queue is full. Otherwise if queue is not full, you will wake up.
* maximum time is "ESPOS_MAX_DELAY", no time is "ESPOS_NO_DELAY"
* @param pos position where sending the message
* ESPOS_QUEUE_SEND_FRONT : send message to the front of the queue
* ESPOS_QUEUE_SEND_BACK : send message to the back of the queue
* @param opt sending option
* ESPOS_QUEUE_SEND_OPT_NORMAL : wake up blocked task
*
* @return the result
* 0 : successful
* -EINVAL : input parameter error
* -ETIMEDOUT : timeout and the queue is full
*
* @note you can transform the millisecond to ticks by "espos_ms_to_ticks"
*/
esp_err_t espos_queue_send_generic(espos_queue_t queue, void *msg, espos_tick_t wait_ticks, espos_pos_t pos, espos_opt_t opt);
/**
* @brief send a message to the front of the queue
*
* @param q queue handle
* @param m message point
* @param t sleep for system ticks if the queue is full. Otherwise if queue is not full, you will wake up.
* maximum time is "ESPOS_MAX_DELAY", no time is "ESPOS_NO_DELAY"
*
* @return the result
* 0 : successful
* -EINVAL : input parameter error
* -ETIMEDOUT : timeout and the queue is full
*
* @note you can transform the millisecond to ticks by "espos_ms_to_ticks"
*/
#define espos_queue_send_front(q, m, t) espos_queue_send_generic(q, m, t, ESPOS_QUEUE_SEND_FRONT, ESPOS_QUEUE_SEND_OPT_NORMAL)
/**
* @brief send a message to the back of the queue
*
* @param q queue handle
* @param m message point
* @param t sleep for system ticks if the queue is full. Otherwise if queue is not full, you will wake up.
* maximum time is "ESPOS_MAX_DELAY", no time is "ESPOS_NO_DELAY"
*
* @return the result
* 0 : successful
* -EINVAL : input parameter error
* -ETIMEDOUT : timeout and the queue is full
*
* @note you can transform the millisecond to ticks by "espos_ms_to_ticks"
*/
#define espos_queue_send(q, m, t) espos_queue_send_generic(q, m, t, ESPOS_QUEUE_SEND_BACK, ESPOS_QUEUE_SEND_OPT_NORMAL)
/**
* @brief receive a message of the queue
*
* @param queue queue handle
* @param msg message point
* @param wait_ticks sleep for system ticks if the queue is empty. Otherwise if queue is not empty, you will wake up.
* maximum time is "ESPOS_MAX_DELAY", no time is "ESPOS_NO_DELAY", at CPU ISR mode, it is forced to be 0
* @param opt queue sending option
* ESPOS_QUEUE_RECV_OPT_NORMAL : use wait_ticks to check if it is need be blocked
*
* @return the result
* 0 : successful
* -EINVAL : input parameter error
* -ETIMEDOUT : timeout and the queue is empty
*
* @note you can transform the millisecond to ticks by "espos_ms_to_ticks"
*/
esp_err_t espos_queue_recv_generic(espos_queue_t queue, void *msg, espos_tick_t wait_ticks, espos_opt_t opt);
/**
* @brief receive a message of the queue with normal option
*
* @param queue queue handle
* @param msg message point
* @param wait_ticks sleep for system ticks if the queue is empty. Otherwise if queue is not empty, you will wake up.
* maximum time is "ESPOS_MAX_DELAY", no time is "ESPOS_NO_DELAY", at CPU ISR mode, it is forced to be 0
*
* @return the result
* 0 : successful
* -EINVAL : input parameter error
* -ETIMEDOUT : timeout and the queue is empty
*
* @note you can transform the millisecond to ticks by "espos_ms_to_ticks"
*/
#define espos_queue_recv(q, m, t) espos_queue_recv_generic(q, m, t, ESPOS_QUEUE_RECV_OPT_NORMAL)
/**
* @brief get current message number of the queue
*
* @param queue queue handle
*
* @return current message number of the queue
*/
espos_size_t espos_queue_msg_waiting(espos_queue_t queue);
/**
* @brief reset the queue
*
* @param queue queue handle
*
* @return the result
* 0 : successful
* -EINVAL : input parameter error
*
* @note if low-level module is YunOS, the function will not awake the tasks which is blocked at the queue
*/
esp_err_t espos_queue_flush(espos_queue_t queue);
/**
* @brief delete the queue
*
* @param queue queue handle
*
* @return the result
* 0 : successful
* -EINTR : you do this at interrupt state, and it is not supported
* -EINVAL : input parameter error
*
* @note if low-level module is YunOS, this function will awake all task blocked at the mutex
*/
esp_err_t espos_queue_del(espos_queue_t queue);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,245 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _ESPOS_SCHEDULER_H_
#define _ESPOS_SCHEDULER_H_
#include <stdbool.h>
#include "espos_types.h"
#include "espos_errno.h"
#include "espos_spinlock.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* ESPOS state
*/
typedef enum espos_stat {
ESPOS_IS_NOT_STARTED = 0,
ESPOS_IS_RUNNING,
ESPOS_IS_SUSPENDED
} espos_stat_t;
/************************************ internal function ************************************/
/**
* @brief enter ESPOS system critical state
*
* @param spinlock spinlock handle point
*
* @return critical state temple variable(used by "espos_exit_critical")
*/
espos_critical_t _espos_enter_critical(espos_spinlock_t *spinlock);
/**
* @brief exit ESPOS system critical state
*
* @param spinlock spinlock handle point
* @param tmp critical state temple variable(created by "espos_enter_critical")
*
* @return none
*/
void _espos_exit_critical(espos_spinlock_t *spinlock, espos_critical_t tmp);
/*******************************************************************************************/
/**
* @brief initialize ESPOS system
*
* @return the result
* 0 : successful
* -ENOMEM : no enough memory
*/
esp_err_t espos_init(void);
/**
* @brief start ESPOS system
*
* @return the result
* 0 : successful
* -EPERM : failed (it will never happen in a general way)
*/
esp_err_t espos_start(void);
/**
* @brief start ESPOS system CPU port
*
* @param port CPU port ID
*
* @return the result
* 0 : successful
* -EPERM : failed (it will never happen in a general way)
*/
esp_err_t espos_start_port(int port);
/**
* @brief get espos system state
*
* @return the state
* ESPOS_IS_NOT_STARTED : ESPOS is not started
* ESPOS_IS_RUNNING : ESPOS is running
* ESPOS_IS_SUSPENDED : ESPOS is suspended
*/
espos_stat_t espos_sched_state_get(void);
/**
* @brief declare espos critical temp data
*/
#define espos_declare_critical(t) espos_critical_t t
/**
* @brief enter ESPOS system critical state
*
* @param sl spinlock handle
* @param t critical state
*
* @return critical state temple variable(used by "espos_exit_critical")
*/
#define espos_enter_critical(t, sl) (t) = _espos_enter_critical(&(sl))
/**
* @brief exit ESPOS system critical state
*
* @param t critical state temple variable(created by "espos_enter_critical")
* @param sl spinlock handle point
*
* @return none
*/
#define espos_exit_critical(t, sl) _espos_exit_critical(&(sl), t)
/**
* @brief OS internal function enter ESPOS system critical state
*
* @param sl spinlock handle
* @param t critical state
*
* @return critical state temple variable(used by "espos_exit_critical")
*
* @note: ESPOS is application level OS API, so it means all APIs call internal
* real OS's function, so if OS's or its core hardware's functions want
* to call ESPOS, loop nesting will occur, so we should tell ESPOS it's
* at OS internal state now.
*/
#define espos_os_enter_critical(t, sl) \
espos_os_enter(); \
(t) = _espos_enter_critical(&(sl))
/**
* @brief OS internal function exit ESPOS system critical state
*
* @param t critical state temple variable(created by "espos_enter_critical")
* @param sl spinlock handle point
*
* @return none
*
* @note: ESPOS is application level OS API, so it means all APIs call internal
* real OS's function, so if OS's or its core hardware's functions want
* to call ESPOS, loop nesting will occur, so we should tell ESPOS it's
* at OS internal state now.
*/
#define espos_os_exit_critical(t, sl) \
_espos_exit_critical(&(sl), t); \
espos_os_exit()
/**
* @brief suspend the local CPU core preempt and the current task
* owned by local CPU core will not be preempted
*
* @return the result
* 0 : successful
* -EAGAIN : preempt suspending maximum number is reached, and fail to do it
* -EINTR : you do this at interrupt state, and it is not supported
*
* @note the function can be used nested
*/
esp_err_t espos_preempt_suspend_local(void);
/**
* @brief resume the local CPU core preempt
*
* @return the result
* 0 : successful
* -EAGAIN : preempt resuming maximum number is reached, and fail to do it
* -EINTR : you do this at interrupt state, and it is not supported
*
* @note the function can be used nested
*/
esp_err_t espos_preempt_resume_local(void);
/**
* @brief enter system interrupt server, the function must be used after entering hardware interrupt
*
* @return the result
* 0 : successful
* -EAGAIN : nested count is reached
*
* @note the function can be used nested
*/
esp_err_t espos_isr_enter (void);
/**
* @brief exit system interrupt server, the function must be used before exiting hardware interrupt
*
* @return none
*
* @note the function can be used nested
*/
void espos_isr_exit(void);
/**
* @brief check if the CPU is at ISR state
*
* @param none
*
* @return true if the CPU is at ISR state or false
*/
bool espos_in_isr(void);
/**
* @brief mark it enters real OS interal function
*
* @return the result
* 0 : successful
* -EAGAIN : nested count is reached
*
* @note the function can be used nested
*/
esp_err_t espos_os_enter(void);
/**
* @brief remove mark it enters real OS interal function
*
* @param none
*
* @return none
*/
void espos_os_exit(void);
/**
* @brief check if the function is at real OS internal fucntion
*
* @param none
*
* @return true if the CPU is at real OS internal fucntion or false
*/
bool espos_os_isr(void);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,119 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _ESPOS_SEMAPHORE_H_
#define _ESPOS_SEMAPHORE_H_
#include "espos_types.h"
#include "espos_errno.h"
#include "espos_time.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief create a semaphore
*
* @param sem semaphore handle point
* @param max_count semaphore maximum count
* @param init_count semaphore initialized count
*
* @return the result
* 0 : successful
* ENOMEM : no enough memory
* EINVAL : input parameter error
*
* @note if low-level module is YunOS, "max_count" does not work, and the reachable count is "0xFFFFFFFF"
*/
esp_err_t espos_sem_create(espos_sem_t *sem, espos_sem_count_t max_count, espos_sem_count_t init_count);
/**
* @brief set a semaphore name
*
* @param semaphore semaphore handle
* @param name semaphore's name
*
* @return the result
* 0 : successful
* -EINVAL : input parameter error
*/
esp_err_t espos_sem_set_name(espos_sem_t sem, const char *name);
/**
* @brief take semaphore
*
* @param sem semaphore handle
* @param wait_ticks sleep for system ticks if the semaphore is empty. Otherwise if semaphore is given,
* oldest blocked task will wake up.
* maximum time is "ESPOS_MAX_DELAY", no time is "ESPOS_NO_DELAY"
*
* @return the result
* 0 : successful
* -EINVAL : input parameter error
* -ETIMEDOUT : timeout and not take semaphore
*
* @note you can transform the millisecond to ticks by "espos_ms_to_ticks"
*/
esp_err_t espos_sem_take(espos_sem_t sem, espos_tick_t wait_ticks);
/**
* @brief try to take semaphore
*
* @param s semaphore handle
*
* @return the result
* 0 : successful
* -EINVAL : input parameter error
* -ETIMEDOUT : not take semaphore
*
* @note you can transform the millisecond to ticks by "espos_ms_to_ticks"
*/
#define espos_sem_trytake(s) espos_sem_take(s, ESPOS_NO_DELAY)
/**
* @brief give up semaphore
*
* @param sem semaphore handle
* @param wait_ticks no meaning
*
* @return the result
* 0 : successful
* -EINVAL : input parameter error
* -EAGAIN : the maximum count is reached
*
* @note you can transform the millisecond to ticks by "espos_ms_to_ticks"
*/
esp_err_t espos_sem_give(espos_sem_t sem);
/**
* @brief delete the semaphore
*
* @param sem semaphore handle
*
* @return the result
* 0 : successful
* -EINTR : you do this at interrupt state, and it is not supported
* -EINVAL : input parameter error
*
* @note if low-level module is YunOS, this function will awake all task blocked here
*/
esp_err_t espos_sem_del(espos_sem_t sem);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,128 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _ESPOS_SPINLOCK_H_
#define _ESPOS_SPINLOCK_H_
#include "espos_types.h"
#include "espos_errno.h"
#include "espos_task.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct espos_spinlock {
espos_spinlock_arch_t lock;
espos_task_t holder;
} espos_spinlock_t;
#define ESPOS_SPINLOCK_UNLOCK_INITIALIZER \
{ \
ESPOS_SPINLOCK_ARCH_UNLOCK_INITIALIZER, \
ESPOS_OBJ_NONE, \
}
#define ESPOS_DEFINE_SPINLOCK(l) \
espos_spinlock_t l = ESPOS_SPINLOCK_UNLOCK_INITIALIZER
#define ESPOS_DEFINE_STATIC_SPINLOCK(l) \
static espos_spinlock_t l = ESPOS_SPINLOCK_UNLOCK_INITIALIZER
/**
* @brief create a spinlock
*
* @param spinlock spinlock handle point
*
* @return the result
* 0 : successful
* -ENOMEM : no enough memory
* -EINVAL : input parameter error
*/
esp_err_t espos_spinlock_create (espos_spinlock_t *spinlock);
/**
* @brief set a spinlock name
*
* @param spinlock spinlock handle
* @param name spinlock's name
*
* @return the result
* 0 : successful
* -EINVAL : input parameter error
*/
esp_err_t espos_spinlock_set_name(espos_spinlock_t *spinlock, const char *name);
/**
* @brief spin to lock a spinlock until successfully
*
* @param spinlock spinlock handle
*
* @return the result
* 0 : successful
* -EINVAL : input parameter error
*/
esp_err_t espos_spinlock_lock(espos_spinlock_t *spinlock);
/**
* @brief try to lock a spinlock
*
* @param spinlock spinlock handle
*
* @return the result
* 0 : successful
* -EAGAIN : no spinlock is valid
* -EINVAL : input parameter error
*/
esp_err_t espos_spinlock_trylock(espos_spinlock_t *spinlock);
/**
* @brief get spinlock holder task handle
*
* @param spinlock spinlock handle
*
* @return holder task handle
*/
espos_task_t espos_spinlock_get_holder(espos_spinlock_t *spinlock);
/**
* @brief unlock a spinlock
*
* @param spinlock spinlock handle
*
* @return the result
* 0 : successful
* -EAGAIN : no spinlock is locked
* -EINVAL : input parameter error
*/
esp_err_t espos_spinlock_unlock(espos_spinlock_t *spinlock);
/**
* @brief delete a spinlock
*
* @param spinlock spinlock handle
*
* @return the result
* 0 : successful
* -EACCES : failed to do it with some special reason
* -EINVAL : input parameter error
*/
esp_err_t espos_spinlock_del(espos_spinlock_t *spinlock);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,209 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _ESPOS_TASK_H_
#define _ESPOS_TASK_H_
#include "espos_types.h"
#include "espos_errno.h"
#include "espos_time.h"
#ifdef __cplusplus
extern "C" {
#endif
/* task will run at any CPU */
#define ESPOS_TASK_NO_AFFINITY -1
/* create task and start it automatically */
#define ESPOS_TASK_CREATE_NORMAL 0
/* just create task and don't start it */
#define ESPOS_TASK_CREATE_SILENCE 1
/* task delete itself */
#define ESPOS_TASK_DELETE_SELF 0
/*
* task priority numbers, we use 26 here because FreeRTOS uses 26 but YunOS uses 62,
* we should use minimum one of them to be compatible with the current application
*/
#ifndef ESPOS_TASK_PRIO_NUM
#define ESPOS_TASK_PRIO_NUM espos_task_prio_num()
#endif
/* task maximum priority number */
#define ESPOS_TASK_PRIO_MAX (ESPOS_TASK_PRIO_NUM - 1)
/**
* @brief create a task
*
* @param task task handle point
* @param name task name, if name is NULL, we will use "default_task" default
* @param arg task entry function inputting parameter
* @param prio task priority
* @param ticks task time slice
* @param stack_size task stack size, its unit is "byte"
* @param entry task entry function
* @param opt task option
* ESPOS_TASK_CREATE_NORMAL : the created task will be started automatically
* ESPOS_TASK_CREATE_SILENCE : the created task will not be started automatically
* @param cpu_id task CPU id
* natural number : the task only runs at the CPU of the number
* ESPOS_TASK_NO_AFFINITY : the task runs at any CPU
*
* @return the result
* 0 : successful
* -ENOMEM : no enough memory
* -EINVAL : input parameter error
* -EINTR : you do this at interrupt state, and it is not supported
*/
esp_err_t espos_task_create_on_cpu(espos_task_t *task, const char *name, void *arg, espos_prio_t prio,
espos_tick_t ticks, espos_size_t stack_size, espos_task_entry_t entry, espos_opt_t opt, espos_cpu_t cpu_id);
/**
* @brief create a task and set its CPU id to be "ESPOS_TASK_NO_AFFINITY"
*
* @param task task handle point
* @param name task name, if name is NULL, we will use "default_task" default
* @param arg task entry function inputting parameter
* @param prio task priority
* @param ticks task time slice
* @param stack_size task stack size, its unit is "byte"
* @param entry task entry function
* @param opt task option
* ESPOS_TASK_CREATE_NORMAL : the created task will be started automatically
* ESPOS_TASK_CREATE_SILENCE : the created task will not be started automatically
*
* @return the result
* 0 : successful
* -ENOMEM : no enough memory
* -EINVAL : input parameter error
* -EINTR : you do this at interrupt state, and it is not supported
*/
#define espos_task_create(task, name, arg, prio, ticks, stack_size, entry, opt) \
espos_task_create_on_cpu(task, name, arg, prio, ticks, stack_size, entry, opt, ESPOS_TASK_NO_AFFINITY)
/**
* @brief delete a task
*
* @param task task handle
* ESPOS_TASK_DELETE_SELF : task will delete itself
*
* @return the result
* 0 : successful
* EACCES : failed to do it with some special reason
*/
esp_err_t espos_task_del(espos_task_t task);
/**
* @brief let current task sleep for some ticks
*
* @param delay_ticks system ticks
*
* @return the result
* 0 : successful
* EINVAL : input parameter error
*/
esp_err_t espos_task_delay(const espos_tick_t delay_ticks);
/**
* @brief suspend target task
*
* @param task task handle
*
* @return the result
* 0 : successful
* EINVAL : input parameter error
*/
esp_err_t espos_task_suspend(espos_task_t task);
/**
* @brief resume target task
*
* @param task task handle
*
* @return the result
* 0 : successful
* EINVAL : input parameter error
*/
esp_err_t espos_task_resume(espos_task_t task);
/**
* @brief yield the cpu once
*
* @return the result
* 0 : successful
* EACCES : failed to do it with some special reason
*/
esp_err_t espos_task_yield(void);
/**
* @brief get current task handle
*
* @return current task handle
*/
espos_task_t espos_task_get_current(void);
/**
* @brief get current task name point
*
* @param task task handle
* @param pname pointing at name's point
*
* @return current task handle
*/
esp_err_t espos_task_get_name (espos_task_t task, char **pname);
/**
* @brief set task private data
*
* @param task task handle
* @param idx task data index
* @param info task private data
*
* @return the result
* 0 : successful
* EINVAL : input parameter error
*/
esp_err_t espos_task_set_private_data(espos_task_t task, int idx, void *info);
/**
* @brief get task private data
*
* @param task task handle
* @param idx task data index
* @param info task private data point
*
* @return the result
* 0 : successful
* EINVAL : input parameter error
*/
esp_err_t espos_task_get_private_data(espos_task_t task, int idx, void **info);
/**
* @brief get CPU affinity of task
*
* @return CPU affinity of task
*/
espos_cpu_t espos_task_get_affinity(espos_task_t task);
size_t espos_task_prio_num(void);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,69 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _ESPOS_TIME_H_
#define _ESPOS_TIME_H_
#include "espos_types.h"
#include "espos_errno.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
* delay or wait for ticks, it is used by mutex, queue,
* semaphore, timer and so on
*/
/* no delay for ticks, function will return immediately */
#define ESPOS_NO_DELAY 0u
/* delay forever, function will never return until event triggers */
#define ESPOS_MAX_DELAY 0xffffffffu
espos_time_t espos_get_tick_per_ms(void);
/**
* @brief get current system ticks
*
* @return current ticks
*/
espos_tick_t espos_get_tick_count(void);
/**
* @brief transform milliseconds to system ticks
*
* @param ms milliseconds
*
* @return system ticks
*
* @note the function discards the shortage of digits, for example:
* 20ms -> 2 ticks ; 21ms -> 2 ticks; 29 -> 2 ticks
*/
espos_tick_t espos_ms_to_ticks(espos_time_t ms);
/**
* @brief transform system ticks to milliseconds
*
* @param ticks system ticks
*
* @return milliseconds
*/
espos_time_t espos_ticks_to_ms(espos_tick_t ticks);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,174 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _ESPOS_TIMER_H_
#define _ESPOS_TIMER_H_
#include "espos_types.h"
#include "espos_errno.h"
#include "espos_time.h"
#ifdef __cplusplus
extern "C" {
#endif
/* timer just run once after starting it */
#define ESPOS_TIMER_NO_AUTO_RUN 0
/* timer run cycle after starting it */
#define ESPOS_TIMER_AUTO_RUN (1 << 0)
/* timer configuration command */
typedef enum espos_timer_cmd {
/* configure time's period */
ESPOS_TIMER_CHANGE_PERIOD = 0,
/* configure time to be "once" */
ESPOS_TIMER_CHANGE_ONCE,
/* configure time to be "auto" */
ESPOS_TIMER_CHANGE_AUTO,
ESPOS_TIMER_CMD_MAX
} espos_timer_cmd_t;
/**
* @brief create a timer
*
* @param timer timer handle point
* @param name timer name, if name is NULL, we will use "default_timer" default
* @param cb timer callback function
* @param arg timer entry function inputting parameter
* @param period_ticks timer period ticks
* @param opt timer option
* ESPOS_TIMER_NO_AUTO_RUN : created timer will run once, even if it is started,
* ESPOS_TIMER_AUTO_RUN : created timer will run automatically
*
* @return the result
* 0 : successful
* -ENOMEM : no enough memory
* -EINVAL : input parameter error
* -EINTR : you do this at interrupt state, and it is not supported
*
* @note after starting the created timer by "espos_timer_start", it will only run.
*/
esp_err_t espos_timer_create(espos_timer_t *timer, const char *name, espos_timer_cb_t cb, void *arg,
espos_tick_t period_ticks, espos_opt_t opt);
/**
* @brief start a timer
*
* @param timer timer handle
*
* @return the result
* 0 : successful
* -EINVAL : input parameter error
* -ECANCELED : failed for some reason depend on low-level OS
*
* @note after starting the created timer by "espos_timer_start", it will only run
*/
esp_err_t espos_timer_start(espos_timer_t timer);
/**
* @brief stop a timer
*
* @param timer timer handle
*
* @return the result
* 0 : successful
* -EINVAL : input parameter error
* -ECANCELED : failed for some reason depend on low-level OS
*
* @note the timer should be started again, if it is stopped
*/
esp_err_t espos_timer_stop(espos_timer_t timer);
/**
* @brief configure a timer
*
* @param timer timer handle
* @param opt timer option command
* @param arg timer parameter
*
* @return the result
* 0 : successful
* -EINVAL : input parameter error
* -ECANCELED : failed for some reason depend on low-level OS
*/
esp_err_t espos_timer_change(espos_timer_t timer, espos_opt_t opt, void *arg);
/**
* @brief configure period of timer
*
* @param t timer handle
* @param a timer period
*
* @return the result
* 0 : successful
* -EINVAL : input parameter error
* -ECANCELED : failed for some reason depend on low-level OS
*/
#define espos_timer_set_period(t, a) espos_timer_change(t, ESPOS_TIMER_CHANGE_PERIOD, (void *)a)
/**
* @brief configure timer to be "once"
*
* @param t timer handle
*
* @return the result
* 0 : successful
* -EINVAL : input parameter error
* -ECANCELED : failed for some reason depend on low-level OS
*/
#define espos_timer_set_once(t) espos_timer_change(t, ESPOS_TIMER_CHANGE_ONCE, NULL)
/**
* @brief configure timer to be "auto"
*
* @param t timer handle
*
* @return the result
* 0 : successful
* -EINVAL : input parameter error
* -ECANCELED : failed for some reason depend on low-level OS
*/
#define espos_timer_set_auto(t) espos_timer_change(t, ESPOS_TIMER_CHANGE_AUTO, NULL)
/**
* @brief delete a timer
*
* @param t timer handle
*
* @return the result
* 0 : successful
* -EACCES : failed to do it with some special reason
* -EINTR : you do this at interrupt state, and it is not supported
*/
esp_err_t espos_timer_del(espos_timer_t timer);
/**
* @brief get current timer name point
*
* @param timer timer handle
* @param pname pointing at name's point
*
* @return the result
* 0 : successful
* -EINVAL : input parameter error
*/
esp_err_t espos_get_timer_name (espos_timer_t timer, char **pname);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,42 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#ifndef _ESPOS_TYPES_H_
#define _ESPOS_TYPES_H_
#include <stdint.h>
#include <stddef.h>
#include "arch/espos_arch.h"
#define ESPOS_OBJ_NONE 0
#ifdef ARCH64
typedef uint64_t espos_obj_t;
#else
typedef uint32_t espos_obj_t;
#endif
typedef espos_obj_t espos_task_t;
typedef espos_obj_t espos_queue_t;
typedef espos_obj_t espos_mutex_t;
typedef espos_obj_t espos_sem_t;
typedef espos_obj_t espos_timer_t;
typedef espos_obj_t espos_critical_t;
typedef size_t espos_size_t;
typedef size_t espos_pos_t;
typedef uint8_t espos_prio_t;
typedef uint32_t espos_opt_t;
typedef int32_t espos_cpu_t;
typedef espos_size_t espos_tick_t;
typedef espos_size_t espos_time_t;
typedef espos_size_t espos_sem_count_t;
typedef void (*espos_task_entry_t)(void *p);
typedef void (*espos_timer_cb_t)(espos_timer_t timer, void *arg);
#endif

View file

@ -0,0 +1,13 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#ifndef ESPOS_ERR_MAP_H
#define ESPOS_ERR_MAP_H
#define IRAM_ATTR __attribute__((section(".text")))
int espos_err_map (kstat_t err_code);
#endif

View file

@ -0,0 +1,22 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include "k_api.h"
#include "espos_err.h"
int IRAM_ATTR espos_err_map (kstat_t err_code)
{
if (err_code == RHINO_SUCCESS) {
return 0;
}
return -1;
}
size_t espos_get_free_heap_size(void)
{
extern k_mm_head *g_kmm_head;
return g_kmm_head->free_size;
}

View file

@ -0,0 +1,111 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdlib.h>
#include "k_api.h"
#include "espos_err.h"
#include "espos_mutex.h"
#include "espos_scheduler.h"
/**
* @brief create a mutex
*/
esp_err_t espos_mutex_create (
espos_mutex_t *mutex,
espos_opt_t opt
)
{
kstat_t ret;
kmutex_t **pmutex = (kmutex_t **)mutex;
ret = krhino_mutex_dyn_create(pmutex, "default_mutex");
return espos_err_map(ret);
}
/**
* @brief set a mutex name
*/
esp_err_t espos_mutex_set_name(espos_mutex_t mutex, const char *name)
{
return 0;
}
/**
* @brief lock a mutex
*/
esp_err_t espos_mutex_lock (
espos_mutex_t mutex,
espos_tick_t wait_ticks
)
{
kstat_t ret;
kmutex_t *pmutex = (kmutex_t *)mutex;
ret = krhino_mutex_lock(pmutex, wait_ticks);
if (ret == RHINO_MUTEX_OWNER_NESTED) {
return 0;
}
return espos_err_map(ret);
}
/**
* @brief unlock a mutex
*/
esp_err_t espos_mutex_unlock (
espos_mutex_t mutex
)
{
kstat_t ret;
kmutex_t *pmutex = (kmutex_t *)mutex;
ret = krhino_mutex_unlock(pmutex);
if (ret == RHINO_MUTEX_OWNER_NESTED) {
return 0;
}
return espos_err_map(ret);
}
/**
* @brief get task handle whick lock the mutex
*/
espos_task_t espos_mutex_get_holder (
espos_mutex_t mutex
)
{
espos_task_t tmp;
kmutex_t *pmutex = (kmutex_t *)mutex;
tmp = (espos_task_t)(pmutex->mutex_task);
return tmp;
}
/**
* @brief delete the mutex
*/
esp_err_t espos_mutex_del (
espos_mutex_t mutex
)
{
kstat_t ret;
kmutex_t *pmutex = (kmutex_t *)mutex;
ret = krhino_mutex_dyn_del(pmutex);
return espos_err_map(ret);
}

View file

@ -0,0 +1,138 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "k_api.h"
#include "espos_err.h"
#include "espos_queue.h"
#include "espos_scheduler.h"
/**
* @brief create a queue
*/
esp_err_t espos_queue_create (
espos_queue_t *queue,
espos_size_t msg_len,
espos_size_t queue_len
)
{
kstat_t ret;
kbuf_queue_t **pqueue = (kbuf_queue_t **)queue;
ret = krhino_buf_queue_dyn_create(pqueue, "default_queue", queue_len * (msg_len + COMPRESS_LEN(msg_len)), msg_len);
return espos_err_map(ret);
}
/**
* @brief set a queue name
*
* @param queue queue handle
* @param name queue's name
*
* @return the result
* 0 : successful
* -EINVAL : input parameter error
*/
esp_err_t espos_queue_set_name(espos_queue_t queue, const char *name)
{
return 0;
}
/**
* @brief send a message to the queue
*/
esp_err_t IRAM_ATTR espos_queue_send_generic (
espos_queue_t queue,
void *msg,
espos_tick_t wait_ticks,
espos_pos_t pos,
espos_opt_t opt
)
{
kstat_t ret;
kbuf_queue_t *pqueue = (kbuf_queue_t *)queue;
ret = krhino_buf_queue_send(pqueue, msg, pqueue->max_msg_size);
return espos_err_map(ret);
}
/**
* @brief receive a message of the queue
*/
esp_err_t espos_queue_recv_generic (
espos_queue_t queue,
void *msg,
espos_tick_t wait_ticks,
espos_opt_t opt
)
{
kstat_t ret;
kbuf_queue_t *pqueue = (kbuf_queue_t *)queue;
size_t msg_len;
ret = krhino_buf_queue_recv(pqueue, wait_ticks, msg, &msg_len);
return espos_err_map(ret);
}
/**
* @brief get current message number of the queue
*/
espos_size_t espos_queue_msg_waiting(espos_queue_t queue)
{
CPSR_ALLOC();
espos_size_t item_size;
kbuf_queue_t *pqueue = (kbuf_queue_t *)queue;
RHINO_CRITICAL_ENTER();
//item_size = (pqueue->buf_size - pqueue->free_buf_size) / (pqueue->max_msg_size + HEADER_SIZE);
item_size = pqueue->cur_num;
RHINO_CRITICAL_EXIT();
return item_size;
}
/**
* @brief reset the queue
*/
esp_err_t espos_queue_flush (
espos_queue_t queue
)
{
kstat_t ret;
kbuf_queue_t *pqueue = (kbuf_queue_t *)queue;
ret = krhino_buf_queue_flush(pqueue);
return espos_err_map(ret);
}
/**
* @brief delete the queue
*/
esp_err_t espos_queue_del (
espos_queue_t queue
)
{
kstat_t ret;
kbuf_queue_t *pqueue = (kbuf_queue_t *)queue;
ret = krhino_buf_queue_dyn_del(pqueue);
return espos_err_map(ret);
}

View file

@ -0,0 +1,217 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stddef.h>
#include <stdint.h>
#include "k_api.h"
#include "espos_err.h"
#include "espos_scheduler.h"
static espos_size_t s_isr_nested_count[ESPOS_PROCESSORS_NUM];
static espos_size_t s_os_nested_count[ESPOS_PROCESSORS_NUM];
#if 1
static espos_size_t s_critial_count[ESPOS_PROCESSORS_NUM];
static espos_critical_t s_critial_status[ESPOS_PROCESSORS_NUM];
#endif
/**
* @brief initialize ESPOS system
*/
esp_err_t espos_init(void)
{
kstat_t ret;
ret = krhino_init();
return espos_err_map(ret);
}
/**
* @brief start ESPOS system
*/
esp_err_t espos_start(void)
{
kstat_t ret;
ret = krhino_start();
return espos_err_map(ret);
}
/**
* @brief start ESPOS system CPU port
*/
esp_err_t espos_start_port(int port)
{
return 0;
}
/**
* @brief get ESPOS system state
*/
espos_stat_t espos_sched_state_get(void)
{
if (g_sys_stat == RHINO_RUNNING) {
return ESPOS_IS_RUNNING;
}
return ESPOS_IS_NOT_STARTED;
}
/**
* @brief check if the CPU is at ISR state
*/
bool espos_in_isr(void)
{
return (s_isr_nested_count[0] > 0) ? true : false;
}
/**
* @brief check if the function is at real OS internal fucntion
*/
bool espos_os_isr(void)
{
return (s_os_nested_count[0] > 0) ? true : false;
}
static inline uint32_t __set_int(void)
{
uint32_t flags;
__asm__ __volatile__(
"rsil %0, 2\n"
: "=a"(flags)
:
: "memory"
);
return flags;
}
static inline void __set_ps(uint32_t flags)
{
__asm__ __volatile__(
"wsr %0, ps\n"
"esync"
:
: "a"(flags)
: "memory"
);
}
/**
* @brief enter ESPOS system critical state
*/
espos_critical_t IRAM_ATTR _espos_enter_critical(espos_spinlock_t *spinlock)
{
espos_critical_t tmp;
tmp = (espos_critical_t)__set_int();
if (!s_critial_count[espos_get_core_id()]) {
s_critial_status[espos_get_core_id()] = tmp;
}
s_critial_count[espos_get_core_id()]++;
return tmp;
}
/**
* @brief exit ESPOS system critical state
*/
void IRAM_ATTR _espos_exit_critical(espos_spinlock_t *spinlock, espos_critical_t tmp)
{
s_critial_count[espos_get_core_id()]--;
if (!s_critial_count[espos_get_core_id()]) {
tmp = s_critial_status[espos_get_core_id()];
__set_ps(tmp);
}
}
/**
* @brief suspend the preempt and the current task will not be preempted
*/
esp_err_t espos_preempt_suspend_local(void)
{
kstat_t ret;
if (g_sys_stat == RHINO_STOPPED) {
return 0;
}
ret = krhino_sched_disable();
return espos_err_map(ret);
}
/**
* @brief resume the preempt
*/
esp_err_t espos_preempt_resume_local(void)
{
kstat_t ret;
if (g_sys_stat == RHINO_STOPPED) {
return 0;
}
ret = krhino_sched_enable();
return espos_err_map(ret);
}
/**
* @brief enter system interrupt server, the function must be used after entering hardware interrupt
*/
esp_err_t espos_isr_enter (void)
{
kstat_t ret;
ret = krhino_intrpt_enter();
return espos_err_map(ret);
}
/**
* @brief exit system interrupt server, the function must be used before exiting hardware interrupt
*/
void espos_isr_exit(void)
{
krhino_intrpt_exit();
}
/**
* @brief mark it enters real OS interal function
*/
esp_err_t espos_os_enter (void)
{
s_os_nested_count[espos_get_core_id()]++;
return 0;
}
/**
* @brief remove mark it enters real OS interal function
*/
void espos_os_exit(void)
{
if (!s_os_nested_count[espos_get_core_id()]) {
return ;
}
s_os_nested_count[espos_get_core_id()]--;
return ;
}

View file

@ -0,0 +1,90 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <k_api.h>
#include "espos_err.h"
#include "espos_semaphore.h"
#include "espos_scheduler.h"
/**
* @brief create a semaphore
*/
esp_err_t espos_sem_create (
espos_sem_t *sem,
espos_sem_count_t max_count,
espos_sem_count_t init_count
)
{
kstat_t ret;
ksem_t **psem = (ksem_t **)sem;
ret = krhino_sem_dyn_create(psem, "default_sem", init_count);
return espos_err_map(ret);
}
/**
* @brief set a semaphore name
*/
esp_err_t espos_sem_set_name(espos_sem_t sem, const char *name)
{
return 0;
}
/**
* @brief take semaphore
*/
esp_err_t espos_sem_take (
espos_sem_t sem,
espos_tick_t wait_ticks
)
{
kstat_t ret;
ksem_t *psem = (ksem_t *)sem;
ret = krhino_sem_take(psem, wait_ticks);
return espos_err_map(ret);
}
/**
* @brief give up semaphore
*/
esp_err_t espos_sem_give (
espos_sem_t sem
)
{
kstat_t ret;
ksem_t *psem = (ksem_t *)sem;
ret = krhino_sem_give(psem);
return espos_err_map(ret);
}
/**
* @brief delete the semaphore
*/
esp_err_t espos_sem_del (
espos_sem_t sem
)
{
kstat_t ret;
ksem_t *psem = (ksem_t *)sem;
ret = krhino_sem_dyn_del(psem);
return espos_err_map(ret);
}

View file

@ -0,0 +1,134 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "espos_spinlock.h"
#include "espos_scheduler.h"
/**
* @brief create a spinlock
*/
esp_err_t espos_spinlock_create (
espos_spinlock_t *spinlock
)
{
if (!spinlock) {
return -EINVAL;
}
espos_spinlock_arch_init(&spinlock->lock);
return 0;
}
/**
* @brief set a spinlock name
*/
esp_err_t espos_spinlock_set_name(espos_spinlock_t *spinlock, const char *name)
{
return 0;
}
/**
* @brief spin to lock a spinlock until sucessfully
*/
esp_err_t espos_spinlock_lock (
espos_spinlock_t *spinlock
)
{
if (!spinlock) {
return -EINVAL;
}
espos_preempt_suspend_local();
espos_spinlock_arch_lock(&spinlock->lock);
spinlock->holder = espos_task_get_current();
return 0;
}
/**
* @brief try to lock a spinlock
*/
esp_err_t espos_spinlock_trylock (
espos_spinlock_t *spinlock
)
{
int ret;
if (!spinlock) {
return -EINVAL;
}
espos_preempt_suspend_local();
ret = espos_spinlock_arch_trylock(&spinlock->lock);
if (ret) {
ret = -EAGAIN;
espos_preempt_resume_local();
} else {
spinlock->holder = espos_task_get_current();
}
return ret;
}
/**
* @brief get spinlock holder task handle
*/
espos_task_t espos_spinlock_get_holder (
espos_spinlock_t *spinlock
)
{
return spinlock->holder;
}
/**
* @brief unlock a spinlock
*/
esp_err_t espos_spinlock_unlock (
espos_spinlock_t *spinlock
)
{
if (!spinlock) {
return -EINVAL;
}
spinlock->holder = ESPOS_OBJ_NONE;
espos_spinlock_arch_unlock(&spinlock->lock);
espos_preempt_resume_local();
return 0;
}
/**
* @brief delete a spinlock
*/
esp_err_t espos_spinlock_del (
espos_spinlock_t *spinlock
)
{
if (!spinlock) {
return -EINVAL;
}
espos_spinlock_arch_deinit(&spinlock->lock);
return 0;
}

View file

@ -0,0 +1,267 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <assert.h>
#include "k_api.h"
#include "espos_err.h"
#include "espos_task.h"
#include "espos_scheduler.h"
/**
* @brief create a task
*/
esp_err_t espos_task_create_on_cpu (
espos_task_t *task,
const char *name,
void *arg,
espos_prio_t prio,
espos_tick_t ticks,
espos_size_t stack_size,
espos_task_entry_t entry,
espos_opt_t opt,
espos_cpu_t cpu_id
)
{
kstat_t ret;
ktask_t **ptask = (ktask_t **)task;
uint8_t auto_run;
extern void _cleanup_r(struct _reent* r);
cpu_stack_t os_task_size;
if (name == NULL) {
name = "default_task";
}
if (prio > ESPOS_TASK_PRIO_NUM)
return espos_err_map(RHINO_BEYOND_MAX_PRI);
if (ESPOS_TASK_CREATE_NORMAL == opt) {
auto_run = 1;
}
else {
auto_run = 0;
}
#if defined(ESPOS_FOR_ESP32)
os_task_size = stack_size / sizeof(cpu_stack_t);
#elif defined(ESPOS_FOR_ESP8266)
os_task_size = stack_size;
#endif
prio = RHINO_CONFIG_USER_PRI_MAX - prio;
assert(prio > 10);
if ( strcmp(name,"event_task") == 0 )
{
/* default event_task size is too small */
os_task_size += 64;
}
ret = krhino_task_dyn_create(ptask, name, arg, prio, ticks,
os_task_size, entry, auto_run);
/* The following code may open it later */
#if 0
if (ret == 0) {
struct _reent *r;
r = krhino_mm_alloc(sizeof(*r));
esp_reent_init(r);
ret = krhino_task_info_set(*ptask, 2, r);
}
#endif
return espos_err_map(ret);
}
/**
* @brief delete a task
*/
esp_err_t espos_task_del (
espos_task_t task
)
{
kstat_t ret;
ktask_t *ptask = (ktask_t *)task;
/* Be very careful here user_info[1] is used here */
#if 0
espos_sem_t *sem = ptask->user_info[1];
if (sem && *sem) {
espos_sem_del(*sem);
}
if (sem){
krhino_mm_free(sem);
}
#endif
ret = krhino_task_dyn_del(ptask);
return espos_err_map(ret);
}
/**
* @brief let current task sleep for some ticks
*/
esp_err_t espos_task_delay (
const espos_tick_t delay_ticks
)
{
kstat_t ret;
ret = krhino_task_sleep(delay_ticks);
return espos_err_map(ret);
}
/**
* @brief suspend target task
*/
esp_err_t espos_task_suspend (
espos_task_t task
)
{
kstat_t ret;
ktask_t *ptask = (ktask_t *)task;
ret = krhino_task_suspend(ptask);
return espos_err_map(ret);
}
/**
* @brief resume target task
*/
esp_err_t espos_task_resume (
espos_task_t task
)
{
kstat_t ret;
ktask_t *ptask = (ktask_t *)task;
ret = krhino_task_resume(ptask);
return espos_err_map(ret);
}
/**
* @brief yield the cpu once
*/
esp_err_t espos_task_yield(void)
{
kstat_t ret;
ret = krhino_task_yield();
return espos_err_map(ret);
}
/**
* @brief get current task handle
*/
espos_task_t espos_task_get_current(void)
{
return (espos_task_t)krhino_cur_task_get();
}
/**
* @brief get current task name point
*/
esp_err_t espos_task_get_name (
espos_task_t task,
char **pname
)
{
ktask_t *ptask = (ktask_t *)task;
*pname = (char *)ptask->task_name;
return 0;
}
/**
* @brief set task private data
*/
esp_err_t espos_task_set_private_data (
espos_task_t task,
int idx,
void *info
)
{
kstat_t ret;
ktask_t *ptask = (ktask_t *)task;;
ret = krhino_task_info_set(ptask, (size_t)idx, info);
return espos_err_map(ret);
}
/**
* @brief get task private data
*/
esp_err_t espos_task_get_private_data (
espos_task_t task,
int idx,
void **info
)
{
kstat_t ret;
ktask_t *ptask = (ktask_t *)task;;
ret = krhino_task_info_get(ptask, idx, info);
return espos_err_map(ret);
}
/**
* @brief get cpu affinity of task
*/
espos_cpu_t espos_task_get_affinity(espos_task_t task)
{
return 0;
}
size_t espos_task_prio_num(void)
{
return RHINO_CONFIG_USER_PRI_MAX + 1 - 10;
}
#if 0
struct _reent* __getreent()
{
void *info;
ktask_t *task = krhino_cur_task_get();
if (task == NULL) {
return _GLOBAL_REENT;
}
else {
krhino_task_info_get(task, 2, &info);
return info;
}
}
#endif
#if defined(ESPOS_FOR_ESP32)
struct _reent* __getreent()
{
ktask_t *task = krhino_cur_task_get();
if (task == NULL) {
return _GLOBAL_REENT;
}
else {
return _GLOBAL_REENT;;
}
}
#endif

View file

@ -0,0 +1,57 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "k_api.h"
#include "espos_err.h"
#include "espos_time.h"
/**
* @brief get current system ticks
*/
espos_tick_t espos_get_tick_count(void)
{
return (espos_tick_t)krhino_sys_tick_get();
}
/**
* @brief transform milliseconds to system ticks
*/
espos_tick_t espos_ms_to_ticks(espos_time_t ms)
{
return (ms / (1000 / RHINO_CONFIG_TICKS_PER_SECOND));
}
/**
* @brief transform system ticks to milliseconds
*/
espos_time_t espos_ticks_to_ms(espos_tick_t ticks)
{
return (ticks * (1000 / RHINO_CONFIG_TICKS_PER_SECOND));
}
void espos_add_tick_count(size_t t)
{
g_tick_count += (sys_time_t)t;
}
size_t espos_get_expected_idle_time(void)
{
ktask_t *task = krhino_cur_task_get();
if (!strcmp(task->task_name, "idle_task")) {
return task->time_slice;
}
return 0;
}

View file

@ -0,0 +1,129 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "k_api.h"
#include "espos_err.h"
#include "espos_timer.h"
#include "espos_scheduler.h"
/**
* @brief create a timer
*/
esp_err_t espos_timer_create (
espos_timer_t *timer,
const char *name,
espos_timer_cb_t cb,
void *arg,
espos_tick_t period_ticks,
espos_opt_t opt
)
{
kstat_t ret = RHINO_SUCCESS;
ktimer_t **ptimer = (ktimer_t **)timer;
tick_t round;
if (opt == ESPOS_TIMER_NO_AUTO_RUN)
round = 0;
else if (opt == ESPOS_TIMER_AUTO_RUN)
round = period_ticks;
else
return EINVAL;
ret = krhino_timer_dyn_create(ptimer, name, (timer_cb_t)cb, period_ticks,
round, arg, 0);
return espos_err_map(ret);
}
/**
* @brief start a timer
*/
esp_err_t espos_timer_start (espos_timer_t timer)
{
kstat_t ret;
ktimer_t *ptimer = (ktimer_t *)timer;
ret = krhino_timer_start(ptimer);
return espos_err_map(ret);
}
/**
* @brief stop a timer
*/
esp_err_t espos_timer_stop (
espos_timer_t timer
)
{
kstat_t ret;
ktimer_t *ptimer = (ktimer_t *)timer;
ret = krhino_timer_stop(ptimer);
return espos_err_map(ret);
}
/**
* @brief configure a timer
*/
esp_err_t espos_timer_change (
espos_timer_t timer,
espos_opt_t opt,
void *arg
)
{
kstat_t ret;
ktimer_t *ptimer = (ktimer_t *)timer;
if (ESPOS_TIMER_CHANGE_PERIOD == opt) {
espos_tick_t period = (espos_tick_t)arg;
ret = krhino_timer_change(ptimer, ptimer->init_count, period);
} else
return EINVAL;
return espos_err_map(ret);
}
/**
* @brief delete a timer
*/
esp_err_t espos_timer_del (
espos_timer_t timer
)
{
kstat_t ret;
ktimer_t *ptimer = (ktimer_t *)timer;
ret = krhino_timer_dyn_del(ptimer);
return espos_err_map(ret);
}
/**
* @brief get current timer name point
*/
esp_err_t espos_get_timer_name (
espos_timer_t timer,
char **tname
)
{
kstat_t ret;
ktimer_t *ptimer = (ktimer_t *)timer;
*tname = (char *)ptimer->name;
ret = RHINO_SUCCESS;
return espos_err_map(ret);
}

View file

@ -0,0 +1,5 @@
#
#Component Makefile
#
COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive

View file

@ -0,0 +1,12 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include <stdio.h>
#include "unity.h"
// No event group API yet

View file

@ -0,0 +1,126 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include <stdio.h>
#if 0
#include "unity.h"
#include "espos_mem.h"
#include "espos_task.h"
#include "espos_semaphore.h"
#include "espos_time.h"
static espos_sem_t sync_semaphore;
TEST_CASE("ESPOS mm api test", "[espos]")
{
uint8_t *buf;
uint8_t non_zero = 0;
uint32_t i;
// do malloc
buf = espos_malloc(1024);
memset(buf, 0xFF, 1024);
TEST_ASSERT(buf != NULL);
espos_free(buf);
// do zalloc
buf = espos_zalloc(1024);
TEST_ASSERT(buf != NULL);
for (i = 0; i < 1024; i++) {
if (buf[i] != 0) {
non_zero = 1;
break;
}
}
TEST_ASSERT(non_zero == 0);
espos_free(buf);
}
static int tryAllocMem()
{
int **mem;
int i, noAllocated, j;
mem = malloc(sizeof(int) * 1024);
if (!mem) {
return 0;
}
for (i = 0; i < 1024; i++) {
mem[i] = malloc(1024);
if (mem[i] == NULL) {
break;
}
for (j = 0; j < 1024 / 4; j++) {
mem[i][j] = (0xdeadbeef);
}
}
noAllocated = i;
for (i = 0; i < noAllocated; i++) {
for (j = 0; j < 1024 / 4; j++) {
TEST_ASSERT(mem[i][j] == (0xdeadbeef));
}
free(mem[i]);
}
free(mem);
return noAllocated;
}
static void malloc_free_task(void *p)
{
uint32_t i;
uint8_t *buf;
for (i = 0; i < 0xFFFF; i++) {
buf = espos_malloc(1024);
espos_task_delay(1);
espos_free(buf);
}
espos_sem_give(sync_semaphore);
espos_task_del(0);
}
TEST_CASE("ESPOS concurrent use of malloc free test", "[espos]")
{
uint32_t m1, m2;
espos_task_t new_task_handle;
espos_sem_create(&sync_semaphore, NULL, 2, 0);
m1 = tryAllocMem();
espos_task_create(&new_task_handle, "malloc_free_task1", NULL, 1,
0, 1024, malloc_free_task, 0);
espos_task_create(&new_task_handle, "malloc_free_task2", NULL, 1,
0, 1024, malloc_free_task, 0);
// wait task exit
espos_sem_take(sync_semaphore, ESPOS_MAX_DELAY);
espos_sem_take(sync_semaphore, ESPOS_MAX_DELAY);
espos_sem_del(sync_semaphore);
m2 = tryAllocMem();
TEST_ASSERT(m1 == m2);
}
TEST_CASE("ESPOS mm API invalid parameter test", "[espos]")
{
uint8_t *buf;
buf = espos_malloc(0xFFFFFFFF);
TEST_ASSERT(buf == NULL);
buf = espos_malloc(0);
TEST_ASSERT(buf == NULL);
buf = espos_zalloc(0xFFFFFFFF);
TEST_ASSERT(buf == NULL);
buf = espos_zalloc(0);
TEST_ASSERT(buf == NULL);
// TODO: need to check if free invalid pointer will cause exception
espos_free(NULL);
espos_free((void *)0xFFFF);
}
#endif
// To add more test cases for specific RTOS, like fragment handling

View file

@ -0,0 +1,223 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include <stdio.h>
#include "unity.h"
#include "espos_mutex.h"
#include "espos_semaphore.h"
#include "espos_task.h"
#include "espos_queue.h"
#include "test_espos_run_in_isr.h"
#define ESPOS_MUTEX_ADD_TEST_COUNT 0xFFFF
#define ESPOS_MUTEX_CREATE_INVALID ESPOS_MUTEX_NORMAL + 10
#define ESPOS_MUTEX_INVALID_HANDLE 0
static espos_sem_t sync_semaphore;
static espos_mutex_t global_mutex;
static espos_queue_t isr_queue;
static int count;
TEST_CASE("ESPOS mutex create delete test", "[espos]")
{
uint32_t i;
espos_queue_t mutex = 0;
for (i = 0; i < 1000; i++) {
if (espos_mutex_create(&mutex, ESPOS_MUTEX_NORMAL) != 0) {
TEST_ASSERT(0);
break;
}
if (espos_mutex_del(mutex) != 0) {
TEST_ASSERT(0);
break;
}
}
}
static void mutex_test_task(void *p)
{
uint32_t i;
for (i = 0; i < ESPOS_MUTEX_ADD_TEST_COUNT; i++) {
TEST_ASSERT(espos_mutex_lock(global_mutex, ESPOS_MAX_DELAY) == 0);
count++;
TEST_ASSERT(espos_mutex_unlock(global_mutex) == 0);
}
TEST_ASSERT(espos_sem_give(sync_semaphore) == 0);
TEST_ASSERT(espos_task_del(0) == 0);
}
TEST_CASE("ESPOS mutex lock unlock test", "[espos]")
{
espos_task_t new_task_handle;
TEST_ASSERT(espos_mutex_create(&global_mutex, ESPOS_MUTEX_NORMAL) == 0);
TEST_ASSERT(espos_sem_create(&sync_semaphore, 2, 0) == 0);
count = 0;
TEST_ASSERT(espos_task_create(&new_task_handle, "mutex_test_task1", NULL, 1,
0, 2048, mutex_test_task, 0) == 0);
TEST_ASSERT(espos_task_create(&new_task_handle, "mutex_test_task2", NULL, 1,
0, 2048, mutex_test_task, 0) == 0);
// wait task exit
TEST_ASSERT(espos_sem_take(sync_semaphore, ESPOS_MAX_DELAY) == 0);
TEST_ASSERT(espos_sem_take(sync_semaphore, ESPOS_MAX_DELAY) == 0);
TEST_ASSERT(espos_sem_del(sync_semaphore) == 0);
TEST_ASSERT(count == (ESPOS_MUTEX_ADD_TEST_COUNT << 1));
TEST_ASSERT(espos_mutex_del(global_mutex) == 0);
}
static void mutex_lock_test_task(void *p)
{
TEST_ASSERT(espos_mutex_lock(global_mutex, ESPOS_MAX_DELAY) == 0);
TEST_ASSERT(espos_mutex_unlock(global_mutex) == 0);
TEST_ASSERT(espos_sem_give(sync_semaphore) == 0);
TEST_ASSERT(espos_task_del(0) == 0);
}
TEST_CASE("ESPOS delete mutex in use test", "[espos]")
{
// TODO: this case is RTOS dependent
espos_task_t new_task_handle;
TEST_ASSERT(espos_mutex_create(&global_mutex, ESPOS_MUTEX_NORMAL) == 0);
TEST_ASSERT(espos_sem_create(&sync_semaphore, 1, 0) == 0);
TEST_ASSERT(espos_mutex_lock(global_mutex, ESPOS_MAX_DELAY) == 0);
TEST_ASSERT(espos_task_create(&new_task_handle, "mutex_lock_test_task", NULL, ESPOS_TASK_PRIO_MAX,
0, 2048, mutex_lock_test_task, 0) == 0);
TEST_ASSERT(espos_mutex_unlock(global_mutex) == 0);
// wait task exit
TEST_ASSERT(espos_sem_take(sync_semaphore, ESPOS_MAX_DELAY) == 0);
TEST_ASSERT(espos_mutex_del(global_mutex) == 0);
TEST_ASSERT(espos_sem_del(sync_semaphore) == 0);
}
static void mutex_unlock_test_task(void *p)
{
TEST_ASSERT(espos_mutex_unlock(global_mutex) == -EPERM);
TEST_ASSERT(espos_sem_give(sync_semaphore) == 0);
TEST_ASSERT(espos_task_del(0) == 0);
}
TEST_CASE("ESPOS mutex unlock by different task test", "[espos]")
{
espos_task_t new_task_handle;
TEST_ASSERT(espos_mutex_create(&global_mutex, ESPOS_MUTEX_NORMAL) == 0);
TEST_ASSERT(espos_sem_create(&sync_semaphore, 1, 0) == 0);
TEST_ASSERT(espos_mutex_lock(global_mutex, ESPOS_MAX_DELAY) == 0);
TEST_ASSERT(espos_task_create(&new_task_handle, "mutex_unlock_test_task", NULL, ESPOS_TASK_PRIO_MAX,
0, 1024, mutex_unlock_test_task, 0) == 0);
TEST_ASSERT(espos_sem_take(sync_semaphore, ESPOS_MAX_DELAY) == 0);
TEST_ASSERT(espos_mutex_del(global_mutex) == 0);
TEST_ASSERT(espos_sem_del(sync_semaphore) == 0);
}
TEST_CASE("ESPOS mutex lock timeout test", "[espos]")
{
espos_queue_t mutex;
TEST_ASSERT(espos_mutex_create(&mutex, ESPOS_MUTEX_NORMAL) == 0);
TEST_ASSERT(espos_mutex_lock(mutex, ESPOS_NO_DELAY) == 0);
TEST_ASSERT(espos_mutex_lock(mutex, ESPOS_NO_DELAY) == -ETIMEDOUT);
TEST_ASSERT(espos_mutex_del(mutex) == 0);
}
static void mutex_lock_hold_test_task(void *p)
{
espos_sem_t sem = (espos_sem_t) p;
TEST_ASSERT(espos_mutex_lock(global_mutex, ESPOS_MAX_DELAY) == 0);
TEST_ASSERT(espos_sem_give(sync_semaphore) == 0);
TEST_ASSERT(espos_sem_take(sem, ESPOS_MAX_DELAY) == 0);
TEST_ASSERT(espos_sem_del(sem) == 0);
TEST_ASSERT(espos_task_del(0) == 0);
}
TEST_CASE("ESPOS mutex lock get holder test", "[espos]")
{
espos_task_t new_task_handle;
espos_sem_t sem;
TEST_ASSERT(espos_mutex_create(&global_mutex, ESPOS_MUTEX_NORMAL) == 0);
TEST_ASSERT(espos_sem_create(&sync_semaphore, 1, 0) == 0);
TEST_ASSERT(espos_sem_create(&sem, 1, 0) == 0);
TEST_ASSERT(espos_mutex_lock(global_mutex, ESPOS_NO_DELAY) == 0);
TEST_ASSERT(espos_mutex_get_holder(global_mutex) == espos_task_get_current());
TEST_ASSERT(espos_mutex_unlock(global_mutex) == 0);
TEST_ASSERT(espos_task_create(&new_task_handle, "mutex_lock_hold_test_task", (void *)sem, ESPOS_TASK_PRIO_MAX,
0, 2048, mutex_lock_hold_test_task, 0) == 0);
TEST_ASSERT(espos_sem_take(sync_semaphore, ESPOS_MAX_DELAY) == 0);
TEST_ASSERT(espos_mutex_get_holder(global_mutex) == new_task_handle);
TEST_ASSERT(espos_sem_give(sem) == 0);
TEST_ASSERT(espos_mutex_del(global_mutex) == 0);
}
TEST_CASE("ESPOS mutex recursive lock unlock test", "[espos]")
{
//TODO: to add this case if recursive lock is supported
}
static void IRAM_ATTR mutex_isr_test(void)
{
uint8_t msg = 0;
if (espos_mutex_lock(global_mutex, 0) != -EINTR
|| espos_mutex_unlock(global_mutex) != -EINTR) {
msg = 1;
}
TEST_ASSERT(espos_queue_send(isr_queue, &msg, ESPOS_MAX_DELAY) == 0);
}
TEST_CASE("ESPOS use mutex in ISR test", "[espos]")
{
uint8_t msg;
TEST_ASSERT(espos_queue_create(&isr_queue, 1, 1) == 0);
TEST_ASSERT(espos_mutex_create(&global_mutex, ESPOS_MUTEX_NORMAL) == 0);
espos_test_run_in_isr(mutex_isr_test);
TEST_ASSERT(espos_queue_recv(isr_queue, &msg, ESPOS_MAX_DELAY) == 0);
TEST_ASSERT(msg == 0);
TEST_ASSERT(espos_mutex_del(global_mutex) == 0);
TEST_ASSERT(espos_queue_del(isr_queue) == 0);
}
TEST_CASE("ESPOS mutex API invalid parameter test", "[espos]")
{
espos_queue_t mutex;
TEST_ASSERT(espos_mutex_create(NULL, ESPOS_MUTEX_NORMAL) == -EINVAL);
TEST_ASSERT(espos_mutex_create(&mutex, ESPOS_MUTEX_CREATE_INVALID) == -EINVAL);
TEST_ASSERT(espos_mutex_lock(ESPOS_MUTEX_INVALID_HANDLE, 0) == -EINVAL);
TEST_ASSERT(espos_mutex_unlock(ESPOS_MUTEX_INVALID_HANDLE) == -EINVAL);
TEST_ASSERT(espos_mutex_del(ESPOS_MUTEX_INVALID_HANDLE) == -EINVAL);
}

View file

@ -0,0 +1,58 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include <stdio.h>
#include "unity.h"
#include "espos_include.h"
uint32_t tick;
// memory management
TEST_CASE("ESPOS malloc free performance", "[espos]")
{
}
// scheduler
TEST_CASE("ESPOS task context switch performance", "[espos]")
{
}
TEST_CASE("ESPOS isr context switch performance", "[espos]")
{
}
TEST_CASE("ESPOS critical section performance", "[espos]")
{
}
// spin lock
TEST_CASE("ESPOS spin lock performance", "[espos]")
{
}
// queue
TEST_CASE("ESPOS queue send recv performance", "[espos]")
{
}
// semaphore
TEST_CASE("ESPOS semaphore performance", "[espos]")
{
}
// timer
TEST_CASE("ESPOS timer accuracy performance", "[espos]")
{
}

View file

@ -0,0 +1,248 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include <stdio.h>
#include "unity.h"
#include "espos_queue.h"
#include "espos_task.h"
#include "espos_semaphore.h"
#include "espos_time.h"
#include "test_espos_run_in_isr.h"
#define ESPOS_QUEUE_INVALID_OPT (ESPOS_QUEUE_SEND_OPT_NORMAL+10)
#define ESPOS_QUEUE_INVALID_POS (ESPOS_QUEUE_SEND_BACK+10)
#define ESPOS_QUEUE_INVALID_HANDLE 0
static espos_sem_t sync_semaphore;
static espos_queue_t global_queue;
static espos_queue_t isr_queue;
TEST_CASE("ESPOS queue create delete", "[espos]")
{
uint32_t i;
espos_queue_t queue = ESPOS_QUEUE_INVALID_HANDLE;
for (i = 0; i < 1000; i++) {
if (espos_queue_create(&queue, 16, 50) != 0) {
TEST_ASSERT(0);
break;
}
if (espos_queue_del(queue) != 0) {
TEST_ASSERT(0);
break;
}
}
}
static void queue_send_task(void *p)
{
uint32_t msg = 0xF1F2F3F4;
uint8_t *received = (uint8_t *) p;
TEST_ASSERT(espos_queue_send(global_queue, &msg, ESPOS_MAX_DELAY) == 0);
// should switch to recv task and then switch back
TEST_ASSERT(*received == 1);
TEST_ASSERT(espos_sem_give(sync_semaphore) == 0);
TEST_ASSERT(espos_task_del(0) == 0);
}
static void queue_recv_task(void *p)
{
uint32_t msg;
uint8_t *received = (uint8_t *) p;
TEST_ASSERT(espos_queue_recv(global_queue, &msg, ESPOS_MAX_DELAY) == 0);
// check msg value
TEST_ASSERT(msg = 0xF1F2F3F4);
// set received flag
*received = 1;
TEST_ASSERT(espos_sem_give(sync_semaphore) == 0);
TEST_ASSERT(espos_task_del(0) == 0);
}
TEST_CASE("ESPOS queue send receive", "[espos]")
{
espos_task_t new_task_handle;
uint8_t received = 0;
TEST_ASSERT(espos_queue_create(&global_queue, 4, 10) == 0);
TEST_ASSERT(espos_sem_create(&sync_semaphore, 2, 0) == 0);
// recv task with higher priority, create recv task first
TEST_ASSERT(espos_task_create_on_cpu(&new_task_handle, "queue_recv_task", &received, 2,
0, 1024, queue_recv_task, 0, 0) == 0);
TEST_ASSERT(espos_task_create_on_cpu(&new_task_handle, "queue_send_task", &received, 1,
0, 1024, queue_send_task, 0, 0) == 0);
// wait task exit
TEST_ASSERT(espos_sem_take(sync_semaphore, ESPOS_MAX_DELAY) == 0);
TEST_ASSERT(espos_sem_take(sync_semaphore, ESPOS_MAX_DELAY) == 0);
TEST_ASSERT(espos_sem_del(sync_semaphore) == 0);
TEST_ASSERT(espos_queue_del(global_queue) == 0);
}
TEST_CASE("ESPOS queue flush", "[espos]")
{
uint32_t msg = 0;
espos_queue_t queue = ESPOS_QUEUE_INVALID_HANDLE;
TEST_ASSERT(espos_queue_create(&queue, 4, 10) == 0);
TEST_ASSERT(espos_queue_send_generic(queue, &msg, ESPOS_MAX_DELAY,
ESPOS_QUEUE_SEND_BACK, ESPOS_QUEUE_SEND_OPT_NORMAL) == 0);
TEST_ASSERT(espos_queue_send_generic(queue, &msg, ESPOS_MAX_DELAY,
ESPOS_QUEUE_SEND_BACK, ESPOS_QUEUE_SEND_OPT_NORMAL) == 0);
TEST_ASSERT(espos_queue_flush(queue) == 0);
TEST_ASSERT(espos_queue_msg_waiting(queue) == 0);
TEST_ASSERT(espos_queue_flush(queue) == 0);
TEST_ASSERT(espos_queue_del(queue) == 0);
}
TEST_CASE("ESPOS queue send front/end", "[espos]")
{
uint32_t msg;
espos_queue_t queue = ESPOS_QUEUE_INVALID_HANDLE;
TEST_ASSERT(espos_queue_create(&queue, 4, 10) == 0);
msg = 0x01;
TEST_ASSERT(espos_queue_send_generic(queue, &msg, ESPOS_MAX_DELAY,
ESPOS_QUEUE_SEND_BACK, ESPOS_QUEUE_SEND_OPT_NORMAL) == 0);
msg = 0x02;
TEST_ASSERT(espos_queue_send_generic(queue, &msg, ESPOS_MAX_DELAY,
ESPOS_QUEUE_SEND_FRONT, ESPOS_QUEUE_SEND_OPT_NORMAL) == 0);
msg = 0x03;
TEST_ASSERT(espos_queue_send_generic(queue, &msg, ESPOS_MAX_DELAY,
ESPOS_QUEUE_SEND_BACK, ESPOS_QUEUE_SEND_OPT_NORMAL) == 0);
TEST_ASSERT(espos_queue_recv(queue, &msg, ESPOS_MAX_DELAY) == 0);
TEST_ASSERT(msg == 0x02);
TEST_ASSERT(espos_queue_recv(queue, &msg, ESPOS_MAX_DELAY) == 0);
TEST_ASSERT(msg == 0x01);
TEST_ASSERT(espos_queue_recv(queue, &msg, ESPOS_MAX_DELAY) == 0);
TEST_ASSERT(msg == 0x03);
TEST_ASSERT(espos_queue_del(queue) == 0);
}
TEST_CASE("ESPOS queue timeout test", "[espos]")
{
uint32_t msg;
espos_queue_t queue = ESPOS_QUEUE_INVALID_HANDLE;
TEST_ASSERT(espos_queue_create(&queue, 4, 1) == 0);
TEST_ASSERT(espos_queue_send_generic(queue, &msg, 0,
ESPOS_QUEUE_SEND_BACK, ESPOS_QUEUE_SEND_OPT_NORMAL) == 0);
TEST_ASSERT(espos_queue_send_generic(queue, &msg, 0,
ESPOS_QUEUE_SEND_BACK, ESPOS_QUEUE_SEND_OPT_NORMAL) == -ETIMEDOUT);
TEST_ASSERT(espos_queue_recv(queue, &msg, 0) == 0);
TEST_ASSERT(espos_queue_recv(queue, &msg, 0) == -ETIMEDOUT);
TEST_ASSERT(espos_queue_del(queue) == 0);
}
TEST_CASE("ESPOS queue create/delete API invalid param test", "[espos]")
{
espos_queue_t queue = ESPOS_QUEUE_INVALID_HANDLE;
TEST_ASSERT(espos_queue_create(&queue, 0xFFFF, 0xFFFFFF) == -ENOMEM);
TEST_ASSERT(espos_queue_del(queue) == -EINVAL);
TEST_ASSERT(espos_queue_create(NULL, 4, 10) == -EINVAL);
TEST_ASSERT(espos_queue_create(&queue, 0, 10) == -EINVAL);
TEST_ASSERT(espos_queue_create(&queue, 4, 0) == -EINVAL);
TEST_ASSERT(espos_queue_del(ESPOS_QUEUE_INVALID_HANDLE) == -EINVAL)
}
TEST_CASE("ESPOS queue send API invalid param test", "[espos]")
{
uint32_t msg;
espos_queue_t queue = ESPOS_QUEUE_INVALID_HANDLE;
TEST_ASSERT(espos_queue_create(&queue, 4, 10) == 0);
TEST_ASSERT(espos_queue_send_generic(queue, NULL, 0,
ESPOS_QUEUE_SEND_BACK, ESPOS_QUEUE_SEND_OPT_NORMAL) == -EINVAL);
TEST_ASSERT(espos_queue_send_generic(queue, &msg, 0,
ESPOS_QUEUE_INVALID_POS, ESPOS_QUEUE_SEND_OPT_NORMAL) == -EINVAL);
TEST_ASSERT(espos_queue_send_generic(queue, &msg, 0,
ESPOS_QUEUE_SEND_BACK, ESPOS_QUEUE_INVALID_OPT) == -EINVAL);
TEST_ASSERT(espos_queue_send_generic(ESPOS_QUEUE_INVALID_HANDLE, &msg, 0,
ESPOS_QUEUE_SEND_BACK, ESPOS_QUEUE_INVALID_OPT) == -EINVAL);
TEST_ASSERT(espos_queue_del(queue) == 0);
}
TEST_CASE("ESPOS queue recv/wait/flush API invalid param test", "[espos]")
{
uint32_t msg;
espos_queue_t queue = ESPOS_QUEUE_INVALID_HANDLE;
TEST_ASSERT(espos_queue_create(&queue, 4, 10) == 0);
TEST_ASSERT(espos_queue_recv(ESPOS_QUEUE_INVALID_HANDLE, &msg, 0) == -EINVAL);
TEST_ASSERT(espos_queue_recv(queue, NULL, 0) == -EINVAL);
//TODO: don't konw what could happen if passing invalid queue handle
TEST_ASSERT(espos_queue_msg_waiting(ESPOS_QUEUE_INVALID_HANDLE) == 0);
TEST_ASSERT(espos_queue_flush(ESPOS_QUEUE_INVALID_HANDLE) == -EINVAL);
TEST_ASSERT(espos_queue_del(queue) == 0);
}
TEST_CASE("ESPOS deleting a queue in use test", "[espos]")
{
// TODO: this case is RTOS dependent
espos_task_t new_task_handle;
uint8_t received = 0;
uint32_t msg = 0xF1F2F3F4;
TEST_ASSERT(espos_queue_create(&global_queue, 4, 1) == 0);
TEST_ASSERT(espos_sem_create(&sync_semaphore, 1, 0) == 0);
TEST_ASSERT(espos_task_create_on_cpu(&new_task_handle, "queue_recv_task", &received, 1,
0, 1024, queue_recv_task, 0, 0) == 0);
TEST_ASSERT(espos_queue_send(global_queue, &msg, ESPOS_MAX_DELAY) == 0);
// wait task exit
TEST_ASSERT(espos_sem_take(sync_semaphore, ESPOS_MAX_DELAY) == 0);
TEST_ASSERT(received == 1);
TEST_ASSERT(espos_sem_del(sync_semaphore) == 0);
TEST_ASSERT(espos_queue_del(global_queue) == 0);
}
static void IRAM_ATTR queue_isr_test(void)
{
uint8_t msg = 0;
TEST_ASSERT(espos_queue_send_generic(isr_queue, &msg, ESPOS_MAX_DELAY,
ESPOS_QUEUE_SEND_BACK, ESPOS_QUEUE_SEND_OPT_NORMAL) == 0);
}
TEST_CASE("ESPOS send to queue in ISR test", "[espos]")
{
uint8_t msg;
espos_queue_create(&isr_queue, 1, 1);
espos_test_run_in_isr(queue_isr_test);
espos_queue_recv(isr_queue, &msg, ESPOS_MAX_DELAY);
TEST_ASSERT(msg == 0);
espos_queue_del(isr_queue);
}

View file

@ -0,0 +1,62 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include <stdio.h>
#include "esp_types.h"
#include "rom/ets_sys.h"
#include "espos_task.h"
#include "espos_scheduler.h"
#include "soc/timer_group_struct.h"
#include "driver/periph_ctrl.h"
#include "driver/timer.h"
#include "test_espos_run_in_isr.h"
#define TIMER_INTR_SEL TIMER_INTR_LEVEL /*!< Timer level interrupt */
#define TIMER_GROUP TIMER_GROUP_0 /*!< Test on timer group 0 */
#define TIMER_DIVIDER 16 /*!< Hardware timer clock divider */
static void IRAM_ATTR timer_isr(void *p)
{
espos_test_isr_routine routine = (espos_test_isr_routine) p;
espos_isr_enter();
TIMERG0.int_clr_timers.t0 = 1;
routine();
espos_isr_exit();
}
void espos_test_run_in_isr(espos_test_isr_routine routine)
{
int timer_group = TIMER_GROUP_0;
int timer_idx = TIMER_0;
timer_config_t config;
config.alarm_en = 1;
config.auto_reload = 0;
config.counter_dir = TIMER_COUNT_UP;
config.divider = TIMER_DIVIDER;
config.intr_type = TIMER_INTR_SEL;
config.counter_en = TIMER_PAUSE;
/*Configure timer*/
timer_init(timer_group, timer_idx, &config);
/*Stop timer counter*/
timer_pause(timer_group, timer_idx);
/*Load counter value */
timer_set_counter_value(timer_group, timer_idx, 0x00000000ULL);
/*Set alarm value*/
timer_set_alarm_value(timer_group, timer_idx, 1);
timer_set_auto_reload(timer_group, timer_idx, TIMER_AUTORELOAD_DIS);
/*Enable timer interrupt*/
timer_enable_intr(timer_group, timer_idx);
/*Set ISR handler*/
timer_isr_register(timer_group, timer_idx, timer_isr,
(void *) routine, ESP_INTR_FLAG_IRAM, NULL);
/*Start timer counter*/
timer_start(timer_group, timer_idx);
}

View file

@ -0,0 +1,27 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#ifndef _TEST_ESPOS_RUN_IN_ISR_H_
#define _TEST_ESPOS_RUN_IN_ISR_H_
#include "espos_types.h"
#include "esp_attr.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef void (*espos_test_isr_routine)(void);
/*
* @brief run handler in timer isr
*/
void espos_test_run_in_isr(espos_test_isr_routine routine);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,52 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include <stdio.h>
#include "unity.h"
#include "espos_task.h"
#include "espos_scheduler.h"
#include "espos_spinlock.h"
#include "test_espos_run_in_isr.h"
#define ESPOS_SCHEDULER_INVALID_HANDLE -1
uint32_t count;
TEST_CASE("ESPOS scheduler critical section test", "[espos]")
{
//TODO: how to test critical section?
}
static void count_task(void *p)
{
count ++;
TEST_ASSERT(espos_task_del(0) == 0);
}
TEST_CASE("ESPOS scheduler preempt suspend resume test", "[espos]")
{
espos_task_t new_task_handle;
count = 0;
TEST_ASSERT(espos_task_create_on_cpu(&new_task_handle, "count_task", NULL, 10,
0, 1024, count_task, 0, 0) == 0);
TEST_ASSERT(espos_task_create_on_cpu(&new_task_handle, "count_task", NULL, 10,
0, 1024, count_task, 0, 0) == 0);
TEST_ASSERT(count == 2);
count = 0;
TEST_ASSERT(espos_preempt_suspend_local() == 0);
TEST_ASSERT(espos_task_create_on_cpu(&new_task_handle, "count_task", NULL, 10,
0, 1024, count_task, 0, 0) == 0);
TEST_ASSERT(espos_task_create_on_cpu(&new_task_handle, "count_task", NULL, 10,
0, 1024, count_task, 0, 0) == 0);
TEST_ASSERT(count == 0);
TEST_ASSERT(espos_preempt_resume_local() == 0);
}

View file

@ -0,0 +1,174 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include <stdio.h>
#include "unity.h"
#include "espos_semaphore.h"
#include "espos_queue.h"
#include "espos_task.h"
#include "espos_time.h"
#include "driver/timer.h"
#include "test_espos_run_in_isr.h"
#define ESPOS_SEM_INVALID_HANDLE 0
static espos_sem_t sync_semaphore;
static espos_sem_t global_sema;
static espos_queue_t isr_queue;
TEST_CASE("ESPOS semaphore create delete test", "[espos]")
{
uint32_t i;
espos_sem_t sem;
for (i = 0; i < 1000; i++) {
if (espos_sem_create(&sem, 1, 1) != 0) {
TEST_ASSERT(0);
break;
}
if (espos_sem_del(sem) != 0) {
TEST_ASSERT(0);
break;
}
}
}
static void sema_give_task(void *p)
{
uint8_t *taken = (uint8_t *) p;
TEST_ASSERT(espos_sem_give(global_sema) == 0);
// should switch to recv task and then switch back
TEST_ASSERT(*taken == 1);
espos_sem_give(sync_semaphore);
espos_task_del(0);
}
static void sema_take_task(void *p)
{
uint8_t *taken = (uint8_t *) p;
TEST_ASSERT(espos_sem_take(global_sema, ESPOS_MAX_DELAY) == 0);
// set taken flag
*taken = 1;
espos_sem_give(sync_semaphore);
espos_task_del(0);
}
TEST_CASE("ESPOS semaphore take give test", "[espos]")
{
espos_task_t new_task_handle;
uint8_t taken = 0;
TEST_ASSERT(espos_sem_create(&global_sema, 1, 0) == 0);
espos_sem_create(&sync_semaphore, 2, 0);
// recv task with higher priority, create recv task first
espos_task_create_on_cpu(&new_task_handle, "sema_take_task", &taken, 2,
0, 1024, sema_take_task, 0, 0);
espos_task_create_on_cpu(&new_task_handle, "sema_give_task", &taken, 1,
0, 1024, sema_give_task, 0, 0);
// wait task exit
espos_sem_take(sync_semaphore, ESPOS_MAX_DELAY);
espos_sem_take(sync_semaphore, ESPOS_MAX_DELAY);
espos_sem_del(sync_semaphore);
TEST_ASSERT(espos_sem_del(global_sema) == 0);
}
TEST_CASE("ESPOS semaphore count test", "[espos]")
{
uint8_t i;
espos_sem_t sem;
TEST_ASSERT(espos_sem_create(&sem, 5, 1) == 0);
TEST_ASSERT(espos_sem_take(sem, ESPOS_MAX_DELAY) == 0);
TEST_ASSERT(espos_sem_trytake(sem) == -ETIMEDOUT);
for (i = 0; i < 5; i++) {
TEST_ASSERT(espos_sem_give(sem) == 0);
}
TEST_ASSERT(espos_sem_give(sem) == -EAGAIN);
for (i = 0; i < 5; i++) {
TEST_ASSERT(espos_sem_trytake(sem) == 0);
}
TEST_ASSERT(espos_sem_del(sem) == 0);
}
static void IRAM_ATTR semaphore_isr_test(void)
{
uint8_t msg = 0;
espos_sem_t sem;
if (espos_sem_create(&sem, 2, 1) != -EINTR) {
msg = 1;
}
if (espos_sem_take(global_sema, 0) != 0
|| espos_sem_give(global_sema) != 0
|| espos_sem_del(global_sema) != -EINTR) {
msg = 1;
}
espos_queue_send(isr_queue, &msg, ESPOS_MAX_DELAY);
}
TEST_CASE("ESPOS use semaphore in ISR test", "[espos]")
{
uint8_t msg;
espos_queue_create(&isr_queue, 1, 1);
TEST_ASSERT(espos_sem_create(&global_sema, 2, 1) == 0);
espos_test_run_in_isr(semaphore_isr_test);
espos_queue_recv(isr_queue, &msg, ESPOS_MAX_DELAY);
TEST_ASSERT(msg == 0);
espos_sem_del(global_sema);
espos_queue_del(isr_queue);
}
TEST_CASE("ESPOS deleting a semaphore in use test", "[espos]")
{
// TODO: this case is RTOS dependent
espos_task_t new_task_handle;
uint8_t taken = 0;
TEST_ASSERT(espos_sem_create(&global_sema, 1, 0) == 0);
espos_sem_create(&sync_semaphore, 1, 0);
espos_task_create_on_cpu(&new_task_handle, "sema_take_task", &taken, ESPOS_TASK_PRIO_MAX,
0, 1024, sema_take_task, 0, 0);
espos_sem_give(global_sema);
// wait task exit
espos_sem_take(sync_semaphore, ESPOS_MAX_DELAY);
TEST_ASSERT(taken == 1);
espos_sem_del(sync_semaphore);
TEST_ASSERT(espos_sem_del(global_sema) == 0);
}
TEST_CASE("ESPOS semaphore API invalid parameter test", "[espos]")
{
TEST_ASSERT(espos_sem_create(NULL, 5, 1) == -EINVAL);
TEST_ASSERT(espos_sem_take(ESPOS_SEM_INVALID_HANDLE, ESPOS_MAX_DELAY) == -EINVAL);
TEST_ASSERT(espos_sem_give(ESPOS_SEM_INVALID_HANDLE) == -EINVAL);
TEST_ASSERT(espos_sem_del(ESPOS_SEM_INVALID_HANDLE) == -EINVAL);
}

View file

@ -0,0 +1,119 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include <stdio.h>
#include "unity.h"
#include "espos_spinlock.h"
#include "espos_task.h"
#include "espos_queue.h"
#include "espos_semaphore.h"
#include "test_espos_run_in_isr.h"
#define ESPOS_SPINLOCK_INVALID_HANDLE NULL
#define ESPOS_SPINLOCK_ADD_TEST_COUNT 0xFFFF
static espos_sem_t sync_semaphore;
static espos_queue_t isr_queue;
static espos_spinlock_t global_spinlock;
static int count;
TEST_CASE("ESPOS spinlock create delete test", "[espos]")
{
espos_spinlock_t spinlock;
for (int i = 0; i < 1000; i++) {
if (espos_spinlock_create(&spinlock) != 0) {
TEST_ASSERT(0);
}
if (espos_spinlock_del(&spinlock) != 0) {
TEST_ASSERT(0);
}
}
}
static void spinlock_test_task(void *p)
{
for (int i = 0; i < ESPOS_SPINLOCK_ADD_TEST_COUNT; i++) {
TEST_ASSERT(espos_spinlock_lock(&global_spinlock) == 0);
count++;
TEST_ASSERT(espos_spinlock_unlock(&global_spinlock) == 0);
}
TEST_ASSERT(espos_sem_give(sync_semaphore) == 0);
TEST_ASSERT(espos_task_del(0) == 0);
}
TEST_CASE("ESPOS spinlock lock unlock test", "[espos]")
{
espos_task_t new_task_handle;
TEST_ASSERT(espos_spinlock_create(&global_spinlock) == 0);
TEST_ASSERT(espos_sem_create(&sync_semaphore, 2, 0) == 0);
count = 0;
TEST_ASSERT(espos_task_create(&new_task_handle, "spinlock_test_task1", NULL, 1,
0, 1024, spinlock_test_task, 0) == 0);
TEST_ASSERT(espos_task_create(&new_task_handle, "spinlock_test_task2", NULL, 1,
0, 1024, spinlock_test_task, 0) == 0);
// wait task exit
TEST_ASSERT(espos_sem_take(sync_semaphore, ESPOS_MAX_DELAY) == 0);
TEST_ASSERT(espos_sem_take(sync_semaphore, ESPOS_MAX_DELAY) == 0);
TEST_ASSERT(espos_sem_del(sync_semaphore) == 0);
TEST_ASSERT(count == (ESPOS_SPINLOCK_ADD_TEST_COUNT << 1));
TEST_ASSERT(espos_spinlock_del(&global_spinlock) == 0);
}
TEST_CASE("ESPOS spinlock trylock test", "[espos]")
{
espos_spinlock_t spinlock;
TEST_ASSERT(espos_spinlock_create(&spinlock) == 0);
TEST_ASSERT(espos_spinlock_trylock(&spinlock) == 0);
TEST_ASSERT(espos_spinlock_trylock(&spinlock) == -EAGAIN);
TEST_ASSERT(espos_spinlock_unlock(&spinlock) == 0);
TEST_ASSERT(espos_spinlock_del(&spinlock) == 0);
}
static void IRAM_ATTR spinlock_isr_test(void)
{
uint8_t msg = 0;
if (espos_spinlock_lock(&global_spinlock) != 0
|| espos_spinlock_unlock(&global_spinlock) != 0) {
msg = 1;
}
TEST_ASSERT(espos_queue_send(isr_queue, &msg, ESPOS_MAX_DELAY) == 0);
}
TEST_CASE("ESPOS spinlock use in ISR test", "[espos]")
{
uint8_t msg;
TEST_ASSERT(espos_queue_create(&isr_queue, 1, 1) == 0);
TEST_ASSERT(espos_spinlock_create(&global_spinlock) == 0);
espos_test_run_in_isr(spinlock_isr_test);
TEST_ASSERT(espos_queue_recv(isr_queue, &msg, ESPOS_MAX_DELAY) == 0);
TEST_ASSERT(msg == 0);
TEST_ASSERT(espos_queue_del(isr_queue) == 0);
TEST_ASSERT(espos_spinlock_del(&global_spinlock) == 0);
}
TEST_CASE("ESPOS spinlock API invalid parameter test", "[espos]")
{
TEST_ASSERT(espos_spinlock_create(NULL) == -EINVAL);
TEST_ASSERT(espos_spinlock_lock(NULL) == -EINVAL);
TEST_ASSERT(espos_spinlock_trylock(NULL) == -EINVAL);
TEST_ASSERT(espos_spinlock_unlock(NULL) == -EINVAL);
TEST_ASSERT(espos_spinlock_del(ESPOS_SPINLOCK_INVALID_HANDLE) == -EINVAL);
}

View file

@ -0,0 +1,73 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include <stdio.h>
#include "unity.h"
#include "espos_task.h"
uint32_t count;
TEST_CASE("ESPOS task SMP create delete test", "[espos]")
{
}
TEST_CASE("ESPOS task multi-core test", "[espos]")
{
}
TEST_CASE("ESPOS task yield test", "[espos]")
{
}
TEST_CASE("ESPOS task exit test", "[espos]")
{
}
TEST_CASE("ESPOS task suspend resume test", "[espos]")
{
}
TEST_CASE("ESPOS task sleep test", "[espos]")
{
}
TEST_CASE("ESPOS task private data test", "[espos]")
{
}
TEST_CASE("ESPOS task priority test", "[espos]")
{
}
TEST_CASE("ESPOS task time slice test", "[espos]")
{
}
TEST_CASE("ESPOS task option test", "[espos]")
{
}
TEST_CASE("ESPOS task stack size test", "[espos]")
{
}
TEST_CASE("ESPOS task API misc param test", "[espos]")
{
}

View file

@ -0,0 +1,30 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include <stdio.h>
#include "unity.h"
#include "espos_time.h"
#include "espos_task.h"
#define _ESPOS_TIME_DELAY_TICK 100
#define _ESPOS_TIME_DELAY_TICK_TH 120
TEST_CASE("ESPOS get tick test", "[espos]")
{
espos_tick_t tick1, tick2;
tick1 = espos_get_tick_count();
espos_task_delay(_ESPOS_TIME_DELAY_TICK);
tick2 = espos_get_tick_count();
TEST_ASSERT(tick2 - tick1 >= _ESPOS_TIME_DELAY_TICK);
TEST_ASSERT(tick2 - tick1 < _ESPOS_TIME_DELAY_TICK_TH);
}
TEST_CASE("ESPOS tick ms convert test", "[espos]")
{
TEST_ASSERT(espos_ticks_to_ms(espos_ms_to_ticks(10)) == 10);
TEST_ASSERT(espos_ms_to_ticks(0xFFFFFFFF) == 0xFFFFFFFF / 10);
}

View file

@ -0,0 +1,162 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include <stdio.h>
#include "unity.h"
#include "espos_timer.h"
#include "espos_semaphore.h"
#define ESPOS_TIMER_INVALID_OPT 0xFF
#define ESPOS_TIMER_INVALID_HANDLE 0
#define ESPOS_TIMER_CHANGE_OPT_INVALID 5
static const char *TIMER_NAME = "timer_test";
static espos_sem_t sync_sema;
static espos_timer_t global_timer;
static int count;
static void espos_test_timer_dummy_cb(espos_timer_t timer, void *arg)
{
}
TEST_CASE("ESPOS timer create delete test", "[espos]")
{
uint32_t i;
espos_timer_t timer = ESPOS_TIMER_INVALID_HANDLE;
for (i = 0; i < 1000; i++) {
if (espos_timer_create(&timer, TIMER_NAME, espos_test_timer_dummy_cb, NULL,
1, ESPOS_TIMER_NO_AUTO_RUN) != 0) {
TEST_ASSERT(0);
break;
}
if (espos_timer_del(timer) != 0) {
TEST_ASSERT(0);
break;
}
}
}
static void espos_test_timer_cb(espos_timer_t timer, void *arg)
{
TEST_ASSERT(global_timer == timer);
TEST_ASSERT(arg == NULL);
count++;
TEST_ASSERT(espos_sem_give(sync_sema) == 0);
}
TEST_CASE("ESPOS timer no auto run test", "[espos]")
{
uint32_t i;
TEST_ASSERT(espos_sem_create(&sync_sema, 1, 0) == 0);
TEST_ASSERT(espos_timer_create(&global_timer, TIMER_NAME, espos_test_timer_cb, NULL,
espos_ms_to_ticks(20), ESPOS_TIMER_NO_AUTO_RUN) == 0);
count = 0;
for (i = 0; i < 100; i++) {
TEST_ASSERT(espos_timer_start(global_timer) == 0);
TEST_ASSERT(espos_sem_take(sync_sema, ESPOS_MAX_DELAY) == 0);
}
TEST_ASSERT(count == 100);
TEST_ASSERT(espos_sem_del(sync_sema) == 0);
TEST_ASSERT(espos_timer_del(global_timer) == 0);
}
TEST_CASE("ESPOS timer auto run test", "[espos]")
{
uint32_t i;
espos_sem_create(&sync_sema, 1, 0);
TEST_ASSERT(espos_timer_create(&global_timer, TIMER_NAME, espos_test_timer_cb, NULL,
espos_ms_to_ticks(20), ESPOS_TIMER_AUTO_RUN) == 0);
count = 0;
TEST_ASSERT(espos_timer_start(global_timer) == 0);
for (i = 0; i < 100; i++) {
espos_sem_take(sync_sema, ESPOS_MAX_DELAY);
}
TEST_ASSERT(espos_timer_stop(global_timer) == 0);
TEST_ASSERT(count == 100);
TEST_ASSERT(espos_sem_del(sync_sema) == 0);
TEST_ASSERT(espos_timer_del(global_timer) == 0);
}
TEST_CASE("ESPOS timer auto run test", "[espos]")
{
espos_timer_t timer;
TEST_ASSERT(espos_sem_create(&sync_sema, 1, 0) == 0);
TEST_ASSERT(espos_timer_create(&timer, TIMER_NAME, espos_test_timer_cb, NULL,
20, ESPOS_TIMER_NO_AUTO_RUN) == 0);
TEST_ASSERT(espos_timer_start(timer) == 0);
TEST_ASSERT(espos_timer_start(timer) == 0);
TEST_ASSERT(espos_sem_take(sync_sema, 200) == 0);
TEST_ASSERT(espos_timer_stop(timer) == 0);
TEST_ASSERT(espos_timer_stop(timer) == 0);
TEST_ASSERT(espos_sem_take(sync_sema, 200) == -ETIMEDOUT);
TEST_ASSERT(espos_timer_del(timer) == 0);
}
TEST_CASE("ESPOS timer change test", "[espos]")
{
TEST_ASSERT(espos_sem_create(&sync_sema, 1, 0) == 0);
TEST_ASSERT(espos_timer_create(&global_timer, TIMER_NAME, espos_test_timer_cb, NULL,
20, ESPOS_TIMER_AUTO_RUN) == 0);
count = 0;
TEST_ASSERT(espos_timer_start(global_timer) == 0);
TEST_ASSERT(espos_sem_take(sync_sema, ESPOS_MAX_DELAY) == 0);
TEST_ASSERT(espos_sem_take(sync_sema, 200) == 0);
TEST_ASSERT(espos_sem_take(sync_sema, 200) == 0);
TEST_ASSERT(espos_timer_stop(global_timer) == 0);
TEST_ASSERT(count == 3);
TEST_ASSERT(espos_sem_del(sync_sema) == 0);
TEST_ASSERT(espos_timer_del(global_timer) == 0);
}
TEST_CASE("ESPOS timer API param test", "[espos]")
{
espos_timer_t timer;
TEST_ASSERT(espos_timer_create(&timer, NULL, NULL, espos_test_timer_cb,
20, ESPOS_TIMER_NO_AUTO_RUN) == -EINVAL);
TEST_ASSERT(espos_timer_create(NULL, NULL, espos_test_timer_cb, NULL,
20, ESPOS_TIMER_AUTO_RUN) == -EINVAL);
TEST_ASSERT(espos_timer_create(&timer, NULL, NULL, NULL,
20, ESPOS_TIMER_AUTO_RUN) == -EINVAL);
TEST_ASSERT(espos_timer_create(&timer, NULL, NULL, espos_test_timer_cb,
20, ESPOS_TIMER_INVALID_OPT) == -EINVAL);
TEST_ASSERT(espos_timer_start(ESPOS_TIMER_INVALID_HANDLE) == -EINVAL);
TEST_ASSERT(espos_timer_stop(ESPOS_TIMER_INVALID_HANDLE) == -EINVAL);
TEST_ASSERT(espos_timer_change(ESPOS_TIMER_INVALID_HANDLE,
ESPOS_TIMER_CHANGE_ONCE, NULL) == -EINVAL);
TEST_ASSERT(espos_timer_change(timer,
ESPOS_TIMER_CHANGE_OPT_INVALID, NULL) == -EINVAL);
TEST_ASSERT(espos_timer_del(ESPOS_TIMER_INVALID_HANDLE) == -EINVAL);
}

View file

@ -0,0 +1,14 @@
src = Split('''
platform/rhino/espos_misc.c
platform/rhino/espos_mutex.c
platform/rhino/espos_queue.c
platform/rhino/espos_scheduler.c
platform/rhino/espos_semaphore.c
platform/rhino/espos_spinlock.c
platform/rhino/espos_task.c
platform/rhino/espos_time.c
platform/rhino/espos_timer.c
''')
component = aos_component('espos', src)
component.add_global_includes('include')

View file

@ -0,0 +1,712 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#ifndef __Common_h__
#define __Common_h__
// ==== STD LIB ====
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#if defined __GNUC__
#include "platform_toolchain.h"
#elif defined ( __ICCARM__ )
#include "EWARM/platform_toolchain.h"
#elif defined ( __CC_ARM ) //KEIL
#include "RVMDK/platform_toolchain.h"
#endif
//#ifdef CONFIG_PLATFORM_8195A
//#include "rtl_lib.h"
//#endif
#ifdef __cplusplus
extern "C" {
#endif
#define TARGET_RT_LITTLE_ENDIAN
/* Use this macro to define an RTOS-aware interrupt handler where RTOS
* primitives can be safely accessed
*
* @usage:
* WWD_RTOS_DEFINE_ISR( my_irq_handler )
* {
* // Do something here
* }
*/
#if defined( __GNUC__ )
/* Section where IRQ handlers are placed */
#define IRQ_SECTION ".text.irq"
#define MICO_RTOS_DEFINE_ISR( function ) \
void function( void ); \
__attribute__(( interrupt, used, section(IRQ_SECTION) )) void function( void )
#elif defined ( __IAR_SYSTEMS_ICC__ )
#define MICO_RTOS_DEFINE_ISR( function ) \
__irq __root void function( void ); \
__irq __root void function( void )
#elif defined ( __CC_ARM ) //KEIL
#define MICO_RTOS_DEFINE_ISR( function ) \
void function( void ); \
__attribute__(( used )) void function( void )
#else
#define MICO_RTOS_DEFINE_ISR( function ) \
void function( void );
#endif
// ==== COMPATIBILITY TYPES
//typedef uint8_t Boolean;
typedef uint8_t mico_bool_t;
#define MICO_FALSE (0)
#define MICO_TRUE (1)
#if( !defined( INT_MAX ) )
#define INT_MAX 2147483647
#endif
// ==== MiCO Timer Typedef ====
#define NANOSECONDS 1000000UL
#define MICROSECONDS 1000
#define MILLISECONDS (1)
#define SECONDS (1000)
#define MINUTES (60 * SECONDS)
#define HOURS (60 * MINUTES)
#define DAYS (24 * HOURS)
typedef uint32_t mico_time_t; /**< Time value in milliseconds */
typedef uint32_t mico_utc_time_t; /**< UTC Time in seconds */
typedef uint64_t mico_utc_time_ms_t; /**< UTC Time in milliseconds */
// ==== OSStatus ====
typedef int OSStatus;
#define kNoErr 0 //! No error occurred.
#define kGeneralErr -1 //! General error.
#define kInProgressErr 1 //! Operation in progress.
// Generic error codes are in the range -6700 to -6779.
#define kGenericErrorBase -6700 //! Starting error code for all generic errors.
#define kUnknownErr -6700 //! Unknown error occurred.
#define kOptionErr -6701 //! Option was not acceptable.
#define kSelectorErr -6702 //! Selector passed in is invalid or unknown.
#define kExecutionStateErr -6703 //! Call made in the wrong execution state (e.g. called at interrupt time).
#define kPathErr -6704 //! Path is invalid, too long, or otherwise not usable.
#define kParamErr -6705 //! Parameter is incorrect, missing, or not appropriate.
#define kUserRequiredErr -6706 //! User interaction is required.
#define kCommandErr -6707 //! Command invalid or not supported.
#define kIDErr -6708 //! Unknown, invalid, or inappropriate identifier.
#define kStateErr -6709 //! Not in appropriate state to perform operation.
#define kRangeErr -6710 //! Index is out of range or not valid.
#define kRequestErr -6711 //! Request was improperly formed or not appropriate.
#define kResponseErr -6712 //! Response was incorrect or out of sequence.
#define kChecksumErr -6713 //! Checksum does not match the actual data.
#define kNotHandledErr -6714 //! Operation was not handled (or not handled completely).
#define kVersionErr -6715 //! Version is not correct or not compatible.
#define kSignatureErr -6716 //! Signature did not match what was expected.
#define kFormatErr -6717 //! Unknown, invalid, or inappropriate file/data format.
#define kNotInitializedErr -6718 //! Action request before needed services were initialized.
#define kAlreadyInitializedErr -6719 //! Attempt made to initialize when already initialized.
#define kNotInUseErr -6720 //! Object not in use (e.g. cannot abort if not already in use).
#define kAlreadyInUseErr -6721 //! Object is in use (e.g. cannot reuse active param blocks).
#define kTimeoutErr -6722 //! Timeout occurred.
#define kCanceledErr -6723 //! Operation canceled (successful cancel).
#define kAlreadyCanceledErr -6724 //! Operation has already been canceled.
#define kCannotCancelErr -6725 //! Operation could not be canceled (maybe already done or invalid).
#define kDeletedErr -6726 //! Object has already been deleted.
#define kNotFoundErr -6727 //! Something was not found.
#define kNoMemoryErr -6728 //! Not enough memory was available to perform the operation.
#define kNoResourcesErr -6729 //! Resources unavailable to perform the operation.
#define kDuplicateErr -6730 //! Duplicate found or something is a duplicate.
#define kImmutableErr -6731 //! Entity is not changeable.
#define kUnsupportedDataErr -6732 //! Data is unknown or not supported.
#define kIntegrityErr -6733 //! Data is corrupt.
#define kIncompatibleErr -6734 //! Data is not compatible or it is in an incompatible format.
#define kUnsupportedErr -6735 //! Feature or option is not supported.
#define kUnexpectedErr -6736 //! Error occurred that was not expected.
#define kValueErr -6737 //! Value is not appropriate.
#define kNotReadableErr -6738 //! Could not read or reading is not allowed.
#define kNotWritableErr -6739 //! Could not write or writing is not allowed.
#define kBadReferenceErr -6740 //! An invalid or inappropriate reference was specified.
#define kFlagErr -6741 //! An invalid, inappropriate, or unsupported flag was specified.
#define kMalformedErr -6742 //! Something was not formed correctly.
#define kSizeErr -6743 //! Size was too big, too small, or not appropriate.
#define kNameErr -6744 //! Name was not correct, allowed, or appropriate.
#define kNotPreparedErr -6745 //! Device or service is not ready.
#define kReadErr -6746 //! Could not read.
#define kWriteErr -6747 //! Could not write.
#define kMismatchErr -6748 //! Something does not match.
#define kDateErr -6749 //! Date is invalid or out-of-range.
#define kUnderrunErr -6750 //! Less data than expected.
#define kOverrunErr -6751 //! More data than expected.
#define kEndingErr -6752 //! Connection, session, or something is ending.
#define kConnectionErr -6753 //! Connection failed or could not be established.
#define kAuthenticationErr -6754 //! Authentication failed or is not supported.
#define kOpenErr -6755 //! Could not open file, pipe, device, etc.
#define kTypeErr -6756 //! Incorrect or incompatible type (e.g. file, data, etc.).
#define kSkipErr -6757 //! Items should be or was skipped.
#define kNoAckErr -6758 //! No acknowledge.
#define kCollisionErr -6759 //! Collision occurred (e.g. two on bus at same time).
#define kBackoffErr -6760 //! Backoff in progress and operation intentionally failed.
#define kNoAddressAckErr -6761 //! No acknowledge of address.
#define kInternalErr -6762 //! An error internal to the implementation occurred.
#define kNoSpaceErr -6763 //! Not enough space to perform operation.
#define kCountErr -6764 //! Count is incorrect.
#define kEndOfDataErr -6765 //! Reached the end of the data (e.g. recv returned 0).
#define kWouldBlockErr -6766 //! Would need to block to continue (e.g. non-blocking read/write).
#define kLookErr -6767 //! Special case that needs to be looked at (e.g. interleaved data).
#define kSecurityRequiredErr -6768 //! Security is required for the operation (e.g. must use encryption).
#define kOrderErr -6769 //! Order is incorrect.
#define kUpgradeErr -6770 //! Must upgrade.
#define kAsyncNoErr -6771 //! Async operation successfully started and is now in progress.
#define kDeprecatedErr -6772 //! Operation or data is deprecated.
#define kPermissionErr -6773 //! Permission denied.
#define kGenericErrorEnd -6779 //! Last generic error code (inclusive)
// ==== C TYPE SAFE MACROS ====
//---------------------------------------------------------------------------------------------------------------------------
/*! @group ctype safe macros
@abstract Wrappers for the ctype.h macros make them safe when used with signed characters.
@discussion
Some implementations of the ctype.h macros use the character value to directly index into a table.
This can lead to crashes and other problems when used with signed characters if the character value
is greater than 127 because the values 128-255 will appear to be negative if viewed as a signed char.
A negative subscript to an array causes it to index before the beginning and access invalid memory.
To work around this, these *_safe wrappers mask the value and cast it to an unsigned char.
*/
#define isalnum_safe( X ) isalnum( ( (unsigned char)( ( X ) & 0xFF ) ) )
#define isalpha_safe( X ) isalpha( ( (unsigned char)( ( X ) & 0xFF ) ) )
#define iscntrl_safe( X ) iscntrl( ( (unsigned char)( ( X ) & 0xFF ) ) )
#define isdigit_safe( X ) isdigit( ( (unsigned char)( ( X ) & 0xFF ) ) )
#define isgraph_safe( X ) isgraph( ( (unsigned char)( ( X ) & 0xFF ) ) )
#define islower_safe( X ) islower( ( (unsigned char)( ( X ) & 0xFF ) ) )
#define isoctal_safe( X ) isoctal( ( (unsigned char)( ( X ) & 0xFF ) ) )
#define isprint_safe( X ) isprint( ( (unsigned char)( ( X ) & 0xFF ) ) )
#define ispunct_safe( X ) ispunct( ( (unsigned char)( ( X ) & 0xFF ) ) )
#define isspace_safe( X ) isspace( ( (unsigned char)( ( X ) & 0xFF ) ) )
#define isupper_safe( X ) isupper( ( (unsigned char)( ( X ) & 0xFF ) ) )
#define isxdigit_safe( X ) isxdigit( ( (unsigned char)( ( X ) & 0xFF ) ) )
#define tolower_safe( X ) tolower( ( (unsigned char)( ( X ) & 0xFF ) ) )
#define toupper_safe( X ) toupper( ( (unsigned char)( ( X ) & 0xFF ) ) )
// ==== SHA DEFINES ====
#define SHA_DIGEST_LENGTH 20
#define SHA_CTX SHA1Context
#define SHA1_Init( CTX ) SHA1Reset( (CTX) )
#define SHA1_Update( CTX, PTR, LEN ) SHA1Input( (CTX), (PTR), (LEN) )
#define SHA1_Final( DIGEST, CTX ) SHA1Result( (CTX), (DIGEST) )
#define SHA1( PTR, LEN, DIGEST ) SHA1Direct( (PTR), (LEN), (DIGEST) )
#define SHA512_DIGEST_LENGTH 64
#define SHA512_CTX SHA512Context
#define SHA512_Init( CTX ) SHA512Reset( (CTX) )
#define SHA512_Update( CTX, PTR, LEN ) SHA512Input( (CTX), (PTR), (LEN) )
#define SHA512_Final( DIGEST, CTX ) SHA512Result( (CTX), (DIGEST) )
#define SHA512( PTR, LEN, DIGEST ) SHA512Direct( (PTR), (LEN), (DIGEST) )
#define SHA3_DIGEST_LENGTH 64
#define SHA3_CTX SHA3_CTX_compat
#define SHA3_Init( CTX ) SHA3_Init_compat( (CTX) )
#define SHA3_Update( CTX, PTR, LEN ) SHA3_Update_compat( (CTX), (PTR), (LEN) )
#define SHA3_Final( DIGEST, CTX ) SHA3_Final_compat( (DIGEST), (CTX) )
#define SHA3( PTR, LEN, DIGEST ) SHA3_compat( (PTR), (LEN), DIGEST )
// ==== MIN / MAX ====
//---------------------------------------------------------------------------------------------------------------------------
/*! @function Min
@abstract Returns the lesser of X and Y.
*/
#if( !defined( Min ) )
#define Min( X, Y ) ( ( ( X ) < ( Y ) ) ? ( X ) : ( Y ) )
#endif
//---------------------------------------------------------------------------------------------------------------------------
/*! @function Max
@abstract Returns the greater of X and Y.
*/
#if( !defined( Max ) )
#define Max( X, Y ) ( ( ( X ) > ( Y ) ) ? ( X ) : ( Y ) )
#endif
// ==== Alignment / Endian safe read/write/swap macros ====
#define ReadBig16( PTR ) \
( (uint16_t)( \
( ( (uint16_t)( (uint8_t *)(PTR) )[ 0 ] ) << 8 ) | \
( (uint16_t)( (uint8_t *)(PTR) )[ 1 ] ) ) )
#define ReadBig32( PTR ) \
( (uint32_t)( \
( ( (uint32_t)( (uint8_t *)(PTR) )[ 0 ] ) << 24 ) | \
( ( (uint32_t)( (uint8_t *)(PTR) )[ 1 ] ) << 16 ) | \
( ( (uint32_t)( (uint8_t *)(PTR) )[ 2 ] ) << 8 ) | \
( (uint32_t)( (uint8_t *)(PTR) )[ 3 ] ) ) )
#define ReadBig48( PTR ) \
( (uint64_t)( \
( ( (uint64_t)( (uint8_t *)(PTR) )[ 0 ] ) << 40 ) | \
( ( (uint64_t)( (uint8_t *)(PTR) )[ 1 ] ) << 32 ) | \
( ( (uint64_t)( (uint8_t *)(PTR) )[ 2 ] ) << 24 ) | \
( ( (uint64_t)( (uint8_t *)(PTR) )[ 3 ] ) << 16 ) | \
( ( (uint64_t)( (uint8_t *)(PTR) )[ 4 ] ) << 8 ) | \
( (uint64_t)( (uint8_t *)(PTR) )[ 5 ] ) ) )
#define ReadBig64( PTR ) \
( (uint64_t)( \
( ( (uint64_t)( (uint8_t *)(PTR) )[ 0 ] ) << 56 ) | \
( ( (uint64_t)( (uint8_t *)(PTR) )[ 1 ] ) << 48 ) | \
( ( (uint64_t)( (uint8_t *)(PTR) )[ 2 ] ) << 40 ) | \
( ( (uint64_t)( (uint8_t *)(PTR) )[ 3 ] ) << 32 ) | \
( ( (uint64_t)( (uint8_t *)(PTR) )[ 4 ] ) << 24 ) | \
( ( (uint64_t)( (uint8_t *)(PTR) )[ 5 ] ) << 16 ) | \
( ( (uint64_t)( (uint8_t *)(PTR) )[ 6 ] ) << 8 ) | \
( (uint64_t)( (uint8_t *)(PTR) )[ 7 ] ) ) )
// Big endian Writing
#define WriteBig16( PTR, X ) \
do \
{ \
( (uint8_t *)(PTR) )[ 0 ] = (uint8_t)( ( (X) >> 8 ) & 0xFF ); \
( (uint8_t *)(PTR) )[ 1 ] = (uint8_t)( (X) & 0xFF ); \
\
} while( 0 )
#define WriteBig32( PTR, X ) \
do \
{ \
( (uint8_t *)(PTR) )[ 0 ] = (uint8_t)( ( (X) >> 24 ) & 0xFF ); \
( (uint8_t *)(PTR) )[ 1 ] = (uint8_t)( ( (X) >> 16 ) & 0xFF ); \
( (uint8_t *)(PTR) )[ 2 ] = (uint8_t)( ( (X) >> 8 ) & 0xFF ); \
( (uint8_t *)(PTR) )[ 3 ] = (uint8_t)( (X) & 0xFF ); \
\
} while( 0 )
#define WriteBig48( PTR, X ) \
do \
{ \
( (uint8_t *)(PTR) )[ 0 ] = (uint8_t)( ( (X) >> 40 ) & 0xFF ); \
( (uint8_t *)(PTR) )[ 1 ] = (uint8_t)( ( (X) >> 32 ) & 0xFF ); \
( (uint8_t *)(PTR) )[ 2 ] = (uint8_t)( ( (X) >> 24 ) & 0xFF ); \
( (uint8_t *)(PTR) )[ 3 ] = (uint8_t)( ( (X) >> 16 ) & 0xFF ); \
( (uint8_t *)(PTR) )[ 4 ] = (uint8_t)( ( (X) >> 8 ) & 0xFF ); \
( (uint8_t *)(PTR) )[ 5 ] = (uint8_t)( (X) & 0xFF ); \
\
} while( 0 )
#define WriteBig64( PTR, X ) \
do \
{ \
( (uint8_t *)(PTR) )[ 0 ] = (uint8_t)( ( (X) >> 56 ) & 0xFF ); \
( (uint8_t *)(PTR) )[ 1 ] = (uint8_t)( ( (X) >> 48 ) & 0xFF ); \
( (uint8_t *)(PTR) )[ 2 ] = (uint8_t)( ( (X) >> 40 ) & 0xFF ); \
( (uint8_t *)(PTR) )[ 3 ] = (uint8_t)( ( (X) >> 32 ) & 0xFF ); \
( (uint8_t *)(PTR) )[ 4 ] = (uint8_t)( ( (X) >> 24 ) & 0xFF ); \
( (uint8_t *)(PTR) )[ 5 ] = (uint8_t)( ( (X) >> 16 ) & 0xFF ); \
( (uint8_t *)(PTR) )[ 6 ] = (uint8_t)( ( (X) >> 8 ) & 0xFF ); \
( (uint8_t *)(PTR) )[ 7 ] = (uint8_t)( (X) & 0xFF ); \
\
} while( 0 )
// Little endian reading
#define ReadLittle16( PTR ) \
( (uint16_t)( \
( (uint16_t)( (uint8_t *)(PTR) )[ 0 ] ) | \
( ( (uint16_t)( (uint8_t *)(PTR) )[ 1 ] ) << 8 ) ) )
#define ReadLittle32( PTR ) \
( (uint32_t)( \
( (uint32_t)( (uint8_t *)(PTR) )[ 0 ] ) | \
( ( (uint32_t)( (uint8_t *)(PTR) )[ 1 ] ) << 8 ) | \
( ( (uint32_t)( (uint8_t *)(PTR) )[ 2 ] ) << 16 ) | \
( ( (uint32_t)( (uint8_t *)(PTR) )[ 3 ] ) << 24 ) ) )
#define ReadLittle48( PTR ) \
( (uint64_t)( \
( (uint64_t)( (uint8_t *)(PTR) )[ 0 ] ) | \
( ( (uint64_t)( (uint8_t *)(PTR) )[ 1 ] ) << 8 ) | \
( ( (uint64_t)( (uint8_t *)(PTR) )[ 2 ] ) << 16 ) | \
( ( (uint64_t)( (uint8_t *)(PTR) )[ 3 ] ) << 24 ) | \
( ( (uint64_t)( (uint8_t *)(PTR) )[ 4 ] ) << 32 ) | \
( ( (uint64_t)( (uint8_t *)(PTR) )[ 5 ] ) << 40 ) ) )
#define ReadLittle64( PTR ) \
( (uint64_t)( \
( (uint64_t)( (uint8_t *)(PTR) )[ 0 ] ) | \
( ( (uint64_t)( (uint8_t *)(PTR) )[ 1 ] ) << 8 ) | \
( ( (uint64_t)( (uint8_t *)(PTR) )[ 2 ] ) << 16 ) | \
( ( (uint64_t)( (uint8_t *)(PTR) )[ 3 ] ) << 24 ) | \
( ( (uint64_t)( (uint8_t *)(PTR) )[ 4 ] ) << 32 ) | \
( ( (uint64_t)( (uint8_t *)(PTR) )[ 5 ] ) << 40 ) | \
( ( (uint64_t)( (uint8_t *)(PTR) )[ 6 ] ) << 48 ) | \
( ( (uint64_t)( (uint8_t *)(PTR) )[ 7 ] ) << 56 ) ) )
// Little endian writing
#define WriteLittle16( PTR, X ) \
do \
{ \
( (uint8_t *)(PTR) )[ 0 ] = (uint8_t)( (X) & 0xFF ); \
( (uint8_t *)(PTR) )[ 1 ] = (uint8_t)( ( (X) >> 8 ) & 0xFF ); \
\
} while( 0 )
#define WriteLittle32( PTR, X ) \
do \
{ \
( (uint8_t *)(PTR) )[ 0 ] = (uint8_t)( (X) & 0xFF ); \
( (uint8_t *)(PTR) )[ 1 ] = (uint8_t)( ( (X) >> 8 ) & 0xFF ); \
( (uint8_t *)(PTR) )[ 2 ] = (uint8_t)( ( (X) >> 16 ) & 0xFF ); \
( (uint8_t *)(PTR) )[ 3 ] = (uint8_t)( ( (X) >> 24 ) & 0xFF ); \
\
} while( 0 )
#define WriteLittle48( PTR, X ) \
do \
{ \
( (uint8_t *)(PTR) )[ 0 ] = (uint8_t)( (X) & 0xFF ); \
( (uint8_t *)(PTR) )[ 1 ] = (uint8_t)( ( (X) >> 8 ) & 0xFF ); \
( (uint8_t *)(PTR) )[ 2 ] = (uint8_t)( ( (X) >> 16 ) & 0xFF ); \
( (uint8_t *)(PTR) )[ 3 ] = (uint8_t)( ( (X) >> 24 ) & 0xFF ); \
( (uint8_t *)(PTR) )[ 4 ] = (uint8_t)( ( (X) >> 32 ) & 0xFF ); \
( (uint8_t *)(PTR) )[ 5 ] = (uint8_t)( ( (X) >> 40 ) & 0xFF ); \
\
} while( 0 )
#define WriteLittle64( PTR, X ) \
do \
{ \
( (uint8_t *)(PTR) )[ 0 ] = (uint8_t)( (X) & 0xFF ); \
( (uint8_t *)(PTR) )[ 1 ] = (uint8_t)( ( (X) >> 8 ) & 0xFF ); \
( (uint8_t *)(PTR) )[ 2 ] = (uint8_t)( ( (X) >> 16 ) & 0xFF ); \
( (uint8_t *)(PTR) )[ 3 ] = (uint8_t)( ( (X) >> 24 ) & 0xFF ); \
( (uint8_t *)(PTR) )[ 4 ] = (uint8_t)( ( (X) >> 32 ) & 0xFF ); \
( (uint8_t *)(PTR) )[ 5 ] = (uint8_t)( ( (X) >> 40 ) & 0xFF ); \
( (uint8_t *)(PTR) )[ 6 ] = (uint8_t)( ( (X) >> 48 ) & 0xFF ); \
( (uint8_t *)(PTR) )[ 7 ] = (uint8_t)( ( (X) >> 56 ) & 0xFF ); \
\
} while( 0 )
#if( !defined( TARGET_RT_LITTLE_ENDIAN ) && !defined( TARGET_RT_BIG_ENDIAN ) )
#error unknown byte order - update your Makefile to define the target platform endianness as TARGET_RT_BIG_ENDIAN / TARGET_RT_LITTLE_ENDIAN
#endif
#if( !defined( TARGET_RT_LITTLE_ENDIAN ) )
#define ReadHost16( PTR ) ReadBig16( (PTR) )
#define ReadHost32( PTR ) ReadBig32( (PTR) )
#define ReadHost48( PTR ) ReadBig48( (PTR) )
#define ReadHost64( PTR ) ReadBig64( (PTR) )
#define WriteHost16( PTR, X ) WriteBig16( (PTR), (X) )
#define WriteHost32( PTR, X ) WriteBig32( (PTR), (X) )
#define WriteHost48( PTR, X ) WriteBig48( (PTR), (X) )
#define WriteHost64( PTR, X ) WriteBig64( (PTR), (X) )
#else
#define ReadHost16( PTR ) ReadLittle16( (PTR) )
#define ReadHost32( PTR ) ReadLittle32( (PTR) )
#define ReadHost48( PTR ) ReadLittle48( (PTR) )
#define ReadHost64( PTR ) ReadLittle64( (PTR) )
#define WriteHost16( PTR, X ) WriteLittle16( (PTR), (X) )
#define WriteHost32( PTR, X ) WriteLittle32( (PTR), (X) )
#define WriteHost48( PTR, X ) WriteLittle48( (PTR), (X) )
#define WriteHost64( PTR, X ) WriteLittle64( (PTR), (X) )
#endif
// Unconditional swap read/write.
#if( !defined( TARGET_RT_LITTLE_ENDIAN ) )
#define ReadSwap16( PTR ) ReadLittle16( (PTR) )
#define ReadSwap32( PTR ) ReadLittle32( (PTR) )
#define ReadSwap48( PTR ) ReadLittle48( (PTR) )
#define ReadSwap64( PTR ) ReadLittle64( (PTR) )
#define WriteSwap16( PTR, X ) WriteLittle16( (PTR), (X) )
#define WriteSwap32( PTR, X ) WriteLittle32( (PTR), (X) )
#define WriteSwap48( PTR, X ) WriteLittle48( (PTR), (X) )
#define WriteSwap64( PTR, X ) WriteLittle64( (PTR), (X) )
#else
#define ReadSwap16( PTR ) ReadBig16( (PTR) )
#define ReadSwap32( PTR ) ReadBig32( (PTR) )
#define ReadSwap48( PTR ) ReadBig48( (PTR) )
#define ReadSwap64( PTR ) ReadBig64( (PTR) )
#define WriteSwap16( PTR, X ) WriteBig16( (PTR), (X) )
#define WriteSwap32( PTR, X ) WriteBig32( (PTR), (X) )
#define WriteSwap48( PTR, X ) WriteBig48( (PTR), (X) )
#define WriteSwap64( PTR, X ) WriteBig64( (PTR), (X) )
#endif
// Memory swaps
#if( !defined( TARGET_RT_LITTLE_ENDIAN ) )
#define HostToBig16Mem( SRC, LEN, DST ) do {} while( 0 )
#define BigToHost16Mem( SRC, LEN, DST ) do {} while( 0 )
#define LittleToHost16Mem( SRC, LEN, DST ) Swap16Mem( (SRC), (LEN), (DST) )
#define LittleToHost16Mem( SRC, LEN, DST ) Swap16Mem( (SRC), (LEN), (DST) )
#else
#define HostToBig16Mem( SRC, LEN, DST ) Swap16Mem( (SRC), (LEN), (DST) )
#define BigToHost16Mem( SRC, LEN, DST ) Swap16Mem( (SRC), (LEN), (DST) )
#define HostToLittle16Mem( SRC, LEN, DST ) do {} while( 0 )
#define LittleToHost16Mem( SRC, LEN, DST ) do {} while( 0 )
#endif
// Unconditional endian swaps
#if !defined (Swap16)
#define Swap16( X ) \
( (uint16_t)( \
( ( ( (uint16_t)(X) ) << 8 ) & UINT16_C( 0xFF00 ) ) | \
( ( ( (uint16_t)(X) ) >> 8 ) & UINT16_C( 0x00FF ) ) ) )
#endif
#if !defined (Swap32)
#define Swap32( X ) \
( (uint32_t)( \
( ( ( (uint32_t)(X) ) << 24 ) & UINT32_C( 0xFF000000 ) ) | \
( ( ( (uint32_t)(X) ) << 8 ) & UINT32_C( 0x00FF0000 ) ) | \
( ( ( (uint32_t)(X) ) >> 8 ) & UINT32_C( 0x0000FF00 ) ) | \
( ( ( (uint32_t)(X) ) >> 24 ) & UINT32_C( 0x000000FF ) ) ) )
#endif
#if !defined (Swap64)
#define Swap64( X ) \
( (uint64_t)( \
( ( ( (uint64_t)(X) ) << 56 ) & UINT64_C( 0xFF00000000000000 ) ) | \
( ( ( (uint64_t)(X) ) << 40 ) & UINT64_C( 0x00FF000000000000 ) ) | \
( ( ( (uint64_t)(X) ) << 24 ) & UINT64_C( 0x0000FF0000000000 ) ) | \
( ( ( (uint64_t)(X) ) << 8 ) & UINT64_C( 0x000000FF00000000 ) ) | \
( ( ( (uint64_t)(X) ) >> 8 ) & UINT64_C( 0x00000000FF000000 ) ) | \
( ( ( (uint64_t)(X) ) >> 24 ) & UINT64_C( 0x0000000000FF0000 ) ) | \
( ( ( (uint64_t)(X) ) >> 40 ) & UINT64_C( 0x000000000000FF00 ) ) | \
( ( ( (uint64_t)(X) ) >> 56 ) & UINT64_C( 0x00000000000000FF ) ) ) )
#endif
// Host<->Network/Big endian swaps
#if( !defined( TARGET_RT_LITTLE_ENDIAN ) )
#define hton16( X ) (X)
#define ntoh16( X ) (X)
#define hton32( X ) (X)
#define ntoh32( X ) (X)
#define hton64( X ) (X)
#define ntoh64( X ) (X)
#else
#define hton16( X ) Swap16( X )
#define ntoh16( X ) Swap16( X )
#define hton32( X ) Swap32( X )
#define ntoh32( X ) Swap32( X )
#define hton64( X ) Swap64( X )
#define ntoh64( X ) Swap64( X )
#endif
#define htons( X ) hton16( X )
#define ntohs( X ) ntoh16( X )
#define htonl( X ) hton32( X )
#define ntohl( X ) ntoh32( X )
//---------------------------------------------------------------------------------------------------------------------------
/*! @function BitArray
@abstract Macros for working with bit arrays.
@discussion
This treats bit numbers starting from the left so bit 0 is 0x80 in byte 0, bit 1 is 0x40 in bit 0,
bit 8 is 0x80 in byte 1, etc. For example, the following ASCII art shows how the bits are arranged:
1 1 1 1 1 1 1 1 1 1 2 2 2 2
Bit 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| x |x | x x| = 0x20 0x80 0x41 (bits 2, 8, 17, and 23).
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Byte 0 1 2
*/
#define BitArray_MinBytes( ARRAY, N_BYTES ) memrlen( (ARRAY), (N_BYTES) )
#define BitArray_MaxBytes( BITS ) ( ( (BITS) + 7 ) / 8 )
#define BitArray_MaxBits( ARRAY_BYTES ) ( (ARRAY_BYTES) * 8 )
#define BitArray_Clear( ARRAY_PTR, ARRAY_BYTES ) memset( (ARRAY_PTR), 0, (ARRAY_BYTES) );
#define BitArray_GetBit( PTR, LEN, BIT ) \
( ( (BIT) < BitArray_MaxBits( (LEN) ) ) && ( (PTR)[ (BIT) / 8 ] & ( 1 << ( 7 - ( (BIT) & 7 ) ) ) ) )
#define BitArray_SetBit( ARRAY, BIT ) ( (ARRAY)[ (BIT) / 8 ] |= ( 1 << ( 7 - ( (BIT) & 7 ) ) ) )
#define BitArray_ClearBit( ARRAY, BIT ) ( (ARRAY)[ (BIT) / 8 ] &= ~( 1 << ( 7 - ( (BIT) & 7 ) ) ) )
//---------------------------------------------------------------------------------------------------------------------------
/*! @group BitRotates
@abstract Rotates X COUNT bits to the left or right.
*/
#define ROTL( X, N, SIZE ) ( ( (X) << (N) ) | ( (X) >> ( (SIZE) - N ) ) )
#define ROTR( X, N, SIZE ) ( ( (X) >> (N) ) | ( (X) << ( (SIZE) - N ) ) )
#define ROTL32( X, N ) ROTL( (X), (N), 32 )
#define ROTR32( X, N ) ROTR( (X), (N), 32 )
#define ROTL64( X, N ) ROTL( (X), (N), 64 )
#define ROTR64( X, N ) ROTR( (X), (N), 64 )
#define RotateBitsLeft( X, N ) ROTL( (X), (N), sizeof( (X) ) * 8 )
#define RotateBitsRight( X, N ) ROTR( (X), (N), sizeof( (X) ) * 8 )
// ==== Macros for minimum-width integer constants ====
#if( !defined( INT8_C ) )
#define INT8_C( value ) value
#endif
#if( !defined( INT16_C ) )
#define INT16_C( value ) value
#endif
#if( !defined( INT32_C ) )
#define INT32_C( value ) value
#endif
#define INT64_C_safe( value ) INT64_C( value )
#if( !defined( INT64_C ) )
#if( defined( _MSC_VER ) )
#define INT64_C( value ) value ## i64
#else
#define INT64_C( value ) value ## LL
#endif
#endif
#define UINT8_C_safe( value ) UINT8_C( value )
#if( !defined( UINT8_C ) )
#define UINT8_C( value ) value ## U
#endif
#define UINT16_C_safe( value ) UINT16_C( value )
#if( !defined( UINT16_C ) )
#define UINT16_C( value ) value ## U
#endif
#define UINT32_C_safe( value ) UINT32_C( value )
#if( !defined( UINT32_C ) )
#define UINT32_C( value ) value ## U
#endif
#define UINT64_C_safe( value ) UINT64_C( value )
#if( !defined( UINT64_C ) )
#if( defined( _MSC_VER ) )
#define UINT64_C( value ) value ## UI64
#else
#define UINT64_C( value ) value ## ULL
#endif
#endif
// ==== SOCKET MACROS ====
#define IsValidSocket( X ) ( ( X ) >= 0 )
/* Suppress unused parameter warning */
#ifndef UNUSED_PARAMETER
#define UNUSED_PARAMETER(x) ( (void)(x) )
#endif
/* Suppress unused variable warning */
#ifndef UNUSED_VARIABLE
#define UNUSED_VARIABLE(x) ( (void)(x) )
#endif
/* Suppress unused variable warning occurring due to an assert which is disabled in release mode */
#ifndef REFERENCE_DEBUG_ONLY_VARIABLE
#define REFERENCE_DEBUG_ONLY_VARIABLE(x) ( (void)(x) )
#endif
#ifdef __cplusplus
}
#endif
#ifdef MICO_ENABLE_MALLOC_DEBUG
#include "malloc_debug.h"
extern void malloc_print_mallocs ( void );
#else
#define calloc_named( name, nelems, elemsize) calloc ( nelems, elemsize )
#define calloc_named_hideleak( name, nelems, elemsize ) calloc ( nelems, elemsize )
#define realloc_named( name, ptr, size ) realloc( ptr, size )
#define malloc_named( name, size ) malloc ( size )
#define malloc_named_hideleak( name, size ) malloc ( size )
#define malloc_set_name( name )
#define malloc_leak_set_ignored( global_flag )
#define malloc_leak_set_base( global_flag )
#define malloc_leak_check( thread, global_flag )
#define malloc_transfer_to_curr_thread( block )
#define malloc_transfer_to_thread( block, thread )
#define malloc_print_mallocs( void )
#define malloc_debug_startup_finished( )
#endif /* ifdef MICO_ENABLE_MALLOC_DEBUG */
/**
******************************************************************************
* Convert a nibble into a hex character
*
* @param[in] nibble The value of the nibble in the lower 4 bits
*
* @return The hex character corresponding to the nibble
*/
static inline ALWAYS_INLINE char nibble_to_hexchar( uint8_t nibble )
{
if (nibble > 9)
{
return (char)('A' + (nibble - 10));
}
else
{
return (char) ('0' + nibble);
}
}
/**
******************************************************************************
* Convert a nibble into a hex character
*
* @param[in] nibble The value of the nibble in the lower 4 bits
*
* @return The hex character corresponding to the nibble
*/
static inline ALWAYS_INLINE char hexchar_to_nibble( char hexchar, uint8_t* nibble )
{
if ( ( hexchar >= '0' ) && ( hexchar <= '9' ) )
{
*nibble = (uint8_t)( hexchar - '0' );
return 0;
}
else if ( ( hexchar >= 'A' ) && ( hexchar <= 'F' ) )
{
*nibble = (uint8_t) ( hexchar - 'A' + 10 );
return 0;
}
else if ( ( hexchar >= 'a' ) && ( hexchar <= 'f' ) )
{
*nibble = (uint8_t) ( hexchar - 'a' + 10 );
return 0;
}
return -1;
}
#endif // __Common_h__

View file

@ -0,0 +1,546 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#ifndef __Debug_h__
#define __Debug_h__
#ifndef MICO_PREBUILT_LIBS
#include "platform.h"
#include "platform_config.h"
#endif
#include "mico_rtos.h"
#include "platform_assert.h"
// ==== LOGGING ====
#ifdef __GNUC__
#define SHORT_FILE __FILENAME__
#else
#define SHORT_FILE strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__
#endif
#define YesOrNo(x) (x ? "YES" : "NO")
#ifdef DEBUG
#ifndef MICO_DISABLE_STDIO
#ifndef NO_MICO_RTOS
extern int mico_debug_enabled;
extern mico_mutex_t stdio_tx_mutex;
#define custom_log(N, M, ...) do {if (mico_debug_enabled==0)break;\
mico_rtos_lock_mutex( &stdio_tx_mutex );\
printf("[%ld][%s: %s:%4d] " M "\r\n", mico_rtos_get_time(), N, SHORT_FILE, __LINE__, ##__VA_ARGS__);\
mico_rtos_unlock_mutex( &stdio_tx_mutex );}while(0==1)
#ifndef MICO_ASSERT_INFO_DISABLE
#define debug_print_assert(A,B,C,D,E,F) do {if (mico_debug_enabled==0)break;\
mico_rtos_lock_mutex( &stdio_tx_mutex );\
printf("[%ld][MICO:%s:%s:%4d] **ASSERT** %s""\r\n", mico_rtos_get_time(), D, F, E, (C!=NULL) ? C : "" );\
mico_rtos_unlock_mutex( &stdio_tx_mutex );}while(0==1)
#else // !MICO_ASSERT_INFO_ENABLE
#define debug_print_assert(A,B,C,D,E,F)
#endif // MICO_ASSERT_INFO_ENABLE
#ifdef TRACE
#define custom_log_trace(N) do {if (mico_debug_enabled==0)break;\
mico_rtos_lock_mutex( &stdio_tx_mutex );\
printf("[%s: [TRACE] %s] %s()\r\n", N, SHORT_FILE, __PRETTY_FUNCTION__);\
mico_rtos_unlock_mutex( &stdio_tx_mutex );}while(0==1)
#else // !TRACE
#define custom_log_trace(N)
#endif // TRACE
#else // NO_MICO_RTOS
#define custom_log(N, M, ...) do {printf("[%s: %s:%4d] " M "\r\n", N, SHORT_FILE, __LINE__, ##__VA_ARGS__);}while(0==1)
#ifndef MICO_ASSERT_INFO_DISABLE
#define debug_print_assert(A,B,C,D,E,F) do {printf("[MICO:%s:%s:%4d] **ASSERT** %s""\r\n", D, F, E, (C!=NULL) ? C : "" );}while(0==1)
#else
#define debug_print_assert(A,B,C,D,E,F)
#endif
#ifdef TRACE
#define custom_log_trace(N) do {printf("[%s: [TRACE] %s] %s()\r\n", N, SHORT_FILE, __PRETTY_FUNCTION__);}while(0==1)
#else // !TRACE
#define custom_log_trace(N)
#endif // TRACE
#endif
#else
#define custom_log(N, M, ...)
#define custom_log_trace(N)
#define debug_print_assert(A,B,C,D,E,F)
#endif //MICO_DISABLE_STDIO
#else // DEBUG = 0
// IF !DEBUG, make the logs NO-OP
#define custom_log(N, M, ...)
#define custom_log_trace(N)
#define debug_print_assert(A,B,C,D,E,F)
#endif // DEBUG
// ==== PLATFORM TIMEING FUNCTIONS ====
#ifdef TIME_PLATFORM
#define function_timer_log(M, N, ...) fprintf(stderr, "[FUNCTION TIMER: " N "()] " M "\n", ##__VA_ARGS__)
#define TIMEPLATFORM( FUNC, FUNC_NAME ) \
do \
{ \
struct timespec startTime; \
clock_gettime(CLOCK_MONOTONIC, &startTime); \
{ FUNC; } \
struct timespec endTime; \
clock_gettime(CLOCK_MONOTONIC, &endTime); \
struct timespec timeDiff = TimeDifference( startTime, endTime ); \
function_timer_log("%lld us", \
FUNC_NAME, \
ElapsedTimeInMicroseconds( timeDiff )); \
} \
while( 1==0 )
#else
#define function_timer_log(M, N, ...)
#define TIMEPLATFORM( FUNC, FUNC_NAME ) \
do \
{ \
{ FUNC; } \
} \
while( 1==0 )
#endif
// ==== BRANCH PREDICTION & EXPRESSION EVALUATION ====
#if( !defined( unlikely ) )
//#define unlikely( EXPRESSSION ) __builtin_expect( !!(EXPRESSSION), 0 )
#define unlikely( EXPRESSSION ) !!(EXPRESSSION)
#endif
//---------------------------------------------------------------------------------------------------------------------------
/*! @defined check
@abstract Check that an expression is true (non-zero).
@discussion
If expression evalulates to false, this prints debugging information (actual expression string, file, line number,
function name, etc.) using the default debugging output method.
Code inside check() statements is not compiled into production builds.
*/
#if( !defined( check ) )
#define check( X ) \
do \
{ \
if( unlikely( !(X) ) ) \
{ \
debug_print_assert( 0, #X, NULL, SHORT_FILE, __LINE__, __PRETTY_FUNCTION__ ); \
} \
\
} while( 1==0 )
#endif
//---------------------------------------------------------------------------------------------------------------------------
/*! @defined check_string
@abstract Check that an expression is true (non-zero) with an explanation.
@discussion
If expression evalulates to false, this prints debugging information (actual expression string, file, line number,
function name, etc.) using the default debugging output method.
Code inside check() statements is not compiled into production builds.
*/
#if( !defined( check_string ) )
#define check_string( X, STR ) \
do \
{ \
if( unlikely( !(X) ) ) \
{ \
debug_print_assert( 0, #X, STR, SHORT_FILE, __LINE__, __PRETTY_FUNCTION__ ); \
MICO_ASSERTION_FAIL_ACTION(); \
} \
\
} while( 1==0 )
#endif
//---------------------------------------------------------------------------------------------------------------------------
/*! @defined require
@abstract Requires that an expression evaluate to true.
@discussion
If expression evalulates to false, this prints debugging information (actual expression string, file, line number,
function name, etc.) using the default debugging output method then jumps to a label.
*/
#if( !defined( require ) )
#define require( X, LABEL ) \
do \
{ \
if( unlikely( !(X) ) ) \
{ \
debug_print_assert( 0, #X, NULL, SHORT_FILE, __LINE__, __PRETTY_FUNCTION__ ); \
goto LABEL; \
} \
\
} while( 1==0 )
#endif
//---------------------------------------------------------------------------------------------------------------------------
/*! @defined require_string
@abstract Requires that an expression evaluate to true with an explanation.
@discussion
If expression evalulates to false, this prints debugging information (actual expression string, file, line number,
function name, etc.) and a custom explanation string using the default debugging output method then jumps to a label.
*/
#if( !defined( require_string ) )
#define require_string( X, LABEL, STR ) \
do \
{ \
if( unlikely( !(X) ) ) \
{ \
debug_print_assert( 0, #X, STR, SHORT_FILE, __LINE__, __PRETTY_FUNCTION__ ); \
goto LABEL; \
} \
\
} while( 1==0 )
#endif
//---------------------------------------------------------------------------------------------------------------------------
/*! @defined require_quiet
@abstract Requires that an expression evaluate to true.
@discussion
If expression evalulates to false, this jumps to a label. No debugging information is printed.
*/
#if( !defined( require_quiet ) )
#define require_quiet( X, LABEL ) \
do \
{ \
if( unlikely( !(X) ) ) \
{ \
goto LABEL; \
} \
\
} while( 1==0 )
#endif
//---------------------------------------------------------------------------------------------------------------------------
/*! @defined require_noerr
@abstract Require that an error code is noErr (0).
@discussion
If the error code is non-0, this prints debugging information (actual expression string, file, line number,
function name, etc.) using the default debugging output method then jumps to a label.
*/
#if( !defined( require_noerr ) )
#define require_noerr( ERR, LABEL ) \
do \
{ \
OSStatus localErr; \
\
localErr = (OSStatus)(ERR); \
if( unlikely( localErr != 0 ) ) \
{ \
debug_print_assert( localErr, NULL, NULL, SHORT_FILE, __LINE__, __PRETTY_FUNCTION__ ); \
goto LABEL; \
} \
\
} while( 1==0 )
#endif
//---------------------------------------------------------------------------------------------------------------------------
/*! @defined require_noerr_string
@abstract Require that an error code is noErr (0).
@discussion
If the error code is non-0, this prints debugging information (actual expression string, file, line number,
function name, etc.), and a custom explanation string using the default debugging output method using the
default debugging output method then jumps to a label.
*/
#if( !defined( require_noerr_string ) )
#define require_noerr_string( ERR, LABEL, STR ) \
do \
{ \
OSStatus localErr; \
\
localErr = (OSStatus)(ERR); \
if( unlikely( localErr != 0 ) ) \
{ \
debug_print_assert( localErr, NULL, STR, SHORT_FILE, __LINE__, __PRETTY_FUNCTION__ ); \
goto LABEL; \
} \
\
} while( 1==0 )
#endif
//---------------------------------------------------------------------------------------------------------------------------
/*! @defined require_noerr_action_string
@abstract Require that an error code is noErr (0).
@discussion
If the error code is non-0, this prints debugging information (actual expression string, file, line number,
function name, etc.), and a custom explanation string using the default debugging output method using the
default debugging output method then executes an action and jumps to a label.
*/
#if( !defined( require_noerr_action_string ) )
#define require_noerr_action_string( ERR, LABEL, ACTION, STR ) \
do \
{ \
OSStatus localErr; \
\
localErr = (OSStatus)(ERR); \
if( unlikely( localErr != 0 ) ) \
{ \
debug_print_assert( localErr, NULL, STR, SHORT_FILE, __LINE__, __PRETTY_FUNCTION__ ); \
{ ACTION; } \
goto LABEL; \
} \
\
} while( 1==0 )
#endif
//---------------------------------------------------------------------------------------------------------------------------
/*! @defined require_noerr_quiet
@abstract Require that an error code is noErr (0).
@discussion
If the error code is non-0, this jumps to a label. No debugging information is printed.
*/
#if( !defined( require_noerr_quiet ) )
#define require_noerr_quiet( ERR, LABEL ) \
do \
{ \
if( unlikely( (ERR) != 0 ) ) \
{ \
goto LABEL; \
} \
\
} while( 1==0 )
#endif
//---------------------------------------------------------------------------------------------------------------------------
/*! @defined require_noerr_action
@abstract Require that an error code is noErr (0) with an action to execute otherwise.
@discussion
If the error code is non-0, this prints debugging information (actual expression string, file, line number,
function name, etc.) using the default debugging output method then executes an action and jumps to a label.
*/
#if( !defined( require_noerr_action ) )
#define require_noerr_action( ERR, LABEL, ACTION ) \
do \
{ \
OSStatus localErr; \
\
localErr = (OSStatus)(ERR); \
if( unlikely( localErr != 0 ) ) \
{ \
debug_print_assert( localErr, NULL, NULL, SHORT_FILE, __LINE__, __PRETTY_FUNCTION__ ); \
{ ACTION; } \
goto LABEL; \
} \
\
} while( 1==0 )
#endif
//---------------------------------------------------------------------------------------------------------------------------
/*! @defined require_noerr_action_quiet
@abstract Require that an error code is noErr (0) with an action to execute otherwise.
@discussion
If the error code is non-0, this executes an action and jumps to a label. No debugging information is printed.
*/
#if( !defined( require_noerr_action_quiet ) )
#define require_noerr_action_quiet( ERR, LABEL, ACTION ) \
do \
{ \
if( unlikely( (ERR) != 0 ) ) \
{ \
{ ACTION; } \
goto LABEL; \
} \
\
} while( 1==0 )
#endif
//---------------------------------------------------------------------------------------------------------------------------
/*! @defined require_action
@abstract Requires that an expression evaluate to true with an action to execute otherwise.
@discussion
If expression evalulates to false, this prints debugging information (actual expression string, file, line number,
function name, etc.) using the default debugging output method then executes an action and jumps to a label.
*/
#if( !defined( require_action ) )
#define require_action( X, LABEL, ACTION ) \
do \
{ \
if( unlikely( !(X) ) ) \
{ \
debug_print_assert( 0, #X, NULL, SHORT_FILE, __LINE__, __PRETTY_FUNCTION__ ); \
{ ACTION; } \
goto LABEL; \
} \
\
} while( 1==0 )
#endif
//---------------------------------------------------------------------------------------------------------------------------
/*! @defined require_action_string
@abstract Requires that an expression evaluate to true with an explanation and action to execute otherwise.
@discussion
If expression evalulates to false, this prints debugging information (actual expression string, file, line number,
function name, etc.) and a custom explanation string using the default debugging output method then executes an
action and jumps to a label.
*/
#if( !defined( require_action_string ) )
#define require_action_string( X, LABEL, ACTION, STR ) \
do \
{ \
if( unlikely( !(X) ) ) \
{ \
debug_print_assert( 0, #X, STR, SHORT_FILE, __LINE__, __PRETTY_FUNCTION__ ); \
{ ACTION; } \
goto LABEL; \
} \
\
} while( 1==0 )
#endif
//---------------------------------------------------------------------------------------------------------------------------
/*! @defined require_action_quiet
@abstract Requires that an expression evaluate to true with an action to execute otherwise.
@discussion
If expression evalulates to false, this executes an action and jumps to a label. No debugging information is printed.
*/
#if( !defined( require_action_quiet ) )
#define require_action_quiet( X, LABEL, ACTION ) \
do \
{ \
if( unlikely( !(X) ) ) \
{ \
{ ACTION; } \
goto LABEL; \
} \
\
} while( 1==0 )
#endif
// ==== ERROR MAPPING ====
#define global_value_errno( VALUE ) ( errno ? errno : kUnknownErr )
#define map_global_value_errno( TEST, VALUE ) ( (TEST) ? 0 : global_value_errno(VALUE) )
#define map_global_noerr_errno( ERR ) ( !(ERR) ? 0 : global_value_errno(ERR) )
#define map_fd_creation_errno( FD ) ( IsValidFD( FD ) ? 0 : global_value_errno( FD ) )
#define map_noerr_errno( ERR ) map_global_noerr_errno( (ERR) )
#define socket_errno( SOCK ) ( errno ? errno : kUnknownErr )
#define socket_value_errno( SOCK, VALUE ) socket_errno( SOCK )
#define map_socket_value_errno( SOCK, TEST, VALUE ) ( (TEST) ? 0 : socket_value_errno( (SOCK), (VALUE) ) )
#define map_socket_noerr_errno( SOCK, ERR ) ( !(ERR) ? 0 : socket_errno( (SOCK) ) )
//---------------------------------------------------------------------------------------------------------------------------
/*! @defined check_ptr_overlap
@abstract Checks that two ptrs do not overlap.
*/
#define check_ptr_overlap( P1, P1_SIZE, P2, P2_SIZE ) \
do \
{ \
check( !( ( (uintptr_t)(P1) >= (uintptr_t)(P2) ) && \
( (uintptr_t)(P1) < ( ( (uintptr_t)(P2) ) + (P2_SIZE) ) ) ) ); \
check( !( ( (uintptr_t)(P2) >= (uintptr_t)(P1) ) && \
( (uintptr_t)(P2) < ( ( (uintptr_t)(P1) ) + (P1_SIZE) ) ) ) ); \
\
} while( 1==0 )
#define IsValidFD( X ) ( ( X ) >= 0 )
//------------------------------------------Memory debug------------------------------------------------------------------
typedef struct
{
int num_of_chunks; /**< number of free chunks*/
int total_memory; /**< maximum total allocated space*/
int allocted_memory; /**< total allocated space*/
int free_memory; /**< total free space*/
} micoMemInfo_t;
#define MicoGetMemoryInfo mico_memory_info
/**
* @brief Get memory usage information
*
* @param None
*
* @return Point to structure of memory usage information in heap
*/
micoMemInfo_t* MicoGetMemoryInfo( void );
//---------------------------------------------------------------------------------------------------------------------------
#ifdef DEBUG
#include "platform_assert.h"
#define MICO_BREAK_IF_DEBUG( ) MICO_ASSERTION_FAIL_ACTION()
#else
#define MICO_BREAK_IF_DEBUG( )
#endif
#ifdef PRINT_PLATFORM_PERMISSION
int platform_wprint_permission(void);
#define PRINT_PLATFORM_PERMISSION_FUNC() platform_print_permission()
#else
#ifdef DEBUG
#define PRINT_PLATFORM_PERMISSION_FUNC() 1
#else
#define PRINT_PLATFORM_PERMISSION_FUNC() 0
#endif
#endif
/******************************************************
* Print declarations
******************************************************/
#define PRINT_ENABLE_LIB_INFO
#define PRINT_ENABLE_LIB_DEBUG
#define PRINT_ENABLE_LIB_ERROR
#define PRINT_MACRO(args) do {if (PRINT_PLATFORM_PERMISSION_FUNC()) printf args;} while(0==1)
/* printing macros for general SDK/Library functions*/
#ifdef PRINT_ENABLE_LIB_INFO
#define WPRINT_LIB_INFO(args) PRINT_MACRO(args)
#else
#define WPRINT_LIB_INFO(args)
#endif
#ifdef PRINT_ENABLE_LIB_DEBUG
#define WPRINT_LIB_DEBUG(args) PRINT_MACRO(args)
#else
#define WPRINT_LIB_DEBUG(args)
#endif
#ifdef PRINT_ENABLE_LIB_ERROR
#define WPRINT_LIB_ERROR(args) { PRINT_MACRO(args); MICO_BREAK_IF_DEBUG(); }
#else
#define WPRINT_LIB_ERROR(args) { MICO_BREAK_IF_DEBUG(); }
#endif
#endif // __Debug_h__

View file

@ -0,0 +1,111 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
/** @mainpage MICO
This documentation describes the MICO APIs.
It consists of:
- MICO Core APIs
- MICO Hardware Abstract Layer APIs
- MICO Algorithm APIs
- MICO System APIs
- MICO Middleware APIs
- MICO Drivers interface
*/
#ifndef __MICO_H_
#define __MICO_H_
/* MiCO SDK APIs */
#include "debug.h"
#include "common.h"
#include <hal/hal.h>
#include "mico_rtos.h"
//#include "mico_socket.h"
//#include "mico_security.h"
#include "mico_platform.h"
//#include "mico_system.h"
#define MicoGetRfVer wlan_driver_version
#define MicoGetVer system_lib_version
#define MicoInit mxchipInit
/** @defgroup MICO_Core_APIs MICO Core APIs
* @brief MiCO Initialization, RTOS, TCP/IP stack, and Network Management
*/
/** @addtogroup MICO_Core_APIs
* @{
*/
/** \defgroup MICO_Init_Info Initialization and Tools
* @brief Get MiCO version or RF version, flash usage information or init MiCO TCPIP stack
* @{
*/
/******************************************************
* Structures
******************************************************/
/******************************************************
* Function Declarations
******************************************************/
/**
* @brief Get RF driver's version.
*
* @note Create a memery buffer to store the version characters.
* THe input buffer length should be 40 bytes at least.
* @note This must be executed after micoInit().
* @param inVersion: Buffer address to store the RF driver.
* @param inLength: Buffer size.
*
* @return int
*/
int MicoGetRfVer( char* outVersion, uint8_t inLength );
/**
* @brief Get MICO's version.
*
* @param None
*
* @return Point to the MICO's version string.
*/
char* MicoGetVer( void );
/**
* @brief Initialize the TCPIP stack thread, RF driver thread, and other
supporting threads needed for wlan connection. Do some necessary
initialization
*
* @param None
*
* @return kNoErr: success, kGeneralErr: fail
*/
OSStatus MicoInit( void );
/**
* @brief Get an identifier id from device, every id is unique and will not change in life-time
*
* @param identifier length
*
* @return Point to the identifier
*/
const uint8_t* mico_generate_cid( uint8_t *length );
#endif /* __MICO_H_ */
/**
* @}
*/
/**
* @}
*/

View file

@ -0,0 +1,168 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#ifndef __MICO_ERRNO_H__
#define __MICO_ERRNO_H__
#if defined (__GNUC__)
#include <errno.h>
#else
#define EPERM 1 /* Operation not permitted */
#define ENOENT 2 /* No such file or directory */
#define ESRCH 3 /* No such process */
#define EINTR 4 /* Interrupted system call */
#define EIO 5 /* I/O error */
#define ENXIO 6 /* No such device or address */
#define E2BIG 7 /* Arg list too long */
#define ENOEXEC 8 /* Exec format error */
#define EBADF 9 /* Bad file number */
#define ECHILD 10 /* No child processes */
#define EAGAIN 11 /* Try again */
#define ENOMEM 12 /* Out of memory */
#define EACCES 13 /* Permission denied */
#define EFAULT 14 /* Bad address */
#define ENOTBLK 15 /* Block device required */
#define EBUSY 16 /* Device or resource busy */
#define EEXIST 17 /* File exists */
#define EXDEV 18 /* Cross-device link */
#define ENODEV 19 /* No such device */
#define ENOTDIR 20 /* Not a directory */
#define EISDIR 21 /* Is a directory */
#define EINVAL 22 /* Invalid argument */
#define ENFILE 23 /* File table overflow */
#define EMFILE 24 /* Too many open files */
#define ENOTTY 25 /* Not a typewriter */
#define ETXTBSY 26 /* Text file busy */
#define EFBIG 27 /* File too large */
#define ENOSPC 28 /* No space left on device */
#define ESPIPE 29 /* Illegal seek */
#define EROFS 30 /* Read-only file system */
#define EMLINK 31 /* Too many links */
#define EPIPE 32 /* Broken pipe */
#define EDOM 33 /* Math argument out of domain of func */
#define ERANGE 34 /* Math result not representable */
#define EDEADLK 35 /* Resource deadlock would occur */
#define ENAMETOOLONG 36 /* File name too long */
#define ENOLCK 37 /* No record locks available */
#define ENOSYS 38 /* Function not implemented */
#define ENOTEMPTY 39 /* Directory not empty */
#define ELOOP 40 /* Too many symbolic links encountered */
#define EWOULDBLOCK EAGAIN /* Operation would block */
#define ENOMSG 42 /* No message of desired type */
#define EIDRM 43 /* Identifier removed */
#define ECHRNG 44 /* Channel number out of range */
#define EL2NSYNC 45 /* Level 2 not synchronized */
#define EL3HLT 46 /* Level 3 halted */
#define EL3RST 47 /* Level 3 reset */
#define ELNRNG 48 /* Link number out of range */
#define EUNATCH 49 /* Protocol driver not attached */
#define ENOCSI 50 /* No CSI structure available */
#define EL2HLT 51 /* Level 2 halted */
#define EBADE 52 /* Invalid exchange */
#define EBADR 53 /* Invalid request descriptor */
#define EXFULL 54 /* Exchange full */
#define ENOANO 55 /* No anode */
#define EBADRQC 56 /* Invalid request code */
#define EBADSLT 57 /* Invalid slot */
#define EDEADLOCK EDEADLK
#define EBFONT 59 /* Bad font file format */
#define ENOSTR 60 /* Device not a stream */
#define ENODATA 61 /* No data available */
#define ETIME 62 /* Timer expired */
#define ENOSR 63 /* Out of streams resources */
#define ENONET 64 /* Machine is not on the network */
#define ENOPKG 65 /* Package not installed */
#define EREMOTE 66 /* Object is remote */
#define ENOLINK 67 /* Link has been severed */
#define EADV 68 /* Advertise error */
#define ESRMNT 69 /* Srmount error */
#define ECOMM 70 /* Communication error on send */
#define EPROTO 71 /* Protocol error */
#define EMULTIHOP 72 /* Multihop attempted */
#define EDOTDOT 73 /* RFS specific error */
#define EBADMSG 74 /* Not a data message */
#define EOVERFLOW 75 /* Value too large for defined data type */
#define ENOTUNIQ 76 /* Name not unique on network */
#define EBADFD 77 /* File descriptor in bad state */
#define EREMCHG 78 /* Remote address changed */
#define ELIBACC 79 /* Can not access a needed shared library */
#define ELIBBAD 80 /* Accessing a corrupted shared library */
#define ELIBSCN 81 /* .lib section in a.out corrupted */
#define ELIBMAX 82 /* Attempting to link in too many shared libraries */
#define ELIBEXEC 83 /* Cannot exec a shared library directly */
#define EILSEQ 84 /* Illegal byte sequence */
#define ERESTART 85 /* Interrupted system call should be restarted */
#define ESTRPIPE 86 /* Streams pipe error */
#define EUSERS 87 /* Too many users */
#define ENOTSOCK 88 /* Socket operation on non-socket */
#define EDESTADDRREQ 89 /* Destination address required */
#define EMSGSIZE 90 /* Message too long */
#define EPROTOTYPE 91 /* Protocol wrong type for socket */
#define ENOPROTOOPT 92 /* Protocol not available */
#define EPROTONOSUPPORT 93 /* Protocol not supported */
#define ESOCKTNOSUPPORT 94 /* Socket type not supported */
#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
#define EPFNOSUPPORT 96 /* Protocol family not supported */
#define EAFNOSUPPORT 97 /* Address family not supported by protocol */
#define EADDRINUSE 98 /* Address already in use */
#define EADDRNOTAVAIL 99 /* Cannot assign requested address */
#define ENETDOWN 100 /* Network is down */
#define ENETUNREACH 101 /* Network is unreachable */
#define ENETRESET 102 /* Network dropped connection because of reset */
#define ECONNABORTED 103 /* Software caused connection abort */
#define ECONNRESET 104 /* Connection reset by peer */
#define ENOBUFS 105 /* No buffer space available */
#define EISCONN 106 /* Transport endpoint is already connected */
#define ENOTCONN 107 /* Transport endpoint is not connected */
#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */
#define ETOOMANYREFS 109 /* Too many references: cannot splice */
#define ETIMEDOUT 110 /* Connection timed out */
#define ECONNREFUSED 111 /* Connection refused */
#define EHOSTDOWN 112 /* Host is down */
#define EHOSTUNREACH 113 /* No route to host */
#define EALREADY 114 /* Operation already in progress */
#define EINPROGRESS 115 /* Operation now in progress */
#define ESTALE 116 /* Stale NFS file handle */
#define EUCLEAN 117 /* Structure needs cleaning */
#define ENOTNAM 118 /* Not a XENIX named type file */
#define ENAVAIL 119 /* No XENIX semaphores available */
#define EISNAM 120 /* Is a named type file */
#define EREMOTEIO 121 /* Remote I/O error */
#define EDQUOT 122 /* Quota exceeded */
#define ENOMEDIUM 123 /* No medium found */
#define EMEDIUMTYPE 124 /* Wrong medium type */
#define ENSROK 0 /* DNS server returned answer with no data */
#define ENSRNODATA 160 /* DNS server returned answer with no data */
#define ENSRFORMERR 161 /* DNS server claims query was misformatted */
#define ENSRSERVFAIL 162 /* DNS server returned general failure */
#define ENSRNOTFOUND 163 /* Domain name not found */
#define ENSRNOTIMP 164 /* DNS server does not implement requested operation */
#define ENSRREFUSED 165 /* DNS server refused query */
#define ENSRBADQUERY 166 /* Misformatted DNS query */
#define ENSRBADNAME 167 /* Misformatted domain name */
#define ENSRBADFAMILY 168 /* Unsupported address family */
#define ENSRBADRESP 169 /* Misformatted DNS reply */
#define ENSRCONNREFUSED 170 /* Could not contact DNS servers */
#define ENSRTIMEOUT 171 /* Timeout while contacting DNS servers */
#define ENSROF 172 /* End of file */
#define ENSRFILE 173 /* Error reading file */
#define ENSRNOMEM 174 /* Out of memory */
#define ENSRDESTRUCTION 175 /* Application terminated lookup */
#define ENSRQUERYDOMAINTOOLONG 176 /* Domain name is too long */
#define ENSRCNAMELOOP 177 /* Domain name is too long */
#endif
#undef errno
extern int errno;
#endif //__MICO_ERRNO_H__

View file

@ -0,0 +1,159 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#pragma once
#ifndef __MICOPLATFORM_H__
#define __MICOPLATFORM_H__
#include "common.h"
//#include "platform.h" /* This file is unique for each platform */
#include "platform_peripheral.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef platform_spi_slave_config_t mico_spi_slave_config_t;
typedef platform_spi_slave_transfer_direction_t mico_spi_slave_transfer_direction_t;
typedef platform_spi_slave_transfer_status_t mico_spi_slave_transfer_status_t;
typedef platform_spi_slave_command_t mico_spi_slave_command_t;
typedef platform_spi_slave_data_buffer_t mico_spi_slave_data_buffer_t;
#if 0
#include "MiCODrivers/MiCODriverI2c.h"
#include "MiCODrivers/MiCODriverSpi.h"
#include "MiCODrivers/MiCODriverUart.h"
#include "MiCODrivers/MiCODriverGpio.h"
#include "MiCODrivers/MiCODriverPwm.h"
#include "MiCODrivers/MiCODriverRtc.h"
#include "MiCODrivers/MiCODriverWdg.h"
#include "MiCODrivers/MiCODriverAdc.h"
#include "MiCODrivers/MiCODriverRng.h"
#include "MiCODrivers/MiCODriverFlash.h"
#include "MiCODrivers/MiCODriverMFiAuth.h"
#endif
#define mico_mcu_powersave_config MicoMcuPowerSaveConfig
/** @defgroup MICO_PLATFORM MICO Hardware Abstract Layer APIs
* @brief Control hardware peripherals on different platfroms using standard HAL API functions
*
*/
/** @addtogroup MICO_PLATFORM
* @{
*/
/** @defgroup platform_misc Task switching, reboot, and standby
* @brief Provide task switching,reboot and standby functions
* @{
*/
#define ENABLE_INTERRUPTS __asm("CPSIE i") /**< Enable interrupts to start task switching in MICO RTOS. */
#define DISABLE_INTERRUPTS __asm("CPSID i") /**< Disable interrupts to stop task switching in MICO RTOS. */
/** @brief Software reboot the MICO hardware
*
* @param none
* @return none
*/
void MicoSystemReboot(void);
/** @brief Software reboot the MICO hardware
*
* @param timeToWakeup: MICO will wakeup after secondsToWakeup (seconds)
* @return none
*/
void MicoSystemStandBy(uint32_t secondsToWakeup);
/** @brief Enables the MCU to enter deep sleep mode when all threads are suspended.
*
* @note: When all threads are suspended, mcu can shut down some peripherals to
* save power. For example, STM32 enters STOP mode in this condition,
* its peripherals are not working and needs to be wake up by an external
* interrupt or MICO core's internal timer. So if you are using a peripherals,
* you should disable this function temporarily.
* To make this function works, you should not disable the macro in MicoDefault.h:
* MICO_DISABLE_MCU_POWERSAVE
*
* @param enable : 1 = enable MCU powersave, 0 = disable MCU powersave
* @return none
*/
void MicoMcuPowerSaveConfig( int enable );
/** @brief Set MiCO system led on/off state
*
* @param onff: State of syetem LED,0: OFF,1:ON
* @return none
*/
void MicoSysLed(bool onoff);
/** @brief Set MiCO RF led on/off state
*
* @param onff: State of RF LED,0: OFF,1:ON
* @return none
*/
void MicoRfLed(bool onoff);
/** @brief add
*
* @param add
* @return none
*/
bool MicoShouldEnterMFGMode(void);
/** @brief add
*
* @param add
* @return none
*/
bool MicoShouldEnterATEMode(void);
/** @brief add
*
* @param add
* @return none
*/
bool MicoShouldEnterBootloader(void);
/** @brief add
*
* @param add
* @return none
*/
char *mico_get_bootloader_ver(void);
#ifdef BOOTLOADER
void mico_set_bootload_ver(void);
#endif
/**
* @}
*/
/**
* @}
*/
#ifdef __cplusplus
} /*extern "C" */
#endif
#endif

View file

@ -0,0 +1,654 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#ifndef __MICORTOS_H__
#define __MICORTOS_H__
#include "common.h"
/** @addtogroup MICO_Core_APIs
* @{
*/
/** @defgroup MICO_RTOS MICO RTOS Operations
* @brief Provide management APIs for Thread, Mutex, Timer, Semaphore and FIFO
* @{
*/
#define MICO_HARDWARE_IO_WORKER_THREAD ( (mico_worker_thread_t*)&mico_hardware_io_worker_thread)
#define MICO_NETWORKING_WORKER_THREAD ( (mico_worker_thread_t*)&mico_worker_thread )
#define MICO_WORKER_THREAD ( (mico_worker_thread_t*)&mico_worker_thread )
#define MICO_NETWORK_WORKER_PRIORITY (3)
#define MICO_DEFAULT_WORKER_PRIORITY (5)
#define MICO_DEFAULT_LIBRARY_PRIORITY (5)
#define MICO_APPLICATION_PRIORITY (7)
#define kNanosecondsPerSecond 1000000000UUL
#define kMicrosecondsPerSecond 1000000UL
#define kMillisecondsPerSecond 1000
#define MICO_NEVER_TIMEOUT (0xFFFFFFFF)
#define MICO_WAIT_FOREVER (0xFFFFFFFF)
#define MICO_NO_WAIT (0)
typedef enum
{
WAIT_FOR_ANY_EVENT,
WAIT_FOR_ALL_EVENTS,
} mico_event_flags_wait_option_t;
typedef uint32_t mico_event_flags_t;
typedef void * mico_semaphore_t;
typedef void * mico_mutex_t;
typedef void * mico_thread_t;
typedef void * mico_queue_t;
typedef void * mico_event_t;// MICO OS event: mico_semaphore_t, mico_mutex_t or mico_queue_t
typedef void (*timer_handler_t)( void* arg );
typedef OSStatus (*event_handler_t)( void* arg );
typedef struct
{
void * handle;
timer_handler_t function;
void * arg;
}mico_timer_t;
typedef struct
{
mico_thread_t thread;
mico_queue_t event_queue;
} mico_worker_thread_t;
typedef struct
{
event_handler_t function;
void* arg;
mico_timer_t timer;
mico_worker_thread_t* thread;
} mico_timed_event_t;
typedef uint32_t mico_thread_arg_t;
typedef void (*mico_thread_function_t)( mico_thread_arg_t arg );
extern mico_worker_thread_t mico_hardware_io_worker_thread;
extern mico_worker_thread_t mico_worker_thread;
/* Legacy definitions */
#define mico_thread_sleep mico_rtos_thread_sleep
#define mico_thread_msleep mico_rtos_thread_msleep
#define mico_rtos_init_timer mico_init_timer
#define mico_rtos_start_timer mico_start_timer
#define mico_rtos_stop_timer mico_stop_timer
#define mico_rtos_reload_timer mico_reload_timer
#define mico_rtos_deinit_timer mico_deinit_timer
#define mico_rtos_is_timer_running mico_is_timer_running
#define mico_rtos_init_event_fd mico_create_event_fd
#define mico_rtos_deinit_event_fd mico_delete_event_fd
#define mico_rtos_thread_msleep mico_rtos_delay_milliseconds
/** @addtogroup MICO_Core_APIs
* @{
*/
/** @defgroup MICO_RTOS MICO RTOS Operations
* @{
*/
/** @defgroup MICO_RTOS_COMMON MICO RTOS Common Functions
* @brief Provide Generic RTOS Functions.
* @{
*/
/**
* @}
*/
/** @defgroup MICO_RTOS_Thread MICO RTOS Thread Management Functions
* @brief Provide thread creation, delete, suspend, resume, and other RTOS management API
* @verbatim
* MICO thread priority table
*
* +----------+-----------------+
* | Priority | Thread |
* |----------|-----------------|
* | 0 | MICO | Highest priority
* | 1 | Network |
* | 2 | |
* | 3 | Network worker |
* | 4 | |
* | 5 | Default Library |
* | | Default worker |
* | 6 | |
* | 7 | Application |
* | 8 | |
* | 9 | Idle | Lowest priority
* +----------+-----------------+
* @endverbatim
* @{
*/
/** @brief Creates and starts a new thread
*
* @param thread : Pointer to variable that will receive the thread handle (can be null)
* @param priority : A priority number.
* @param name : a text name for the thread (can be null)
* @param function : the main thread function
* @param stack_size : stack size for this thread
* @param arg : argument which will be passed to thread function
*
* @return kNoErr : on success.
* @return kGeneralErr : if an error occurred
*/
OSStatus mico_rtos_create_thread( mico_thread_t* thread, uint8_t priority, const char* name, mico_thread_function_t function, uint32_t stack_size, mico_thread_arg_t arg );
/** @brief Deletes a terminated thread
*
* @param thread : the handle of the thread to delete, , NULL is the current thread
*
* @return kNoErr : on success.
* @return kGeneralErr : if an error occurred
*/
OSStatus mico_rtos_delete_thread( mico_thread_t* thread );
/** @brief Creates a worker thread
*
* Creates a worker thread
* A worker thread is a thread in whose context timed and asynchronous events
* execute.
*
* @param worker_thread : a pointer to the worker thread to be created
* @param priority : thread priority
* @param stack_size : thread's stack size in number of bytes
* @param event_queue_size : number of events can be pushed into the queue
*
* @return kNoErr : on success.
* @return kGeneralErr : if an error occurred
*/
OSStatus mico_rtos_create_worker_thread( mico_worker_thread_t* worker_thread, uint8_t priority, uint32_t stack_size, uint32_t event_queue_size );
/** @brief Deletes a worker thread
*
* @param worker_thread : a pointer to the worker thread to be created
*
* @return kNoErr : on success.
* @return kGeneralErr : if an error occurred
*/
OSStatus mico_rtos_delete_worker_thread( mico_worker_thread_t* worker_thread );
/** @brief Suspend a thread
*
* @param thread : the handle of the thread to suspend, NULL is the current thread
*
* @return kNoErr : on success.
* @return kGeneralErr : if an error occurred
*/
void mico_rtos_suspend_thread(mico_thread_t* thread);
/** @brief Suspend all other thread
*
* @param none
*
* @return none
*/
void mico_rtos_suspend_all_thread(void);
/** @brief Rresume all other thread
*
* @param none
*
* @return none
*/
long mico_rtos_resume_all_thread(void);
/** @brief Sleeps until another thread has terminated
*
* @Details Causes the current thread to sleep until the specified other thread
* has terminated. If the processor is heavily loaded with higher priority
* tasks, this thread may not wake until significantly after the thread termination.
*
* @param thread : the handle of the other thread which will terminate
*
* @return kNoErr : on success.
* @return kGeneralErr : if an error occurred
*/
OSStatus mico_rtos_thread_join( mico_thread_t* thread );
/** @brief Forcibly wakes another thread
*
* @Details Causes the specified thread to wake from suspension. This will usually
* cause an error or timeout in that thread, since the task it was waiting on
* is not complete.
*
* @param thread : the handle of the other thread which will be woken
*
* @return kNoErr : on success.
* @return kGeneralErr : if an error occurred
*/
OSStatus mico_rtos_thread_force_awake( mico_thread_t* thread );
/** @brief Checks if a thread is the current thread
*
* @Details Checks if a specified thread is the currently running thread
*
* @param thread : the handle of the other thread against which the current thread
* will be compared
*
* @return true : specified thread is the current thread
* @return false : specified thread is not currently running
*/
bool mico_rtos_is_current_thread( mico_thread_t* thread );
/** @brief Suspend current thread for a specific time
*
* @param num_ms : A time interval (Unit: millisecond)
*
* @return kNoErr.
*/
OSStatus mico_rtos_delay_milliseconds( uint32_t num_ms );
/** @brief Print Thread status into buffer
*
* @param buffer, point to buffer to store thread status
* @param length, length of the buffer
*
* @return none
*/
OSStatus mico_rtos_print_thread_status( char* buffer, int length );
/**
* @}
*/
/** @defgroup MICO_RTOS_SEM MICO RTOS Semaphore Functions
* @brief Provide management APIs for semaphore such as init,set,get and dinit.
* @{
*/
/** @brief Initialises a counting semaphore and set count to 0
*
* @param semaphore : a pointer to the semaphore handle to be initialised
* @param count : the max count number of this semaphore
*
* @return kNoErr : on success.
* @return kGeneralErr : if an error occurred
*/
OSStatus mico_rtos_init_semaphore( mico_semaphore_t* semaphore, int count );
/** @brief Set (post/put/increment) a semaphore
*
* @param semaphore : a pointer to the semaphore handle to be set
*
* @return kNoErr : on success.
* @return kGeneralErr : if an error occurred
*/
OSStatus mico_rtos_set_semaphore( mico_semaphore_t* semaphore );
/** @brief Get (wait/decrement) a semaphore
*
* @Details Attempts to get (wait/decrement) a semaphore. If semaphore is at zero already,
* then the calling thread will be suspended until another thread sets the
* semaphore with @ref mico_rtos_set_semaphore
*
* @param semaphore : a pointer to the semaphore handle
* @param timeout_ms: the number of milliseconds to wait before returning
*
* @return kNoErr : on success.
* @return kGeneralErr : if an error occurred
*/
OSStatus mico_rtos_get_semaphore( mico_semaphore_t* semaphore, uint32_t timeout_ms );
/** @brief De-initialise a semaphore
*
* @Details Deletes a semaphore created with @ref mico_rtos_init_semaphore
*
* @param semaphore : a pointer to the semaphore handle
*
* @return kNoErr : on success.
* @return kGeneralErr : if an error occurred
*/
OSStatus mico_rtos_deinit_semaphore( mico_semaphore_t* semaphore );
/**
* @}
*/
/** @defgroup MICO_RTOS_MUTEX MICO RTOS Mutex Functions
* @brief Provide management APIs for Mutex such as init,lock,unlock and dinit.
* @{
*/
/** @brief Initialises a mutex
*
* @Details A mutex is different to a semaphore in that a thread that already holds
* the lock on the mutex can request the lock again (nested) without causing
* it to be suspended.
*
* @param mutex : a pointer to the mutex handle to be initialised
*
* @return kNoErr : on success.
* @return kGeneralErr : if an error occurred
*/
OSStatus mico_rtos_init_mutex( mico_mutex_t* mutex );
/** @brief Obtains the lock on a mutex
*
* @Details Attempts to obtain the lock on a mutex. If the lock is already held
* by another thead, the calling thread will be suspended until the mutex
* lock is released by the other thread.
*
* @param mutex : a pointer to the mutex handle to be locked
*
* @return kNoErr : on success.
* @return kGeneralErr : if an error occurred
*/
OSStatus mico_rtos_lock_mutex( mico_mutex_t* mutex );
/** @brief Releases the lock on a mutex
*
* @Details Releases a currently held lock on a mutex. If another thread
* is waiting on the mutex lock, then it will be resumed.
*
* @param mutex : a pointer to the mutex handle to be unlocked
*
* @return kNoErr : on success.
* @return kGeneralErr : if an error occurred
*/
OSStatus mico_rtos_unlock_mutex( mico_mutex_t* mutex );
/** @brief De-initialise a mutex
*
* @Details Deletes a mutex created with @ref mico_rtos_init_mutex
*
* @param mutex : a pointer to the mutex handle
*
* @return kNoErr : on success.
* @return kGeneralErr : if an error occurred
*/
OSStatus mico_rtos_deinit_mutex( mico_mutex_t* mutex );
/**
* @}
*/
/** @defgroup MICO_RTOS_QUEUE MICO RTOS FIFO Queue Functions
* @brief Provide management APIs for FIFO such as init,push,pop and dinit.
* @{
*/
/** @brief Initialises a FIFO queue
*
* @param queue : a pointer to the queue handle to be initialised
* @param name : a text string name for the queue (NULL is allowed)
* @param message_size : size in bytes of objects that will be held in the queue
* @param number_of_messages : depth of the queue - i.e. max number of objects in the queue
*
* @return kNoErr : on success.
* @return kGeneralErr : if an error occurred
*/
OSStatus mico_rtos_init_queue( mico_queue_t* queue, const char* name, uint32_t message_size, uint32_t number_of_messages );
/** @brief Pushes an object onto a queue
*
* @param queue : a pointer to the queue handle
* @param message : the object to be added to the queue. Size is assumed to be
* the size specified in @ref mico_rtos_init_queue
* @param timeout_ms: the number of milliseconds to wait before returning
*
* @return kNoErr : on success.
* @return kGeneralErr : if an error or timeout occurred
*/
OSStatus mico_rtos_push_to_queue( mico_queue_t* queue, void* message, uint32_t timeout_ms );
/** @brief Pops an object off a queue
*
* @param queue : a pointer to the queue handle
* @param message : pointer to a buffer that will receive the object being
* popped off the queue. Size is assumed to be
* the size specified in @ref mico_rtos_init_queue , hence
* you must ensure the buffer is long enough or memory
* corruption will result
* @param timeout_ms: the number of milliseconds to wait before returning
*
* @return kNoErr : on success.
* @return kGeneralErr : if an error or timeout occurred
*/
OSStatus mico_rtos_pop_from_queue( mico_queue_t* queue, void* message, uint32_t timeout_ms );
/** @brief De-initialise a queue created with @ref mico_rtos_init_queue
*
* @param queue : a pointer to the queue handle
*
* @return kNoErr : on success.
* @return kGeneralErr : if an error occurred
*/
OSStatus mico_rtos_deinit_queue( mico_queue_t* queue );
/** @brief Check if a queue is empty
*
* @param queue : a pointer to the queue handle
*
* @return true : queue is empty.
* @return false : queue is not empty.
*/
bool mico_rtos_is_queue_empty( mico_queue_t* queue );
/** @brief Check if a queue is full
*
* @param queue : a pointer to the queue handle
*
* @return true : queue is empty.
* @return false : queue is not empty.
*/
bool mico_rtos_is_queue_full( mico_queue_t* queue );
/**
* @}
*/
/** @defgroup MICO_RTOS_EVENT MICO RTOS Event Functions
* @{
*/
/**
* @brief Sends an asynchronous event to the associated worker thread
*
* @param worker_thread :the worker thread in which context the callback should execute from
* @param function : the callback function to be called from the worker thread
* @param arg : the argument to be passed to the callback function
*
* @return kNoErr : on success.
* @return kGeneralErr : if an error occurred
*/
OSStatus mico_rtos_send_asynchronous_event( mico_worker_thread_t* worker_thread, event_handler_t function, void* arg );
/** Requests a function be called at a regular interval
*
* This function registers a function that will be called at a regular
* interval. Since this is based on the RTOS time-slice scheduling, the
* accuracy is not high, and is affected by processor load.
*
* @param event_object : pointer to a event handle which will be initialised
* @param worker_thread : pointer to the worker thread in whose context the
* callback function runs on
* @param function : the callback function that is to be called regularly
* @param time_ms : the time period between function calls in milliseconds
* @param arg : an argument that will be supplied to the function when
* it is called
*
* @return kNoErr : on success.
* @return kGeneralErr : if an error occurred
*/
OSStatus mico_rtos_register_timed_event( mico_timed_event_t* event_object, mico_worker_thread_t* worker_thread, event_handler_t function, uint32_t time_ms, void* arg );
/** Removes a request for a regular function execution
*
* This function de-registers a function that has previously been set-up
* with @ref mico_rtos_register_timed_event.
*
* @param event_object : the event handle used with @ref mico_rtos_register_timed_event
*
* @return kNoErr : on success.
* @return kGeneralErr : if an error occurred
*/
OSStatus mico_rtos_deregister_timed_event( mico_timed_event_t* event_object );
/**
* @}
*/
/** @defgroup MICO_RTOS_TIMER MICO RTOS Timer Functions
* @brief Provide management APIs for timer such as init,start,stop,reload and dinit.
* @{
*/
/**
* @brief Gets time in miiliseconds since RTOS start
*
* @note: Since this is only 32 bits, it will roll over every 49 days, 17 hours.
*
* @returns Time in milliseconds since RTOS started.
*/
uint32_t mico_rtos_get_time(void);
/**
* @brief Initialize a RTOS timer
*
* @note Timer does not start running until @ref mico_start_timer is called
*
* @param timer : a pointer to the timer handle to be initialised
* @param time_ms : Timer period in milliseconds
* @param function : the callback handler function that is called each time the
* timer expires
* @param arg : an argument that will be passed to the callback function
*
* @return kNoErr : on success.
* @return kGeneralErr : if an error occurred
*/
OSStatus mico_rtos_init_timer( mico_timer_t* timer, uint32_t time_ms, timer_handler_t function, void* arg );
/** @brief Starts a RTOS timer running
*
* @note Timer must have been previously initialised with @ref mico_rtos_init_timer
*
* @param timer : a pointer to the timer handle to start
*
* @return kNoErr : on success.
* @return kGeneralErr : if an error occurred
*/
OSStatus mico_rtos_start_timer( mico_timer_t* timer );
/** @brief Stops a running RTOS timer
*
* @note Timer must have been previously started with @ref mico_rtos_init_timer
*
* @param timer : a pointer to the timer handle to stop
*
* @return kNoErr : on success.
* @return kGeneralErr : if an error occurred
*/
OSStatus mico_rtos_stop_timer( mico_timer_t* timer );
/** @brief Reloads a RTOS timer that has expired
*
* @note This is usually called in the timer callback handler, to
* reschedule the timer for the next period.
*
* @param timer : a pointer to the timer handle to reload
*
* @return kNoErr : on success.
* @return kGeneralErr : if an error occurred
*/
OSStatus mico_rtos_reload_timer( mico_timer_t* timer );
/** @brief De-initialise a RTOS timer
*
* @note Deletes a RTOS timer created with @ref mico_rtos_init_timer
*
* @param timer : a pointer to the RTOS timer handle
*
* @return kNoErr : on success.
* @return kGeneralErr : if an error occurred
*/
OSStatus mico_rtos_deinit_timer( mico_timer_t* timer );
/** @brief Check if an RTOS timer is running
*
* @param timer : a pointer to the RTOS timer handle
*
* @return true : if running.
* @return false : if not running
*/
bool mico_rtos_is_timer_running( mico_timer_t* timer );
int SetTimer(unsigned long ms, void (*psysTimerHandler)(void));
int SetTimer_uniq(unsigned long ms, void (*psysTimerHandler)(void));
int UnSetTimer(void (*psysTimerHandler)(void));
/** @brief Initialize an endpoint for a RTOS event, a file descriptor
* will be created, can be used for select
*
* @param event_handle : mico_semaphore_t, mico_mutex_t or mico_queue_t
*
* @retval On success, a file descriptor for RTOS event is returned.
* On error, -1 is returned.
*/
int mico_rtos_init_event_fd(mico_event_t event_handle);
/** @brief De-initialise an endpoint created from a RTOS event
*
* @param fd : file descriptor for RTOS event
*
* @retval 0 for success. On error, -1 is returned.
*/
int mico_rtos_deinit_event_fd(int fd);
/**
* @}
*/
#endif
/**
* @}
*/
/**
* @}
*/

View file

@ -0,0 +1,52 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/******************************************************
* Macros
******************************************************/
/******************************************************
* Constants
******************************************************/
#define rtos_log(M, ...) custom_log("RTOS", M, ##__VA_ARGS__)
#define rtos_log_trace() custom_log_trace("RTOS")
/******************************************************
* Enumerations
******************************************************/
/******************************************************
* Type Definitions
******************************************************/
/******************************************************
* Structures
******************************************************/
/******************************************************
* Global Variables
******************************************************/
/******************************************************
* Function Declarations
******************************************************/
/* MiCO <-> RTOS API */
extern OSStatus mico_rtos_init ( void );
extern OSStatus mico_rtos_deinit( void );
/* Entry point for user Application */
extern void application_start ( void );
#ifdef __cplusplus
} /* extern "C" */
#endif

View file

@ -0,0 +1,717 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#pragma once
#include "common.h"
#include "Curve25519/curve25519-donna.h"
#include "SHAUtils/sha.h"
#include "stdint.h"
#include "CheckSumUtils.h"
/** \defgroup MICO_Algorithm_APIs MICO Algorithm APIs
* @brief Provide commonly used Algorithm APIs
* @{
*/
/** @addtogroup MICO_Algorithm_APIs
* @{
*/
/** @defgroup MICO_Security_MD5 MICO MD5 Encryption
* @brief MiCO MD5 Encryption Function
* @{
*/
typedef unsigned char byte;
typedef unsigned short word16;
typedef unsigned int word32;
typedef unsigned long long word64;
/**
* @brief Constant data during MD5 Encryption
*/
enum {
MD5 = 0, /** hash type unique */
MD5_BLOCK_SIZE = 64,
MD5_DIGEST_SIZE = 16,
MD5_PAD_SIZE = 56
};
/**
* @brief MD5 Context definition
*/
typedef struct {
uint32_t state[4]; /** state (ABCD) */
uint32_t count[2]; /** number of bits, modulo 2^64 (lsb first) */
uint32_t buffer[64]; /** input buffer */
} md5_context;
/**
* @brief MD5 context setup
*
* @param ctx context to be initialized
*/
void InitMd5(md5_context *ctx);
/**
* @brief MD5 process buffer
*
* @param ctx MD5 context
* @param input buffer holding the data
* @param ilen length of the input data
*/
void Md5Update(md5_context *ctx, unsigned char *input, int ilen);
/**
* @brief MD5 final digest
*
* @param ctx MD5 context
* @param output MD5 checksum result
*/
void Md5Final(md5_context *ctx, unsigned char output[16]);
/**
* @}
*/
/** @defgroup MICO_Security_HAMC_MD5 MICO HMAC_MD5 Encryption
* @brief MiCO HMAC_MD5 Encryption Function
* @{
*/
/**
* @brief Constant data during HAMC_MD5 Encryption
*/
enum{
HMAC_BLOCK_SIZE = 64,
INNER_HASH_SIZE = 128,
};
/**
* @brief Hash union during HMAC_MD5 Encryption
*/
typedef union {
md5_context md5;
} Hash;
/**
* @brief Hmac digest during HMAC_MD5 Encription
*/
typedef struct Hmac {
Hash hash;
word32 ipad[HMAC_BLOCK_SIZE / sizeof(word32)]; /* same block size all*/
word32 opad[HMAC_BLOCK_SIZE / sizeof(word32)];
word32 innerHash[INNER_HASH_SIZE / sizeof(word32)]; /* max size */
byte macType; /* md5 */
byte innerHashKeyed; /* keyed flag */
} Hmac;
/**
* @brief HMAC_MD5 extend external key into a longer bit string
*
* @param hmac Hmac context
* @param type hash type(only include MD5)
* @param key key
* @param keysz length of key
* @retval None
*/
void HmacSetKey(Hmac* hmac, int type, const byte* key, word32 keySz);
/**
* @brief HMAC_MD5 process buffer
*
* @param Hmac hmac context
* @param byte* buffer holding the input data
* @param inLen length of the input data.
* Note: The length is arbitrary.
* @retval None
*/
void HmacUpdate(Hmac* hmac, const byte* input, word32 inLen);
/**
* @brief HMAC Final Digest
*
* @param hmac Hmac context
* @param output buffer holding the output data
* @retval None
*/
void HmacFinal(Hmac* hmac, byte* output);
/**
* @}
*/
/** @defgroup MICO_Security_DES MICO DES Encryption Algorithm
* @brief MiCO DES Encryption and Decryption Function
* @{
*/
/**
* @brief Constant data during DES Encryption
*/
enum {
DES_ENC_TYPE = 2, /* cipher unique type */
DES3_ENC_TYPE = 3, /* cipher unique type */
DES_BLOCK_SIZE = 8,
DES_KS_SIZE = 32,
DES_ENCRYPTION = 0,
DES_DECRYPTION = 1
};
/**
* @brief Des context
*/
typedef struct Des {
word32 key[DES_KS_SIZE];
word32 reg[DES_BLOCK_SIZE / sizeof(word32)]; /* for CBC mode */
word32 tmp[DES_BLOCK_SIZE / sizeof(word32)]; /* same */
} Des;
/**
* @brief Des3 context
*/
typedef struct Des3 {
word32 key[3][DES_KS_SIZE];
word32 reg[DES_BLOCK_SIZE / sizeof(word32)]; /* for CBC mode */
word32 tmp[DES_BLOCK_SIZE / sizeof(word32)]; /* same */
} Des3;
/**
* @brief DES extend external key into a longer bit string
*
* @param des Des context
* @param key external key defined by user,the length must be 64 bits
* @param iv extension key defined by user,must be the same size with key
* @param dir Specify the process of encryption or decryption
* @retval None
*/
void Des_SetKey(Des* des, const byte* key, const byte* iv, int dir);
/**
* @brief DES encryption process in Cbc mode
*
* @param des Des context
* @param output buffer to hold output - Cipher Text. It has the same size with input
* @param input buffer to hold input - Plain Text.
* Note: The size of input must be the multiple of DES_BLOCK_SIZE 64 bits
* @param sz size of input
* Note: input and output have the same size.
* @retval None
*/
/**
* @brief DES decryption process in Cbc mode
*
* @param des Des context
* @param output buffer to hold output - Plain Text.
* @param input buffer to hold input - Cipher Text.
* Note: The size of input - Cipher Text must be with 2^64 bits
* And it must be the multiple of DES_BLOCK_SIZE 8 bytes
* @param sz size of input
* Note: input and output have the same size.
* @retval None
*/
void Des_CbcDecrypt(Des* des, byte* output, const byte* input, word32 sz);
/**
* @brief DES3 extend external key into a longer bit string
*
* @param des Des3 context
* @param key external key defined by user,the length must be 192 bits<EFBFBD><EFBFBD>24 bytes<EFBFBD><EFBFBD>
* @param iv extension key defined by user,must be the same size with key
* @param dir Specify the process of encryption or decryption
* @retval None
*/
void Des3_SetKey(Des3* des, const byte* key, const byte* iv,int dir);
/**
* @brief DES3 encryption process in Cbc mode
*
* @param des Des3 context
* @param output buffer to hold output - Cipher Text. It has the same size with input
* @param input buffer to hold input - Plain Text.
* Note: The size of input must be the multiple of DES_BLOCK_SIZE 64 bits
* @param sz size of input
* Note: input and output have the same size.
* @retval None
*/
void Des3_CbcEncrypt(Des3* des, byte* output, const byte* input,word32 sz);
/**
* @brief DES3 decryption process in Cbc mode
*
* @param des Des3 context
* @param output buffer to hold output - Plain Text.
* @param input buffer to hold input - Cipher Text.
* Note: The size of input - Cipher Text must be with 2^64 bits
* And it must be the multiple of DES_BLOCK_SIZE 8 bytes
* @param sz size of input
* Note: input and output have the same size.
* @retval None
*/
void Des3_CbcDecrypt(Des3* des, byte* output, const byte* input,word32 sz);
/**
* @}
*/
/** @defgroup MICO_Security_AES MICO AES Encryption Algorytm
* @brief MiCO AES Encryption and Decryption Function
* @{
*/
/**
* @brief Constant data during AES Encription
*/
enum {
AES_ENC_TYPE = 1, /* cipher unique type */
AES_ENCRYPTION = 0,
AES_DECRYPTION = 1,
AES_BLOCK_SIZE = 16
};
/**
* @brief Aes context
*/
typedef struct Aes {
/* AESNI needs key first, rounds 2nd, not sure why yet */
word32 key[60];
word32 rounds;
word32 reg[AES_BLOCK_SIZE / sizeof(word32)];
word32 tmp[AES_BLOCK_SIZE / sizeof(word32)];
} Aes;
/**
* @brief AES extend external key into a longer bit string
*
* @param aes AES context
* @param key external key defined by user,must be 128 bits
* @param ilen size of AES_BLOCK_SIZE
* @param iv extension key defined by user,must be the same size with key
* @param dir Specify the process of encryption or decryption
* @retval kNoErr is returned on success, otherwise, kXXXErr is returned.
*/
int AesSetKey(Aes* aes, const byte* key, word32 ilen, const byte* iv,int dir);
/**
* @brief AES encryption process in Cbc mode
*
* @param aes AES context
* @param output buffer to hold output - Cipher Text.
* @param input buffer to hold input - Plain Text.
* Note: The size of input - Plain Text must be the multiple of AES_BLOCK_SIZE 128 bits
* @param sz size of input
* Note: input and output have the same size.
* @retval kNoErr is returned on success, otherwise, kXXXErr is returned.
*/
int AesCbcEncrypt(Aes* aes, byte* output, const byte* input, word32 sz);
/**
* @brief AES decryption process in Cbc mode
*
* @param aes AES context
* @param output buffer to hold output - Plain Text. It has the same size with input
* @param input buffer to hold input - Cipher Text.
* Note: The size of input must be the multiple of AES_BLOCK_SIZE 128 bits
* @param sz size of input
* Note: input and output have the same size.
* @retval kNoErr is returned on success, otherwise, kXXXErr is returned.
*/
int AesCbcDecrypt(Aes* aes, byte* output, const byte* input, word32 sz);
/**
* @brief AES encryption process in Cbc mode with PKCS#5 padding
*
* @param aes AES context
* @param output buffer to hold output - Cipher Text.
* @param input buffer to hold input - Plain Text.
* @param sz size of input
* @retval the Cipher Text size, should be the multiple of AES_BLOCK_SIZE 128 bits
*/
word32 AesCbcEncryptPkcs5Padding(Aes* aes, byte* output, const byte* input, word32 sz);
/**
* @brief AES decryption process in Cbc mode with PKCS#5 padding
*
* @param aes AES context
* @param output buffer to hold output - Plain Text.
* @param input buffer to hold input - Cipher Text.
* @param sz size of input, must be the multiple of AES_BLOCK_SIZE 128 bits
* @retval the Plain Text size
*/
word32 AesCbcDecryptPkcs5Padding(Aes* aes, byte* output, const byte* input, word32 sz);
/**
* @brief AES extend external key into a longer bit string
*
* @param aes AES context
* @param key external key defined by user,must be 128 bits
* @param ilen size of AES_BLOCK_SIZE.
* @param out buffer to put cipher text.
* @param dir Specify the process of encryption or decryption
* @retval kNoErr is returned on success, otherwise, kXXXErr is returned.
*/
int AesSetKeyDirect(Aes* aes, const byte* key, word32 ilen,const byte* out, int dir);
/**
* @brief AES encryption process in ecb mode
*
* @param aes AES context
* @param output buffer to hold output - Plain Text. It has the same size with input
* @param input buffer to hold input - Cipher Text.
* Note: The size of input must be the multiple of AES_BLOCK_SIZE 128 bits
* @param sz size of input
* Note: input and output have the same size.
* @retval None.
*/
void AesEncryptDirect(Aes* aes, byte* out, const byte* in);
/**
* @brief AES decryption process in ecb mode
*
* @param aes AES context
* @param output buffer to hold output - Plain Text. It has the same size with input
* @param input buffer to hold input - Cipher Text.
* Note: The size of input must be the multiple of AES_BLOCK_SIZE 128 bits
* @param sz size of input
* Note: input and output have the same size.
* @retval None.
*/
void AesDecryptDirect(Aes* aes, byte* out, const byte* in);
/**
* @}
*/
/** @defgroup MICO_Security_ARC4 MICO ARC4 Encryption Algorytm
* @brief MiCO ARC4 Encryption and Decryption Fucntion
* @{
*/
/**
* @brief Constant data during Arc4 Encription
*/
enum {
ARC4_ENC_TYPE = 4, /* cipher unique type */
ARC4_STATE_SIZE = 256
};
/**
* @brief Arc4 context
*/
typedef struct Arc4 {
byte x;
byte y;
byte state[ARC4_STATE_SIZE];
} Arc4;
/**
* @brief ARC4 extend external key
*
* @param arc4 ARC4 context
* @param key external key defined by user
* @param keylen length of the key, range is 1-256 bits.
* Note: 0 is illegal.
* @retval None.
*/
void Arc4SetKey(Arc4 *arc4, const byte *key, word32 keylen );
/**
* @brief ARC4 encryption or decription process
*
* @param arc4 ARC4 context
* @param output buffer to hold output - Cipher Text.It has the same size with input
* @param input buffer to hold input - Plain Text.
* Note: The length must be within 1 to 20 bytes.
* @param outlen size of output.
* @retval None.
*/
void Arc4Process(Arc4 *arc4, byte *output, const byte *input, word32 outlen);
/**
* @}
*/
/** @defgroup MICO_Security_Rabbit MICO Rabbit Encryption Algorithm
* @brief MiCO Rabbit Encryption and Decryption Function
* @{
*/
/**
* @brief Constant data during Rabbit Encryption
*/
enum {
RABBIT_ENC_TYPE = 5 /* cipher unique type */
};
/**
* @brief Rabbit Context
*/
typedef struct RabbitCtx {
word32 x[8];
word32 c[8];
word32 carry;
} RabbitCtx;
/**
* @brief Rabbit stream cipher
*/
typedef struct Rabbit {
RabbitCtx masterCtx;
RabbitCtx workCtx;
} Rabbit;
/**
* @brief Rabbit extend external key into a longer bit string
*
* @param rabbit Rabbit context
* @param key Key Seed defined by user, but length must be 128 bits
* @param iv initial vector - IV, but length must be 64 bits
*/
int RabbitSetKey(Rabbit* rabbit, const byte* key, const byte* iv);
/**
* @brief Rabbit encryption or decryption process
*
* @param rabbit Rabbit context
* @param output buffer to hold output - Cipher Text.
* Note: The size of output is the same with input.
* @param input buffer to hold input.
* Note: The size must be within 1 to 16bytes
* @param sz size of output.
* @retval kNoErr is returned on success, otherwise, kXXXErr is returned.
*/
int RabbitProcess(Rabbit* rabbit, byte* output, const byte* input, word32 sz);
/**
* @}
*/
/** @defgroup MICO_Security_RSA MICO RSA Encryption Algorithm
* @brief MiCO RSA Encryption and Decryption Function
* @{
*/
/**
* @brief Constant data during RSA Encryption
*/
#define DBRG_SEED_LEN (440/8)
enum {
RSA_PUBLIC = 0,
RSA_PRIVATE = 1
};
/**
* @brief OS specific seeder
*/
typedef struct OS_Seed {
int fd;
} OS_Seed;
/**
* @brief the infamous mp_int structure
*/
typedef struct {
int used, alloc, sign;
unsigned short *dp;
} mp_int;
/**
* @brief rsakey define
*/
typedef struct RsaKey {
mp_int n, e, d, p, q, dP, dQ, u;
int type; /* public or private */
void* heap; /* for user memory overrides */
} RsaKey;
/**
* @brief Constant data during RSA Encryption
*/
enum {
SHA256_BLOCK_SIZE = 64,
SHA256_DIGEST_SIZE = 32,
SHA256_PAD_SIZE = 56
};
/**
* @brief ha256 digest
*/
typedef struct Sha256 {
word32 buffLen; /* in bytes */
word32 loLen; /* length in bytes */
word32 hiLen; /* length in bytes */
word32 digest[SHA256_DIGEST_SIZE / sizeof(word32)];
word32 buffer[SHA256_BLOCK_SIZE / sizeof(word32)];
} Sha256;
/**
* @brief RNG definition used for RSA
*/
typedef struct CyaSSL_RNG {
OS_Seed seed;
Sha256 sha;
byte digest[SHA256_DIGEST_SIZE];
byte V[DBRG_SEED_LEN];
byte C[DBRG_SEED_LEN];
word64 reseed_ctr;
} CyaSSL_RNG;
/**
* @brief Initialize RsaKey
*
* @param key RsaKey context
*
* @retval None
*/
void InitRsaKey(RsaKey* key, void*);
/**
* @brief Free RsaKey
*
* @param key RsaKey context
*
* @retval None
*/
void FreeRsaKey(RsaKey* key);
/**
* @brief Initialize Rng for RSA
*
* @param key CyaSSL_RNG context
*
* @retval kNoErr is returned on success, otherwise, kXXXErr is returned.
*/
int InitRng(CyaSSL_RNG *);
/**
* @brief Encrypt the string with the public key
*
* @param in string need to be encrypted
* @param inLen string length
* @param out used to store the result of encryption
* @param outLen length of out
* @param key RsaKey context
* @param rng CyaSSL_RNG context
*
* @retval kNoErr is returned on success, otherwise, kXXXErr is returned.
*/
int RsaPublicEncrypt(const byte* in, word32 inLen, byte* out,
word32 outLen, RsaKey* key, CyaSSL_RNG* rng);
/**
* @brief Decrypt the string with the private key
*
* @param in string need to be decrypted
* @param inLen string length
* @param out used to store the result of decryption
* @param outLen length of out
* @param key RsaKey context
*
* @retval Return the length in bytes written to out or a negative
number in case of an error.
*/
int RsaPrivateDecrypt(const byte* in, word32 inLen, byte* out,
word32 outLen, RsaKey* key);
/**
* @brief Sign data using RSA
* @param in string need to be signed
* @param inLen string length
* @param out used to store the result of signing
* @param outLen length of out
* @param key RsaKey context
* @param rng rng used to sign
*
* @retval return the length in bytes written to out or a negative
number in case of an error.
*/
int RsaSSL_Sign(const byte* in, word32 inLen, byte* out,
word32 outLen, RsaKey* key, CyaSSL_RNG* rng);
/**
* @brief Verify data using RSA
*
* @param in string need to be verify
* @param inLen string length
* @param out used to store the result of verifying
* @param outLen length of out
* @param key RsaKey context
*
* @retval return the length in bytes written to out or a negative
number in case of an error.
*/
int RsaSSL_Verify(const byte* in, word32 inLen, byte* out,
word32 outLen, RsaKey* key);
/**
* @brief Decode the private key
*
* @param input holds the raw data from the key
* @param inOutIdx start address
* @param key RsaKey context
* @param length length to decode
*
* @retval return the index or error
*/
int RsaPrivateKeyDecode(const byte* input, word32* inOutIdx, RsaKey* key,
word32 length);
/**
* @brief Decode the public key
*
* @param input holds the raw data from the key
* @param inOutIdx start address
* @param key RsaKey context
* @param length length to decode
*
* @retval return the index or error
*/
int RsaPublicKeyDecode(const byte* input, word32* inOutIdx, RsaKey *key,word32);
/**
* @}
*/
/**
* @}
*/

View file

@ -0,0 +1,720 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#ifndef __MICOSOCKET_H__
#define __MICOSOCKET_H__
#if defined __GNUC__
#include <sys/time.h>
#include <sys/select.h>
#endif
#include "mico_errno.h"
#ifdef __cplusplus
extern "C" {
#endif
/** @addtogroup MICO_Core_APIs
* @{
*/
/** @defgroup MICO_SOCKET MICO Socket Operations
* @brief Communicate with other device using TCP or UDP over MICO network
* @{
*/
/** For compatibility with BSD code */
struct in_addr {
uint32_t s_addr;
};
/** 255.255.255.255 */
#define INADDR_NONE ((uint32_t)0xffffffffUL)
/** 127.0.0.1 */
#define INADDR_LOOPBACK ((uint32_t)0x7f000001UL)
/** 0.0.0.0 */
#define INADDR_ANY ((uint32_t)0x00000000UL)
/** 255.255.255.255 */
#define INADDR_BROADCAST ((uint32_t)0xffffffffUL)
/* members are in network byte order */
struct sockaddr_in {
uint8_t sin_len;
uint8_t sin_family;
uint16_t sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
struct sockaddr {
uint8_t sa_len;
uint8_t sa_family;
uint8_t sa_data[14];
};
#ifndef socklen_t
# define socklen_t uint32_t
#endif
struct hostent {
char *h_name; /* Official name of the host. */
char **h_aliases; /* A pointer to an array of pointers to alternative host names,
terminated by a null pointer. */
int h_addrtype; /* Address type. */
int h_length; /* The length, in bytes, of the address. */
char **h_addr_list; /* A pointer to an array of pointers to network addresses (in
network byte order) for the host, terminated by a null pointer. */
#define h_addr h_addr_list[0] /* for backward compatibility */
};
struct addrinfo {
int ai_flags; /* Input flags. */
int ai_family; /* Address family of socket. */
int ai_socktype; /* Socket type. */
int ai_protocol; /* Protocol of socket. */
socklen_t ai_addrlen; /* Length of socket address. */
struct sockaddr *ai_addr; /* Socket address of socket. */
char *ai_canonname; /* Canonical name of service location. */
struct addrinfo *ai_next; /* Pointer to next in list. */
};
/* Socket protocol types (TCP/UDP/RAW) */
#define SOCK_STREAM 1
#define SOCK_DGRAM 2
#define SOCK_RAW 3
#define SOL_SOCKET 0xfff /* options for socket level */
#define AF_UNSPEC 0
#define AF_INET 2
#define PF_INET AF_INET
#define PF_UNSPEC AF_UNSPEC
#define IPPROTO_IP 0
#define IPPROTO_TCP 6
#define IPPROTO_UDP 17
#define IPPROTO_UDPLITE 136
/*
* Options for level IPPROTO_IP
*/
#define IP_TOS 1
#define IP_TTL 2
typedef struct ip_mreq {
struct in_addr imr_multiaddr; /* IP multicast address of group */
struct in_addr imr_interface; /* local IP address of interface */
} ip_mreq;
/**
* @brief Socket option types, level: SOL_SOCKET
*/
typedef enum {
SO_DEBUG = 0x0001, /**< Unimplemented: turn on debugging info recording */
SO_ACCEPTCONN = 0x0002, /**< socket has had listen() */
SO_REUSEADDR = 0x0004, /**< Allow local address reuse */
SO_KEEPALIVE = 0x0008, /**< keep connections alive */
SO_DONTROUTE = 0x0010, /**< Just use interface addresses */
SO_BROADCAST = 0x0020, /**< Permit to send and to receive broadcast messages */
SO_USELOOPBACK = 0x0040, /**< Bypass hardware when possible */
SO_LINGER = 0x0080, /**< linger on close if data present */
SO_OOBINLINE = 0x0100, /**< Leave received OOB data in line */
SO_REUSEPORT = 0x0200, /**< Allow local address & port reuse */
SO_BLOCKMODE = 0x1000, /**< set socket as block(optval=0)/non-block(optval=1) mode.
Default is block mode. */
SO_SNDBUF = 0x1001,
SO_SNDTIMEO = 0x1005, /**< Send timeout in block mode. block for ever in dafault mode. */
SO_RCVTIMEO = 0x1006, /**< Recv timeout in block mode. block 1 second in default mode. */
SO_ERROR = 0x1007, /**< Get socket error number. */
SO_TYPE = 0x1008, /**< Get socket type. */
SO_NO_CHECK = 0x100a /**< Don't create UDP checksum. */
} SOCK_OPT_VAL;
struct pollfd {
int fd; /**< fd related to */
short events; /**< which POLL... events to respond to */
short revents; /**< which POLL... events occurred */
};
#define POLLIN 0x0001
#define POLLPRI 0x0002
#define POLLOUT 0x0004
#define POLLERR 0x0008
#define POLLHUP 0x0010
#define POLLNVAL 0x0020
/**
* @brief IP option types, level: IPPROTO_IP
*/
typedef enum {
IP_ADD_MEMBERSHIP = 0x0003, /**< Join multicast group. */
IP_DROP_MEMBERSHIP = 0x0004, /**< Leave multicast group. */
IP_MULTICAST_TTL = 0x0005,
IP_MULTICAST_IF = 0x0006,
IP_MULTICAST_LOOP = 0x0007
} IP_OPT_VAL;
/**
* @brief TCP option types, level: IPPROTO_TCP
*/
typedef enum {
TCP_NODELAY = 0x0001,
TCP_KEEPALIVE = 0x0002,
TCP_CONN_NUM = 0x0006, /**< Read the current connected TCP client number. */
TCP_MAX_CONN_NUM = 0x0007, /**< Set the max number of TCP client that server can support. */
TCP_KEEPIDLE = 0x0003, /**< set pcb->keep_idle - send KEEPALIVE probes when idle for pcb->keep_idle milliseconds */
TCP_KEEPINTVL = 0x0004, /**< set pcb->keep_intvl - Use seconds for get/setsockopt */
TCP_KEEPCNT = 0x0005, /**< set pcb->keep_cnt - Use number of probes sent for get/setsockopt */
} TCP_OPT_VAL;
#if !defined(FIONREAD) || !defined(FIONBIO)
#define IOCPARM_MASK 0x7fU /* parameters must be < 128 bytes */
#define IOC_VOID 0x20000000UL /* no parameters */
#define IOC_OUT 0x40000000UL /* copy out parameters */
#define IOC_IN 0x80000000UL /* copy in parameters */
#define IOC_INOUT (IOC_IN|IOC_OUT)
/* 0x20000000 distinguishes new &
old ioctl's */
#define _IO(x,y) (IOC_VOID|((x)<<8)|(y))
#define _IOR(x,y,t) (IOC_OUT|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y))
#define _IOW(x,y,t) (IOC_IN|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y))
#endif /* !defined(FIONREAD) || !defined(FIONBIO) */
#ifndef FIONREAD
#define FIONREAD _IOR('f', 127, unsigned long) /* get # bytes to read */
#endif
#ifndef FIONBIO
#define FIONBIO _IOW('f', 126, unsigned long) /* set/clear non-blocking i/o */
#endif
typedef void* mico_ssl_t;
/**
* @brief Supported SSL protocol version
*/
enum ssl_version_type_e
{
SSL_V3_MODE = 1,
TLS_V1_0_MODE = 2,
TLS_V1_1_MODE = 3,
TLS_V1_2_MODE = 4,
};
typedef uint8_t ssl_version_type_t;
#if !defined __GNUC__
struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* and microseconds */
};
#define FD_SETSIZE 64 /**< MAX fd number is 64 in MICO. */
#define howmany(x, y) (((x) + ((y) - 1)) / (y))
#define NBBY 8 /**< number of bits in a byte. */
#define NFDBITS (sizeof(unsigned long) * NBBY) /**< bits per mask */
#define _fdset_mask(n) ((unsigned long)1 << ((n) % NFDBITS))
typedef struct fd_set {
unsigned long fds_bits[howmany(FD_SETSIZE, NFDBITS)];
} fd_set;
#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= _fdset_mask(n)) /**< Add a fd to FD set. */
#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~_fdset_mask(n)) /**< Remove fd from FD set. */
#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & _fdset_mask(n)) /**< Check if the fd is set in FD set. */
#define FD_ZERO(p) memset(p, 0, sizeof(*(p))) /**< Clear FD set. */
#endif
#ifndef SHUT_RD
#define SHUT_RD 1
#define SHUT_WR 2
#define SHUT_RDWR 3
#endif
#define MAX_TCP_CLIENT_PER_SERVER 5
/** @defgroup MICO_SOCKET_GROUP_1 MICO BSD-like Socket Functions
* @brief Provide basic APIs for socket function
* @{
*/
/**
* @brief Create an endpoint for communication
* @attention Never doing operations on one socket in different MICO threads
* @param domain: Specifies a communication domain; this selects the protocol
* family which will be used for communication.
* This parameter can be one value:
* @arg AF_INET: IPv4 Internet protocols.
* @param type: Specifies the communication semantics.
* This parameter can be one of the following values:
* @arg SOCK_STREAM: Provides sequenced, reliable, two-way,
* connection-based byte streams. An out-of-band data
* transmission mechanism may be supported. (TCP)
* @arg SOCK_DGRAM: Supports datagrams (connectionless, unreliable
* messages of a fixed maximum length).(UDP)
* @param protocol: specifies a particular protocol to be used with the socket.
* This parameter can be one of the following values:
* @arg IPPROTO_TCP: TCP protocol
* @arg IPPROTO_UDP: UDP protocol
* @retval On success, a file descriptor for the new socket is returned.
On error, -1 is returned.
*/
int socket(int domain, int type, int protocol);
/**
* @brief Set options on sockets
* @attention Never doing operations on one socket in different MICO threads
* @param socket: A file descriptor
* @param level: This parameter can be : IPPROTO_IP, SOL_SOCKET, IPPROTO_TCP, IPPROTO_UDP
* @param optname: This parameter is defined in SOCK_OPT_VAL
* @param optval: address of buffer in which the value for the requested option(s)
* are to be set.
* @param optlen: containing the size of the buffer pointed to by optval
* @retval On success, zero is returned. On error, -1 is returned.
*/
int setsockopt (int socket, int level, int optname, void *optval, socklen_t optlen);
/**
* @brief Get options on sockets
* @attention Never doing operations on one socket in different MICO threads
* @param socket: A file descriptor
* @param level: This parameter can be : IPPROTO_IP, SOL_SOCKET, IPPROTO_TCP, IPPROTO_UDP
* @param optname: This parameter is defined in SOCK_OPT_VAL
* @param optval: address of buffer in which the value for the requested option(s)
* are to be returned.
* @param optlen_ptr: This is a value-result argument, initially containing the size
* of the buffer pointed to by optval, and modified on return to indicate
* the actual size of the value returned.
* @retval On success, zero is returned. On error, -1 is returned.
*/
int getsockopt (int socket, int level, int optname, void *optval, socklen_t *optlen_ptr);
/**
* @brief bind a name to a socket
* @attention Never doing operations on one socket in different MICO threads
* @note Assigns the address specified by addr to the socket referred to by the file
* descriptor socket.
* @param socket: A file descriptor
* @param addr: Point to the target address to be binded
* @param length: This parameter containing the size of the buffer pointed to by addr
* @retval On success, zero is returned. On error, -1 is returned.
*/
int bind (int socket, struct sockaddr *addr, socklen_t length);
/**
* @brief Initiate a connection on a socket
* @attention Never doing operations on one socket in different MICO threads
* @details The connect() system call connects the socket referred to by the file
* descriptor socket to the address specified by addr.
* @param socket: A file descriptor
* @param addr: Point to the target address to be binded
* @param length: This parameter containing the size of the buffer pointed to by addr
* @retval On success, zero is returned. On error, -1 is returned.
*/
int connect (int socket, struct sockaddr *addr, socklen_t length);
/**
* @brief Listen for connections on a socket
* @attention Never doing operations on one socket in different MICO threads
* @details listen() marks the socket referred to by socket as a passive socket,
* that is, as a socket that will be used to accept incoming connection
* requests using accept().
* @param socket: a file descriptor.
* @param n: Defines the maximum length to which the queue of pending
* connections for socket may grow. This parameter is not used in MICO,
* use 0 is fine.
* @retval On success, zero is returned. On error, -1 is returned.
*/
int listen (int socket, int n);
/**
* @brief Accept a connection on a socket
* @attention Never doing operations on one socket in different MICO threads
* @details The accept() system call is used with connection-based socket types
* (SOCK_STREAM). It extracts the first connection request on the queue
* of pending connections for the listening socket, sockfd, creates a
* new connected socket, and returns a new file descriptor referring to
* that socket. The newly created socket is not in the listening state.
* The original socket socket is unaffected by this call.
* @param socket: A file descriptor.
* @param addr: Point to the buffer to store the address of the accepted client.
* @param length_ptr: This parameter containing the size of the buffer pointed to
* by addr.
* @retval On success, zero is returned. On error, -1 is returned.
*/
int accept (int socket, struct sockaddr *addr, socklen_t *length_ptr);
/**
* @brief Monitor multiple file descriptors, waiting until one or more of the
* file descriptors become "ready" for some class of I/O operation
* (e.g., input possible).
* @attention Never doing operations on one socket in different MICO threads
* @note A file descriptor is considered ready if it is possible to perform
* the corresponding I/O operation (e.g., read()) without blocking.
* @param nfds: is the highest-numbered file descriptor in any of the three
* sets, plus 1. In MICO, the mount of file descriptors is fewer, so
* MICO use the MAX number of these file descriptors inside, and this
* parameter is cared.
* @param readfds: A file descriptor sets will be watched to see if characters
* become available for reading
* @param writefds: A file descriptor sets will be watched to see if a write
* will not block.
* @param exceptfds: A file descriptor sets will be watched for exceptions.
* @param timeout: The timeout argument specifies the interval that select()
* should block waiting for a file descriptor to become ready.
* If timeout is NULL (no timeout), select() can block indefinitely.
* @retval On success, return the number of file descriptors contained in the
* three returned descriptor sets (that is, the total number of bits
* that are set in readfds, writefds, exceptfds) which may be zero if
* the timeout expires before anything interesting happens. On error,
* -1 is returned, the file descriptor sets are unmodified, and timeout
* becomes undefined.
*/
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
int poll(struct pollfd *fds, int nfds, int timeout);
/**
* @brief Send a message on a socket
* @attention Never doing operations on one socket in different MICO threads
* @details The send() call may be used only when the socket is in a connected
* state (so that the intended recipient is known). The only difference
* between send() and write() is the presence of flags. With a zero
* flags argument, send() is equivalent to write().
* @note When the message does not fit into the send buffer of the socket,
* send() normally blocks, unless the socket has been placed in
* nonblocking I/O mode. In nonblocking mode it would fail. The select()
* call may be used to determine when it is possible to send more data.
* @param socket: A file descriptor.
* @param buffer: Point to the send data buffer.
* @param size: Length of the send data buffer.
* @param flags: Zero in MICO.
* @retval On success, these calls return the number of bytes sent. On error,
* -1 is returned,
*/
int send (int socket, const void *buffer, size_t size, int flags);
/**
* @brief Send a message on a socket
* @attention Never doing operations on one socket in different MICO threads
* @note Refer send() for details.
*/
ssize_t write (int filedes, const void *buffer, size_t size);
/**
* @brief Send a message on a socket to a specific target address.
* @attention Never doing operations on one socket in different MICO threads
* @details Refer send() for details. If sendto() is used on a connection-mode
* (SOCK_STREAM, SOCK_SEQPACKET) socket, the arguments dest_addr and
* addrlen are ignored. Otherwise, the address of the target is given by
* dest_addr with addrlen specifying its size.
* @param socket: Refer send() for details.
* @param buffer: Refer send() for details.
* @param size: Refer send() for details.
* @param flags: Refer send() for details.
* @param addr: Point to the target address.
* @param length: This parameter containing the size of the buffer pointed to
* by addr.
* @retval On success, these calls return the number of bytes sent. On error,
* -1 is returned,
*/
int sendto (int socket, const void *buffer, size_t size, int flags, const struct sockaddr *addr, socklen_t length);
/**
* @brief Receive a message from a socket.
* @attention Never doing operations on one socket in different MICO threads
* @details If no messages are available at the socket, the receive calls wait
* for a message to arrive, unless the socket is nonblocking, in
* which case the value -1 is returned. The receive calls normally
* return any data available, up to the requested amount, rather than
* waiting for receipt of the full amount requested.
* @param socket: A file descriptor.
* @param buffer: Point to the send data buffer.
* @param size: Length of the send data buffer.
* @param flags: Zero in MICO.
* @retval These calls return the number of bytes received, or -1 if an error
* occurred.
* When a stream socket peer has performed an orderly shutdown, the
* return value will be 0 (the traditional "end-of-file" return).
* The value 0 may also be returned if the requested number of bytes to
* receive from a stream socket was 0.
*/
int recv (int socket, void *buffer, size_t size, int flags);
/**
* @brief Receive a message from a socket.
* @attention Never doing operations on one socket in different MICO threads
* @note Refer recv() for details.
*/
ssize_t read (int filedes, void *buffer, size_t size);
/**
* @brief Receive a message from a socket and get the source address.
* @attention Never doing operations on one socket in different MICO threads
* @details If src_addr is not NULL, and the underlying protocol provides
* the source address of the message, that source address is placed
* in the buffer pointed to by src_addr. In this case, addrlen is
* a value-result argument. Before the call, it should be
* initialized to the size of the buffer associated with src_addr.
* Upon return, addrlen is updated to contain the actual size of
* the source address. The returned address is truncated if the
* buffer provided is too small; in this case, addrlen will return
* a value greater than was supplied to the call.
* If the caller is not interested in the source address, src_addr
* should be specified as NULL and addrlen should be specified as 0.
* @param sockfd: Refer recv() for details.
* @param buf: Refer recv() for details.
* @param len: Refer recv() for details.
* @param flags: Refer recv() for details.
* @param src_addr: Point to the buffer to store the source address.
* @param addrlen: This parameter containing the size of the buffer pointed to
* by src_addr.
* @retval These calls return the number of bytes received, or -1 if an
* error occurred.
* When a stream socket peer has performed an orderly shutdown, the
* return value will be 0 (the traditional "end-of-file" return).
* The value 0 may also be returned if the requested number of bytes to
* receive from a stream socket was 0.
*/
int recvfrom (int socket, void *buffer, size_t size, int flags, struct sockaddr *addr, socklen_t *length_ptr);
/**
* @brief Close a file descriptor.
* @attention Never doing operations on one socket in different MICO threads
* @details closes a file descriptor, so that it no longer refers to any
* file and may be reused.the resources associated with the
* open file description are freed.
* @param filedes: A file descriptor.
* @retval Returns zero on success. On error, -1 is returned.
*/
int close (int filedes);
int shutdown(int s, int how);
int ioctl(int s, long cmd, void *argp);
/**
* @}
*/
/** @defgroup MICO_SOCKET_GROUP_2 MICO Socket Tool Functions
* @brief Provide APIs for MiCO Socket Tool functions
* @{
*/
/**
* @brief converts the Internet host address from IPv4 numbers-and-dots
* notation into binary data in network byte order
* @note If the input is invalid, INADDR_NONE (usually -1) is returned.
* @param name: Internet host address from IPv4 numbers-and-dots.
* @retval Returns zero on success. On error, -1 is returned.
*/
uint32_t inet_addr (const char *name);
/**
* @brief Converts the Internet host address in, given in network byte
* order, to a string in IPv4 dotted-decimal notation.
* @note The returned string is stored in a given buffer, and the buffer
* size should larger than 16.
* @param s: Point to a buffer to store the returned string in IPv4
* dotted-decimal
* @param x: the Internet host address in.
* @retval Returns the same value as param s.
*/
extern char *inet_ntoa (struct in_addr addr);
/** @brief Get the IP address from a host name.
*
* @note Different to stand BSD function type, this function in MICO do
* not return a buffer that contain the result, but write the result
* to a buffer provided by application. Also this function simplify
* the return value compared to the standard BSD version.
* This functon runs under block mode.
*
* @param name: This parameter is either a hostname, or an IPv4 address in
* standard dot notation.
* @param addr: Point to a buffer to store the returned string in IPv4
* dotted-decimal
* @param addrLen: This parameter containing the size of the buffer pointed
* to by addr, 16 is recommended.
* @retval kNoerr or kGeneralErr
*/
struct hostent* gethostbyname(const char *name);
int getaddrinfo(const char *nodename,
const char *servname,
const struct addrinfo *hints,
struct addrinfo **res);
void freeaddrinfo(struct addrinfo *ai);
int getpeername (int s, struct sockaddr *name, socklen_t *namelen);
int getsockname (int s, struct sockaddr *name, socklen_t *namelen);
/** @brief Set TCP keep-alive mechanism parameters.
*
* @details When TCP data is not transimitting for a certain time (defined by seconds),
* MICO send keep-alive package over the TCP socket, and the remote device
* should return the keep-alive back to MICO. This is a basic TCP function
* deployed on every TCP/IP stack and application's interaction is not required.
* If the remote device doesn't return the keep-alive package, MICO add 1 to an
* internal counter, and close the current socket connection once this count has
* reached the maxErrNum (defined in parm: maxErrNum).
*
* @param inMaxErrNum: The max possible count that the remote device doesn't return the
* keep-alive package. If remote device returns, the internal count is cleared
* to 0.
* @param inSeconds: The time interval between two keep-alive package
*
* @retval kNoerr or kGeneralErr
*/
void set_tcp_keepalive(int inMaxErrNum, int inSeconds);
/** @brief Get TCP keep-alive mechanism parameters. Refer to @ref set_tcp_keepalive
*
* @param outMaxErrNum: Point to the address that store the maxErrNumber.
* @param outSeconds: Point to the address that store the time interval between two
* keep-alive package.
*
* @retval kNoerr or kGeneralErr
*/
void get_tcp_keepalive(int *outMaxErrNum, int *outSeconds);
/* SSL */
/** @brief Used to set the ssl protocol version for both ssl client and ssl server
*
* @note This function should be called before ssl is ready to function (before
* ssl_connect and ssl_accept is called by application ).
*
* @param version: SSL protocol version, Refer SSL_VERSION for details.
*
* @retval void
*/
void ssl_set_client_version( ssl_version_type_t version );
/** @brief Get the internal socket fire description
*
* @note This function should be called after ssl connection is established.
*
* @param ssl: SSL handler.
*
* @retval File descriptor for the SSL connection.
*/
int ssl_socket( mico_ssl_t ssl );
/** @brief Used by the SSL server. Set the certificate and private key for a SSL server.
*
* @details This function is called on the server side to set it's certifact and private key.
* It must be called before ssl_accept. These two arguments must be global
* string buffer, library will not create a copy for them.
*
* @param _cert_pem: Point to the certificate string in PEM format.
* @param private_key_pem: Point to the private key string in PEM format.
*
* @retval void
*/
void ssl_set_cert(const char *_cert_pem, const char *private_key_pem);
/** @brief SSL client create a SSL connection.
*
* @details This function is called on the client side and initiates an SSL/TLS handshake with a
* server. When this function is called, the underlying communication channel has already
* been set up. This function is called after TCP 3-way handshak finished.
*
* @param fd: The fd number for a connected TCP socket.
* @param calen: the string length of ca. 0=do not verify server's certificate.
* @param ca: pointer to the CA certificate string, used to verify server's certificate.
* @param errno: return the errno if ssl_connect return NULL.
*
* @retval return the SSL context pointer on success or NULL for fail.
*/
mico_ssl_t ssl_connect(int fd, int calen, char*ca, int *errno);
/** @brief SSL Server accept a SSL connection
*
* @param fd: The fd number for a connected TCP socket.
*
* @retval return the SSL context pointer on success or NULL for fail.
*/
mico_ssl_t ssl_accept(int fd);
/** @brief SSL send data
*
* @param ssl: Point to the SSL context.
* @param data: Point to send data.
* @param len: data length.
*
* @retval On success, these calls return the number of bytes sent. On error,
* -1 is returned,
*/
int ssl_send(mico_ssl_t ssl, void* data, size_t len);
/** @brief SSL receive data
*
* @param ssl: Point to the SSL context.
* @param data: Point to buffer to receive SSL data.
* @param len: max receive buffer length.
*
* @retval On success, these calls return the number of bytes received. On error,
* -1 is returned,
*/
int ssl_recv(mico_ssl_t ssl, void* data, size_t len);
/** @brief Close the SSL session, release resource.
*
* @param ssl: Point to the SSL context.
*
* @retval kNoerr or kGeneralErr
*/
int ssl_close(mico_ssl_t ssl);
int ssl_pending(void*ssl);
int ssl_get_error(void* ssl, int ret);
void ssl_set_using_nonblock(void* ssl, int nonblock);
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /*__MICO_SOCKET_H__*/

View file

@ -0,0 +1,754 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#if 0
#pragma once
#include "common.h"
#include "system.h"
#include "command_console/mico_cli.h"
#include "json_c/json.h"
#ifndef MICO_PREBUILT_LIBS
#include "mico_config.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
typedef system_state_t mico_system_state_t;
typedef system_config_t mico_Context_t;
typedef system_status_wlan_t mico_system_status_wlan_t;
/** @defgroup MICO_SYSTEM_APIs MICO System APIs
* @brief MiCO System provide a basic framework for application based on MiCO core APIs
* @{
*/
/** @addtogroup MICO_SYSTEM_APIs
* @{
*/
/** @defgroup System_General System General Tools
* @brief Read MiCO system's version
* @{
*/
/**
* @brief Read MiCO SDK version.
* @param major: Major version number.
* @param minor: Minor version number.
* @param revision: Revision nember.
* @retval kNoErr is returned on success, otherwise, kXXXErr is returned.
*/
void mico_sdk_version( uint8_t *major, uint8_t *minor, uint8_t *revision );
/**
* @brief Read MiCO Application information.
* @param p_info: Point to the memory to store the info.
* @param len_info: Size of the menory.
* @retval none.
*/
void mico_app_info(char *p_info, int len_info);
/** @} */
/** @defgroup system_context Core Data Functions
* @brief System core data management, should initialized before other system functions
* @{
*/
/* Parameter section store in flash */
typedef enum
{
PARA_BOOT_TABLE_SECTION,
PARA_MICO_DATA_SECTION,
#ifdef MICO_BLUETOOTH_ENABLE
PARA_BT_DATA_SECTION,
#endif
PARA_SYS_END_SECTION,
PARA_APP_DATA_SECTION,
PARA_END_SECTION
} para_section_t;
/**
* @brief Initialize core data used by MiCO system framework. System and
* application's configuration are read from non-volatile storage:
* flash etc.
* @param size_of_user_data: The length of config data used by application
* @retval Address of core data.
*/
void* mico_system_context_init( uint32_t size_of_user_data );
/**
* @brief Get the address of the core data.
* @param none
* @retval Address of core data.
*/
mico_Context_t* mico_system_context_get( void );
/**
* @brief Get the address of the application's config data.
* @param in_context: The address of the core data.
* @retval Address of the application's config data.
*/
void* mico_system_context_get_user_data( mico_Context_t* const in_context );
/**
* @brief Restore configurations to default settings, it will cause a delegate
* function: appRestoreDefault_callback( ) to give a default value for
* application's config data.
* @param in_context: The address of the core data.
* @retval kNoErr is returned on success, otherwise, kXXXErr is returned.
*/
OSStatus mico_system_context_restore( mico_Context_t* const in_context );
/**
* @brief Application should give a default value for application's config data
* on address: user_config_data
* @note This a delegate function, can be completed by developer.
* @param user_config_data: The address of the application's config data.
* @param size: The size of the application's config data.
* @retval None
*/
void appRestoreDefault_callback(void * const user_config_data, uint32_t size);
/**
* @brief Write config data hosted by core data to non-volatile storage
* @param in_context: The address of the core data.
* @retval kNoErr is returned on success, otherwise, kXXXErr is returned.
*/
OSStatus mico_system_context_update( mico_Context_t* const in_context );
OSStatus mico_system_para_read(void** info_ptr, int section, uint32_t offset, uint32_t size);
OSStatus mico_system_para_write(const void* info_ptr, int section, uint32_t offset, uint32_t size);
OSStatus mico_system_para_read_release( void* info_ptr );
/** @} */
/** @defgroup MiCO OTA Functions
* @brief MiCO firmware updation functions
* @{
*/
/**
* @brief Active downloaded firmware that stored in MICO_PARTITION_OTA_TEMP
* @param ota_data_len: the length of the new firmware
* @param ota_data_crc: the crc result of the new firmware
* @retval kNoErr is returned on success, otherwise, kXXXErr is returned.
*/
OSStatus mico_ota_switch_to_new_fw(int ota_data_len, uint16_t ota_data_crc);
/** @} */
/** @defgroup system System Framework Functions
* @brief Initialize MiCO system functions defined in mico_config.h
* @{
*/
/** @brief Wlan configuration source */
typedef enum{
CONFIG_BY_NONE, /**< Default value */
CONFIG_BY_EASYLINK_V2, /**< Wlan configured by EasyLink revision 2.0 */
CONFIG_BY_EASYLINK_PLUS, /**< Wlan configured by EasyLink Plus */
CONFIG_BY_EASYLINK_MINUS, /**< Wlan configured by EasyLink Minus */
CONFIG_BY_AIRKISS, /**< Wlan configured by airkiss from wechat Tencent inc. */
CONFIG_BY_SOFT_AP, /**< Wlan configured by EasyLink soft ap mode */
CONFIG_BY_WAC, /**< Wlan configured by wireless accessory configuration from Apple inc. */
CONFIG_BY_USER, /**< Wlan configured by user defined functions. */
} mico_config_source_t;
/**
* @brief Initialize MiCO system functions according to mico_config.h
* @param in_context: The address of the core data.
* @retval kNoErr is returned on success, otherwise, kXXXErr is returned.
*/
OSStatus mico_system_init( mico_Context_t* const in_context );
/**
* @brief Get IP, MAC, driver info for wlan interface
* @param status: The memory to store wlan status's address.
* @retval kNoErr is returned on success, otherwise, kXXXErr is returned.
*/
OSStatus mico_system_wlan_get_status( mico_system_status_wlan_t** status );
/**
* @brief Start wlan configuration mode, EasyLink, SoftAP, Airkiss...
* according to macro: MICO_WLAN_CONFIG_MODE
* @retval kNoErr is returned on success, otherwise, kXXXErr is returned.
*/
OSStatus mico_system_wlan_start_autoconf( void );
/**
* @brief Inform the application that EasyLink configuration will start
* @note This a delegate function, can be completed by developer.
* @retval None
*/
void mico_system_delegate_config_will_start( void );
/**
* @brief Inform the application that EasyLink configuration will stop
* @note This a delegate function, can be completed by developer.
* @retval None
*/
void mico_system_delegate_config_will_stop( void );
/**
* @brief Inform the application that EasyLink soft ap mode will start
* @note This a delegate function, can be completed by developer.
* @retval None
*/
void mico_system_delegate_soft_ap_will_start( void );
/**
* @brief Inform the application that ssid and key are received from
* EasyLink client
* @note This a delegate function, can be completed by developer.
* @param ssid: The address of the SSID string.
* @param key: The address of the Key string.
* @retval None
*/
void mico_system_delegate_config_recv_ssid ( char *ssid, char *key );
/**
* @brief Inform the application that auth data has received from
* EasyLink client
* @note This a delegate function, can be completed by developer.
* @param userInfo: Authentication data string.
* @retval kNoErr is returned on success, otherwise, kXXXErr is returned.
*/
OSStatus mico_system_delegate_config_recv_auth_data( char * userInfo );
/**
* @brief Inform the application that Easylink configuration is success.
* (MiCO has connect to wlan with the ssid and key)
* @note This a delegate function, can be completed by developer.
* @param source: The configuration mode used by EasyLink client
* @retval None
*/
void mico_system_delegate_config_success( mico_config_source_t source );
/** @} */
/** @defgroup system_monitor System Monitor Functions
* @brief Create monitors in MiCO. Monitors should be updated periodically,
* if not, a system reboot will perform.
* @{
*/
/** @brief Structure to hold information about a system monitor item
* Application should not destroy or modify a system monitor item
*/
typedef struct _mico_system_monitor_t
{
uint32_t last_update; /**< Time of the last system monitor update */
uint32_t longest_permitted_delay; /**< Longest permitted delay between checkins with the system monitor */
} mico_system_monitor_t;
/**
* @brief Start the system monitor daemon
* @note This function can be called automatically by mico_system_init( )
* if macro: MICO_SYSTEM_MONITOR_ENABLE is defined
* @retval None
*/
OSStatus mico_system_monitor_daemen_start( void );
/**
* @brief Register a system monitor point
* @param system_monitor: The address of a system monitor item.
* @param initial_permitted_delay: Longest permitted delay between checkins with the system monitor.
* @retval kNoErr is returned on success, otherwise, kXXXErr is returned.
*/
OSStatus mico_system_monitor_register( mico_system_monitor_t* system_monitor, uint32_t initial_permitted_delay );
/**
* @brief Perform a system monitor point checkin
* @param system_monitor: The address of a system monitor item.
* @param permitted_delay: The next permitted delay on the next checkin with the system monitor.
* @retval kNoErr is returned on success, otherwise, kXXXErr is returned.
*/
OSStatus mico_system_monitor_update ( mico_system_monitor_t* system_monitor, uint32_t permitted_delay );
/**
*
@}
*/
/** @defgroup system_power System Power Management Functions
* @brief Perform a safety power status change on MiCO.
* @{
*/
/**
* @brief Perform a system power change.
* @note This function can be used only after power management daemon is started
* @param in_context: The address of the core data.
* @retval kNoErr is returned on success, otherwise, kXXXErr is returned.
*/
OSStatus mico_system_power_perform( mico_Context_t* const in_context, mico_system_state_t new_state );
/** @} */
/*****************************************************************************/
/** @defgroup system_notify System Notify Functions
* @brief Register a user function to a MiCO notification, this function will
* be called when a MiCO notification is triggered
* @{
*/
/*****************************************************************************/
typedef notify_wlan_t WiFiEvent;
/** @brief MICO system defined notifications */
typedef enum{
mico_notify_WIFI_SCAN_COMPLETED, /**< A wlan scan is completed, type: void (*function)(ScanResult *pApList, void* arg)*/
mico_notify_WIFI_STATUS_CHANGED, /**< Wlan connection status is changed, type: void (*function)(WiFiEvent status, void* arg)*/
mico_notify_WiFI_PARA_CHANGED, /**< Wlan parameters has received (channel, BSSID, key...), called when connect to a wlan, type: void (*function)(apinfo_adv_t *ap_info, char *key, int key_len, void* arg)*/
mico_notify_DHCP_COMPLETED, /**< MiCO has get the IP address from DHCP server, type: void (*function)(IPStatusTypedef *pnet, void* arg)*/
mico_notify_EASYLINK_WPS_COMPLETED, /**< EasyLink receive SSID, Key, type: void (*function)(network_InitTypeDef_st *nwkpara, void* arg)*/
mico_notify_EASYLINK_GET_EXTRA_DATA, /**< EasyLink receive extra data, type: void (*function)(int datalen, char*data, void* arg)*/
mico_notify_TCP_CLIENT_CONNECTED, /**< A tcp client has connected to TCP server, type: void (*function)(int fd, void* arg)*/
mico_notify_DNS_RESOLVE_COMPLETED, /**< A DNS host address has resolved, type: void (*function)(uint8_t *hostname, uint32_t ip, void* arg)*/
mico_notify_SYS_WILL_POWER_OFF, /**< System power will be turned off, type: void (*function)(void* arg)*/
mico_notify_WIFI_CONNECT_FAILED, /**< A wlan connection attemption is failed, type: void join_fail(OSStatus err, void* arg)*/
mico_notify_WIFI_SCAN_ADV_COMPLETED, /**< A anvanced wlan scan is completed, type: void (*function)(ScanResult_adv *pApList, void* arg)*/
mico_notify_WIFI_Fatal_ERROR, /**< A fatal error occured when communicating with wlan sub-system, type: void (*function)(void* arg)*/
mico_notify_Stack_Overflow_ERROR, /**< A MiCO RTOS thread's stack is over-flowed, type: void (*function)(char *taskname, void* arg)*/
} mico_notify_types_t;
/**
* @brief Register a user function to a MiCO notification.
* @param notify_type: The type of MiCO notification.
* @param functionAddress: The address of user function.
* @param arg: The address of argument, which will be called by registered user function.
* @retval kNoErr is returned on success, otherwise, kXXXErr is returned.
*/
OSStatus mico_system_notify_register( mico_notify_types_t notify_type, void* functionAddress, void* arg );
/**
* @brief Remove a user function from a MiCO notification.
* @param notify_type: The type of MiCO notification.
* @param functionAddress: The address of user function.
* @retval kNoErr is returned on success, otherwise, kXXXErr is returned.
*/
OSStatus mico_system_notify_remove( mico_notify_types_t notify_type, void *functionAddress );
/**
* @brief Remove all user function from a MiCO notification.
* @param notify_type: The type of MiCO notification.
* @retval kNoErr is returned on success, otherwise, kXXXErr is returned.
*/
OSStatus mico_system_notify_remove_all( mico_notify_types_t notify_type);
/** @} */
/** @defgroup config_server System Config Server Daemon
* @brief Local network service, used to change MiCO system's configurations
* @{
*/
/**
* @brief Start local config server.
* @note This function can be called automatically by mico_system_init( )
* if macro: MICO_CONFIG_SERVER_ENABLE is defined.
* @param in_context: The address of the core data.
* @retval kNoErr is returned on success, otherwise, kXXXErr is returned.
*/
OSStatus config_server_start ( void );
/**
* @brief Stop local config server.
* @retval kNoErr is returned on success, otherwise, kXXXErr is returned.
*/
OSStatus config_server_stop ( void );
/**
* @brief Inform the application that configuration data is received from
* config client
* @note This a delegate function, can be completed by developer.
* @param key: The name of a configuration item.
* @param value: The value of a configuration item, can be read use a json_object_get_xxx
* function from json_c library.
* @param in_context: The address of the core data.
* @retval None.
*/
void config_server_delegate_recv( const char *key, json_object *value, bool *need_reboot, mico_Context_t *in_context );
/**
* @brief Inform the application that configuration server is collecting application's config data
* @note This a delegate function, can be completed by developer.
* @param config_cell_list: The UI element container to store application's config data.
* Developer can use config_server_create_xxx_cell functions to add customized UI element
* to config_cell_list.
* @param in_context: The address of the core data.
* @retval None.
*/
void config_server_delegate_report( json_object *config_cell_list, mico_Context_t *in_context );
/**
* @brief Add a cell UI holds a string value. config_cell_list(1)<=config_cell(1).
* @param config_cell_list: The config cell container.
* @param name: String indicate the name of a config data.
* @param content: String value of a config data.
* @param privilege: The privilege of a value on config client.
* @arg "RO": Read only. @arg "RW": Read or write.
* @param secectionArray: Generate a selection list for possible value, input NULL if not exist
* @retval kNoErr is returned on success, otherwise, kXXXErr is returned.
*/
OSStatus config_server_create_string_cell (json_object* config_cell_list, char* const name, char* const content, char* const privilege, json_object* secectionArray);
/**
* @brief Add a cell UI holds a integer value. config_cell_list(1)<=config_cell(1).
* @param config_cell_list: The config cell container.
* @param name: String indicate the name of a config data.
* @param content: Integer value of a config data.
* @param privilege: The privilege of a value on config client.
* @arg "RO": Read only. @arg "RW": Read or write.
* @param secectionArray: Generate a selection list for possible value, input NULL if not exist
* @retval kNoErr is returned on success, otherwise, kXXXErr is returned.
*/
OSStatus config_server_create_number_cell (json_object* config_cell_list, char* const name, int content, char* const privilege, json_object* secectionArray);
/**
* @brief Add a cell UI holds a float value. config_cell_list(1)<=config_cell(1).
* @param config_cell_list: The config cell container.
* @param name: String indicate the name of a config data.
* @param content: Float value of a config data.
* @param privilege: The privilege of a value on config client.
* @arg "RO": Read only. @arg "RW": Read or write.
* @param secectionArray: Generate a selection list for possible value
* @retval kNoErr is returned on success, otherwise, kXXXErr is returned.
*/
OSStatus config_server_create_float_cell (json_object* config_cell_list, char* const name, float content, char* const privilege, json_object* secectionArray);
/**
* @brief Add a cell UI holds a bool value. config_cell_list(1)<=config_cell(1).
* @param config_cell_list: The config cell container.
* @param name: String indicate the name of a config data.
* @param content: Bool value of a config data.
* @param privilege: The privilege of a value on config client.
* @arg "RO": Read only. @arg "RW": Read or write.
* @param secectionArray: Generate a selection list for possible value
* @retval kNoErr is returned on success, otherwise, kXXXErr is returned.
*/
OSStatus config_server_create_bool_cell (json_object* config_cell_list, char* const name, boolean content, char* const privilege);
/**
* @brief Add a cell UI holds a sub menu, config_cell_list(1)<=sub_menu_array(1).
* @param config_cell_list: The config cell container.
* @param name: String indicate the name of a sub menu.
* @param sub_menu_array: An array that buids a sub menu list.
* @retval kNoErr is returned on success, otherwise, kXXXErr is returned.
*/
OSStatus config_server_create_sub_menu_cell (json_object* config_cell_list, char* const name, json_object* sub_menu_array);
/**
* @brief Create a new config cell list to an exist menu. sub_menu_array(1)<=config_cell_list(n)
* @param sub_menu_array: An array that buids a sub menu list.
* @param name: String indicate the name of a config cell list.
* @param config_cell_list: The config cell container.
* @retval kNoErr is returned on success, otherwise, kXXXErr is returned.
*/
OSStatus config_server_create_sector (json_object* sub_menu_array, char* const name, json_object *config_cell_list);
/** @} */
/** \defgroup cli System Command Line Interface
* @brief MiCO command console
* @{
*/
/**
* @brief Initialize the CLI module
* @note This function can be called automatically by mico_system_init( )
* if macro: MICO_CLI_ENABLE is defined.
* @retval 0 is returned on success, otherwise, -1 is returned.
*/
//int cli_init(void);
/** @} */
/** @defgroup system_mdns System mDNS service functions
* @brief Multicast DNS is a way of using familiar DNS programming interfaces,
* packet formats and operating semantics, in a small network.
* @{
*/
/** @brief Structure to store mDNS record data
*/
enum mdns_record_state_e{
RECORD_REMOVED, /**< The service and resources are removed. */
RECORD_UPDATE, /**< The service record is updating, mdns routine will announce the new service content. */
RECORD_REMOVE, /**< The service record is removing, mdns routine will announce the service with TTL = 0 for
1 second, resources will be removed after the announce period */
RECORD_SUSPEND, /**< The service record is suspended, mdns routine will announce the service with TTL = 0 for
1 second and not respond the mdns query. */
RECORD_NORMAL, /**< The service can respond to mdns query . */
};
typedef uint8_t mdns_record_state_t;
typedef struct _mdns_init_t
{
char *service_name; /**< The service name of a mDNS record, example: "_easylink_config._tcp.local." */
char *host_name; /**< The host name of a mDNS record, example: "device_name.local." */
char *instance_name; /**< The instance name of a mDNS record, example: "device_name" */
char *txt_record; /**< Txt record holds customized info, every info is seperated by '.',
the orginal '.' is replaced by "/.", example: "record/.1=1.record/.2=2/.3" */
uint16_t service_port; /**< Service port */
} mdns_init_t;
/**
* @brief Add a new mDNS record, a mDNS service daemon will be start if necessary
* @param record: mDNS record data.
* @param interface: Which network interface, the IP info will be read from when response a nDNS request.
* @param time_to_live: The TTL of a mDNS record.
* @retval kNoErr is returned on success, otherwise, kXXXErr is returned.
*/
OSStatus mdns_add_record( mdns_init_t record, hal_wifi_type_t interface, uint32_t time_to_live );
/**
* @brief Suspend a mDNS record, announce the TTL of this record equal to zero, and do not respond mDNS request
* @param service_name: The service name of a mDNS record. example: "_easylink_config._tcp.local."
* @param interface: Which network interface, the IP info will be read from when response a nDNS request.
* @param will_remove: Destory record info from memory after announced.
* @retval None.
*/
void mdns_suspend_record( char *service_name, hal_wifi_type_t interface, bool will_remove );
/**
* @brief Resume a suspended mDNS record, announce the TTL of this record to orginal value, and respond to following mDNS request
* @param service_name: The service name of a mDNS record. example: "_easylink_config._tcp.local."
* @param interface: Which network interface, the IP info will be read from when response a nDNS request.
* @retval None.
*/
void mdns_resume_record( char *service_name, hal_wifi_type_t interface );
/**
* @brief Update txt record with a new value
* @param service_name: The service name of a mDNS record. example: "_easylink_config._tcp.local."
* @param interface: Which network interface, the IP info will be read from when response a nDNS request.
* @param txt_record: Txt record holds customized info, every info is seperated by '.', the orginal '.' is
* replaced by "/.", example: "record/.1=1.record/.2=2/.3" = "record.1=1" and "record.2=2.3"
* @retval None.
*/
void mdns_update_txt_record( char *service_name, hal_wifi_type_t interface, char *txt_record );
/**
* @brief Get mdns service status
* @param service_name: The service name of a mDNS record. example: "_easylink_config._tcp.local."
* @param interface: network interface, the mdns service is bonded
* @retval @ref mdns_record_state_t.
*/
mdns_record_state_t mdns_get_record_status( char *service_name, hal_wifi_type_t interface);
/** @} */
/** @defgroup system_time MiCO System time functions
* @brief Functions to get and set the real-time-clock time.
* @{
*/
/** ISO8601 Time Structure
*/
#pragma pack(1)
typedef struct
{
char year[4]; /**< Year */
char dash1; /**< Dash1 */
char month[2]; /**< Month */
char dash2; /**< Dash2 */
char day[2]; /**< Day */
char T; /**< T */
char hour[2]; /**< Hour */
char colon1; /**< Colon1 */
char minute[2]; /**< Minute */
char colon2; /**< Colon2 */
char second[2]; /**< Second */
char decimal; /**< Decimal */
char sub_second[6]; /**< Sub-second */
char Z; /**< UTC timezone */
} iso8601_time_t;
#pragma pack()
/** Get the current system tick time in milliseconds
*
* @note The time will roll over every 49.7 days
*
* @param[out] time : A pointer to the variable which will receive the time value
*
* @return @ref OSStatus
*/
OSStatus mico_time_get_time( mico_time_t* time );
/** Set the current system tick time in milliseconds
*
* @param[in] time : the time value to set
*
* @return @ref OSStatus
*/
OSStatus mico_time_set_time( const mico_time_t* time );
/** Get the current UTC time in seconds
*
* This will only be accurate if the time has previously been set by using @ref mico_time_set_utc_time_ms
*
* @param[out] utc_time : A pointer to the variable which will receive the time value
*
* @return @ref OSStatus
*/
OSStatus mico_time_get_utc_time( mico_utc_time_t* utc_time );
/** Get the current UTC time in milliseconds
*
* This will only be accurate if the time has previously been set by using @ref mico_time_set_utc_time_ms
*
* @param[out] utc_time_ms : A pointer to the variable which will receive the time value
*
* @return @ref OSStatus
*/
OSStatus mico_time_get_utc_time_ms( mico_utc_time_ms_t* utc_time_ms );
/** Set the current UTC time in milliseconds
*
* @param[in] utc_time_ms : the time value to set
*
* @return @ref OSStatus
*/
OSStatus mico_time_set_utc_time_ms( const mico_utc_time_ms_t* utc_time_ms );
/** Get the current UTC time in iso 8601 format e.g. "2012-07-02T17:12:34.567890Z"
*
* @note The time will roll over every 49.7 days
*
* @param[out] iso8601_time : A pointer to the structure variable that
* will receive the time value
*
* @return @ref OSStatus
*/
OSStatus mico_time_get_iso8601_time( iso8601_time_t* iso8601_time );
/** Convert a time from UTC milliseconds to iso 8601 format e.g. "2012-07-02T17:12:34.567890Z"
*
* @param[in] utc_time_ms : the time value to convert
* @param[out] iso8601_time : A pointer to the structure variable that
* will receive the time value
*
* @return @ref OSStatus
*/
OSStatus mico_time_convert_utc_ms_to_iso8601( mico_utc_time_ms_t utc_time_ms, iso8601_time_t* iso8601_time );
#define MicoNanosendDelay mico_nanosecond_delay
/** Delay a period of time
*
* @param[in] delayus : the time value to set ( unit: nanosecond )
*
* @return none: this function will block until target time is reached
*/
void mico_nanosecond_delay( uint64_t delayus );
/** Get current nanosecond time
*
* @return current nanosecond time
*/
uint64_t mico_nanosecond_clock_value( void );
/** Set current nanosecond time to zero
*
* @return none
*/
void mico_nanosecond_reset( void );
/** Initialisse nanosecond counter function
*
* @return none
*/
void mico_nanosecond_init( void );
/** @} */
/** @defgroup tftp_ota Firmware Update From a TFTP Server
* @brief Provide an easy way to download firmware from tftp server, use a
* predefined wlan and server address. It is used under factory environment
* @{
*/
/**
* @brief Get new firmware from a TFTP Server, and replace the old one
* @retval None.
*/
void tftp_ota(void);
/** @} */
/** @} */
/** @} */
#ifdef __cplusplus
} /*extern "C" */
#endif
#else
#define MICO_BT_PARA_LOCAL_KEY_DATA 65 /* BTM_SECURITY_LOCAL_KEY_DATA_LEN */
#define MICO_BT_DCT_NAME 249
#define MICO_BT_DCT_MAX_KEYBLOBS 146 /* Maximum size of key blobs to be stored := size of BR-EDR link keys + size of BLE keys*/
#define MICO_BT_DCT_ADDR_FIELD 6
#define MICO_BT_DCT_LENGTH_FIELD 2
#ifndef MICO_BT_DCT_MAX_DEVICES
#define MICO_BT_DCT_MAX_DEVICES 10 /* Maximum number of device records stored in nvram */
#endif
#define MICO_BT_DCT_ADDR_TYPE 1
#define MICO_BT_DCT_DEVICE_TYPE 1
/* Length of BD_ADDR + 2bytes length field */
#define MICO_BT_DCT_ENTRY_HDR_LENGTH (MICO_BT_DCT_ADDR_FIELD + MICO_BT_DCT_LENGTH_FIELD + MICO_BT_DCT_ADDR_TYPE + MICO_BT_DCT_DEVICE_TYPE)
#define MICO_BT_DCT_LOCAL_KEY_OFFSET OFFSETOF( mico_bt_config_t, bluetooth_local_key )
#define MICO_BT_DCT_REMOTE_KEY_OFFSET OFFSETOF( mico_bt_config_t, bluetooth_remote_key )
#pragma pack(1)
typedef struct
{
// uint8_t bluetooth_local_addeess[6];
// uint8_t bluetooth_local_name[249]; /* including null termination */
uint8_t bluetooth_local_key[MICO_BT_PARA_LOCAL_KEY_DATA];
uint8_t bluetooth_remote_key[MICO_BT_DCT_ENTRY_HDR_LENGTH + MICO_BT_DCT_MAX_KEYBLOBS][MICO_BT_DCT_MAX_DEVICES];
uint8_t padding[1]; /* to ensure 32-bit aligned size */
} mico_bt_config_t;
#pragma pack()
#endif

View file

@ -0,0 +1,90 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#pragma once
#include <stddef.h>
#ifdef __cplusplus
extern "C"
{
#endif
/******************************************************
* Macros
******************************************************/
#ifndef WEAK
#ifndef __MINGW32__
#define WEAK __attribute__((weak))
#else
/* MinGW doesn't support weak */
#define WEAK
#endif
#endif
#ifndef USED
#define USED __attribute__((used))
#endif
#ifndef MAY_BE_UNUSED
#define MAY_BE_UNUSED __attribute__((unused))
#endif
#ifndef NORETURN
#define NORETURN __attribute__((noreturn))
#endif
#ifndef ALIGNED
#define ALIGNED(size) __attribute__((aligned(size)))
#endif
#ifndef SECTION
#define SECTION(name) __attribute__((section(name)))
#endif
#ifndef NEVER_INLINE
#define NEVER_INLINE __attribute__((noinline))
#endif
#ifndef ALWAYS_INLINE
#define ALWAYS_INLINE __attribute__((always_inline))
#endif
/******************************************************
* Constants
******************************************************/
/******************************************************
* Enumerations
******************************************************/
/******************************************************
* Type Definitions
******************************************************/
/******************************************************
* Structures
******************************************************/
/******************************************************
* Global Variables
******************************************************/
/******************************************************
* Function Declarations
******************************************************/
void *memrchr( const void *s, int c, size_t n );
/* Windows doesn't come with support for strlcpy */
#ifdef WIN32
size_t strlcpy (char *dest, const char *src, size_t size);
#endif /* WIN32 */
#ifdef __cplusplus
} /* extern "C" */
#endif

View file

@ -0,0 +1,595 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include <k_api.h>
#include <string.h>
#include <stdlib.h>
#include "mico_rtos.h"
#include "mico_rtos_common.h"
#include "common.h"
typedef struct
{
event_handler_t function;
void* arg;
} mico_event_message_t;
OSStatus mico_rtos_create_thread( mico_thread_t* thread, uint8_t priority, const char* name, mico_thread_function_t function, uint32_t stack_size, mico_thread_arg_t arg )
{
kstat_t ret;
ktask_t *task_tmp;
if (thread == NULL) {
ret = krhino_task_dyn_create(&task_tmp, name, (void *)arg, priority, 0, stack_size/4, (task_entry_t)function, 1);
} else {
ret = krhino_task_dyn_create((ktask_t **)thread, name, (void *)arg, priority, 0, stack_size/4, (task_entry_t)function, 1);
}
if (ret == RHINO_SUCCESS) {
return kNoErr;
}
return kGeneralErr;
}
OSStatus mico_rtos_delete_thread( mico_thread_t* thread )
{
kstat_t ret;
if (thread == NULL) {
ret = krhino_task_dyn_del(NULL);
} else {
ret = krhino_task_dyn_del(*((ktask_t **)thread));
}
if (ret == RHINO_SUCCESS) {
return kNoErr;
}
return kGeneralErr;
}
void mico_rtos_suspend_thread(mico_thread_t* thread)
{
if (thread == NULL) {
krhino_task_suspend(krhino_cur_task_get());
}
else {
krhino_task_suspend(*((ktask_t **)thread));
}
}
void mico_rtos_suspend_all_thread(void)
{
krhino_sched_disable();
}
long mico_rtos_resume_all_thread(void)
{
kstat_t ret;
ret = krhino_sched_enable();
if (ret == RHINO_SUCCESS) {
return kNoErr;
}
return kGeneralErr;
}
OSStatus mico_rtos_thread_join( mico_thread_t* thread )
{
return kNoErr;
}
OSStatus mico_rtos_thread_force_awake( mico_thread_t* thread )
{
kstat_t ret;
ret = krhino_task_wait_abort(*((ktask_t **)thread));
if (ret == RHINO_SUCCESS) {
return kNoErr;
}
return kGeneralErr;
}
bool mico_rtos_is_current_thread( mico_thread_t* thread )
{
ktask_t *t;
t = *((ktask_t **)thread);
if (t == krhino_cur_task_get()) {
return true;
}
return false;
}
OSStatus mico_rtos_delay_milliseconds( uint32_t num_ms )
{
uint32_t ticks;
ticks = krhino_ms_to_ticks(num_ms);
if (ticks == 0) {
ticks = 1;
}
krhino_task_sleep(ticks);
return kNoErr;
}
OSStatus mico_rtos_print_thread_status( char* pcWriteBuffer, int xWriteBufferLen )
{
pcWriteBuffer[0] = 'n';
pcWriteBuffer[1] = '\0';
(void)xWriteBufferLen;
return kNoErr;
}
OSStatus mico_rtos_init_semaphore( mico_semaphore_t* semaphore, int count )
{
kstat_t ret;
ret = krhino_sem_dyn_create((ksem_t **)semaphore, "sema", 0);
if (ret == RHINO_SUCCESS) {
return kNoErr;
}
return kGeneralErr;
}
OSStatus mico_rtos_set_semaphore( mico_semaphore_t* semaphore )
{
kstat_t ret;
ret = krhino_sem_give(*((ksem_t **)semaphore));
if (ret == RHINO_SUCCESS) {
return kNoErr;
}
return kGeneralErr;
}
OSStatus mico_rtos_get_semaphore( mico_semaphore_t* semaphore, uint32_t timeout_ms )
{
kstat_t ret;
tick_t ticks;
if (timeout_ms == MICO_NEVER_TIMEOUT) {
ret = krhino_sem_take(*((ksem_t **)semaphore), RHINO_WAIT_FOREVER);
}
else {
ticks = krhino_ms_to_ticks(timeout_ms);
ret = krhino_sem_take(*((ksem_t **)semaphore), ticks);
}
if (ret == RHINO_SUCCESS) {
return kNoErr;
}
return kGeneralErr;
}
OSStatus mico_rtos_deinit_semaphore( mico_semaphore_t* semaphore )
{
kstat_t ret;
ret = krhino_sem_dyn_del(*((ksem_t **)semaphore));
if (ret == RHINO_SUCCESS) {
return kNoErr;
}
return kGeneralErr;
}
OSStatus mico_rtos_init_mutex( mico_mutex_t* mutex )
{
kstat_t ret;
ret = krhino_mutex_dyn_create((kmutex_t **)mutex, "mutex");
if (ret == RHINO_SUCCESS) {
return kNoErr;
}
return kGeneralErr;
}
OSStatus mico_rtos_lock_mutex( mico_mutex_t* mutex )
{
kstat_t ret;
ret = krhino_mutex_lock(*((kmutex_t **)mutex), RHINO_WAIT_FOREVER);
if (ret == RHINO_SUCCESS) {
return kNoErr;
}
return kGeneralErr;
}
OSStatus mico_rtos_unlock_mutex( mico_mutex_t* mutex )
{
kstat_t ret;
ret = krhino_mutex_unlock(*((kmutex_t **)mutex));
if (ret == RHINO_SUCCESS) {
return kNoErr;
}
return kGeneralErr;
}
OSStatus mico_rtos_deinit_mutex( mico_mutex_t* mutex )
{
kstat_t ret;
ret = krhino_mutex_dyn_del(*((kmutex_t **)mutex));
if (ret == RHINO_SUCCESS) {
return kNoErr;
}
return kGeneralErr;
}
OSStatus mico_rtos_init_queue( mico_queue_t* queue, const char* name, uint32_t message_size, uint32_t number_of_messages )
{
kstat_t ret;
if (name == NULL) {
name = "default_queue";
}
ret = krhino_buf_queue_dyn_create((kbuf_queue_t **)queue, name, number_of_messages * (message_size + COMPRESS_LEN(message_size)), message_size);
if (ret == RHINO_SUCCESS) {
return kNoErr;
}
return kGeneralErr;
}
OSStatus mico_rtos_push_to_queue( mico_queue_t* queue, void* message, uint32_t timeout_ms )
{
kstat_t ret;
kbuf_queue_t *q = *((kbuf_queue_t **)queue);
timeout_ms = timeout_ms;
ret = krhino_buf_queue_send(q, message, q->max_msg_size);
if (ret == RHINO_SUCCESS) {
return kNoErr;
}
return kGeneralErr;
}
OSStatus mico_rtos_pop_from_queue( mico_queue_t* queue, void* message, uint32_t timeout_ms )
{
kstat_t ret;
size_t msg_len;
ret = krhino_buf_queue_recv(*((kbuf_queue_t **)queue), krhino_ms_to_ticks(timeout_ms), message, &msg_len);
if (ret == RHINO_SUCCESS) {
return kNoErr;
}
return kGeneralErr;
}
OSStatus mico_rtos_deinit_queue( mico_queue_t* queue )
{
kstat_t ret;
ret = krhino_buf_queue_dyn_del(*((kbuf_queue_t **)queue));
if (ret == RHINO_SUCCESS) {
return kNoErr;
}
return kGeneralErr;
}
bool mico_rtos_is_queue_empty( mico_queue_t* queue )
{
bool ret;
CPSR_ALLOC();
kbuf_queue_t *q = *((kbuf_queue_t **)queue);
RHINO_CRITICAL_ENTER();
if (q->cur_num == 0) {
ret = true;
}
else {
ret = false;;
}
RHINO_CRITICAL_EXIT();
return ret;
}
bool mico_rtos_is_queue_full( mico_queue_t* queue )
{
bool ret;
CPSR_ALLOC();
kbuf_queue_t *q = *((kbuf_queue_t **)queue);
uint32_t max_msg_num;
RHINO_CRITICAL_ENTER();
max_msg_num = (q->ringbuf.end - q->ringbuf.buf) / (q->max_msg_size + COMPRESS_LEN(q->max_msg_size));
if (q->cur_num == max_msg_num) {
ret = true;
}
else {
ret = false;
}
RHINO_CRITICAL_EXIT();
return ret;
}
mico_time_t mico_rtos_get_time( void )
{
return krhino_ticks_to_ms(krhino_sys_tick_get());
}
static void timmer_wrapper(void *timer, void *arg)
{
(void)timer;
mico_timer_t *timer_arg = arg;
if (timer_arg->function != 0) {
timer_arg->function(timer_arg->arg);
}
}
OSStatus mico_rtos_init_timer( mico_timer_t* timer, uint32_t time_ms, timer_handler_t function, void* arg )
{
kstat_t ret;
timer->function = function;
timer->arg = arg;
ret = krhino_timer_dyn_create((ktimer_t **)(&timer->handle),"timer", timmer_wrapper,
krhino_ms_to_ticks(time_ms), krhino_ms_to_ticks(time_ms), timer, 0);
if (ret == RHINO_SUCCESS) {
return kNoErr;
}
return kGeneralErr;
}
OSStatus mico_rtos_init_oneshot_timer( mico_timer_t* timer, uint32_t time_ms, timer_handler_t function, void* arg )
{
kstat_t ret;
timer->function = function;
timer->arg = arg;
ret = krhino_timer_dyn_create((ktimer_t **)(&timer->handle),"timer", timmer_wrapper,
krhino_ms_to_ticks(time_ms), 0, timer, 0);
if (ret == RHINO_SUCCESS) {
return kNoErr;
}
return kGeneralErr;
}
OSStatus mico_rtos_start_timer( mico_timer_t* timer )
{
kstat_t ret;
ret = krhino_timer_start((ktimer_t *)(timer->handle));
if (ret == RHINO_SUCCESS) {
return kNoErr;
}
return kGeneralErr;
}
OSStatus mico_rtos_stop_timer( mico_timer_t* timer )
{
kstat_t ret;
ret = krhino_timer_stop((ktimer_t *)(timer->handle));
if (ret == RHINO_SUCCESS) {
return kNoErr;
}
return kGeneralErr;
}
OSStatus mico_rtos_reload_timer( mico_timer_t* timer )
{
kstat_t ret;
krhino_timer_stop((ktimer_t *)(timer->handle));
ret = krhino_timer_start((ktimer_t *)(timer->handle));
if (ret == RHINO_SUCCESS) {
return kNoErr;
}
return kGeneralErr;
}
OSStatus mico_rtos_deinit_timer( mico_timer_t* timer )
{
kstat_t ret;
krhino_timer_stop((ktimer_t *)(timer->handle));
ret = krhino_timer_dyn_del((ktimer_t *)(timer->handle));
if (ret == RHINO_SUCCESS) {
return kNoErr;
}
return kGeneralErr;
}
bool mico_rtos_is_timer_running( mico_timer_t* timer )
{
ktimer_t *t;
t = (ktimer_t *)timer->handle;
if (t->timer_state == TIMER_ACTIVE) {
return true;
}
return false;
}
bool mico_rtos_is_timer_init( mico_timer_t* timer )
{
if (timer == NULL)
return false;
if (timer->handle == NULL)
return false;
return true;
}
static void worker_thread_main( uint32_t arg )
{
mico_worker_thread_t* worker_thread = (mico_worker_thread_t*) arg;
while ( 1 )
{
mico_event_message_t message;
if ( mico_rtos_pop_from_queue( &worker_thread->event_queue, &message, MICO_WAIT_FOREVER ) == kNoErr )
{
message.function( message.arg );
}
}
}
OSStatus mico_rtos_create_worker_thread( mico_worker_thread_t* worker_thread, uint8_t priority, uint32_t stack_size, uint32_t event_queue_size )
{
memset( worker_thread, 0, sizeof( *worker_thread ) );
if ( mico_rtos_init_queue( &worker_thread->event_queue, "worker queue", sizeof(mico_event_message_t), event_queue_size ) != kNoErr )
{
return kGeneralErr;
}
if ( mico_rtos_create_thread( &worker_thread->thread, priority , "worker thread", worker_thread_main, stack_size, (mico_thread_arg_t) worker_thread ) != kNoErr )
{
mico_rtos_deinit_queue( &worker_thread->event_queue );
return kGeneralErr;
}
return kNoErr;
}
OSStatus mico_rtos_delete_worker_thread( mico_worker_thread_t* worker_thread )
{
if ( mico_rtos_delete_thread( &worker_thread->thread ) != kNoErr )
{
return kGeneralErr;
}
if ( mico_rtos_deinit_queue( &worker_thread->event_queue ) != kNoErr )
{
return kGeneralErr;
}
return kNoErr;
}
OSStatus mico_rtos_send_asynchronous_event( mico_worker_thread_t* worker_thread, event_handler_t function, void* arg )
{
mico_event_message_t message;
if( worker_thread->thread == NULL )
return kNotInitializedErr;
message.function = function;
message.arg = arg;
return mico_rtos_push_to_queue( &worker_thread->event_queue, &message, MICO_NO_WAIT );
}
static void timed_event_handler( void* arg )
{
mico_timed_event_t* event_object = (mico_timed_event_t*) arg;
mico_event_message_t message;
message.function = event_object->function;
message.arg = event_object->arg;
mico_rtos_push_to_queue( &event_object->thread->event_queue, &message, MICO_NO_WAIT );
}
OSStatus mico_rtos_register_timed_event( mico_timed_event_t* event_object, mico_worker_thread_t* worker_thread, event_handler_t function, uint32_t time_ms, void* arg )
{
if( worker_thread->thread == NULL )
return kNotInitializedErr;
if ( mico_rtos_init_timer( &event_object->timer, time_ms, timed_event_handler, (void*) event_object ) != kNoErr )
{
return kGeneralErr;
}
event_object->function = function;
event_object->thread = worker_thread;
event_object->arg = arg;
if ( mico_rtos_start_timer( &event_object->timer ) != kNoErr )
{
mico_rtos_deinit_timer( &event_object->timer );
return kGeneralErr;
}
return kNoErr;
}
OSStatus mico_rtos_deregister_timed_event( mico_timed_event_t* event_object )
{
if ( mico_rtos_deinit_timer( &event_object->timer ) != kNoErr )
{
return kGeneralErr;
}
return kNoErr;
}

View file

@ -0,0 +1,29 @@
src = []
component = aos_component('vcall', src)
component.add_global_includes('mico/include')
if aos_global_config.arch == 'ARM968E-S':
component.add_cflags('-marm')
@pre_config('vcall')
def vcall_pre(comp):
vcall = aos_global_config.get('vcall', 'rhino')
if vcall == 'freertos':
comp.add_global_macros('VCALL_FREERTOS')
comp.add_sources('aos/aos_freertos.c')
elif vcall == 'posix':
comp.add_global_macros('VCALL_POSIX')
comp.add_sources('aos/aos_posix.c')
else:
comp.add_global_macros('VCALL_RHINO')
comp.add_comp_deps('kernel/rhino')
if aos_global_config.mcu_family == 'esp32' or aos_global_config.mcu_family == 'esp8266':
comp.add_comp_deps('kernel/vcall/espos')
if aos_global_config.board == 'linuxhost' or aos_global_config.board == 'mk3060' \
or aos_global_config.board == 'mk3239' or aos_global_config.board == 'mk3166' or aos_global_config.board == 'mk3165':
comp.add_sources('mico/mico_rhino.c')
comp.add_sources('aos/aos_rhino.c')
vcall_pre(component)

View file

@ -0,0 +1,54 @@
NAME := vcall
$(NAME)_TYPE := kernel
$(NAME)_MBINS_TYPE := share
GLOBAL_INCLUDES += ./mico/include
#default gcc
ifeq ($(COMPILER),)
$(NAME)_CFLAGS += -Wall -Werror
else ifeq ($(COMPILER),gcc)
$(NAME)_CFLAGS += -Wall -Werror
endif
ifeq ($(HOST_ARCH),ARM968E-S)
$(NAME)_CFLAGS += -marm
endif
vcall ?= rhino
ifeq ($(vcall),freertos)
GLOBAL_DEFINES += VCALL_FREERTOS
$(NAME)_SOURCES += \
aos/aos_freertos.c
endif
ifeq ($(vcall),posix)
GLOBAL_DEFINES += VCALL_POSIX
$(NAME)_SOURCES += \
aos/aos_posix.c
endif
ifeq ($(vcall),rhino)
GLOBAL_DEFINES += VCALL_RHINO
$(NAME)_COMPONENTS += rhino
ifeq ($(HOST_MCU_FAMILY),esp32)
$(NAME)_COMPONENTS += vcall.espos
else
ifeq ($(HOST_MCU_FAMILY),esp8266)
$(NAME)_COMPONENTS += vcall.espos
endif
endif
ifneq (,$(filter $(PLATFORM), linuxhost mk3060 mk3239 mk3166 mk3165))
$(NAME)_SOURCES += mico/mico_rhino.c
endif
$(NAME)_SOURCES += \
aos/aos_rhino.c
endif