From 741f8a0c4a7bdef9c5baf59e3214daf6f7f30422 Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Mon, 9 Apr 2018 19:40:29 +0800 Subject: [PATCH] feat(espos): Add espos component --- components/espos/component.mk | 4 + components/espos/include/arch/espos_arch.h | 20 ++ components/espos/include/arch/espos_esp8266.h | 57 +++ components/espos/include/espos_errno.h | 20 ++ components/espos/include/espos_mutex.h | 141 ++++++++ components/espos/include/espos_queue.h | 212 ++++++++++++ components/espos/include/espos_scheduler.h | 325 ++++++++++++++++++ components/espos/include/espos_semaphore.h | 118 +++++++ components/espos/include/espos_spinlock.h | 237 +++++++++++++ components/espos/include/espos_task.h | 214 ++++++++++++ components/espos/include/espos_time.h | 72 ++++ components/espos/include/espos_timer.h | 173 ++++++++++ components/espos/include/espos_types.h | 48 +++ .../espos/platform/freertos/espos_mutex.c | 210 +++++++++++ .../espos/platform/freertos/espos_queue.c | 233 +++++++++++++ .../espos/platform/freertos/espos_scheduler.c | 195 +++++++++++ .../espos/platform/freertos/espos_semaphore.c | 163 +++++++++ .../espos/platform/freertos/espos_task.c | 241 +++++++++++++ .../espos/platform/freertos/espos_time.c | 52 +++ .../espos/platform/freertos/espos_timer.c | 279 +++++++++++++++ 20 files changed, 3014 insertions(+) create mode 100644 components/espos/component.mk create mode 100644 components/espos/include/arch/espos_arch.h create mode 100644 components/espos/include/arch/espos_esp8266.h create mode 100644 components/espos/include/espos_errno.h create mode 100644 components/espos/include/espos_mutex.h create mode 100644 components/espos/include/espos_queue.h create mode 100644 components/espos/include/espos_scheduler.h create mode 100644 components/espos/include/espos_semaphore.h create mode 100644 components/espos/include/espos_spinlock.h create mode 100644 components/espos/include/espos_task.h create mode 100644 components/espos/include/espos_time.h create mode 100644 components/espos/include/espos_timer.h create mode 100644 components/espos/include/espos_types.h create mode 100644 components/espos/platform/freertos/espos_mutex.c create mode 100644 components/espos/platform/freertos/espos_queue.c create mode 100644 components/espos/platform/freertos/espos_scheduler.c create mode 100644 components/espos/platform/freertos/espos_semaphore.c create mode 100644 components/espos/platform/freertos/espos_task.c create mode 100644 components/espos/platform/freertos/espos_time.c create mode 100644 components/espos/platform/freertos/espos_timer.c diff --git a/components/espos/component.mk b/components/espos/component.mk new file mode 100644 index 00000000..510745da --- /dev/null +++ b/components/espos/component.mk @@ -0,0 +1,4 @@ +# +# Component Makefile +# +COMPONENT_SRCDIRS := platform/freertos diff --git a/components/espos/include/arch/espos_arch.h b/components/espos/include/arch/espos_arch.h new file mode 100644 index 00000000..dadd3230 --- /dev/null +++ b/components/espos/include/arch/espos_arch.h @@ -0,0 +1,20 @@ +// 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_ + +#include "espos_esp8266.h" + +#endif /* _ESPOS_ARCH_H_ */ diff --git a/components/espos/include/arch/espos_esp8266.h b/components/espos/include/arch/espos_esp8266.h new file mode 100644 index 00000000..5e5699a9 --- /dev/null +++ b/components/espos/include/arch/espos_esp8266.h @@ -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 + +#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 { + uintptr_t 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_ */ diff --git a/components/espos/include/espos_errno.h b/components/espos/include/espos_errno.h new file mode 100644 index 00000000..a82c124a --- /dev/null +++ b/components/espos/include/espos_errno.h @@ -0,0 +1,20 @@ +// 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_ERRNO_H_ +#define _ESPOS_ERRNO_H_ + +#include + +#endif /* _ESPOS_ERRNO_H_ */ diff --git a/components/espos/include/espos_mutex.h b/components/espos/include/espos_mutex.h new file mode 100644 index 00000000..05e6abad --- /dev/null +++ b/components/espos/include/espos_mutex.h @@ -0,0 +1,141 @@ +// 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_type_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_opt_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_mutex_type_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 /* _ESPOS_MUTEX_H_ */ diff --git a/components/espos/include/espos_queue.h b/components/espos/include/espos_queue.h new file mode 100644 index 00000000..163a5d13 --- /dev/null +++ b/components/espos/include/espos_queue.h @@ -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 /* _ESPOS_QUEUE_H_ */ diff --git a/components/espos/include/espos_scheduler.h b/components/espos/include/espos_scheduler.h new file mode 100644 index 00000000..b7747c9b --- /dev/null +++ b/components/espos/include/espos_scheduler.h @@ -0,0 +1,325 @@ +// 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 + +#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 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); + +#if ESPOS_PROCESSORS_NUM > 1u + +/** + * @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 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() + +#else + +/** + * @brief start ESPOS system CPU port + * + * @param port CPU port ID + * + * @return the result + * -ENODEV : no device + */ +static inline esp_err_t espos_start_port(int port) +{ + return -ENODEV; +} + +/** + * @brief declare espos critical temp data + */ +#define espos_declare_critical(t) espos_critical_t t + +/** + * @brief enter ESPOS system critical state + * + * @param sl no mean + * @param t critical state + * + * @return critical state temple variable(used by "espos_exit_critical") + */ +#define espos_enter_critical(t, sl) (t) = _espos_enter_critical(NULL) + +/** + * @brief exit ESPOS system critical state + * + * @param t critical state temple variable(created by "espos_enter_critical") + * @param sl no mean + * + * @return none + */ +#define espos_exit_critical(t, sl) _espos_exit_critical(NULL, t) + +/** + * @brief OS internal function enter ESPOS system critical state + * + * @param sl no mean + * @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(NULL) + +/** + * @brief OS internal function exit ESPOS system critical state + * + * @param t critical state temple variable(created by "espos_enter_critical") + * @param sl no mean + * + * @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(NULL, t); \ + espos_os_exit() + +#endif + +/** + * @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); + +size_t espos_get_free_heap_size(void); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/components/espos/include/espos_semaphore.h b/components/espos/include/espos_semaphore.h new file mode 100644 index 00000000..96f9badc --- /dev/null +++ b/components/espos/include/espos_semaphore.h @@ -0,0 +1,118 @@ +// 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 /* _ESPOS_SEMAPHORE_H_ */ diff --git a/components/espos/include/espos_spinlock.h b/components/espos/include/espos_spinlock.h new file mode 100644 index 00000000..7413e9ce --- /dev/null +++ b/components/espos/include/espos_spinlock.h @@ -0,0 +1,237 @@ +// 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 + +#if ESPOS_PROCESSORS_NUM > 1u + +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); + +#else + +typedef struct espos_spinlock { + espos_spinlock_arch_t lock; +} espos_spinlock_t; + +#define ESPOS_SPINLOCK_UNLOCK_INITIALIZER \ + { \ + ESPOS_SPINLOCK_ARCH_UNLOCK_INITIALIZER, \ + } + +#define ESPOS_DEFINE_SPINLOCK(l) + +#define ESPOS_DEFINE_STATIC_SPINLOCK(l) + +/** + * @brief create a spinlock + * + * @param spinlock spinlock handle point + * + * @return the result + * -ENODEV : no device + */ +static inline esp_err_t espos_spinlock_create (espos_spinlock_t *spinlock) +{ + return -ENODEV; +} + +/** + * @brief set a spinlock name + * + * @param spinlock spinlock handle + * @param name spinlock's name + * + * @return the result + * -ENODEV : no device + */ +static inline esp_err_t espos_spinlock_set_name(espos_spinlock_t *spinlock, const char *name) +{ + return -ENODEV; +} + +/** + * @brief spin to lock a spinlock until successfully + * + * @param spinlock spinlock handle + * + * @return the result + * -ENODEV : no device + */ +static inline esp_err_t espos_spinlock_lock(espos_spinlock_t *spinlock) +{ + return -ENODEV; +} + +/** + * @brief try to lock a spinlock + * + * @param spinlock spinlock handle + * + * @return the result + * -ENODEV : no device + */ +static inline esp_err_t espos_spinlock_trylock(espos_spinlock_t *spinlock) +{ + return -ENODEV; +} + +/** + * @brief get spinlock holder task handle + * + * @param spinlock spinlock handle + * + * @return none espos object + */ +static inline espos_task_t espos_spinlock_get_holder(espos_spinlock_t *spinlock) +{ + return ESPOS_OBJ_NONE; +} + +/** + * @brief unlock a spinlock + * + * @param spinlock spinlock handle + * + * @return the result + * -ENODEV : no device + */ +static inline esp_err_t espos_spinlock_unlock(espos_spinlock_t *spinlock) +{ + return -ENODEV; +} + +/** + * @brief delete a spinlock + * + * @param spinlock spinlock handle + * + * @return the result + * -ENODEV : no device + */ +static inline esp_err_t espos_spinlock_del(espos_spinlock_t *spinlock) +{ + return -ENODEV; +} + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _ESPOS_SPINLOCK_H_ */ diff --git a/components/espos/include/espos_task.h b/components/espos/include/espos_task.h new file mode 100644 index 00000000..fcb449a8 --- /dev/null +++ b/components/espos/include/espos_task.h @@ -0,0 +1,214 @@ +// 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 + +typedef enum espos_task_opt { + /* create task and start it automatically */ + ESPOS_TASK_CREATE_NORMAL = 0, + /* just create task and don't start it */ + ESPOS_TASK_CREATE_SILENCE, + + ESPOS_TASK_OPT_MAX +} espos_task_opt_t; + +/* task delete itself */ +#define ESPOS_TASK_DELETE_SELF 0 + +/* + * we should use a platform API instead of 'marco' + */ +#define ESPOS_TASK_PRIO_NUM espos_task_prio_num() + +/* 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_task_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); + +/** + * @brief get ESPOS task priority number + * + * @return ESPOS task priority number + */ +espos_size_t espos_task_prio_num(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _ESPOS_TASK_H_ */ diff --git a/components/espos/include/espos_time.h b/components/espos/include/espos_time.h new file mode 100644 index 00000000..6d8c4d91 --- /dev/null +++ b/components/espos/include/espos_time.h @@ -0,0 +1,72 @@ +// 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" + +#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 + +/** + * @brief get tick milliseconds per system tick + * + * @return current ticks + */ +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 /* _ESPOS_TIME_H_ */ diff --git a/components/espos/include/espos_timer.h b/components/espos/include/espos_timer.h new file mode 100644 index 00000000..7c24e9a1 --- /dev/null +++ b/components/espos/include/espos_timer.h @@ -0,0 +1,173 @@ +// 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 /* _ESPOS_TIMER_H_ */ diff --git a/components/espos/include/espos_types.h b/components/espos/include/espos_types.h new file mode 100644 index 00000000..5f78a910 --- /dev/null +++ b/components/espos/include/espos_types.h @@ -0,0 +1,48 @@ +// 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_TYPES_H_ +#define _ESPOS_TYPES_H_ + +#include +#include +#include + +#include "arch/espos_arch.h" + +#define ESPOS_OBJ_NONE 0 + +typedef uintptr_t espos_obj_t; + +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 /* _ESPOS_TYPES_H_ */ diff --git a/components/espos/platform/freertos/espos_mutex.c b/components/espos/platform/freertos/espos_mutex.c new file mode 100644 index 00000000..882bef88 --- /dev/null +++ b/components/espos/platform/freertos/espos_mutex.c @@ -0,0 +1,210 @@ +// 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 + +#include "freertos/FreeRTOS.h" +#include "freertos/semphr.h" +#include "freertos/task.h" + +#include "espos_mutex.h" +#include "espos_scheduler.h" + +/* real ESPOS mutex structure */ +typedef struct espos_mutex_os { + espos_opt_t opt; + SemaphoreHandle_t mutex; +} espos_mutex_os_t; + +/** + * @brief create a mutex + */ +esp_err_t espos_mutex_create ( + espos_mutex_t *mutex, + espos_mutex_type_opt_t opt +) +{ + esp_err_t ret; + espos_mutex_os_t *os_mutex; + + if (!mutex || (ESPOS_MUTEX_TYPE(opt) >= ESPOS_MUTEX_TYPE_MAX)) { + return -EINVAL; + } + + if (espos_in_isr() == true) { + return -EINTR; + } + + os_mutex = malloc(sizeof(espos_mutex_os_t)); + if (!os_mutex) { + return -ENOMEM; + } + + switch (ESPOS_MUTEX_TYPE(opt)) { + case ESPOS_MUTEX_NORMAL: + os_mutex->mutex = xSemaphoreCreateMutex(); + break; + case ESPOS_MUTEX_RECURSIVE: + os_mutex->mutex = xSemaphoreCreateRecursiveMutex(); + break; + default : + os_mutex->mutex = NULL; + break; + } + + if (os_mutex->mutex) { + ret = 0; + os_mutex->opt = opt; + *mutex = (espos_mutex_t)os_mutex; + } else { + free(os_mutex); + ret = -ENOMEM; + } + + return 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 +) +{ + esp_err_t ret; + espos_mutex_os_t *os_mutex = (espos_mutex_os_t *)mutex; + + if (!os_mutex) { + return -EINVAL; + } + + if (espos_in_isr() == true) { + return -EINTR; + } + + switch (ESPOS_MUTEX_TYPE(os_mutex->opt)) { + case ESPOS_MUTEX_NORMAL: + ret = xSemaphoreTake(os_mutex->mutex, wait_ticks); + break; + case ESPOS_MUTEX_RECURSIVE: + ret = xSemaphoreTakeRecursive(os_mutex->mutex, wait_ticks); + break; + default: + ret = -EINVAL; + break; + } + + if (ret == pdTRUE) { + ret = 0; + } else { + ret = -ETIMEDOUT; + } + + return ret; +} + +/** + * @brief unlock a mutex + */ +esp_err_t espos_mutex_unlock ( + espos_mutex_t mutex +) +{ + esp_err_t ret; + espos_mutex_os_t *os_mutex = (espos_mutex_os_t *)mutex; + + if (!os_mutex) { + return -EINVAL; + } + + if (espos_in_isr() == true) { + return -EINTR; + } + + if (xSemaphoreGetMutexHolder(os_mutex->mutex) != xTaskGetCurrentTaskHandle()) { + return -EPERM; + } + + switch (ESPOS_MUTEX_TYPE(os_mutex->opt)) { + case ESPOS_MUTEX_NORMAL: + ret = xSemaphoreGive(os_mutex->mutex); + break; + case ESPOS_MUTEX_RECURSIVE: + ret = xSemaphoreGiveRecursive(os_mutex->mutex); + break; + default: + ret = -EINVAL; + break; + } + + if (ret == pdTRUE) { + ret = 0; + } else { + ret = -EPERM; + } + + return ret; +} + +/** + * @brief get task handle whick lock the mutex + */ +espos_task_t espos_mutex_get_holder ( + espos_mutex_t mutex +) +{ + espos_task_t tmp; + espos_mutex_os_t *os_mutex = (espos_mutex_os_t *)mutex; + + if (!os_mutex) { + return -EINVAL; + } + + tmp = (espos_task_t)xSemaphoreGetMutexHolder(os_mutex->mutex); + + return tmp; +} + +/** + * @brief delete the mutex + */ +esp_err_t espos_mutex_del ( + espos_mutex_t mutex +) +{ + espos_mutex_os_t *os_mutex = (espos_mutex_os_t *)mutex; + + if (!os_mutex) { + return -EINVAL; + } + + if (espos_in_isr() == true) { + return -EINTR; + } + + vSemaphoreDelete(os_mutex->mutex); + free(os_mutex); + + return 0; +} + diff --git a/components/espos/platform/freertos/espos_queue.c b/components/espos/platform/freertos/espos_queue.c new file mode 100644 index 00000000..a6753c67 --- /dev/null +++ b/components/espos/platform/freertos/espos_queue.c @@ -0,0 +1,233 @@ +// 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 "freertos/FreeRTOS.h" +#include "freertos/queue.h" +#include "freertos/task.h" + +#include "espos_queue.h" +#include "espos_scheduler.h" + +#define portYIELD_FROM_ISR() taskYIELD() + +/** + * @brief create a queue + */ +esp_err_t espos_queue_create ( + espos_queue_t *queue, + espos_size_t msg_len, + espos_size_t queue_len +) +{ + esp_err_t ret; + QueueHandle_t os_queue; + + if (!queue || !msg_len || !queue_len) { + return -EINVAL; + } + + if (espos_in_isr() == true) { + return -EINTR; + } + + os_queue = xQueueCreate(queue_len, msg_len); + if (os_queue) { + ret = 0; + *queue = (espos_queue_t)os_queue; + } else { + ret = -ENOMEM; + } + + return 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 espos_queue_send_generic ( + espos_queue_t queue, + void *msg, + espos_tick_t wait_ticks, + espos_pos_t pos, + espos_opt_t opt +) +{ + esp_err_t ret; + QueueHandle_t os_queue = (QueueHandle_t)queue; + + if (!queue || !msg || pos >= ESPOS_QUEUE_POS_MAX + || opt >= ESPOS_QUEUE_SEND_OPT_MAX) { + return -EINVAL; + } + + if (espos_in_isr() == true) { + BaseType_t xHigherPrioritTaskWoken = pdFALSE; + + if (pos == ESPOS_QUEUE_SEND_FRONT) { + ret = xQueueSendToFrontFromISR(os_queue, msg, &xHigherPrioritTaskWoken); + } else if (pos == ESPOS_QUEUE_SEND_BACK) { + ret = xQueueSendToBackFromISR(os_queue, msg, &xHigherPrioritTaskWoken); + } else { + ret = pdFAIL; + } + + if (pdPASS == ret && pdTRUE == xHigherPrioritTaskWoken) { + portYIELD_FROM_ISR(); + } + + if (ret == pdPASS) { + ret = 0; + } else { + ret = -ETIMEDOUT; + } + } else { + if (pos == ESPOS_QUEUE_SEND_FRONT) { + ret = xQueueSendToFront(os_queue, msg, wait_ticks); + } else if (pos == ESPOS_QUEUE_SEND_BACK) { + ret = xQueueSendToBack(os_queue, msg, wait_ticks); + } else { + ret = pdFAIL; + } + + if (ret == pdPASS) { + ret = 0; + } else { + ret = -ETIMEDOUT; + } + } + + return 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 +) +{ + esp_err_t ret; + QueueHandle_t os_queue = (QueueHandle_t)queue; + + if (!os_queue || !msg || opt >= ESPOS_QUEUE_RECV_OPT_MAX) { + return -EINVAL; + } + + if (espos_in_isr() == true) { + BaseType_t xHigherPrioritTaskWoken = pdFALSE; + + ret = xQueueReceiveFromISR(os_queue, msg, &xHigherPrioritTaskWoken); + if (pdTRUE == ret && pdTRUE == xHigherPrioritTaskWoken) { + portYIELD_FROM_ISR(); + } + + if (ret == pdTRUE) { + ret = 0; + } else { + ret = -ETIMEDOUT; + } + } else { + ret = xQueueReceive(os_queue, msg, wait_ticks); + if (ret == pdTRUE) { + ret = 0; + } else { + ret = -ETIMEDOUT; + } + } + + return ret; + +} + +/** + * @brief get current message number of the queue + */ +espos_size_t espos_queue_msg_waiting(espos_queue_t queue) +{ + UBaseType_t num; + QueueHandle_t os_queue = (QueueHandle_t)queue; + + if (!os_queue) { + return 0; + } + + num = uxQueueMessagesWaiting(os_queue); + + return num; +} + +/** + * @brief reset the queue + */ +esp_err_t espos_queue_flush ( + espos_queue_t queue +) +{ + BaseType_t ret; + QueueHandle_t os_queue = (QueueHandle_t)queue; + + if (!os_queue) { + return -EINVAL; + } + + ret = xQueueReset(os_queue); + if (ret == pdTRUE) { + ret = 0; + } else { + ret = -EINVAL; + } + + return 0; +} + +/** + * @brief delete the queue + */ +esp_err_t espos_queue_del ( + espos_queue_t queue +) +{ + QueueHandle_t os_queue = (QueueHandle_t)queue; + + if (!os_queue) { + return -EINVAL; + } + + if (espos_in_isr() == true) { + return -EINTR; + } + + vQueueDelete(os_queue); + + return 0; +} + diff --git a/components/espos/platform/freertos/espos_scheduler.c b/components/espos/platform/freertos/espos_scheduler.c new file mode 100644 index 00000000..ff2f4edb --- /dev/null +++ b/components/espos/platform/freertos/espos_scheduler.c @@ -0,0 +1,195 @@ +// 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 +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/queue.h" +#include "freertos/task.h" + +#include "espos_scheduler.h" + +#define portYIELD_FROM_ISR() taskYIELD() + +static espos_size_t s_isr_nested_count[ESPOS_PROCESSORS_NUM]; +static espos_size_t s_os_nested_count[ESPOS_PROCESSORS_NUM]; +static espos_size_t s_critial_count[ESPOS_PROCESSORS_NUM]; +static espos_critical_t s_critical_state[ESPOS_PROCESSORS_NUM]; + +/** + * @brief initialize ESPOS system + */ +esp_err_t espos_init(void) +{ + return 0; +} + +/** + * @brief start ESPOS system + */ +esp_err_t espos_start(void) +{ + vTaskStartScheduler(); + + return 0; +} + +/** + * @brief get ESPOS system state + */ +espos_stat_t espos_sched_state_get(void) +{ + espos_stat_t state; + BaseType_t os_state = xTaskGetSchedulerState(); + + if (os_state == taskSCHEDULER_NOT_STARTED) { + state = ESPOS_IS_NOT_STARTED; + } else if (os_state == taskSCHEDULER_RUNNING) { + state = ESPOS_IS_RUNNING; + } else { + state = ESPOS_IS_SUSPENDED; + } + + return state; +} + +/** + * @brief check if the CPU is at ISR state + */ +bool espos_in_isr(void) +{ + extern char _xt_isr_status; + //return (s_isr_nested_count[espos_get_core_id()] > 0) ? true : false; + return _xt_isr_status == 0 ? false : true; +} + +/** + * @brief check if the function is at real OS internal fucntion + */ +bool espos_os_isr(void) +{ + return (s_os_nested_count[espos_get_core_id()] > 0) ? true : false; +} + +/** + * @brief enter ESPOS system critical state + */ +espos_critical_t _espos_enter_critical(espos_spinlock_t *spinlock) +{ + espos_critical_t tmp; + + tmp = espos_suspend_interrupt(); + + if (!s_critial_count[espos_get_core_id()]) + s_critical_state[espos_get_core_id()] = tmp; + s_critial_count[espos_get_core_id()]++; + +#ifdef CONFIG_ESPOS_SMP + if (espos_spinlock_get_holder(spinlock) != espos_task_get_current()) + espos_spinlock_lock(spinlock); +#else + //espos_preempt_suspend_local(); +#endif + + return tmp; +} + +/** + * @brief exit ESPOS system critical state + */ +void _espos_exit_critical(espos_spinlock_t *spinlock, espos_critical_t tmp) +{ +#ifdef CONFIG_ESPOS_SMP + espos_spinlock_unlock(spinlock); +#else + //espos_preempt_resume_local(); +#endif + + s_critial_count[espos_get_core_id()]--; + if (!s_critial_count[espos_get_core_id()]) { + espos_resume_interrupt( s_critical_state[espos_get_core_id()]); + } +} + + +/** +* @brief suspend the preempt and the current task will not be preempted +*/ +esp_err_t espos_preempt_suspend_local(void) +{ + vTaskSuspendAll(); + + return 0; +} + +/** + * @brief resume the preempt + */ +esp_err_t espos_preempt_resume_local(void) +{ + if (xTaskResumeAll() == 0) { + taskYIELD(); + } + + return 0; +} + +/** + * @brief enter system interrupt server, the function must be used after entering hardware interrupt + */ +esp_err_t espos_isr_enter (void) +{ + s_isr_nested_count[espos_get_core_id()]++; + + return 0; +} + +/** + * @brief exit system interrupt server, the function must be used before exiting hardware interrupt + */ +void espos_isr_exit(void) +{ + if (!s_isr_nested_count[espos_get_core_id()]) { + return ; + } + + s_isr_nested_count[espos_get_core_id()]--; + + return ; +} + +/** + * @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 ; +} diff --git a/components/espos/platform/freertos/espos_semaphore.c b/components/espos/platform/freertos/espos_semaphore.c new file mode 100644 index 00000000..3e4419a5 --- /dev/null +++ b/components/espos/platform/freertos/espos_semaphore.c @@ -0,0 +1,163 @@ +// 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 "freertos/FreeRTOS.h" +#include "freertos/semphr.h" +#include "freertos/task.h" + +#include "espos_semaphore.h" +#include "espos_scheduler.h" + +#define portYIELD_FROM_ISR() taskYIELD() + +/** + * @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 +) +{ + esp_err_t ret; + SemaphoreHandle_t os_mutex; + + if (!sem || !max_count) { + return -EINVAL; + } + + if (espos_in_isr() == true) { + return -EINTR; + } + + os_mutex = xSemaphoreCreateCounting(max_count, init_count); + if (os_mutex) { + ret = 0; + *sem = (espos_sem_t)os_mutex; + } else { + ret = -ENOMEM; + } + + return 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 +) +{ + esp_err_t ret; + SemaphoreHandle_t os_sem = (SemaphoreHandle_t)sem; + + if (!os_sem) { + return -EINVAL; + } + + if (espos_in_isr() == true) { + BaseType_t xHigherPrioritTaskWoken = pdFALSE; + + ret = xSemaphoreTakeFromISR(os_sem, &xHigherPrioritTaskWoken); + if (pdPASS == ret && pdTRUE == xHigherPrioritTaskWoken) { + portYIELD_FROM_ISR(); + } + + if (ret == pdPASS) { + ret = 0; + } else { + ret = -ETIMEDOUT; + } + } else { + ret = xSemaphoreTake(os_sem, wait_ticks); + if (ret == pdPASS) { + ret = 0; + } else { + ret = -ETIMEDOUT; + } + } + + return ret; +} + +/** + * @brief give up semaphore + */ +esp_err_t espos_sem_give ( + espos_sem_t sem +) +{ + BaseType_t ret; + SemaphoreHandle_t os_sem = (SemaphoreHandle_t)sem; + + if (!os_sem) { + return -EINVAL; + } + + if (espos_in_isr() == true) { + BaseType_t xHigherPrioritTaskWoken = pdFALSE; + + ret = xSemaphoreGiveFromISR(os_sem, &xHigherPrioritTaskWoken); + if (pdPASS == ret && pdTRUE == xHigherPrioritTaskWoken) { + portYIELD_FROM_ISR(); + } + + if (ret == pdPASS) { + ret = 0; + } else { + ret = -EAGAIN; + } + } else { + ret = xSemaphoreGive(os_sem); + if (ret == pdPASS) { + ret = 0; + } else { + ret = -EAGAIN; + } + } + + return ret; +} + +/** + * @brief delete the semaphore + */ +esp_err_t espos_sem_del ( + espos_sem_t sem +) +{ + SemaphoreHandle_t os_sem = (SemaphoreHandle_t)sem; + + if (!os_sem) { + return -EINVAL; + } + + if (espos_in_isr() == true) { + return -EINTR; + } + + vSemaphoreDelete(os_sem); + + return 0; +} + diff --git a/components/espos/platform/freertos/espos_task.c b/components/espos/platform/freertos/espos_task.c new file mode 100644 index 00000000..9d98054f --- /dev/null +++ b/components/espos/platform/freertos/espos_task.c @@ -0,0 +1,241 @@ +// 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 "freertos/FreeRTOS.h" +#include "freertos/task.h" + +#include "espos_task.h" +#include "espos_scheduler.h" + +#define portYIELD_FROM_ISR() taskYIELD() + +/** + * @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_task_opt_t opt, + espos_cpu_t cpu_id +) +{ + BaseType_t ret; + TaskHandle_t os_task; + + if (!task || !name || !stack_size || !entry) { + return -EINVAL; + } + + if (espos_in_isr() == true) { + return -EINTR; + } + + ret = xTaskCreate(entry, name, stack_size, arg, prio, &os_task); + if (ret == pdPASS) { + ret = 0; + + *task = (espos_task_t)os_task; + } else { + ret = -ENOMEM; + } + + return ret; +} + +/** + * @brief delete a task + */ +esp_err_t espos_task_del ( + espos_task_t task +) +{ + TaskHandle_t os_task = (TaskHandle_t)task; + + if (espos_in_isr() == true) { + return -EINTR; + } + + vTaskDelete(os_task); + + return 0; +} + +/** + * @brief let current task sleep for some ticks + */ +esp_err_t espos_task_delay ( + const espos_tick_t delay_ticks +) +{ + vTaskDelay(delay_ticks); + + return 0; +} + +/** + * @brief suspend target task + */ +esp_err_t espos_task_suspend ( + espos_task_t task +) +{ + TaskHandle_t os_task = (TaskHandle_t)task; + + if (!os_task) { + return -EINVAL; + } + + vTaskSuspend(os_task); + + return 0; +} + +/** + * @brief resume target task + */ +esp_err_t espos_task_resume ( + espos_task_t task +) +{ + esp_err_t ret; + TaskHandle_t os_task = (TaskHandle_t)task; + + if (!os_task) { + return -EINVAL; + } + + if (espos_in_isr() == true) { + ret = xTaskResumeFromISR(os_task); + if (ret == pdTRUE) { + ret = 0; + portYIELD_FROM_ISR(); + } else { + ret = -ECANCELED; + } + + } else { + vTaskResume(os_task); + ret = 0; + } + + return 0; +} + +/** + * @brief yield the cpu once + */ +esp_err_t espos_task_yield(void) +{ + taskYIELD(); + + return 0; +} + +/** + * @brief get current task handle + */ +espos_task_t espos_task_get_current(void) +{ + return (espos_task_t)xTaskGetCurrentTaskHandle(); +} + +/** + * @brief get current task name point + */ +esp_err_t espos_task_get_name ( + espos_task_t task, + char **pname +) +{ + TaskHandle_t os_task = (TaskHandle_t)task; + + if (!os_task) { + return -EINVAL; + } + + *pname = (char *)pcTaskGetTaskName(os_task); + + return 0; +} + +#if 0 + +/** + * @brief set task private data + */ +esp_err_t espos_task_set_private_data ( + espos_task_t task, + int idx, + void *info +) +{ + TaskHandle_t os_task = (TaskHandle_t)task; + + if (!os_task) { + return -EINVAL; + } + + vTaskSetThreadLocalStoragePointer(os_task, idx, info); + + return 0; +} + +/** + * @brief get task private data + */ +esp_err_t espos_task_get_private_data ( + espos_task_t task, + int idx, + void **info +) +{ + TaskHandle_t os_task = (TaskHandle_t)task; + + if (!os_task || !info) { + return -EINVAL; + } + + *info = pvTaskGetThreadLocalStoragePointer(os_task, idx); + + return 0; +} + +/** + * @brief get cpu affinity of task + */ +espos_cpu_t espos_task_get_affinity(espos_task_t task) +{ + TaskHandle_t os_task = (TaskHandle_t)task; + + if (!os_task) { + return -EINVAL; + } + + return xTaskGetAffinity(os_task); +} + +#endif + +/** + * @brief get ESPOS task priority number + */ +espos_size_t espos_task_prio_num(void) +{ + return configMAX_PRIORITIES + 1; +} diff --git a/components/espos/platform/freertos/espos_time.c b/components/espos/platform/freertos/espos_time.c new file mode 100644 index 00000000..445f8374 --- /dev/null +++ b/components/espos/platform/freertos/espos_time.c @@ -0,0 +1,52 @@ +// 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 "freertos/FreeRTOS.h" +#include "freertos/task.h" + +#include "espos_time.h" + +espos_time_t espos_get_tick_per_ms(void) +{ + return portTICK_PERIOD_MS; +} + +/** + * @brief get current system ticks + */ +espos_tick_t espos_get_tick_count(void) +{ + return (espos_tick_t)xTaskGetTickCount(); +} + +/** + * @brief transform milliseconds to system ticks + */ +espos_tick_t espos_ms_to_ticks(espos_time_t ms) +{ + return (ms / (portTICK_PERIOD_MS)); +} + +/** + * @brief transform system ticks to milliseconds + */ +espos_time_t espos_ticks_to_ms(espos_tick_t ticks) +{ + return (ticks * (portTICK_PERIOD_MS)); +} + +void espos_add_tick_count(size_t t) +{ + vTaskStepTick((portTickType)t); +} diff --git a/components/espos/platform/freertos/espos_timer.c b/components/espos/platform/freertos/espos_timer.c new file mode 100644 index 00000000..9dc1352e --- /dev/null +++ b/components/espos/platform/freertos/espos_timer.c @@ -0,0 +1,279 @@ +// 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 + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/timers.h" + +#include "espos_timer.h" +#include "espos_scheduler.h" + +#define portYIELD_FROM_ISR() taskYIELD() + +typedef struct espos_timer_os { + /* FreeRTOS handle */ + TimerHandle_t timer; + + /* ESPOS timer callback function */ + espos_timer_cb_t cb; + + /* ESPOS timer private parameter*/ + void *priv; +} espos_timer_os_t; + +/** + * @brief FreeRTOS callback function + */ +static void os_timer_callback(TimerHandle_t xTimer) +{ + espos_timer_os_t *os_timer = + (espos_timer_os_t *)pvTimerGetTimerID(xTimer); + espos_timer_t timer = (espos_timer_t)os_timer; + + os_timer->cb(timer, os_timer->priv); +} + +/** + * @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 +) +{ + espos_timer_os_t *os_timer; + UBaseType_t auto_load; + esp_err_t ret; + + if (!timer || !name || !cb || !period_ticks) { + return -EINVAL; + } + + if (opt == ESPOS_TIMER_AUTO_RUN) { + auto_load = pdTRUE; + } else if (opt == ESPOS_TIMER_NO_AUTO_RUN) { + auto_load = pdFALSE; + } else { + return -EINVAL; + } + + if (espos_in_isr() == true) { + return -EINTR; + } + + os_timer = malloc(sizeof(espos_timer_os_t)); + if (!os_timer) { + return -ENOMEM; + } + + os_timer->timer = xTimerCreate(name, period_ticks, auto_load, os_timer, os_timer_callback); + if (os_timer->timer) { + ret = 0; + + os_timer->cb = cb; + os_timer->priv = arg; + + *timer = (espos_timer_t)os_timer; + } else { + ret = -ENOMEM; + + free(os_timer); + } + + return ret; +} + +/** + * @brief start a timer + */ +esp_err_t espos_timer_start ( + espos_timer_t timer +) +{ + esp_err_t ret; + espos_timer_os_t *os_timer = (espos_timer_os_t *)timer; + + if (!os_timer) { + return -EINVAL; + } + + if (espos_in_isr() == true) { + BaseType_t xHigherPrioritTaskWoken = pdFALSE; + + ret = xTimerStartFromISR(os_timer->timer, &xHigherPrioritTaskWoken); + if (pdTRUE == ret && pdTRUE == xHigherPrioritTaskWoken) { + portYIELD_FROM_ISR(); + } + + if (ret == pdTRUE) { + ret = 0; + } else { + ret = -ECANCELED; + } + } else { + ret = xTimerStart(os_timer->timer, ESPOS_MAX_DELAY); + if (ret == pdTRUE) { + ret = 0; + } else { + ret = -ECANCELED; + } + } + + return ret; +} + +/** + * @brief stop a timer + */ +esp_err_t espos_timer_stop ( + espos_timer_t timer +) +{ + esp_err_t ret; + espos_timer_os_t *os_timer = (espos_timer_os_t *)timer; + + if (!os_timer) { + return -EINVAL; + } + + if (espos_in_isr() == true) { + BaseType_t xHigherPrioritTaskWoken = pdFALSE; + + ret = xTimerStopFromISR(os_timer->timer, &xHigherPrioritTaskWoken); + if (pdTRUE == ret && pdTRUE == xHigherPrioritTaskWoken) { + portYIELD_FROM_ISR(); + } + + if (ret == pdTRUE) { + ret = 0; + } else { + ret = -ECANCELED; + } + } else { + ret = xTimerStop(os_timer->timer, ESPOS_MAX_DELAY); + if (ret == pdTRUE) { + ret = 0; + } else { + ret = -ECANCELED; + } + } + + return ret; +} + +/** + * @brief configure a timer + */ +esp_err_t espos_timer_change ( + espos_timer_t timer, + espos_opt_t opt, + void *arg +) +{ + esp_err_t ret; + espos_timer_os_t *os_timer = (espos_timer_os_t *)timer; + + if (!os_timer) { + return -EINVAL; + } + + if (ESPOS_TIMER_CHANGE_PERIOD == opt) { + TickType_t period = (TickType_t)arg; + + if (espos_in_isr() == true) { + BaseType_t xHigherPrioritTaskWoken = pdFALSE; + + ret = xTimerChangePeriodFromISR(os_timer->timer, period, &xHigherPrioritTaskWoken); + if (pdTRUE == ret && pdTRUE == xHigherPrioritTaskWoken) { + portYIELD_FROM_ISR(); + } + + if (ret == pdTRUE) { + ret = 0; + } else { + ret = -ECANCELED; + } + } else { + ret = xTimerChangePeriod(os_timer->timer, period, ESPOS_MAX_DELAY); + if (ret == pdTRUE) { + ret = 0; + } else { + ret = -ECANCELED; + } + } + } else if (ESPOS_TIMER_CHANGE_ONCE == opt) { + return -EINVAL; + } else if (ESPOS_TIMER_CHANGE_AUTO == opt) { + return -EINVAL; + } else { + return -EINVAL; + } + + return -ret; +} + +/** + * @brief delete a timer + */ +esp_err_t espos_timer_del ( + espos_timer_t timer +) +{ + esp_err_t ret; + espos_timer_os_t *os_timer = (espos_timer_os_t *)timer; + + if (!os_timer) { + return -EINVAL; + } + + if (espos_in_isr() == true) { + return -EINTR; + } + + ret = xTimerDelete(os_timer->timer, ESPOS_MAX_DELAY); + if (ret == pdTRUE) { + ret = 0; + free(os_timer); + } else { + ret = -ECANCELED; + } + + return ret; +} + +/** + * @brief get current timer name point + */ +esp_err_t espos_get_timer_name ( + espos_timer_t timer, + char **tname +) +{ + espos_timer_os_t *os_timer = (espos_timer_os_t *)timer; + + if (!os_timer) { + return -EINVAL; + } + + *tname = NULL; + + return -ENODEV; +} +