/* * Copyright (c) 2020 Project CHIP Authors * Copyright (c) 2018-2019 Google LLC. * * 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. */ /* * * Description: * LwIP sys_arch definitions for use with FreeRTOS. * */ #include #include #include "FreeRTOS.h" #include "queue.h" #include "semphr.h" #include "task.h" #include "arch/sys_arch.h" #include "lwip/debug.h" #include "lwip/def.h" #include "lwip/mem.h" #include "lwip/opt.h" #include "lwip/stats.h" #include "lwip/sys.h" #ifndef LWIP_FREERTOS_USE_STATIC_TCPIP_TASK #define LWIP_FREERTOS_USE_STATIC_TCPIP_TASK configSUPPORT_STATIC_ALLOCATION #endif #ifndef LWIP_FREERTOS_USE_STATIC_TCPIP_QUEUE #define LWIP_FREERTOS_USE_STATIC_TCPIP_QUEUE configSUPPORT_STATIC_ALLOCATION #endif #if LWIP_FREERTOS_USE_STATIC_TCPIP_TASK static StaticTask_t gTCPIPTask; static StackType_t gTCPIPTaskStack[TCPIP_THREAD_STACKSIZE / sizeof(StackType_t)]; #endif #if LWIP_FREERTOS_USE_STATIC_TCPIP_QUEUE static StaticQueue_t gTCPIPMsgQueue; static uint8_t gTCPIPMsgQueueStorage[SYS_MESG_QUEUE_LENGTH * sizeof(void *)]; #endif static inline u32_t TicksToMS(TickType_t ticks) { return (ticks * 1000) / configTICK_RATE_HZ; } void sys_init(void) { // nothing to do. } err_t sys_sem_new(sys_sem_t * sem, u8_t count) { *sem = xSemaphoreCreateBinary(); if (*sem != NULL) { if (count != 0) { xSemaphoreGive(*sem); } SYS_STATS_INC_USED(sem); return ERR_OK; } else { SYS_STATS_INC(sem.err); return ERR_MEM; } } void sys_sem_free(sys_sem_t * sem) { vSemaphoreDelete(*sem); SYS_STATS_DEC(sem); } void sys_sem_signal(sys_sem_t * sem) { xSemaphoreGive(*sem); } u32_t sys_arch_sem_wait(sys_sem_t * sem, u32_t timeout) { TickType_t timeoutTicks, startTime; BaseType_t res; if (timeout == 0) timeoutTicks = portMAX_DELAY; else timeoutTicks = pdMS_TO_TICKS(timeout); startTime = xTaskGetTickCount(); do { res = xSemaphoreTake(*sem, timeoutTicks); } while (res != pdTRUE && timeout == 0); if (res == pdTRUE) { u32_t elapsedTime = TicksToMS(xTaskGetTickCount() - startTime); if (elapsedTime == 0) elapsedTime = 1; return elapsedTime; } else return SYS_ARCH_TIMEOUT; } err_t sys_mutex_new(sys_mutex_t * mutex) { *mutex = xSemaphoreCreateMutex(); if (*mutex != NULL) { xSemaphoreGive(*mutex); SYS_STATS_INC_USED(mutex); return ERR_OK; } else { SYS_STATS_INC(mutex.err); return ERR_MEM; } } void sys_mutex_free(sys_mutex_t * mutex) { vSemaphoreDelete(*mutex); SYS_STATS_DEC(mutex); } void sys_mutex_lock(sys_mutex_t * mutex) { xSemaphoreTake(*mutex, portMAX_DELAY); } void sys_mutex_unlock(sys_mutex_t * mutex) { xSemaphoreGive(*mutex); } err_t sys_mbox_new(sys_mbox_t * mbox, int size) { if (size != SYS_MESG_QUEUE_LENGTH) { SYS_STATS_INC(mbox.err); return ERR_MEM; } #if LWIP_FREERTOS_USE_STATIC_TCPIP_QUEUE *mbox = xQueueCreateStatic((UBaseType_t) size, (UBaseType_t) sizeof(void *), gTCPIPMsgQueueStorage, &gTCPIPMsgQueue); #else *mbox = xQueueCreate((UBaseType_t) size, (UBaseType_t) sizeof(void *)); #endif if (*mbox != NULL) { SYS_STATS_INC_USED(mbox); return ERR_OK; } else { SYS_STATS_INC(mbox.err); return ERR_MEM; } } void sys_mbox_free(sys_mbox_t * mbox) { vQueueDelete(*mbox); } void sys_mbox_post(sys_mbox_t * mbox, void * msg) { BaseType_t res; res = xQueueSendToBack(*mbox, &msg, pdMS_TO_TICKS(SYS_POST_BLOCK_TIME_MS)); LWIP_ASSERT("Error posting to LwIP mbox", res == pdTRUE); } u32_t sys_arch_mbox_fetch(sys_mbox_t * mbox, void ** msg, u32_t timeout) { TickType_t timeoutTicks, startTime; BaseType_t res; void * dummy; if (msg == NULL) msg = &dummy; if (timeout == 0) timeoutTicks = portMAX_DELAY; else timeoutTicks = pdMS_TO_TICKS(timeout); startTime = xTaskGetTickCount(); do { res = xQueueReceive(*mbox, (void *) msg, timeoutTicks); } while (res != pdTRUE && timeout == 0); if (res == pdTRUE) { u32_t elapsedTime = TicksToMS(xTaskGetTickCount() - startTime); if (elapsedTime == 0) elapsedTime = 1; return elapsedTime; } else { *msg = NULL; return SYS_ARCH_TIMEOUT; } } u32_t sys_arch_mbox_tryfetch(sys_mbox_t * mbox, void ** msg) { BaseType_t res; void * dummy; if (msg == NULL) msg = &dummy; res = xQueueReceive(*mbox, (void *) msg, 0); return (res == pdTRUE) ? 0 : SYS_MBOX_EMPTY; } err_t sys_mbox_trypost(sys_mbox_t * mbox, void * msg) { BaseType_t res; res = xQueueSendToBack(*mbox, &msg, 0); if (res == pdTRUE) return ERR_OK; else { SYS_STATS_INC(mbox.err); return ERR_MEM; } } sys_thread_t sys_thread_new(const char * name, lwip_thread_fn thread, void * arg, int stacksize, int prio) { TaskHandle_t taskH; const unsigned short stacksizeWords = (unsigned short) (stacksize / sizeof(StackType_t)); if (strcmp(name, TCPIP_THREAD_NAME) != 0 || stacksize != TCPIP_THREAD_STACKSIZE) return NULL; #if LWIP_FREERTOS_USE_STATIC_TCPIP_TASK taskH = xTaskCreateStatic(thread, name, stacksizeWords, arg, (UBaseType_t) prio, gTCPIPTaskStack, &gTCPIPTask); #else // LWIP_FREERTOS_USE_STATIC_TCPIP_TASK if (xTaskCreate(thread, name, stacksizeWords, arg, (UBaseType_t) prio, &taskH) != pdPASS) taskH = NULL; #endif // LWIP_FREERTOS_USE_STATIC_TCPIP_TASK return taskH; } err_t sys_thread_finish(sys_thread_t t) { #if INCLUDE_vTaskDelete TaskHandle_t taskH = (TaskHandle_t) t; vTaskDelete(taskH); #endif return ERR_OK; } u32_t sys_now(void) { return TicksToMS(xTaskGetTickCount()); } sys_prot_t sys_arch_protect(void) { return taskENTER_CRITICAL_FROM_ISR(); } void sys_arch_unprotect(sys_prot_t pval) { taskEXIT_CRITICAL_FROM_ISR(pval); }