projects/freertos/platform.c (229 lines of code) (raw):

// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. #include <stdlib.h> #include <stddef.h> #include <string.h> #include "platform_api.h" /** * An additional requirement of FreeRTOS in order to make use of semaphores (or any other calls) * from an ISR is a way to track when it is necessary to call the scheduler when exiting an ISR. * This call must be implemented by the platform to convey this detail in a meaningful way. * * It is not necessary to conditionally call this function. It will be called regardless of the * value of the yield flag. * * @param yield Flag indicating if a task has been awoken and needs to be scheduled. */ void freertos_isr_update_yield (BaseType_t yield); void* platform_calloc (size_t nmemb, size_t size) { void *mem; mem = pvPortMalloc (nmemb * size); if (mem != NULL) { memset (mem, 0, nmemb * size); } return mem; } #if configFRTOS_MEMORY_SCHEME == 3 void* platform_realloc (void *ptr, size_t size) { void *mem; vTaskSuspendAll (); { mem = realloc (ptr, size); } (void) xTaskResumeAll (); return mem; } #endif int platform_mutex_init (platform_mutex *mutex) { if (mutex == NULL) { return PLATFORM_MUTEX_ERROR (PLATFORM_INVALID_ARGUMENT); } *mutex = xSemaphoreCreateMutex (); if (*mutex == NULL) { return PLATFORM_MUTEX_ERROR (PLATFORM_NO_MEMORY); } return 0; } int platform_mutex_free (platform_mutex *mutex) { if (mutex && *mutex) { vSemaphoreDelete (*mutex); } return 0; } int platform_mutex_lock (platform_mutex *mutex) { if (mutex == NULL) { return PLATFORM_MUTEX_ERROR (PLATFORM_INVALID_ARGUMENT); } xSemaphoreTake (*mutex, portMAX_DELAY); return 0; } int platform_mutex_unlock (platform_mutex *mutex) { if (mutex == NULL) { return PLATFORM_MUTEX_ERROR (PLATFORM_INVALID_ARGUMENT); } xSemaphoreGive (*mutex); return 0; } int platform_recursive_mutex_init (platform_mutex *mutex) { if (mutex == NULL) { return PLATFORM_MUTEX_ERROR (PLATFORM_INVALID_ARGUMENT); } *mutex = xSemaphoreCreateRecursiveMutex (); if (*mutex == NULL) { return PLATFORM_MUTEX_ERROR (PLATFORM_NO_MEMORY); } return 0; } int platform_recursive_mutex_lock (platform_mutex *mutex) { if (mutex == NULL) { return PLATFORM_MUTEX_ERROR (PLATFORM_INVALID_ARGUMENT); } xSemaphoreTakeRecursive (*mutex, portMAX_DELAY); return 0; } int platform_recursive_mutex_unlock (platform_mutex *mutex) { if (mutex == NULL) { return PLATFORM_MUTEX_ERROR (PLATFORM_INVALID_ARGUMENT); } xSemaphoreGiveRecursive (*mutex); return 0; } /** * Internal notification function for timer expiration. * * @param timer The timer that expired. */ static void platform_timer_notification (TimerHandle_t timer) { platform_timer *instance = pvTimerGetTimerID (timer); if (instance) { xSemaphoreTakeRecursive (instance->disarm_lock, portMAX_DELAY); if (!instance->disarm) { instance->callback (instance->context); } xSemaphoreGiveRecursive (instance->disarm_lock); } } int platform_timer_create (platform_timer *timer, timer_callback callback, void *context) { if ((timer == NULL) || (callback == NULL)) { return PLATFORM_TIMER_ERROR (PLATFORM_INVALID_ARGUMENT); } timer->disarm_lock = xSemaphoreCreateRecursiveMutex (); if (timer->disarm_lock == NULL) { return PLATFORM_TIMER_ERROR (PLATFORM_NO_MEMORY); } timer->timer = xTimerCreate ("SWTimer", 1, pdFALSE, timer, platform_timer_notification); if (timer->timer == NULL) { vSemaphoreDelete (timer->disarm_lock); return PLATFORM_TIMER_ERROR (PLATFORM_NO_MEMORY); } timer->callback = callback; timer->context = context; timer->disarm = 1; return 0; } int platform_timer_arm_one_shot (platform_timer *timer, uint32_t ms_timeout) { if ((timer == NULL) || (ms_timeout == 0)) { return PLATFORM_TIMER_ERROR (PLATFORM_INVALID_ARGUMENT); } xSemaphoreTakeRecursive (timer->disarm_lock, portMAX_DELAY); timer->disarm = 0; xTimerChangePeriod (timer->timer, pdMS_TO_TICKS (ms_timeout), portMAX_DELAY); xTimerReset (timer->timer, portMAX_DELAY); xSemaphoreGiveRecursive (timer->disarm_lock); return 0; } int platform_timer_disarm (platform_timer *timer) { if (timer == NULL) { return PLATFORM_TIMER_ERROR (PLATFORM_INVALID_ARGUMENT); } xSemaphoreTakeRecursive (timer->disarm_lock, portMAX_DELAY); timer->disarm = 1; xTimerStop (timer->timer, portMAX_DELAY); xSemaphoreGiveRecursive (timer->disarm_lock); return 0; } void platform_timer_delete (platform_timer *timer) { if (timer != NULL) { platform_timer_disarm (timer); platform_msleep (100); xTimerDelete (timer->timer, portMAX_DELAY); vSemaphoreDelete (timer->disarm_lock); } } int platform_semaphore_init (platform_semaphore *sem) { if (sem == NULL) { return PLATFORM_SEMAPHORE_ERROR (PLATFORM_INVALID_ARGUMENT); } *sem = xSemaphoreCreateBinary (); if (*sem == NULL) { return PLATFORM_SEMAPHORE_ERROR (PLATFORM_NO_MEMORY); } return 0; } void platform_semaphore_free (platform_semaphore *sem) { if (sem && *sem) { vSemaphoreDelete (*sem); } } int platform_semaphore_post (platform_semaphore *sem) { BaseType_t status; if (sem == NULL) { return PLATFORM_SEMAPHORE_ERROR (PLATFORM_INVALID_ARGUMENT); } status = xSemaphoreGive (*sem); return (status == pdTRUE) ? 0 : PLATFORM_SEMAPHORE_ERROR (PLATFORM_FAILURE); } int platform_semaphore_post_from_isr (platform_semaphore *sem) { BaseType_t status; BaseType_t yield = pdFALSE; if (sem == NULL) { return PLATFORM_SEMAPHORE_ERROR (PLATFORM_INVALID_ARGUMENT); } status = xSemaphoreGiveFromISR (*sem, &yield); freertos_isr_update_yield (yield); return (status == pdTRUE) ? 0 : PLATFORM_SEMAPHORE_ERROR (PLATFORM_FAILURE); } int platform_semaphore_wait (platform_semaphore *sem, uint32_t ms_timeout) { TickType_t timeout; BaseType_t status; if (sem == NULL) { return PLATFORM_SEMAPHORE_ERROR (PLATFORM_INVALID_ARGUMENT); } if (ms_timeout == 0) { timeout = portMAX_DELAY; } else { timeout = pdMS_TO_TICKS (ms_timeout); } status = xSemaphoreTake (*sem, timeout); return (status == pdTRUE) ? 0 : 1; } int platform_semaphore_try_wait (platform_semaphore *sem) { BaseType_t status; if (sem == NULL) { return PLATFORM_SEMAPHORE_ERROR (PLATFORM_INVALID_ARGUMENT); } status = xSemaphoreTake (*sem, 0); return (status == pdTRUE) ? 0 : 1; } int platform_semaphore_reset (platform_semaphore *sem) { if (sem == NULL) { return PLATFORM_SEMAPHORE_ERROR (PLATFORM_INVALID_ARGUMENT); } xSemaphoreTake (*sem, 0); return 0; } int platform_os_suspend_scheduler () { vTaskSuspendAll (); return 0; } int platform_os_resume_scheduler () { /* Don't care about the return. It only indicates if a context switched happened or not. The * return could be inspected to force a context switch, but that is probably not necessary. */ xTaskResumeAll (); return 0; }