1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2024-11-29 07:24:13 +01:00
LibrePilot/flight/pios/common/pios_semaphore.c

412 lines
10 KiB
C

/**
******************************************************************************
* @file pios_semaphore.c
* @author Tau Labs, http://taulabs.org, Copyright (C) 2013-2014
* @addtogroup PIOS PIOS Core hardware abstraction layer
* @{
* @addtogroup PIOS_Semaphore Semaphore Abstraction
* @{
* @brief Abstracts the concept of a binary semaphore to hide different implementations
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "pios.h"
#include "pios_semaphore.h"
#if !defined(PIOS_INCLUDE_FREERTOS) && !defined(PIOS_INCLUDE_CHIBIOS) && !defined(PIOS_INCLUDE_IRQ)
#error "pios_semaphore.c requires either PIOS_INCLUDE_FREERTOS, PIOS_INCLUDE_CHIBIOS or PIOS_INCLUDE_IRQ to be defined"
#endif
#if defined(PIOS_INCLUDE_FREERTOS)
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
// portTICK_RATE_MS is in [ms/tick].
// See http://sourceforge.net/tracker/?func=detail&aid=3498382&group_id=111543&atid=659636
#define TICKS2MS(t) ((t) * (portTICK_RATE_MS))
#define MS2TICKS(m) ((m) / (portTICK_RATE_MS))
/**
*
* @brief Creates a binary semaphore.
*
* @returns instance of @p struct pios_semaphore or NULL on failure
*
*/
struct pios_semaphore *PIOS_Semaphore_Create(void)
{
struct pios_semaphore *sema = pios_malloc(sizeof(struct pios_semaphore));
if (sema == NULL) {
return NULL;
}
/*
* The initial state of a binary semaphore is "given".
* FreeRTOS executes a "give" upon creation.
*/
xSemaphoreHandle temp;
vSemaphoreCreateBinary(temp);
sema->sema_handle = (uintptr_t)temp;
return sema;
}
/**
*
* @brief Takes binary semaphore.
*
* @param[in] sema pointer to instance of @p struct pios_semaphore
* @param[in] timeout_ms timeout for acquiring the lock in milliseconds
*
* @returns true on success or false on timeout or failure
*
*/
bool PIOS_Semaphore_Take(struct pios_semaphore *sema, uint32_t timeout_ms)
{
PIOS_Assert(sema != NULL);
portTickType timeout_ticks;
if (timeout_ms == PIOS_SEMAPHORE_TIMEOUT_MAX) {
timeout_ticks = portMAX_DELAY;
} else {
timeout_ticks = MS2TICKS(timeout_ms);
}
return xSemaphoreTake(sema->sema_handle, timeout_ticks) == pdTRUE;
}
/**
*
* @brief Gives binary semaphore.
*
* @param[in] sema pointer to instance of @p struct pios_semaphore
*
* @returns true on success or false on timeout or failure
*
*/
bool PIOS_Semaphore_Give(struct pios_semaphore *sema)
{
PIOS_Assert(sema != NULL);
return xSemaphoreGive(sema->sema_handle) == pdTRUE;
}
/* Workaround for simulator version of FreeRTOS. */
#if !defined(SIM_POSIX)
/**
*
* @brief Takes binary semaphore from ISR context.
*
* @param[in] sema pointer to instance of @p struct pios_semaphore
* @param[out] woken pointer to bool which will be set true if a context switch is required
*
* @returns true on success or false on timeout or failure
*
*/
bool PIOS_Semaphore_Take_FromISR(struct pios_semaphore *sema, bool *woken)
{
PIOS_Assert(sema != NULL);
PIOS_Assert(woken != NULL);
signed portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
bool result = xSemaphoreTakeFromISR(sema->sema_handle, &xHigherPriorityTaskWoken) == pdTRUE;
*woken = *woken || xHigherPriorityTaskWoken == pdTRUE;
return result;
}
/**
*
* @brief Gives binary semaphore from ISR context.
*
* @param[in] sema pointer to instance of @p struct pios_semaphore
* @param[out] woken pointer to bool which will be set true if a context switch is required
*
* @returns true on success or false on timeout or failure
*
*/
bool PIOS_Semaphore_Give_FromISR(struct pios_semaphore *sema, bool *woken)
{
PIOS_Assert(sema != NULL);
PIOS_Assert(woken != NULL);
signed portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
bool result = xSemaphoreGiveFromISR(sema->sema_handle, &xHigherPriorityTaskWoken) == pdTRUE;
*woken = *woken || xHigherPriorityTaskWoken == pdTRUE;
return result;
}
#endif /* !defined(SIM_POSIX) */
#elif defined(PIOS_INCLUDE_CHIBIOS)
/**
*
* @brief Creates a binary semaphore.
*
* @returns instance of @p struct pios_semaphore or NULL on failure
*
*/
struct pios_semaphore *PIOS_Semaphore_Create(void)
{
struct pios_semaphore *sema = PIOS_malloc(sizeof(struct pios_semaphore));
if (sema == NULL) {
return NULL;
}
/*
* The initial state of a binary semaphore is "given".
*/
chBSemInit(&sema->sema, false);
return sema;
}
/**
*
* @brief Takes binary semaphore.
*
* @param[in] sema pointer to instance of @p struct pios_semaphore
* @param[in] timeout_ms timeout for acquiring the lock in milliseconds
*
* @returns true on success or false on timeout or failure
*
*/
bool PIOS_Semaphore_Take(struct pios_semaphore *sema, uint32_t timeout_ms)
{
PIOS_Assert(sema != NULL);
if (timeout_ms == PIOS_SEMAPHORE_TIMEOUT_MAX) {
return chBSemWait(&sema->sema) == RDY_OK;
} else if (timeout_ms == 0) {
return chBSemWaitTimeout(&sema->sema, TIME_IMMEDIATE) == RDY_OK;
} else {
return chBSemWaitTimeout(&sema->sema, MS2ST(timeout_ms)) == RDY_OK;
}
}
/**
*
* @brief Gives binary semaphore.
*
* @param[in] sema pointer to instance of @p struct pios_semaphore
*
* @returns true on success or false on timeout or failure
*
*/
bool PIOS_Semaphore_Give(struct pios_semaphore *sema)
{
PIOS_Assert(sema != NULL);
chBSemSignal(&sema->sema);
return true;
}
/**
*
* @brief Takes binary semaphore from ISR context.
*
* @param[in] sema pointer to instance of @p struct pios_semaphore
* @param[out] woken pointer to bool which will be set true if a context switch is required
*
* @returns true on success or false on timeout or failure
*
*/
bool PIOS_Semaphore_Take_FromISR(struct pios_semaphore *sema, bool *woken)
{
/* Waiting on a semaphore within an interrupt is not supported by ChibiOS. */
PIOS_Assert(false);
return false;
}
/**
*
* @brief Gives binary semaphore from ISR context.
*
* @param[in] sema pointer to instance of @p struct pios_semaphore
* @param[out] woken pointer to bool which will be set true if a context switch is required
*
* @returns true on success or false on timeout or failure
*
*/
bool PIOS_Semaphore_Give_FromISR(struct pios_semaphore *sema, bool *woken)
{
PIOS_Assert(sema != NULL);
PIOS_Assert(woken != NULL);
chSysLockFromIsr();
chBSemSignalI(&sema->sema);
chSysUnlockFromIsr();
return true;
}
#elif defined(PIOS_INCLUDE_IRQ)
/**
*
* @brief Creates a binary semaphore.
*
* @returns instance of @p struct pios_semaphore or NULL on failure
*
*/
struct pios_semaphore *PIOS_Semaphore_Create(void)
{
struct pios_semaphore *sema = PIOS_malloc_no_dma(sizeof(struct pios_semaphore));
if (sema == NULL) {
return NULL;
}
/*
* The initial state of a binary semaphore is "given".
*/
sema->sema_count = 1;
return sema;
}
/**
*
* @brief Takes binary semaphore.
*
* @param[in] sema pointer to instance of @p struct pios_semaphore
* @param[in] timeout_ms timeout for acquiring the lock in milliseconds
*
* @returns true on success or false on timeout or failure
*
*/
bool PIOS_Semaphore_Take(struct pios_semaphore *sema, uint32_t timeout_ms)
{
PIOS_Assert(sema != NULL);
uint32_t start = PIOS_DELAY_GetRaw();
uint32_t temp_sema_count;
do {
PIOS_IRQ_Disable();
if ((temp_sema_count = sema->sema_count) != 0) {
--sema->sema_count;
}
PIOS_IRQ_Enable();
} while (temp_sema_count == 0 &&
PIOS_DELAY_DiffuS(start) < timeout_ms * 1000);
return temp_sema_count != 0;
}
/**
*
* @brief Gives binary semaphore.
*
* @param[in] sema pointer to instance of @p struct pios_semaphore
*
* @returns true on success or false on timeout or failure
*
*/
bool PIOS_Semaphore_Give(struct pios_semaphore *sema)
{
PIOS_Assert(sema != NULL);
bool result = true;
PIOS_IRQ_Disable();
if (sema->sema_count == 0) {
++sema->sema_count;
} else {
result = false;
}
PIOS_IRQ_Enable();
return result;
}
/* Workaround for simulator version of FreeRTOS. */
#if !defined(SIM_POSIX)
/**
*
* @brief Takes binary semaphore from ISR context.
*
* @param[in] sema pointer to instance of @p struct pios_semaphore
* @param[out] woken pointer to bool which will be set true if a context switch is required
*
* @returns true on success or false on timeout or failure
*
*/
bool PIOS_Semaphore_Take_FromISR(struct pios_semaphore *sema, bool *woken)
{
PIOS_Assert(sema != NULL);
bool result = true;
PIOS_IRQ_Disable();
if (sema->sema_count != 0) {
--sema->sema_count;
} else {
result = false;
}
PIOS_IRQ_Enable();
return result;
}
/**
*
* @brief Gives binary semaphore from ISR context.
*
* @param[in] sema pointer to instance of @p struct pios_semaphore
* @param[out] woken pointer to bool which will be set true if a context switch is required
*
* @returns true on success or false on timeout or failure
*
*/
bool PIOS_Semaphore_Give_FromISR(struct pios_semaphore *sema, bool *woken)
{
PIOS_Assert(sema != NULL);
bool result = true;
PIOS_IRQ_Disable();
if (sema->sema_count == 0) {
++sema->sema_count;
} else {
result = false;
}
PIOS_IRQ_Enable();
return result;
}
#endif /* !defined(SIM_POSIX) */
#endif /* defined(PIOS_INCLUDE_IRQ) */