1189 lines
38 KiB
C
1189 lines
38 KiB
C
/*
|
||
*********************************************************************************************************
|
||
* uC/USB-Host
|
||
* The Embedded USB Host Stack
|
||
*
|
||
* Copyright (c) 2021 Semidrive Semiconductor
|
||
*
|
||
* All rights reserved.
|
||
*
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
*
|
||
* USB HOST OPERATING SYSTEM LAYER
|
||
* For CMSIS OS2
|
||
*
|
||
* Filename : usbh_os.c
|
||
* Version : V1.00.00
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* INCLUDE FILES
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
#include <stdlib.h>
|
||
#include <FreeRTOS.h>
|
||
#include <udelay/udelay.h>
|
||
#include "task.h"
|
||
#include "event_groups.h"
|
||
#include "semphr.h"
|
||
#include <usbh_cfg.h>
|
||
#include "../../Source/usbh_os.h"
|
||
#include <board.h>
|
||
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* LOCAL DEFINES
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
#define USBH_OS_MUTEX_REQUIRED ((((USBH_CFG_MAX_NBR_EPS * USBH_CFG_MAX_NBR_IFS) + 1u) * USBH_CFG_MAX_NBR_DEVS) + \
|
||
USBH_CFG_MAX_NBR_DEVS + USBH_CFG_MAX_NBR_HC + \
|
||
USBH_CDC_CFG_MAX_DEV + USBH_HID_CFG_MAX_DEV + USBH_MSC_CFG_MAX_DEV)
|
||
#define USBH_OS_SEM_REQUIRED (3u + (((USBH_CFG_MAX_NBR_EPS * USBH_CFG_MAX_NBR_IFS) + 1u) * USBH_CFG_MAX_NBR_DEVS))
|
||
#define USBH_OS_TCB_REQUIRED 4u
|
||
#define USBH_OS_Q_REQUIRED 1u
|
||
|
||
|
||
#define USBH_SEM_EVENT_POST (1u<<0)
|
||
#define USBH_SEM_EVENT_ABORT (1u<<1)
|
||
#define USBH_SEM_EVENT_DEL (1u<<2)
|
||
#define USBH_SEM_EVENT_ALL (USBH_SEM_EVENT_POST | USBH_SEM_EVENT_ABORT | USBH_SEM_EVENT_DEL)
|
||
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* LOCAL CONSTANTS
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* LOCAL DATA TYPES
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
typedef struct usbh_semaphore {
|
||
EventGroupHandle_t evt;
|
||
volatile CPU_INT32U cnt;
|
||
} USBH_SIGNAL;
|
||
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* LOCAL TABLES
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* LOCAL GLOBAL VARIABLES
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* LOCAL FUNCTION PROTOTYPES
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
#define usbh_os_err(...) ssdk_printf(SSDK_CRIT, __VA_ARGS__)
|
||
|
||
#define IS_IRQ_MASKED arch_irq_is_masked
|
||
#define IS_IRQ_MODE arch_in_irq_mode
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* IRQ_Context()
|
||
*
|
||
* Description : Determine if CPU executes from interrupt context or if interrupts are masked.
|
||
*
|
||
* Argument(s) : None.
|
||
*
|
||
* Return(s) : 0, thread context.
|
||
* 1, IRQ context.
|
||
*
|
||
* Note(s) : None.
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
__STATIC_INLINE uint32_t IRQ_Context (void)
|
||
{
|
||
uint32_t irq;
|
||
BaseType_t state;
|
||
|
||
irq = 0U;
|
||
|
||
if (IS_IRQ_MODE()) {
|
||
/* Called from interrupt context */
|
||
irq = 1U;
|
||
} else {
|
||
/* Get FreeRTOS scheduler state */
|
||
state = xTaskGetSchedulerState();
|
||
|
||
if (state != taskSCHEDULER_NOT_STARTED) {
|
||
/* Scheduler was started */
|
||
if (IS_IRQ_MASKED()) {
|
||
/* Interrupts are masked */
|
||
irq = 1U;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* Return context, 0: thread context, 1: IRQ context */
|
||
return (irq);
|
||
}
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* sdQueueCreate()
|
||
*
|
||
* Description : Creates a new queue and returns a handle by which the queue can be referenced.
|
||
*
|
||
* Argument(s) : queue_count, The maximum number of items that the queue being created can hold at
|
||
* any one time.
|
||
* queue_size, The size, in bytes, of each data item that can be stored in the queue.
|
||
*
|
||
* Return(s) : NULL, The queue cannot be created because there is insufficient heap memory
|
||
* available for FreeRTOS to allocate the queue data structures and storage
|
||
* area.
|
||
* Any other value, The queue was created successfully. The returned value is a handle by
|
||
* which the created queue can be referenced.
|
||
*
|
||
* Note(s) : None.
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
static QueueHandle_t sdQueueCreate(UBaseType_t queue_count, UBaseType_t queue_size)
|
||
{
|
||
QueueHandle_t msg_q = xQueueCreate(queue_count, queue_size);
|
||
|
||
/* Return msg */
|
||
return (msg_q);
|
||
}
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* sdQueueReceive()
|
||
*
|
||
* Description : Receive (read) an item from a queue.
|
||
*
|
||
* Argument(s) : hQueue, The handle of the queue from which the data is being received (read).
|
||
* msg_ptr, A pointer to the memory into which the received data will be copied.
|
||
* timeout, The maximum amount of time the task should remain in the Blocked state to
|
||
* wait for data to become available on the queue, should the queue already be
|
||
* empty.
|
||
*
|
||
* Return(s) : pdPASS, Returned if data was successfully read from the queue.
|
||
* errQUEUE_EMPTY, Returned if data cannot be read from the queue because the queue is
|
||
* already empty.
|
||
*
|
||
* Note(s) : None.
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
static BaseType_t sdQueueReceive(QueueHandle_t hQueue, void *msg_ptr, uint32_t timeout)
|
||
{
|
||
BaseType_t ret = pdTRUE;
|
||
BaseType_t yield;
|
||
|
||
if (IRQ_Context() != 0U) {
|
||
yield = pdFALSE;
|
||
|
||
if (xQueueReceiveFromISR(hQueue, msg_ptr, &yield) != pdPASS) {
|
||
ret = pdFALSE;
|
||
} else {
|
||
portYIELD_FROM_ISR(yield);
|
||
}
|
||
} else {
|
||
if (xQueueReceive(hQueue, msg_ptr, (TickType_t)timeout) != pdPASS) {
|
||
ret = pdFALSE;
|
||
}
|
||
}
|
||
|
||
/* Return execution status */
|
||
return (ret);
|
||
}
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* sdQueueSend()
|
||
*
|
||
* Description : Sends (writes) an item to the front or the back of a queue.
|
||
*
|
||
* Argument(s) : hQueue, The handle of the queue to which the data is being sent (written).
|
||
* msg_ptr, A pointer to the data to be copied into the queue.
|
||
* timeout, The maximum amount of time the task should remain in the Blocked state to
|
||
* wait for space to become available on the queue, should the queue already
|
||
* be full.
|
||
*
|
||
* Return(s) : pdPASS, Returned if data was successfully sent to the queue.
|
||
* errQUEUE_FULL, Returned if data could not be written to the queue because the queue was
|
||
* already full.
|
||
*
|
||
* Note(s) : None.
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
static BaseType_t sdQueueSend(QueueHandle_t hQueue, const void *msg_ptr, uint32_t timeout)
|
||
{
|
||
BaseType_t ret = pdTRUE;
|
||
BaseType_t yield;
|
||
|
||
if (IRQ_Context() != 0U) {
|
||
yield = pdFALSE;
|
||
|
||
if (xQueueSendToBackFromISR(hQueue, msg_ptr, &yield) != pdTRUE) {
|
||
ret = pdFALSE;
|
||
} else {
|
||
portYIELD_FROM_ISR(yield);
|
||
}
|
||
} else {
|
||
ret = xQueueSendToBack(hQueue, msg_ptr, (TickType_t)timeout);
|
||
}
|
||
|
||
/* Return execution status */
|
||
return (ret);
|
||
}
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* sdSemaphoreTake()
|
||
*
|
||
* Description : Takes’ (or obtains) a semaphore.
|
||
*
|
||
* Argument(s) : hSemaphore, The Semaphore being ‘taken’.
|
||
* timeout, The maximum amount of time the task should remain in the Blocked state to
|
||
* wait for the semaphore to become available, if the semaphore is not
|
||
* available immediately.
|
||
*
|
||
* Return(s) : pdPASS, Returned only if the call to sdSemaphoreTake() was successful in obtaining
|
||
* the semaphore.
|
||
* pdFAIL, Returned if the call to sdSemaphoreTake() did not successfully obtain the
|
||
* semaphore.
|
||
*
|
||
* Note(s) : None.
|
||
*********************************************************************************************************
|
||
*/
|
||
static BaseType_t sdSemaphoreTake(SemaphoreHandle_t hSemaphore, uint32_t timeout)
|
||
{
|
||
BaseType_t ret = pdTRUE;
|
||
BaseType_t yield;
|
||
|
||
if(IRQ_Context() != 0U) {
|
||
yield = pdFALSE;
|
||
|
||
if (xSemaphoreTakeFromISR(hSemaphore, &yield) != pdPASS) {
|
||
ret = pdFALSE;
|
||
} else {
|
||
portYIELD_FROM_ISR (yield);
|
||
}
|
||
} else {
|
||
ret = xSemaphoreTake(hSemaphore, (TickType_t)timeout);
|
||
}
|
||
|
||
/* Return execution status */
|
||
return (ret);
|
||
}
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* sdSemaphoreGive()
|
||
*
|
||
* Description : ‘Gives’ (or releases) a semaphore.
|
||
*
|
||
* Argument(s) : hSemaphore, The Semaphore being ‘given’.
|
||
*
|
||
* Return(s) : pdPASS, The semaphore ‘give’ operation was successful.
|
||
* pdFAIL, The semaphore ‘give’ operation was not successful.
|
||
*
|
||
* Note(s) : None.
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
static BaseType_t sdSemaphoreGive(SemaphoreHandle_t hSemaphore)
|
||
{
|
||
BaseType_t ret = pdFALSE;
|
||
|
||
if (IRQ_Context() == 0U) {
|
||
ret = xSemaphoreGive(hSemaphore);
|
||
}
|
||
|
||
/* Return ret */
|
||
return (ret);
|
||
}
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* sdSemaphoreCreateMutex()
|
||
*
|
||
* Description : Creates a mutex type semaphore, and returns a handle by which the mutex can be
|
||
* referenced.
|
||
*
|
||
* Argument(s) : None.
|
||
*
|
||
* Return(s) : NULL, Returned if the semaphore cannot be created because there is insufficient
|
||
* heap memory available for FreeRTOS to allocate the semaphore data
|
||
* structures.
|
||
* Any other value, The semaphore was created successfully. The returned value is a handle
|
||
* by which the created semaphore can be referenced.
|
||
*
|
||
* Note(s) : None.
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
static SemaphoreHandle_t sdSemaphoreCreateMutex(void)
|
||
{
|
||
SemaphoreHandle_t hMutex = 0;
|
||
|
||
if (IRQ_Context() == 0U) {
|
||
hMutex = xSemaphoreCreateMutex();
|
||
}
|
||
|
||
/* Return mutex ID */
|
||
return (hMutex);
|
||
}
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* sdSemaphoreDelete()
|
||
*
|
||
* Description : Deletes a semaphore.
|
||
*
|
||
* Argument(s) : hSemaphore, The handle of the semaphore being deleted.
|
||
*
|
||
* Return(s) : None.
|
||
*
|
||
* Note(s) : None.
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
static BaseType_t sdSemaphoreDelete(SemaphoreHandle_t hSemaphore)
|
||
{
|
||
BaseType_t ret = pdFALSE;
|
||
|
||
if (IRQ_Context() == 0U) {
|
||
vSemaphoreDelete(hSemaphore);
|
||
ret = pdTRUE;
|
||
}
|
||
|
||
/* Return ret */
|
||
return (ret);
|
||
}
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* sdEventGroupCreate()
|
||
*
|
||
* Description : Creates a new event group and returns a handle by which the created event group can be
|
||
* referenced.
|
||
*
|
||
* Argument(s) : None.
|
||
*
|
||
* Return(s) : NULL, The event group could not be created because there was insufficient
|
||
* FreeRTOS heap available.
|
||
* Any other value, The event group was created and the value returned is the handle of the
|
||
* created event group
|
||
*
|
||
* Note(s) : None.
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
static EventGroupHandle_t sdEventGroupCreate(void)
|
||
{
|
||
EventGroupHandle_t evt = NULL;
|
||
|
||
if (IRQ_Context() == 0U) {
|
||
evt = xEventGroupCreate();
|
||
}
|
||
|
||
/* Return evt */
|
||
return (evt);
|
||
}
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* sdEventGroupDelete()
|
||
*
|
||
* Description : Deletes a group.
|
||
*
|
||
* Argument(s) : hEventGroup, The event group to delete.
|
||
*
|
||
* Return(s) : None.
|
||
*
|
||
* Note(s) : None.
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
static BaseType_t sdEventGroupDelete(EventGroupHandle_t hEventGroup)
|
||
{
|
||
BaseType_t ret = pdFALSE;
|
||
|
||
if (IRQ_Context() == 0U) {
|
||
vEventGroupDelete(hEventGroup);
|
||
ret = pdTRUE;
|
||
}
|
||
|
||
/* Return ret */
|
||
return (ret);
|
||
}
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* sdEventGroupSetBits()
|
||
*
|
||
* Description : Sets bits (flags) within an RTOS event group.
|
||
*
|
||
* Argument(s) : hEventGroup, The event group in which the bits are to be set.
|
||
* flags, A bitwise value that indicates the bit or bits to set in the event group.
|
||
*
|
||
* Return(s) : Any Value, The value of the bits in the event group at the time to returned.
|
||
*
|
||
* Note(s) : None.
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
static EventBits_t sdEventGroupSetBits(EventGroupHandle_t hEventGroup, uint32_t flags)
|
||
{
|
||
EventBits_t rflags;
|
||
BaseType_t yield;
|
||
|
||
if (IRQ_Context() != 0U) {
|
||
yield = pdFALSE;
|
||
|
||
if (xEventGroupSetBitsFromISR(hEventGroup, (EventBits_t)flags, &yield) == pdFAIL) {
|
||
rflags = pdFAIL;
|
||
} else {
|
||
rflags = flags;
|
||
portYIELD_FROM_ISR (yield);
|
||
}
|
||
}
|
||
else {
|
||
rflags = xEventGroupSetBits(hEventGroup, (EventBits_t)flags);
|
||
}
|
||
|
||
/* Return event flags after setting */
|
||
return (rflags);
|
||
}
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* sdEventGroupWaitBits()
|
||
*
|
||
* Description : Read bits within an RTOS event group.
|
||
*
|
||
* Argument(s) : hEventGroup, The event group in which the bits are being tested.
|
||
* timeout, The maximum amount of time (specified in 'ticks') to wait.
|
||
*
|
||
* Return(s) : Any Value, The value of the event group at the time either the event bits being waited
|
||
* for became set, or the block time expired.
|
||
*
|
||
* Note(s) : None.
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
static EventBits_t sdEventGroupWaitBits(EventGroupHandle_t hEventGroup, uint32_t timeout)
|
||
{
|
||
EventBits_t rflags = 0;
|
||
|
||
if (IRQ_Context() == 0U) {
|
||
rflags = xEventGroupWaitBits(hEventGroup, USBH_SEM_EVENT_ALL, pdTRUE, pdFALSE, timeout);
|
||
}
|
||
|
||
/* Return event flags after setting */
|
||
return (rflags);
|
||
}
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* USBH_OS_LayerInit()
|
||
*
|
||
* Description : Initialize OS layer.
|
||
*
|
||
* Argument(s) : none.
|
||
*
|
||
* Return(s) : USBH_ERR_NONE, if successful.
|
||
*
|
||
* Note(s) : none.
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
USBH_ERR USBH_OS_LayerInit (void)
|
||
{
|
||
return (USBH_ERR_NONE);
|
||
}
|
||
|
||
|
||
/*
|
||
**************************************************************************************************************
|
||
* USBH_OS_VirToBus()
|
||
*
|
||
* Description : Convert from virtual address to physical address if the operating system uses
|
||
* virtual memory
|
||
*
|
||
* Arguments : x Virtual address to convert
|
||
*
|
||
* Returns : The corresponding physical address
|
||
*
|
||
* Note(s) : None.
|
||
**************************************************************************************************************
|
||
*/
|
||
|
||
void *USBH_OS_VirToBus (void *x)
|
||
{
|
||
return (x);
|
||
}
|
||
|
||
|
||
/*
|
||
**************************************************************************************************************
|
||
* USBH_OS_BusToVir()
|
||
*
|
||
* Description : Convert from physical address to virtual address if the operating system uses
|
||
* virtual memory
|
||
*
|
||
* Arguments : x Physical address to convert
|
||
*
|
||
* Returns : The corresponding virtual address
|
||
*
|
||
* Note(s) : None.
|
||
**************************************************************************************************************
|
||
*/
|
||
|
||
void *USBH_OS_BusToVir (void *x)
|
||
{
|
||
return (x);
|
||
}
|
||
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
*********************************************************************************************************
|
||
* DELAY FUNCTIONS
|
||
*********************************************************************************************************
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* USBH_OS_DlyMS()
|
||
*
|
||
* Description : Delay the current task by specified delay.
|
||
*
|
||
* Argument(s) : dly Delay, in milliseconds.
|
||
*
|
||
* Return(s) : none.
|
||
*
|
||
* Note(s) : none.
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
void USBH_OS_DlyMS (CPU_INT32U dly)
|
||
{
|
||
if (dly < 3)
|
||
udelay(dly * 1000);
|
||
else
|
||
vTaskDelay(dly);
|
||
}
|
||
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* USBH_OS_DlyUS()
|
||
*
|
||
* Description : Delay the current task by specified delay.
|
||
*
|
||
* Argument(s) : dly Delay, in microseconds.
|
||
*
|
||
* Return(s) : none.
|
||
*
|
||
* Note(s) : none.
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
void USBH_OS_DlyUS (CPU_INT32U dly)
|
||
{
|
||
udelay(dly);
|
||
}
|
||
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
*********************************************************************************************************
|
||
* MUTEX FUNCTIONS
|
||
*********************************************************************************************************
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* USBH_OS_MutexCreate()
|
||
*
|
||
* Description : Create a mutex.
|
||
*
|
||
* Argument(s) : p_mutex Pointer to variable that will receive handle of the mutex.
|
||
*
|
||
* Return(s) : USBH_ERR_NONE, if successful.
|
||
* USBH_ERR_ALLOC,
|
||
* USBH_ERR_OS_SIGNAL_CREATE,
|
||
*
|
||
* Note(s) : none.
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
USBH_ERR USBH_OS_MutexCreate (USBH_HMUTEX *p_mutex)
|
||
{
|
||
SemaphoreHandle_t ret;
|
||
|
||
ret = sdSemaphoreCreateMutex();
|
||
if (!ret) {
|
||
usbh_os_err("Creat Mutex failed\r\n");
|
||
return USBH_ERR_OS_SIGNAL_CREATE;
|
||
} else {
|
||
*p_mutex = (USBH_HMUTEX)ret;
|
||
return USBH_ERR_NONE;
|
||
}
|
||
}
|
||
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* USBH_OS_MutexLock()
|
||
*
|
||
* Description : Acquire a mutex.
|
||
*
|
||
* Argument(s) : mutex Mutex handle.
|
||
*
|
||
* Return(s) : USBH_ERR_NONE, if successful.
|
||
* USBH_ERR_OS_TIMEOUT, if timeout.
|
||
* USBH_ERR_OS_FAIL, otherwise.
|
||
*
|
||
* Note(s) : none.
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
USBH_ERR USBH_OS_MutexLock (USBH_HMUTEX mutex)
|
||
{
|
||
BaseType_t ret;
|
||
|
||
ret = sdSemaphoreTake((SemaphoreHandle_t)mutex, portMAX_DELAY);
|
||
switch (ret) {
|
||
case pdPASS:
|
||
return USBH_ERR_NONE;
|
||
break;
|
||
|
||
case pdFAIL:
|
||
default:
|
||
usbh_os_err("Get Mutex %X ret %d\r\n", mutex, ret);
|
||
return USBH_ERR_OS_FAIL;
|
||
break;
|
||
}
|
||
}
|
||
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* USBH_OS_MutexUnlock()
|
||
*
|
||
* Description : Releases a mutex.
|
||
*
|
||
* Argument(s) : mutex Mutex handle.
|
||
*
|
||
* Return(s) : USBH_ERR_NONE, if successful.
|
||
* USBH_ERR_OS_FAIL, otherwise.
|
||
*
|
||
* Note(s) : none.
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
USBH_ERR USBH_OS_MutexUnlock (USBH_HMUTEX mutex)
|
||
{
|
||
if (sdSemaphoreGive((SemaphoreHandle_t)mutex) != pdPASS) {
|
||
usbh_os_err("Mutex %X Release ret %d\r\n", mutex);
|
||
return USBH_ERR_OS_FAIL;
|
||
}
|
||
|
||
return USBH_ERR_NONE;
|
||
}
|
||
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* USBH_OS_MutexDestroy()
|
||
*
|
||
* Description : Destroys a mutex only when no task is pending on the mutex.
|
||
*
|
||
* Argument(s) : mutex Mutex handle.
|
||
*
|
||
* Return(s) : USBH_ERR_NONE, if successful.
|
||
* USBH_ERR_OS_FAIL, if mutex delete failed.
|
||
* USBH_ERR_FREE, if mutex free failed.
|
||
*
|
||
* Note(s) : none.
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
USBH_ERR USBH_OS_MutexDestroy (USBH_HMUTEX mutex)
|
||
{
|
||
sdSemaphoreDelete((SemaphoreHandle_t)mutex);
|
||
return USBH_ERR_NONE;
|
||
}
|
||
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
*********************************************************************************************************
|
||
* SEMAPHORE FUNCTIONS
|
||
*********************************************************************************************************
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* USBH_OS_SemCreate()
|
||
*
|
||
* Description : Create semaphore with given count.
|
||
*
|
||
* Argument(s) : p_sem Pointer that will receive handle for managing semaphore.
|
||
|
||
* cnt Value with which the semaphore will be initialized.
|
||
*
|
||
* Return(s) : USBH_ERR_NONE, if successful.
|
||
* USBH_ERR_OS_SIGNAL_CREATE,
|
||
* USBH_ERR_ALLOC,
|
||
*
|
||
* Note(s) : none.
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
USBH_ERR USBH_OS_SemCreate (USBH_HSEM *p_sem,
|
||
CPU_INT32U cnt)
|
||
{
|
||
EventGroupHandle_t evt;
|
||
USBH_SIGNAL *hsig;
|
||
|
||
hsig = pvPortMallocAligned(sizeof(*hsig), sizeof(void *));
|
||
if (!hsig)
|
||
return USBH_ERR_ALLOC;
|
||
|
||
evt = sdEventGroupCreate();
|
||
if (!evt) {
|
||
usbh_os_err("Creat Semaphore failed\r\n");
|
||
free(hsig);
|
||
return USBH_ERR_OS_SIGNAL_CREATE;
|
||
}
|
||
|
||
hsig->evt = evt;
|
||
hsig->cnt = cnt;
|
||
if (cnt > 0) {
|
||
sdEventGroupSetBits(hsig->evt, USBH_SEM_EVENT_POST);
|
||
}
|
||
|
||
*p_sem = (USBH_HSEM)hsig;
|
||
|
||
return USBH_ERR_NONE;
|
||
}
|
||
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* USBH_OS_SemDestroy()
|
||
*
|
||
* Description : Destroy a semphore if no tasks are waiting on it.
|
||
*
|
||
* Argument(s) : sem Semaphore handle.
|
||
*
|
||
* Return(s) : none.
|
||
*
|
||
* Note(s) : none.
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
USBH_ERR USBH_OS_SemDestroy (USBH_HSEM sem)
|
||
{
|
||
USBH_SIGNAL *hsig;
|
||
|
||
hsig = (USBH_SIGNAL *)sem;
|
||
|
||
if (!hsig || !hsig->evt)
|
||
return USBH_ERR_INVALID_ARG;
|
||
|
||
sdEventGroupSetBits(hsig->evt, USBH_SEM_EVENT_DEL);
|
||
sdEventGroupDelete(hsig->evt);
|
||
|
||
free(hsig);
|
||
|
||
return USBH_ERR_NONE;
|
||
}
|
||
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* USBH_OS_SemWait()
|
||
*
|
||
* Description : Wait on a semaphore to become available.
|
||
*
|
||
* Argument(s) : sem Semaphore handle.
|
||
*
|
||
* timeout Timeout.
|
||
*
|
||
* Return(s) : USBH_ERR_NONE, if successful.
|
||
* USBH_ERR_OS_TIMEOUT, if timeout error.
|
||
* USBH_ERR_OS_ABORT,
|
||
* USBH_ERR_OS_FAIL,
|
||
*
|
||
* Note(s) : none.
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
USBH_ERR USBH_OS_SemWait (USBH_HSEM sem,
|
||
CPU_INT32U timeout)
|
||
{
|
||
USBH_SIGNAL *hsig;
|
||
uint32_t rflags;
|
||
uint32_t tmo;
|
||
uint32_t tk_start, tk_current;
|
||
CPU_INT32U cnt;
|
||
CPU_SR_ALLOC();
|
||
|
||
hsig = (USBH_SIGNAL *)sem;
|
||
if (!hsig || !hsig->evt)
|
||
return USBH_ERR_INVALID_ARG;
|
||
|
||
tk_start = xTaskGetTickCount();
|
||
tk_current = tk_start;
|
||
do {
|
||
tmo = timeout ? (tk_start + timeout - tk_current): portMAX_DELAY;
|
||
rflags = sdEventGroupWaitBits(hsig->evt, tmo);
|
||
if ((rflags & USBH_SEM_EVENT_ALL) == 0U) {
|
||
if (tmo > 0U) {
|
||
return USBH_ERR_OS_TIMEOUT;
|
||
} else {
|
||
usbh_os_err("Get Signal %p rflags %d\r\n", hsig->evt, rflags);
|
||
return USBH_ERR_OS_FAIL;
|
||
}
|
||
} else if (rflags & USBH_SEM_EVENT_DEL) {
|
||
usbh_os_err("Get Multi Signal %p ret Del\r\n", hsig->evt);
|
||
return USBH_ERR_OS_FAIL;
|
||
} else if (rflags & USBH_SEM_EVENT_ABORT) {
|
||
return USBH_ERR_OS_ABORT;
|
||
}
|
||
|
||
CPU_CRITICAL_ENTER();
|
||
cnt = hsig->cnt;
|
||
if (cnt)
|
||
hsig->cnt = cnt - 1;
|
||
CPU_CRITICAL_EXIT();
|
||
|
||
if (cnt > 1) {
|
||
sdEventGroupSetBits(hsig->evt, USBH_SEM_EVENT_POST);
|
||
}
|
||
|
||
if (cnt) {
|
||
return USBH_ERR_NONE;
|
||
}
|
||
|
||
tk_current = xTaskGetTickCount();
|
||
} while (!timeout || (tk_current - tk_start <= timeout));
|
||
|
||
return USBH_ERR_OS_TIMEOUT;
|
||
}
|
||
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* USBH_OS_SemWaitAbort()
|
||
*
|
||
* Description : Resume all tasks waiting on specified semaphore.
|
||
*
|
||
* Argument(s) : sem Semaphore handle.
|
||
*
|
||
* Return(s) : USBH_ERR_NONE, if successful.
|
||
* USBH_ERR_OS_TIMEOUT, if timeout error.
|
||
* USBH_ERR_OS_ABORT,
|
||
* USBH_ERR_OS_FAIL,
|
||
*
|
||
* Note(s) : none.
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
USBH_ERR USBH_OS_SemWaitAbort (USBH_HSEM sem)
|
||
{
|
||
int32_t ret;
|
||
USBH_SIGNAL *hsig;
|
||
|
||
hsig = (USBH_SIGNAL *)sem;
|
||
if (!hsig || !hsig->evt)
|
||
return USBH_ERR_INVALID_ARG;
|
||
|
||
ret = sdEventGroupSetBits(hsig->evt, USBH_SEM_EVENT_ABORT);
|
||
if (ret < 0) {
|
||
return USBH_ERR_OS_FAIL;
|
||
}
|
||
|
||
return USBH_ERR_NONE;
|
||
}
|
||
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* USBH_OS_SemPost()
|
||
*
|
||
* Description : Post a semaphore.
|
||
*
|
||
* Argument(s) : sem Semaphore handle.
|
||
*
|
||
* Return(s) : USBH_ERR_NONE, if successful.
|
||
* USBH_ERR_OS_FAIL, otherwise.
|
||
*
|
||
* Note(s) : none.
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
USBH_ERR USBH_OS_SemPost (USBH_HSEM sem)
|
||
{
|
||
int32_t ret;
|
||
USBH_SIGNAL *hsig;
|
||
CPU_SR_ALLOC();
|
||
|
||
hsig = (USBH_SIGNAL *)sem;
|
||
if (!hsig || !hsig->evt)
|
||
return USBH_ERR_INVALID_ARG;
|
||
|
||
CPU_CRITICAL_ENTER();
|
||
hsig->cnt++;
|
||
CPU_CRITICAL_EXIT();
|
||
|
||
ret = sdEventGroupSetBits(hsig->evt, USBH_SEM_EVENT_POST);
|
||
if (ret < 0) {
|
||
return USBH_ERR_OS_FAIL;
|
||
}
|
||
|
||
return USBH_ERR_NONE;
|
||
}
|
||
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
*********************************************************************************************************
|
||
* THREAD FUNCTIONS
|
||
*********************************************************************************************************
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* USBH_OS_ThreadCreate()
|
||
*
|
||
* Description : Create a thread (or task).
|
||
*
|
||
* Argument(s) : p_name Pointer to name to assign to thread.
|
||
*
|
||
* prio Priority of the thread to be created.
|
||
*
|
||
* thread_fnct Pointer to the function that will be executed in this thread.
|
||
*
|
||
* p_data Pointer to the data that is passed to the thread function.
|
||
*
|
||
* p_stk Pointer to the beginning of the stack used by the thread.
|
||
*
|
||
* stk_size Size of the stack.
|
||
*
|
||
* p_thread Pointer that will receive handle for managing thread.
|
||
*
|
||
* Return(s) : USBH_ERR_NONE, if successful.
|
||
* USBH_ERR_ALLOC,
|
||
* USBH_ERR_OS_TASK_CREATE,
|
||
*
|
||
* Note(s) : none.
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
USBH_ERR USBH_OS_TaskCreate (CPU_CHAR *p_name,
|
||
CPU_INT32U prio,
|
||
USBH_TASK_FNCT task_fnct,
|
||
void *p_data,
|
||
CPU_INT32U *p_stk,
|
||
CPU_INT32U stk_size,
|
||
USBH_HTASK *p_task)
|
||
{
|
||
|
||
TaskHandle_t thread;
|
||
|
||
if (p_stk != NULL) {
|
||
thread = xTaskCreateStatic(task_fnct, p_name, stk_size, p_data, prio,
|
||
(StackType_t *)p_stk, (StaticTask_t *)p_task);
|
||
if (!thread) {
|
||
p_task = NULL;
|
||
return USBH_ERR_OS_TASK_CREATE;
|
||
}
|
||
} else {
|
||
if (xTaskCreate(task_fnct, p_name, stk_size, p_data, prio, &thread) != pdPASS) {
|
||
return USBH_ERR_OS_TASK_CREATE;
|
||
}
|
||
}
|
||
|
||
*p_task = (USBH_HTASK)thread;
|
||
|
||
return USBH_ERR_NONE;
|
||
}
|
||
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
*********************************************************************************************************
|
||
* MESSAGE QUEUE
|
||
*********************************************************************************************************
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* USBH_OS_MsgQueueCreate()
|
||
*
|
||
* Description : Create a message queue.
|
||
*
|
||
* Argument(s) : p_start Pointer to the base address of the message queue storage area.
|
||
*
|
||
* size Number of elements in the storage area.
|
||
*
|
||
* p_err Pointer to variable that will receive the return error code from this function:
|
||
*
|
||
* USBH_ERR_NONE Message queue created.
|
||
* USBH_ERR_ALLOC Message queue creation failed.
|
||
* USBH_ERR_OS_SIGNAL_CREATE
|
||
*
|
||
* Return(s) : The handle of the message queue.
|
||
*
|
||
* Note(s) : none.
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
USBH_HQUEUE USBH_OS_MsgQueueCreate (void **p_start,
|
||
CPU_INT16U size,
|
||
USBH_ERR *p_err)
|
||
{
|
||
QueueHandle_t msg_q;
|
||
|
||
if (p_err == NULL) {
|
||
return (USBH_ERR_INVALID_ARG);
|
||
}
|
||
|
||
msg_q = sdQueueCreate(size, sizeof(void *));
|
||
if (!msg_q) {
|
||
usbh_os_err("Creat Queue failed\r\n");
|
||
*p_err = USBH_ERR_OS_SIGNAL_CREATE;
|
||
return ((USBH_HQUEUE )0);
|
||
}
|
||
|
||
*p_err = USBH_ERR_NONE;
|
||
return ((USBH_HQUEUE)msg_q);
|
||
}
|
||
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* USBH_OS_MsgQueuePut()
|
||
*
|
||
* Description : Post a message to a message queue.
|
||
*
|
||
* Argument(s) : msg_q Message queue handle.
|
||
*
|
||
* p_msg Pointer to the message to send.
|
||
*
|
||
* Return(s) : USBH_ERR_NONE, if successful.
|
||
* USBH_ERR_OS_FAIL, otherwise.
|
||
*
|
||
* Note(s) : none.
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
USBH_ERR USBH_OS_MsgQueuePut (USBH_HQUEUE msg_q,
|
||
void *p_msg)
|
||
{
|
||
void *p;
|
||
|
||
if (p_msg == NULL) {
|
||
return (USBH_ERR_INVALID_ARG);
|
||
}
|
||
|
||
p = p_msg;
|
||
if (sdQueueSend((QueueHandle_t)msg_q, &p, 0) != pdPASS) {
|
||
usbh_os_err("MsgQ Put failed\r\n");
|
||
return USBH_ERR_OS_FAIL;
|
||
}
|
||
|
||
return (USBH_ERR_NONE);
|
||
}
|
||
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* USBH_OS_MsgQueueGet()
|
||
*
|
||
* Description : Get a message from a message queue and blocks forever until a message is posted in the
|
||
* queue.
|
||
*
|
||
* Argument(s) : msg_q Message queue handle.
|
||
*
|
||
* timeout Time to wait for a message, in milliseconds.
|
||
*
|
||
* p_err Pointer to variable that will receive the return error code from this function :
|
||
*
|
||
* USBH_ERR_NONE, if successful.
|
||
* USBH_ERR_OS_TIMEOUT,
|
||
* USBH_ERR_OS_ABORT,
|
||
* USBH_ERR_OS_FAIL,
|
||
*
|
||
* Return(s) : Pointer to message, if successful.
|
||
* Pointer to null, otherwise.
|
||
*
|
||
* Note(s) : none.
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
void *USBH_OS_MsgQueueGet (USBH_HQUEUE msg_q,
|
||
CPU_INT32U timeout,
|
||
USBH_ERR *p_err)
|
||
{
|
||
void *p_msg;
|
||
BaseType_t ret;
|
||
uint32_t tmo;
|
||
|
||
if (p_err == NULL) {
|
||
return NULL;
|
||
}
|
||
|
||
tmo = timeout ? timeout : portMAX_DELAY;
|
||
ret = sdQueueReceive((QueueHandle_t)msg_q, &p_msg, tmo);
|
||
switch (ret) {
|
||
case pdPASS:
|
||
*p_err = USBH_ERR_NONE;
|
||
break;
|
||
|
||
case pdFAIL:
|
||
default:
|
||
if (tmo) {
|
||
usbh_os_err("USBH_OS_MsgQueueGet timeout 1\r\n");
|
||
*p_err = USBH_ERR_OS_TIMEOUT;
|
||
} else {
|
||
*p_err = USBH_ERR_OS_FAIL;
|
||
}
|
||
usbh_os_err("MsgQ Get failed\r\n");
|
||
break;
|
||
}
|
||
|
||
return (*p_err == USBH_ERR_NONE ? p_msg : NULL);
|
||
}
|
||
|