diff --git a/Core/Src/main.c b/Core/Src/main.c index da059fb..b02d3bd 100644 --- a/Core/Src/main.c +++ b/Core/Src/main.c @@ -22,7 +22,7 @@ /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ - +#include "ucos_ii.h" /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ @@ -46,13 +46,12 @@ DMA_HandleTypeDef hdma_usart1_rx; DMA_HandleTypeDef hdma_usart1_tx; /* USER CODE BEGIN PV */ - static const uint8_t uart1_test_message[] = "USART1 DMA TX TEST\r\n"; static volatile uint32_t uart1_tx_ok_count; static volatile uint32_t uart1_tx_busy_count; static volatile uint32_t uart1_tx_error_count; static volatile uint32_t uart1_tx_complete_count; - +static OS_STK AppTaskStartStk[APP_TASK_START_STK_SIZE]; /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ @@ -61,12 +60,45 @@ static void MX_GPIO_Init(void); static void MX_DMA_Init(void); static void MX_USART1_UART_Init(void); /* USER CODE BEGIN PFP */ +static void AppTaskStart(void *p_arg); + + /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ +static void AppTaskStart(void *p_arg) +{ + HAL_StatusTypeDef uart_status; + + (void)p_arg; + + while (1) + { + uart_status = HAL_UART_Transmit_DMA(&huart1, + (uint8_t *)uart1_test_message, + sizeof(uart1_test_message) - 1U); + + if (uart_status == HAL_OK) + { + uart1_tx_ok_count++; + } + else if (uart_status == HAL_BUSY) + { + uart1_tx_busy_count++; + } + else + { + uart1_tx_error_count++; + } + + OSTimeDly(OS_TICKS_PER_SEC); + } +} + + /* USER CODE END 0 */ /** @@ -102,7 +134,24 @@ int main(void) MX_USB_DEVICE_Init(); MX_USART1_UART_Init(); /* USER CODE BEGIN 2 */ - + INT8U os_err; + OSInit(); + os_err = OSTaskCreateExt(AppTaskStart, + 0, + &AppTaskStartStk[APP_TASK_START_STK_SIZE - 1u], + APP_TASK_START_PRIO, + APP_TASK_START_PRIO, + &AppTaskStartStk[0], + APP_TASK_START_STK_SIZE, + 0, + (OS_TASK_OPT_STK_CHK | + OS_TASK_OPT_STK_CLR)); + + if (os_err != OS_ERR_NONE) + { + Error_Handler(); + } + OSStart(); /* USER CODE END 2 */ /* Infinite loop */ @@ -112,26 +161,7 @@ int main(void) /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ - HAL_StatusTypeDef uart_status; - - uart_status = HAL_UART_Transmit_DMA(&huart1, - (uint8_t *)uart1_test_message, - sizeof(uart1_test_message) - 1U); - - if (uart_status == HAL_OK) - { - uart1_tx_ok_count++; - } - else if (uart_status == HAL_BUSY) - { - uart1_tx_busy_count++; - } - else - { - uart1_tx_error_count++; - } - HAL_Delay(1000U); } /* USER CODE END 3 */ } diff --git a/Core/Src/stm32f4xx_it.c b/Core/Src/stm32f4xx_it.c index 47664e9..bd7fbca 100644 --- a/Core/Src/stm32f4xx_it.c +++ b/Core/Src/stm32f4xx_it.c @@ -22,6 +22,7 @@ #include "stm32f4xx_it.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ +#include "ucos_ii.h" /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ @@ -191,7 +192,10 @@ void SysTick_Handler(void) /* USER CODE END SysTick_IRQn 0 */ HAL_IncTick(); /* USER CODE BEGIN SysTick_IRQn 1 */ - + if (OSRunning == OS_TRUE) + { + OS_CPU_SysTickHandler(); + } /* USER CODE END SysTick_IRQn 1 */ } diff --git a/EWARM/Modbus.ewp b/EWARM/Modbus.ewp index 419f78d..55c8775 100644 --- a/EWARM/Modbus.ewp +++ b/EWARM/Modbus.ewp @@ -1,1181 +1,1261 @@ - 3 - - Modbus - - ARM - - 1 - - General - 3 - - 31 - 1 + 3 + + Modbus + + ARM + 1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ICCARM - 2 - - 35 - 1 - 1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - AARM - 2 - - 10 - 1 - 1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OBJCOPY - 0 - - 1 - 1 - 1 - - - - - - - - - CUSTOM - 3 - - - - 0 - - - - BICOMP - 0 - - - - BUILDACTION - 1 - - - - - - - ILINK - 0 - - 22 - 1 - 1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - IARCHIVE - 0 - - 0 - 1 - 1 - - - - - - - BILINK - 0 - - - - Coder - 0 - - - - - Application + + General + 3 + + 31 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ICCARM + 2 + + 35 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AARM + 2 + + 10 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OBJCOPY + 0 + + 1 + 1 + 1 + + + + + + + + + CUSTOM + 3 + + + + 0 + + + + BICOMP + 0 + + + + BUILDACTION + 1 + + + + + + + ILINK + 0 + + 23 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + IARCHIVE + 0 + + 0 + 1 + 1 + + + + + + + BILINK + 0 + + + + Coder + 0 + + + - EWARM - - $PROJ_DIR$/startup_stm32f407xx.s - - - - User - - Core - - $PROJ_DIR$/../Core/Src/main.c - - - $PROJ_DIR$/../Core/Src/stm32f4xx_it.c - - - $PROJ_DIR$/../Core/Src/stm32f4xx_hal_msp.c - - - - USB_DEVICE + Application - App - - $PROJ_DIR$/../USB_DEVICE/App/usb_device.c - - - $PROJ_DIR$/../USB_DEVICE/App/usbd_desc.c - - - $PROJ_DIR$/../USB_DEVICE/App/usbd_cdc_if.c - + EWARM + + $PROJ_DIR$\startup_stm32f407xx.s + - Target - - $PROJ_DIR$/../USB_DEVICE/Target/usbd_conf.c - + User + + Core + + $PROJ_DIR$\..\Core\Src\main.c + + + $PROJ_DIR$\..\Core\Src\stm32f4xx_hal_msp.c + + + $PROJ_DIR$\..\Core\Src\stm32f4xx_it.c + + + + USB_DEVICE + + App + + $PROJ_DIR$\..\USB_DEVICE\App\usb_device.c + + + $PROJ_DIR$\..\USB_DEVICE\App\usbd_cdc_if.c + + + $PROJ_DIR$\..\USB_DEVICE\App\usbd_desc.c + + + + Target + + $PROJ_DIR$\..\USB_DEVICE\Target\usbd_conf.c + + + - - - - Drivers - STM32F4xx_HAL_Driver - - $PROJ_DIR$/../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pcd.c - - - $PROJ_DIR$/../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pcd_ex.c - - - $PROJ_DIR$/../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_usb.c - - - $PROJ_DIR$/../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rcc.c - - - $PROJ_DIR$/../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rcc_ex.c - - - $PROJ_DIR$/../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash.c - - - $PROJ_DIR$/../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash_ex.c - - - $PROJ_DIR$/../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash_ramfunc.c - - - $PROJ_DIR$/../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_gpio.c - - - $PROJ_DIR$/../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma_ex.c - - - $PROJ_DIR$/../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma.c - - - $PROJ_DIR$/../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pwr.c - - - $PROJ_DIR$/../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pwr_ex.c - - - $PROJ_DIR$/../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_cortex.c - - - $PROJ_DIR$/../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal.c - - - $PROJ_DIR$/../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_exti.c - - - $PROJ_DIR$/../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_uart.c - + Drivers + + CMSIS + + $PROJ_DIR$\..\Core\Src\system_stm32f4xx.c + + + + STM32F4xx_HAL_Driver + + $PROJ_DIR$\..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal.c + + + $PROJ_DIR$\..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_cortex.c + + + $PROJ_DIR$\..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_dma.c + + + $PROJ_DIR$\..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_dma_ex.c + + + $PROJ_DIR$\..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_exti.c + + + $PROJ_DIR$\..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_flash.c + + + $PROJ_DIR$\..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_flash_ex.c + + + $PROJ_DIR$\..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_flash_ramfunc.c + + + $PROJ_DIR$\..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_gpio.c + + + $PROJ_DIR$\..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_pcd.c + + + $PROJ_DIR$\..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_pcd_ex.c + + + $PROJ_DIR$\..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_pwr.c + + + $PROJ_DIR$\..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_pwr_ex.c + + + $PROJ_DIR$\..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_rcc.c + + + $PROJ_DIR$\..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_rcc_ex.c + + + $PROJ_DIR$\..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_uart.c + + + $PROJ_DIR$\..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_ll_usb.c + + - CMSIS - - $PROJ_DIR$/../Core/Src/system_stm32f4xx.c - + Micrium + + Micrium Config + + $PROJ_DIR$\..\Middlewares\Third_Party\Micrium\Config\app_cfg.h + + + $PROJ_DIR$\..\Middlewares\Third_Party\Micrium\Config\cpu_cfg.h + + + $PROJ_DIR$\..\Middlewares\Third_Party\Micrium\Config\os_cfg.h + + + + uCOS-II Port + + $PROJ_DIR$\..\Middlewares\Third_Party\Micrium\uCOS-II\Ports\ARM-Cortex-M4\IAR\os_cpu_a.asm + + + $PROJ_DIR$\..\Middlewares\Third_Party\Micrium\uCOS-II\Ports\ARM-Cortex-M4\IAR\os_cpu_c.c + + + $PROJ_DIR$\..\Middlewares\Third_Party\Micrium\uCOS-II\Ports\ARM-Cortex-M4\IAR\os_dbg.c + + + + uCOS-II Source + + $PROJ_DIR$\..\Middlewares\Third_Party\Micrium\uCOS-II\Source\os_core.c + + + $PROJ_DIR$\..\Middlewares\Third_Party\Micrium\uCOS-II\Source\os_flag.c + + + $PROJ_DIR$\..\Middlewares\Third_Party\Micrium\uCOS-II\Source\os_mbox.c + + + $PROJ_DIR$\..\Middlewares\Third_Party\Micrium\uCOS-II\Source\os_mem.c + + + $PROJ_DIR$\..\Middlewares\Third_Party\Micrium\uCOS-II\Source\os_mutex.c + + + $PROJ_DIR$\..\Middlewares\Third_Party\Micrium\uCOS-II\Source\os_q.c + + + $PROJ_DIR$\..\Middlewares\Third_Party\Micrium\uCOS-II\Source\os_sem.c + + + $PROJ_DIR$\..\Middlewares\Third_Party\Micrium\uCOS-II\Source\os_task.c + + + $PROJ_DIR$\..\Middlewares\Third_Party\Micrium\uCOS-II\Source\os_time.c + + + $PROJ_DIR$\..\Middlewares\Third_Party\Micrium\uCOS-II\Source\os_tmr.c + + - - - Middlewares - USB_Device_Library - - $PROJ_DIR$/../Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_core.c - - - $PROJ_DIR$/../Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ctlreq.c - - - $PROJ_DIR$/../Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ioreq.c - - - $PROJ_DIR$/../Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c - + Middlewares + + USB_Device_Library + + $PROJ_DIR$\..\Middlewares\ST\STM32_USB_Device_Library\Class\CDC\Src\usbd_cdc.c + + + $PROJ_DIR$\..\Middlewares\ST\STM32_USB_Device_Library\Core\Src\usbd_core.c + + + $PROJ_DIR$\..\Middlewares\ST\STM32_USB_Device_Library\Core\Src\usbd_ctlreq.c + + + $PROJ_DIR$\..\Middlewares\ST\STM32_USB_Device_Library\Core\Src\usbd_ioreq.c + + - - diff --git a/EWARM/Modbus.ewt b/EWARM/Modbus.ewt new file mode 100644 index 0000000..be6db69 --- /dev/null +++ b/EWARM/Modbus.ewt @@ -0,0 +1,1375 @@ + + + 3 + + Modbus + + ARM + + 1 + + C-STAT + 262 + + 262 + + 0 + + 1 + 600 + 1 + 10 + 0 + 1 + 100 + + + 1.6.2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + RuntimeChecking + 0 + + 2 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + Application + + EWARM + + $PROJ_DIR$\startup_stm32f407xx.s + + + + User + + Core + + $PROJ_DIR$\..\Core\Src\main.c + + + $PROJ_DIR$\..\Core\Src\stm32f4xx_hal_msp.c + + + $PROJ_DIR$\..\Core\Src\stm32f4xx_it.c + + + + USB_DEVICE + + App + + $PROJ_DIR$\..\USB_DEVICE\App\usb_device.c + + + $PROJ_DIR$\..\USB_DEVICE\App\usbd_cdc_if.c + + + $PROJ_DIR$\..\USB_DEVICE\App\usbd_desc.c + + + + Target + + $PROJ_DIR$\..\USB_DEVICE\Target\usbd_conf.c + + + + + + + Drivers + + CMSIS + + $PROJ_DIR$\..\Core\Src\system_stm32f4xx.c + + + + STM32F4xx_HAL_Driver + + $PROJ_DIR$\..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal.c + + + $PROJ_DIR$\..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_cortex.c + + + $PROJ_DIR$\..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_dma.c + + + $PROJ_DIR$\..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_dma_ex.c + + + $PROJ_DIR$\..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_exti.c + + + $PROJ_DIR$\..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_flash.c + + + $PROJ_DIR$\..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_flash_ex.c + + + $PROJ_DIR$\..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_flash_ramfunc.c + + + $PROJ_DIR$\..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_gpio.c + + + $PROJ_DIR$\..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_pcd.c + + + $PROJ_DIR$\..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_pcd_ex.c + + + $PROJ_DIR$\..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_pwr.c + + + $PROJ_DIR$\..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_pwr_ex.c + + + $PROJ_DIR$\..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_rcc.c + + + $PROJ_DIR$\..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_rcc_ex.c + + + $PROJ_DIR$\..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_uart.c + + + $PROJ_DIR$\..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_ll_usb.c + + + + + Micrium + + Micrium Config + + $PROJ_DIR$\..\Middlewares\Third_Party\Micrium\Config\app_cfg.h + + + $PROJ_DIR$\..\Middlewares\Third_Party\Micrium\Config\cpu_cfg.h + + + $PROJ_DIR$\..\Middlewares\Third_Party\Micrium\Config\os_cfg.h + + + + uCOS-II Port + + $PROJ_DIR$\..\Middlewares\Third_Party\Micrium\uCOS-II\Ports\ARM-Cortex-M4\IAR\os_cpu_a.asm + + + $PROJ_DIR$\..\Middlewares\Third_Party\Micrium\uCOS-II\Ports\ARM-Cortex-M4\IAR\os_cpu_c.c + + + $PROJ_DIR$\..\Middlewares\Third_Party\Micrium\uCOS-II\Ports\ARM-Cortex-M4\IAR\os_dbg.c + + + + uCOS-II Source + + $PROJ_DIR$\..\Middlewares\Third_Party\Micrium\uCOS-II\Source\os_core.c + + + $PROJ_DIR$\..\Middlewares\Third_Party\Micrium\uCOS-II\Source\os_flag.c + + + $PROJ_DIR$\..\Middlewares\Third_Party\Micrium\uCOS-II\Source\os_mbox.c + + + $PROJ_DIR$\..\Middlewares\Third_Party\Micrium\uCOS-II\Source\os_mem.c + + + $PROJ_DIR$\..\Middlewares\Third_Party\Micrium\uCOS-II\Source\os_mutex.c + + + $PROJ_DIR$\..\Middlewares\Third_Party\Micrium\uCOS-II\Source\os_q.c + + + $PROJ_DIR$\..\Middlewares\Third_Party\Micrium\uCOS-II\Source\os_sem.c + + + $PROJ_DIR$\..\Middlewares\Third_Party\Micrium\uCOS-II\Source\os_task.c + + + $PROJ_DIR$\..\Middlewares\Third_Party\Micrium\uCOS-II\Source\os_time.c + + + $PROJ_DIR$\..\Middlewares\Third_Party\Micrium\uCOS-II\Source\os_tmr.c + + + + + Middlewares + + USB_Device_Library + + $PROJ_DIR$\..\Middlewares\ST\STM32_USB_Device_Library\Class\CDC\Src\usbd_cdc.c + + + $PROJ_DIR$\..\Middlewares\ST\STM32_USB_Device_Library\Core\Src\usbd_core.c + + + $PROJ_DIR$\..\Middlewares\ST\STM32_USB_Device_Library\Core\Src\usbd_ctlreq.c + + + $PROJ_DIR$\..\Middlewares\ST\STM32_USB_Device_Library\Core\Src\usbd_ioreq.c + + + + diff --git a/EWARM/startup_stm32f407xx.s b/EWARM/startup_stm32f407xx.s index 9b0da01..21f1af4 100644 --- a/EWARM/startup_stm32f407xx.s +++ b/EWARM/startup_stm32f407xx.s @@ -48,6 +48,7 @@ EXTERN __iar_program_start EXTERN SystemInit + EXTERN OS_CPU_PendSVHandler PUBLIC __vector_table DATA @@ -67,7 +68,7 @@ __vector_table DCD SVC_Handler ; SVCall Handler DCD DebugMon_Handler ; Debug Monitor Handler DCD 0 ; Reserved - DCD PendSV_Handler ; PendSV Handler + DCD OS_CPU_PendSVHandler ; uC/OS-II context switch DCD SysTick_Handler ; SysTick Handler ; External Interrupts diff --git a/Middlewares/Third_Party/Micrium/Config/app_cfg.h b/Middlewares/Third_Party/Micrium/Config/app_cfg.h new file mode 100644 index 0000000..80634a2 --- /dev/null +++ b/Middlewares/Third_Party/Micrium/Config/app_cfg.h @@ -0,0 +1,10 @@ +#ifndef APP_CFG_H +#define APP_CFG_H + +#define APP_TASK_START_PRIO 5u +#define APP_TASK_TEST_PRIO 6u + +#define APP_TASK_START_STK_SIZE 256u +#define APP_TASK_TEST_STK_SIZE 256u + +#endif \ No newline at end of file diff --git a/Middlewares/Third_Party/Micrium/Config/cpu_cfg.h b/Middlewares/Third_Party/Micrium/Config/cpu_cfg.h new file mode 100644 index 0000000..90c45ff --- /dev/null +++ b/Middlewares/Third_Party/Micrium/Config/cpu_cfg.h @@ -0,0 +1,215 @@ +/* +********************************************************************************************************* +* uC/CPU +* CPU CONFIGURATION & PORT LAYER +* +* (c) Copyright 2004-2015; Micrium, Inc.; Weston, FL +* +* All rights reserved. Protected by international copyright laws. +* +* uC/CPU is provided in source form to registered licensees ONLY. It is +* illegal to distribute this source code to any third party unless you receive +* written permission by an authorized Micrium representative. Knowledge of +* the source code may NOT be used to develop a similar product. +* +* Please help us continue to provide the Embedded community with the finest +* software available. Your honesty is greatly appreciated. +* +* You can find our product's user manual, API reference, release notes and +* more information at https://doc.micrium.com. +* You can contact us at www.micrium.com. +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* +* CPU CONFIGURATION FILE +* +* TEMPLATE +* +* Filename : cpu_cfg.h +* Version : V1.30.02 +* Programmer(s) : SR +* ITJ +* JBL +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* MODULE +********************************************************************************************************* +*/ + +#ifndef CPU_CFG_MODULE_PRESENT +#define CPU_CFG_MODULE_PRESENT + + +/* +********************************************************************************************************* +* CPU NAME CONFIGURATION +* +* Note(s) : (1) Configure CPU_CFG_NAME_EN to enable/disable CPU host name feature : +* +* (a) CPU host name storage +* (b) CPU host name API functions +* +* (2) Configure CPU_CFG_NAME_SIZE with the desired ASCII string size of the CPU host name, +* including the terminating NULL character. +* +* See also 'cpu_core.h GLOBAL VARIABLES Note #1'. +********************************************************************************************************* +*/ + + /* Configure CPU host name feature (see Note #1) : */ +#define CPU_CFG_NAME_EN DEF_ENABLED + /* DEF_DISABLED CPU host name DISABLED */ + /* DEF_ENABLED CPU host name ENABLED */ + + /* Configure CPU host name ASCII string size ... */ +#define CPU_CFG_NAME_SIZE 16 /* ... (see Note #2). */ + + +/* +********************************************************************************************************* +* CPU TIMESTAMP CONFIGURATION +* +* Note(s) : (1) Configure CPU_CFG_TS_xx_EN to enable/disable CPU timestamp features : +* +* (a) CPU_CFG_TS_32_EN enable/disable 32-bit CPU timestamp feature +* (b) CPU_CFG_TS_64_EN enable/disable 64-bit CPU timestamp feature +* +* (2) (a) Configure CPU_CFG_TS_TMR_SIZE with the CPU timestamp timer's word size : +* +* CPU_WORD_SIZE_08 8-bit word size +* CPU_WORD_SIZE_16 16-bit word size +* CPU_WORD_SIZE_32 32-bit word size +* CPU_WORD_SIZE_64 64-bit word size +* +* (b) If the size of the CPU timestamp timer is not a binary multiple of 8-bit octets +* (e.g. 20-bits or even 24-bits), then the next lower, binary-multiple octet word +* size SHOULD be configured (e.g. to 16-bits). However, the minimum supported word +* size for CPU timestamp timers is 8-bits. +* +* See also 'cpu_core.h FUNCTION PROTOTYPES CPU_TS_TmrRd() Note #2a'. +********************************************************************************************************* +*/ + + /* Configure CPU timestamp features (see Note #1) : */ +#define CPU_CFG_TS_32_EN DEF_ENABLED +#define CPU_CFG_TS_64_EN DEF_DISABLED + /* DEF_DISABLED CPU timestamps DISABLED */ + /* DEF_ENABLED CPU timestamps ENABLED */ + + /* Configure CPU timestamp timer word size ... */ + /* ... (see Note #2) : */ +#define CPU_CFG_TS_TMR_SIZE CPU_WORD_SIZE_32 + + +/* +********************************************************************************************************* +* CPU INTERRUPTS DISABLED TIME MEASUREMENT CONFIGURATION +* +* Note(s) : (1) (a) Configure CPU_CFG_INT_DIS_MEAS_EN to enable/disable measuring CPU's interrupts +* disabled time : +* +* (a) Enabled, if CPU_CFG_INT_DIS_MEAS_EN #define'd in 'cpu_cfg.h' +* +* (b) Disabled, if CPU_CFG_INT_DIS_MEAS_EN NOT #define'd in 'cpu_cfg.h' +* +* See also 'cpu_core.h FUNCTION PROTOTYPES Note #1'. +* +* (b) Configure CPU_CFG_INT_DIS_MEAS_OVRHD_NBR with the number of times to measure & +* average the interrupts disabled time measurements overhead. +* +* See also 'cpu_core.c CPU_IntDisMeasInit() Note #3a'. +********************************************************************************************************* +*/ + +#if 1 /* Configure CPU interrupts disabled time ... */ +#define CPU_CFG_INT_DIS_MEAS_EN /* ... measurements feature (see Note #1a). */ +#endif + + /* Configure number of interrupts disabled overhead ... */ +#define CPU_CFG_INT_DIS_MEAS_OVRHD_NBR 1u /* ... time measurements (see Note #1b). */ + + +/* +********************************************************************************************************* +* CPU COUNT ZEROS CONFIGURATION +* +* Note(s) : (1) (a) Configure CPU_CFG_LEAD_ZEROS_ASM_PRESENT to define count leading zeros bits +* function(s) in : +* +* (1) 'cpu_a.asm', if CPU_CFG_LEAD_ZEROS_ASM_PRESENT #define'd in 'cpu.h'/ +* 'cpu_cfg.h' to enable assembly-optimized function(s) +* +* (2) 'cpu_core.c', if CPU_CFG_LEAD_ZEROS_ASM_PRESENT NOT #define'd in 'cpu.h'/ +* 'cpu_cfg.h' to enable C-source-optimized function(s) otherwise +* +* (b) Configure CPU_CFG_TRAIL_ZEROS_ASM_PRESENT to define count trailing zeros bits +* function(s) in : +* +* (1) 'cpu_a.asm', if CPU_CFG_TRAIL_ZEROS_ASM_PRESENT #define'd in 'cpu.h'/ +* 'cpu_cfg.h' to enable assembly-optimized function(s) +* +* (2) 'cpu_core.c', if CPU_CFG_TRAIL_ZEROS_ASM_PRESENT NOT #define'd in 'cpu.h'/ +* 'cpu_cfg.h' to enable C-source-optimized function(s) otherwise +********************************************************************************************************* +*/ + +#if 1 /* Configure CPU count leading zeros bits ... */ +#define CPU_CFG_LEAD_ZEROS_ASM_PRESENT /* ... assembly-version (see Note #1a). */ +#endif + +#if 0 /* Configure CPU count trailing zeros bits ... */ +#define CPU_CFG_TRAIL_ZEROS_ASM_PRESENT /* ... assembly-version (see Note #1b). */ +#endif + + +/* +********************************************************************************************************* +* CPU ENDIAN TYPE OVERRIDE +* +* Note(s) : (1) Configure CPU_CFG_ENDIAN_TYPE to override the default CPU endian type defined in cpu.h. +* +* (a) CPU_ENDIAN_TYPE_BIG Big- endian word order (CPU words' most significant +* octet @ lowest memory address) +* (b) CPU_ENDIAN_TYPE_LITTLE Little-endian word order (CPU words' least significant +* octet @ lowest memory address) +* +* (2) Defining CPU_CFG_ENDIAN_TYPE here is only valid for supported bi-endian architectures. +* See 'cpu.h CPU WORD CONFIGURATION Note #3' for details +********************************************************************************************************* +*/ + +#if 0 +#define CPU_CFG_ENDIAN_TYPE CPU_ENDIAN_TYPE_BIG /* Defines CPU data word-memory order (see Note #2). */ +#endif + + +/* +********************************************************************************************************* +* CACHE MANAGEMENT +* +* Note(s) : (1) Configure CPU_CFG_CACHE_MGMT_EN to enable the cache managment API. + +* +* (2) Defining CPU_CFG_CACHE_MGMT_EN to DEF_ENABLED only enable the cache management function. +* Cache are assumed to be configured and enabled by the time CPU_init() is called. +********************************************************************************************************* +*/ + +#define CPU_CFG_CACHE_MGMT_EN DEF_DISABLED /* Defines CPU data word-memory order (see Note #1). */ + + +/* +********************************************************************************************************* +* MODULE END +********************************************************************************************************* +*/ + +#endif /* End of CPU cfg module include. */ + diff --git a/Middlewares/Third_Party/Micrium/Config/os_cfg.h b/Middlewares/Third_Party/Micrium/Config/os_cfg.h new file mode 100644 index 0000000..4e2235d --- /dev/null +++ b/Middlewares/Third_Party/Micrium/Config/os_cfg.h @@ -0,0 +1,145 @@ +/* +********************************************************************************************************* +* uC/OS-II +* The Real-Time Kernel +* uC/OS-II Configuration File for V2.9x +* +* (c) Copyright 2005-2014, Micrium, Weston, FL +* All Rights Reserved +* +* +* File : OS_CFG.H +* By : Jean J. Labrosse +* Version : V2.92.11 +* +* LICENSING TERMS: +* --------------- +* uC/OS-II is provided in source form for FREE evaluation, for educational use or for peaceful research. +* If you plan on using uC/OS-II in a commercial product you need to contact Micrium to properly license +* its use in your product. We provide ALL the source code for your convenience and to help you experience +* uC/OS-II. The fact that the source is provided does NOT mean that you can use it without paying a +* licensing fee. +********************************************************************************************************* +*/ + +#ifndef OS_CFG_H +#define OS_CFG_H + + + /* ---------------------- MISCELLANEOUS ----------------------- */ +#define OS_APP_HOOKS_EN 0u /* Application-defined hooks are called from the uC/OS-II hooks */ +#define OS_ARG_CHK_EN 0u /* Enable (1) or Disable (0) argument checking */ +#define OS_CPU_HOOKS_EN 1u /* uC/OS-II hooks are found in the processor port files */ + +#define OS_DEBUG_EN 1u /* Enable(1) debug variables */ + +#define OS_EVENT_MULTI_EN 1u /* Include code for OSEventPendMulti() */ +#define OS_EVENT_NAME_EN 1u /* Enable names for Sem, Mutex, Mbox and Q */ + +#define OS_LOWEST_PRIO 63u /* Defines the lowest priority that can be assigned ... */ + /* ... MUST NEVER be higher than 254! */ + +#define OS_MAX_EVENTS 20u /* Max. number of event control blocks in your application */ +#define OS_MAX_FLAGS 5u /* Max. number of Event Flag Groups in your application */ +#define OS_MAX_MEM_PART 5u /* Max. number of memory partitions */ +#define OS_MAX_QS 4u /* Max. number of queue control blocks in your application */ +#define OS_MAX_TASKS 10u /* Max. number of tasks in your application, MUST be >= 2 */ + +#define OS_SCHED_LOCK_EN 1u /* Include code for OSSchedLock() and OSSchedUnlock() */ + +#define OS_TICK_STEP_EN 1u /* Enable tick stepping feature for uC/OS-View */ +#define OS_TICKS_PER_SEC 1000u /* Set the number of ticks in one second */ + +#define OS_TLS_TBL_SIZE 0u /* Size of Thread-Local Storage Table */ + + + /* --------------------- TASK STACK SIZE ---------------------- */ +#define OS_TASK_TMR_STK_SIZE 128u /* Timer task stack size (# of OS_STK wide entries) */ +#define OS_TASK_STAT_STK_SIZE 128u /* Statistics task stack size (# of OS_STK wide entries) */ +#define OS_TASK_IDLE_STK_SIZE 128u /* Idle task stack size (# of OS_STK wide entries) */ + + + /* --------------------- TASK MANAGEMENT ---------------------- */ +#define OS_TASK_CHANGE_PRIO_EN 1u /* Include code for OSTaskChangePrio() */ +#define OS_TASK_CREATE_EN 1u /* Include code for OSTaskCreate() */ +#define OS_TASK_CREATE_EXT_EN 1u /* Include code for OSTaskCreateExt() */ +#define OS_TASK_DEL_EN 1u /* Include code for OSTaskDel() */ +#define OS_TASK_NAME_EN 1u /* Enable task names */ +#define OS_TASK_PROFILE_EN 1u /* Include variables in OS_TCB for profiling */ +#define OS_TASK_QUERY_EN 1u /* Include code for OSTaskQuery() */ +#define OS_TASK_REG_TBL_SIZE 1u /* Size of task variables array (#of INT32U entries) */ +#define OS_TASK_STAT_EN 0u /* Enable (1) or Disable(0) the statistics task */ +#define OS_TASK_STAT_STK_CHK_EN 0u /* Check task stacks from statistic task */ +#define OS_TASK_SUSPEND_EN 1u /* Include code for OSTaskSuspend() and OSTaskResume() */ +#define OS_TASK_SW_HOOK_EN 1u /* Include code for OSTaskSwHook() */ + + + /* ----------------------- EVENT FLAGS ------------------------ */ +#define OS_FLAG_EN 1u /* Enable (1) or Disable (0) code generation for EVENT FLAGS */ +#define OS_FLAG_ACCEPT_EN 1u /* Include code for OSFlagAccept() */ +#define OS_FLAG_DEL_EN 1u /* Include code for OSFlagDel() */ +#define OS_FLAG_NAME_EN 1u /* Enable names for event flag group */ +#define OS_FLAG_QUERY_EN 1u /* Include code for OSFlagQuery() */ +#define OS_FLAG_WAIT_CLR_EN 1u /* Include code for Wait on Clear EVENT FLAGS */ +#define OS_FLAGS_NBITS 16u /* Size in #bits of OS_FLAGS data type (8, 16 or 32) */ + + + /* -------------------- MESSAGE MAILBOXES --------------------- */ +#define OS_MBOX_EN 1u /* Enable (1) or Disable (0) code generation for MAILBOXES */ +#define OS_MBOX_ACCEPT_EN 1u /* Include code for OSMboxAccept() */ +#define OS_MBOX_DEL_EN 1u /* Include code for OSMboxDel() */ +#define OS_MBOX_PEND_ABORT_EN 1u /* Include code for OSMboxPendAbort() */ +#define OS_MBOX_POST_EN 1u /* Include code for OSMboxPost() */ +#define OS_MBOX_POST_OPT_EN 1u /* Include code for OSMboxPostOpt() */ +#define OS_MBOX_QUERY_EN 1u /* Include code for OSMboxQuery() */ + + + /* --------------------- MEMORY MANAGEMENT -------------------- */ +#define OS_MEM_EN 0u /* Enable (1) or Disable (0) code generation for MEMORY MANAGER */ +#define OS_MEM_NAME_EN 1u /* Enable memory partition names */ +#define OS_MEM_QUERY_EN 1u /* Include code for OSMemQuery() */ + + + /* ---------------- MUTUAL EXCLUSION SEMAPHORES --------------- */ +#define OS_MUTEX_EN 1u /* Enable (1) or Disable (0) code generation for MUTEX */ +#define OS_MUTEX_ACCEPT_EN 1u /* Include code for OSMutexAccept() */ +#define OS_MUTEX_DEL_EN 1u /* Include code for OSMutexDel() */ +#define OS_MUTEX_QUERY_EN 1u /* Include code for OSMutexQuery() */ + + + /* ---------------------- MESSAGE QUEUES ---------------------- */ +#define OS_Q_EN 1u /* Enable (1) or Disable (0) code generation for QUEUES */ +#define OS_Q_ACCEPT_EN 1u /* Include code for OSQAccept() */ +#define OS_Q_DEL_EN 1u /* Include code for OSQDel() */ +#define OS_Q_FLUSH_EN 1u /* Include code for OSQFlush() */ +#define OS_Q_PEND_ABORT_EN 1u /* Include code for OSQPendAbort() */ +#define OS_Q_POST_EN 1u /* Include code for OSQPost() */ +#define OS_Q_POST_FRONT_EN 1u /* Include code for OSQPostFront() */ +#define OS_Q_POST_OPT_EN 1u /* Include code for OSQPostOpt() */ +#define OS_Q_QUERY_EN 1u /* Include code for OSQQuery() */ + + + /* ------------------------ SEMAPHORES ------------------------ */ +#define OS_SEM_EN 1u /* Enable (1) or Disable (0) code generation for SEMAPHORES */ +#define OS_SEM_ACCEPT_EN 1u /* Include code for OSSemAccept() */ +#define OS_SEM_DEL_EN 1u /* Include code for OSSemDel() */ +#define OS_SEM_PEND_ABORT_EN 1u /* Include code for OSSemPendAbort() */ +#define OS_SEM_QUERY_EN 1u /* Include code for OSSemQuery() */ +#define OS_SEM_SET_EN 1u /* Include code for OSSemSet() */ + + + /* --------------------- TIME MANAGEMENT ---------------------- */ +#define OS_TIME_DLY_HMSM_EN 1u /* Include code for OSTimeDlyHMSM() */ +#define OS_TIME_DLY_RESUME_EN 1u /* Include code for OSTimeDlyResume() */ +#define OS_TIME_GET_SET_EN 1u /* Include code for OSTimeGet() and OSTimeSet() */ +#define OS_TIME_TICK_HOOK_EN 1u /* Include code for OSTimeTickHook() */ + + + /* --------------------- TIMER MANAGEMENT --------------------- */ +#define OS_TMR_EN 0u /* Enable (1) or Disable (0) code generation for TIMERS */ +#define OS_TMR_CFG_MAX 16u /* Maximum number of timers */ +#define OS_TMR_CFG_NAME_EN 1u /* Determine timer names */ +#define OS_TMR_CFG_WHEEL_SIZE 7u /* Size of timer wheel (#Spokes) */ +#define OS_TMR_CFG_TICKS_PER_SEC 10u /* Rate at which timer management task runs (Hz) */ + +#endif diff --git a/Middlewares/Third_Party/Micrium/uC-CPU/ARM-Cortex-M4/IAR/cpu.h b/Middlewares/Third_Party/Micrium/uC-CPU/ARM-Cortex-M4/IAR/cpu.h new file mode 100644 index 0000000..f84de5c --- /dev/null +++ b/Middlewares/Third_Party/Micrium/uC-CPU/ARM-Cortex-M4/IAR/cpu.h @@ -0,0 +1,754 @@ +/* +********************************************************************************************************* +* uC/CPU +* CPU CONFIGURATION & PORT LAYER +* +* (c) Copyright 2004-2015; Micrium, Inc.; Weston, FL +* +* All rights reserved. Protected by international copyright laws. +* +* uC/CPU is provided in source form to registered licensees ONLY. It is +* illegal to distribute this source code to any third party unless you receive +* written permission by an authorized Micrium representative. Knowledge of +* the source code may NOT be used to develop a similar product. +* +* Please help us continue to provide the Embedded community with the finest +* software available. Your honesty is greatly appreciated. +* +* You can find our product's user manual, API reference, release notes and +* more information at https://doc.micrium.com. +* You can contact us at www.micrium.com. +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* +* CPU PORT FILE +* +* ARM-Cortex-M4 +* IAR C Compiler +* +* Filename : cpu.h +* Version : V1.30.02.00 +* Programmer(s) : JJL +* BAN +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* MODULE +* +* Note(s) : (1) This CPU header file is protected from multiple pre-processor inclusion through use of +* the CPU module present pre-processor macro definition. +********************************************************************************************************* +*/ + +#ifndef CPU_MODULE_PRESENT /* See Note #1. */ +#define CPU_MODULE_PRESENT + + +/* +********************************************************************************************************* +* CPU INCLUDE FILES +* +* Note(s) : (1) The following CPU files are located in the following directories : +* +* (a) \\cpu_cfg.h +* +* (b) (1) \\cpu_def.h +* (2) \\\\cpu*.* +* +* where +* directory path for Your Product's Application +* directory path for common CPU-compiler software +* directory name for specific CPU +* directory name for specific compiler +* +* (2) Compiler MUST be configured to include as additional include path directories : +* +* (a) '\\' directory See Note #1a +* +* (b) (1) '\\' directory See Note #1b1 +* (2) '\\\\' directory See Note #1b2 +* +* (3) Since NO custom library modules are included, 'cpu.h' may ONLY use configurations from +* CPU configuration file 'cpu_cfg.h' that do NOT reference any custom library definitions. +* +* In other words, 'cpu.h' may use 'cpu_cfg.h' configurations that are #define'd to numeric +* constants or to NULL (i.e. NULL-valued #define's); but may NOT use configurations to +* custom library #define's (e.g. DEF_DISABLED or DEF_ENABLED). +********************************************************************************************************* +*/ + +#include + +#include +#include /* See Note #3. */ + +#ifdef __cplusplus +extern "C" { +#endif + + +/* +********************************************************************************************************* +* CONFIGURE STANDARD DATA TYPES +* +* Note(s) : (1) Configure standard data types according to CPU-/compiler-specifications. +* +* (2) (a) (1) 'CPU_FNCT_VOID' data type defined to replace the commonly-used function pointer +* data type of a pointer to a function which returns void & has no arguments. +* +* (2) Example function pointer usage : +* +* CPU_FNCT_VOID FnctName; +* +* FnctName(); +* +* (b) (1) 'CPU_FNCT_PTR' data type defined to replace the commonly-used function pointer +* data type of a pointer to a function which returns void & has a single void +* pointer argument. +* +* (2) Example function pointer usage : +* +* CPU_FNCT_PTR FnctName; +* void *p_obj +* +* FnctName(p_obj); +********************************************************************************************************* +*/ + +typedef void CPU_VOID; +typedef char CPU_CHAR; /* 8-bit character */ +typedef unsigned char CPU_BOOLEAN; /* 8-bit boolean or logical */ +typedef unsigned char CPU_INT08U; /* 8-bit unsigned integer */ +typedef signed char CPU_INT08S; /* 8-bit signed integer */ +typedef unsigned short CPU_INT16U; /* 16-bit unsigned integer */ +typedef signed short CPU_INT16S; /* 16-bit signed integer */ +typedef unsigned int CPU_INT32U; /* 32-bit unsigned integer */ +typedef signed int CPU_INT32S; /* 32-bit signed integer */ +typedef unsigned long long CPU_INT64U; /* 64-bit unsigned integer */ +typedef signed long long CPU_INT64S; /* 64-bit signed integer */ + +typedef float CPU_FP32; /* 32-bit floating point */ +typedef double CPU_FP64; /* 64-bit floating point */ + + +typedef volatile CPU_INT08U CPU_REG08; /* 8-bit register */ +typedef volatile CPU_INT16U CPU_REG16; /* 16-bit register */ +typedef volatile CPU_INT32U CPU_REG32; /* 32-bit register */ +typedef volatile CPU_INT64U CPU_REG64; /* 64-bit register */ + + +typedef void (*CPU_FNCT_VOID)(void); /* See Note #2a. */ +typedef void (*CPU_FNCT_PTR )(void *p_obj); /* See Note #2b. */ + + +/* +********************************************************************************************************* +* CPU WORD CONFIGURATION +* +* Note(s) : (1) Configure CPU_CFG_ADDR_SIZE, CPU_CFG_DATA_SIZE, & CPU_CFG_DATA_SIZE_MAX with CPU's &/or +* compiler's word sizes : +* +* CPU_WORD_SIZE_08 8-bit word size +* CPU_WORD_SIZE_16 16-bit word size +* CPU_WORD_SIZE_32 32-bit word size +* CPU_WORD_SIZE_64 64-bit word size +* +* (2) Configure CPU_CFG_ENDIAN_TYPE with CPU's data-word-memory order : +* +* (a) CPU_ENDIAN_TYPE_BIG Big- endian word order (CPU words' most significant +* octet @ lowest memory address) +* (b) CPU_ENDIAN_TYPE_LITTLE Little-endian word order (CPU words' least significant +* octet @ lowest memory address) +********************************************************************************************************* +*/ + + /* Define CPU word sizes (see Note #1) : */ +#define CPU_CFG_ADDR_SIZE CPU_WORD_SIZE_32 /* Defines CPU address word size (in octets). */ +#define CPU_CFG_DATA_SIZE CPU_WORD_SIZE_32 /* Defines CPU data word size (in octets). */ +#define CPU_CFG_DATA_SIZE_MAX CPU_WORD_SIZE_64 /* Defines CPU maximum word size (in octets). */ + +#define CPU_CFG_ENDIAN_TYPE CPU_ENDIAN_TYPE_LITTLE /* Defines CPU data word-memory order (see Note #2). */ + + +/* +********************************************************************************************************* +* CONFIGURE CPU ADDRESS & DATA TYPES +********************************************************************************************************* +*/ + + /* CPU address type based on address bus size. */ +#if (CPU_CFG_ADDR_SIZE == CPU_WORD_SIZE_32) +typedef CPU_INT32U CPU_ADDR; +#elif (CPU_CFG_ADDR_SIZE == CPU_WORD_SIZE_16) +typedef CPU_INT16U CPU_ADDR; +#else +typedef CPU_INT08U CPU_ADDR; +#endif + + /* CPU data type based on data bus size. */ +#if (CPU_CFG_DATA_SIZE == CPU_WORD_SIZE_32) +typedef CPU_INT32U CPU_DATA; +#elif (CPU_CFG_DATA_SIZE == CPU_WORD_SIZE_16) +typedef CPU_INT16U CPU_DATA; +#else +typedef CPU_INT08U CPU_DATA; +#endif + + +typedef CPU_DATA CPU_ALIGN; /* Defines CPU data-word-alignment size. */ +typedef CPU_ADDR CPU_SIZE_T; /* Defines CPU standard 'size_t' size. */ + + +/* +********************************************************************************************************* +* CPU STACK CONFIGURATION +* +* Note(s) : (1) Configure CPU_CFG_STK_GROWTH in 'cpu.h' with CPU's stack growth order : +* +* (a) CPU_STK_GROWTH_LO_TO_HI CPU stack pointer increments to the next higher stack +* memory address after data is pushed onto the stack +* (b) CPU_STK_GROWTH_HI_TO_LO CPU stack pointer decrements to the next lower stack +* memory address after data is pushed onto the stack +* +* (2) Configure CPU_CFG_STK_ALIGN_BYTES with the highest minimum alignement required for +* cpu stacks. +* +* (a) ARM Procedure Calls Standard requires an 8 bytes stack alignment. +********************************************************************************************************* +*/ + +#define CPU_CFG_STK_GROWTH CPU_STK_GROWTH_HI_TO_LO /* Defines CPU stack growth order (see Note #1). */ + +#define CPU_CFG_STK_ALIGN_BYTES (8u) /* Defines CPU stack alignment in bytes. (see Note #2). */ + +typedef CPU_INT32U CPU_STK; /* Defines CPU stack data type. */ +typedef CPU_ADDR CPU_STK_SIZE; /* Defines CPU stack size data type. */ + + +/* +********************************************************************************************************* +* CRITICAL SECTION CONFIGURATION +* +* Note(s) : (1) Configure CPU_CFG_CRITICAL_METHOD with CPU's/compiler's critical section method : +* +* Enter/Exit critical sections by ... +* +* CPU_CRITICAL_METHOD_INT_DIS_EN Disable/Enable interrupts +* CPU_CRITICAL_METHOD_STATUS_STK Push/Pop interrupt status onto stack +* CPU_CRITICAL_METHOD_STATUS_LOCAL Save/Restore interrupt status to local variable +* +* (a) CPU_CRITICAL_METHOD_INT_DIS_EN is NOT a preferred method since it does NOT support +* multiple levels of interrupts. However, with some CPUs/compilers, this is the only +* available method. +* +* (b) CPU_CRITICAL_METHOD_STATUS_STK is one preferred method since it supports multiple +* levels of interrupts. However, this method assumes that the compiler provides C-level +* &/or assembly-level functionality for the following : +* +* ENTER CRITICAL SECTION : +* (1) Push/save interrupt status onto a local stack +* (2) Disable interrupts +* +* EXIT CRITICAL SECTION : +* (3) Pop/restore interrupt status from a local stack +* +* (c) CPU_CRITICAL_METHOD_STATUS_LOCAL is one preferred method since it supports multiple +* levels of interrupts. However, this method assumes that the compiler provides C-level +* &/or assembly-level functionality for the following : +* +* ENTER CRITICAL SECTION : +* (1) Save interrupt status into a local variable +* (2) Disable interrupts +* +* EXIT CRITICAL SECTION : +* (3) Restore interrupt status from a local variable +* +* (2) Critical section macro's most likely require inline assembly. If the compiler does NOT +* allow inline assembly in C source files, critical section macro's MUST call an assembly +* subroutine defined in a 'cpu_a.asm' file located in the following software directory : +* +* \\\\ +* +* where +* directory path for common CPU-compiler software +* directory name for specific CPU +* directory name for specific compiler +* +* (3) (a) To save/restore interrupt status, a local variable 'cpu_sr' of type 'CPU_SR' MAY need +* to be declared (e.g. if 'CPU_CRITICAL_METHOD_STATUS_LOCAL' method is configured). +* +* (1) 'cpu_sr' local variable SHOULD be declared via the CPU_SR_ALLOC() macro which, if +* used, MUST be declared following ALL other local variables. +* +* Example : +* +* void Fnct (void) +* { +* CPU_INT08U val_08; +* CPU_INT16U val_16; +* CPU_INT32U val_32; +* CPU_SR_ALLOC(); MUST be declared after ALL other local variables +* : +* : +* } +* +* (b) Configure 'CPU_SR' data type with the appropriate-sized CPU data type large enough to +* completely store the CPU's/compiler's status word. +********************************************************************************************************* +*/ + /* Configure CPU critical method (see Note #1) : */ +#define CPU_CFG_CRITICAL_METHOD CPU_CRITICAL_METHOD_STATUS_LOCAL + +typedef CPU_INT32U CPU_SR; /* Defines CPU status register size (see Note #3b). */ + + /* Allocates CPU status register word (see Note #3a). */ +#if (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL) +#define CPU_SR_ALLOC() CPU_SR cpu_sr = (CPU_SR)0 +#else +#define CPU_SR_ALLOC() +#endif + + /* Save CPU status word & disable interrupts.*/ +#define CPU_INT_DIS() do { cpu_sr = __get_PRIMASK(); __disable_interrupt(); } while (0) +#define CPU_INT_EN() do { __set_PRIMASK(cpu_sr); } while (0) /* Restore CPU status word. */ + + +#ifdef CPU_CFG_INT_DIS_MEAS_EN + /* Disable interrupts, ... */ + /* & start interrupts disabled time measurement.*/ +#define CPU_CRITICAL_ENTER() do { CPU_INT_DIS(); \ + CPU_IntDisMeasStart(); } while (0) + /* Stop & measure interrupts disabled time, */ + /* ... & re-enable interrupts. */ +#define CPU_CRITICAL_EXIT() do { CPU_IntDisMeasStop(); \ + CPU_INT_EN(); } while (0) + +#else + +#define CPU_CRITICAL_ENTER() do { CPU_INT_DIS(); } while (0) /* Disable interrupts. */ +#define CPU_CRITICAL_EXIT() do { CPU_INT_EN(); } while (0) /* Re-enable interrupts. */ + +#endif + + +/* +********************************************************************************************************* +* MEMORY BARRIERS CONFIGURATION +* +* Note(s) : (1) (a) Configure memory barriers if required by the architecture. +* +* CPU_MB Full memory barrier. +* CPU_RMB Read (Loads) memory barrier. +* CPU_WMB Write (Stores) memory barrier. +* +********************************************************************************************************* +*/ + +#define CPU_MB() __DSB() +#define CPU_RMB() __DSB() +#define CPU_WMB() __DSB() + + +/* +********************************************************************************************************* +* CPU COUNT ZEROS CONFIGURATION +* +* Note(s) : (1) (a) Configure CPU_CFG_LEAD_ZEROS_ASM_PRESENT to define count leading zeros bits +* function(s) in : +* +* (1) 'cpu_a.asm', if CPU_CFG_LEAD_ZEROS_ASM_PRESENT #define'd in 'cpu.h'/ +* 'cpu_cfg.h' to enable assembly-optimized function(s) +* +* (2) 'cpu_core.c', if CPU_CFG_LEAD_ZEROS_ASM_PRESENT NOT #define'd in 'cpu.h'/ +* 'cpu_cfg.h' to enable C-source-optimized function(s) otherwise +* +* (b) Configure CPU_CFG_TRAIL_ZEROS_ASM_PRESENT to define count trailing zeros bits +* function(s) in : +* +* (1) 'cpu_a.asm', if CPU_CFG_TRAIL_ZEROS_ASM_PRESENT #define'd in 'cpu.h'/ +* 'cpu_cfg.h' to enable assembly-optimized function(s) +* +* (2) 'cpu_core.c', if CPU_CFG_TRAIL_ZEROS_ASM_PRESENT NOT #define'd in 'cpu.h'/ +* 'cpu_cfg.h' to enable C-source-optimized function(s) otherwise +********************************************************************************************************* +*/ + + /* Configure CPU count leading zeros bits ... */ +#define CPU_CFG_LEAD_ZEROS_ASM_PRESENT /* ... assembly-version (see Note #1a). */ + + /* Configure CPU count trailing zeros bits ... */ +#define CPU_CFG_TRAIL_ZEROS_ASM_PRESENT /* ... assembly-version (see Note #1b). */ + + +/* +********************************************************************************************************* +* FUNCTION PROTOTYPES +********************************************************************************************************* +*/ + +void CPU_IntDis (void); +void CPU_IntEn (void); + +void CPU_IntSrcDis (CPU_INT08U pos); +void CPU_IntSrcEn (CPU_INT08U pos); +void CPU_IntSrcPendClr(CPU_INT08U pos); +CPU_INT16S CPU_IntSrcPrioGet(CPU_INT08U pos); +void CPU_IntSrcPrioSet(CPU_INT08U pos, + CPU_INT08U prio); + + +CPU_SR CPU_SR_Save (void); +void CPU_SR_Restore (CPU_SR cpu_sr); + + +void CPU_WaitForInt (void); +void CPU_WaitForExcept(void); + + +CPU_DATA CPU_RevBits (CPU_DATA val); + +void CPU_BitBandClr (CPU_ADDR addr, + CPU_INT08U bit_nbr); +void CPU_BitBandSet (CPU_ADDR addr, + CPU_INT08U bit_nbr); + + +/* +********************************************************************************************************* +* INTERRUPT SOURCES +********************************************************************************************************* +*/ + +#define CPU_INT_STK_PTR 0u +#define CPU_INT_RESET 1u +#define CPU_INT_NMI 2u +#define CPU_INT_HFAULT 3u +#define CPU_INT_MEM 4u +#define CPU_INT_BUSFAULT 5u +#define CPU_INT_USAGEFAULT 6u +#define CPU_INT_RSVD_07 7u +#define CPU_INT_RSVD_08 8u +#define CPU_INT_RSVD_09 9u +#define CPU_INT_RSVD_10 10u +#define CPU_INT_SVCALL 11u +#define CPU_INT_DBGMON 12u +#define CPU_INT_RSVD_13 13u +#define CPU_INT_PENDSV 14u +#define CPU_INT_SYSTICK 15u +#define CPU_INT_EXT0 16u + +/* +********************************************************************************************************* +* CPU REGISTERS +********************************************************************************************************* +*/ + +#define CPU_REG_NVIC_NVIC (*((CPU_REG32 *)(0xE000E004))) /* Int Ctrl'er Type Reg. */ +#define CPU_REG_NVIC_ST_CTRL (*((CPU_REG32 *)(0xE000E010))) /* SysTick Ctrl & Status Reg. */ +#define CPU_REG_NVIC_ST_RELOAD (*((CPU_REG32 *)(0xE000E014))) /* SysTick Reload Value Reg. */ +#define CPU_REG_NVIC_ST_CURRENT (*((CPU_REG32 *)(0xE000E018))) /* SysTick Current Value Reg. */ +#define CPU_REG_NVIC_ST_CAL (*((CPU_REG32 *)(0xE000E01C))) /* SysTick Calibration Value Reg. */ + +#define CPU_REG_NVIC_SETEN(n) (*((CPU_REG32 *)(0xE000E100 + (n) * 4u))) /* IRQ Set En Reg. */ +#define CPU_REG_NVIC_CLREN(n) (*((CPU_REG32 *)(0xE000E180 + (n) * 4u))) /* IRQ Clr En Reg. */ +#define CPU_REG_NVIC_SETPEND(n) (*((CPU_REG32 *)(0xE000E200 + (n) * 4u))) /* IRQ Set Pending Reg. */ +#define CPU_REG_NVIC_CLRPEND(n) (*((CPU_REG32 *)(0xE000E280 + (n) * 4u))) /* IRQ Clr Pending Reg. */ +#define CPU_REG_NVIC_ACTIVE(n) (*((CPU_REG32 *)(0xE000E300 + (n) * 4u))) /* IRQ Active Reg. */ +#define CPU_REG_NVIC_PRIO(n) (*((CPU_REG32 *)(0xE000E400 + (n) * 4u))) /* IRQ Prio Reg. */ + +#define CPU_REG_NVIC_CPUID (*((CPU_REG32 *)(0xE000ED00))) /* CPUID Base Reg. */ +#define CPU_REG_NVIC_ICSR (*((CPU_REG32 *)(0xE000ED04))) /* Int Ctrl State Reg. */ +#define CPU_REG_NVIC_VTOR (*((CPU_REG32 *)(0xE000ED08))) /* Vect Tbl Offset Reg. */ +#define CPU_REG_NVIC_AIRCR (*((CPU_REG32 *)(0xE000ED0C))) /* App Int/Reset Ctrl Reg. */ +#define CPU_REG_NVIC_SCR (*((CPU_REG32 *)(0xE000ED10))) /* System Ctrl Reg. */ +#define CPU_REG_NVIC_CCR (*((CPU_REG32 *)(0xE000ED14))) /* Cfg Ctrl Reg. */ +#define CPU_REG_NVIC_SHPRI1 (*((CPU_REG32 *)(0xE000ED18))) /* System Handlers 4 to 7 Prio. */ +#define CPU_REG_NVIC_SHPRI2 (*((CPU_REG32 *)(0xE000ED1C))) /* System Handlers 8 to 11 Prio. */ +#define CPU_REG_NVIC_SHPRI3 (*((CPU_REG32 *)(0xE000ED20))) /* System Handlers 12 to 15 Prio. */ +#define CPU_REG_NVIC_SHCSR (*((CPU_REG32 *)(0xE000ED24))) /* System Handler Ctrl & State Reg. */ +#define CPU_REG_NVIC_CFSR (*((CPU_REG32 *)(0xE000ED28))) /* Configurable Fault Status Reg. */ +#define CPU_REG_NVIC_HFSR (*((CPU_REG32 *)(0xE000ED2C))) /* Hard Fault Status Reg. */ +#define CPU_REG_NVIC_DFSR (*((CPU_REG32 *)(0xE000ED30))) /* Debug Fault Status Reg. */ +#define CPU_REG_NVIC_MMFAR (*((CPU_REG32 *)(0xE000ED34))) /* Mem Manage Addr Reg. */ +#define CPU_REG_NVIC_BFAR (*((CPU_REG32 *)(0xE000ED38))) /* Bus Fault Addr Reg. */ +#define CPU_REG_NVIC_AFSR (*((CPU_REG32 *)(0xE000ED3C))) /* Aux Fault Status Reg. */ +#define CPU_REG_NVIC_CPACR (*((CPU_REG32 *)(0xE000ED88))) /* Coprocessor Access Control Reg. */ + +#define CPU_REG_NVIC_PFR0 (*((CPU_REG32 *)(0xE000ED40))) /* Processor Feature Reg 0. */ +#define CPU_REG_NVIC_PFR1 (*((CPU_REG32 *)(0xE000ED44))) /* Processor Feature Reg 1. */ +#define CPU_REG_NVIC_DFR0 (*((CPU_REG32 *)(0xE000ED48))) /* Debug Feature Reg 0. */ +#define CPU_REG_NVIC_AFR0 (*((CPU_REG32 *)(0xE000ED4C))) /* Aux Feature Reg 0. */ +#define CPU_REG_NVIC_MMFR0 (*((CPU_REG32 *)(0xE000ED50))) /* Memory Model Feature Reg 0. */ +#define CPU_REG_NVIC_MMFR1 (*((CPU_REG32 *)(0xE000ED54))) /* Memory Model Feature Reg 1. */ +#define CPU_REG_NVIC_MMFR2 (*((CPU_REG32 *)(0xE000ED58))) /* Memory Model Feature Reg 2. */ +#define CPU_REG_NVIC_MMFR3 (*((CPU_REG32 *)(0xE000ED5C))) /* Memory Model Feature Reg 3. */ +#define CPU_REG_NVIC_ISAFR0 (*((CPU_REG32 *)(0xE000ED60))) /* ISA Feature Reg 0. */ +#define CPU_REG_NVIC_ISAFR1 (*((CPU_REG32 *)(0xE000ED64))) /* ISA Feature Reg 1. */ +#define CPU_REG_NVIC_ISAFR2 (*((CPU_REG32 *)(0xE000ED68))) /* ISA Feature Reg 2. */ +#define CPU_REG_NVIC_ISAFR3 (*((CPU_REG32 *)(0xE000ED6C))) /* ISA Feature Reg 3. */ +#define CPU_REG_NVIC_ISAFR4 (*((CPU_REG32 *)(0xE000ED70))) /* ISA Feature Reg 4. */ +#define CPU_REG_NVIC_SW_TRIG (*((CPU_REG32 *)(0xE000EF00))) /* Software Trigger Int Reg. */ + +#define CPU_REG_MPU_TYPE (*((CPU_REG32 *)(0xE000ED90))) /* MPU Type Reg. */ +#define CPU_REG_MPU_CTRL (*((CPU_REG32 *)(0xE000ED94))) /* MPU Ctrl Reg. */ +#define CPU_REG_MPU_REG_NBR (*((CPU_REG32 *)(0xE000ED98))) /* MPU Region Nbr Reg. */ +#define CPU_REG_MPU_REG_BASE (*((CPU_REG32 *)(0xE000ED9C))) /* MPU Region Base Addr Reg. */ +#define CPU_REG_MPU_REG_ATTR (*((CPU_REG32 *)(0xE000EDA0))) /* MPU Region Attrib & Size Reg. */ + +#define CPU_REG_DBG_CTRL (*((CPU_REG32 *)(0xE000EDF0))) /* Debug Halting Ctrl & Status Reg. */ +#define CPU_REG_DBG_SELECT (*((CPU_REG32 *)(0xE000EDF4))) /* Debug Core Reg Selector Reg. */ +#define CPU_REG_DBG_DATA (*((CPU_REG32 *)(0xE000EDF8))) /* Debug Core Reg Data Reg. */ +#define CPU_REG_DBG_INT (*((CPU_REG32 *)(0xE000EDFC))) /* Debug Except & Monitor Ctrl Reg. */ + +#define CPU_REG_SCB_FPCCR (*((CPU_REG32 *)(0xE000EF34))) /* Floating-Point Context Control Reg. */ +#define CPU_REG_SCB_FPCAR (*((CPU_REG32 *)(0xE000EF38))) /* Floating-Point Context Address Reg. */ +#define CPU_REG_SCB_FPDSCR (*((CPU_REG32 *)(0xE000EF3C))) /* FP Default Status Control Reg. */ + + +/* +********************************************************************************************************* +* CPU REGISTER BITS +********************************************************************************************************* +*/ + + /* ---------- SYSTICK CTRL & STATUS REG BITS ---------- */ +#define CPU_REG_NVIC_ST_CTRL_COUNTFLAG 0x00010000 +#define CPU_REG_NVIC_ST_CTRL_CLKSOURCE 0x00000004 +#define CPU_REG_NVIC_ST_CTRL_TICKINT 0x00000002 +#define CPU_REG_NVIC_ST_CTRL_ENABLE 0x00000001 + + + /* -------- SYSTICK CALIBRATION VALUE REG BITS -------- */ +#define CPU_REG_NVIC_ST_CAL_NOREF 0x80000000 +#define CPU_REG_NVIC_ST_CAL_SKEW 0x40000000 + + /* -------------- INT CTRL STATE REG BITS ------------- */ +#define CPU_REG_NVIC_ICSR_NMIPENDSET 0x80000000 +#define CPU_REG_NVIC_ICSR_PENDSVSET 0x10000000 +#define CPU_REG_NVIC_ICSR_PENDSVCLR 0x08000000 +#define CPU_REG_NVIC_ICSR_PENDSTSET 0x04000000 +#define CPU_REG_NVIC_ICSR_PENDSTCLR 0x02000000 +#define CPU_REG_NVIC_ICSR_ISRPREEMPT 0x00800000 +#define CPU_REG_NVIC_ICSR_ISRPENDING 0x00400000 +#define CPU_REG_NVIC_ICSR_RETTOBASE 0x00000800 + + /* ------------- VECT TBL OFFSET REG BITS ------------- */ +#define CPU_REG_NVIC_VTOR_TBLBASE 0x20000000 + + /* ------------ APP INT/RESET CTRL REG BITS ----------- */ +#define CPU_REG_NVIC_AIRCR_ENDIANNESS 0x00008000 +#define CPU_REG_NVIC_AIRCR_SYSRESETREQ 0x00000004 +#define CPU_REG_NVIC_AIRCR_VECTCLRACTIVE 0x00000002 +#define CPU_REG_NVIC_AIRCR_VECTRESET 0x00000001 + + /* --------------- SYSTEM CTRL REG BITS --------------- */ +#define CPU_REG_NVIC_SCR_SEVONPEND 0x00000010 +#define CPU_REG_NVIC_SCR_SLEEPDEEP 0x00000004 +#define CPU_REG_NVIC_SCR_SLEEPONEXIT 0x00000002 + + /* ----------------- CFG CTRL REG BITS ---------------- */ +#define CPU_REG_NVIC_CCR_STKALIGN 0x00000200 +#define CPU_REG_NVIC_CCR_BFHFNMIGN 0x00000100 +#define CPU_REG_NVIC_CCR_DIV_0_TRP 0x00000010 +#define CPU_REG_NVIC_CCR_UNALIGN_TRP 0x00000008 +#define CPU_REG_NVIC_CCR_USERSETMPEND 0x00000002 +#define CPU_REG_NVIC_CCR_NONBASETHRDENA 0x00000001 + + /* ------- SYSTEM HANDLER CTRL & STATE REG BITS ------- */ +#define CPU_REG_NVIC_SHCSR_USGFAULTENA 0x00040000 +#define CPU_REG_NVIC_SHCSR_BUSFAULTENA 0x00020000 +#define CPU_REG_NVIC_SHCSR_MEMFAULTENA 0x00010000 +#define CPU_REG_NVIC_SHCSR_SVCALLPENDED 0x00008000 +#define CPU_REG_NVIC_SHCSR_BUSFAULTPENDED 0x00004000 +#define CPU_REG_NVIC_SHCSR_MEMFAULTPENDED 0x00002000 +#define CPU_REG_NVIC_SHCSR_USGFAULTPENDED 0x00001000 +#define CPU_REG_NVIC_SHCSR_SYSTICKACT 0x00000800 +#define CPU_REG_NVIC_SHCSR_PENDSVACT 0x00000400 +#define CPU_REG_NVIC_SHCSR_MONITORACT 0x00000100 +#define CPU_REG_NVIC_SHCSR_SVCALLACT 0x00000080 +#define CPU_REG_NVIC_SHCSR_USGFAULTACT 0x00000008 +#define CPU_REG_NVIC_SHCSR_BUSFAULTACT 0x00000002 +#define CPU_REG_NVIC_SHCSR_MEMFAULTACT 0x00000001 + + /* -------- CONFIGURABLE FAULT STATUS REG BITS -------- */ +#define CPU_REG_NVIC_CFSR_DIVBYZERO 0x02000000 +#define CPU_REG_NVIC_CFSR_UNALIGNED 0x01000000 +#define CPU_REG_NVIC_CFSR_NOCP 0x00080000 +#define CPU_REG_NVIC_CFSR_INVPC 0x00040000 +#define CPU_REG_NVIC_CFSR_INVSTATE 0x00020000 +#define CPU_REG_NVIC_CFSR_UNDEFINSTR 0x00010000 +#define CPU_REG_NVIC_CFSR_BFARVALID 0x00008000 +#define CPU_REG_NVIC_CFSR_STKERR 0x00001000 +#define CPU_REG_NVIC_CFSR_UNSTKERR 0x00000800 +#define CPU_REG_NVIC_CFSR_IMPRECISERR 0x00000400 +#define CPU_REG_NVIC_CFSR_PRECISERR 0x00000200 +#define CPU_REG_NVIC_CFSR_IBUSERR 0x00000100 +#define CPU_REG_NVIC_CFSR_MMARVALID 0x00000080 +#define CPU_REG_NVIC_CFSR_MSTKERR 0x00000010 +#define CPU_REG_NVIC_CFSR_MUNSTKERR 0x00000008 +#define CPU_REG_NVIC_CFSR_DACCVIOL 0x00000002 +#define CPU_REG_NVIC_CFSR_IACCVIOL 0x00000001 + + /* ------------ HARD FAULT STATUS REG BITS ------------ */ +#define CPU_REG_NVIC_HFSR_DEBUGEVT 0x80000000 +#define CPU_REG_NVIC_HFSR_FORCED 0x40000000 +#define CPU_REG_NVIC_HFSR_VECTTBL 0x00000002 + + /* ------------ DEBUG FAULT STATUS REG BITS ----------- */ +#define CPU_REG_NVIC_DFSR_EXTERNAL 0x00000010 +#define CPU_REG_NVIC_DFSR_VCATCH 0x00000008 +#define CPU_REG_NVIC_DFSR_DWTTRAP 0x00000004 +#define CPU_REG_NVIC_DFSR_BKPT 0x00000002 +#define CPU_REG_NVIC_DFSR_HALTED 0x00000001 + + /* -------- COPROCESSOR ACCESS CONTROL REG BITS ------- */ +#define CPU_REG_NVIC_CPACR_CP10_FULL_ACCESS 0x00300000 +#define CPU_REG_NVIC_CPACR_CP11_FULL_ACCESS 0x00C00000 + +/* +********************************************************************************************************* +* CPU REGISTER MASK +********************************************************************************************************* +*/ + +#define CPU_MSK_NVIC_ICSR_VECT_ACTIVE 0x000001FF + + +/* +********************************************************************************************************* +* CONFIGURATION ERRORS +********************************************************************************************************* +*/ + +#ifndef CPU_CFG_ADDR_SIZE +#error "CPU_CFG_ADDR_SIZE not #define'd in 'cpu.h' " +#error " [MUST be CPU_WORD_SIZE_08 8-bit alignment]" +#error " [ || CPU_WORD_SIZE_16 16-bit alignment]" +#error " [ || CPU_WORD_SIZE_32 32-bit alignment]" +#error " [ || CPU_WORD_SIZE_64 64-bit alignment]" + +#elif ((CPU_CFG_ADDR_SIZE != CPU_WORD_SIZE_08) && \ + (CPU_CFG_ADDR_SIZE != CPU_WORD_SIZE_16) && \ + (CPU_CFG_ADDR_SIZE != CPU_WORD_SIZE_32) && \ + (CPU_CFG_ADDR_SIZE != CPU_WORD_SIZE_64)) +#error "CPU_CFG_ADDR_SIZE illegally #define'd in 'cpu.h' " +#error " [MUST be CPU_WORD_SIZE_08 8-bit alignment]" +#error " [ || CPU_WORD_SIZE_16 16-bit alignment]" +#error " [ || CPU_WORD_SIZE_32 32-bit alignment]" +#error " [ || CPU_WORD_SIZE_64 64-bit alignment]" +#endif + + +#ifndef CPU_CFG_DATA_SIZE +#error "CPU_CFG_DATA_SIZE not #define'd in 'cpu.h' " +#error " [MUST be CPU_WORD_SIZE_08 8-bit alignment]" +#error " [ || CPU_WORD_SIZE_16 16-bit alignment]" +#error " [ || CPU_WORD_SIZE_32 32-bit alignment]" +#error " [ || CPU_WORD_SIZE_64 64-bit alignment]" + +#elif ((CPU_CFG_DATA_SIZE != CPU_WORD_SIZE_08) && \ + (CPU_CFG_DATA_SIZE != CPU_WORD_SIZE_16) && \ + (CPU_CFG_DATA_SIZE != CPU_WORD_SIZE_32) && \ + (CPU_CFG_DATA_SIZE != CPU_WORD_SIZE_64)) +#error "CPU_CFG_DATA_SIZE illegally #define'd in 'cpu.h' " +#error " [MUST be CPU_WORD_SIZE_08 8-bit alignment]" +#error " [ || CPU_WORD_SIZE_16 16-bit alignment]" +#error " [ || CPU_WORD_SIZE_32 32-bit alignment]" +#error " [ || CPU_WORD_SIZE_64 64-bit alignment]" +#endif + + +#ifndef CPU_CFG_DATA_SIZE_MAX +#error "CPU_CFG_DATA_SIZE_MAX not #define'd in 'cpu.h' " +#error " [MUST be CPU_WORD_SIZE_08 8-bit alignment]" +#error " [ || CPU_WORD_SIZE_16 16-bit alignment]" +#error " [ || CPU_WORD_SIZE_32 32-bit alignment]" +#error " [ || CPU_WORD_SIZE_64 64-bit alignment]" + +#elif ((CPU_CFG_DATA_SIZE_MAX != CPU_WORD_SIZE_08) && \ + (CPU_CFG_DATA_SIZE_MAX != CPU_WORD_SIZE_16) && \ + (CPU_CFG_DATA_SIZE_MAX != CPU_WORD_SIZE_32) && \ + (CPU_CFG_DATA_SIZE_MAX != CPU_WORD_SIZE_64)) +#error "CPU_CFG_DATA_SIZE_MAX illegally #define'd in 'cpu.h' " +#error " [MUST be CPU_WORD_SIZE_08 8-bit alignment]" +#error " [ || CPU_WORD_SIZE_16 16-bit alignment]" +#error " [ || CPU_WORD_SIZE_32 32-bit alignment]" +#error " [ || CPU_WORD_SIZE_64 64-bit alignment]" +#endif + + + +#if (CPU_CFG_DATA_SIZE_MAX < CPU_CFG_DATA_SIZE) +#error "CPU_CFG_DATA_SIZE_MAX illegally #define'd in 'cpu.h' " +#error " [MUST be >= CPU_CFG_DATA_SIZE]" +#endif + + + + +#ifndef CPU_CFG_ENDIAN_TYPE +#error "CPU_CFG_ENDIAN_TYPE not #define'd in 'cpu.h' " +#error " [MUST be CPU_ENDIAN_TYPE_BIG ]" +#error " [ || CPU_ENDIAN_TYPE_LITTLE]" + +#elif ((CPU_CFG_ENDIAN_TYPE != CPU_ENDIAN_TYPE_BIG ) && \ + (CPU_CFG_ENDIAN_TYPE != CPU_ENDIAN_TYPE_LITTLE)) +#error "CPU_CFG_ENDIAN_TYPE illegally #define'd in 'cpu.h' " +#error " [MUST be CPU_ENDIAN_TYPE_BIG ]" +#error " [ || CPU_ENDIAN_TYPE_LITTLE]" +#endif + + + + +#ifndef CPU_CFG_STK_GROWTH +#error "CPU_CFG_STK_GROWTH not #define'd in 'cpu.h' " +#error " [MUST be CPU_STK_GROWTH_LO_TO_HI]" +#error " [ || CPU_STK_GROWTH_HI_TO_LO]" + +#elif ((CPU_CFG_STK_GROWTH != CPU_STK_GROWTH_LO_TO_HI) && \ + (CPU_CFG_STK_GROWTH != CPU_STK_GROWTH_HI_TO_LO)) +#error "CPU_CFG_STK_GROWTH illegally #define'd in 'cpu.h' " +#error " [MUST be CPU_STK_GROWTH_LO_TO_HI]" +#error " [ || CPU_STK_GROWTH_HI_TO_LO]" +#endif + + + + +#ifndef CPU_CFG_CRITICAL_METHOD +#error "CPU_CFG_CRITICAL_METHOD not #define'd in 'cpu.h' " +#error " [MUST be CPU_CRITICAL_METHOD_INT_DIS_EN ]" +#error " [ || CPU_CRITICAL_METHOD_STATUS_STK ]" +#error " [ || CPU_CRITICAL_METHOD_STATUS_LOCAL]" + +#elif ((CPU_CFG_CRITICAL_METHOD != CPU_CRITICAL_METHOD_INT_DIS_EN ) && \ + (CPU_CFG_CRITICAL_METHOD != CPU_CRITICAL_METHOD_STATUS_STK ) && \ + (CPU_CFG_CRITICAL_METHOD != CPU_CRITICAL_METHOD_STATUS_LOCAL)) +#error "CPU_CFG_CRITICAL_METHOD illegally #define'd in 'cpu.h' " +#error " [MUST be CPU_CRITICAL_METHOD_INT_DIS_EN ]" +#error " [ || CPU_CRITICAL_METHOD_STATUS_STK ]" +#error " [ || CPU_CRITICAL_METHOD_STATUS_LOCAL]" +#endif + + +/* +********************************************************************************************************* +* MODULE END +* +* Note(s) : (1) See 'cpu.h MODULE'. +********************************************************************************************************* +*/ + +#ifdef __cplusplus +} +#endif + +#endif /* End of CPU module include. */ + diff --git a/Middlewares/Third_Party/Micrium/uC-CPU/ARM-Cortex-M4/IAR/cpu_a.asm b/Middlewares/Third_Party/Micrium/uC-CPU/ARM-Cortex-M4/IAR/cpu_a.asm new file mode 100644 index 0000000..ad2e1e2 --- /dev/null +++ b/Middlewares/Third_Party/Micrium/uC-CPU/ARM-Cortex-M4/IAR/cpu_a.asm @@ -0,0 +1,281 @@ +;******************************************************************************************************** +; uC/CPU +; CPU CONFIGURATION & PORT LAYER +; +; (c) Copyright 2004-2015; Micrium, Inc.; Weston, FL +; +; All rights reserved. Protected by international copyright laws. +; +; uC/CPU is provided in source form to registered licensees ONLY. It is +; illegal to distribute this source code to any third party unless you receive +; written permission by an authorized Micrium representative. Knowledge of +; the source code may NOT be used to develop a similar product. +; +; Please help us continue to provide the Embedded community with the finest +; software available. Your honesty is greatly appreciated. +; +; You can find our product's user manual, API reference, release notes and +; more information at https://doc.micrium.com. +; You can contact us at www.micrium.com. +;******************************************************************************************************** + +;******************************************************************************************************** +; +; CPU PORT FILE +; +; ARM-Cortex-M4 +; IAR C Compiler +; +; Filename : cpu_a.asm +; Version : V1.30.02.00 +; Programmer(s) : JJL +;******************************************************************************************************** + + +;******************************************************************************************************** +; PUBLIC FUNCTIONS +;******************************************************************************************************** + + PUBLIC CPU_IntDis + PUBLIC CPU_IntEn + + PUBLIC CPU_SR_Save + PUBLIC CPU_SR_Restore + + PUBLIC CPU_WaitForInt + PUBLIC CPU_WaitForExcept + + + PUBLIC CPU_CntLeadZeros + PUBLIC CPU_CntTrailZeros + PUBLIC CPU_RevBits + + +;******************************************************************************************************** +; CODE GENERATION DIRECTIVES +;******************************************************************************************************** + + RSEG CODE:CODE:NOROOT(2) + THUMB + +;******************************************************************************************************** +; DISABLE and ENABLE INTERRUPTS +; +; Description: Disable/Enable interrupts. +; +; Prototypes : void CPU_IntDis(void); +; void CPU_IntEn (void); +;******************************************************************************************************** + +CPU_IntDis + CPSID I + BX LR + + +CPU_IntEn + CPSIE I + BX LR + + +;******************************************************************************************************** +; CRITICAL SECTION FUNCTIONS +; +; Description : Disable/Enable interrupts by preserving the state of interrupts. Generally speaking, the +; state of the interrupt disable flag is stored in the local variable 'cpu_sr' & interrupts +; are then disabled ('cpu_sr' is allocated in all functions that need to disable interrupts). +; The previous interrupt state is restored by copying 'cpu_sr' into the CPU's status register. +; +; Prototypes : CPU_SR CPU_SR_Save (void); +; void CPU_SR_Restore(CPU_SR cpu_sr); +; +; Note(s) : (1) These functions are used in general like this : +; +; void Task (void *p_arg) +; { +; CPU_SR_ALLOC(); /* Allocate storage for CPU status register */ +; : +; : +; CPU_CRITICAL_ENTER(); /* cpu_sr = CPU_SR_Save(); */ +; : +; : +; CPU_CRITICAL_EXIT(); /* CPU_SR_Restore(cpu_sr); */ +; : +; } +;******************************************************************************************************** + +CPU_SR_Save + MRS R0, PRIMASK ; Set prio int mask to mask all (except faults) + CPSID I + BX LR + + +CPU_SR_Restore ; See Note #2. + MSR PRIMASK, R0 + BX LR + + +;******************************************************************************************************** +; WAIT FOR INTERRUPT +; +; Description : Enters sleep state, which will be exited when an interrupt is received. +; +; Prototypes : void CPU_WaitForInt (void) +; +; Argument(s) : none. +;******************************************************************************************************** + +CPU_WaitForInt: + WFI ; Wait for interrupt + BX LR + + +;******************************************************************************************************** +; WAIT FOR EXCEPTION +; +; Description : Enters sleep state, which will be exited when an exception is received. +; +; Prototypes : void CPU_WaitForExcept (void) +; +; Argument(s) : none. +;******************************************************************************************************** + +CPU_WaitForExcept: + WFE ; Wait for exception + BX LR + + +;******************************************************************************************************** +; CPU_CntLeadZeros() +; COUNT LEADING ZEROS +; +; Description : Counts the number of contiguous, most-significant, leading zero bits before the +; first binary one bit in a data value. +; +; Prototype : CPU_DATA CPU_CntLeadZeros(CPU_DATA val); +; +; Argument(s) : val Data value to count leading zero bits. +; +; Return(s) : Number of contiguous, most-significant, leading zero bits in 'val'. +; +; Caller(s) : Application. +; +; This function is an INTERNAL CPU module function but MAY be called by application +; function(s). +; +; Note(s) : (1) (a) Supports 32-bit data value size as configured by 'CPU_DATA' (see 'cpu.h +; CPU WORD CONFIGURATION Note #1'). +; +; (b) For 32-bit values : +; +; b31 b30 b29 ... b04 b03 b02 b01 b00 # Leading Zeros +; --- --- --- --- --- --- --- --- --------------- +; 1 x x x x x x x 0 +; 0 1 x x x x x x 1 +; 0 0 1 x x x x x 2 +; : : : : : : : : : +; : : : : : : : : : +; 0 0 0 1 x x x x 27 +; 0 0 0 0 1 x x x 28 +; 0 0 0 0 0 1 x x 29 +; 0 0 0 0 0 0 1 x 30 +; 0 0 0 0 0 0 0 1 31 +; 0 0 0 0 0 0 0 0 32 +; +; +; (2) MUST be defined in 'cpu_a.asm' (or 'cpu_c.c') if CPU_CFG_LEAD_ZEROS_ASM_PRESENT is +; #define'd in 'cpu_cfg.h' or 'cpu.h'. +;******************************************************************************************************** + +CPU_CntLeadZeros: + CLZ R0, R0 ; Count leading zeros + BX LR + + +;******************************************************************************************************** +; CPU_CntTrailZeros() +; COUNT TRAILING ZEROS +; +; Description : Counts the number of contiguous, least-significant, trailing zero bits before the +; first binary one bit in a data value. +; +; Prototype : CPU_DATA CPU_CntTrailZeros(CPU_DATA val); +; +; Argument(s) : val Data value to count trailing zero bits. +; +; Return(s) : Number of contiguous, least-significant, trailing zero bits in 'val'. +; +; Caller(s) : Application. +; +; This function is an INTERNAL CPU module function but MAY be called by application +; function(s). +; +; Note(s) : (1) (a) Supports 32-bit data value size as configured by 'CPU_DATA' (see 'cpu.h +; CPU WORD CONFIGURATION Note #1'). +; +; (b) For 32-bit values : +; +; b31 b30 b29 b28 b27 ... b02 b01 b00 # Trailing Zeros +; --- --- --- --- --- --- --- --- ---------------- +; x x x x x x x 1 0 +; x x x x x x 1 0 1 +; x x x x x 1 0 0 2 +; : : : : : : : : : +; : : : : : : : : : +; x x x x 1 0 0 0 27 +; x x x 1 0 0 0 0 28 +; x x 1 0 0 0 0 0 29 +; x 1 0 0 0 0 0 0 30 +; 1 0 0 0 0 0 0 0 31 +; 0 0 0 0 0 0 0 0 32 +; +; +; (2) MUST be defined in 'cpu_a.asm' (or 'cpu_c.c') if CPU_CFG_TRAIL_ZEROS_ASM_PRESENT is +; #define'd in 'cpu_cfg.h' or 'cpu.h'. +;******************************************************************************************************** + +CPU_CntTrailZeros: + RBIT R0, R0 ; Reverse bits + CLZ R0, R0 ; Count trailing zeros + BX LR + + +;******************************************************************************************************** +; CPU_RevBits() +; REVERSE BITS +; +; Description : Reverses the bits in a data value. +; +; Prototypes : CPU_DATA CPU_RevBits(CPU_DATA val); +; +; Argument(s) : val Data value to reverse bits. +; +; Return(s) : Value with all bits in 'val' reversed (see Note #1). +; +; Caller(s) : Application. +; +; This function is an INTERNAL CPU module function but MAY be called by application function(s). +; +; Note(s) : (1) The final, reversed data value for 'val' is such that : +; +; 'val's final bit 0 = 'val's original bit N +; 'val's final bit 1 = 'val's original bit (N - 1) +; 'val's final bit 2 = 'val's original bit (N - 2) +; +; ... ... +; +; 'val's final bit (N - 2) = 'val's original bit 2 +; 'val's final bit (N - 1) = 'val's original bit 1 +; 'val's final bit N = 'val's original bit 0 +;******************************************************************************************************** + +CPU_RevBits: + RBIT R0, R0 ; Reverse bits + BX LR + + +;******************************************************************************************************** +; CPU ASSEMBLY PORT FILE END +;******************************************************************************************************** + + END + diff --git a/Middlewares/Third_Party/Micrium/uC-CPU/ARM-Cortex-M4/IAR/cpu_c.c b/Middlewares/Third_Party/Micrium/uC-CPU/ARM-Cortex-M4/IAR/cpu_c.c new file mode 100644 index 0000000..fc52ddd --- /dev/null +++ b/Middlewares/Third_Party/Micrium/uC-CPU/ARM-Cortex-M4/IAR/cpu_c.c @@ -0,0 +1,746 @@ +/* +********************************************************************************************************* +* uC/CPU +* CPU CONFIGURATION & PORT LAYER +* +* (c) Copyright 2004-2015; Micrium, Inc.; Weston, FL +* +* All rights reserved. Protected by international copyright laws. +* +* uC/CPU is provided in source form to registered licensees ONLY. It is +* illegal to distribute this source code to any third party unless you receive +* written permission by an authorized Micrium representative. Knowledge of +* the source code may NOT be used to develop a similar product. +* +* Please help us continue to provide the Embedded community with the finest +* software available. Your honesty is greatly appreciated. +* +* You can find our product's user manual, API reference, release notes and +* more information at https://doc.micrium.com. +* You can contact us at www.micrium.com. +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* +* CPU PORT FILE +* +* ARM-Cortex-M4 +* IAR C Compiler +* +* Filename : cpu_c.c +* Version : V1.30.02.00 +* Programmer(s) : JJL +* BAN +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* INCLUDE FILES +********************************************************************************************************* +*/ + +#define MICRIUM_SOURCE +#include +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/* +********************************************************************************************************* +* LOCAL DEFINES +********************************************************************************************************* +*/ + +#define CPU_INT_SRC_POS_MAX ((((CPU_REG_NVIC_NVIC + 1) & 0x1F) * 32) + 16) + +#define CPU_BIT_BAND_SRAM_REG_LO 0x20000000 +#define CPU_BIT_BAND_SRAM_REG_HI 0x200FFFFF +#define CPU_BIT_BAND_SRAM_BASE 0x22000000 + + +#define CPU_BIT_BAND_PERIPH_REG_LO 0x40000000 +#define CPU_BIT_BAND_PERIPH_REG_HI 0x400FFFFF +#define CPU_BIT_BAND_PERIPH_BASE 0x42000000 + + +/* +********************************************************************************************************* +* LOCAL CONSTANTS +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL DATA TYPES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL TABLES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL GLOBAL VARIABLES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL FUNCTION PROTOTYPES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL CONFIGURATION ERRORS +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* CPU_BitBandClr() +* +* Description : Clear bit in bit-band region. +* +* Argument(s) : addr Byte address in memory space. +* +* bit_nbr Bit number in byte. +* +* Return(s) : none. +* +* Caller(s) : Application. +* +* Note(s) : none. +********************************************************************************************************* +*/ + +void CPU_BitBandClr (CPU_ADDR addr, + CPU_INT08U bit_nbr) +{ + CPU_ADDR bit_word_off; + CPU_ADDR bit_word_addr; + + + if ((addr >= CPU_BIT_BAND_SRAM_REG_LO) && + (addr <= CPU_BIT_BAND_SRAM_REG_HI)) { + bit_word_off = ((addr - CPU_BIT_BAND_SRAM_REG_LO ) * 32) + (bit_nbr * 4); + bit_word_addr = CPU_BIT_BAND_SRAM_BASE + bit_word_off; + + *(volatile CPU_INT32U *)(bit_word_addr) = 0; + + } else if ((addr >= CPU_BIT_BAND_PERIPH_REG_LO) && + (addr <= CPU_BIT_BAND_PERIPH_REG_HI)) { + bit_word_off = ((addr - CPU_BIT_BAND_PERIPH_REG_LO) * 32) + (bit_nbr * 4); + bit_word_addr = CPU_BIT_BAND_PERIPH_BASE + bit_word_off; + + *(volatile CPU_INT32U *)(bit_word_addr) = 0; + } +} + + +/* +********************************************************************************************************* +* CPU_BitBandSet() +* +* Description : Set bit in bit-band region. +* +* Argument(s) : addr Byte address in memory space. +* +* bit_nbr Bit number in byte. +* +* Return(s) : none. +* +* Caller(s) : Application. +* +* Note(s) : none. +********************************************************************************************************* +*/ + +void CPU_BitBandSet (CPU_ADDR addr, + CPU_INT08U bit_nbr) +{ + CPU_ADDR bit_word_off; + CPU_ADDR bit_word_addr; + + + if ((addr >= CPU_BIT_BAND_SRAM_REG_LO) && + (addr <= CPU_BIT_BAND_SRAM_REG_HI)) { + bit_word_off = ((addr - CPU_BIT_BAND_SRAM_REG_LO ) * 32) + (bit_nbr * 4); + bit_word_addr = CPU_BIT_BAND_SRAM_BASE + bit_word_off; + + *(volatile CPU_INT32U *)(bit_word_addr) = 1; + + } else if ((addr >= CPU_BIT_BAND_PERIPH_REG_LO) && + (addr <= CPU_BIT_BAND_PERIPH_REG_HI)) { + bit_word_off = ((addr - CPU_BIT_BAND_PERIPH_REG_LO) * 32) + (bit_nbr * 4); + bit_word_addr = CPU_BIT_BAND_PERIPH_BASE + bit_word_off; + + *(volatile CPU_INT32U *)(bit_word_addr) = 1; + } +} + + +/* +********************************************************************************************************* +* CPU_IntSrcDis() +* +* Description : Disable an interrupt source. +* +* Argument(s) : pos Position of interrupt vector in interrupt table : +* +* 0 Invalid (see Note #1a). +* 1 Invalid (see Note #1b). +* 2 Non-maskable interrupt. +* 3 Hard Fault. +* 4 Memory Management. +* 5 Bus Fault. +* 6 Usage Fault. +* 7-10 Reserved. +* 11 SVCall +* 12 Debug monitor. +* 13 Reserved +* 14 PendSV. +* 15 SysTick. +* 16+ External Interrupt. +* +* Return(s) : none. +* +* Caller(s) : Application. +* +* Note(s) : (1) Several table positions do not contain interrupt sources : +* +* (a) Position 0 contains the stack pointer. +* (b) Positions 7-10, 13 are reserved. +* +* (2) Several interrupts cannot be disabled/enabled : +* +* (a) Reset. +* (b) NMI. +* (c) Hard fault. +* (d) SVCall. +* (e) Debug monitor. +* (f) PendSV. +* +* (3) The maximum Cortex-M3 table position is 256. A particular Cortex-M3 may have fewer +* than 240 external exceptions and, consequently, fewer than 256 table positions. +* This function assumes that the specified table position is valid if the interrupt +* controller type register's INTLINESNUM field is large enough so that the position +* COULD be valid. +********************************************************************************************************* +*/ +void CPU_IntSrcDis (CPU_INT08U pos) +{ + CPU_INT08U group; + CPU_INT08U pos_max; + CPU_INT08U nbr; + CPU_SR_ALLOC(); + + + switch (pos) { + case CPU_INT_STK_PTR: /* ---------------- INVALID OR RESERVED --------------- */ + case CPU_INT_RSVD_07: + case CPU_INT_RSVD_08: + case CPU_INT_RSVD_09: + case CPU_INT_RSVD_10: + case CPU_INT_RSVD_13: + break; + + + /* ----------------- SYSTEM EXCEPTIONS ---------------- */ + case CPU_INT_RESET: /* Reset (see Note #2). */ + case CPU_INT_NMI: /* Non-maskable interrupt (see Note #2). */ + case CPU_INT_HFAULT: /* Hard fault (see Note #2). */ + case CPU_INT_SVCALL: /* SVCall (see Note #2). */ + case CPU_INT_DBGMON: /* Debug monitor (see Note #2). */ + case CPU_INT_PENDSV: /* PendSV (see Note #2). */ + break; + + case CPU_INT_MEM: /* Memory management. */ + CPU_CRITICAL_ENTER(); + CPU_REG_NVIC_SHCSR &= ~CPU_REG_NVIC_SHCSR_MEMFAULTENA; + CPU_CRITICAL_EXIT(); + break; + + case CPU_INT_BUSFAULT: /* Bus fault. */ + CPU_CRITICAL_ENTER(); + CPU_REG_NVIC_SHCSR &= ~CPU_REG_NVIC_SHCSR_BUSFAULTENA; + CPU_CRITICAL_EXIT(); + break; + + case CPU_INT_USAGEFAULT: /* Usage fault. */ + CPU_CRITICAL_ENTER(); + CPU_REG_NVIC_SHCSR &= ~CPU_REG_NVIC_SHCSR_USGFAULTENA; + CPU_CRITICAL_EXIT(); + break; + + case CPU_INT_SYSTICK: /* SysTick. */ + CPU_CRITICAL_ENTER(); + CPU_REG_NVIC_ST_CTRL &= ~CPU_REG_NVIC_ST_CTRL_ENABLE; + CPU_CRITICAL_EXIT(); + break; + + + /* ---------------- EXTERNAL INTERRUPT ---------------- */ + default: + pos_max = CPU_INT_SRC_POS_MAX; + if (pos < pos_max) { /* See Note #3. */ + group = (pos - 16) / 32; + nbr = (pos - 16) % 32; + + CPU_CRITICAL_ENTER(); + CPU_REG_NVIC_CLREN(group) = DEF_BIT(nbr); + CPU_CRITICAL_EXIT(); + } + break; + } +} + + +/* +********************************************************************************************************* +* CPU_IntSrcEn() +* +* Description : Enable an interrupt source. +* +* Argument(s) : pos Position of interrupt vector in interrupt table (see 'CPU_IntSrcDis()'). +* +* Return(s) : none. +* +* Caller(s) : Application. +* +* Note(s) : (1) See 'CPU_IntSrcDis() Note #1'. +* +* (2) See 'CPU_IntSrcDis() Note #2'. +* +* (3) See 'CPU_IntSrcDis() Note #3'. +********************************************************************************************************* +*/ + +void CPU_IntSrcEn (CPU_INT08U pos) +{ + CPU_INT08U group; + CPU_INT08U nbr; + CPU_INT08U pos_max; + CPU_SR_ALLOC(); + + + switch (pos) { + case CPU_INT_STK_PTR: /* ---------------- INVALID OR RESERVED --------------- */ + case CPU_INT_RSVD_07: + case CPU_INT_RSVD_08: + case CPU_INT_RSVD_09: + case CPU_INT_RSVD_10: + case CPU_INT_RSVD_13: + break; + + + /* ----------------- SYSTEM EXCEPTIONS ---------------- */ + case CPU_INT_RESET: /* Reset (see Note #2). */ + case CPU_INT_NMI: /* Non-maskable interrupt (see Note #2). */ + case CPU_INT_HFAULT: /* Hard fault (see Note #2). */ + case CPU_INT_SVCALL: /* SVCall (see Note #2). */ + case CPU_INT_DBGMON: /* Debug monitor (see Note #2). */ + case CPU_INT_PENDSV: /* PendSV (see Note #2). */ + break; + + case CPU_INT_MEM: /* Memory management. */ + CPU_CRITICAL_ENTER(); + CPU_REG_NVIC_SHCSR |= CPU_REG_NVIC_SHCSR_MEMFAULTENA; + CPU_CRITICAL_EXIT(); + break; + + case CPU_INT_BUSFAULT: /* Bus fault. */ + CPU_CRITICAL_ENTER(); + CPU_REG_NVIC_SHCSR |= CPU_REG_NVIC_SHCSR_BUSFAULTENA; + CPU_CRITICAL_EXIT(); + break; + + case CPU_INT_USAGEFAULT: /* Usage fault. */ + CPU_CRITICAL_ENTER(); + CPU_REG_NVIC_SHCSR |= CPU_REG_NVIC_SHCSR_USGFAULTENA; + CPU_CRITICAL_EXIT(); + break; + + case CPU_INT_SYSTICK: /* SysTick. */ + CPU_CRITICAL_ENTER(); + CPU_REG_NVIC_ST_CTRL |= CPU_REG_NVIC_ST_CTRL_ENABLE; + CPU_CRITICAL_EXIT(); + break; + + + /* ---------------- EXTERNAL INTERRUPT ---------------- */ + default: + pos_max = CPU_INT_SRC_POS_MAX; + if (pos < pos_max) { /* See Note #3. */ + group = (pos - 16) / 32; + nbr = (pos - 16) % 32; + + CPU_CRITICAL_ENTER(); + CPU_REG_NVIC_SETEN(group) = DEF_BIT(nbr); + CPU_CRITICAL_EXIT(); + } + break; + } +} + +/* +********************************************************************************************************* +* CPU_IntSrcPendClr() +* +* Description : Clear a pending interrupt. +* +* Argument(s) : pos Position of interrupt vector in interrupt table (see 'CPU_IntSrcDis()'). +* +* Return(s) : none. +* +* Caller(s) : Application. +* +* Note(s) : (1) See 'CPU_IntSrcDis() Note #1'. +* +* (2) The pending status of several interrupts cannot be clear/set : +* +* (a) Reset. +* (b) NMI. +* (c) Hard fault. +* (d) Memory Managment. +* (e) Bus Fault. +* (f) Usage Fault. +* (g) SVCall. +* (h) Debug monitor. +* (i) PendSV. +* (j) Systick +* +* (3) See 'CPU_IntSrcDis() Note #3'. +********************************************************************************************************* +*/ + +void CPU_IntSrcPendClr (CPU_INT08U pos) + +{ + CPU_INT08U group; + CPU_INT08U nbr; + CPU_INT08U pos_max; + CPU_SR_ALLOC(); + + + switch (pos) { + case CPU_INT_STK_PTR: /* ---------------- INVALID OR RESERVED --------------- */ + case CPU_INT_RSVD_07: + case CPU_INT_RSVD_08: + case CPU_INT_RSVD_09: + case CPU_INT_RSVD_10: + case CPU_INT_RSVD_13: + break; + /* ----------------- SYSTEM EXCEPTIONS ---------------- */ + case CPU_INT_RESET: /* Reset (see Note #2). */ + case CPU_INT_NMI: /* Non-maskable interrupt (see Note #2). */ + case CPU_INT_HFAULT: /* Hard fault (see Note #2). */ + case CPU_INT_MEM: /* Memory management (see Note #2). */ + case CPU_INT_SVCALL: /* SVCall (see Note #2). */ + case CPU_INT_DBGMON: /* Debug monitor (see Note #2). */ + case CPU_INT_PENDSV: /* PendSV (see Note #2). */ + case CPU_INT_BUSFAULT: /* Bus fault. */ + case CPU_INT_USAGEFAULT: /* Usage fault. */ + case CPU_INT_SYSTICK: /* SysTick. */ + break; + /* ---------------- EXTERNAL INTERRUPT ---------------- */ + default: + pos_max = CPU_INT_SRC_POS_MAX; + if (pos < pos_max) { /* See Note #3. */ + group = (pos - 16) / 32; + nbr = (pos - 16) % 32; + + CPU_CRITICAL_ENTER(); + CPU_REG_NVIC_CLRPEND(group) = DEF_BIT(nbr); + CPU_CRITICAL_EXIT(); + } + break; + } +} + + +/* +********************************************************************************************************* +* CPU_IntSrcPrioSet() +* +* Description : Set priority of an interrupt source. +* +* Argument(s) : pos Position of interrupt vector in interrupt table (see 'CPU_IntSrcDis()'). +* +* prio Priority. Use a lower priority number for a higher priority. +* +* Return(s) : none. +* +* Caller(s) : Application. +* +* Note(s) : (1) See 'CPU_IntSrcDis() Note #1'. +* +* (2) Several interrupts priorities CANNOT be set : +* +* (a) Reset (always -3). +* (b) NMI (always -2). +* (c) Hard fault (always -1). +* +* (3) See 'CPU_IntSrcDis() Note #3'. +********************************************************************************************************* +*/ + +void CPU_IntSrcPrioSet (CPU_INT08U pos, + CPU_INT08U prio) +{ + CPU_INT08U group; + CPU_INT08U nbr; + CPU_INT08U pos_max; + CPU_INT32U temp; + CPU_SR_ALLOC(); + + + switch (pos) { + case CPU_INT_STK_PTR: /* ---------------- INVALID OR RESERVED --------------- */ + case CPU_INT_RSVD_07: + case CPU_INT_RSVD_08: + case CPU_INT_RSVD_09: + case CPU_INT_RSVD_10: + case CPU_INT_RSVD_13: + break; + + + /* ----------------- SYSTEM EXCEPTIONS ---------------- */ + case CPU_INT_RESET: /* Reset (see Note #2). */ + case CPU_INT_NMI: /* Non-maskable interrupt (see Note #2). */ + case CPU_INT_HFAULT: /* Hard fault (see Note #2). */ + break; + + case CPU_INT_MEM: /* Memory management. */ + CPU_CRITICAL_ENTER(); + temp = CPU_REG_NVIC_SHPRI1; + temp &= ~(DEF_OCTET_MASK << (0 * DEF_OCTET_NBR_BITS)); + temp |= (prio << (0 * DEF_OCTET_NBR_BITS)); + CPU_REG_NVIC_SHPRI1 = temp; + CPU_CRITICAL_EXIT(); + break; + + case CPU_INT_BUSFAULT: /* Bus fault. */ + CPU_CRITICAL_ENTER(); + temp = CPU_REG_NVIC_SHPRI1; + temp &= ~(DEF_OCTET_MASK << (1 * DEF_OCTET_NBR_BITS)); + temp |= (prio << (1 * DEF_OCTET_NBR_BITS)); + CPU_REG_NVIC_SHPRI1 = temp; + CPU_CRITICAL_EXIT(); + break; + + case CPU_INT_USAGEFAULT: /* Usage fault. */ + CPU_CRITICAL_ENTER(); + temp = CPU_REG_NVIC_SHPRI1; + temp &= ~(DEF_OCTET_MASK << (2 * DEF_OCTET_NBR_BITS)); + temp |= (prio << (2 * DEF_OCTET_NBR_BITS)); + CPU_REG_NVIC_SHPRI1 = temp; + CPU_CRITICAL_EXIT(); + break; + + case CPU_INT_SVCALL: /* SVCall. */ + CPU_CRITICAL_ENTER(); + temp = CPU_REG_NVIC_SHPRI2; + temp &= ~((CPU_INT32U)DEF_OCTET_MASK << (3 * DEF_OCTET_NBR_BITS)); + temp |= (prio << (3 * DEF_OCTET_NBR_BITS)); + CPU_REG_NVIC_SHPRI2 = temp; + CPU_CRITICAL_EXIT(); + break; + + case CPU_INT_DBGMON: /* Debug monitor. */ + CPU_CRITICAL_ENTER(); + temp = CPU_REG_NVIC_SHPRI3; + temp &= ~(DEF_OCTET_MASK << (0 * DEF_OCTET_NBR_BITS)); + temp |= (prio << (0 * DEF_OCTET_NBR_BITS)); + CPU_REG_NVIC_SHPRI3 = temp; + CPU_CRITICAL_EXIT(); + break; + + case CPU_INT_PENDSV: /* PendSV. */ + CPU_CRITICAL_ENTER(); + temp = CPU_REG_NVIC_SHPRI3; + temp &= ~(DEF_OCTET_MASK << (2 * DEF_OCTET_NBR_BITS)); + temp |= (prio << (2 * DEF_OCTET_NBR_BITS)); + CPU_REG_NVIC_SHPRI3 = temp; + CPU_CRITICAL_EXIT(); + break; + + case CPU_INT_SYSTICK: /* SysTick. */ + CPU_CRITICAL_ENTER(); + temp = CPU_REG_NVIC_SHPRI3; + temp &= ~((CPU_INT32U)DEF_OCTET_MASK << (3 * DEF_OCTET_NBR_BITS)); + temp |= (prio << (3 * DEF_OCTET_NBR_BITS)); + CPU_REG_NVIC_SHPRI3 = temp; + CPU_CRITICAL_EXIT(); + break; + + + /* ---------------- EXTERNAL INTERRUPT ---------------- */ + default: + pos_max = CPU_INT_SRC_POS_MAX; + if (pos < pos_max) { /* See Note #3. */ + group = (pos - 16) / 4; + nbr = (pos - 16) % 4; + + CPU_CRITICAL_ENTER(); + temp = CPU_REG_NVIC_PRIO(group); + temp &= ~(DEF_OCTET_MASK << (nbr * DEF_OCTET_NBR_BITS)); + temp |= (prio << (nbr * DEF_OCTET_NBR_BITS)); + CPU_REG_NVIC_PRIO(group) = temp; + CPU_CRITICAL_EXIT(); + } + break; + } +} + + +/* +********************************************************************************************************* +* CPU_IntSrcPrioGet() +* +* Description : Get priority of an interrupt source. +* +* Argument(s) : pos Position of interrupt vector in interrupt table (see 'CPU_IntSrcDis()'). +* +* Return(s) : Priority of interrupt source. If the interrupt source specified is invalid, then +* DEF_INT_16S_MIN_VAL is returned. +* +* Caller(s) : Application. +* +* Note(s) : (1) See 'CPU_IntSrcDis() Note #1'. +* +* (2) See 'CPU_IntSrcPrioSet() Note #2'. +* +* (3) See 'CPU_IntSrcDis() Note #3'. +********************************************************************************************************* +*/ + +CPU_INT16S CPU_IntSrcPrioGet (CPU_INT08U pos) +{ + CPU_INT08U group; + CPU_INT08U nbr; + CPU_INT08U pos_max; + CPU_INT16S prio; + CPU_INT32U temp; + CPU_SR_ALLOC(); + + + switch (pos) { + case CPU_INT_STK_PTR: /* ---------------- INVALID OR RESERVED --------------- */ + case CPU_INT_RSVD_07: + case CPU_INT_RSVD_08: + case CPU_INT_RSVD_09: + case CPU_INT_RSVD_10: + case CPU_INT_RSVD_13: + prio = DEF_INT_16S_MIN_VAL; + break; + + + /* ----------------- SYSTEM EXCEPTIONS ---------------- */ + case CPU_INT_RESET: /* Reset (see Note #2). */ + prio = -3; + break; + + case CPU_INT_NMI: /* Non-maskable interrupt (see Note #2). */ + prio = -2; + break; + + case CPU_INT_HFAULT: /* Hard fault (see Note #2). */ + prio = -1; + break; + + + case CPU_INT_MEM: /* Memory management. */ + CPU_CRITICAL_ENTER(); + temp = CPU_REG_NVIC_SHPRI1; + prio = (temp >> (0 * DEF_OCTET_NBR_BITS)) & DEF_OCTET_MASK; + CPU_CRITICAL_EXIT(); + break; + + + case CPU_INT_BUSFAULT: /* Bus fault. */ + CPU_CRITICAL_ENTER(); + temp = CPU_REG_NVIC_SHPRI1; + prio = (temp >> (1 * DEF_OCTET_NBR_BITS)) & DEF_OCTET_MASK; + CPU_CRITICAL_EXIT(); + break; + + + case CPU_INT_USAGEFAULT: /* Usage fault. */ + CPU_CRITICAL_ENTER(); + temp = CPU_REG_NVIC_SHPRI1; + prio = (temp >> (2 * DEF_OCTET_NBR_BITS)) & DEF_OCTET_MASK; + CPU_CRITICAL_EXIT(); + break; + + case CPU_INT_SVCALL: /* SVCall. */ + CPU_CRITICAL_ENTER(); + temp = CPU_REG_NVIC_SHPRI2; + prio = (temp >> (3 * DEF_OCTET_NBR_BITS)) & DEF_OCTET_MASK; + CPU_CRITICAL_EXIT(); + break; + + case CPU_INT_DBGMON: /* Debug monitor. */ + CPU_CRITICAL_ENTER(); + temp = CPU_REG_NVIC_SHPRI3; + prio = (temp >> (0 * DEF_OCTET_NBR_BITS)) & DEF_OCTET_MASK; + CPU_CRITICAL_EXIT(); + break; + + case CPU_INT_PENDSV: /* PendSV. */ + CPU_CRITICAL_ENTER(); + temp = CPU_REG_NVIC_SHPRI3; + prio = (temp >> (2 * DEF_OCTET_NBR_BITS)) & DEF_OCTET_MASK; + CPU_CRITICAL_EXIT(); + break; + + case CPU_INT_SYSTICK: /* SysTick. */ + CPU_CRITICAL_ENTER(); + temp = CPU_REG_NVIC_SHPRI3; + prio = (temp >> (3 * DEF_OCTET_NBR_BITS)) & DEF_OCTET_MASK; + CPU_CRITICAL_EXIT(); + break; + + + /* ---------------- EXTERNAL INTERRUPT ---------------- */ + default: + pos_max = CPU_INT_SRC_POS_MAX; + if (pos < pos_max) { /* See Note #3. */ + group = (pos - 16) / 4; + nbr = (pos - 16) % 4; + + CPU_CRITICAL_ENTER(); + temp = CPU_REG_NVIC_PRIO(group); + CPU_CRITICAL_EXIT(); + + prio = (temp >> (nbr * DEF_OCTET_NBR_BITS)) & DEF_OCTET_MASK; + } else { + prio = DEF_INT_16S_MIN_VAL; + } + break; + } + + return (prio); +} + +#ifdef __cplusplus +} +#endif diff --git a/Middlewares/Third_Party/Micrium/uC-CPU/cpu_core.c b/Middlewares/Third_Party/Micrium/uC-CPU/cpu_core.c new file mode 100644 index 0000000..7d6ee40 --- /dev/null +++ b/Middlewares/Third_Party/Micrium/uC-CPU/cpu_core.c @@ -0,0 +1,2387 @@ +/* +********************************************************************************************************* +* uC/CPU +* CPU CONFIGURATION & PORT LAYER +* +* (c) Copyright 2004-2015; Micrium, Inc.; Weston, FL +* +* All rights reserved. Protected by international copyright laws. +* +* uC/CPU is provided in source form to registered licensees ONLY. It is +* illegal to distribute this source code to any third party unless you receive +* written permission by an authorized Micrium representative. Knowledge of +* the source code may NOT be used to develop a similar product. +* +* Please help us continue to provide the Embedded community with the finest +* software available. Your honesty is greatly appreciated. +* +* You can find our product's user manual, API reference, release notes and +* more information at https://doc.micrium.com. +* You can contact us at www.micrium.com. +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* +* CORE CPU MODULE +* +* Filename : cpu_core.c +* Version : V1.30.02 +* Programmer(s) : SR +* ITJ +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* INCLUDE FILES +********************************************************************************************************* +*/ + +#define MICRIUM_SOURCE +#define CPU_CORE_MODULE +#include "cpu_core.h" + +#if defined(CPU_CFG_CACHE_MGMT_EN) +#if (CPU_CFG_CACHE_MGMT_EN == DEF_ENABLED) +#include "cpu_cache.h" +#endif +#endif + + +/* +********************************************************************************************************* +* LOCAL DEFINES +********************************************************************************************************* +*/ + + /* Pop cnt algorithm csts. */ +#define CRC_UTIL_POPCNT_MASK01010101_32 0x55555555u +#define CRC_UTIL_POPCNT_MASK00110011_32 0x33333333u +#define CRC_UTIL_POPCNT_MASK00001111_32 0x0F0F0F0Fu +#define CRC_UTIL_POPCNT_POWERSOF256_32 0x01010101u + + +/* +********************************************************************************************************* +* LOCAL CONSTANTS +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL DATA TYPES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL TABLES +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* CPU COUNT LEAD ZEROs LOOKUP TABLE +* +* Note(s) : (1) Index into bit pattern table determines the number of leading zeros in an 8-bit value : +* +* b07 b06 b05 b04 b03 b02 b01 b00 # Leading Zeros +* --- --- --- --- --- --- --- --- --------------- +* 1 x x x x x x x 0 +* 0 1 x x x x x x 1 +* 0 0 1 x x x x x 2 +* 0 0 0 1 x x x x 3 +* 0 0 0 0 1 x x x 4 +* 0 0 0 0 0 1 x x 5 +* 0 0 0 0 0 0 1 x 6 +* 0 0 0 0 0 0 0 1 7 +* 0 0 0 0 0 0 0 0 8 +********************************************************************************************************* +*/ + +#if (!(defined(CPU_CFG_LEAD_ZEROS_ASM_PRESENT)) || \ + (CPU_CFG_DATA_SIZE_MAX > CPU_CFG_DATA_SIZE)) +static const CPU_INT08U CPU_CntLeadZerosTbl[256] = { /* Data vals : */ +/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ + 8u, 7u, 6u, 6u, 5u, 5u, 5u, 5u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, /* 0x00 to 0x0F */ + 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, /* 0x10 to 0x1F */ + 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, /* 0x20 to 0x2F */ + 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, /* 0x30 to 0x3F */ + 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, /* 0x40 to 0x4F */ + 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, /* 0x50 to 0x5F */ + 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, /* 0x60 to 0x6F */ + 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, /* 0x70 to 0x7F */ + 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, /* 0x80 to 0x8F */ + 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, /* 0x90 to 0x9F */ + 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, /* 0xA0 to 0xAF */ + 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, /* 0xB0 to 0xBF */ + 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, /* 0xC0 to 0xCF */ + 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, /* 0xD0 to 0xDF */ + 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, /* 0xE0 to 0xEF */ + 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u /* 0xF0 to 0xFF */ +}; +#endif + + +/* +********************************************************************************************************* +* LOCAL GLOBAL VARIABLES +********************************************************************************************************* +*/ + +CPU_INT32U const CPU_EndiannessTest = 0x12345678LU; /* Variable to test CPU endianness. */ + + +/* +********************************************************************************************************* +* LOCAL FUNCTION PROTOTYPES +********************************************************************************************************* +*/ + +#if (CPU_CFG_NAME_EN == DEF_ENABLED) /* ---------------- CPU NAME FNCTS ---------------- */ +static void CPU_NameInit (void); +#endif + + + /* ----------------- CPU TS FNCTS ----------------- */ +#if ((CPU_CFG_TS_EN == DEF_ENABLED) || \ + (CPU_CFG_TS_TMR_EN == DEF_ENABLED)) +static void CPU_TS_Init (void); +#endif + + +#ifdef CPU_CFG_INT_DIS_MEAS_EN /* ---------- CPU INT DIS TIME MEAS FNCTS --------- */ +static void CPU_IntDisMeasInit (void); + +static CPU_TS_TMR CPU_IntDisMeasMaxCalc(CPU_TS_TMR time_tot_cnts); +#endif + + +/* +********************************************************************************************************* +* LOCAL CONFIGURATION ERRORS +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* CPU_Init() +* +* Description : (1) Initialize CPU module : +* +* (a) Initialize CPU timestamps +* (b) Initialize CPU interrupts disabled time measurements +* (c) Initialize CPU host name +* +* +* Argument(s) : none. +* +* Return(s) : none. +* +* Caller(s) : Your Product's Application. +* +* This function is a CPU initialization function & MAY be called by application/ +* initialization function(s). +* +* Note(s) : (2) CPU_Init() MUST be called ... : +* +* (a) ONLY ONCE from a product's application; ... +* (b) BEFORE product's application calls any core CPU module function(s) +* +* (3) The following initialization functions MUST be sequenced as follows : +* +* (a) CPU_TS_Init() SHOULD precede ALL calls to other CPU timestamp functions +* +* (b) CPU_IntDisMeasInit() SHOULD precede ALL calls to CPU_CRITICAL_ENTER()/CPU_CRITICAL_EXIT() +* & other CPU interrupts disabled time measurement functions +********************************************************************************************************* +*/ + +void CPU_Init (void) +{ + /* --------------------- INIT TS ---------------------- */ +#if ((CPU_CFG_TS_EN == DEF_ENABLED) || \ + (CPU_CFG_TS_TMR_EN == DEF_ENABLED)) + CPU_TS_Init(); /* See Note #3a. */ +#endif + /* -------------- INIT INT DIS TIME MEAS -------------- */ +#ifdef CPU_CFG_INT_DIS_MEAS_EN + CPU_IntDisMeasInit(); /* See Note #3b. */ +#endif + + /* ------------------ INIT CPU NAME ------------------- */ +#if (CPU_CFG_NAME_EN == DEF_ENABLED) + CPU_NameInit(); +#endif + +#if (CPU_CFG_CACHE_MGMT_EN == DEF_ENABLED) + CPU_Cache_Init(); +#endif +} + + +/* +********************************************************************************************************* +* CPU_SW_Exception() +* +* Description : Trap unrecoverable software exception. +* +* Argument(s) : none. +* +* Return(s) : none. +* +* Caller(s) : various. +* +* Note(s) : (1) CPU_SW_Exception() deadlocks the current code execution -- whether multi-tasked/ +* -processed/-threaded or single-threaded -- when the current code execution cannot +* gracefully recover or report a fault or exception condition. +* +* See also 'cpu_core.h CPU_SW_EXCEPTION() Note #1'. +********************************************************************************************************* +*/ + +void CPU_SW_Exception (void) +{ + while (DEF_ON) { + ; + } +} + + +/* +********************************************************************************************************* +* CPU_NameClr() +* +* Description : Clear CPU Name. +* +* Argument(s) : none. +* +* Return(s) : none. +* +* Caller(s) : CPU_NameInit(), +* Application. +* +* This function is a CPU module application programming interface (API) function & MAY be +* called by application function(s). +* +* Note(s) : none. +********************************************************************************************************* +*/ + +#if (CPU_CFG_NAME_EN == DEF_ENABLED) +void CPU_NameClr (void) +{ + CPU_SR_ALLOC(); + + + CPU_CRITICAL_ENTER(); + Mem_Clr((void *)&CPU_Name[0], + (CPU_SIZE_T) CPU_CFG_NAME_SIZE); + CPU_CRITICAL_EXIT(); +} +#endif + + +/* +********************************************************************************************************* +* CPU_NameGet() +* +* Description : Get CPU host name. +* +* Argument(s) : p_name Pointer to an ASCII character array that will receive the return CPU host +* name ASCII string from this function (see Note #1). +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* CPU_ERR_NONE CPU host name successfully returned. +* CPU_ERR_NULL_PTR Argument 'p_name' passed a NULL pointer. +* +* Return(s) : none. +* +* Caller(s) : Application. +* +* This function is a CPU module application programming interface (API) function & MAY +* be called by application function(s). +* +* Note(s) : (1) The size of the ASCII character array that will receive the return CPU host name +* ASCII string : +* +* (a) MUST be greater than or equal to the current CPU host name's ASCII string +* size including the terminating NULL character; +* (b) SHOULD be greater than or equal to CPU_CFG_NAME_SIZE +********************************************************************************************************* +*/ + +#if (CPU_CFG_NAME_EN == DEF_ENABLED) +void CPU_NameGet (CPU_CHAR *p_name, + CPU_ERR *p_err) +{ + CPU_SR_ALLOC(); + + + if (p_err == (CPU_ERR *)0) { + CPU_SW_EXCEPTION(;); + } + + if (p_name == (CPU_CHAR *)0) { + *p_err = CPU_ERR_NULL_PTR; + return; + } + + CPU_CRITICAL_ENTER(); + (void)Str_Copy_N(p_name, + &CPU_Name[0], + CPU_CFG_NAME_SIZE); + CPU_CRITICAL_EXIT(); + + *p_err = CPU_ERR_NONE; +} +#endif + + +/* +********************************************************************************************************* +* CPU_NameSet() +* +* Description : Set CPU host name. +* +* Argument(s) : p_name Pointer to CPU host name to set. +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* CPU_ERR_NONE CPU host name successfully set. +* CPU_ERR_NULL_PTR Argument 'p_name' passed a NULL pointer. +* CPU_ERR_NAME_SIZE Invalid CPU host name size (see Note #1). +* +* Return(s) : none. +* +* Caller(s) : Application. +* +* This function is a CPU module application programming interface (API) function & MAY be +* called by application function(s). +* +* Note(s) : (1) 'p_name' ASCII string size, including the terminating NULL character, MUST be less +* than or equal to CPU_CFG_NAME_SIZE. +********************************************************************************************************* +*/ + +#if (CPU_CFG_NAME_EN == DEF_ENABLED) +void CPU_NameSet (const CPU_CHAR *p_name, + CPU_ERR *p_err) +{ + CPU_SIZE_T len; + CPU_SR_ALLOC(); + + + if (p_err == (CPU_ERR *)0) { + CPU_SW_EXCEPTION(;); + } + + if (p_name == (const CPU_CHAR *)0) { + *p_err = CPU_ERR_NULL_PTR; + return; + } + + len = Str_Len_N(p_name, + CPU_CFG_NAME_SIZE); + if (len < CPU_CFG_NAME_SIZE) { /* If cfg name len < max name size, ... */ + CPU_CRITICAL_ENTER(); + (void)Str_Copy_N(&CPU_Name[0], /* ... copy cfg name to CPU host name. */ + p_name, + CPU_CFG_NAME_SIZE); + CPU_CRITICAL_EXIT(); + *p_err = CPU_ERR_NONE; + + } else { + *p_err = CPU_ERR_NAME_SIZE; + } +} +#endif + + +/* +********************************************************************************************************* +* CPU_TS_Get32() +* +* Description : Get current 32-bit CPU timestamp. +* +* Argument(s) : none. +* +* Return(s) : Current 32-bit CPU timestamp (in timestamp timer counts). +* +* Caller(s) : Application. +* +* This function is a CPU module application programming interface (API) function & MAY +* be called by application function(s). +* +* Note(s) : (1) When applicable, the amount of time measured by CPU timestamps is calculated by +* either of the following equations : +* +* (a) Time measured = Number timer counts * Timer period +* +* where +* +* Number timer counts Number of timer counts measured +* Timer period Timer's period in some units of +* (fractional) seconds +* Time measured Amount of time measured, in same +* units of (fractional) seconds +* as the Timer period +* +* Number timer counts +* (b) Time measured = --------------------- +* Timer frequency +* +* where +* +* Number timer counts Number of timer counts measured +* Timer frequency Timer's frequency in some units +* of counts per second +* Time measured Amount of time measured, in seconds +* +* See also 'cpu_core.h FUNCTION PROTOTYPES CPU_TS_TmrRd() Note #2c1'. +* +* (2) In case the CPU timestamp timer has lower precision than the 32-bit CPU timestamp; +* its precision is extended via periodic updates by accumulating the deltas of the +* timestamp timer count values into the higher-precision 32-bit CPU timestamp. +* +* (3) After initialization, 'CPU_TS_32_Accum' & 'CPU_TS_32_TmrPrev' MUST ALWAYS +* be accessed AND updated exclusively with interrupts disabled -- but NOT +* with critical sections. +********************************************************************************************************* +*/ + +#if (CPU_CFG_TS_32_EN == DEF_ENABLED) +CPU_TS32 CPU_TS_Get32 (void) +{ + CPU_TS32 ts; +#if (CPU_CFG_TS_TMR_SIZE < CPU_WORD_SIZE_32) + CPU_TS_TMR tmr_cur; + CPU_TS_TMR tmr_delta; + CPU_SR_ALLOC(); +#endif + + +#if (CPU_CFG_TS_TMR_SIZE >= CPU_WORD_SIZE_32) + ts = (CPU_TS32)CPU_TS_TmrRd(); /* Get cur ts tmr val (in 32-bit ts cnts). */ + +#else + CPU_INT_DIS(); + tmr_cur = (CPU_TS_TMR) CPU_TS_TmrRd(); /* Get cur ts tmr val (in ts tmr cnts). */ + tmr_delta = (CPU_TS_TMR)(tmr_cur - CPU_TS_32_TmrPrev); /* Calc delta ts tmr cnts. */ + CPU_TS_32_Accum += (CPU_TS32 ) tmr_delta; /* Inc ts by delta ts tmr cnts (see Note #2). */ + CPU_TS_32_TmrPrev = (CPU_TS_TMR) tmr_cur; /* Save cur ts tmr cnts for next update. */ + ts = (CPU_TS32 ) CPU_TS_32_Accum; + CPU_INT_EN(); +#endif + + return (ts); +} +#endif + + +/* +********************************************************************************************************* +* CPU_TS_Get64() +* +* Description : Get current 64-bit CPU timestamp. +* +* Argument(s) : none. +* +* Return(s) : Current 64-bit CPU timestamp (in timestamp timer counts). +* +* Caller(s) : Application. +* +* This function is a CPU module application programming interface (API) function & MAY +* be called by application function(s). +* +* Note(s) : (1) When applicable, the amount of time measured by CPU timestamps is calculated by +* either of the following equations : +* +* (a) Time measured = Number timer counts * Timer period +* +* where +* +* Number timer counts Number of timer counts measured +* Timer period Timer's period in some units of +* (fractional) seconds +* Time measured Amount of time measured, in same +* units of (fractional) seconds +* as the Timer period +* +* Number timer counts +* (b) Time measured = --------------------- +* Timer frequency +* +* where +* +* Number timer counts Number of timer counts measured +* Timer frequency Timer's frequency in some units +* of counts per second +* Time measured Amount of time measured, in seconds +* +* See also 'cpu_core.h FUNCTION PROTOTYPES CPU_TS_TmrRd() Note #2c1'. +* +* (2) In case the CPU timestamp timer has lower precision than the 64-bit CPU timestamp; +* its precision is extended via periodic updates by accumulating the deltas of the +* timestamp timer count values into the higher-precision 64-bit CPU timestamp. +* +* (3) After initialization, 'CPU_TS_64_Accum' & 'CPU_TS_64_TmrPrev' MUST ALWAYS +* be accessed AND updated exclusively with interrupts disabled -- but NOT +* with critical sections. +********************************************************************************************************* +*/ + +#if (CPU_CFG_TS_64_EN == DEF_ENABLED) +CPU_TS64 CPU_TS_Get64 (void) +{ + CPU_TS64 ts; +#if (CPU_CFG_TS_TMR_SIZE < CPU_WORD_SIZE_64) + CPU_TS_TMR tmr_cur; + CPU_TS_TMR tmr_delta; + CPU_SR_ALLOC(); +#endif + + +#if (CPU_CFG_TS_TMR_SIZE >= CPU_WORD_SIZE_64) + ts = (CPU_TS64)CPU_TS_TmrRd(); /* Get cur ts tmr val (in 64-bit ts cnts). */ + +#else + CPU_INT_DIS(); + tmr_cur = (CPU_TS_TMR) CPU_TS_TmrRd(); /* Get cur ts tmr val (in ts tmr cnts). */ + tmr_delta = (CPU_TS_TMR)(tmr_cur - CPU_TS_64_TmrPrev); /* Calc delta ts tmr cnts. */ + CPU_TS_64_Accum += (CPU_TS64 ) tmr_delta; /* Inc ts by delta ts tmr cnts (see Note #2). */ + CPU_TS_64_TmrPrev = (CPU_TS_TMR) tmr_cur; /* Save cur ts tmr cnts for next update. */ + ts = (CPU_TS64 ) CPU_TS_64_Accum; + CPU_INT_EN(); +#endif + + return (ts); +} +#endif + + +/* +********************************************************************************************************* +* CPU_TS_Update() +* +* Description : Update current CPU timestamp(s). +* +* Argument(s) : none. +* +* Return(s) : none. +* +* Caller(s) : Application/BSP periodic time handler (see Note #1). +* +* This function is a CPU timestamp BSP function & SHOULD be called only by appropriate +* application/BSP function(s). +* +* Note(s) : (1) (a) CPU timestamp(s) MUST be updated periodically by some application (or BSP) time +* handler in order to (adequately) maintain CPU timestamp(s)' time. +* +* (b) CPU timestamp(s) MUST be updated more frequently than the CPU timestamp timer +* overflows; otherwise, CPU timestamp(s) will lose time. +* +* See also 'cpu_core.h FUNCTION PROTOTYPES CPU_TS_TmrRd() Note #2c2'. +********************************************************************************************************* +*/ + +#if (CPU_CFG_TS_EN == DEF_ENABLED) +void CPU_TS_Update (void) +{ +#if ((CPU_CFG_TS_32_EN == DEF_ENABLED) && \ + (CPU_CFG_TS_TMR_SIZE < CPU_WORD_SIZE_32)) + (void)CPU_TS_Get32(); +#endif + +#if ((CPU_CFG_TS_64_EN == DEF_ENABLED) && \ + (CPU_CFG_TS_TMR_SIZE < CPU_WORD_SIZE_64)) + (void)CPU_TS_Get64(); +#endif +} +#endif + + +/* +********************************************************************************************************* +* CPU_TS_TmrFreqGet() +* +* Description : Get CPU timestamp's timer frequency. +* +* Argument(s) : p_err Pointer to variable that will receive the return error code from this function : +* +* CPU_ERR_NONE CPU timestamp's timer frequency successfully +* returned. +* CPU_ERR_TS_FREQ_INVALID CPU timestamp's timer frequency invalid &/or +* NOT yet configured. +* +* Return(s) : CPU timestamp's timer frequency (in Hertz), if NO error(s). +* +* 0, otherwise. +* +* Caller(s) : Application. +* +* This function is a CPU module application programming interface (API) function & MAY be +* called by application function(s). +* +* Note(s) : none. +********************************************************************************************************* +*/ + +#if (CPU_CFG_TS_TMR_EN == DEF_ENABLED) +CPU_TS_TMR_FREQ CPU_TS_TmrFreqGet (CPU_ERR *p_err) +{ + CPU_TS_TMR_FREQ freq_hz; + + + if (p_err == (CPU_ERR *)0) { + CPU_SW_EXCEPTION(;); + } + + freq_hz = CPU_TS_TmrFreq_Hz; + *p_err = (freq_hz != 0u) ? CPU_ERR_NONE : CPU_ERR_TS_FREQ_INVALID; + + return (freq_hz); +} +#endif + + +/* +********************************************************************************************************* +* CPU_TS_TmrFreqSet() +* +* Description : Set CPU timestamp's timer frequency. +* +* Argument(s) : freq_hz Frequency (in Hertz) to set for CPU timestamp's timer. +* +* Return(s) : none. +* +* Caller(s) : CPU_TS_TmrInit(), +* Application/BSP initialization function(s). +* +* This function is a CPU module BSP function & SHOULD be called only by appropriate +* application/BSP function(s) [see Note #1]. +* +* Note(s) : (1) (a) (1) CPU timestamp timer frequency is NOT required for internal CPU timestamp +* operations but may OPTIONALLY be configured by CPU_TS_TmrInit() or other +* application/BSP initialization functions. +* +* (2) CPU timestamp timer frequency MAY be used with optional CPU_TSxx_to_uSec() +* to convert CPU timestamps from timer counts into microseconds. +* +* See also 'cpu_core.h FUNCTION PROTOTYPES CPU_TSxx_to_uSec() Note #2a'. +* +* (b) CPU timestamp timer period SHOULD be less than the typical measured time but MUST +* be less than the maximum measured time; otherwise, timer resolution inadequate to +* measure desired times. +* +* See also 'cpu_core.h FUNCTION PROTOTYPES CPU_TSxx_to_uSec() Note #2b'. +********************************************************************************************************* +*/ + +#if (CPU_CFG_TS_TMR_EN == DEF_ENABLED) +void CPU_TS_TmrFreqSet (CPU_TS_TMR_FREQ freq_hz) +{ + CPU_TS_TmrFreq_Hz = freq_hz; +} +#endif + + +/* +********************************************************************************************************* +* CPU_IntDisMeasMaxCurReset() +* +* Description : Reset current maximum interrupts disabled time. +* +* Argument(s) : none. +* +* Return(s) : Maximum interrupts disabled time (in CPU timestamp timer counts) before resetting. +* +* See also 'cpu_core.h FUNCTION PROTOTYPES CPU_TS_TmrRd() Note #2c' +* & 'cpu_core.h FUNCTION PROTOTYPES CPU_TSxx_to_uSec() Note #2'. +* +* Caller(s) : Application. +* +* This function is a CPU module application programming interface (API) function +* & MAY be called by application function(s). +* +* Note(s) : (1) After initialization, 'CPU_IntDisMeasMaxCur_cnts' MUST ALWAYS be accessed +* exclusively with interrupts disabled -- but NOT with critical sections. +********************************************************************************************************* +*/ + +#ifdef CPU_CFG_INT_DIS_MEAS_EN +CPU_TS_TMR CPU_IntDisMeasMaxCurReset (void) +{ + CPU_TS_TMR time_max_cnts; + CPU_SR_ALLOC(); + + + time_max_cnts = CPU_IntDisMeasMaxCurGet(); + CPU_INT_DIS(); + CPU_IntDisMeasMaxCur_cnts = 0u; + CPU_INT_EN(); + + return (time_max_cnts); +} +#endif + + +/* +********************************************************************************************************* +* CPU_IntDisMeasMaxCurGet() +* +* Description : Get current maximum interrupts disabled time. +* +* Argument(s) : none. +* +* Return(s) : Current maximum interrupts disabled time (in CPU timestamp timer counts). +* +* See also 'cpu_core.h FUNCTION PROTOTYPES CPU_TS_TmrRd() Note #2c' +* & 'cpu_core.h FUNCTION PROTOTYPES CPU_TSxx_to_uSec() Note #2'. +* +* Caller(s) : CPU_IntDisMeasMaxCurReset(), +* Application. +* +* This function is a CPU module application programming interface (API) function +* & MAY be called by application function(s). +* +* Note(s) : (1) After initialization, 'CPU_IntDisMeasMaxCur_cnts' MUST ALWAYS be accessed +* exclusively with interrupts disabled -- but NOT with critical sections. +********************************************************************************************************* +*/ + +#ifdef CPU_CFG_INT_DIS_MEAS_EN +CPU_TS_TMR CPU_IntDisMeasMaxCurGet (void) +{ + CPU_TS_TMR time_tot_cnts; + CPU_TS_TMR time_max_cnts; + CPU_SR_ALLOC(); + + + CPU_INT_DIS(); + time_tot_cnts = CPU_IntDisMeasMaxCur_cnts; + CPU_INT_EN(); + time_max_cnts = CPU_IntDisMeasMaxCalc(time_tot_cnts); + + return (time_max_cnts); +} +#endif + + +/* +********************************************************************************************************* +* CPU_IntDisMeasMaxGet() +* +* Description : Get (non-resetable) maximum interrupts disabled time. +* +* Argument(s) : none. +* +* Return(s) : (Non-resetable) maximum interrupts disabled time (in CPU timestamp timer counts). +* +* See also 'cpu_core.h FUNCTION PROTOTYPES CPU_TS_TmrRd() Note #2c' +* & 'cpu_core.h FUNCTION PROTOTYPES CPU_TSxx_to_uSec() Note #2'. +* +* Caller(s) : CPU_IntDisMeasInit(), +* Application. +* +* This function is a CPU module application programming interface (API) function +* & MAY be called by application function(s). +* +* Note(s) : (1) After initialization, 'CPU_IntDisMeasMax_cnts' MUST ALWAYS be accessed +* exclusively with interrupts disabled -- but NOT with critical sections. +********************************************************************************************************* +*/ + +#ifdef CPU_CFG_INT_DIS_MEAS_EN +CPU_TS_TMR CPU_IntDisMeasMaxGet (void) +{ + CPU_TS_TMR time_tot_cnts; + CPU_TS_TMR time_max_cnts; + CPU_SR_ALLOC(); + + + CPU_INT_DIS(); + time_tot_cnts = CPU_IntDisMeasMax_cnts; + CPU_INT_EN(); + time_max_cnts = CPU_IntDisMeasMaxCalc(time_tot_cnts); + + return (time_max_cnts); +} +#endif + + +/* +********************************************************************************************************* +* CPU_IntDisMeasStart() +* +* Description : Start interrupts disabled time measurement. +* +* Argument(s) : none. +* +* Return(s) : none. +* +* Caller(s) : CPU_CRITICAL_ENTER(). +* +* This function is an INTERNAL CPU module function & MUST NOT be called by application +* function(s). +* +* Note(s) : none. +********************************************************************************************************* +*/ + +#ifdef CPU_CFG_INT_DIS_MEAS_EN +void CPU_IntDisMeasStart (void) +{ + CPU_IntDisMeasCtr++; + if (CPU_IntDisNestCtr == 0u) { /* If ints NOT yet dis'd, ... */ + CPU_IntDisMeasStart_cnts = CPU_TS_TmrRd(); /* ... get ints dis'd start time. */ + } + CPU_IntDisNestCtr++; +} +#endif + + +/* +********************************************************************************************************* +* CPU_IntDisMeasStop() +* +* Description : Stop interrupts disabled time measurement. +* +* Argument(s) : none. +* +* Return(s) : none. +* +* Caller(s) : CPU_CRITICAL_EXIT(). +* +* This function is an INTERNAL CPU module function & MUST NOT be called by application +* function(s). +* +* Note(s) : (1) (a) The total amount of time interrupts are disabled by system &/or application code +* during critical sections is calculated by the following equations : +* +* (1) When interrupts disabled time measurements are disabled : +* +* +* | CRITICAL | | CRITICAL | +* |<- SECTION ->| |<- SECTION ->| +* | ENTER | | EXIT | +* +* Disable Enable +* Interrupts Interrupts +* +* || || || || +* || || || || +* || | ||<------------------------->|| | || +* || |<->|| | ||<----->| || +* || | | || | || | | || +* | | | | | +* interrupts time interrupts +* disabled interrupts |enabled +* | disabled | +* | (via application) | +* time time +* interrupts interrupts +* disabled ovrhd enabled ovrhd +* +* +* (A) time = [ time - time ] - time +* interrupts [ interrupts interrupts ] total +* disabled [ enabled disabled ] ovrhd +* (via application) +* +* +* (B) time = time + time +* total interrupts interrupts +* ovrhd enabled ovrhd disabled ovrhd +* +* +* where +* +* time time interrupts are disabled between +* interrupts first critical section enter & +* disabled last critical section exit (i.e. +* (via application) minus total overhead time) +* +* time time when interrupts are disabled +* interrupts +* disabled +* +* time time when interrupts are enabled +* interrupts +* enabled +* +* +* time total overhead time to disable/enable +* total interrupts during critical section +* ovrhd enter & exit +* +* time total overhead time to disable interrupts +* interrupts during critical section enter +* disabled ovrhd +* +* time total overhead time to enable interrupts +* interrupts during critical section exit +* enabled ovrhd +* +* +* (2) When interrupts disabled time measurements are enabled : +* +* +* | | | | +* |<----- CRITICAL SECTION ENTER ----->| |<------- CRITICAL SECTION EXIT ------->| +* | | | | +* +* Time Time +* Disable Measurement Measurement Enable +* Interrupts Start Stop Interrupts +* +* || | || || | || +* || | || || | || +* || | | ||<------------------------->|| | | || +* || | | |<----------->|| | ||<------------->| | | || +* || | | | | || | || | | | | || +* | | | | | | | +* interrupts get | time | get interrupts +* disabled start time | interrupts | stop time enabled +* meas | disabled | meas +* time (via application) time +* start meas stop meas +* ovrhd ovrhd +* +* +* (A) time = [ time - time ] - time +* interrupts [ stop start ] total meas +* disabled [ meas meas ] ovrhd +* (via application) +* +* +* (B) time = time + time +* total meas start meas stop meas +* ovrhd ovrhd ovrhd +* +* +* where +* +* time time interrupts are disabled between first +* interrupts critical section enter & last critical +* disabled section exit (i.e. minus measurement +* (via application) overhead time; however, this does NOT +* include any overhead time to disable +* or enable interrupts during critical +* section enter & exit) +* +* time time of disable interrupts start time +* start measurement (in timer counts) +* meas +* +* time time of disable interrupts stop time +* stop measurement (in timer counts) +* meas +* +* +* time total overhead time to start/stop disabled +* total meas interrupts time measurements (in timer +* ovrhd counts) +* +* time total overhead time after getting start +* start meas time until end of start measurement +* ovrhd function (in timer counts) +* +* time total overhead time from beginning of stop +* stop meas measurement function until after getting +* ovrhd stop time (in timer counts) +* +* +* (b) (1) (A) In order to correctly handle unsigned subtraction overflows of start times +* from stop times, CPU timestamp timer count values MUST be returned via +* word-size-configurable 'CPU_TS_TMR' data type. +* +* See also 'cpu_core.h FUNCTION PROTOTYPES CPU_TS_TmrRd() Note #2a'. +* +* (B) Since unsigned subtraction of start times from stop times assumes increasing +* values, timestamp timer count values MUST increase with each time count. +* +* See also 'cpu_core.h FUNCTION PROTOTYPES CPU_TS_TmrRd() Note #2b'. +* +* (2) (A) To expedite & reduce interrupts disabled time measurement overhead; only the +* subtraction of start times from stop times is performed. +* +* (B) The final calculations to subtract the interrupts disabled time measurement +* overhead is performed asynchronously in appropriate API functions. +* +* See also 'CPU_IntDisMeasMaxCalc() Note #1b'. +********************************************************************************************************* +*/ + +#ifdef CPU_CFG_INT_DIS_MEAS_EN +void CPU_IntDisMeasStop (void) +{ + CPU_TS_TMR time_ints_disd_cnts; + + + CPU_IntDisNestCtr--; + if (CPU_IntDisNestCtr == 0u) { /* If ints NO longer dis'd, ... */ + CPU_IntDisMeasStop_cnts = CPU_TS_TmrRd(); /* ... get ints dis'd stop time & ... */ + /* ... calc ints dis'd tot time (see Note #1b2A). */ + time_ints_disd_cnts = CPU_IntDisMeasStop_cnts - + CPU_IntDisMeasStart_cnts; + /* Calc max ints dis'd times. */ + if (CPU_IntDisMeasMaxCur_cnts < time_ints_disd_cnts) { + CPU_IntDisMeasMaxCur_cnts = time_ints_disd_cnts; + } + if (CPU_IntDisMeasMax_cnts < time_ints_disd_cnts) { + CPU_IntDisMeasMax_cnts = time_ints_disd_cnts; + } + } +} +#endif + + +/* +********************************************************************************************************* +* CPU_CntLeadZeros() +* +* Description : Count the number of contiguous, most-significant, leading zero bits in a data value. +* +* Argument(s) : val Data value to count leading zero bits. +* +* Return(s) : Number of contiguous, most-significant, leading zero bits in 'val', if NO error(s). +* +* DEF_INT_CPU_U_MAX_VAL, otherwise. +* +* Caller(s) : CPU_CntTrailZeros(), +* Application. +* +* This function is a CPU module application programming interface (API) function & MAY +* be called by application function(s). +* +* Note(s) : (1) (a) Supports the following data value sizes : +* +* (1) 8-bits +* (2) 16-bits +* (3) 32-bits +* (4) 64-bits +* +* See also 'cpu_def.h CPU WORD CONFIGURATION Note #1'. +* +* (b) (1) For 8-bit values : +* +* b07 b06 b05 b04 b03 b02 b01 b00 # Leading Zeros +* --- --- --- --- --- --- --- --- --------------- +* 1 x x x x x x x 0 +* 0 1 x x x x x x 1 +* 0 0 1 x x x x x 2 +* 0 0 0 1 x x x x 3 +* 0 0 0 0 1 x x x 4 +* 0 0 0 0 0 1 x x 5 +* 0 0 0 0 0 0 1 x 6 +* 0 0 0 0 0 0 0 1 7 +* 0 0 0 0 0 0 0 0 8 +* +* +* (2) For 16-bit values : +* +* b15 b14 b13 ... b04 b03 b02 b01 b00 # Leading Zeros +* --- --- --- --- --- --- --- --- --------------- +* 1 x x x x x x x 0 +* 0 1 x x x x x x 1 +* 0 0 1 x x x x x 2 +* : : : : : : : : : +* : : : : : : : : : +* 0 0 0 1 x x x x 11 +* 0 0 0 0 1 x x x 12 +* 0 0 0 0 0 1 x x 13 +* 0 0 0 0 0 0 1 x 14 +* 0 0 0 0 0 0 0 1 15 +* 0 0 0 0 0 0 0 0 16 +* +* (3) For 32-bit values : +* +* b31 b30 b29 ... b04 b03 b02 b01 b00 # Leading Zeros +* --- --- --- --- --- --- --- --- --------------- +* 1 x x x x x x x 0 +* 0 1 x x x x x x 1 +* 0 0 1 x x x x x 2 +* : : : : : : : : : +* : : : : : : : : : +* 0 0 0 1 x x x x 27 +* 0 0 0 0 1 x x x 28 +* 0 0 0 0 0 1 x x 29 +* 0 0 0 0 0 0 1 x 30 +* 0 0 0 0 0 0 0 1 31 +* 0 0 0 0 0 0 0 0 32 +* +* +* (4) For 64-bit values : +* +* b63 b62 b61 ... b04 b03 b02 b01 b00 # Leading Zeros +* --- --- --- --- --- --- --- --- --------------- +* 1 x x x x x x x 0 +* 0 1 x x x x x x 1 +* 0 0 1 x x x x x 2 +* : : : : : : : : : +* : : : : : : : : : +* 0 0 0 1 x x x x 59 +* 0 0 0 0 1 x x x 60 +* 0 0 0 0 0 1 x x 61 +* 0 0 0 0 0 0 1 x 62 +* 0 0 0 0 0 0 0 1 63 +* 0 0 0 0 0 0 0 0 64 +* +* +* See also 'CPU COUNT LEAD ZEROs LOOKUP TABLE Note #1'. +********************************************************************************************************* +*/ + +#ifndef CPU_CFG_LEAD_ZEROS_ASM_PRESENT +CPU_DATA CPU_CntLeadZeros (CPU_DATA val) +{ + CPU_DATA nbr_lead_zeros; + + +#if (CPU_CFG_DATA_SIZE == CPU_WORD_SIZE_08) + nbr_lead_zeros = CPU_CntLeadZeros08((CPU_INT08U)val); + +#elif (CPU_CFG_DATA_SIZE == CPU_WORD_SIZE_16) + nbr_lead_zeros = CPU_CntLeadZeros16((CPU_INT16U)val); + +#elif (CPU_CFG_DATA_SIZE == CPU_WORD_SIZE_32) + nbr_lead_zeros = CPU_CntLeadZeros32((CPU_INT32U)val); + +#elif (CPU_CFG_DATA_SIZE == CPU_WORD_SIZE_64) + nbr_lead_zeros = CPU_CntLeadZeros64((CPU_INT64U)val); + +#else /* See Note #1a. */ + nbr_lead_zeros = DEF_INT_CPU_U_MAX_VAL; +#endif + + + return (nbr_lead_zeros); +} +#endif + + +/* +********************************************************************************************************* +* CPU_CntLeadZeros08() +* +* Description : Count the number of contiguous, most-significant, leading zero bits in an 8-bit data value. +* +* Argument(s) : val Data value to count leading zero bits. +* +* Return(s) : Number of contiguous, most-significant, leading zero bits in 'val'. +* +* Caller(s) : CPU_CntLeadZeros(), +* CPU_CntTrailZeros08(), +* Application. +* +* This function is a CPU module application programming interface (API) function & MAY be +* called by application function(s). +* +* Note(s) : (1) Supports 8-bit values : +* +* b07 b06 b05 b04 b03 b02 b01 b00 # Leading Zeros +* --- --- --- --- --- --- --- --- --------------- +* 1 x x x x x x x 0 +* 0 1 x x x x x x 1 +* 0 0 1 x x x x x 2 +* 0 0 0 1 x x x x 3 +* 0 0 0 0 1 x x x 4 +* 0 0 0 0 0 1 x x 5 +* 0 0 0 0 0 0 1 x 6 +* 0 0 0 0 0 0 0 1 7 +* 0 0 0 0 0 0 0 0 8 +* +* +* See also 'CPU COUNT LEAD ZEROs LOOKUP TABLE Note #1'. +********************************************************************************************************* +*/ + +#if (CPU_CFG_DATA_SIZE_MAX >= CPU_WORD_SIZE_08) +CPU_DATA CPU_CntLeadZeros08 (CPU_INT08U val) +{ +#if (!((defined(CPU_CFG_LEAD_ZEROS_ASM_PRESENT)) && \ + (CPU_CFG_DATA_SIZE >= CPU_WORD_SIZE_08))) + CPU_DATA ix; +#endif + CPU_DATA nbr_lead_zeros; + + /* ---------- ASM-OPTIMIZED ----------- */ +#if ((defined(CPU_CFG_LEAD_ZEROS_ASM_PRESENT)) && \ + (CPU_CFG_DATA_SIZE >= CPU_WORD_SIZE_08)) + nbr_lead_zeros = CPU_CntLeadZeros((CPU_DATA)val); + nbr_lead_zeros -= (CPU_CFG_DATA_SIZE - CPU_WORD_SIZE_08) * DEF_OCTET_NBR_BITS; + + +#else /* ----------- C-OPTIMIZED ------------ */ + /* Chk bits [07:00] : */ + /* .. Nbr lead zeros = .. */ + ix = (CPU_DATA)(val); /* .. lookup tbl ix = 'val' >> 0 bits */ + nbr_lead_zeros = (CPU_DATA)(CPU_CntLeadZerosTbl[ix]); /* .. plus nbr msb lead zeros = 0 bits.*/ +#endif + + + return (nbr_lead_zeros); +} +#endif + + +/* +********************************************************************************************************* +* CPU_CntLeadZeros16() +* +* Description : Count the number of contiguous, most-significant, leading zero bits in a 16-bit data value. +* +* Argument(s) : val Data value to count leading zero bits. +* +* Return(s) : Number of contiguous, most-significant, leading zero bits in 'val'. +* +* Caller(s) : CPU_CntLeadZeros(), +* CPU_CntTrailZeros16(), +* Application. +* +* This function is a CPU module application programming interface (API) function & MAY be +* called by application function(s). +* +* Note(s) : (1) Supports 16-bit values : +* +* b15 b14 b13 ... b04 b03 b02 b01 b00 # Leading Zeros +* --- --- --- --- --- --- --- --- --------------- +* 1 x x x x x x x 0 +* 0 1 x x x x x x 1 +* 0 0 1 x x x x x 2 +* : : : : : : : : : +* : : : : : : : : : +* 0 0 0 1 x x x x 11 +* 0 0 0 0 1 x x x 12 +* 0 0 0 0 0 1 x x 13 +* 0 0 0 0 0 0 1 x 14 +* 0 0 0 0 0 0 0 1 15 +* 0 0 0 0 0 0 0 0 16 +* +* +* See also 'CPU COUNT LEAD ZEROs LOOKUP TABLE Note #1'. +********************************************************************************************************* +*/ + +#if (CPU_CFG_DATA_SIZE_MAX >= CPU_WORD_SIZE_16) +CPU_DATA CPU_CntLeadZeros16 (CPU_INT16U val) +{ +#if (!((defined(CPU_CFG_LEAD_ZEROS_ASM_PRESENT)) && \ + (CPU_CFG_DATA_SIZE >= CPU_WORD_SIZE_16))) + CPU_DATA ix; +#endif + CPU_DATA nbr_lead_zeros; + + /* ---------- ASM-OPTIMIZED ----------- */ +#if ((defined(CPU_CFG_LEAD_ZEROS_ASM_PRESENT)) && \ + (CPU_CFG_DATA_SIZE >= CPU_WORD_SIZE_16)) + nbr_lead_zeros = CPU_CntLeadZeros((CPU_DATA)val); + nbr_lead_zeros -= (CPU_CFG_DATA_SIZE - CPU_WORD_SIZE_16) * DEF_OCTET_NBR_BITS; + + +#else /* ----------- C-OPTIMIZED ------------ */ + if (val > 0x00FFu) { /* Chk bits [15:08] : */ + /* .. Nbr lead zeros = .. */ + ix = (CPU_DATA)((CPU_DATA)val >> 8u); /* .. lookup tbl ix = 'val' >> 8 bits */ + nbr_lead_zeros = (CPU_DATA)(CPU_CntLeadZerosTbl[ix]); /* .. plus nbr msb lead zeros = 0 bits.*/ + + } else { /* Chk bits [07:00] : */ + /* .. Nbr lead zeros = .. */ + ix = (CPU_DATA)(val); /* .. lookup tbl ix = 'val' >> 0 bits */ + nbr_lead_zeros = (CPU_DATA)((CPU_DATA)CPU_CntLeadZerosTbl[ix] + 8u); /* .. plus nbr msb lead zeros = 8 bits.*/ + } +#endif + + + return (nbr_lead_zeros); +} +#endif + + +/* +********************************************************************************************************* +* CPU_CntLeadZeros32() +* +* Description : Count the number of contiguous, most-significant, leading zero bits in a 32-bit data value. +* +* Argument(s) : val Data value to count leading zero bits. +* +* Return(s) : Number of contiguous, most-significant, leading zero bits in 'val'. +* +* Caller(s) : CPU_CntLeadZeros(), +* CPU_CntTrailZeros32(), +* Application. +* +* This function is a CPU module application programming interface (API) function & MAY be +* called by application function(s). +* +* Note(s) : (1) Supports 32-bit values : +* +* b31 b30 b29 ... b04 b03 b02 b01 b00 # Leading Zeros +* --- --- --- --- --- --- --- --- --------------- +* 1 x x x x x x x 0 +* 0 1 x x x x x x 1 +* 0 0 1 x x x x x 2 +* : : : : : : : : : +* : : : : : : : : : +* 0 0 0 1 x x x x 27 +* 0 0 0 0 1 x x x 28 +* 0 0 0 0 0 1 x x 29 +* 0 0 0 0 0 0 1 x 30 +* 0 0 0 0 0 0 0 1 31 +* 0 0 0 0 0 0 0 0 32 +* +* +* See also 'CPU COUNT LEAD ZEROs LOOKUP TABLE Note #1'. +********************************************************************************************************* +*/ + +#if (CPU_CFG_DATA_SIZE_MAX >= CPU_WORD_SIZE_32) +CPU_DATA CPU_CntLeadZeros32 (CPU_INT32U val) +{ +#if (!((defined(CPU_CFG_LEAD_ZEROS_ASM_PRESENT)) && \ + (CPU_CFG_DATA_SIZE >= CPU_WORD_SIZE_32))) + CPU_DATA ix; +#endif + CPU_DATA nbr_lead_zeros; + + /* ---------- ASM-OPTIMIZED ----------- */ +#if ((defined(CPU_CFG_LEAD_ZEROS_ASM_PRESENT)) && \ + (CPU_CFG_DATA_SIZE >= CPU_WORD_SIZE_32)) + nbr_lead_zeros = CPU_CntLeadZeros((CPU_DATA)val); + nbr_lead_zeros -= (CPU_CFG_DATA_SIZE - CPU_WORD_SIZE_32) * DEF_OCTET_NBR_BITS; + + +#else /* ----------- C-OPTIMIZED ------------ */ + if (val > 0x0000FFFFu) { + if (val > 0x00FFFFFFu) { /* Chk bits [31:24] : */ + /* .. Nbr lead zeros = .. */ + ix = (CPU_DATA)((CPU_DATA)(val >> 24u)); /* .. lookup tbl ix = 'val' >> 24 bits */ + nbr_lead_zeros = (CPU_DATA)(CPU_CntLeadZerosTbl[ix]); /* .. plus nbr msb lead zeros = 0 bits.*/ + + } else { /* Chk bits [23:16] : */ + /* .. Nbr lead zeros = .. */ + ix = (CPU_DATA)((CPU_DATA)(val >> 16u)); /* .. lookup tbl ix = 'val' >> 16 bits */ + nbr_lead_zeros = (CPU_DATA)((CPU_DATA)CPU_CntLeadZerosTbl[ix] + 8u);/* .. plus nbr msb lead zeros = 8 bits.*/ + } + + } else { + if (val > 0x000000FFu) { /* Chk bits [15:08] : */ + /* .. Nbr lead zeros = .. */ + ix = (CPU_DATA)((CPU_DATA)(val >> 8u)); /* .. lookup tbl ix = 'val' >> 8 bits */ + nbr_lead_zeros = (CPU_DATA)((CPU_DATA)CPU_CntLeadZerosTbl[ix] + 16u);/* .. plus nbr msb lead zeros = 16 bits.*/ + + } else { /* Chk bits [07:00] : */ + /* .. Nbr lead zeros = .. */ + ix = (CPU_DATA)((CPU_DATA)(val >> 0u)); /* .. lookup tbl ix = 'val' >> 0 bits */ + nbr_lead_zeros = (CPU_DATA)((CPU_DATA)CPU_CntLeadZerosTbl[ix] + 24u);/* .. plus nbr msb lead zeros = 24 bits.*/ + } + } +#endif + + + return (nbr_lead_zeros); +} +#endif + + +/* +********************************************************************************************************* +* CPU_CntLeadZeros64() +* +* Description : Count the number of contiguous, most-significant, leading zero bits in a 64-bit data value. +* +* Argument(s) : val Data value to count leading zero bits. +* +* Return(s) : Number of contiguous, most-significant, leading zero bits in 'val'. +* +* Caller(s) : CPU_CntLeadZeros(), +* CPU_CntTrailZeros64(), +* Application. +* +* This function is a CPU module application programming interface (API) function & MAY be +* called by application function(s). +* +* Note(s) : (1) Supports 64-bit values : +* +* b63 b62 b61 ... b04 b03 b02 b01 b00 # Leading Zeros +* --- --- --- --- --- --- --- --- --------------- +* 1 x x x x x x x 0 +* 0 1 x x x x x x 1 +* 0 0 1 x x x x x 2 +* : : : : : : : : : +* : : : : : : : : : +* 0 0 0 1 x x x x 59 +* 0 0 0 0 1 x x x 60 +* 0 0 0 0 0 1 x x 61 +* 0 0 0 0 0 0 1 x 62 +* 0 0 0 0 0 0 0 1 63 +* 0 0 0 0 0 0 0 0 64 +* +* +* See also 'CPU COUNT LEAD ZEROs LOOKUP TABLE Note #1'. +********************************************************************************************************* +*/ + +#if (CPU_CFG_DATA_SIZE_MAX >= CPU_WORD_SIZE_64) +CPU_DATA CPU_CntLeadZeros64 (CPU_INT64U val) +{ +#if (!((defined(CPU_CFG_LEAD_ZEROS_ASM_PRESENT)) && \ + (CPU_CFG_DATA_SIZE >= CPU_WORD_SIZE_64))) + CPU_DATA ix; +#endif + CPU_DATA nbr_lead_zeros; + + /* ---------- ASM-OPTIMIZED ----------- */ +#if ((defined(CPU_CFG_LEAD_ZEROS_ASM_PRESENT)) && \ + (CPU_CFG_DATA_SIZE >= CPU_WORD_SIZE_64)) + nbr_lead_zeros = CPU_CntLeadZeros((CPU_DATA)val); + nbr_lead_zeros -= (CPU_CFG_DATA_SIZE - CPU_WORD_SIZE_64) * DEF_OCTET_NBR_BITS; + + +#else /* ----------- C-OPTIMIZED ------------ */ + if (val > 0x00000000FFFFFFFFu) { + if (val > 0x0000FFFFFFFFFFFFu) { + if (val > 0x00FFFFFFFFFFFFFFu) { /* Chk bits [63:56] : */ + /* .. Nbr lead zeros = .. */ + ix = (CPU_DATA)((CPU_INT64U)val >> 56u); /* .. lookup tbl ix = 'val' >> 56 bits */ + nbr_lead_zeros = (CPU_DATA)(CPU_CntLeadZerosTbl[ix]); /* .. plus nbr msb lead zeros = 0 bits.*/ + + } else { /* Chk bits [55:48] : */ + /* .. Nbr lead zeros = .. */ + ix = (CPU_DATA)((CPU_INT64U)val >> 48u); /* .. lookup tbl ix = 'val' >> 48 bits */ + nbr_lead_zeros = (CPU_DATA)((CPU_INT64U)CPU_CntLeadZerosTbl[ix] + 8u);/* .. plus nbr msb lead zeros = 8 bits.*/ + } + + } else { + if (val > 0x000000FFFFFFFFFFu) { /* Chk bits [47:40] : */ + /* .. Nbr lead zeros = .. */ + ix = (CPU_DATA)((CPU_INT64U)val >> 40u); /* .. lookup tbl ix = 'val' >> 40 bits */ + nbr_lead_zeros = (CPU_DATA)((CPU_INT64U)CPU_CntLeadZerosTbl[ix] + 16u);/* .. plus nbr msb lead zeros = 16 bits.*/ + + } else { /* Chk bits [39:32] : */ + /* .. Nbr lead zeros = .. */ + ix = (CPU_DATA)((CPU_INT64U)val >> 32u); /* .. lookup tbl ix = 'val' >> 32 bits */ + nbr_lead_zeros = (CPU_DATA)((CPU_INT64U)CPU_CntLeadZerosTbl[ix] + 24u);/* .. plus nbr msb lead zeros = 24 bits.*/ + } + } + + } else { + if (val > 0x000000000000FFFFu) { + if (val > 0x0000000000FFFFFFu) { /* Chk bits [31:24] : */ + /* .. Nbr lead zeros = .. */ + ix = (CPU_DATA)((CPU_INT64U)val >> 24u); /* .. lookup tbl ix = 'val' >> 24 bits */ + nbr_lead_zeros = (CPU_DATA)((CPU_INT64U)CPU_CntLeadZerosTbl[ix] + 32u);/* .. plus nbr msb lead zeros = 32 bits.*/ + + } else { /* Chk bits [23:16] : */ + /* .. Nbr lead zeros = .. */ + ix = (CPU_DATA)((CPU_INT64U)val >> 16u); /* .. lookup tbl ix = 'val' >> 16 bits */ + nbr_lead_zeros = (CPU_DATA)((CPU_INT64U)CPU_CntLeadZerosTbl[ix] + 40u);/* .. plus nbr msb lead zeros = 40 bits.*/ + } + + } else { + if (val > 0x00000000000000FFu) { /* Chk bits [15:08] : */ + /* .. Nbr lead zeros = .. */ + ix = (CPU_DATA)((CPU_INT64U)val >> 8u); /* .. lookup tbl ix = 'val' >> 8 bits */ + nbr_lead_zeros = (CPU_DATA)((CPU_INT64U)CPU_CntLeadZerosTbl[ix] + 48u);/* .. plus nbr msb lead zeros = 48 bits.*/ + + } else { /* Chk bits [07:00] : */ + /* .. Nbr lead zeros = .. */ + ix = (CPU_DATA)(val); /* .. lookup tbl ix = 'val' >> 0 bits */ + nbr_lead_zeros = (CPU_DATA)((CPU_INT64U)CPU_CntLeadZerosTbl[ix] + 56u);/* .. plus nbr msb lead zeros = 56 bits.*/ + } + } + } +#endif + + + return (nbr_lead_zeros); +} +#endif + + +/* +********************************************************************************************************* +* CPU_CntTrailZeros() +* +* Description : Count the number of contiguous, least-significant, trailing zero bits in a data value. +* +* Argument(s) : val Data value to count trailing zero bits. +* +* Return(s) : Number of contiguous, least-significant, trailing zero bits in 'val'. +* +* Caller(s) : Application. +* +* This function is a CPU module application programming interface (API) function & MAY +* be called by application function(s). +* +* Note(s) : (1) (a) Supports the following data value sizes : +* +* (1) 8-bits +* (2) 16-bits +* (3) 32-bits +* (4) 64-bits +* +* See also 'cpu_def.h CPU WORD CONFIGURATION Note #1'. +* +* (b) (1) For 8-bit values : +* +* b07 b06 b05 b04 b03 b02 b01 b00 # Trailing Zeros +* --- --- --- --- --- --- --- --- ---------------- +* x x x x x x x 1 0 +* x x x x x x 1 0 1 +* x x x x x 1 0 0 2 +* x x x x 1 0 0 0 3 +* x x x 1 0 0 0 0 4 +* x x 1 0 0 0 0 0 5 +* x 1 0 0 0 0 0 0 6 +* 1 0 0 0 0 0 0 0 7 +* 0 0 0 0 0 0 0 0 8 +* +* +* (2) For 16-bit values : +* +* b15 b14 b13 b12 b11 ... b02 b01 b00 # Trailing Zeros +* --- --- --- --- --- --- --- --- ---------------- +* x x x x x x x 1 0 +* x x x x x x 1 0 1 +* x x x x x 1 0 0 2 +* : : : : : : : : : +* : : : : : : : : : +* x x x x 1 0 0 0 11 +* x x x 1 0 0 0 0 12 +* x x 1 0 0 0 0 0 13 +* x 1 0 0 0 0 0 0 14 +* 1 0 0 0 0 0 0 0 15 +* 0 0 0 0 0 0 0 0 16 +* +* +* (3) For 32-bit values : +* +* b31 b30 b29 b28 b27 ... b02 b01 b00 # Trailing Zeros +* --- --- --- --- --- --- --- --- ---------------- +* x x x x x x x 1 0 +* x x x x x x 1 0 1 +* x x x x x 1 0 0 2 +* : : : : : : : : : +* : : : : : : : : : +* x x x x 1 0 0 0 27 +* x x x 1 0 0 0 0 28 +* x x 1 0 0 0 0 0 29 +* x 1 0 0 0 0 0 0 30 +* 1 0 0 0 0 0 0 0 31 +* 0 0 0 0 0 0 0 0 32 +* +* +* (4) For 64-bit values : +* +* b63 b62 b61 b60 b59 ... b02 b01 b00 # Trailing Zeros +* --- --- --- --- --- --- --- --- ---------------- +* x x x x x x x 1 0 +* x x x x x x 1 0 1 +* x x x x x 1 0 0 2 +* : : : : : : : : : +* : : : : : : : : : +* x x x x 1 0 0 0 59 +* x x x 1 0 0 0 0 60 +* x x 1 0 0 0 0 0 61 +* x 1 0 0 0 0 0 0 62 +* 1 0 0 0 0 0 0 0 63 +* 0 0 0 0 0 0 0 0 64 +* +* (2) For non-zero values, the returned number of contiguous, least-significant, trailing +* zero bits is also equivalent to the bit position of the least-significant set bit. +* +* (3) 'val' SHOULD be validated for non-'0' PRIOR to all other counting zero calculations : +* +* (a) CPU_CntTrailZeros()'s final conditional statement calculates 'val's number of +* trailing zeros based on its return data size, 'CPU_CFG_DATA_SIZE', & 'val's +* calculated number of lead zeros ONLY if the initial 'val' is non-'0' : +* +* if (val != 0u) { +* nbr_trail_zeros = ((CPU_CFG_DATA_SIZE * DEF_OCTET_NBR_BITS) - 1u) - nbr_lead_zeros; +* } else { +* nbr_trail_zeros = nbr_lead_zeros; +* } +* +* Therefore, initially validating all non-'0' values avoids having to conditionally +* execute the final 'if' statement. +********************************************************************************************************* +*/ + +#ifndef CPU_CFG_TRAIL_ZEROS_ASM_PRESENT +CPU_DATA CPU_CntTrailZeros (CPU_DATA val) +{ + CPU_DATA val_bit_mask; + CPU_DATA nbr_lead_zeros; + CPU_DATA nbr_trail_zeros; + + + if (val == 0u) { /* Rtn ALL val bits as zero'd (see Note #3). */ + return (CPU_CFG_DATA_SIZE * DEF_OCTET_NBR_BITS); + } + + + val_bit_mask = val & ((CPU_DATA)~val + 1u); /* Zero/clr all bits EXCEPT least-sig set bit. */ + nbr_lead_zeros = CPU_CntLeadZeros(val_bit_mask); /* Cnt nbr lead 0s. */ + /* Calc nbr trail 0s = (nbr val bits - 1) - nbr lead 0s.*/ + nbr_trail_zeros = ((CPU_CFG_DATA_SIZE * DEF_OCTET_NBR_BITS) - 1u) - nbr_lead_zeros; + + + return (nbr_trail_zeros); +} +#endif + + +/* +********************************************************************************************************* +* CPU_CntTrailZeros08() +* +* Description : Count the number of contiguous, least-significant, trailing zero bits in an 8-bit data value. +* +* Argument(s) : val Data value to count trailing zero bits. +* +* Return(s) : Number of contiguous, least-significant, trailing zero bits in 'val'. +* +* Caller(s) : Application. +* +* This function is a CPU module application programming interface (API) function & MAY be +* called by application function(s). +* +* Note(s) : (1) Supports 8-bit values : +* +* b07 b06 b05 b04 b03 b02 b01 b00 # Trailing Zeros +* --- --- --- --- --- --- --- --- ---------------- +* x x x x x x x 1 0 +* x x x x x x 1 0 1 +* x x x x x 1 0 0 2 +* x x x x 1 0 0 0 3 +* x x x 1 0 0 0 0 4 +* x x 1 0 0 0 0 0 5 +* x 1 0 0 0 0 0 0 6 +* 1 0 0 0 0 0 0 0 7 +* 0 0 0 0 0 0 0 0 8 +* +* +* (2) For non-zero values, the returned number of contiguous, least-significant, trailing +* zero bits is also equivalent to the bit position of the least-significant set bit. +* +* (3) 'val' SHOULD be validated for non-'0' PRIOR to all other counting zero calculations : +* +* (a) For assembly-optimized implementations, CPU_CntTrailZeros() returns 'val's +* number of trailing zeros via CPU's native data size, 'CPU_CFG_DATA_SIZE'. +* If the returned number of zeros exceeds CPU_CntTrailZeros08()'s 8-bit return +* data size, then the returned number of zeros must be offset by the difference +* between CPU_CntTrailZeros()'s & CPU_CntTrailZeros08()'s return data size : +* +* nbr_trail_zeros = CPU_CntTrailZeros((CPU_DATA)val); +* if (nbr_trail_zeros > (CPU_WORD_SIZE_08 * DEF_OCTET_NBR_BITS)) { +* nbr_trail_zeros -= (CPU_CFG_DATA_SIZE - CPU_WORD_SIZE_08) * DEF_OCTET_NBR_BITS; +* } +* +* However, this ONLY occurs for an initial 'val' of '0' since all non-'0' 8-bit +* values would return a number of trailing zeros less than or equal to 8 bits. +* +* Therefore, initially validating all non-'0' values prior to calling assembly- +* optimized CPU_CntTrailZeros() avoids having to offset the number of returned +* trailing zeros by the difference in CPU data size and 8-bit data value bits. +* +* (b) For CPU_CntTrailZeros08()'s C implementation, the final conditional statement +* calculates 'val's number of trailing zeros based on CPU_CntTrailZeros08()'s +* 8-bit return data size & 'val's calculated number of lead zeros ONLY if the +* initial 'val' is non-'0' : +* +* if (val != 0u) { +* nbr_trail_zeros = ((CPU_WORD_SIZE_08 * DEF_OCTET_NBR_BITS) - 1u) - nbr_lead_zeros; +* } else { +* nbr_trail_zeros = nbr_lead_zeros; +* } +* +* Therefore, initially validating all non-'0' values avoids having to conditionally +* execute the final 'if' statement. +********************************************************************************************************* +*/ + +#if (CPU_CFG_DATA_SIZE_MAX >= CPU_WORD_SIZE_08) +CPU_DATA CPU_CntTrailZeros08 (CPU_INT08U val) +{ +#if (!((defined(CPU_CFG_TRAIL_ZEROS_ASM_PRESENT)) && \ + (CPU_CFG_DATA_SIZE >= CPU_WORD_SIZE_08))) + CPU_INT08U val_bit_mask; + CPU_DATA nbr_lead_zeros; +#endif + CPU_DATA nbr_trail_zeros; + + + if (val == 0u) { /* Rtn ALL val bits as zero'd (see Note #3). */ + return (CPU_WORD_SIZE_08 * DEF_OCTET_NBR_BITS); + } + + /* ------------------ ASM-OPTIMIZED ------------------- */ +#if ((defined(CPU_CFG_TRAIL_ZEROS_ASM_PRESENT)) && \ + (CPU_CFG_DATA_SIZE >= CPU_WORD_SIZE_08)) + nbr_trail_zeros = CPU_CntTrailZeros((CPU_DATA)val); + +#else /* ------------------- C-OPTIMIZED -------------------- */ + val_bit_mask = val & ((CPU_INT08U)~val + 1u); /* Zero/clr all bits EXCEPT least-sig set bit. */ + nbr_lead_zeros = CPU_CntLeadZeros08(val_bit_mask); /* Cnt nbr lead 0s. */ + /* Calc nbr trail 0s = (nbr val bits - 1) - nbr lead 0s.*/ + nbr_trail_zeros = ((CPU_WORD_SIZE_08 * DEF_OCTET_NBR_BITS) - 1u) - nbr_lead_zeros; +#endif + + + return (nbr_trail_zeros); +} +#endif + + +/* +********************************************************************************************************* +* CPU_CntTrailZeros16() +* +* Description : Count the number of contiguous, least-significant, trailing zero bits in a 16-bit data value. +* +* Argument(s) : val Data value to count trailing zero bits. +* +* Return(s) : Number of contiguous, least-significant, trailing zero bits in 'val'. +* +* Caller(s) : Application. +* +* This function is a CPU module application programming interface (API) function & MAY be +* called by application function(s). +* +* Note(s) : (1) Supports 16-bit values : +* +* b15 b14 b13 b12 b11 ... b02 b01 b00 # Trailing Zeros +* --- --- --- --- --- --- --- --- ---------------- +* x x x x x x x 1 0 +* x x x x x x 1 0 1 +* x x x x x 1 0 0 2 +* : : : : : : : : : +* : : : : : : : : : +* x x x x 1 0 0 0 11 +* x x x 1 0 0 0 0 12 +* x x 1 0 0 0 0 0 13 +* x 1 0 0 0 0 0 0 14 +* 1 0 0 0 0 0 0 0 15 +* 0 0 0 0 0 0 0 0 16 +* +* +* (2) For non-zero values, the returned number of contiguous, least-significant, trailing +* zero bits is also equivalent to the bit position of the least-significant set bit. +* +* (3) 'val' SHOULD be validated for non-'0' PRIOR to all other counting zero calculations : +* +* (a) For assembly-optimized implementations, CPU_CntTrailZeros() returns 'val's +* number of trailing zeros via CPU's native data size, 'CPU_CFG_DATA_SIZE'. +* If the returned number of zeros exceeds CPU_CntTrailZeros16()'s 16-bit return +* data size, then the returned number of zeros must be offset by the difference +* between CPU_CntTrailZeros()'s & CPU_CntTrailZeros16()'s return data size : +* +* nbr_trail_zeros = CPU_CntTrailZeros((CPU_DATA)val); +* if (nbr_trail_zeros > (CPU_WORD_SIZE_16 * DEF_OCTET_NBR_BITS)) { +* nbr_trail_zeros -= (CPU_CFG_DATA_SIZE - CPU_WORD_SIZE_16) * DEF_OCTET_NBR_BITS; +* } +* +* However, this ONLY occurs for an initial 'val' of '0' since all non-'0' 16-bit +* values would return a number of trailing zeros less than or equal to 16 bits. +* +* Therefore, initially validating all non-'0' values prior to calling assembly- +* optimized CPU_CntTrailZeros() avoids having to offset the number of returned +* trailing zeros by the difference in CPU data size and 16-bit data value bits. +* +* (b) For CPU_CntTrailZeros16()'s C implementation, the final conditional statement +* calculates 'val's number of trailing zeros based on CPU_CntTrailZeros16()'s +* 16-bit return data size & 'val's calculated number of lead zeros ONLY if the +* initial 'val' is non-'0' : +* +* if (val != 0u) { +* nbr_trail_zeros = ((CPU_WORD_SIZE_16 * DEF_OCTET_NBR_BITS) - 1u) - nbr_lead_zeros; +* } else { +* nbr_trail_zeros = nbr_lead_zeros; +* } +* +* Therefore, initially validating all non-'0' values avoids having to conditionally +* execute the final 'if' statement. +********************************************************************************************************* +*/ + +#if (CPU_CFG_DATA_SIZE_MAX >= CPU_WORD_SIZE_16) +CPU_DATA CPU_CntTrailZeros16 (CPU_INT16U val) +{ +#if (!((defined(CPU_CFG_TRAIL_ZEROS_ASM_PRESENT)) && \ + (CPU_CFG_DATA_SIZE >= CPU_WORD_SIZE_16))) + CPU_INT16U val_bit_mask; + CPU_DATA nbr_lead_zeros; +#endif + CPU_DATA nbr_trail_zeros; + + + if (val == 0u) { /* Rtn ALL val bits as zero'd (see Note #3). */ + return (CPU_WORD_SIZE_16 * DEF_OCTET_NBR_BITS); + } + + /* ------------------ ASM-OPTIMIZED ------------------- */ +#if ((defined(CPU_CFG_TRAIL_ZEROS_ASM_PRESENT)) && \ + (CPU_CFG_DATA_SIZE >= CPU_WORD_SIZE_16)) + nbr_trail_zeros = CPU_CntTrailZeros((CPU_DATA)val); + +#else /* ------------------- C-OPTIMIZED -------------------- */ + val_bit_mask = val & ((CPU_INT16U)~val + 1u); /* Zero/clr all bits EXCEPT least-sig set bit. */ + nbr_lead_zeros = CPU_CntLeadZeros16(val_bit_mask); /* Cnt nbr lead 0s. */ + /* Calc nbr trail 0s = (nbr val bits - 1) - nbr lead 0s.*/ + nbr_trail_zeros = ((CPU_WORD_SIZE_16 * DEF_OCTET_NBR_BITS) - 1u) - nbr_lead_zeros; +#endif + + + return (nbr_trail_zeros); +} +#endif + + +/* +********************************************************************************************************* +* CPU_CntTrailZeros32() +* +* Description : Count the number of contiguous, least-significant, trailing zero bits in a 32-bit data value. +* +* Argument(s) : val Data value to count trailing zero bits. +* +* Return(s) : Number of contiguous, least-significant, trailing zero bits in 'val'. +* +* Caller(s) : Application. +* +* This function is a CPU module application programming interface (API) function & MAY be +* called by application function(s). +* +* Note(s) : (1) Supports 32-bit values : +* +* b31 b30 b29 b28 b27 ... b02 b01 b00 # Trailing Zeros +* --- --- --- --- --- --- --- --- ---------------- +* x x x x x x x 1 0 +* x x x x x x 1 0 1 +* x x x x x 1 0 0 2 +* : : : : : : : : : +* : : : : : : : : : +* x x x x 1 0 0 0 27 +* x x x 1 0 0 0 0 28 +* x x 1 0 0 0 0 0 29 +* x 1 0 0 0 0 0 0 30 +* 1 0 0 0 0 0 0 0 31 +* 0 0 0 0 0 0 0 0 32 +* +* +* (2) For non-zero values, the returned number of contiguous, least-significant, trailing +* zero bits is also equivalent to the bit position of the least-significant set bit. +* +* (3) 'val' SHOULD be validated for non-'0' PRIOR to all other counting zero calculations : +* +* (a) For assembly-optimized implementations, CPU_CntTrailZeros() returns 'val's +* number of trailing zeros via CPU's native data size, 'CPU_CFG_DATA_SIZE'. +* If the returned number of zeros exceeds CPU_CntTrailZeros32()'s 32-bit return +* data size, then the returned number of zeros must be offset by the difference +* between CPU_CntTrailZeros()'s & CPU_CntTrailZeros32()'s return data size : +* +* nbr_trail_zeros = CPU_CntTrailZeros((CPU_DATA)val); +* if (nbr_trail_zeros > (CPU_WORD_SIZE_32 * DEF_OCTET_NBR_BITS)) { +* nbr_trail_zeros -= (CPU_CFG_DATA_SIZE - CPU_WORD_SIZE_32) * DEF_OCTET_NBR_BITS; +* } +* +* However, this ONLY occurs for an initial 'val' of '0' since all non-'0' 32-bit +* values would return a number of trailing zeros less than or equal to 32 bits. +* +* Therefore, initially validating all non-'0' values prior to calling assembly- +* optimized CPU_CntTrailZeros() avoids having to offset the number of returned +* trailing zeros by the difference in CPU data size and 32-bit data value bits. +* +* (b) For CPU_CntTrailZeros32()'s C implementation, the final conditional statement +* calculates 'val's number of trailing zeros based on CPU_CntTrailZeros32()'s +* 32-bit return data size & 'val's calculated number of lead zeros ONLY if the +* initial 'val' is non-'0' : +* +* if (val != 0u) { +* nbr_trail_zeros = ((CPU_WORD_SIZE_32 * DEF_OCTET_NBR_BITS) - 1u) - nbr_lead_zeros; +* } else { +* nbr_trail_zeros = nbr_lead_zeros; +* } +* +* Therefore, initially validating all non-'0' values avoids having to conditionally +* execute the final 'if' statement. +********************************************************************************************************* +*/ + +#if (CPU_CFG_DATA_SIZE_MAX >= CPU_WORD_SIZE_32) +CPU_DATA CPU_CntTrailZeros32 (CPU_INT32U val) +{ +#if (!((defined(CPU_CFG_TRAIL_ZEROS_ASM_PRESENT)) && \ + (CPU_CFG_DATA_SIZE >= CPU_WORD_SIZE_32))) + CPU_INT32U val_bit_mask; + CPU_DATA nbr_lead_zeros; +#endif + CPU_DATA nbr_trail_zeros; + + + if (val == 0u) { /* Rtn ALL val bits as zero'd (see Note #3). */ + return (CPU_WORD_SIZE_32 * DEF_OCTET_NBR_BITS); + } + + /* ------------------ ASM-OPTIMIZED ------------------- */ +#if ((defined(CPU_CFG_TRAIL_ZEROS_ASM_PRESENT)) && \ + (CPU_CFG_DATA_SIZE >= CPU_WORD_SIZE_32)) + nbr_trail_zeros = CPU_CntTrailZeros((CPU_DATA)val); + +#else /* ------------------- C-OPTIMIZED -------------------- */ + val_bit_mask = val & ((CPU_INT32U)~val + 1u); /* Zero/clr all bits EXCEPT least-sig set bit. */ + nbr_lead_zeros = CPU_CntLeadZeros32(val_bit_mask); /* Cnt nbr lead 0s. */ + /* Calc nbr trail 0s = (nbr val bits - 1) - nbr lead 0s.*/ + nbr_trail_zeros = ((CPU_WORD_SIZE_32 * DEF_OCTET_NBR_BITS) - 1u) - nbr_lead_zeros; +#endif + + + return (nbr_trail_zeros); +} +#endif + + +/* +********************************************************************************************************* +* CPU_CntTrailZeros64() +* +* Description : Count the number of contiguous, least-significant, trailing zero bits in a 64-bit data value. +* +* Argument(s) : val Data value to count trailing zero bits. +* +* Return(s) : Number of contiguous, least-significant, trailing zero bits in 'val'. +* +* Caller(s) : Application. +* +* This function is a CPU module application programming interface (API) function & MAY be +* called by application function(s). +* +* Note(s) : (1) Supports 64-bit values : +* +* b63 b62 b61 b60 b59 ... b02 b01 b00 # Trailing Zeros +* --- --- --- --- --- --- --- --- ---------------- +* x x x x x x x 1 0 +* x x x x x x 1 0 1 +* x x x x x 1 0 0 2 +* : : : : : : : : : +* : : : : : : : : : +* x x x x 1 0 0 0 59 +* x x x 1 0 0 0 0 60 +* x x 1 0 0 0 0 0 61 +* x 1 0 0 0 0 0 0 62 +* 1 0 0 0 0 0 0 0 63 +* 0 0 0 0 0 0 0 0 64 +* +* +* (2) For non-zero values, the returned number of contiguous, least-significant, trailing +* zero bits is also equivalent to the bit position of the least-significant set bit. +* +* (3) 'val' SHOULD be validated for non-'0' PRIOR to all other counting zero calculations : +* +* (a) For assembly-optimized implementations, CPU_CntTrailZeros() returns 'val's +* number of trailing zeros via CPU's native data size, 'CPU_CFG_DATA_SIZE'. +* If the returned number of zeros exceeds CPU_CntTrailZeros64()'s 64-bit return +* data size, then the returned number of zeros must be offset by the difference +* between CPU_CntTrailZeros()'s & CPU_CntTrailZeros64()'s return data size : +* +* nbr_trail_zeros = CPU_CntTrailZeros((CPU_DATA)val); +* if (nbr_trail_zeros > (CPU_WORD_SIZE_64 * DEF_OCTET_NBR_BITS)) { +* nbr_trail_zeros -= (CPU_CFG_DATA_SIZE - CPU_WORD_SIZE_64) * DEF_OCTET_NBR_BITS; +* } +* +* However, this ONLY occurs for an initial 'val' of '0' since all non-'0' 64-bit +* values would return a number of trailing zeros less than or equal to 64 bits. +* +* Therefore, initially validating all non-'0' values prior to calling assembly- +* optimized CPU_CntTrailZeros() avoids having to offset the number of returned +* trailing zeros by the difference in CPU data size and 64-bit data value bits. +* +* (b) For CPU_CntTrailZeros64()'s C implementation, the final conditional statement +* calculates 'val's number of trailing zeros based on CPU_CntTrailZeros64()'s +* 64-bit return data size & 'val's calculated number of lead zeros ONLY if the +* initial 'val' is non-'0' : +* +* if (val != 0u) { +* nbr_trail_zeros = ((CPU_WORD_SIZE_64 * DEF_OCTET_NBR_BITS) - 1u) - nbr_lead_zeros; +* } else { +* nbr_trail_zeros = nbr_lead_zeros; +* } +* +* Therefore, initially validating all non-'0' values avoids having to conditionally +* execute the final 'if' statement. +********************************************************************************************************* +*/ + +#if (CPU_CFG_DATA_SIZE_MAX >= CPU_WORD_SIZE_64) +CPU_DATA CPU_CntTrailZeros64 (CPU_INT64U val) +{ +#if (!((defined(CPU_CFG_TRAIL_ZEROS_ASM_PRESENT)) && \ + (CPU_CFG_DATA_SIZE >= CPU_WORD_SIZE_64))) + CPU_INT64U val_bit_mask; + CPU_DATA nbr_lead_zeros; +#endif + CPU_DATA nbr_trail_zeros; + + + if (val == 0u) { /* Rtn ALL val bits as zero'd (see Note #3). */ + return (CPU_WORD_SIZE_64 * DEF_OCTET_NBR_BITS); + } + + /* ------------------ ASM-OPTIMIZED ------------------- */ +#if ((defined(CPU_CFG_TRAIL_ZEROS_ASM_PRESENT)) && \ + (CPU_CFG_DATA_SIZE >= CPU_WORD_SIZE_64)) + nbr_trail_zeros = CPU_CntTrailZeros((CPU_DATA)val); + +#else /* ------------------- C-OPTIMIZED -------------------- */ + val_bit_mask = val & ((CPU_INT64U)~val + 1u); /* Zero/clr all bits EXCEPT least-sig set bit. */ + nbr_lead_zeros = CPU_CntLeadZeros64(val_bit_mask); /* Cnt nbr lead 0s. */ + /* Calc nbr trail 0s = (nbr val bits - 1) - nbr lead 0s.*/ + nbr_trail_zeros = ((CPU_WORD_SIZE_64 * DEF_OCTET_NBR_BITS) - 1u) - nbr_lead_zeros; +#endif + + + return (nbr_trail_zeros); +} +#endif + + +/* +********************************************************************************************************* +* CRCUtil_PopCnt_32() +* +* Description : Compute population count (hamming weight) for value (number of bits set). +* +* Argument(s) : value Value to compute population count on. +* +* +* Return(s) : value's population count. +* +* Caller(s) : various. +* +* Note(s) : (1) Algorithm taken from http://en.wikipedia.org/wiki/Hamming_weight +********************************************************************************************************* +*/ + +CPU_INT08U CPU_PopCnt32 (CPU_INT32U value) +{ + CPU_INT32U even_cnt; + CPU_INT32U odd_cnt; + CPU_INT32U result; + + + odd_cnt = (value >> 1u) & CRC_UTIL_POPCNT_MASK01010101_32; /* 2-bits pieces. */ + result = value - odd_cnt; /* Same result as result=odd_cnt+(value & 0x55555555). */ + + even_cnt = result & CRC_UTIL_POPCNT_MASK00110011_32; /* 4-bits pieces. */ + odd_cnt = (result >> 2u) & CRC_UTIL_POPCNT_MASK00110011_32; + result = even_cnt + odd_cnt; + + even_cnt = result & CRC_UTIL_POPCNT_MASK00001111_32; /* 8-bits pieces. */ + odd_cnt = (result >> 4u) & CRC_UTIL_POPCNT_MASK00001111_32; + result = even_cnt + odd_cnt; + + result = (result * CRC_UTIL_POPCNT_POWERSOF256_32) >> 24u; + + return (result); +} + + +/* +********************************************************************************************************* +********************************************************************************************************* +* LOCAL FUNCTIONS +********************************************************************************************************* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* CPU_NameInit() +* +* Description : Initialize CPU Name. +* +* Argument(s) : none. +* +* Return(s) : none. +* +* Caller(s) : CPU_Init(). +* +* Note(s) : none. +********************************************************************************************************* +*/ + +#if (CPU_CFG_NAME_EN == DEF_ENABLED) +static void CPU_NameInit (void) +{ + CPU_NameClr(); +} +#endif + + +/* +********************************************************************************************************* +* CPU_TS_Init() +* +* Description : (1) Initialize CPU timestamp : +* +* (a) Initialize/start CPU timestamp timer See Note #1 +* (b) Initialize CPU timestamp controls +* +* +* Argument(s) : none. +* +* Return(s) : none. +* +* Caller(s) : CPU_Init(). +* +* Note(s) : (1) The following initialization MUST be sequenced as follows : +* +* (a) CPU_TS_TmrFreq_Hz MUST be initialized prior to CPU_TS_TmrInit() +* (b) CPU_TS_TmrInit() SHOULD precede calls to all other CPU timestamp functions; +* otherwise, invalid time measurements may be calculated/ +* returned. +* +* See also 'CPU_Init() Note #3a'. +********************************************************************************************************* +*/ + +#if ((CPU_CFG_TS_EN == DEF_ENABLED) || \ + (CPU_CFG_TS_TMR_EN == DEF_ENABLED)) +static void CPU_TS_Init (void) +{ +#if (((CPU_CFG_TS_32_EN == DEF_ENABLED ) && \ + (CPU_CFG_TS_TMR_SIZE < CPU_WORD_SIZE_32)) || \ + ((CPU_CFG_TS_64_EN == DEF_ENABLED ) && \ + (CPU_CFG_TS_TMR_SIZE < CPU_WORD_SIZE_64))) + CPU_TS_TMR ts_tmr_cnts; +#endif + + + /* ----------------- INIT CPU TS TMR ------------------ */ +#if (CPU_CFG_TS_TMR_EN == DEF_ENABLED) + CPU_TS_TmrFreq_Hz = 0u; /* Init/clr ts tmr freq (see Note #1a). */ + CPU_TS_TmrInit(); /* Init & start ts tmr (see Note #1b). */ +#endif + + + /* ------------------- INIT CPU TS -------------------- */ +#if (((CPU_CFG_TS_32_EN == DEF_ENABLED ) && \ + (CPU_CFG_TS_TMR_SIZE < CPU_WORD_SIZE_32)) || \ + ((CPU_CFG_TS_64_EN == DEF_ENABLED ) && \ + (CPU_CFG_TS_TMR_SIZE < CPU_WORD_SIZE_64))) + ts_tmr_cnts = CPU_TS_TmrRd(); /* Get init ts tmr val (in ts tmr cnts). */ +#endif + +#if ((CPU_CFG_TS_32_EN == DEF_ENABLED) && \ + (CPU_CFG_TS_TMR_SIZE < CPU_WORD_SIZE_32)) + CPU_TS_32_Accum = 0u; /* Init 32-bit accum'd ts. */ + CPU_TS_32_TmrPrev = ts_tmr_cnts; /* Init 32-bit ts prev tmr val. */ +#endif + +#if ((CPU_CFG_TS_64_EN == DEF_ENABLED) && \ + (CPU_CFG_TS_TMR_SIZE < CPU_WORD_SIZE_64)) + CPU_TS_64_Accum = 0u; /* Init 64-bit accum'd ts. */ + CPU_TS_64_TmrPrev = ts_tmr_cnts; /* Init 64-bit ts prev tmr val. */ +#endif +} +#endif + + +/* +********************************************************************************************************* +* CPU_IntDisMeasInit() +* +* Description : (1) Initialize interrupts disabled time measurements feature : +* +* (a) Initialize interrupts disabled time measurement controls +* (b) Calculate interrupts disabled time measurement overhead +* +* +* Argument(s) : none. +* +* Return(s) : none. +* +* Caller(s) : CPU_Init(). +* +* Note(s) : (2) CPU_IntDisMeasInit() SHOULD precede ALL calls to CPU_CRITICAL_ENTER()/CPU_CRITICAL_EXIT() +* & other CPU interrupts disabled time measurement functions; otherwise, invalid interrupts +* disabled time measurements may be calculated/returned. +* +* See also 'CPU_Init() Note #3b'. +* +* (3) (a) (1) Interrupts disabled time measurement overhead performed multiple times to calculate +* a rounded average with better accuracy, hopefully of +/- one timer count. +* +* (2) However, a single overhead time measurement is recommended, even for instruction- +* cache-enabled CPUs, since critical sections are NOT typically called within +* instruction-cached loops. Thus a single non-cached/non-averaged time measurement +* is a more realistic overhead for the majority of non-cached interrupts disabled +* time measurements. +* +* (b) Interrupts MUST be disabled while measuring the interrupts disabled time measurement +* overhead; otherwise, overhead measurements could be interrupted which would incorrectly +* calculate an inflated overhead time which would then incorrectly calculate deflated +* interrupts disabled times. +********************************************************************************************************* +*/ + +#ifdef CPU_CFG_INT_DIS_MEAS_EN +static void CPU_IntDisMeasInit (void) +{ + CPU_TS_TMR time_meas_tot_cnts; + CPU_INT16U i; + CPU_SR_ALLOC(); + + /* ----------- INIT INT DIS TIME MEAS CTRLS ----------- */ + CPU_IntDisMeasCtr = 0u; + CPU_IntDisNestCtr = 0u; + CPU_IntDisMeasStart_cnts = 0u; + CPU_IntDisMeasStop_cnts = 0u; + CPU_IntDisMeasMaxCur_cnts = 0u; + CPU_IntDisMeasMax_cnts = 0u; + CPU_IntDisMeasOvrhd_cnts = 0u; + + /* ----------- CALC INT DIS TIME MEAS OVRHD ----------- */ + time_meas_tot_cnts = 0u; + CPU_INT_DIS(); /* Ints MUST be dis'd for ovrhd calc (see Note #3b). */ + for (i = 0u; i < CPU_CFG_INT_DIS_MEAS_OVRHD_NBR; i++) { + CPU_IntDisMeasMaxCur_cnts = 0u; + CPU_IntDisMeasStart(); /* Perform multiple consecutive start/stop time meas's */ + CPU_IntDisMeasStop(); + time_meas_tot_cnts += CPU_IntDisMeasMaxCur_cnts; /* ... & sum time meas max's ... */ + } + /* ... to calc avg time meas ovrhd (see Note #3a). */ + CPU_IntDisMeasOvrhd_cnts = (time_meas_tot_cnts + (CPU_CFG_INT_DIS_MEAS_OVRHD_NBR / 2u)) + / CPU_CFG_INT_DIS_MEAS_OVRHD_NBR; + CPU_IntDisMeasMaxCur_cnts = 0u; /* Reset max ints dis'd times. */ + CPU_IntDisMeasMax_cnts = 0u; + CPU_INT_EN(); +} +#endif + + +/* +********************************************************************************************************* +* CPU_IntDisMeasMaxCalc() +* +* Description : Calculate maximum interrupts disabled time. +* +* Argument(s) : time_tot_cnts Total interrupt disabled time, in timer counts. +* +* Return(s) : Maximum interrupts disabled time (in CPU timestamp timer counts). +* +* Caller(s) : CPU_IntDisMeasMaxCurGet(), +* CPU_IntDisMeasMaxGet(). +* +* Note(s) : (1) (a) The total amount of time interrupts are disabled by system &/or application code +* during critical sections is calculated by the following equations : +* +* (1) time = [ time - time ] - time +* interrupts [ stop start ] total meas +* disabled [ meas meas ] ovrhd +* (via application) +* +* +* (2) time = time + time +* total meas start meas stop meas +* ovrhd ovrhd ovrhd +* +* +* where +* +* time time interrupts are disabled between +* interrupts first critical section enter & +* disabled last critical section exit minus +* (via application) time measurement overhead +* +* time time of disable interrupts start time +* start measurement (in timer counts) +* meas +* +* time time of disable interrupts stop time +* stop measurement (in timer counts) +* meas +* +* time total overhead time to start/stop disabled +* total meas interrupts time measurements (in timer +* ovrhd counts) +* +* time total overhead time after getting start +* start meas time until end of start measurement +* ovrhd function (in timer counts) +* +* time total overhead time from beginning of stop +* stop meas measurement function until after getting +* ovrhd stop time (in timer counts) +* +* +* (b) To expedite & reduce interrupts disabled time measurement overhead, the final +* calculations to subtract the interrupts disabled time measurement overhead is +* performed asynchronously in API functions. +* +* See also 'CPU_IntDisMeasStop() Note #1b2'. +* +* (c) The amount of time interrupts are disabled is calculated by either of the +* following equations : +* +* (1) Interrupts disabled time = Number timer counts * Timer period +* +* where +* +* Number timer counts Number of timer counts measured +* Timer period Timer's period in some units of +* (fractional) seconds +* Interrupts disabled time Amount of time interrupts are +* disabled, in same units of +* (fractional) seconds as the +* Timer period +* +* Number timer counts +* (2) Interrupts disabled time = --------------------- +* Timer frequency +* +* where +* +* Number timer counts Number of timer counts measured +* Timer frequency Timer's frequency in some units +* of counts per second +* Interrupts disabled time Amount of time interrupts are +* disabled, in seconds +* +* See also 'cpu_core.h FUNCTION PROTOTYPES CPU_TS_TmrRd() Note #2c' +* & 'cpu_core.h FUNCTION PROTOTYPES CPU_TSxx_to_uSec() Note #2'. +* +* (2) Although it is not typical, it is possible for an interrupts disabled time +* measurement to be less than the interrupts disabled time measurement overhead; +* especially if the overhead was calculated with a single, non-cached measurement +* & critical sections are called within instruction-cached loops. +********************************************************************************************************* +*/ + +#ifdef CPU_CFG_INT_DIS_MEAS_EN +static CPU_TS_TMR CPU_IntDisMeasMaxCalc (CPU_TS_TMR time_tot_cnts) +{ + CPU_TS_TMR time_max_cnts; + + + time_max_cnts = time_tot_cnts; + if (time_max_cnts > CPU_IntDisMeasOvrhd_cnts) { /* If max ints dis'd time > ovrhd time, ... */ + time_max_cnts -= CPU_IntDisMeasOvrhd_cnts; /* ... adj max ints dis'd time by ovrhd time; ... */ + } else { /* ... else max ints dis'd time < ovrhd time, ... */ + time_max_cnts = 0u; /* ... clr max ints dis'd time (see Note #2). */ + } + + return (time_max_cnts); +} +#endif + diff --git a/Middlewares/Third_Party/Micrium/uC-CPU/cpu_core.h b/Middlewares/Third_Party/Micrium/uC-CPU/cpu_core.h new file mode 100644 index 0000000..59a0551 --- /dev/null +++ b/Middlewares/Third_Party/Micrium/uC-CPU/cpu_core.h @@ -0,0 +1,1032 @@ +/* +********************************************************************************************************* +* uC/CPU +* CPU CONFIGURATION & PORT LAYER +* +* (c) Copyright 2004-2015; Micrium, Inc.; Weston, FL +* +* All rights reserved. Protected by international copyright laws. +* +* uC/CPU is provided in source form to registered licensees ONLY. It is +* illegal to distribute this source code to any third party unless you receive +* written permission by an authorized Micrium representative. Knowledge of +* the source code may NOT be used to develop a similar product. +* +* Please help us continue to provide the Embedded community with the finest +* software available. Your honesty is greatly appreciated. +* +* You can find our product's user manual, API reference, release notes and +* more information at https://doc.micrium.com. +* You can contact us at www.micrium.com. +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* +* CORE CPU MODULE +* +* Filename : cpu_core.h +* Version : V1.30.02 +* Programmer(s) : SR +* ITJ +********************************************************************************************************* +* Note(s) : (1) Assumes the following versions (or more recent) of software modules are included in +* the project build : +* +* (a) uC/LIB V1.35.00 +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* MODULE +* +* Note(s) : (1) This core CPU header file is protected from multiple pre-processor inclusion through use of +* the core CPU module present pre-processor macro definition. +********************************************************************************************************* +*/ + +#ifndef CPU_CORE_MODULE_PRESENT /* See Note #1. */ +#define CPU_CORE_MODULE_PRESENT + + +/* +********************************************************************************************************* +* EXTERNS +********************************************************************************************************* +*/ + +#ifdef CPU_CORE_MODULE +#define CPU_CORE_EXT +#else +#define CPU_CORE_EXT extern +#endif + + +/* +********************************************************************************************************* +* INCLUDE FILES +* +* Note(s) : (1) CPU-configuration software files are located in the following directories : +* +* (a) \\cpu_cfg.h +* +* (b) (1) \\cpu_*.* +* (2) \\\\cpu*.* +* +* where +* directory path for Your Product's Application +* directory path for common CPU-compiler software +* directory name for specific processor (CPU) +* directory name for specific compiler +* +* (2) NO compiler-supplied standard library functions SHOULD be used. +* +* (a) Standard library functions are implemented in the custom library module(s) : +* +* \\lib_*.* +* +* where +* directory path for custom library software +* +* (3) Compiler MUST be configured to include as additional include path directories : +* +* (a) '\\' directory See Note #1a +* +* (b) (1) '\\' directory See Note #1b1 +* (2) '\\\\' directory See Note #1b2 +* +* (c) '\\' directory See Note #2a +********************************************************************************************************* +*/ + +#include +#include +#include + +#if (CPU_CFG_NAME_EN == DEF_ENABLED) +#include +#include +#endif + + +/* +********************************************************************************************************* +* CPU CONFIGURATION +* +* Note(s) : (1) The following pre-processor directives correctly configure CPU parameters. DO NOT MODIFY. +* +* (2) CPU timestamp timer feature is required for : +* +* (a) CPU timestamps +* (b) CPU interrupts disabled time measurement +* +* See also 'cpu_cfg.h CPU TIMESTAMP CONFIGURATION Note #1' +* & 'cpu_cfg.h CPU INTERRUPTS DISABLED TIME MEASUREMENT CONFIGURATION Note #1'. +********************************************************************************************************* +*/ + +#ifdef CPU_CFG_TS_EN +#undef CPU_CFG_TS_EN +#endif + + +#if ((CPU_CFG_TS_32_EN == DEF_ENABLED) || \ + (CPU_CFG_TS_64_EN == DEF_ENABLED)) +#define CPU_CFG_TS_EN DEF_ENABLED +#else +#define CPU_CFG_TS_EN DEF_DISABLED +#endif + +#if ((CPU_CFG_TS_EN == DEF_ENABLED) || \ +(defined(CPU_CFG_INT_DIS_MEAS_EN))) +#define CPU_CFG_TS_TMR_EN DEF_ENABLED +#else +#define CPU_CFG_TS_TMR_EN DEF_DISABLED +#endif + + +/* +********************************************************************************************************* +* DEFINES +********************************************************************************************************* +*/ + +#define CPU_TIME_MEAS_NBR_MIN 1u +#define CPU_TIME_MEAS_NBR_MAX 128u + + +/* +********************************************************************************************************* +* DATA TYPES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* CPU ERROR CODES +********************************************************************************************************* +*/ + +typedef enum cpu_err { + + CPU_ERR_NONE = 0u, + CPU_ERR_NULL_PTR = 10u, + + CPU_ERR_NAME_SIZE = 1000u, + + CPU_ERR_TS_FREQ_INVALID = 2000u + +} CPU_ERR; + + +/* +********************************************************************************************************* +* CPU TIMESTAMP DATA TYPES +* +* Note(s) : (1) CPU timestamp timer data type defined to the binary-multiple of 8-bit octets as configured +* by 'CPU_CFG_TS_TMR_SIZE' (see 'cpu_cfg.h CPU TIMESTAMP CONFIGURATION Note #2'). +********************************************************************************************************* +*/ + +typedef CPU_INT32U CPU_TS32; +typedef CPU_INT64U CPU_TS64; + +typedef CPU_TS32 CPU_TS; /* Req'd for backwards-compatibility. */ + + +#if (CPU_CFG_TS_TMR_EN == DEF_ENABLED) /* CPU ts tmr defined to cfg'd word size (see Note #1). */ +#if (CPU_CFG_TS_TMR_SIZE == CPU_WORD_SIZE_08) +typedef CPU_INT08U CPU_TS_TMR; +#elif (CPU_CFG_TS_TMR_SIZE == CPU_WORD_SIZE_16) +typedef CPU_INT16U CPU_TS_TMR; +#elif (CPU_CFG_TS_TMR_SIZE == CPU_WORD_SIZE_64) +typedef CPU_INT64U CPU_TS_TMR; +#else /* CPU ts tmr dflt size = 32-bits. */ +typedef CPU_INT32U CPU_TS_TMR; +#endif +#endif + + +/* +********************************************************************************************************* +* CPU TIMESTAMP TIMER FREQUENCY DATA TYPE +********************************************************************************************************* +*/ + +typedef CPU_INT32U CPU_TS_TMR_FREQ; + + +/* +********************************************************************************************************* +* GLOBAL VARIABLES +********************************************************************************************************* +*/ + +#if (CPU_CFG_NAME_EN == DEF_ENABLED) +CPU_CORE_EXT CPU_CHAR CPU_Name[CPU_CFG_NAME_SIZE]; /* CPU host name. */ +#endif + + +#if ((CPU_CFG_TS_32_EN == DEF_ENABLED) && \ + (CPU_CFG_TS_TMR_SIZE < CPU_WORD_SIZE_32)) +CPU_CORE_EXT CPU_TS32 CPU_TS_32_Accum; /* 32-bit accum'd ts (in ts tmr cnts). */ +CPU_CORE_EXT CPU_TS_TMR CPU_TS_32_TmrPrev; /* 32-bit ts prev tmr (in ts tmr cnts). */ +#endif + +#if ((CPU_CFG_TS_64_EN == DEF_ENABLED) && \ + (CPU_CFG_TS_TMR_SIZE < CPU_WORD_SIZE_64)) +CPU_CORE_EXT CPU_TS64 CPU_TS_64_Accum; /* 64-bit accum'd ts (in ts tmr cnts). */ +CPU_CORE_EXT CPU_TS_TMR CPU_TS_64_TmrPrev; /* 64-bit ts prev tmr (in ts tmr cnts). */ +#endif + +#if (CPU_CFG_TS_TMR_EN == DEF_ENABLED) +CPU_CORE_EXT CPU_TS_TMR_FREQ CPU_TS_TmrFreq_Hz; /* CPU ts tmr freq (in Hz). */ +#endif + + +#ifdef CPU_CFG_INT_DIS_MEAS_EN +CPU_CORE_EXT CPU_INT16U CPU_IntDisMeasCtr; /* Nbr tot ints dis'd ctr. */ +CPU_CORE_EXT CPU_INT16U CPU_IntDisNestCtr; /* Nbr nested ints dis'd ctr. */ + /* Ints dis'd time (in ts tmr cnts) : ... */ +CPU_CORE_EXT CPU_TS_TMR CPU_IntDisMeasStart_cnts; /* ... start time. */ +CPU_CORE_EXT CPU_TS_TMR CPU_IntDisMeasStop_cnts; /* ... stop time. */ +CPU_CORE_EXT CPU_TS_TMR CPU_IntDisMeasOvrhd_cnts; /* ... time meas ovrhd. */ +CPU_CORE_EXT CPU_TS_TMR CPU_IntDisMeasMaxCur_cnts; /* ... resetable max time dis'd. */ +CPU_CORE_EXT CPU_TS_TMR CPU_IntDisMeasMax_cnts; /* ... non-resetable max time dis'd. */ +#endif + + +/* +********************************************************************************************************* +* MACRO'S +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* CPU_SW_EXCEPTION() +* +* Description : Trap unrecoverable software exception. +* +* Argument(s) : err_rtn_val Error type &/or value of the calling function to return (see Note #2b). +* +* Return(s) : none. +* +* Caller(s) : various. +* +* Note(s) : (1) CPU_SW_EXCEPTION() deadlocks the current code execution -- whether multi-tasked/ +* -processed/-threaded or single-threaded -- when the current code execution cannot +* gracefully recover or report a fault or exception condition. +* +* Example CPU_SW_EXCEPTION() call : +* +* void Fnct (CPU_ERR *p_err) +* { +* : +* +* if (p_err == (CPU_ERR *)0) { If 'p_err' NULL, cannot return error ... +* CPU_SW_EXCEPTION(;); ... so trap invalid argument exception. +* } +* +* : +* } +* +* See also 'cpu_core.c CPU_SW_Exception() Note #1'. +* +* (2) (a) CPU_SW_EXCEPTION() MAY be developer-implemented to output &/or handle any error or +* exception conditions; but since CPU_SW_EXCEPTION() is intended to trap unrecoverable +* software conditions, it is recommended that developer-implemented versions prevent +* execution of any code following calls to CPU_SW_EXCEPTION() by deadlocking the code +* (see Note #1). +* +* Example CPU_SW_EXCEPTION() : +* +* #define CPU_SW_EXCEPTION(err_rtn_val) do { \ +* Log(__FILE__, __LINE__); \ +* CPU_SW_Exception(); \ +* } while (0) +* +* (b) (1) However, if execution of code following calls to CPU_SW_EXCEPTION() is required +* (e.g. for automated testing); it is recommended that the last statement in +* developer-implemented versions be to return from the current function to prevent +* possible software exception(s) in the current function from triggering CPU &/or +* hardware exception(s). +* +* Example CPU_SW_EXCEPTION() : +* +* #define CPU_SW_EXCEPTION(err_rtn_val) do { \ +* Log(__FILE__, __LINE__); \ +* return err_rtn_val; \ +* } while (0) +* +* (A) Note that 'err_rtn_val' in the return statement MUST NOT be enclosed in +* parentheses. This allows CPU_SW_EXCEPTION() to return from functions that +* return 'void', i.e. NO return type or value (see also Note #2b2A). +* +* (2) In order for CPU_SW_EXCEPTION() to return from functions with various return +* types/values, each caller function MUST pass an appropriate error return type +* & value to CPU_SW_EXCEPTION(). +* +* (A) Note that CPU_SW_EXCEPTION() MUST NOT be passed any return type or value +* for functions that return 'void', i.e. NO return type or value; but SHOULD +* instead be passed a single semicolon. This prevents possible compiler +* warnings that CPU_SW_EXCEPTION() is passed too few arguments. However, +* the compiler may warn that CPU_SW_EXCEPTION() does NOT prevent creating +* null statements on lines with NO other code statements. +* +* Example CPU_SW_EXCEPTION() calls : +* +* void Fnct (CPU_ERR *p_err) +* { +* : +* +* if (p_err == (CPU_ERR *)0) { +* CPU_SW_EXCEPTION(;); Exception macro returns NO value +* } (see Note #2b2A) +* +* : +* } +* +* CPU_BOOLEAN Fnct (CPU_ERR *p_err) +* { +* : +* +* if (p_err == (CPU_ERR *)0) { +* CPU_SW_EXCEPTION(DEF_FAIL); Exception macro returns 'DEF_FAIL' +* } +* +* : +* } +* +* OBJ *Fnct (CPU_ERR *p_err) +* { +* : +* +* if (p_err == (CPU_ERR *)0) { +* CPU_SW_EXCEPTION((OBJ *)0); Exception macro returns NULL 'OBJ *' +* } +* +* : +* } +* +********************************************************************************************************* +*/ + +#ifndef CPU_SW_EXCEPTION /* See Note #2. */ +#define CPU_SW_EXCEPTION(err_rtn_val) do { \ + CPU_SW_Exception(); \ + } while (0) +#endif + + +/* +********************************************************************************************************* +* CPU_VAL_UNUSED() +* +* Description : +* +* Argument(s) : none. +* +* Return(s) : none. +* +* Caller(s) : #### various. +* +* Note(s) : none. +********************************************************************************************************* +*/ + + +#define CPU_VAL_UNUSED(val) ((void)&(val)); + + +#define CPU_VAL_IGNORED(val) CPU_VAL_UNUSED(val) + + +/* +********************************************************************************************************* +* CPU_TYPE_CREATE() +* +* Description : Creates a generic type value. +* +* Argument(s) : char_1 1st ASCII character to create generic type value. +* +* char_2 2nd ASCII character to create generic type value. +* +* char_3 3rd ASCII character to create generic type value. +* +* char_4 4th ASCII character to create generic type value. +* +* Return(s) : 32-bit generic type value. +* +* Caller(s) : various. +* +* Note(s) : (1) (a) Generic type values should be #define'd with large, non-trivial values to trap +* & discard invalid/corrupted objects based on type value. +* +* In other words, by assigning large, non-trivial values to valid objects' type +* fields; the likelihood that an object with an unassigned &/or corrupted type +* field will contain a value is highly improbable & therefore the object itself +* will be trapped as invalid. +* +* (b) (1) CPU_TYPE_CREATE() creates a 32-bit type value from four values. +* +* (2) Ideally, generic type values SHOULD be created from 'CPU_CHAR' characters to +* represent ASCII string abbreviations of the specific object types. Memory +* displays of object type values will display the specific object types with +* their chosen ASCII names. +* +* Examples : +* +* #define FILE_TYPE CPU_TYPE_CREATE('F', 'I', 'L', 'E') +* #define BUF_TYPE CPU_TYPE_CREATE('B', 'U', 'F', ' ') +********************************************************************************************************* +*/ + +#if (CPU_CFG_ENDIAN_TYPE == CPU_ENDIAN_TYPE_BIG) +#define CPU_TYPE_CREATE(char_1, char_2, char_3, char_4) (((CPU_INT32U)((CPU_INT08U)(char_1)) << (3u * DEF_OCTET_NBR_BITS)) | \ + ((CPU_INT32U)((CPU_INT08U)(char_2)) << (2u * DEF_OCTET_NBR_BITS)) | \ + ((CPU_INT32U)((CPU_INT08U)(char_3)) << (1u * DEF_OCTET_NBR_BITS)) | \ + ((CPU_INT32U)((CPU_INT08U)(char_4)))) + +#else + +#if ((CPU_CFG_DATA_SIZE == CPU_WORD_SIZE_64) || \ + (CPU_CFG_DATA_SIZE == CPU_WORD_SIZE_32)) +#define CPU_TYPE_CREATE(char_1, char_2, char_3, char_4) (((CPU_INT32U)((CPU_INT08U)(char_1))) | \ + ((CPU_INT32U)((CPU_INT08U)(char_2)) << (1u * DEF_OCTET_NBR_BITS)) | \ + ((CPU_INT32U)((CPU_INT08U)(char_3)) << (2u * DEF_OCTET_NBR_BITS)) | \ + ((CPU_INT32U)((CPU_INT08U)(char_4)) << (3u * DEF_OCTET_NBR_BITS))) + + +#elif (CPU_CFG_DATA_SIZE == CPU_WORD_SIZE_16) +#define CPU_TYPE_CREATE(char_1, char_2, char_3, char_4) (((CPU_INT32U)((CPU_INT08U)(char_1)) << (2u * DEF_OCTET_NBR_BITS)) | \ + ((CPU_INT32U)((CPU_INT08U)(char_2)) << (3u * DEF_OCTET_NBR_BITS)) | \ + ((CPU_INT32U)((CPU_INT08U)(char_3))) | \ + ((CPU_INT32U)((CPU_INT08U)(char_4)) << (1u * DEF_OCTET_NBR_BITS))) + +#else /* Dflt CPU_WORD_SIZE_08. */ +#define CPU_TYPE_CREATE(char_1, char_2, char_3, char_4) (((CPU_INT32U)((CPU_INT08U)(char_1)) << (3u * DEF_OCTET_NBR_BITS)) | \ + ((CPU_INT32U)((CPU_INT08U)(char_2)) << (2u * DEF_OCTET_NBR_BITS)) | \ + ((CPU_INT32U)((CPU_INT08U)(char_3)) << (1u * DEF_OCTET_NBR_BITS)) | \ + ((CPU_INT32U)((CPU_INT08U)(char_4)))) +#endif +#endif + + +/* +********************************************************************************************************* +* FUNCTION PROTOTYPES +* +* Note(s) : (1) CPU interrupts disabled time measurement functions prototyped/defined only if +* CPU_CFG_INT_DIS_MEAS_EN #define'd in 'cpu_cfg.h'. +* +* (2) (a) CPU_CntLeadZeros() defined in : +* +* (1) 'cpu_a.asm', if CPU_CFG_LEAD_ZEROS_ASM_PRESENT #define'd in 'cpu.h'/ +* 'cpu_cfg.h' to enable assembly-optimized function(s) +* +* (2) 'cpu_core.c', if CPU_CFG_LEAD_ZEROS_ASM_PRESENT NOT #define'd in 'cpu.h'/ +* 'cpu_cfg.h' to enable C-source-optimized function(s) +* +* (b) CPU_CntTrailZeros() defined in : +* +* (1) 'cpu_a.asm', if CPU_CFG_TRAIL_ZEROS_ASM_PRESENT #define'd in 'cpu.h'/ +* 'cpu_cfg.h' to enable assembly-optimized function(s) +* +* (2) 'cpu_core.c', if CPU_CFG_TRAIL_ZEROS_ASM_PRESENT NOT #define'd in 'cpu.h'/ +* 'cpu_cfg.h' to enable C-source-optimized function(s) +********************************************************************************************************* +*/ + +void CPU_Init (void); + +void CPU_SW_Exception (void); + + + +#if (CPU_CFG_NAME_EN == DEF_ENABLED) /* -------------- CPU NAME FNCTS -------------- */ +void CPU_NameClr (void); + +void CPU_NameGet ( CPU_CHAR *p_name, + CPU_ERR *p_err); + +void CPU_NameSet (const CPU_CHAR *p_name, + CPU_ERR *p_err); +#endif + + + + /* --------------- CPU TS FNCTS --------------- */ +#if (CPU_CFG_TS_32_EN == DEF_ENABLED) +CPU_TS32 CPU_TS_Get32 (void); +#endif + +#if (CPU_CFG_TS_64_EN == DEF_ENABLED) +CPU_TS64 CPU_TS_Get64 (void); +#endif + +#if (CPU_CFG_TS_EN == DEF_ENABLED) +void CPU_TS_Update (void); +#endif + + +#if (CPU_CFG_TS_TMR_EN == DEF_ENABLED) /* ------------- CPU TS TMR FNCTS ------------- */ +CPU_TS_TMR_FREQ CPU_TS_TmrFreqGet (CPU_ERR *p_err); + +void CPU_TS_TmrFreqSet (CPU_TS_TMR_FREQ freq_hz); +#endif + + + +#ifdef CPU_CFG_INT_DIS_MEAS_EN /* -------- CPU INT DIS TIME MEAS FNCTS ------- */ + /* See Note #1. */ +CPU_TS_TMR CPU_IntDisMeasMaxCurReset(void); + +CPU_TS_TMR CPU_IntDisMeasMaxCurGet (void); + +CPU_TS_TMR CPU_IntDisMeasMaxGet (void); + + +void CPU_IntDisMeasStart (void); + +void CPU_IntDisMeasStop (void); +#endif + + + + /* ----------- CPU CNT ZEROS FNCTS ------------ */ +#ifdef CPU_CFG_LEAD_ZEROS_ASM_PRESENT +#ifdef __cplusplus +extern "C" { +#endif +#endif + +CPU_DATA CPU_CntLeadZeros (CPU_DATA val); + +#ifdef CPU_CFG_LEAD_ZEROS_ASM_PRESENT +#ifdef __cplusplus +} +#endif +#endif + +#if (CPU_CFG_DATA_SIZE_MAX >= CPU_WORD_SIZE_08) +CPU_DATA CPU_CntLeadZeros08 (CPU_INT08U val); +#endif +#if (CPU_CFG_DATA_SIZE_MAX >= CPU_WORD_SIZE_16) +CPU_DATA CPU_CntLeadZeros16 (CPU_INT16U val); +#endif +#if (CPU_CFG_DATA_SIZE_MAX >= CPU_WORD_SIZE_32) +CPU_DATA CPU_CntLeadZeros32 (CPU_INT32U val); +#endif +#if (CPU_CFG_DATA_SIZE_MAX >= CPU_WORD_SIZE_64) +CPU_DATA CPU_CntLeadZeros64 (CPU_INT64U val); +#endif + + +#ifdef CPU_CFG_LEAD_ZEROS_ASM_PRESENT +#ifdef __cplusplus +extern "C" { +#endif +#endif + +CPU_DATA CPU_CntTrailZeros (CPU_DATA val); + +#ifdef CPU_CFG_LEAD_ZEROS_ASM_PRESENT +#ifdef __cplusplus +} +#endif +#endif + +#if (CPU_CFG_DATA_SIZE_MAX >= CPU_WORD_SIZE_08) +CPU_DATA CPU_CntTrailZeros08 (CPU_INT08U val); +#endif +#if (CPU_CFG_DATA_SIZE_MAX >= CPU_WORD_SIZE_16) +CPU_DATA CPU_CntTrailZeros16 (CPU_INT16U val); +#endif +#if (CPU_CFG_DATA_SIZE_MAX >= CPU_WORD_SIZE_32) +CPU_DATA CPU_CntTrailZeros32 (CPU_INT32U val); +#endif +#if (CPU_CFG_DATA_SIZE_MAX >= CPU_WORD_SIZE_64) +CPU_DATA CPU_CntTrailZeros64 (CPU_INT64U val); +#endif + +CPU_INT08U CPU_PopCnt32 (CPU_INT32U value); + +/* +********************************************************************************************************* +* FUNCTION PROTOTYPES +* DEFINED IN PRODUCT'S BSP +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* CPU_TS_TmrInit() +* +* Description : Initialize & start CPU timestamp timer. +* +* Argument(s) : none. +* +* Return(s) : none. +* +* Caller(s) : CPU_TS_Init(). +* +* This function is an INTERNAL CPU module function & MUST be implemented by application/ +* BSP function(s) [see Note #1] but MUST NOT be called by application function(s). +* +* Note(s) : (1) CPU_TS_TmrInit() is an application/BSP function that MUST be defined by the developer +* if either of the following CPU features is enabled : +* +* (a) CPU timestamps +* (b) CPU interrupts disabled time measurements +* +* See 'cpu_cfg.h CPU TIMESTAMP CONFIGURATION Note #1' +* & 'cpu_cfg.h CPU INTERRUPTS DISABLED TIME MEASUREMENT CONFIGURATION Note #1a'. +* +* (2) (a) Timer count values MUST be returned via word-size-configurable 'CPU_TS_TMR' +* data type. +* +* (1) If timer has more bits, truncate timer values' higher-order bits greater +* than the configured 'CPU_TS_TMR' timestamp timer data type word size. +* +* (2) Since the timer MUST NOT have less bits than the configured 'CPU_TS_TMR' +* timestamp timer data type word size; 'CPU_CFG_TS_TMR_SIZE' MUST be +* configured so that ALL bits in 'CPU_TS_TMR' data type are significant. +* +* In other words, if timer size is not a binary-multiple of 8-bit octets +* (e.g. 20-bits or even 24-bits), then the next lower, binary-multiple +* octet word size SHOULD be configured (e.g. to 16-bits). However, the +* minimum supported word size for CPU timestamp timers is 8-bits. +* +* See also 'cpu_cfg.h CPU TIMESTAMP CONFIGURATION Note #2' +* & 'cpu_core.h CPU TIMESTAMP DATA TYPES Note #1'. +* +* (b) Timer SHOULD be an 'up' counter whose values increase with each time count. +* +* (c) When applicable, timer period SHOULD be less than the typical measured time +* but MUST be less than the maximum measured time; otherwise, timer resolution +* inadequate to measure desired times. +* +* See also 'CPU_TS_TmrRd() Note #2'. +********************************************************************************************************* +*/ + +#if (CPU_CFG_TS_TMR_EN == DEF_ENABLED) +void CPU_TS_TmrInit(void); +#endif + + +/* +********************************************************************************************************* +* CPU_TS_TmrRd() +* +* Description : Get current CPU timestamp timer count value. +* +* Argument(s) : none. +* +* Return(s) : Timestamp timer count (see Notes #2a & #2b). +* +* Caller(s) : CPU_TS_Init(), +* CPU_TS_Get32(), +* CPU_TS_Get64(), +* CPU_IntDisMeasStart(), +* CPU_IntDisMeasStop(). +* +* This function is an INTERNAL CPU module function & MUST be implemented by application/ +* BSP function(s) [see Note #1] but SHOULD NOT be called by application function(s). +* +* Note(s) : (1) CPU_TS_TmrRd() is an application/BSP function that MUST be defined by the developer +* if either of the following CPU features is enabled : +* +* (a) CPU timestamps +* (b) CPU interrupts disabled time measurements +* +* See 'cpu_cfg.h CPU TIMESTAMP CONFIGURATION Note #1' +* & 'cpu_cfg.h CPU INTERRUPTS DISABLED TIME MEASUREMENT CONFIGURATION Note #1a'. +* +* (2) (a) Timer count values MUST be returned via word-size-configurable 'CPU_TS_TMR' +* data type. +* +* (1) If timer has more bits, truncate timer values' higher-order bits greater +* than the configured 'CPU_TS_TMR' timestamp timer data type word size. +* +* (2) Since the timer MUST NOT have less bits than the configured 'CPU_TS_TMR' +* timestamp timer data type word size; 'CPU_CFG_TS_TMR_SIZE' MUST be +* configured so that ALL bits in 'CPU_TS_TMR' data type are significant. +* +* In other words, if timer size is not a binary-multiple of 8-bit octets +* (e.g. 20-bits or even 24-bits), then the next lower, binary-multiple +* octet word size SHOULD be configured (e.g. to 16-bits). However, the +* minimum supported word size for CPU timestamp timers is 8-bits. +* +* See also 'cpu_cfg.h CPU TIMESTAMP CONFIGURATION Note #2' +* & 'cpu_core.h CPU TIMESTAMP DATA TYPES Note #1'. +* +* (b) Timer SHOULD be an 'up' counter whose values increase with each time count. +* +* (1) If timer is a 'down' counter whose values decrease with each time count, +* then the returned timer value MUST be ones-complemented. +* +* (c) (1) When applicable, the amount of time measured by CPU timestamps is +* calculated by either of the following equations : +* +* (A) Time measured = Number timer counts * Timer period +* +* where +* +* Number timer counts Number of timer counts measured +* Timer period Timer's period in some units of +* (fractional) seconds +* Time measured Amount of time measured, in same +* units of (fractional) seconds +* as the Timer period +* +* Number timer counts +* (B) Time measured = --------------------- +* Timer frequency +* +* where +* +* Number timer counts Number of timer counts measured +* Timer frequency Timer's frequency in some units +* of counts per second +* Time measured Amount of time measured, in seconds +* +* (2) Timer period SHOULD be less than the typical measured time but MUST be less +* than the maximum measured time; otherwise, timer resolution inadequate to +* measure desired times. +********************************************************************************************************* +*/ + +#if (CPU_CFG_TS_TMR_EN == DEF_ENABLED) +CPU_TS_TMR CPU_TS_TmrRd(void); +#endif + + +/* +********************************************************************************************************* +* CPU_TSxx_to_uSec() +* +* Description : Convert a 32-/64-bit CPU timestamp from timer counts to microseconds. +* +* Argument(s) : ts_cnts CPU timestamp (in timestamp timer counts [see Note #2aA]). +* +* Return(s) : Converted CPU timestamp (in microseconds [see Note #2aD]). +* +* Caller(s) : Application. +* +* This function is an (optional) CPU module application programming interface (API) +* function which MAY be implemented by application/BSP function(s) [see Note #1] & +* MAY be called by application function(s). +* +* Note(s) : (1) CPU_TS32_to_uSec()/CPU_TS64_to_uSec() are application/BSP functions that MAY be +* optionally defined by the developer when either of the following CPU features is +* enabled : +* +* (a) CPU timestamps +* (b) CPU interrupts disabled time measurements +* +* See 'cpu_cfg.h CPU TIMESTAMP CONFIGURATION Note #1' +* & 'cpu_cfg.h CPU INTERRUPTS DISABLED TIME MEASUREMENT CONFIGURATION Note #1a'. +* +* (2) (a) The amount of time measured by CPU timestamps is calculated by either of +* the following equations : +* +* 10^6 microseconds +* (1) Time measured = Number timer counts * ------------------- * Timer period +* 1 second +* +* Number timer counts 10^6 microseconds +* (2) Time measured = --------------------- * ------------------- +* Timer frequency 1 second +* +* where +* +* (A) Number timer counts Number of timer counts measured +* (B) Timer frequency Timer's frequency in some units +* of counts per second +* (C) Timer period Timer's period in some units of +* (fractional) seconds +* (D) Time measured Amount of time measured, +* in microseconds +* +* (b) Timer period SHOULD be less than the typical measured time but MUST be less +* than the maximum measured time; otherwise, timer resolution inadequate to +* measure desired times. +* +* (c) Specific implementations may convert any number of CPU_TS32 or CPU_TS64 bits +* -- up to 32 or 64, respectively -- into microseconds. +********************************************************************************************************* +*/ + +#if (CPU_CFG_TS_32_EN == DEF_ENABLED) +CPU_INT64U CPU_TS32_to_uSec(CPU_TS32 ts_cnts); +#endif + +#if (CPU_CFG_TS_64_EN == DEF_ENABLED) +CPU_INT64U CPU_TS64_to_uSec(CPU_TS64 ts_cnts); +#endif + + +/* +********************************************************************************************************* +* CONFIGURATION ERRORS +********************************************************************************************************* +*/ + +#ifndef CPU_CFG_NAME_EN +#error "CPU_CFG_NAME_EN not #define'd in 'cpu_cfg.h'" +#error " [MUST be DEF_ENABLED ] " +#error " [ || DEF_DISABLED] " + +#elif ((CPU_CFG_NAME_EN != DEF_ENABLED ) && \ + (CPU_CFG_NAME_EN != DEF_DISABLED)) +#error "CPU_CFG_NAME_EN illegally #define'd in 'cpu_cfg.h'" +#error " [MUST be DEF_ENABLED ] " +#error " [ || DEF_DISABLED] " + + +#elif (CPU_CFG_NAME_EN == DEF_ENABLED) + +#ifndef CPU_CFG_NAME_SIZE +#error "CPU_CFG_NAME_SIZE not #define'd in 'cpu_cfg.h'" +#error " [MUST be >= 1] " +#error " [ && <= 255] " + +#elif (DEF_CHK_VAL(CPU_CFG_NAME_SIZE, \ + 1, \ + DEF_INT_08U_MAX_VAL) != DEF_OK) +#error "CPU_CFG_NAME_SIZE illegally #define'd in 'cpu_cfg.h'" +#error " [MUST be >= 1] " +#error " [ && <= 255] " +#endif + +#endif + + + + +#ifndef CPU_CFG_TS_32_EN +#error "CPU_CFG_TS_32_EN not #define'd in 'cpu_cfg.h'" +#error " [MUST be DEF_DISABLED] " +#error " [ || DEF_ENABLED ] " + +#elif ((CPU_CFG_TS_32_EN != DEF_DISABLED) && \ + (CPU_CFG_TS_32_EN != DEF_ENABLED )) +#error "CPU_CFG_TS_32_EN illegally #define'd in 'cpu_cfg.h'" +#error " [MUST be DEF_DISABLED] " +#error " [ || DEF_ENABLED ] " + +#endif + + +#ifndef CPU_CFG_TS_64_EN +#error "CPU_CFG_TS_64_EN not #define'd in 'cpu_cfg.h'" +#error " [MUST be DEF_DISABLED] " +#error " [ || DEF_ENABLED ] " + +#elif ((CPU_CFG_TS_64_EN != DEF_DISABLED) && \ + (CPU_CFG_TS_64_EN != DEF_ENABLED )) +#error "CPU_CFG_TS_64_EN illegally #define'd in 'cpu_cfg.h'" +#error " [MUST be DEF_DISABLED] " +#error " [ || DEF_ENABLED ] " + +#endif + + /* Correctly configured in 'cpu_core.h'; DO NOT MODIFY. */ +#ifndef CPU_CFG_TS_EN +#error "CPU_CFG_TS_EN not #define'd in 'cpu_core.h'" +#error " [MUST be DEF_DISABLED] " +#error " [ || DEF_ENABLED ] " + +#elif ((CPU_CFG_TS_EN != DEF_DISABLED) && \ + (CPU_CFG_TS_EN != DEF_ENABLED )) +#error "CPU_CFG_TS_EN illegally #define'd in 'cpu_core.h'" +#error " [MUST be DEF_DISABLED] " +#error " [ || DEF_ENABLED ] " + +#endif + + + /* Correctly configured in 'cpu_core.h'; DO NOT MODIFY. */ +#ifndef CPU_CFG_TS_TMR_EN +#error "CPU_CFG_TS_TMR_EN not #define'd in 'cpu_core.h'" +#error " [MUST be DEF_DISABLED] " +#error " [ || DEF_ENABLED ] " + +#elif ((CPU_CFG_TS_TMR_EN != DEF_DISABLED) && \ + (CPU_CFG_TS_TMR_EN != DEF_ENABLED )) +#error "CPU_CFG_TS_TMR_EN illegally #define'd in 'cpu_core.h'" +#error " [MUST be DEF_DISABLED] " +#error " [ || DEF_ENABLED ] " + + +#elif (CPU_CFG_TS_TMR_EN == DEF_ENABLED) + +#ifndef CPU_CFG_TS_TMR_SIZE +#error "CPU_CFG_TS_TMR_SIZE not #define'd in 'cpu_cfg.h' " +#error " [MUST be CPU_WORD_SIZE_08 8-bit timer]" +#error " [ || CPU_WORD_SIZE_16 16-bit timer]" +#error " [ || CPU_WORD_SIZE_32 32-bit timer]" +#error " [ || CPU_WORD_SIZE_64 64-bit timer]" + +#elif ((CPU_CFG_TS_TMR_SIZE != CPU_WORD_SIZE_08) && \ + (CPU_CFG_TS_TMR_SIZE != CPU_WORD_SIZE_16) && \ + (CPU_CFG_TS_TMR_SIZE != CPU_WORD_SIZE_32) && \ + (CPU_CFG_TS_TMR_SIZE != CPU_WORD_SIZE_64)) +#error "CPU_CFG_TS_TMR_SIZE illegally #define'd in 'cpu_cfg.h' " +#error " [MUST be CPU_WORD_SIZE_08 8-bit timer]" +#error " [ || CPU_WORD_SIZE_16 16-bit timer]" +#error " [ || CPU_WORD_SIZE_32 32-bit timer]" +#error " [ || CPU_WORD_SIZE_64 64-bit timer]" +#endif + +#endif + + + +#ifndef CPU_CFG_INT_DIS_MEAS_EN +#if 0 /* Optionally configured in 'cpu_cfg.h'; DO NOT MODIFY. */ +#error "CPU_CFG_INT_DIS_MEAS_EN not #define'd in 'cpu_cfg.h'" +#endif + +#else + +#ifndef CPU_CFG_INT_DIS_MEAS_OVRHD_NBR +#error "CPU_CFG_INT_DIS_MEAS_OVRHD_NBR not #define'd in 'cpu_cfg.h' " +#error " [MUST be >= CPU_TIME_MEAS_NBR_MIN]" +#error " [ || <= CPU_TIME_MEAS_NBR_MAX]" + +#elif (DEF_CHK_VAL(CPU_CFG_INT_DIS_MEAS_OVRHD_NBR, \ + CPU_TIME_MEAS_NBR_MIN, \ + CPU_TIME_MEAS_NBR_MAX) != DEF_OK) +#error "CPU_CFG_INT_DIS_MEAS_OVRHD_NBR illegally #define'd in 'cpu_cfg.h' " +#error " [MUST be >= CPU_TIME_MEAS_NBR_MIN]" +#error " [ || <= CPU_TIME_MEAS_NBR_MAX]" + +#endif + +#endif + + + + +#ifndef CPU_CFG_LEAD_ZEROS_ASM_PRESENT +#if 0 /* Optionally configured in 'cpu_cfg.h'; DO NOT MODIFY. */ +#error "CPU_CFG_LEAD_ZEROS_ASM_PRESENT not #define'd in 'cpu.h'/'cpu_cfg.h'" +#endif +#endif + + +#ifndef CPU_CFG_TRAIL_ZEROS_ASM_PRESENT +#if 0 /* Optionally configured in 'cpu_cfg.h'; DO NOT MODIFY. */ +#error "CPU_CFG_TRAIL_ZEROS_ASM_PRESENT not #define'd in 'cpu.h'/'cpu_cfg.h'" +#endif +#endif + + +/* +********************************************************************************************************* +* CPU PORT CONFIGURATION ERRORS +********************************************************************************************************* +*/ + +#ifndef CPU_CFG_ADDR_SIZE +#error "CPU_CFG_ADDR_SIZE not #define'd in 'cpu.h'" +#endif + +#ifndef CPU_CFG_DATA_SIZE +#error "CPU_CFG_DATA_SIZE not #define'd in 'cpu.h'" +#endif + +#ifndef CPU_CFG_DATA_SIZE_MAX +#error "CPU_CFG_DATA_SIZE_MAX not #define'd in 'cpu.h'" +#endif + + +/* +********************************************************************************************************* +* LIBRARY CONFIGURATION ERRORS +********************************************************************************************************* +*/ + + /* See 'cpu_core.h Note #1a'. */ +#if (LIB_VERSION < 13500u) +#error "LIB_VERSION [SHOULD be >= V1.35.00]" +#endif + + +/* +********************************************************************************************************* +* MODULE END +* +* Note(s) : (1) See 'cpu_core.h MODULE'. +********************************************************************************************************* +*/ + +#endif /* End of CPU core module include. */ + diff --git a/Middlewares/Third_Party/Micrium/uC-CPU/cpu_def.h b/Middlewares/Third_Party/Micrium/uC-CPU/cpu_def.h new file mode 100644 index 0000000..c22fa41 --- /dev/null +++ b/Middlewares/Third_Party/Micrium/uC-CPU/cpu_def.h @@ -0,0 +1,220 @@ +/* +********************************************************************************************************* +* uC/CPU +* CPU CONFIGURATION & PORT LAYER +* +* (c) Copyright 2004-2015; Micrium, Inc.; Weston, FL +* +* All rights reserved. Protected by international copyright laws. +* +* uC/CPU is provided in source form to registered licensees ONLY. It is +* illegal to distribute this source code to any third party unless you receive +* written permission by an authorized Micrium representative. Knowledge of +* the source code may NOT be used to develop a similar product. +* +* Please help us continue to provide the Embedded community with the finest +* software available. Your honesty is greatly appreciated. +* +* You can find our product's user manual, API reference, release notes and +* more information at https://doc.micrium.com. +* You can contact us at www.micrium.com. +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* +* CPU CONFIGURATION DEFINES +* +* Filename : cpu_def.h +* Version : V1.30.02 +* Programmer(s) : ITJ +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* MODULE +* +* Note(s) : (1) This CPU definition header file is protected from multiple pre-processor inclusion +* through use of the CPU definition module present pre-processor macro definition. +********************************************************************************************************* +*/ + +#ifndef CPU_DEF_MODULE_PRESENT +#define CPU_DEF_MODULE_PRESENT + + +/* +********************************************************************************************************* +* CORE CPU MODULE VERSION NUMBER +* +* Note(s) : (1) (a) The core CPU module software version is denoted as follows : +* +* Vx.yy.zz +* +* where +* V denotes 'Version' label +* x denotes major software version revision number +* yy denotes minor software version revision number +* zz denotes sub-minor software version revision number +* +* (b) The software version label #define is formatted as follows : +* +* ver = x.yyzz * 100 * 100 +* +* where +* ver denotes software version number scaled as an integer value +* x.yyzz denotes software version number, where the unscaled integer +* portion denotes the major version number & the unscaled +* fractional portion denotes the (concatenated) minor +* version numbers +********************************************************************************************************* +*/ + +#define CPU_CORE_VERSION 13002u /* See Note #1. */ + + +/* +********************************************************************************************************* +* CPU WORD CONFIGURATION +* +* Note(s) : (1) Configure CPU_CFG_ADDR_SIZE & CPU_CFG_DATA_SIZE in 'cpu.h' with CPU's word sizes : +* +* CPU_WORD_SIZE_08 8-bit word size +* CPU_WORD_SIZE_16 16-bit word size +* CPU_WORD_SIZE_32 32-bit word size +* CPU_WORD_SIZE_64 64-bit word size +* +* (2) Configure CPU_CFG_ENDIAN_TYPE in 'cpu.h' with CPU's data-word-memory order : +* +* (a) CPU_ENDIAN_TYPE_BIG Big- endian word order (CPU words' most significant +* octet @ lowest memory address) +* (b) CPU_ENDIAN_TYPE_LITTLE Little-endian word order (CPU words' least significant +* octet @ lowest memory address) +********************************************************************************************************* +*/ + + /* ---------------------- CPU WORD SIZE ----------------------- */ +#define CPU_WORD_SIZE_08 1u /* 8-bit word size (in octets). */ +#define CPU_WORD_SIZE_16 2u /* 16-bit word size (in octets). */ +#define CPU_WORD_SIZE_32 4u /* 32-bit word size (in octets). */ +#define CPU_WORD_SIZE_64 8u /* 64-bit word size (in octets). */ + + + /* ------------------ CPU WORD-ENDIAN ORDER ------------------- */ +#define CPU_ENDIAN_TYPE_NONE 0u +#define CPU_ENDIAN_TYPE_BIG 1u /* Big- endian word order (see Note #1a). */ +#define CPU_ENDIAN_TYPE_LITTLE 2u /* Little-endian word order (see Note #1b). */ + + +/* +********************************************************************************************************* +* CPU STACK CONFIGURATION +* +* Note(s) : (1) Configure CPU_CFG_STK_GROWTH in 'cpu.h' with CPU's stack growth order : +* +* (a) CPU_STK_GROWTH_LO_TO_HI CPU stack pointer increments to the next higher stack +* memory address after data is pushed onto the stack +* (b) CPU_STK_GROWTH_HI_TO_LO CPU stack pointer decrements to the next lower stack +* memory address after data is pushed onto the stack +********************************************************************************************************* +*/ + + /* ------------------ CPU STACK GROWTH ORDER ------------------ */ +#define CPU_STK_GROWTH_NONE 0u +#define CPU_STK_GROWTH_LO_TO_HI 1u /* CPU stk incs towards higher mem addrs (see Note #1a). */ +#define CPU_STK_GROWTH_HI_TO_LO 2u /* CPU stk decs towards lower mem addrs (see Note #1b). */ + + +/* +********************************************************************************************************* +* CRITICAL SECTION CONFIGURATION +* +* Note(s) : (1) Configure CPU_CFG_CRITICAL_METHOD with CPU's/compiler's critical section method : +* +* Enter/Exit critical sections by ... +* +* CPU_CRITICAL_METHOD_INT_DIS_EN Disable/Enable interrupts +* CPU_CRITICAL_METHOD_STATUS_STK Push/Pop interrupt status onto stack +* CPU_CRITICAL_METHOD_STATUS_LOCAL Save/Restore interrupt status to local variable +* +* (a) CPU_CRITICAL_METHOD_INT_DIS_EN is NOT a preferred method since it does NOT support +* multiple levels of interrupts. However, with some CPUs/compilers, this is the only +* available method. +* +* (b) CPU_CRITICAL_METHOD_STATUS_STK is one preferred method since it supports multiple +* levels of interrupts. However, this method assumes that the compiler provides C-level +* &/or assembly-level functionality for the following : +* +* ENTER CRITICAL SECTION : +* (1) Push/save interrupt status onto a local stack +* (2) Disable interrupts +* +* EXIT CRITICAL SECTION : +* (3) Pop/restore interrupt status from a local stack +* +* (c) CPU_CRITICAL_METHOD_STATUS_LOCAL is one preferred method since it supports multiple +* levels of interrupts. However, this method assumes that the compiler provides C-level +* &/or assembly-level functionality for the following : +* +* ENTER CRITICAL SECTION : +* (1) Save interrupt status into a local variable +* (2) Disable interrupts +* +* EXIT CRITICAL SECTION : +* (3) Restore interrupt status from a local variable +* +* (2) Critical section macro's most likely require inline assembly. If the compiler does NOT +* allow inline assembly in C source files, critical section macro's MUST call an assembly +* subroutine defined in a 'cpu_a.asm' file located in the following software directory : +* +* \\\\ +* +* where +* directory path for common CPU-compiler software +* directory name for specific CPU +* directory name for specific compiler +* +* (3) (a) To save/restore interrupt status, a local variable 'cpu_sr' of type 'CPU_SR' MAY need +* to be declared (e.g. if 'CPU_CRITICAL_METHOD_STATUS_LOCAL' method is configured). +* +* (1) 'cpu_sr' local variable SHOULD be declared via the CPU_SR_ALLOC() macro which, +* if used, MUST be declared following ALL other local variables (see any 'cpu.h +* CRITICAL SECTION CONFIGURATION Note #3a1'). +* +* Example : +* +* void Fnct (void) +* { +* CPU_INT08U val_08; +* CPU_INT16U val_16; +* CPU_INT32U val_32; +* CPU_SR_ALLOC(); MUST be declared after ALL other local variables +* : +* : +* } +* +* (b) Configure 'CPU_SR' data type with the appropriate-sized CPU data type large enough to +* completely store the CPU's/compiler's status word. +********************************************************************************************************* +*/ + + /* --------------- CPU CRITICAL SECTION METHODS --------------- */ +#define CPU_CRITICAL_METHOD_NONE 0u /* */ +#define CPU_CRITICAL_METHOD_INT_DIS_EN 1u /* DIS/EN ints (see Note #1a). */ +#define CPU_CRITICAL_METHOD_STATUS_STK 2u /* Push/Pop int status onto stk (see Note #1b). */ +#define CPU_CRITICAL_METHOD_STATUS_LOCAL 3u /* Save/Restore int status to local var (see Note #1c). */ + + +/* +********************************************************************************************************* +* MODULE END +* +* Note(s) : (1) See 'cpu_def.h MODULE'. +********************************************************************************************************* +*/ + +#endif /* End of CPU def module include. */ + diff --git a/Middlewares/Third_Party/Micrium/uC-LIB/Ports/ARM-Cortex-M4/GNU/lib_mem_a.s b/Middlewares/Third_Party/Micrium/uC-LIB/Ports/ARM-Cortex-M4/GNU/lib_mem_a.s new file mode 100644 index 0000000..942bbca --- /dev/null +++ b/Middlewares/Third_Party/Micrium/uC-LIB/Ports/ARM-Cortex-M4/GNU/lib_mem_a.s @@ -0,0 +1,309 @@ +@******************************************************************************************************** +@ uC/LIB +@ CUSTOM LIBRARY MODULES +@ +@ (c) Copyright 2004-2011; Micrium, Inc.; Weston, FL +@ +@ All rights reserved. Protected by international copyright laws. +@ +@ uC/LIB is provided in source form to registered licensees ONLY. It is +@ illegal to distribute this source code to any third party unless you receive +@ written permission by an authorized Micrium representative. Knowledge of +@ the source code may NOT be used to develop a similar product. +@ +@ Please help us continue to provide the Embedded community with the finest +@ software available. Your honesty is greatly appreciated. +@ +@ You can contact us at www.micrium.com. +@******************************************************************************************************** + + +@******************************************************************************************************** +@ +@ STANDARD MEMORY OPERATIONS +@ +@ ARM-Cortex-M4 +@ GNU Compiler +@ +@ Filename : lib_mem_a.s +@ Version : V1.38.01.00 +@ Programmer(s) : JDH +@ DC +@******************************************************************************************************** +@ Note(s) : (1) NO compiler-supplied standard library functions are used in library or product software. +@ +@ (a) ALL standard library functions are implemented in the custom library modules : +@ +@ (1) \\lib*.* +@ +@ (2) \\Ports\\\lib*_a.* +@ +@ where +@ directory path for custom library software +@ directory name for specific processor (CPU) +@ directory name for specific compiler +@ +@ (b) Product-specific library functions are implemented in individual products. +@ +@ (2) Assumes ARM CPU mode configured for Little Endian. +@******************************************************************************************************** + + +@******************************************************************************************************** +@ PUBLIC FUNCTIONS +@******************************************************************************************************** + +.global Mem_Copy + + +@******************************************************************************************************** +@ CODE GENERATION DIRECTIVES +@******************************************************************************************************** + +.text +.align 2 +.thumb +.syntax unified + +@$PAGE +@******************************************************************************************************** +@ Mem_Copy() +@ +@ Description : Copy data octets from one buffer to another buffer. +@ +@ Argument(s) : pdest Pointer to destination memory buffer. +@ +@ psrc Pointer to source memory buffer. +@ +@ size Number of data buffer octets to copy. +@ +@ Return(s) : none. +@ +@ Caller(s) : Application. +@ +@ Note(s) : (1) Null copies allowed (i.e. 0-octet size). +@ +@ (2) Memory buffers NOT checked for overlapping. +@ +@ (3) Modulo arithmetic is used to determine whether a memory buffer starts on a 'CPU_ALIGN' +@ address boundary. +@ +@ (4) ARM Cortex-M3 processors use a subset of the ARM Thumb-2 instruction set which does +@ NOT support 16-bit conditional branch instructions but ONLY supports 8-bit conditional +@ branch instructions. +@ +@ Therefore, branches exceeding 8-bit, signed, relative offsets : +@ +@ (a) CANNOT be implemented with conditional branches@ but ... +@ (b) MUST be implemented with non-conditional branches. +@******************************************************************************************************** + +@ void Mem_Copy (void *pdest, @ ==> R0 +@ void *psrc, @ ==> R1 +@ CPU_SIZE_T size) @ ==> R2 + +.thumb_func +Mem_Copy: + CMP R0, #0 + BNE Mem_Copy_1 + BX LR @ return if pdest == NULL + +Mem_Copy_1: + CMP R1, #0 + BNE Mem_Copy_2 + BX LR @ return if psrc == NULL + +Mem_Copy_2: + CMP R2, #0 + BNE Mem_Copy_3 + BX LR @ return if size == 0 + +Mem_Copy_3: + STMFD SP!, {R3-R12} @ save registers on stack + + +@$PAGE +Chk_Align_32: @ check if both dest & src 32-bit aligned + AND R3, R0, #0x03 + AND R4, R1, #0x03 + CMP R3, R4 + BNE Chk_Align_16 @ not 32-bit aligned, check for 16-bit alignment + + RSB R3, R3, #0x04 @ compute 1-2-3 pre-copy bytes (to align to the next 32-bit boundary) + AND R3, R3, #0x03 + +Pre_Copy_1: + CMP R3, #1 @ copy 1-2-3 bytes (to align to the next 32-bit boundary) + BCC Copy_32_1 @ start real 32-bit copy + CMP R2, #1 @ check if any more data to copy + BCS Pre_Copy_1_Cont + B Mem_Copy_END @ no more data to copy (see Note #4b) + +Pre_Copy_1_Cont: + LDRB R4, [R1], #1 + STRB R4, [R0], #1 + SUB R3, R3, #1 + SUB R2, R2, #1 + B Pre_Copy_1 + + +Chk_Align_16: @ check if both dest & src 16-bit aligned + AND R3, R0, #0x01 + AND R4, R1, #0x01 + CMP R3, R4 + BEQ Pre_Copy_2 + B Copy_08_1 @ not 16-bit aligned, start 8-bit copy (see Note #4b) + +Pre_Copy_2: + CMP R3, #1 @ copy 1 byte (to align to the next 16-bit boundary) + BCC Copy_16_1 @ start real 16-bit copy + + LDRB R4, [R1], #1 + STRB R4, [R0], #1 + SUB R3, R3, #1 + SUB R2, R2, #1 + B Pre_Copy_2 + + +Copy_32_1: + CMP R2, #360 @ Copy 9 chunks of 10 32-bit words (360 octets per loop) + BCC Copy_32_2 + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + SUB R2, R2, #360 + B Copy_32_1 + +Copy_32_2: + CMP R2, #(04*10*01) @ Copy chunks of 10 32-bit words (40 octets per loop) + BCC Copy_32_3 + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + SUB R2, R2, #(04*10*01) + B Copy_32_2 + +Copy_32_3: + CMP R2, #(04*01*01) @ Copy remaining 32-bit words + BCC Copy_16_1 + LDR R3, [R1], #4 + STR R3, [R0], #4 + SUB R2, R2, #(04*01*01) + B Copy_32_3 + +@$PAGE +Copy_16_1: + CMP R2, #(02*01*16) @ Copy chunks of 16 16-bit words (32 bytes per loop) + BCC Copy_16_2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + SUB R2, R2, #(02*01*16) + B Copy_16_1 + +Copy_16_2: + CMP R2, #(02*01*01) @ Copy remaining 16-bit words + BCC Copy_08_1 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + SUB R2, R2, #(02*01*01) + B Copy_16_2 + +@$PAGE +Copy_08_1: + CMP R2, #(01*01*16) @ Copy chunks of 16 8-bit words (16 bytes per loop) + BCC Copy_08_2 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + SUB R2, R2, #(01*01*16) + B Copy_08_1 + +Copy_08_2: + CMP R2, #(01*01*01) @ Copy remaining 8-bit words + BCC Mem_Copy_END + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + SUB R2, R2, #(01*01*01) + B Copy_08_2 + + +Mem_Copy_END: + LDMFD SP!, {R3-R12} @ restore registers from stack + BX LR @ return + + +.end + diff --git a/Middlewares/Third_Party/Micrium/uC-LIB/Ports/ARM-Cortex-M4/IAR/lib_mem_a.asm b/Middlewares/Third_Party/Micrium/uC-LIB/Ports/ARM-Cortex-M4/IAR/lib_mem_a.asm new file mode 100644 index 0000000..044d7d2 --- /dev/null +++ b/Middlewares/Third_Party/Micrium/uC-LIB/Ports/ARM-Cortex-M4/IAR/lib_mem_a.asm @@ -0,0 +1,306 @@ +;******************************************************************************************************** +; uC/LIB +; CUSTOM LIBRARY MODULES +; +; (c) Copyright 2004-2011; Micrium, Inc.; Weston, FL +; +; All rights reserved. Protected by international copyright laws. +; +; uC/LIB is provided in source form to registered licensees ONLY. It is +; illegal to distribute this source code to any third party unless you receive +; written permission by an authorized Micrium representative. Knowledge of +; the source code may NOT be used to develop a similar product. +; +; Please help us continue to provide the Embedded community with the finest +; software available. Your honesty is greatly appreciated. +; +; You can contact us at www.micrium.com. +;******************************************************************************************************** + + +;******************************************************************************************************** +; +; STANDARD MEMORY OPERATIONS +; +; ARM-Cortex-M4 +; IAR Compiler +; +; Filename : lib_mem_a.asm +; Version : V1.38.01.00 +; Programmer(s) : JDH +; BAN +;******************************************************************************************************** +; Note(s) : (1) NO compiler-supplied standard library functions are used in library or product software. +; +; (a) ALL standard library functions are implemented in the custom library modules : +; +; (1) \\lib*.* +; +; (2) \\Ports\\\lib*_a.* +; +; where +; directory path for custom library software +; directory name for specific processor (CPU) +; directory name for specific compiler +; +; (b) Product-specific library functions are implemented in individual products. +; +; (2) Assumes ARM CPU mode configured for Little Endian. +;******************************************************************************************************** + + +;******************************************************************************************************** +; PUBLIC FUNCTIONS +;******************************************************************************************************** + + PUBLIC Mem_Copy + + +;******************************************************************************************************** +; CODE GENERATION DIRECTIVES +;******************************************************************************************************** + + RSEG CODE:CODE:NOROOT(2) + + +;$PAGE +;******************************************************************************************************** +; Mem_Copy() +; +; Description : Copy data octets from one buffer to another buffer. +; +; Argument(s) : pdest Pointer to destination memory buffer. +; +; psrc Pointer to source memory buffer. +; +; size Number of data buffer octets to copy. +; +; Return(s) : none. +; +; Caller(s) : Application. +; +; Note(s) : (1) Null copies allowed (i.e. 0-octet size). +; +; (2) Memory buffers NOT checked for overlapping. +; +; (3) Modulo arithmetic is used to determine whether a memory buffer starts on a 'CPU_ALIGN' +; address boundary. +; +; (4) ARM Cortex-M3 processors use a subset of the ARM Thumb-2 instruction set which does +; NOT support 16-bit conditional branch instructions but ONLY supports 8-bit conditional +; branch instructions. +; +; Therefore, branches exceeding 8-bit, signed, relative offsets : +; +; (a) CANNOT be implemented with conditional branches; but ... +; (b) MUST be implemented with non-conditional branches. +;******************************************************************************************************** + +; void Mem_Copy (void *pdest, ; ==> R0 +; void *psrc, ; ==> R1 +; CPU_SIZE_T size) ; ==> R2 + +Mem_Copy: + CMP R0, #0 + BNE Mem_Copy_1 + BX LR ; return if pdest == NULL + +Mem_Copy_1: + CMP R1, #0 + BNE Mem_Copy_2 + BX LR ; return if psrc == NULL + +Mem_Copy_2: + CMP R2, #0 + BNE Mem_Copy_3 + BX LR ; return if size == 0 + +Mem_Copy_3: + STMFD SP!, {R3-R12} ; save registers on stack + + +;$PAGE +Chk_Align_32: ; check if both dest & src 32-bit aligned + AND R3, R0, #0x03 + AND R4, R1, #0x03 + CMP R3, R4 + BNE Chk_Align_16 ; not 32-bit aligned, check for 16-bit alignment + + RSB R3, R3, #0x04 ; compute 1-2-3 pre-copy bytes (to align to the next 32-bit boundary) + AND R3, R3, #0x03 + +Pre_Copy_1: + CMP R3, #1 ; copy 1-2-3 bytes (to align to the next 32-bit boundary) + BCC Copy_32_1 ; start real 32-bit copy + CMP R2, #1 ; check if any more data to copy + BCS Pre_Copy_1_Cont + B Mem_Copy_END ; no more data to copy (see Note #4b) + +Pre_Copy_1_Cont: + LDRB R4, [R1], #1 + STRB R4, [R0], #1 + SUB R3, R3, #1 + SUB R2, R2, #1 + B Pre_Copy_1 + + +Chk_Align_16: ; check if both dest & src 16-bit aligned + AND R3, R0, #0x01 + AND R4, R1, #0x01 + CMP R3, R4 + BEQ Pre_Copy_2 + B Copy_08_1 ; not 16-bit aligned, start 8-bit copy (see Note #4b) + +Pre_Copy_2: + CMP R3, #1 ; copy 1 byte (to align to the next 16-bit boundary) + BCC Copy_16_1 ; start real 16-bit copy + + LDRB R4, [R1], #1 + STRB R4, [R0], #1 + SUB R3, R3, #1 + SUB R2, R2, #1 + B Pre_Copy_2 + + +Copy_32_1: + CMP R2, #(04*10*09) ; Copy 9 chunks of 10 32-bit words (360 octets per loop) + BCC Copy_32_2 + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + SUB R2, R2, #(04*10*09) + B Copy_32_1 + +Copy_32_2: + CMP R2, #(04*10*01) ; Copy chunks of 10 32-bit words (40 octets per loop) + BCC Copy_32_3 + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + SUB R2, R2, #(04*10*01) + B Copy_32_2 + +Copy_32_3: + CMP R2, #(04*01*01) ; Copy remaining 32-bit words + BCC Copy_16_1 + LDR R3, [R1], #4 + STR R3, [R0], #4 + SUB R2, R2, #(04*01*01) + B Copy_32_3 + +;$PAGE +Copy_16_1: + CMP R2, #(02*01*16) ; Copy chunks of 16 16-bit words (32 bytes per loop) + BCC Copy_16_2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + SUB R2, R2, #(02*01*16) + B Copy_16_1 + +Copy_16_2: + CMP R2, #(02*01*01) ; Copy remaining 16-bit words + BCC Copy_08_1 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + SUB R2, R2, #(02*01*01) + B Copy_16_2 + +;$PAGE +Copy_08_1: + CMP R2, #(01*01*16) ; Copy chunks of 16 8-bit words (16 bytes per loop) + BCC Copy_08_2 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + SUB R2, R2, #(01*01*16) + B Copy_08_1 + +Copy_08_2: + CMP R2, #(01*01*01) ; Copy remaining 8-bit words + BCC Mem_Copy_END + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + SUB R2, R2, #(01*01*01) + B Copy_08_2 + + +Mem_Copy_END: + LDMFD SP!, {R3-R12} ; restore registers from stack + BX LR ; return + + + END + diff --git a/Middlewares/Third_Party/Micrium/uC-LIB/Ports/ARM-Cortex-M4/RealView/lib_mem_a.asm b/Middlewares/Third_Party/Micrium/uC-LIB/Ports/ARM-Cortex-M4/RealView/lib_mem_a.asm new file mode 100644 index 0000000..b9013fc --- /dev/null +++ b/Middlewares/Third_Party/Micrium/uC-LIB/Ports/ARM-Cortex-M4/RealView/lib_mem_a.asm @@ -0,0 +1,312 @@ +;******************************************************************************************************** +; uC/LIB +; CUSTOM LIBRARY MODULES +; +; (c) Copyright 2004-2011; Micrium, Inc.; Weston, FL +; +; All rights reserved. Protected by international copyright laws. +; +; uC/LIB is provided in source form to registered licensees ONLY. It is +; illegal to distribute this source code to any third party unless you receive +; written permission by an authorized Micrium representative. Knowledge of +; the source code may NOT be used to develop a similar product. +; +; Please help us continue to provide the Embedded community with the finest +; software available. Your honesty is greatly appreciated. +; +; You can contact us at www.micrium.com. +;******************************************************************************************************** + + +;******************************************************************************************************** +; +; STANDARD MEMORY OPERATIONS +; +; ARM-Cortex-M4 +; RealView Development Suite +; RealView Microcontroller Development Kit (MDK) +; ARM Developer Suite (ADS) +; Keil uVision +; +; Filename : lib_mem_a.asm +; Version : V1.38.01.00 +; Programmer(s) : JDH +; BAN +;******************************************************************************************************** +; Note(s) : (1) NO compiler-supplied standard library functions are used in library or product software. +; +; (a) ALL standard library functions are implemented in the custom library modules : +; +; (1) \\lib*.* +; +; (2) \\Ports\\\lib*_a.* +; +; where +; directory path for custom library software +; directory name for specific processor (CPU) +; directory name for specific compiler +; +; (b) Product-specific library functions are implemented in individual products. +; +; (2) Assumes ARM CPU mode configured for Little Endian. +;******************************************************************************************************** + + +;******************************************************************************************************** +; PUBLIC FUNCTIONS +;******************************************************************************************************** + + EXPORT Mem_Copy + + +;******************************************************************************************************** +; CODE GENERATION DIRECTIVES +;******************************************************************************************************** + + AREA |.text|, CODE, READONLY, ALIGN=2 + THUMB + REQUIRE8 + PRESERVE8 + + +;$PAGE +;******************************************************************************************************** +; Mem_Copy() +; +; Description : Copy data octets from one buffer to another buffer. +; +; Argument(s) : pdest Pointer to destination memory buffer. +; +; psrc Pointer to source memory buffer. +; +; size Number of data buffer octets to copy. +; +; Return(s) : none. +; +; Caller(s) : Application. +; +; Note(s) : (1) Null copies allowed (i.e. 0-octet size). +; +; (2) Memory buffers NOT checked for overlapping. +; +; (3) Modulo arithmetic is used to determine whether a memory buffer starts on a 'CPU_ALIGN' +; address boundary. +; +; (4) ARM Cortex-M3 processors use a subset of the ARM Thumb-2 instruction set which does +; NOT support 16-bit conditional branch instructions but ONLY supports 8-bit conditional +; branch instructions. +; +; Therefore, branches exceeding 8-bit, signed, relative offsets : +; +; (a) CANNOT be implemented with conditional branches; but ... +; (b) MUST be implemented with non-conditional branches. +;******************************************************************************************************** + +; void Mem_Copy (void *pdest, ; ==> R0 +; void *psrc, ; ==> R1 +; CPU_SIZE_T size) ; ==> R2 + +Mem_Copy + CMP R0, #0 + BNE Mem_Copy_1 + BX LR ; return if pdest == NULL + +Mem_Copy_1 + CMP R1, #0 + BNE Mem_Copy_2 + BX LR ; return if psrc == NULL + +Mem_Copy_2 + CMP R2, #0 + BNE Mem_Copy_3 + BX LR ; return if size == 0 + +Mem_Copy_3 + STMFD SP!, {R3-R12} ; save registers on stack + + +;$PAGE +Chk_Align_32 ; check if both dest & src 32-bit aligned + AND R3, R0, #0x03 + AND R4, R1, #0x03 + CMP R3, R4 + BNE Chk_Align_16 ; not 32-bit aligned, check for 16-bit alignment + + RSB R3, R3, #0x04 ; compute 1-2-3 pre-copy bytes (to align to the next 32-bit boundary) + AND R3, R3, #0x03 + +Pre_Copy_1 + CMP R3, #1 ; copy 1-2-3 bytes (to align to the next 32-bit boundary) + BCC Copy_32_1 ; start real 32-bit copy + CMP R2, #1 ; check if any more data to copy + BCS Pre_Copy_1_Cont + B Mem_Copy_END ; no more data to copy (see Note #4b) + +Pre_Copy_1_Cont + LDRB R4, [R1], #1 + STRB R4, [R0], #1 + SUB R3, R3, #1 + SUB R2, R2, #1 + B Pre_Copy_1 + + +Chk_Align_16 ; check if both dest & src 16-bit aligned + AND R3, R0, #0x01 + AND R4, R1, #0x01 + CMP R3, R4 + BEQ Pre_Copy_2 + B Copy_08_1 ; not 16-bit aligned, start 8-bit copy (see Note #4b) + +Pre_Copy_2 + CMP R3, #1 ; copy 1 byte (to align to the next 16-bit boundary) + BCC Copy_16_1 ; start real 16-bit copy + + LDRB R4, [R1], #1 + STRB R4, [R0], #1 + SUB R3, R3, #1 + SUB R2, R2, #1 + B Pre_Copy_2 + + +Copy_32_1 + CMP R2, #(04*10*09) ; Copy 9 chunks of 10 32-bit words (360 octets per loop) + BCC Copy_32_2 + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + SUB R2, R2, #(04*10*09) + B Copy_32_1 + +Copy_32_2 + CMP R2, #(04*10*01) ; Copy chunks of 10 32-bit words (40 octets per loop) + BCC Copy_32_3 + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + SUB R2, R2, #(04*10*01) + B Copy_32_2 + +Copy_32_3 + CMP R2, #(04*01*01) ; Copy remaining 32-bit words + BCC Copy_16_1 + LDR R3, [R1], #4 + STR R3, [R0], #4 + SUB R2, R2, #(04*01*01) + B Copy_32_3 + +;$PAGE +Copy_16_1 + CMP R2, #(02*01*16) ; Copy chunks of 16 16-bit words (32 bytes per loop) + BCC Copy_16_2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + SUB R2, R2, #(02*01*16) + B Copy_16_1 + +Copy_16_2 + CMP R2, #(02*01*01) ; Copy remaining 16-bit words + BCC Copy_08_1 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + SUB R2, R2, #(02*01*01) + B Copy_16_2 + +;$PAGE +Copy_08_1 + CMP R2, #(01*01*16) ; Copy chunks of 16 8-bit words (16 bytes per loop) + BCC Copy_08_2 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + SUB R2, R2, #(01*01*16) + B Copy_08_1 + +Copy_08_2 + CMP R2, #(01*01*01) ; Copy remaining 8-bit words + BCC Mem_Copy_END + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + SUB R2, R2, #(01*01*01) + B Copy_08_2 + + +Mem_Copy_END + LDMFD SP!, {R3-R12} ; restore registers from stack + BX LR ; return + + + END + diff --git a/Middlewares/Third_Party/Micrium/uC-LIB/lib_ascii.c b/Middlewares/Third_Party/Micrium/uC-LIB/lib_ascii.c new file mode 100644 index 0000000..52839ea --- /dev/null +++ b/Middlewares/Third_Party/Micrium/uC-LIB/lib_ascii.c @@ -0,0 +1,655 @@ +/* +********************************************************************************************************* +* uC/LIB +* CUSTOM LIBRARY MODULES +* +* (c) Copyright 2004-2014; Micrium, Inc.; Weston, FL +* +* All rights reserved. Protected by international copyright laws. +* +* uC/LIB is provided in source form to registered licensees ONLY. It is +* illegal to distribute this source code to any third party unless you receive +* written permission by an authorized Micrium representative. Knowledge of +* the source code may NOT be used to develop a similar product. +* +* Please help us continue to provide the Embedded community with the finest +* software available. Your honesty is greatly appreciated. +* +* You can find our product's user manual, API reference, release notes and +* more information at: https://doc.micrium.com +* +* You can contact us at: http://www.micrium.com +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* +* ASCII CHARACTER OPERATIONS +* +* Filename : lib_ascii.c +* Version : V1.38.01 +* Programmer(s) : BAN +* ITJ +********************************************************************************************************* +* Note(s) : (1) NO compiler-supplied standard library functions are used in library or product software. +* +* (a) ALL standard library functions are implemented in the custom library modules : +* +* (1) \\lib_*.* +* +* (2) \\Ports\\\lib*_a.* +* +* where +* directory path for custom library software +* directory name for specific processor (CPU) +* directory name for specific compiler +* +* (b) Product-specific library functions are implemented in individual products. +* +* +* (2) (a) ECMA-6 '7-Bit coded Character Set' (6th edition), which corresponds to the +* 3rd edition of ISO 646, specifies several versions of a 7-bit character set : +* +* (1) THE GENERAL VERSION, which allows characters at 0x23 and 0x24 to be given a +* set alternate form and allows the characters 0x40, 0x5B, 0x5D, 0x60, 0x7B & +* 0x7D to be assigned a "unique graphic character" or to be declared as unused. +* All other characters are explicitly specified. +* +* (2) THE INTERNATIONAL REFERENCE VERSION, which explicitly specifies all characters +* in the 7-bit character set. +* +* (3) NATIONAL & APPLICATION-ORIENTED VERSIONS, which may be derived from the +* standard in specified ways. +* +* (b) The character set represented in this file reproduces the Internation Reference +* Version. This is identical to the 7-bit character set which occupies Unicode +* characters 0x0000 through 0x007F. The character names are taken from v5.0 of the +* Unicode specification, with certain abbreviations so that the resulting #define +* names will not violate ANSI C naming restriction : +* +* (1) For the Latin capital & lowercase letters, the name components 'LETTER_CAPITAL' +* & 'LETTER_SMALL' are replaced by 'UPPER' & 'LOWER', respectively. +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* INCLUDE FILES +********************************************************************************************************* +*/ + +#define MICRIUM_SOURCE +#define LIB_ASCII_MODULE +#include + + +/* +********************************************************************************************************* +* LOCAL DEFINES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL CONSTANTS +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL DATA TYPES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL TABLES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL GLOBAL VARIABLES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL FUNCTION PROTOTYPES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL CONFIGURATION ERRORS +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* ASCII_IsAlpha() +* +* Description : Determine whether a character is an alphabetic character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is an alphabetic character. +* +* DEF_NO, if character is NOT an alphabetic character. +* +* Caller(s) : Application. +* +* Note(s) : (1) ISO/IEC 9899:TC2, Section 7.4.1.2.(2) states that "isalpha() returns true only for the +* characters for which isupper() or islower() is true". +********************************************************************************************************* +*/ + +CPU_BOOLEAN ASCII_IsAlpha (CPU_CHAR c) +{ + CPU_BOOLEAN alpha; + + + alpha = ASCII_IS_ALPHA(c); + + return (alpha); +} + + +/* +********************************************************************************************************* +* ASCII_IsAlphaNum() +* +* Description : Determine whether a character is an alphanumeric character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is an alphanumeric character. +* +* DEF_NO, if character is NOT an alphanumeric character. +* +* Caller(s) : Application. +* +* Note(s) : (1) ISO/IEC 9899:TC2, Section 7.4.1.1.(2) states that "isalnum() ... tests for any character +* for which isalpha() or isdigit() is true". +********************************************************************************************************* +*/ + +CPU_BOOLEAN ASCII_IsAlphaNum (CPU_CHAR c) +{ + CPU_BOOLEAN alpha_num; + + + alpha_num = ASCII_IS_ALPHA_NUM(c); + + return (alpha_num); +} + + +/* +********************************************************************************************************* +* ASCII_IsLower() +* +* Description : Determine whether a character is a lowercase alphabetic character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is a lowercase alphabetic character. +* +* DEF_NO, if character is NOT a lowercase alphabetic character. +* +* Caller(s) : Application. +* +* Note(s) : (1) ISO/IEC 9899:TC2, Section 7.4.1.7.(2) states that "islower() returns true only for +* the lowercase letters". +********************************************************************************************************* +*/ + +CPU_BOOLEAN ASCII_IsLower (CPU_CHAR c) +{ + CPU_BOOLEAN lower; + + + lower = ASCII_IS_LOWER(c); + + return (lower); +} + + +/* +********************************************************************************************************* +* ASCII_IsUpper() +* +* Description : Determine whether a character is an uppercase alphabetic character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is an uppercase alphabetic character. +* +* DEF_NO, if character is NOT an uppercase alphabetic character. +* +* Caller(s) : Application. +* +* Note(s) : (1) ISO/IEC 9899:TC2, Section 7.4.1.11.(2) states that "isupper() returns true only for +* the uppercase letters". +********************************************************************************************************* +*/ + +CPU_BOOLEAN ASCII_IsUpper (CPU_CHAR c) +{ + CPU_BOOLEAN upper; + + + upper = ASCII_IS_UPPER(c); + + return (upper); +} + + +/* +********************************************************************************************************* +* ASCII_IsDig() +* +* Description : Determine whether a character is a decimal-digit character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is a decimal-digit character. +* +* DEF_NO, if character is NOT a decimal-digit character. +* +* Caller(s) : Application. +* +* Note(s) : (1) ISO/IEC 9899:TC2, Section 7.4.1.5.(2) states that "isdigit() ... tests for any +* decimal-digit character". +********************************************************************************************************* +*/ + +CPU_BOOLEAN ASCII_IsDig (CPU_CHAR c) +{ + CPU_BOOLEAN dig; + + + dig = ASCII_IS_DIG(c); + + return (dig); +} + + +/* +********************************************************************************************************* +* ASCII_IsDigOct() +* +* Description : Determine whether a character is an octal-digit character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is an octal-digit character. +* +* DEF_NO, if character is NOT an octal-digit character. +* +* Caller(s) : Application. +* +* Note(s) : none. +********************************************************************************************************* +*/ + +CPU_BOOLEAN ASCII_IsDigOct (CPU_CHAR c) +{ + CPU_BOOLEAN dig_oct; + + + dig_oct = ASCII_IS_DIG_OCT(c); + + return (dig_oct); +} + + +/* +********************************************************************************************************* +* ASCII_IsDigHex() +* +* Description : Determine whether a character is a hexadecimal-digit character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is a hexadecimal-digit character. +* +* DEF_NO, if character is NOT a hexadecimal-digit character. +* +* Caller(s) : Application. +* +* Note(s) : (1) ISO/IEC 9899:TC2, Section 7.4.1.12.(2) states that "isxdigit() ... tests for any +* hexadecimal-digit character". +********************************************************************************************************* +*/ + +CPU_BOOLEAN ASCII_IsDigHex (CPU_CHAR c) +{ + CPU_BOOLEAN dig_hex; + + + dig_hex = ASCII_IS_DIG_HEX(c); + + return (dig_hex); +} + + +/* +********************************************************************************************************* +* ASCII_IsBlank() +* +* Description : Determine whether a character is a standard blank character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is a standard blank character. +* +* DEF_NO, if character is NOT a standard blank character. +* +* Caller(s) : Application. +* +* Note(s) : (1) (a) ISO/IEC 9899:TC2, Section 7.4.1.3.(2) states that "isblank() returns true only for +* the standard blank characters". +* +* (b) ISO/IEC 9899:TC2, Section 7.4.1.3.(2) defines "the standard blank characters" as +* the "space (' '), and horizontal tab ('\t')". +********************************************************************************************************* +*/ + +CPU_BOOLEAN ASCII_IsBlank (CPU_CHAR c) +{ + CPU_BOOLEAN blank; + + + blank = ASCII_IS_BLANK(c); + + return (blank); +} + + +/* +********************************************************************************************************* +* ASCII_IsSpace() +* +* Description : Determine whether a character is a white-space character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is a white-space character. +* +* DEF_NO, if character is NOT a white-space character. +* +* Caller(s) : Application. +* +* Note(s) : (1) (a) ISO/IEC 9899:TC2, Section 7.4.1.10.(2) states that "isspace() returns true only +* for the standard white-space characters". +* +* (b) ISO/IEC 9899:TC2, Section 7.4.1.10.(2) defines "the standard white-space characters" +* as the "space (' '), form feed ('\f'), new-line ('\n'), carriage return ('\r'), +* horizontal tab ('\t'), and vertical tab ('\v')". +********************************************************************************************************* +*/ + +CPU_BOOLEAN ASCII_IsSpace (CPU_CHAR c) +{ + CPU_BOOLEAN space; + + + space = ASCII_IS_SPACE(c); + + return (space); +} + + +/* +********************************************************************************************************* +* ASCII_IsPrint() +* +* Description : Determine whether a character is a printing character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is a printing character. +* +* DEF_NO, if character is NOT a printing character. +* +* Caller(s) : Application. +* +* Note(s) : (1) (a) ISO/IEC 9899:TC2, Section 7.4.1.8.(2) states that "isprint() ... tests for any +* printing character including space (' ')". +* +* (b) ISO/IEC 9899:TC2, Section 7.4.(3), Note 169, states that in "the seven-bit US +* ASCII character set, the printing characters are those whose values lie from +* 0x20 (space) through 0x7E (tilde)". +********************************************************************************************************* +*/ + +CPU_BOOLEAN ASCII_IsPrint (CPU_CHAR c) +{ + CPU_BOOLEAN print; + + + print = ASCII_IS_PRINT(c); + + return (print); +} + + +/* +********************************************************************************************************* +* ASCII_IsGraph() +* +* Description : Determine whether a character is any printing character except a space character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is a graphic character. +* +* DEF_NO, if character is NOT a graphic character. +* +* Caller(s) : Application. +* +* Note(s) : (1) (a) ISO/IEC 9899:TC2, Section 7.4.1.6.(2) states that "isgraph() ... tests for any +* printing character except space (' ')". +* +* (b) ISO/IEC 9899:TC2, Section 7.4.(3), Note 169, states that in "the seven-bit US +* ASCII character set, the printing characters are those whose values lie from +* 0x20 (space) through 0x7E (tilde)". +********************************************************************************************************* +*/ + +CPU_BOOLEAN ASCII_IsGraph (CPU_CHAR c) +{ + CPU_BOOLEAN graph; + + + graph = ASCII_IS_GRAPH(c); + + return (graph); +} + + +/* +********************************************************************************************************* +* ASCII_IsPunct() +* +* Description : Determine whether a character is a punctuation character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is a punctuation character. +* +* DEF_NO, if character is NOT a punctuation character. +* +* Caller(s) : Application. +* +* Note(s) : (1) ISO/IEC 9899:TC2, Section 7.4.1.9.(2) states that "ispunct() returns true for every +* printing character for which neither isspace() nor isalnum() is true". +********************************************************************************************************* +*/ + +CPU_BOOLEAN ASCII_IsPunct (CPU_CHAR c) +{ + CPU_BOOLEAN punct; + + + punct = ASCII_IS_PUNCT(c); + + return (punct); +} + + +/* +********************************************************************************************************* +* ASCII_IsCtrl() +* +* Description : Determine whether a character is a control character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is a control character. +* +* DEF_NO, if character is NOT a control character. +* +* Caller(s) : Application. +* +* Note(s) : (1) (a) ISO/IEC 9899:TC2, Section 7.4.1.4.(2) states that "iscntrl() ... tests for any +* control character". +* +* (b) ISO/IEC 9899:TC2, Section 7.4.(3), Note 169, states that in "the seven-bit US +* ASCII character set, ... the control characters are those whose values lie from +* 0 (NUL) through 0x1F (US), and the character 0x7F (DEL)". +********************************************************************************************************* +*/ + +CPU_BOOLEAN ASCII_IsCtrl (CPU_CHAR c) +{ + CPU_BOOLEAN ctrl; + + + ctrl = ASCII_IS_CTRL(c); + + return (ctrl); +} + + +/* +********************************************************************************************************* +* ASCII_ToLower() +* +* Description : Convert uppercase alphabetic character to its corresponding lowercase alphabetic character. +* +* Argument(s) : c Character to convert. +* +* Return(s) : Lowercase equivalent of 'c', if character 'c' is an uppercase character (see Note #1b1). +* +* Character 'c', otherwise (see Note #1b2). +* +* Caller(s) : Application. +* +* Note(s) : (1) (a) ISO/IEC 9899:TC2, Section 7.4.2.1.(2) states that "tolower() ... converts an +* uppercase letter to a corresponding lowercase letter". +* +* (b) ISO/IEC 9899:TC2, Section 7.4.2.1.(3) states that : +* +* (1) (A) "if the argument is a character for which isupper() is true and there are +* one or more corresponding characters ... for which islower() is true," ... +* (B) "tolower() ... returns one of the corresponding characters;" ... +* +* (2) "otherwise, the argument is returned unchanged." +********************************************************************************************************* +*/ + +CPU_CHAR ASCII_ToLower (CPU_CHAR c) +{ + CPU_CHAR lower; + + + lower = ASCII_TO_LOWER(c); + + return (lower); +} + + +/* +********************************************************************************************************* +* ASCII_ToUpper() +* +* Description : Convert lowercase alphabetic character to its corresponding uppercase alphabetic character. +* +* Argument(s) : c Character to convert. +* +* Return(s) : Uppercase equivalent of 'c', if character 'c' is a lowercase character (see Note #1b1). +* +* Character 'c', otherwise (see Note #1b2). +* +* Caller(s) : Application. +* +* Note(s) : (1) (a) ISO/IEC 9899:TC2, Section 7.4.2.2.(2) states that "toupper() ... converts a +* lowercase letter to a corresponding uppercase letter". +* +* (b) ISO/IEC 9899:TC2, Section 7.4.2.2.(3) states that : +* +* (1) (A) "if the argument is a character for which islower() is true and there are +* one or more corresponding characters ... for which isupper() is true," ... +* (B) "toupper() ... returns one of the corresponding characters;" ... +* +* (2) "otherwise, the argument is returned unchanged." +********************************************************************************************************* +*/ + +CPU_CHAR ASCII_ToUpper (CPU_CHAR c) +{ + CPU_CHAR upper; + + + upper = ASCII_TO_UPPER(c); + + return (upper); +} + + +/* +********************************************************************************************************* +* ASCII_Cmp() +* +* Description : Determine if two characters are identical (case-insensitive). +* +* Argument(s) : c1 First character. +* +* c2 Second character. +* +* Return(s) : DEF_YES, if the characters are identical. +* +* DEF_NO, if the characters are NOT identical. +* +* Caller(s) : Application. +* +* Note(s) : none. +********************************************************************************************************* +*/ + +CPU_BOOLEAN ASCII_Cmp (CPU_CHAR c1, + CPU_CHAR c2) +{ + CPU_CHAR c1_upper; + CPU_CHAR c2_upper; + CPU_BOOLEAN cmp; + + + c1_upper = ASCII_ToUpper(c1); + c2_upper = ASCII_ToUpper(c2); + cmp = (c1_upper == c2_upper) ? (DEF_YES) : (DEF_NO); + + return (cmp); +} + diff --git a/Middlewares/Third_Party/Micrium/uC-LIB/lib_ascii.h b/Middlewares/Third_Party/Micrium/uC-LIB/lib_ascii.h new file mode 100644 index 0000000..c3d484f --- /dev/null +++ b/Middlewares/Third_Party/Micrium/uC-LIB/lib_ascii.h @@ -0,0 +1,842 @@ +/* +********************************************************************************************************* +* uC/LIB +* CUSTOM LIBRARY MODULES +* +* (c) Copyright 2004-2014; Micrium, Inc.; Weston, FL +* +* All rights reserved. Protected by international copyright laws. +* +* uC/LIB is provided in source form to registered licensees ONLY. It is +* illegal to distribute this source code to any third party unless you receive +* written permission by an authorized Micrium representative. Knowledge of +* the source code may NOT be used to develop a similar product. +* +* Please help us continue to provide the Embedded community with the finest +* software available. Your honesty is greatly appreciated. +* +* You can find our product's user manual, API reference, release notes and +* more information at: https://doc.micrium.com +* +* You can contact us at: http://www.micrium.com +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* +* ASCII CHARACTER OPERATIONS +* +* Filename : lib_ascii.h +* Version : V1.38.01 +* Programmer(s) : BAN +********************************************************************************************************* +* Note(s) : (1) NO compiler-supplied standard library functions are used in library or product software. +* +* (a) ALL standard library functions are implemented in the custom library modules : +* +* (1) \\lib_*.* +* +* (2) \\Ports\\\lib*_a.* +* +* where +* directory path for custom library software +* directory name for specific processor (CPU) +* directory name for specific compiler +* +* (b) Product-specific library functions are implemented in individual products. +* +* +* (2) (a) ECMA-6 '7-Bit coded Character Set' (6th edition), which corresponds to the +* 3rd edition of ISO 646, specifies several versions of a 7-bit character set : +* +* (1) THE GENERAL VERSION, which allows characters at 0x23 and 0x24 to be given a +* set alternate form and allows the characters 0x40, 0x5B, 0x5D, 0x60, 0x7B & +* 0x7D to be assigned a "unique graphic character" or to be declared as unused. +* All other characters are explicitly specified. +* +* (2) THE INTERNATIONAL REFERENCE VERSION, which explicitly specifies all characters +* in the 7-bit character set. +* +* (3) NATIONAL & APPLICATION-ORIENTED VERSIONS, which may be derived from the +* standard in specified ways. +* +* (b) The character set represented in this file reproduces the Internation Reference +* Version. This is identical to the 7-bit character set which occupies Unicode +* characters 0x0000 through 0x007F. The character names are taken from v5.0 of the +* Unicode specification, with certain abbreviations so that the resulting #define +* names will not violate ANSI C naming restriction : +* +* (1) For the Latin capital & lowercase letters, the name components 'LETTER_CAPITAL' +* & 'LETTER_SMALL' are replaced by 'UPPER' & 'LOWER', respectively. +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* MODULE +* +* Note(s) : (1) This ASCII library header file is protected from multiple pre-processor inclusion through +* use of the ASCII library module present pre-processor macro definition. +********************************************************************************************************* +*/ + +#ifndef LIB_ASCII_MODULE_PRESENT /* See Note #1. */ +#define LIB_ASCII_MODULE_PRESENT + + +/* +********************************************************************************************************* +* INCLUDE FILES +* +* Note(s) : (1) The custom library software files are located in the following directories : +* +* (a) \\lib_*.* +* +* where +* directory path for custom library software +* +* (2) CPU-configuration software files are located in the following directories : +* +* (a) \\cpu_*.* +* (b) \\\\cpu*.* +* +* where +* directory path for common CPU-compiler software +* directory name for specific processor (CPU) +* directory name for specific compiler +* +* (3) Compiler MUST be configured to include as additional include path directories : +* +* (a) '\\' directory See Note #1a +* +* (b) (1) '\\' directory See Note #2a +* (2) '\\\\' directory See Note #2b +* +* (4) NO compiler-supplied standard library functions SHOULD be used. +********************************************************************************************************* +*/ + +#include +#include + + +/* +********************************************************************************************************* +* EXTERNS +********************************************************************************************************* +*/ + +#ifdef LIB_ASCII_MODULE +#define LIB_ASCII_EXT +#else +#define LIB_ASCII_EXT extern +#endif + + +/* +********************************************************************************************************* +* DEFINES +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* ASCII CHARACTER DEFINES +********************************************************************************************************* +*/ + + /* -------------------- C0 CONTROLS ------------------- */ +#define ASCII_CHAR_NULL 0x00 /* '\0' */ +#define ASCII_CHAR_START_OF_HEADING 0x01 +#define ASCII_CHAR_START_OF_TEXT 0x02 +#define ASCII_CHAR_END_OF_TEXT 0x03 +#define ASCII_CHAR_END_OF_TRANSMISSION 0x04 +#define ASCII_CHAR_ENQUIRY 0x05 +#define ASCII_CHAR_ACKNOWLEDGE 0x06 +#define ASCII_CHAR_BELL 0x07 /* '\a' */ +#define ASCII_CHAR_BACKSPACE 0x08 /* '\b' */ +#define ASCII_CHAR_CHARACTER_TABULATION 0x09 /* '\t' */ +#define ASCII_CHAR_LINE_FEED 0x0A /* '\n' */ +#define ASCII_CHAR_LINE_TABULATION 0x0B /* '\v' */ +#define ASCII_CHAR_FORM_FEED 0x0C /* '\f' */ +#define ASCII_CHAR_CARRIAGE_RETURN 0x0D /* '\r' */ +#define ASCII_CHAR_SHIFT_OUT 0x0E +#define ASCII_CHAR_SHIFT_IN 0x0F +#define ASCII_CHAR_DATA_LINK_ESCAPE 0x10 +#define ASCII_CHAR_DEVICE_CONTROL_ONE 0x11 +#define ASCII_CHAR_DEVICE_CONTROL_TWO 0x12 +#define ASCII_CHAR_DEVICE_CONTROL_THREE 0x13 +#define ASCII_CHAR_DEVICE_CONTROL_FOUR 0x14 +#define ASCII_CHAR_NEGATIVE_ACKNOWLEDGE 0x15 +#define ASCII_CHAR_SYNCHRONOUS_IDLE 0x16 +#define ASCII_CHAR_END_OF_TRANSMISSION_BLOCK 0x17 +#define ASCII_CHAR_CANCEL 0x18 +#define ASCII_CHAR_END_OF_MEDIUM 0x19 +#define ASCII_CHAR_SUBSITUTE 0x1A +#define ASCII_CHAR_ESCAPE 0x1B +#define ASCII_CHAR_INFO_SEPARATOR_FOUR 0x1C +#define ASCII_CHAR_INFO_SEPARATOR_THREE 0x1D +#define ASCII_CHAR_INFO_SEPARATOR_TWO 0x1E +#define ASCII_CHAR_INFO_SEPARATOR_ONE 0x1F + +#define ASCII_CHAR_NUL ASCII_CHAR_NULL +#define ASCII_CHAR_SOH ASCII_CHAR_START_OF_HEADING +#define ASCII_CHAR_START_HEADING ASCII_CHAR_START_OF_HEADING +#define ASCII_CHAR_STX ASCII_CHAR_START_OF_TEXT +#define ASCII_CHAR_START_TEXT ASCII_CHAR_START_OF_TEXT +#define ASCII_CHAR_ETX ASCII_CHAR_END_OF_TEXT +#define ASCII_CHAR_END_TEXT ASCII_CHAR_END_OF_TEXT +#define ASCII_CHAR_EOT ASCII_CHAR_END_OF_TRANSMISSION +#define ASCII_CHAR_END_TRANSMISSION ASCII_CHAR_END_OF_TRANSMISSION +#define ASCII_CHAR_ENQ ASCII_CHAR_ENQUIRY +#define ASCII_CHAR_ACK ASCII_CHAR_ACKNOWLEDGE +#define ASCII_CHAR_BEL ASCII_CHAR_BELL +#define ASCII_CHAR_BS ASCII_CHAR_BACKSPACE +#define ASCII_CHAR_HT ASCII_CHAR_CHARACTER_TABULATION +#define ASCII_CHAR_TAB ASCII_CHAR_CHARACTER_TABULATION +#define ASCII_CHAR_LF ASCII_CHAR_LINE_FEED +#define ASCII_CHAR_VT ASCII_CHAR_LINE_TABULATION +#define ASCII_CHAR_FF ASCII_CHAR_FORM_FEED +#define ASCII_CHAR_CR ASCII_CHAR_CARRIAGE_RETURN +#define ASCII_CHAR_SO ASCII_CHAR_SHIFT_OUT +#define ASCII_CHAR_SI ASCII_CHAR_SHIFT_IN +#define ASCII_CHAR_DLE ASCII_CHAR_DATA_LINK_ESCAPE +#define ASCII_CHAR_DC1 ASCII_CHAR_DEVICE_CONTROL_ONE +#define ASCII_CHAR_DC2 ASCII_CHAR_DEVICE_CONTROL_TWO +#define ASCII_CHAR_DC3 ASCII_CHAR_DEVICE_CONTROL_THREE +#define ASCII_CHAR_DC4 ASCII_CHAR_DEVICE_CONTROL_FOUR +#define ASCII_CHAR_DEV_CTRL_ONE ASCII_CHAR_DEVICE_CONTROL_ONE +#define ASCII_CHAR_DEV_CTRL_TWO ASCII_CHAR_DEVICE_CONTROL_TWO +#define ASCII_CHAR_DEV_CTRL_THREE ASCII_CHAR_DEVICE_CONTROL_THREE +#define ASCII_CHAR_DEV_CTRL_FOUR ASCII_CHAR_DEVICE_CONTROL_FOUR +#define ASCII_CHAR_NAK ASCII_CHAR_NEGATIVE_ACKNOWLEDGE +#define ASCII_CHAR_NEG_ACK ASCII_CHAR_NEGATIVE_ACKNOWLEDGE +#define ASCII_CHAR_SYN ASCII_CHAR_SYNCHRONOUS_IDLE +#define ASCII_CHAR_SYNC_IDLE ASCII_CHAR_SYNCHRONOUS_IDLE +#define ASCII_CHAR_ETB ASCII_CHAR_END_OF_TRANSMISSION_BLOCK +#define ASCII_CHAR_END_TRANSMISSION_BLK ASCII_CHAR_END_OF_TRANSMISSION_BLOCK +#define ASCII_CHAR_CAN ASCII_CHAR_CANCEL +#define ASCII_CHAR_EM ASCII_CHAR_END_OF_MEDIUM +#define ASCII_CHAR_END_MEDIUM ASCII_CHAR_END_OF_MEDIUM +#define ASCII_CHAR_SUB ASCII_CHAR_SUBSITUTE +#define ASCII_CHAR_ESC ASCII_CHAR_ESCAPE +#define ASCII_CHAR_IS1 ASCII_CHAR_INFO_SEPARATOR_ONE +#define ASCII_CHAR_IS2 ASCII_CHAR_INFO_SEPARATOR_TWO +#define ASCII_CHAR_IS3 ASCII_CHAR_INFO_SEPARATOR_THREE +#define ASCII_CHAR_IS4 ASCII_CHAR_INFO_SEPARATOR_FOUR + + + /* ------------ ASCII PUNCTUATION & SYMBOLS ----------- */ +#define ASCII_CHAR_SPACE 0x20 /* ' ' */ +#define ASCII_CHAR_EXCLAMATION_MARK 0x21 /* '!' */ +#define ASCII_CHAR_QUOTATION_MARK 0x22 /* '\"' */ +#define ASCII_CHAR_NUMBER_SIGN 0x23 /* '#' */ +#define ASCII_CHAR_DOLLAR_SIGN 0x24 /* '$' */ +#define ASCII_CHAR_PERCENTAGE_SIGN 0x25 /* '%' */ +#define ASCII_CHAR_AMPERSAND 0x26 /* '&' */ +#define ASCII_CHAR_APOSTROPHE 0x27 /* '\'' */ +#define ASCII_CHAR_LEFT_PARENTHESIS 0x28 /* '(' */ +#define ASCII_CHAR_RIGHT_PARENTHESIS 0x29 /* ')' */ +#define ASCII_CHAR_ASTERISK 0x2A /* '*' */ +#define ASCII_CHAR_PLUS_SIGN 0x2B /* '+' */ +#define ASCII_CHAR_COMMA 0x2C /* ',' */ +#define ASCII_CHAR_HYPHEN_MINUS 0x2D /* '-' */ +#define ASCII_CHAR_FULL_STOP 0x2E /* '.' */ +#define ASCII_CHAR_SOLIDUS 0x2F /* '/' */ + +#define ASCII_CHAR_PAREN_LEFT ASCII_CHAR_LEFT_PARENTHESIS +#define ASCII_CHAR_PAREN_RIGHT ASCII_CHAR_RIGHT_PARENTHESIS + + + /* ------------------- ASCII DIGITS ------------------- */ +#define ASCII_CHAR_DIGIT_ZERO 0x30 /* '0' */ +#define ASCII_CHAR_DIGIT_ONE 0x31 /* '1' */ +#define ASCII_CHAR_DIGIT_TWO 0x32 /* '2' */ +#define ASCII_CHAR_DIGIT_THREE 0x33 /* '3' */ +#define ASCII_CHAR_DIGIT_FOUR 0x34 /* '4' */ +#define ASCII_CHAR_DIGIT_FIVE 0x35 /* '5' */ +#define ASCII_CHAR_DIGIT_SIX 0x36 /* '6' */ +#define ASCII_CHAR_DIGIT_SEVEN 0x37 /* '7' */ +#define ASCII_CHAR_DIGIT_EIGHT 0x38 /* '8' */ +#define ASCII_CHAR_DIGIT_NINE 0x39 /* '9' */ + +#define ASCII_CHAR_DIG_ZERO ASCII_CHAR_DIGIT_ZERO +#define ASCII_CHAR_DIG_ONE ASCII_CHAR_DIGIT_ONE +#define ASCII_CHAR_DIG_TWO ASCII_CHAR_DIGIT_TWO +#define ASCII_CHAR_DIG_THREE ASCII_CHAR_DIGIT_THREE +#define ASCII_CHAR_DIG_FOUR ASCII_CHAR_DIGIT_FOUR +#define ASCII_CHAR_DIG_FIVE ASCII_CHAR_DIGIT_FIVE +#define ASCII_CHAR_DIG_SIX ASCII_CHAR_DIGIT_SIX +#define ASCII_CHAR_DIG_SEVEN ASCII_CHAR_DIGIT_SEVEN +#define ASCII_CHAR_DIG_EIGHT ASCII_CHAR_DIGIT_EIGHT +#define ASCII_CHAR_DIG_NINE ASCII_CHAR_DIGIT_NINE + + + /* ------------ ASCII PUNCTUATION & SYMBOLS ----------- */ +#define ASCII_CHAR_COLON 0x3A /* ':' */ +#define ASCII_CHAR_SEMICOLON 0x3B /* ';' */ +#define ASCII_CHAR_LESS_THAN_SIGN 0x3C /* '<' */ +#define ASCII_CHAR_EQUALS_SIGN 0x3D /* '=' */ +#define ASCII_CHAR_GREATER_THAN_SIGN 0x3E /* '>' */ +#define ASCII_CHAR_QUESTION_MARK 0x3F /* '\?' */ +#define ASCII_CHAR_COMMERCIAL_AT 0x40 /* '@' */ + +#define ASCII_CHAR_AT_SIGN ASCII_CHAR_COMMERCIAL_AT + + + /* ------------- UPPERCASE LATIN ALPHABET ------------- */ +#define ASCII_CHAR_LATIN_UPPER_A 0x41 /* 'A' */ +#define ASCII_CHAR_LATIN_UPPER_B 0x42 /* 'B' */ +#define ASCII_CHAR_LATIN_UPPER_C 0x43 /* 'C' */ +#define ASCII_CHAR_LATIN_UPPER_D 0x44 /* 'D' */ +#define ASCII_CHAR_LATIN_UPPER_E 0x45 /* 'E' */ +#define ASCII_CHAR_LATIN_UPPER_F 0x46 /* 'F' */ +#define ASCII_CHAR_LATIN_UPPER_G 0x47 /* 'G' */ +#define ASCII_CHAR_LATIN_UPPER_H 0x48 /* 'H' */ +#define ASCII_CHAR_LATIN_UPPER_I 0x49 /* 'I' */ +#define ASCII_CHAR_LATIN_UPPER_J 0x4A /* 'J' */ +#define ASCII_CHAR_LATIN_UPPER_K 0x4B /* 'K' */ +#define ASCII_CHAR_LATIN_UPPER_L 0x4C /* 'L' */ +#define ASCII_CHAR_LATIN_UPPER_M 0x4D /* 'M' */ +#define ASCII_CHAR_LATIN_UPPER_N 0x4E /* 'N' */ +#define ASCII_CHAR_LATIN_UPPER_O 0x4F /* 'O' */ +#define ASCII_CHAR_LATIN_UPPER_P 0x50 /* 'P' */ +#define ASCII_CHAR_LATIN_UPPER_Q 0x51 /* 'Q' */ +#define ASCII_CHAR_LATIN_UPPER_R 0x52 /* 'R' */ +#define ASCII_CHAR_LATIN_UPPER_S 0x53 /* 'S' */ +#define ASCII_CHAR_LATIN_UPPER_T 0x54 /* 'T' */ +#define ASCII_CHAR_LATIN_UPPER_U 0x55 /* 'U' */ +#define ASCII_CHAR_LATIN_UPPER_V 0x56 /* 'V' */ +#define ASCII_CHAR_LATIN_UPPER_W 0x57 /* 'W' */ +#define ASCII_CHAR_LATIN_UPPER_X 0x58 /* 'X' */ +#define ASCII_CHAR_LATIN_UPPER_Y 0x59 /* 'Y' */ +#define ASCII_CHAR_LATIN_UPPER_Z 0x5A /* 'Z' */ + + + /* ------------ ASCII PUNCTUATION & SYMBOLS ----------- */ +#define ASCII_CHAR_LEFT_SQUARE_BRACKET 0x5B /* '[' */ +#define ASCII_CHAR_REVERSE_SOLIDUS 0x5C /* '\\' */ +#define ASCII_CHAR_RIGHT_SQUARE_BRACKET 0x5D /* ']' */ +#define ASCII_CHAR_CIRCUMFLEX_ACCENT 0x5E /* '^' */ +#define ASCII_CHAR_LOW_LINE 0x5F /* '_' */ +#define ASCII_CHAR_GRAVE_ACCENT 0x60 /* '`' */ + +#define ASCII_CHAR_BRACKET_SQUARE_LEFT ASCII_CHAR_LEFT_SQUARE_BRACKET +#define ASCII_CHAR_BRACKET_SQUARE_RIGHT ASCII_CHAR_RIGHT_SQUARE_BRACKET + + + /* ------------- LOWERCASE LATIN ALPHABET ------------- */ +#define ASCII_CHAR_LATIN_LOWER_A 0x61 /* 'a' */ +#define ASCII_CHAR_LATIN_LOWER_B 0x62 /* 'b' */ +#define ASCII_CHAR_LATIN_LOWER_C 0x63 /* 'c' */ +#define ASCII_CHAR_LATIN_LOWER_D 0x64 /* 'd' */ +#define ASCII_CHAR_LATIN_LOWER_E 0x65 /* 'e' */ +#define ASCII_CHAR_LATIN_LOWER_F 0x66 /* 'f' */ +#define ASCII_CHAR_LATIN_LOWER_G 0x67 /* 'g' */ +#define ASCII_CHAR_LATIN_LOWER_H 0x68 /* 'h' */ +#define ASCII_CHAR_LATIN_LOWER_I 0x69 /* 'i' */ +#define ASCII_CHAR_LATIN_LOWER_J 0x6A /* 'j' */ +#define ASCII_CHAR_LATIN_LOWER_K 0x6B /* 'k' */ +#define ASCII_CHAR_LATIN_LOWER_L 0x6C /* 'l' */ +#define ASCII_CHAR_LATIN_LOWER_M 0x6D /* 'm' */ +#define ASCII_CHAR_LATIN_LOWER_N 0x6E /* 'n' */ +#define ASCII_CHAR_LATIN_LOWER_O 0x6F /* 'o' */ +#define ASCII_CHAR_LATIN_LOWER_P 0x70 /* 'p' */ +#define ASCII_CHAR_LATIN_LOWER_Q 0x71 /* 'q' */ +#define ASCII_CHAR_LATIN_LOWER_R 0x72 /* 'r' */ +#define ASCII_CHAR_LATIN_LOWER_S 0x73 /* 's' */ +#define ASCII_CHAR_LATIN_LOWER_T 0x74 /* 't' */ +#define ASCII_CHAR_LATIN_LOWER_U 0x75 /* 'u' */ +#define ASCII_CHAR_LATIN_LOWER_V 0x76 /* 'v' */ +#define ASCII_CHAR_LATIN_LOWER_W 0x77 /* 'w' */ +#define ASCII_CHAR_LATIN_LOWER_X 0x78 /* 'x' */ +#define ASCII_CHAR_LATIN_LOWER_Y 0x79 /* 'y' */ +#define ASCII_CHAR_LATIN_LOWER_Z 0x7A /* 'z' */ + + + /* ------------ ASCII PUNCTUATION & SYMBOLS ----------- */ +#define ASCII_CHAR_LEFT_CURLY_BRACKET 0x7B /* '{' */ +#define ASCII_CHAR_VERTICAL_LINE 0x7C /* '|' */ +#define ASCII_CHAR_RIGHT_CURLY_BRACKET 0x7D /* '}' */ +#define ASCII_CHAR_TILDE 0x7E /* '~' */ + +#define ASCII_CHAR_BRACKET_CURLY_LEFT ASCII_CHAR_LEFT_CURLY_BRACKET +#define ASCII_CHAR_BRACKET_CURLY_RIGHT ASCII_CHAR_RIGHT_CURLY_BRACKET + + + /* ---------------- CONTROL CHARACTERS ---------------- */ +#define ASCII_CHAR_DELETE 0x7F + +#define ASCII_CHAR_DEL ASCII_CHAR_DELETE + + +/* +********************************************************************************************************* +* DATA TYPES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* GLOBAL VARIABLES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* MACRO'S +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* ASCII CHARACTER CLASSIFICATION MACRO's +* +* Note(s) : (1) ISO/IEC 9899:TC2, Section 7.4.1.(1) states that "character classification functions ... +* return nonzero (true) if and only if the value of the argument 'c' conforms to ... the +* description of the function." +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* ASCII_IS_DIG() +* +* Description : Determine whether a character is a decimal-digit character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is a decimal-digit character. +* +* DEF_NO, if character is NOT a decimal-digit character. +* +* Caller(s) : Application. +* +* Note(s) : (1) ISO/IEC 9899:TC2, Section 7.4.1.5.(2) states that "isdigit() ... tests for any +* decimal-digit character". +********************************************************************************************************* +*/ + +#define ASCII_IS_DIG(c) ((((c) >= ASCII_CHAR_DIG_ZERO) && ((c) <= ASCII_CHAR_DIG_NINE)) ? (DEF_YES) : (DEF_NO)) + + +/* +********************************************************************************************************* +* ASCII_IS_DIG_OCT() +* +* Description : Determine whether a character is an octal-digit character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is an octal-digit character. +* +* DEF_NO, if character is NOT an octal-digit character. +* +* Caller(s) : Application. +* +* Note(s) : none. +********************************************************************************************************* +*/ + +#define ASCII_IS_DIG_OCT(c) ((((c) >= ASCII_CHAR_DIG_ZERO) && ((c) <= ASCII_CHAR_DIG_SEVEN)) ? (DEF_YES) : (DEF_NO)) + + +/* +********************************************************************************************************* +* ASCII_IS_DIG_HEX() +* +* Description : Determine whether a character is a hexadecimal-digit character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is a hexadecimal-digit character. +* +* DEF_NO, if character is NOT a hexadecimal-digit character. +* +* Caller(s) : Application. +* +* Note(s) : (1) ISO/IEC 9899:TC2, Section 7.4.1.12.(2) states that "isxdigit() ... tests for any +* hexadecimal-digit character". +********************************************************************************************************* +*/ + +#define ASCII_IS_DIG_HEX(c) (((((c) >= ASCII_CHAR_DIG_ZERO ) && ((c) <= ASCII_CHAR_DIG_NINE )) || \ + (((c) >= ASCII_CHAR_LATIN_UPPER_A) && ((c) <= ASCII_CHAR_LATIN_UPPER_F)) || \ + (((c) >= ASCII_CHAR_LATIN_LOWER_A) && ((c) <= ASCII_CHAR_LATIN_LOWER_F))) ? (DEF_YES) : (DEF_NO)) + + +/* +********************************************************************************************************* +* ASCII_IS_LOWER() +* +* Description : Determine whether a character is a lowercase alphabetic character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is a lowercase alphabetic character. +* +* DEF_NO, if character is NOT a lowercase alphabetic character. +* +* Caller(s) : Application. +* +* Note(s) : (1) ISO/IEC 9899:TC2, Section 7.4.1.7.(2) states that "islower() returns true only for +* the lowercase letters". +********************************************************************************************************* +*/ + +#define ASCII_IS_LOWER(c) ((((c) >= ASCII_CHAR_LATIN_LOWER_A) && ((c) <= ASCII_CHAR_LATIN_LOWER_Z)) ? (DEF_YES) : (DEF_NO)) + + +/* +********************************************************************************************************* +* ASCII_IS_UPPER() +* +* Description : Determine whether a character is an uppercase alphabetic character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is an uppercase alphabetic character. +* +* DEF_NO, if character is NOT an uppercase alphabetic character. +* +* Caller(s) : Application. +* +* Note(s) : (1) ISO/IEC 9899:TC2, Section 7.4.1.11.(2) states that "isupper() returns true only for +* the uppercase letters". +********************************************************************************************************* +*/ + +#define ASCII_IS_UPPER(c) ((((c) >= ASCII_CHAR_LATIN_UPPER_A) && ((c) <= ASCII_CHAR_LATIN_UPPER_Z)) ? (DEF_YES) : (DEF_NO)) + + +/* +********************************************************************************************************* +* ASCII_IS_ALPHA() +* +* Description : Determine whether a character is an alphabetic character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is an alphabetic character. +* +* DEF_NO, if character is NOT an alphabetic character. +* +* Caller(s) : Application. +* +* Note(s) : (1) ISO/IEC 9899:TC2, Section 7.4.1.2.(2) states that "isalpha() returns true only for the +* characters for which isupper() or islower() is true". +********************************************************************************************************* +*/ + +#define ASCII_IS_ALPHA(c) ((((ASCII_IS_UPPER(c)) == DEF_YES) || \ + ((ASCII_IS_LOWER(c)) == DEF_YES)) ? (DEF_YES) : (DEF_NO)) + + +/* +********************************************************************************************************* +* ASCII_IS_ALPHA_NUM() +* +* Description : Determine whether a character is an alphanumeric character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is an alphanumeric character. +* +* DEF_NO, if character is NOT an alphanumeric character. +* +* Caller(s) : Application. +* +* Note(s) : (1) ISO/IEC 9899:TC2, Section 7.4.1.1.(2) states that "isalnum() ... tests for any character +* for which isalpha() or isdigit() is true". +********************************************************************************************************* +*/ + +#define ASCII_IS_ALPHA_NUM(c) ((((ASCII_IS_ALPHA(c)) == DEF_YES) || \ + ((ASCII_IS_DIG (c)) == DEF_YES)) ? (DEF_YES) : (DEF_NO)) + + +/* +********************************************************************************************************* +* ASCII_IS_BLANK() +* +* Description : Determine whether a character is a standard blank character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is a standard blank character. +* +* DEF_NO, if character is NOT a standard blank character. +* +* Caller(s) : Application. +* +* Note(s) : (1) (a) ISO/IEC 9899:TC2, Section 7.4.1.3.(2) states that "isblank() returns true only for +* the standard blank characters". +* +* (b) ISO/IEC 9899:TC2, Section 7.4.1.3.(2) defines "the standard blank characters" as +* the "space (' '), and horizontal tab ('\t')". +********************************************************************************************************* +*/ + +#define ASCII_IS_BLANK(c) ((((c) == ASCII_CHAR_SPACE) || ((c) == ASCII_CHAR_HT)) ? (DEF_YES) : (DEF_NO)) + + +/* +********************************************************************************************************* +* ASCII_IS_SPACE() +* +* Description : Determine whether a character is a white-space character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is a white-space character. +* +* DEF_NO, if character is NOT a white-space character. +* +* Caller(s) : Application. +* +* Note(s) : (1) (a) ISO/IEC 9899:TC2, Section 7.4.1.10.(2) states that "isspace() returns true only +* for the standard white-space characters". +* +* (b) ISO/IEC 9899:TC2, Section 7.4.1.10.(2) defines "the standard white-space characters" +* as the "space (' '), form feed ('\f'), new-line ('\n'), carriage return ('\r'), +* horizontal tab ('\t'), and vertical tab ('\v')". +********************************************************************************************************* +*/ + +#define ASCII_IS_SPACE(c) ((((c) == ASCII_CHAR_SPACE) || ((c) == ASCII_CHAR_CR) || \ + ((c) == ASCII_CHAR_LF ) || ((c) == ASCII_CHAR_FF) || \ + ((c) == ASCII_CHAR_HT ) || ((c) == ASCII_CHAR_VT)) ? (DEF_YES) : (DEF_NO)) + + +/* +********************************************************************************************************* +* ASCII_IS_PRINT() +* +* Description : Determine whether a character is a printing character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is a printing character. +* +* DEF_NO, if character is NOT a printing character. +* +* Caller(s) : Application. +* +* Note(s) : (1) (a) ISO/IEC 9899:TC2, Section 7.4.1.8.(2) states that "isprint() ... tests for any +* printing character including space (' ')". +* +* (b) ISO/IEC 9899:TC2, Section 7.4.(3), Note 169, states that in "the seven-bit US +* ASCII character set, the printing characters are those whose values lie from +* 0x20 (space) through 0x7E (tilde)". +********************************************************************************************************* +*/ + +#define ASCII_IS_PRINT(c) ((((c) >= ASCII_CHAR_SPACE) && ((c) <= ASCII_CHAR_TILDE)) ? (DEF_YES) : (DEF_NO)) + + +/* +********************************************************************************************************* +* ASCII_IS_GRAPH() +* +* Description : Determine whether a character is any printing character except a space character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is a graphic character. +* +* DEF_NO, if character is NOT a graphic character. +* +* Caller(s) : Application. +* +* Note(s) : (1) (a) ISO/IEC 9899:TC2, Section 7.4.1.6.(2) states that "isgraph() ... tests for any +* printing character except space (' ')". +* +* (b) ISO/IEC 9899:TC2, Section 7.4.(3), Note 169, states that in "the seven-bit US +* ASCII character set, the printing characters are those whose values lie from +* 0x20 (space) through 0x7E (tilde)". +********************************************************************************************************* +*/ + +#define ASCII_IS_GRAPH(c) ((((c) >= ASCII_CHAR_EXCLAMATION_MARK) && ((c) <= ASCII_CHAR_TILDE)) ? (DEF_YES) : (DEF_NO)) + + +/* +********************************************************************************************************* +* ASCII_IS_PUNCT() +* +* Description : Determine whether a character is a punctuation character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is a punctuation character. +* +* DEF_NO, if character is NOT a punctuation character. +* +* Caller(s) : Application. +* +* Note(s) : (1) ISO/IEC 9899:TC2, Section 7.4.1.9.(2) states that "ispunct() returns true for every +* printing character for which neither isspace() nor isalnum() is true". +********************************************************************************************************* +*/ + +#define ASCII_IS_PUNCT(c) ((((ASCII_IS_PRINT(c)) == DEF_YES) && \ + ((ASCII_IS_SPACE(c)) == DEF_NO ) && \ + ((ASCII_IS_ALPHA_NUM(c)) == DEF_NO )) ? (DEF_YES) : (DEF_NO)) + + +/* +********************************************************************************************************* +* ASCII_IS_CTRL() +* +* Description : Determine whether a character is a control character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is a control character. +* +* DEF_NO, if character is NOT a control character. +* +* Caller(s) : Application. +* +* Note(s) : (1) (a) ISO/IEC 9899:TC2, Section 7.4.1.4.(2) states that "iscntrl() ... tests for any +* control character". +* +* (b) ISO/IEC 9899:TC2, Section 7.4.(3), Note 169, states that in "the seven-bit US +* ASCII character set, ... the control characters are those whose values lie from +* 0 (NUL) through 0x1F (US), and the character 0x7F (DEL)". +********************************************************************************************************* +*/ + +#define ASCII_IS_CTRL(c) (((((CPU_INT08S)(c) >= ASCII_CHAR_NULL ) && ((c) <= ASCII_CHAR_IS1)) || \ + ((c) == ASCII_CHAR_DEL)) ? (DEF_YES) : (DEF_NO)) + + +/* +********************************************************************************************************* +* ASCII CHARACTER CASE MAPPING MACRO's +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* ASCII_TO_LOWER() +* +* Description : Convert uppercase alphabetic character to its corresponding lowercase alphabetic character. +* +* Argument(s) : c Character to convert. +* +* Return(s) : Lowercase equivalent of 'c', if character 'c' is an uppercase character (see Note #1b1). +* +* Character 'c', otherwise (see Note #1b2). +* +* Caller(s) : Application. +* +* Note(s) : (1) (a) ISO/IEC 9899:TC2, Section 7.4.2.1.(2) states that "tolower() ... converts an +* uppercase letter to a corresponding lowercase letter". +* +* (b) ISO/IEC 9899:TC2, Section 7.4.2.1.(3) states that : +* +* (1) (A) "if the argument is a character for which isupper() is true and there are +* one or more corresponding characters ... for which islower() is true," ... +* (B) "tolower() ... returns one of the corresponding characters;" ... +* +* (2) "otherwise, the argument is returned unchanged." +********************************************************************************************************* +*/ + +#define ASCII_TO_LOWER(c) (((ASCII_IS_UPPER(c)) == DEF_YES) ? ((c) + (ASCII_CHAR_LATIN_LOWER_A - ASCII_CHAR_LATIN_UPPER_A)) : (c)) + + +/* +********************************************************************************************************* +* ASCII_TO_UPPER() +* +* Description : Convert lowercase alphabetic character to its corresponding uppercase alphabetic character. +* +* Argument(s) : c Character to convert. +* +* Return(s) : Uppercase equivalent of 'c', if character 'c' is a lowercase character (see Note #1b1). +* +* Character 'c', otherwise (see Note #1b2). +* +* Caller(s) : Application. +* +* Note(s) : (1) (a) ISO/IEC 9899:TC2, Section 7.4.2.2.(2) states that "toupper() ... converts a +* lowercase letter to a corresponding uppercase letter". +* +* (b) ISO/IEC 9899:TC2, Section 7.4.2.2.(3) states that : +* +* (1) (A) "if the argument is a character for which islower() is true and there are +* one or more corresponding characters ... for which isupper() is true," ... +* (B) "toupper() ... returns one of the corresponding characters;" ... +* +* (2) "otherwise, the argument is returned unchanged." +********************************************************************************************************* +*/ + +#define ASCII_TO_UPPER(c) (((ASCII_IS_LOWER(c)) == DEF_YES) ? ((c) - (ASCII_CHAR_LATIN_LOWER_A - ASCII_CHAR_LATIN_UPPER_A)) : (c)) + + +/* +********************************************************************************************************* +* FUNCTION PROTOTYPES +********************************************************************************************************* +*/ + +CPU_BOOLEAN ASCII_IsAlpha (CPU_CHAR c); + +CPU_BOOLEAN ASCII_IsAlphaNum(CPU_CHAR c); + +CPU_BOOLEAN ASCII_IsLower (CPU_CHAR c); + +CPU_BOOLEAN ASCII_IsUpper (CPU_CHAR c); + +CPU_BOOLEAN ASCII_IsDig (CPU_CHAR c); + +CPU_BOOLEAN ASCII_IsDigOct (CPU_CHAR c); + +CPU_BOOLEAN ASCII_IsDigHex (CPU_CHAR c); + +CPU_BOOLEAN ASCII_IsBlank (CPU_CHAR c); + +CPU_BOOLEAN ASCII_IsSpace (CPU_CHAR c); + +CPU_BOOLEAN ASCII_IsPrint (CPU_CHAR c); + +CPU_BOOLEAN ASCII_IsGraph (CPU_CHAR c); + +CPU_BOOLEAN ASCII_IsPunct (CPU_CHAR c); + +CPU_BOOLEAN ASCII_IsCtrl (CPU_CHAR c); + + +CPU_CHAR ASCII_ToLower (CPU_CHAR c); + +CPU_CHAR ASCII_ToUpper (CPU_CHAR c); + + +CPU_BOOLEAN ASCII_Cmp (CPU_CHAR c1, + CPU_CHAR c2); + + +/* +********************************************************************************************************* +* CONFIGURATION ERRORS +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* MODULE END +* +* Note(s) : (1) See 'lib_ascii.h MODULE'. +********************************************************************************************************* +*/ + +#endif /* End of lib ascii module include. */ + diff --git a/Middlewares/Third_Party/Micrium/uC-LIB/lib_def.h b/Middlewares/Third_Party/Micrium/uC-LIB/lib_def.h new file mode 100644 index 0000000..0ada21d --- /dev/null +++ b/Middlewares/Third_Party/Micrium/uC-LIB/lib_def.h @@ -0,0 +1,1344 @@ +/* +********************************************************************************************************* +* uC/LIB +* CUSTOM LIBRARY MODULES +* +* (c) Copyright 2004-2014; Micrium, Inc.; Weston, FL +* +* All rights reserved. Protected by international copyright laws. +* +* uC/LIB is provided in source form to registered licensees ONLY. It is +* illegal to distribute this source code to any third party unless you receive +* written permission by an authorized Micrium representative. Knowledge of +* the source code may NOT be used to develop a similar product. +* +* Please help us continue to provide the Embedded community with the finest +* software available. Your honesty is greatly appreciated. +* +* You can find our product's user manual, API reference, release notes and +* more information at: https://doc.micrium.com +* +* You can contact us at: http://www.micrium.com +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* +* CORE CUSTOM LIBRARY MODULE +* +* Filename : lib_def.h +* Version : V1.38.01 +* Programmer(s) : ITJ +* FBJ +* JFD +********************************************************************************************************* +* Note(s) : (1) Assumes the following versions (or more recent) of software modules are included in +* the project build : +* +* (a) uC/CPU V1.29.00 +* +* +* (2) NO compiler-supplied standard library functions are used in library or product software. +* +* (a) ALL standard library functions are implemented in the custom library modules : +* +* (1) \\lib_*.* +* +* (2) \\Ports\\\lib*_a.* +* +* where +* directory path for custom library software +* directory name for specific processor (CPU) +* directory name for specific compiler +* +* (b) Product-specific library functions are implemented in individual products. +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* MODULE +* +* Note(s) : (1) This library definition header file is protected from multiple pre-processor inclusion +* through use of the library definition module present pre-processor macro definition. +********************************************************************************************************* +*/ + +#ifndef LIB_DEF_MODULE_PRESENT +#define LIB_DEF_MODULE_PRESENT + + +/* +********************************************************************************************************* +* CUSTOM LIBRARY MODULE VERSION NUMBER +* +* Note(s) : (1) (a) The custom library module software version is denoted as follows : +* +* Vx.yy.zz +* +* where +* V denotes 'Version' label +* x denotes major software version revision number +* yy denotes minor software version revision number +* zz denotes sub-minor software version revision number +* +* (b) The software version label #define is formatted as follows : +* +* ver = x.yyzz * 100 * 100 +* +* where +* ver denotes software version number scaled as an integer value +* x.yyzz denotes software version number, where the unscaled integer +* portion denotes the major version number & the unscaled +* fractional portion denotes the (concatenated) minor +* version numbers +********************************************************************************************************* +*/ + +#define LIB_VERSION 13801u /* See Note #1. */ + + +/* +********************************************************************************************************* +* INCLUDE FILES +* +* Note(s) : (1) The custom library software files are located in the following directories : +* +* (a) \\lib_*.* +* +* where +* directory path for custom library software +* +* (2) CPU-configuration software files are located in the following directories : +* +* (a) \\cpu_*.* +* (b) \\\\cpu*.* +* +* where +* directory path for common CPU-compiler software +* directory name for specific processor (CPU) +* directory name for specific compiler +* +* (3) Compiler MUST be configured to include as additional include path directories : +* +* (a) '\\' directory See Note #1a +* +* (b) (1) '\\' directory See Note #2a +* (2) '\\\\' directory See Note #2b +********************************************************************************************************* +*/ + +#include +#include + + +/* +********************************************************************************************************* +* STANDARD DEFINES +********************************************************************************************************* +*/ + +#define DEF_NULL 0 + + + /* ----------------- BOOLEAN DEFINES ------------------ */ +#define DEF_FALSE 0u +#define DEF_TRUE 1u + +#define DEF_NO 0u +#define DEF_YES 1u + +#define DEF_DISABLED 0u +#define DEF_ENABLED 1u + +#define DEF_INACTIVE 0u +#define DEF_ACTIVE 1u + +#define DEF_INVALID 0u +#define DEF_VALID 1u + +#define DEF_OFF 0u +#define DEF_ON 1u + +#define DEF_CLR 0u +#define DEF_SET 1u + +#define DEF_FAIL 0u +#define DEF_OK 1u + + + /* ------------------- BIT DEFINES -------------------- */ +#define DEF_BIT_NONE 0x00u + +#define DEF_BIT_00 0x01u +#define DEF_BIT_01 0x02u +#define DEF_BIT_02 0x04u +#define DEF_BIT_03 0x08u +#define DEF_BIT_04 0x10u +#define DEF_BIT_05 0x20u +#define DEF_BIT_06 0x40u +#define DEF_BIT_07 0x80u + +#define DEF_BIT_08 0x0100u +#define DEF_BIT_09 0x0200u +#define DEF_BIT_10 0x0400u +#define DEF_BIT_11 0x0800u +#define DEF_BIT_12 0x1000u +#define DEF_BIT_13 0x2000u +#define DEF_BIT_14 0x4000u +#define DEF_BIT_15 0x8000u + +#define DEF_BIT_16 0x00010000u +#define DEF_BIT_17 0x00020000u +#define DEF_BIT_18 0x00040000u +#define DEF_BIT_19 0x00080000u +#define DEF_BIT_20 0x00100000u +#define DEF_BIT_21 0x00200000u +#define DEF_BIT_22 0x00400000u +#define DEF_BIT_23 0x00800000u + +#define DEF_BIT_24 0x01000000u +#define DEF_BIT_25 0x02000000u +#define DEF_BIT_26 0x04000000u +#define DEF_BIT_27 0x08000000u +#define DEF_BIT_28 0x10000000u +#define DEF_BIT_29 0x20000000u +#define DEF_BIT_30 0x40000000u +#define DEF_BIT_31 0x80000000u +#define DEF_BIT_32 0x0000000100000000u +#define DEF_BIT_33 0x0000000200000000u +#define DEF_BIT_34 0x0000000400000000u +#define DEF_BIT_35 0x0000000800000000u +#define DEF_BIT_36 0x0000001000000000u +#define DEF_BIT_37 0x0000002000000000u +#define DEF_BIT_38 0x0000004000000000u +#define DEF_BIT_39 0x0000008000000000u + +#define DEF_BIT_40 0x0000010000000000u +#define DEF_BIT_41 0x0000020000000000u +#define DEF_BIT_42 0x0000040000000000u +#define DEF_BIT_43 0x0000080000000000u +#define DEF_BIT_44 0x0000100000000000u +#define DEF_BIT_45 0x0000200000000000u +#define DEF_BIT_46 0x0000400000000000u +#define DEF_BIT_47 0x0000800000000000u + +#define DEF_BIT_48 0x0001000000000000u +#define DEF_BIT_49 0x0002000000000000u +#define DEF_BIT_50 0x0004000000000000u +#define DEF_BIT_51 0x0008000000000000u +#define DEF_BIT_52 0x0010000000000000u +#define DEF_BIT_53 0x0020000000000000u +#define DEF_BIT_54 0x0040000000000000u +#define DEF_BIT_55 0x0080000000000000u + +#define DEF_BIT_56 0x0100000000000000u +#define DEF_BIT_57 0x0200000000000000u +#define DEF_BIT_58 0x0400000000000000u +#define DEF_BIT_59 0x0800000000000000u +#define DEF_BIT_60 0x1000000000000000u +#define DEF_BIT_61 0x2000000000000000u +#define DEF_BIT_62 0x4000000000000000u +#define DEF_BIT_63 0x8000000000000000u + + + /* ------------------ ALIGN DEFINES ------------------- */ +#define DEF_ALIGN_MAX_NBR_OCTETS 4096u + + + /* ------------------ OCTET DEFINES ------------------- */ +#define DEF_OCTET_NBR_BITS 8u +#define DEF_OCTET_MASK 0xFFu + +#define DEF_OCTET_TO_BIT_NBR_BITS 3u +#define DEF_OCTET_TO_BIT_SHIFT DEF_OCTET_TO_BIT_NBR_BITS +#define DEF_OCTET_TO_BIT_MASK 0x07u + + +#define DEF_NIBBLE_NBR_BITS 4u +#define DEF_NIBBLE_MASK 0x0Fu + + + /* --------------- NUMBER BASE DEFINES ---------------- */ +#define DEF_NBR_BASE_BIN 2u +#define DEF_NBR_BASE_OCT 8u +#define DEF_NBR_BASE_DEC 10u +#define DEF_NBR_BASE_HEX 16u + + + /* ----------------- INTEGER DEFINES ------------------ */ +#define DEF_INT_08_NBR_BITS 8u +#define DEF_INT_08_MASK 0xFFu + +#define DEF_INT_08U_MIN_VAL 0u +#define DEF_INT_08U_MAX_VAL 255u + +#define DEF_INT_08S_MIN_VAL_ONES_CPL (-127) +#define DEF_INT_08S_MAX_VAL_ONES_CPL 127 + +#define DEF_INT_08S_MIN_VAL (DEF_INT_08S_MIN_VAL_ONES_CPL - 1) +#define DEF_INT_08S_MAX_VAL DEF_INT_08S_MAX_VAL_ONES_CPL + +#define DEF_INT_08U_NBR_DIG_MIN 1u +#define DEF_INT_08U_NBR_DIG_MAX 3u + +#define DEF_INT_08S_NBR_DIG_MIN 3u +#define DEF_INT_08S_NBR_DIG_MAX 3u + + + +#define DEF_INT_16_NBR_BITS 16u +#define DEF_INT_16_MASK 0xFFFFu + +#define DEF_INT_16U_MIN_VAL 0u +#define DEF_INT_16U_MAX_VAL 65535u + +#define DEF_INT_16S_MIN_VAL_ONES_CPL (-32767) +#define DEF_INT_16S_MAX_VAL_ONES_CPL 32767 + +#define DEF_INT_16S_MIN_VAL (DEF_INT_16S_MIN_VAL_ONES_CPL - 1) +#define DEF_INT_16S_MAX_VAL DEF_INT_16S_MAX_VAL_ONES_CPL + +#define DEF_INT_16U_NBR_DIG_MIN 1u +#define DEF_INT_16U_NBR_DIG_MAX 5u + +#define DEF_INT_16S_NBR_DIG_MIN 5u +#define DEF_INT_16S_NBR_DIG_MAX 5u + + + +#define DEF_INT_32_NBR_BITS 32u +#define DEF_INT_32_MASK 0xFFFFFFFFu + +#define DEF_INT_32U_MIN_VAL 0u +#define DEF_INT_32U_MAX_VAL 4294967295u + +#define DEF_INT_32S_MIN_VAL_ONES_CPL (-2147483647) +#define DEF_INT_32S_MAX_VAL_ONES_CPL 2147483647 + +#define DEF_INT_32S_MIN_VAL (DEF_INT_32S_MIN_VAL_ONES_CPL - 1) +#define DEF_INT_32S_MAX_VAL DEF_INT_32S_MAX_VAL_ONES_CPL + +#define DEF_INT_32U_NBR_DIG_MIN 1u +#define DEF_INT_32U_NBR_DIG_MAX 10u + +#define DEF_INT_32S_NBR_DIG_MIN 10u +#define DEF_INT_32S_NBR_DIG_MAX 10u + + + +#define DEF_INT_64_NBR_BITS 64u +#define DEF_INT_64_MASK 0xFFFFFFFFFFFFFFFFu + +#define DEF_INT_64U_MIN_VAL 0u +#define DEF_INT_64U_MAX_VAL 18446744073709551615u + +#define DEF_INT_64S_MIN_VAL_ONES_CPL (-9223372036854775807) +#define DEF_INT_64S_MAX_VAL_ONES_CPL 9223372036854775807 + +#define DEF_INT_64S_MIN_VAL (DEF_INT_64S_MIN_VAL_ONES_CPL - 1) +#define DEF_INT_64S_MAX_VAL DEF_INT_64S_MAX_VAL_ONES_CPL + +#define DEF_INT_64U_NBR_DIG_MIN 1u +#define DEF_INT_64U_NBR_DIG_MAX 20u + +#define DEF_INT_64S_NBR_DIG_MIN 19u +#define DEF_INT_64S_NBR_DIG_MAX 19u + + + /* --------------- CPU INTEGER DEFINES ---------------- */ +#define DEF_INT_CPU_NBR_BITS (CPU_CFG_DATA_SIZE * DEF_OCTET_NBR_BITS) +#define DEF_INT_CPU_NBR_BITS_MAX (CPU_CFG_DATA_SIZE_MAX * DEF_OCTET_NBR_BITS) + + + +#if (DEF_INT_CPU_NBR_BITS == DEF_INT_08_NBR_BITS) + + +#define DEF_INT_CPU_MASK DEF_INT_08_MASK + +#define DEF_INT_CPU_U_MIN_VAL DEF_INT_08U_MIN_VAL +#define DEF_INT_CPU_U_MAX_VAL DEF_INT_08U_MAX_VAL + +#define DEF_INT_CPU_S_MIN_VAL DEF_INT_08S_MIN_VAL +#define DEF_INT_CPU_S_MAX_VAL DEF_INT_08S_MAX_VAL + +#define DEF_INT_CPU_S_MIN_VAL_ONES_CPL DEF_INT_08S_MIN_VAL_ONES_CPL +#define DEF_INT_CPU_S_MAX_VAL_ONES_CPL DEF_INT_08S_MAX_VAL_ONES_CPL + + + +#elif (DEF_INT_CPU_NBR_BITS == DEF_INT_16_NBR_BITS) + + +#define DEF_INT_CPU_MASK DEF_INT_16_MASK + +#define DEF_INT_CPU_U_MIN_VAL DEF_INT_16U_MIN_VAL +#define DEF_INT_CPU_U_MAX_VAL DEF_INT_16U_MAX_VAL + +#define DEF_INT_CPU_S_MIN_VAL DEF_INT_16S_MIN_VAL +#define DEF_INT_CPU_S_MAX_VAL DEF_INT_16S_MAX_VAL + +#define DEF_INT_CPU_S_MIN_VAL_ONES_CPL DEF_INT_16S_MIN_VAL_ONES_CPL +#define DEF_INT_CPU_S_MAX_VAL_ONES_CPL DEF_INT_16S_MAX_VAL_ONES_CPL + + + +#elif (DEF_INT_CPU_NBR_BITS == DEF_INT_32_NBR_BITS) + + +#define DEF_INT_CPU_MASK DEF_INT_32_MASK + +#define DEF_INT_CPU_U_MIN_VAL DEF_INT_32U_MIN_VAL +#define DEF_INT_CPU_U_MAX_VAL DEF_INT_32U_MAX_VAL + +#define DEF_INT_CPU_S_MIN_VAL DEF_INT_32S_MIN_VAL +#define DEF_INT_CPU_S_MAX_VAL DEF_INT_32S_MAX_VAL + +#define DEF_INT_CPU_S_MIN_VAL_ONES_CPL DEF_INT_32S_MIN_VAL_ONES_CPL +#define DEF_INT_CPU_S_MAX_VAL_ONES_CPL DEF_INT_32S_MAX_VAL_ONES_CPL + + + +#elif (DEF_INT_CPU_NBR_BITS == DEF_INT_64_NBR_BITS) + + +#define DEF_INT_CPU_MASK DEF_INT_64_MASK + +#define DEF_INT_CPU_U_MIN_VAL DEF_INT_64U_MIN_VAL +#define DEF_INT_CPU_U_MAX_VAL DEF_INT_64U_MAX_VAL + +#define DEF_INT_CPU_S_MIN_VAL DEF_INT_64S_MIN_VAL +#define DEF_INT_CPU_S_MAX_VAL DEF_INT_64S_MAX_VAL + +#define DEF_INT_CPU_S_MIN_VAL_ONES_CPL DEF_INT_64S_MIN_VAL_ONES_CPL +#define DEF_INT_CPU_S_MAX_VAL_ONES_CPL DEF_INT_64S_MAX_VAL_ONES_CPL + + + +#else + +#error "CPU_CFG_DATA_SIZE illegally #defined in 'cpu.h' " +#error " [See 'cpu.h CONFIGURATION ERRORS']" + +#endif + + + /* ------------------- TIME DEFINES ------------------- */ +#define DEF_TIME_NBR_DAY_PER_WK 7u +#define DEF_TIME_NBR_DAY_PER_YR 365u +#define DEF_TIME_NBR_DAY_PER_YR_LEAP 366u + +#define DEF_TIME_NBR_HR_PER_DAY 24u +#define DEF_TIME_NBR_HR_PER_WK (DEF_TIME_NBR_HR_PER_DAY * DEF_TIME_NBR_DAY_PER_WK ) +#define DEF_TIME_NBR_HR_PER_YR (DEF_TIME_NBR_HR_PER_DAY * DEF_TIME_NBR_DAY_PER_YR ) +#define DEF_TIME_NBR_HR_PER_YR_LEAP (DEF_TIME_NBR_HR_PER_DAY * DEF_TIME_NBR_DAY_PER_YR_LEAP) + +#define DEF_TIME_NBR_MIN_PER_HR 60u +#define DEF_TIME_NBR_MIN_PER_DAY (DEF_TIME_NBR_MIN_PER_HR * DEF_TIME_NBR_HR_PER_DAY ) +#define DEF_TIME_NBR_MIN_PER_WK (DEF_TIME_NBR_MIN_PER_DAY * DEF_TIME_NBR_DAY_PER_WK ) +#define DEF_TIME_NBR_MIN_PER_YR (DEF_TIME_NBR_MIN_PER_DAY * DEF_TIME_NBR_DAY_PER_YR ) +#define DEF_TIME_NBR_MIN_PER_YR_LEAP (DEF_TIME_NBR_MIN_PER_DAY * DEF_TIME_NBR_DAY_PER_YR_LEAP) + +#define DEF_TIME_NBR_SEC_PER_MIN 60u +#define DEF_TIME_NBR_SEC_PER_HR (DEF_TIME_NBR_SEC_PER_MIN * DEF_TIME_NBR_MIN_PER_HR ) +#define DEF_TIME_NBR_SEC_PER_DAY (DEF_TIME_NBR_SEC_PER_HR * DEF_TIME_NBR_HR_PER_DAY ) +#define DEF_TIME_NBR_SEC_PER_WK (DEF_TIME_NBR_SEC_PER_DAY * DEF_TIME_NBR_DAY_PER_WK ) +#define DEF_TIME_NBR_SEC_PER_YR (DEF_TIME_NBR_SEC_PER_DAY * DEF_TIME_NBR_DAY_PER_YR ) +#define DEF_TIME_NBR_SEC_PER_YR_LEAP (DEF_TIME_NBR_SEC_PER_DAY * DEF_TIME_NBR_DAY_PER_YR_LEAP) + +#define DEF_TIME_NBR_mS_PER_SEC 1000u +#define DEF_TIME_NBR_uS_PER_SEC 1000000u +#define DEF_TIME_NBR_nS_PER_SEC 1000000000u + + +/* +********************************************************************************************************* +* ERROR CODES +* +* Note(s) : (1) All library error codes are #define'd in 'lib_def.h'; +********************************************************************************************************* +*/ + +typedef enum lib_err { + + LIB_ERR_NONE = 0u, + + LIB_MEM_ERR_NONE = 10000u, + LIB_MEM_ERR_NULL_PTR = 10001u, /* Ptr arg(s) passed NULL ptr(s). */ + + LIB_MEM_ERR_INVALID_MEM_SIZE = 10100u, /* Invalid mem size. */ + LIB_MEM_ERR_INVALID_MEM_ALIGN = 10101u, /* Invalid mem align. */ + LIB_MEM_ERR_INVALID_SEG_SIZE = 10110u, /* Invalid mem seg size. */ + LIB_MEM_ERR_INVALID_SEG_OVERLAP = 10111u, /* Invalid mem seg overlaps other mem seg(s). */ + LIB_MEM_ERR_INVALID_SEG_EXISTS = 10112u, /* Invalid mem seg already exists. */ + LIB_MEM_ERR_INVALID_POOL = 10120u, /* Invalid mem pool. */ + LIB_MEM_ERR_INVALID_BLK_NBR = 10130u, /* Invalid mem pool blk nbr. */ + LIB_MEM_ERR_INVALID_BLK_SIZE = 10131u, /* Invalid mem pool blk size. */ + LIB_MEM_ERR_INVALID_BLK_ALIGN = 10132u, /* Invalid mem pool blk align. */ + LIB_MEM_ERR_INVALID_BLK_IX = 10133u, /* Invalid mem pool ix. */ + LIB_MEM_ERR_INVALID_BLK_ADDR = 10135u, /* Invalid mem pool blk addr. */ + LIB_MEM_ERR_INVALID_BLK_ADDR_IN_POOL = 10136u, /* Mem pool blk addr already in mem pool. */ + + LIB_MEM_ERR_SEG_EMPTY = 10200u, /* Mem seg empty; i.e. NO avail mem in seg. */ + LIB_MEM_ERR_SEG_OVF = 10201u, /* Mem seg ovf; i.e. req'd mem ovfs rem mem in seg. */ + LIB_MEM_ERR_POOL_FULL = 10205u, /* Mem pool full; i.e. all mem blks avail in mem pool. */ + LIB_MEM_ERR_POOL_EMPTY = 10206u, /* Mem pool empty; i.e. NO mem blks avail in mem pool. */ + LIB_MEM_ERR_POOL_UNLIMITED = 10207u, /* Mem pool is unlimited. */ + + LIB_MEM_ERR_HEAP_EMPTY = 10210u, /* Heap seg empty; i.e. NO avail mem in heap. */ + LIB_MEM_ERR_HEAP_OVF = 10211u, /* Heap seg ovf; i.e. req'd mem ovfs rem mem in heap. */ + LIB_MEM_ERR_HEAP_NOT_FOUND = 10215u /* Heap seg NOT found. */ + +} LIB_ERR; + + +/* +********************************************************************************************************* +* DATA TYPES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* GLOBAL VARIABLES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* TRACING +********************************************************************************************************* +*/ + + /* Trace level, default to TRACE_LEVEL_OFF. */ +#ifndef TRACE_LEVEL_OFF +#define TRACE_LEVEL_OFF 0u +#endif + +#ifndef TRACE_LEVEL_INFO +#define TRACE_LEVEL_INFO 1u +#endif + +#ifndef TRACE_LEVEL_DBG +#define TRACE_LEVEL_DBG 2u +#endif + +#ifndef TRACE_LEVEL_LOG +#define TRACE_LEVEL_LOG 3u +#endif + + +/* +********************************************************************************************************* +* BIT MACRO'S +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* DEF_BIT() +* +* Description : Create bit mask with single, specified bit set. +* +* Argument(s) : bit Bit number of bit to set. +* +* Return(s) : Bit mask with single, specified bit set. +* +* Caller(s) : Application. +* +* Note(s) : (1) 'bit' SHOULD be a non-negative integer. +* +* (2) (a) 'bit' values that overflow the target CPU &/or compiler environment (e.g. negative +* or greater-than-CPU-data-size values) MAY generate compiler warnings &/or errors. +********************************************************************************************************* +*/ + +#define DEF_BIT(bit) (1u << (bit)) + + +/* +********************************************************************************************************* +* DEF_BITxx() +* +* Description : Create bit mask of specified bit size with single, specified bit set. +* +* Argument(s) : bit Bit number of bit to set. +* +* Return(s) : Bit mask with single, specified bit set. +* +* Caller(s) : Application. +* +* Note(s) : (1) 'bit' SHOULD be a non-negative integer. +* +* (2) (a) 'bit' values that overflow the target CPU &/or compiler environment (e.g. negative +* or greater-than-CPU-data-size values) MAY generate compiler warnings &/or errors. +* +* (b) To avoid overflowing any target CPU &/or compiler's integer data type, unsigned +* bit constant '1' is cast to specified integer data type size. +* +* (3) Ideally, DEF_BITxx() macro's should be named DEF_BIT_xx(); however, these names already +* previously-released for bit constant #define's (see 'STANDARD DEFINES BIT DEFINES'). +********************************************************************************************************* +*/ + +#define DEF_BIT08(bit) ((CPU_INT08U)((CPU_INT08U)1u << (bit))) + +#define DEF_BIT16(bit) ((CPU_INT16U)((CPU_INT16U)1u << (bit))) + +#define DEF_BIT32(bit) ((CPU_INT32U)((CPU_INT32U)1u << (bit))) + +#define DEF_BIT64(bit) ((CPU_INT64U)((CPU_INT64U)1u << (bit))) + + +/* +********************************************************************************************************* +* DEF_BIT_MASK() +* +* Description : Shift a bit mask. +* +* Argument(s) : bit_mask Bit mask to shift. +* +* bit_shift Number of bit positions to left-shift bit mask. +* +* Return(s) : Shifted bit mask. +* +* Caller(s) : Application. +* +* Note(s) : (1) (a) 'bit_mask' SHOULD be an unsigned integer. +* +* (b) 'bit_shift' SHOULD be a non-negative integer. +* +* (2) 'bit_shift' values that overflow the target CPU &/or compiler environment (e.g. negative +* or greater-than-CPU-data-size values) MAY generate compiler warnings &/or errors. +********************************************************************************************************* +*/ + +#define DEF_BIT_MASK(bit_mask, bit_shift) ((bit_mask) << (bit_shift)) + + +/* +********************************************************************************************************* +* DEF_BIT_MASK_xx() +* +* Description : Shift a bit mask of specified bit size. +* +* Argument(s) : bit_mask Bit mask to shift. +* +* bit_shift Number of bit positions to left-shift bit mask. +* +* Return(s) : Shifted bit mask. +* +* Caller(s) : Application. +* +* Note(s) : (1) (a) 'bit_mask' SHOULD be an unsigned integer. +* +* (b) 'bit_shift' SHOULD be a non-negative integer. +* +* (2) 'bit_shift' values that overflow the target CPU &/or compiler environment (e.g. negative +* or greater-than-CPU-data-size values) MAY generate compiler warnings &/or errors. +********************************************************************************************************* +*/ + +#define DEF_BIT_MASK_08(bit_mask, bit_shift) ((CPU_INT08U)((CPU_INT08U)(bit_mask) << (bit_shift))) + +#define DEF_BIT_MASK_16(bit_mask, bit_shift) ((CPU_INT16U)((CPU_INT16U)(bit_mask) << (bit_shift))) + +#define DEF_BIT_MASK_32(bit_mask, bit_shift) ((CPU_INT32U)((CPU_INT32U)(bit_mask) << (bit_shift))) + +#define DEF_BIT_MASK_64(bit_mask, bit_shift) ((CPU_INT64U)((CPU_INT64U)(bit_mask) << (bit_shift))) + + +/* +********************************************************************************************************* +* DEF_BIT_FIELD() +* +* Description : Create & shift a contiguous bit field. +* +* Argument(s) : bit_field Number of contiguous bits to set in the bit field. +* +* bit_shift Number of bit positions to left-shift bit field. +* +* Return(s) : Shifted bit field. +* +* Caller(s) : Application. +* +* Note(s) : (1) 'bit_field' & 'bit_shift' SHOULD be non-negative integers. +* +* (2) (a) 'bit_field'/'bit_shift' values that overflow the target CPU &/or compiler +* environment (e.g. negative or greater-than-CPU-data-size values) MAY generate +* compiler warnings &/or errors. +* +* (b) To avoid overflowing any target CPU &/or compiler's integer data type, unsigned +* bit constant '1' is suffixed with 'L'ong integer modifier. +* +* This may still be insufficient for CPUs &/or compilers that support 'long long' +* integer data types, in which case 'LL' integer modifier should be suffixed. +* However, since almost all 16- & 32-bit CPUs & compilers support 'long' integer +* data types but many may NOT support 'long long' integer data types, only 'long' +* integer data types & modifiers are supported. +* +* See also 'DEF_BIT_FIELD_xx() Note #1b'. +********************************************************************************************************* +*/ + +#define DEF_BIT_FIELD(bit_field, bit_shift) ((((bit_field) >= DEF_INT_CPU_NBR_BITS) ? (DEF_INT_CPU_U_MAX_VAL) \ + : (DEF_BIT(bit_field) - 1uL)) \ + << (bit_shift)) + +/* +********************************************************************************************************* +* DEF_BIT_FIELD_xx() +* +* Description : Create & shift a contiguous bit field of specified bit size. +* +* Argument(s) : bit_field Number of contiguous bits to set in the bit field. +* +* bit_shift Number of bit positions to left-shift bit field. +* +* Return(s) : Shifted bit field. +* +* Caller(s) : Application. +* +* Note(s) : (1) 'bit_field' & 'bit_shift' SHOULD be non-negative integers. +* +* (2) (a) 'bit_field'/'bit_shift' values that overflow the target CPU &/or compiler +* environment (e.g. negative or greater-than-CPU-data-size values) MAY generate +* compiler warnings &/or errors. +* +* (b) To avoid overflowing any target CPU &/or compiler's integer data type, unsigned +* bit constant '1' is cast to specified integer data type size. +********************************************************************************************************* +*/ + +#define DEF_BIT_FIELD_08(bit_field, bit_shift) ((CPU_INT08U)((((CPU_INT08U)(bit_field) >= (CPU_INT08U)DEF_INT_08_NBR_BITS) ? (CPU_INT08U)(DEF_INT_08U_MAX_VAL) \ + : (CPU_INT08U)(DEF_BIT08(bit_field) - (CPU_INT08U)1u)) \ + << (bit_shift))) + +#define DEF_BIT_FIELD_16(bit_field, bit_shift) ((CPU_INT16U)((((CPU_INT16U)(bit_field) >= (CPU_INT16U)DEF_INT_16_NBR_BITS) ? (CPU_INT16U)(DEF_INT_16U_MAX_VAL) \ + : (CPU_INT16U)(DEF_BIT16(bit_field) - (CPU_INT16U)1u)) \ + << (bit_shift))) + +#define DEF_BIT_FIELD_32(bit_field, bit_shift) ((CPU_INT32U)((((CPU_INT32U)(bit_field) >= (CPU_INT32U)DEF_INT_32_NBR_BITS) ? (CPU_INT32U)(DEF_INT_32U_MAX_VAL) \ + : (CPU_INT32U)(DEF_BIT32(bit_field) - (CPU_INT32U)1u)) \ + << (bit_shift))) + +#define DEF_BIT_FIELD_64(bit_field, bit_shift) ((CPU_INT64U)((((CPU_INT64U)(bit_field) >= (CPU_INT64U)DEF_INT_64_NBR_BITS) ? (CPU_INT64U)(DEF_INT_64U_MAX_VAL) \ + : (CPU_INT64U)(DEF_BIT64(bit_field) - (CPU_INT64U)1u)) \ + << (bit_shift))) + + +/* +********************************************************************************************************* +* DEF_BIT_SET() +* +* Description : Set specified bit(s) in a value. +* +* Argument(s) : val Value to modify by setting specified bit(s). +* +* mask Mask of bits to set. +* +* Return(s) : Modified value with specified bit(s) set. +* +* Caller(s) : Application. +* +* Note(s) : (1) 'val' & 'mask' SHOULD be unsigned integers. +********************************************************************************************************* +*/ + +#define DEF_BIT_SET(val, mask) ((val) = ((val) | (mask))) + + +/* +********************************************************************************************************* +* DEF_BIT_SET_xx() +* +* Description : Set specified bit(s) in a value of specified bit size. +* +* Argument(s) : val Value to modify by setting specified bit(s). +* +* mask Mask of bits to set. +* +* Return(s) : Modified value with specified bit(s) set. +* +* Caller(s) : Application. +* +* Note(s) : (1) 'val' & 'mask' SHOULD be unsigned integers. +* +* (2) These macros are deprecated and should be replaced by the DEF_BIT_SET macro. +********************************************************************************************************* +*/ + +#define DEF_BIT_SET_08(val, mask) DEF_BIT_SET((val), (mask)) + +#define DEF_BIT_SET_16(val, mask) DEF_BIT_SET((val), (mask)) + +#define DEF_BIT_SET_32(val, mask) DEF_BIT_SET((val), (mask)) + +#define DEF_BIT_SET_64(val, mask) DEF_BIT_SET((val), (mask)) + + +/* +********************************************************************************************************* +* DEF_BIT_CLR() +* +* Description : Clear specified bit(s) in a value. +* +* Argument(s) : val Value to modify by clearing specified bit(s). +* +* mask Mask of bits to clear. +* +* Return(s) : Modified value with specified bit(s) clear. +* +* Caller(s) : Application. +* +* Note(s) : (1) 'val' & 'mask' SHOULD be unsigned integers. +********************************************************************************************************* +*/ + +#define DEF_BIT_CLR(val, mask) ((val) = ((val) & ~(mask))) + + +/* +********************************************************************************************************* +* DEF_BIT_CLR_xx() +* +* Description : Clear specified bit(s) in a value of specified bit size. +* +* Argument(s) : val Value to modify by clearing specified bit(s). +* +* mask Mask of bits to clear. +* +* Return(s) : Modified value with specified bit(s) clear. +* +* Caller(s) : Application. +* +* Note(s) : (1) 'val' & 'mask' SHOULD be unsigned integers. +* +* (2) These macros are deprecated and should be replaced by the DEF_BIT_CLR macro. +********************************************************************************************************* +*/ + +#define DEF_BIT_CLR_08(val, mask) DEF_BIT_CLR((val), (mask)) + +#define DEF_BIT_CLR_16(val, mask) DEF_BIT_CLR((val), (mask)) + +#define DEF_BIT_CLR_32(val, mask) DEF_BIT_CLR((val), (mask)) + +#define DEF_BIT_CLR_64(val, mask) DEF_BIT_CLR((val), (mask)) + + +/* +********************************************************************************************************* +* DEF_BIT_TOGGLE() +* +* Description : Toggles specified bit(s) in a value. +* +* Argument(s) : val Value to modify by toggling specified bit(s). +* +* mask Mask of bits to toggle. +* +* Return(s) : Modified value with specified bit(s) toggled. +* +* Caller(s) : Application. +* +* Note(s) : (1) 'val' & 'mask' SHOULD be unsigned integers. +********************************************************************************************************* +*/ + +#define DEF_BIT_TOGGLE(val, mask) ((val) ^= (mask)) + + +/* +********************************************************************************************************* +* DEF_BIT_FIELD_RD() +* +* Description : Reads a 'val' field, masked and shifted, given by mask 'field_mask'. +* +* Argument(s) : val Value to read from. +* +* field_mask Mask of field to read. See note #1, #2 and #3. +* +* Return(s) : Field value, masked and right-shifted to bit position 0. +* +* Caller(s) : Application. +* +* Note(s) : (1) 'field_mask' argument must NOT be 0. +* +* (2) 'field_mask' argument must contain a mask with contiguous set bits. +* +* (3) 'val' & 'field_mask' SHOULD be unsigned integers. +********************************************************************************************************* +*/ + +#define DEF_BIT_FIELD_RD(val, field_mask) (((val) & (field_mask)) / ((field_mask) & ~((field_mask) << 1u))) + + +/* +********************************************************************************************************* +* DEF_BIT_FIELD_ENC() +* +* Description : Encodes given 'field_val' at position given by mask 'field_mask'. +* +* Argument(s) : field_val Value to encode. +* +* field_mask Mask of field to read. See note #1 and #2. +* +* Return(s) : Field value, masked and left-shifted to field position. +* +* Caller(s) : Application. +* +* Note(s) : (1) 'field_mask' argument must contain a mask with contiguous set bits. +* +* (2) 'field_val' & 'field_mask' SHOULD be unsigned integers. +********************************************************************************************************* +*/ + +#define DEF_BIT_FIELD_ENC(field_val, field_mask) (((field_val) * ((field_mask) & ~((field_mask) << 1u))) & (field_mask)) + + +/* +********************************************************************************************************* +* DEF_BIT_FIELD_WR() +* +* Description : Writes 'field_val' field at position given by mask 'field_mask' in variable 'var'. +* +* Argument(s) : var Variable to write field to. See note #2. +* +* field_val Desired value for field. See note #2. +* +* field_mask Mask of field to write to. See note #1 and #2. +* +* Return(s) : None. +* +* Caller(s) : Application. +* +* Note(s) : (1) 'field_mask' argument must contain a mask with contiguous set bits. +* +* (2) 'var', 'field_val' & 'field_mask' SHOULD be unsigned integers. +********************************************************************************************************* +*/ + +#define DEF_BIT_FIELD_WR(var, field_val, field_mask) (var) = (((var) & ~(field_mask)) | DEF_BIT_FIELD_ENC((field_val), (field_mask))) + + +/* +********************************************************************************************************* +* DEF_BIT_IS_SET() +* +* Description : Determine if specified bit(s) in a value are set. +* +* Argument(s) : val Value to check for specified bit(s) set. +* +* mask Mask of bits to check if set (see Note #2). +* +* Return(s) : DEF_YES, if ALL specified bit(s) are set in value. +* +* DEF_NO, if ALL specified bit(s) are NOT set in value. +* +* Caller(s) : Application. +* +* Note(s) : (1) 'val' & 'mask' SHOULD be unsigned integers. +* +* (2) NULL 'mask' allowed; returns 'DEF_NO' since NO mask bits specified. +********************************************************************************************************* +*/ + +#define DEF_BIT_IS_SET(val, mask) (((((val) & (mask)) == (mask)) && \ + ((mask) != 0u)) ? (DEF_YES) : (DEF_NO)) + + +/* +********************************************************************************************************* +* DEF_BIT_IS_CLR() +* +* Description : Determine if specified bit(s) in a value are clear. +* +* Argument(s) : val Value to check for specified bit(s) clear. +* +* mask Mask of bits to check if clear (see Note #2). +* +* Return(s) : DEF_YES, if ALL specified bit(s) are clear in value. +* +* DEF_NO, if ALL specified bit(s) are NOT clear in value. +* +* Caller(s) : Application. +* +* Note(s) : (1) 'val' & 'mask' SHOULD be unsigned integers. +* +* (2) NULL 'mask' allowed; returns 'DEF_NO' since NO mask bits specified. +********************************************************************************************************* +*/ + +#define DEF_BIT_IS_CLR(val, mask) (((((val) & (mask)) == 0u) && \ + ((mask) != 0u)) ? (DEF_YES) : (DEF_NO)) + + +/* +********************************************************************************************************* +* DEF_BIT_IS_SET_ANY() +* +* Description : Determine if any specified bit(s) in a value are set. +* +* Argument(s) : val Value to check for specified bit(s) set. +* +* mask Mask of bits to check if set (see Note #2). +* +* Return(s) : DEF_YES, if ANY specified bit(s) are set in value. +* +* DEF_NO, if ALL specified bit(s) are NOT set in value. +* +* Caller(s) : Application. +* +* Note(s) : (1) 'val' & 'mask' SHOULD be unsigned integers. +* +* (2) NULL 'mask' allowed; returns 'DEF_NO' since NO mask bits specified. +********************************************************************************************************* +*/ + +#define DEF_BIT_IS_SET_ANY(val, mask) ((((val) & (mask)) == 0u) ? (DEF_NO ) : (DEF_YES)) + + +/* +********************************************************************************************************* +* DEF_BIT_IS_CLR_ANY() +* +* Description : Determine if any specified bit(s) in a value are clear. +* +* Argument(s) : val Value to check for specified bit(s) clear. +* +* mask Mask of bits to check if clear (see Note #2). +* +* Return(s) : DEF_YES, if ANY specified bit(s) are clear in value. +* +* DEF_NO, if ALL specified bit(s) are NOT clear in value. +* +* Note(s) : (1) 'val' & 'mask' SHOULD be unsigned integers. +* +* (2) NULL 'mask' allowed; returns 'DEF_NO' since NO mask bits specified. +********************************************************************************************************* +*/ + +#define DEF_BIT_IS_CLR_ANY(val, mask) ((((val) & (mask)) == (mask)) ? (DEF_NO ) : (DEF_YES)) + + +/* +********************************************************************************************************* +* VALUE MACRO'S +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* DEF_CHK_VAL_MIN() +* +* Description : Validate a value as greater than or equal to a specified minimum value. +* +* Argument(s) : val Value to validate. +* +* val_min Minimum value to test. +* +* Return(s) : DEF_OK, Value is greater than or equal to minimum value. +* +* DEF_FAIL, otherwise. +* +* Caller(s) : Application. +* +* Note(s) : (1) DEF_CHK_VAL_MIN() avoids directly comparing any two values if only one of the values +* is negative since the negative value might be incorrectly promoted to an arbitrary +* unsigned value if the other value to compare is unsigned. +* +* (2) Validation of values is limited to the range supported by the compiler &/or target +* environment. All other values that underflow/overflow the supported range will +* modulo/wrap into the supported range as arbitrary signed or unsigned values. +* +* Therefore, any values that underflow the most negative signed value or overflow +* the most positive unsigned value supported by the compiler &/or target environment +* cannot be validated : +* +* ( N-1 N ] +* ( -(2 ) , 2 - 1 ] +* ( ] +* +* where +* N Number of data word bits supported by the compiler +* &/or target environment +* +* (a) Note that the most negative value, -2^(N-1), is NOT included in the supported +* range since many compilers do NOT always correctly handle this value. +* +* (3) 'val' and 'val_min' are compared to 1 instead of 0 to avoid warning generated for +* unsigned numbers. +********************************************************************************************************* +*/ + +#define DEF_CHK_VAL_MIN(val, val_min) (((!(((val) >= 1) && ((val_min) < 1))) && \ + ((((val_min) >= 1) && ((val) < 1)) || \ + ((val) < (val_min)))) ? DEF_FAIL : DEF_OK) + + +/* +********************************************************************************************************* +* DEF_CHK_VAL_MAX() +* +* Description : Validate a value as less than or equal to a specified maximum value. +* +* Argument(s) : val Value to validate. +* +* val_max Maximum value to test. +* +* Return(s) : DEF_OK, Value is less than or equal to maximum value. +* +* DEF_FAIL, otherwise. +* +* Caller(s) : Application. +* +* Note(s) : (1) DEF_CHK_VAL_MAX() avoids directly comparing any two values if only one of the values +* is negative since the negative value might be incorrectly promoted to an arbitrary +* unsigned value if the other value to compare is unsigned. +* +* (2) Validation of values is limited to the range supported by the compiler &/or target +* environment. All other values that underflow/overflow the supported range will +* modulo/wrap into the supported range as arbitrary signed or unsigned values. +* +* Therefore, any values that underflow the most negative signed value or overflow +* the most positive unsigned value supported by the compiler &/or target environment +* cannot be validated : +* +* ( N-1 N ] +* ( -(2 ) , 2 - 1 ] +* ( ] +* +* where +* N Number of data word bits supported by the compiler +* &/or target environment +* +* (a) Note that the most negative value, -2^(N-1), is NOT included in the supported +* range since many compilers do NOT always correctly handle this value. +* +* (3) 'val' and 'val_max' are compared to 1 instead of 0 to avoid warning generated for +* unsigned numbers. +********************************************************************************************************* +*/ + +#define DEF_CHK_VAL_MAX(val, val_max) (((!(((val_max) >= 1) && ((val) < 1))) && \ + ((((val) >= 1) && ((val_max) < 1)) || \ + ((val) > (val_max)))) ? DEF_FAIL : DEF_OK) + + +/* +********************************************************************************************************* +* DEF_CHK_VAL() +* +* Description : Validate a value as greater than or equal to a specified minimum value & less than or +* equal to a specified maximum value. +* +* Argument(s) : val Value to validate. +* +* val_min Minimum value to test. +* +* val_max Maximum value to test. +* +* Return(s) : DEF_OK, Value is greater than or equal to minimum value AND +* less than or equal to maximum value. +* +* DEF_FAIL, otherwise. +* +* Caller(s) : Application. +* +* Note(s) : (1) DEF_CHK_VAL() avoids directly comparing any two values if only one of the values +* is negative since the negative value might be incorrectly promoted to an arbitrary +* unsigned value if the other value to compare is unsigned. +* +* (2) Validation of values is limited to the range supported by the compiler &/or target +* environment. All other values that underflow/overflow the supported range will +* modulo/wrap into the supported range as arbitrary signed or unsigned values. +* +* Therefore, any values that underflow the most negative signed value or overflow +* the most positive unsigned value supported by the compiler &/or target environment +* cannot be validated : +* +* ( N-1 N ] +* ( -(2 ) , 2 - 1 ] +* ( ] +* +* where +* N Number of data word bits supported by the compiler +* &/or target environment +* +* (a) Note that the most negative value, -2^(N-1), is NOT included in the supported +* range since many compilers do NOT always correctly handle this value. +* +* (3) DEF_CHK_VAL() does NOT validate that the maximum value ('val_max') is greater than +* or equal to the minimum value ('val_min'). +********************************************************************************************************* +*/ + +#define DEF_CHK_VAL(val, val_min, val_max) (((DEF_CHK_VAL_MIN((val), (val_min)) == DEF_FAIL) || \ + (DEF_CHK_VAL_MAX((val), (val_max)) == DEF_FAIL)) ? DEF_FAIL : DEF_OK) + + +/* +********************************************************************************************************* +* DEF_GET_U_MAX_VAL() +* +* Description : Get the maximum unsigned value that can be represented in an unsigned integer variable +* of the same data type size as an object. +* +* Argument(s) : obj Object or data type to return maximum unsigned value (see Note #1). +* +* Return(s) : Maximum unsigned integer value that can be represented by the object, if NO error(s). +* +* 0, otherwise. +* +* Caller(s) : Application. +* +* Note(s) : (1) 'obj' SHOULD be an integer object or data type but COULD also be a character or +* pointer object or data type. +********************************************************************************************************* +*/ + +#if (CPU_CFG_DATA_SIZE_MAX == CPU_WORD_SIZE_08) + +#define DEF_GET_U_MAX_VAL(obj) ((sizeof(obj) == CPU_WORD_SIZE_08) ? DEF_INT_08U_MAX_VAL : 0) + + +#elif (CPU_CFG_DATA_SIZE_MAX == CPU_WORD_SIZE_16) + +#define DEF_GET_U_MAX_VAL(obj) ((sizeof(obj) == CPU_WORD_SIZE_08) ? DEF_INT_08U_MAX_VAL : \ + ((sizeof(obj) == CPU_WORD_SIZE_16) ? DEF_INT_16U_MAX_VAL : 0)) + + +#elif (CPU_CFG_DATA_SIZE_MAX == CPU_WORD_SIZE_32) + +#define DEF_GET_U_MAX_VAL(obj) ((sizeof(obj) == CPU_WORD_SIZE_08) ? DEF_INT_08U_MAX_VAL : \ + ((sizeof(obj) == CPU_WORD_SIZE_16) ? DEF_INT_16U_MAX_VAL : \ + ((sizeof(obj) == CPU_WORD_SIZE_32) ? DEF_INT_32U_MAX_VAL : 0))) + + +#elif (CPU_CFG_DATA_SIZE_MAX == CPU_WORD_SIZE_64) + +#define DEF_GET_U_MAX_VAL(obj) ((sizeof(obj) == CPU_WORD_SIZE_08) ? DEF_INT_08U_MAX_VAL : \ + ((sizeof(obj) == CPU_WORD_SIZE_16) ? DEF_INT_16U_MAX_VAL : \ + ((sizeof(obj) == CPU_WORD_SIZE_32) ? DEF_INT_32U_MAX_VAL : \ + ((sizeof(obj) == CPU_WORD_SIZE_64) ? DEF_INT_64U_MAX_VAL : 0)))) + +#else + +#error "CPU_CFG_DATA_SIZE_MAX illegally #defined in 'cpu.h' " +#error " [See 'cpu.h CONFIGURATION ERRORS']" + +#endif + + +/* +********************************************************************************************************* +* MATH MACRO'S +* +* Note(s) : (1) Ideally, ALL mathematical macro's & functions SHOULD be defined in the custom mathematics +* library ('lib_math.*'). #### However, to maintain backwards compatibility with previously- +* released modules, mathematical macro & function definitions should only be moved to the +* custom mathematics library once all previously-released modules are updated to include the +* custom mathematics library. +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* DEF_MIN() +* +* Description : Determine the minimum of two values. +* +* Argument(s) : a First value. +* +* b Second value. +* +* Return(s) : Minimum of the two values. +* +* Caller(s) : Application. +* +* Note(s) : none. +********************************************************************************************************* +*/ + +#define DEF_MIN(a, b) (((a) < (b)) ? (a) : (b)) + + +/* +********************************************************************************************************* +* DEF_MAX() +* +* Description : Determine the maximum of two values. +* +* Argument(s) : a First value. +* +* b Second value. +* +* Return(s) : Maximum of the two values. +* +* Note(s) : none. +********************************************************************************************************* +*/ + +#define DEF_MAX(a, b) (((a) > (b)) ? (a) : (b)) + + +/* +********************************************************************************************************* +* DEF_ABS() +* +* Description : Determine the absolute value of a value. +* +* Argument(s) : a Value to calculate absolute value. +* +* Return(s) : Absolute value of the value. +* +* Caller(s) : Application. +* +* Note(s) : none. +********************************************************************************************************* +*/ + +#define DEF_ABS(a) (((a) < 0) ? (-(a)) : (a)) + + +/* +********************************************************************************************************* +* FUNCTION PROTOTYPES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* CONFIGURATION ERRORS +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LIBRARY CONFIGURATION ERRORS +********************************************************************************************************* +*/ + + /* See 'lib_def.h Note #1a'. */ +#if (CPU_CORE_VERSION < 12900u) +#error "CPU_CORE_VERSION [SHOULD be >= V1.29.00]" +#endif + + +/* +********************************************************************************************************* +* MODULE END +* +* Note(s) : (1) See 'lib_def.h MODULE'. +********************************************************************************************************* +*/ + +#endif /* End of lib def module include. */ + diff --git a/Middlewares/Third_Party/Micrium/uC-LIB/lib_math.c b/Middlewares/Third_Party/Micrium/uC-LIB/lib_math.c new file mode 100644 index 0000000..1c6ffc3 --- /dev/null +++ b/Middlewares/Third_Party/Micrium/uC-LIB/lib_math.c @@ -0,0 +1,281 @@ +/* +********************************************************************************************************* +* uC/LIB +* CUSTOM LIBRARY MODULES +* +* (c) Copyright 2004-2014; Micrium, Inc.; Weston, FL +* +* All rights reserved. Protected by international copyright laws. +* +* uC/LIB is provided in source form to registered licensees ONLY. It is +* illegal to distribute this source code to any third party unless you receive +* written permission by an authorized Micrium representative. Knowledge of +* the source code may NOT be used to develop a similar product. +* +* Please help us continue to provide the Embedded community with the finest +* software available. Your honesty is greatly appreciated. +* +* You can find our product's user manual, API reference, release notes and +* more information at: https://doc.micrium.com +* +* You can contact us at: http://www.micrium.com +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* +* MATHEMATIC OPERATIONS +* +* Filename : lib_math.c +* Version : V1.38.01 +* Programmer(s) : SR +* ITJ +********************************************************************************************************* +* Note(s) : (1) NO compiler-supplied standard library functions are used in library or product software. +* +* (a) ALL standard library functions are implemented in the custom library modules : +* +* (1) \\lib_*.* +* +* (2) \\Ports\\\lib*_a.* +* +* where +* directory path for custom library software +* directory name for specific processor (CPU) +* directory name for specific compiler +* +* (b) Product-specific library functions are implemented in individual products. +* +********************************************************************************************************* +* Notice(s) : (1) The Institute of Electrical and Electronics Engineers and The Open Group, have given +* us permission to reprint portions of their documentation. Portions of this text are +* reprinted and reproduced in electronic form from the IEEE Std 1003.1, 2004 Edition, +* Standard for Information Technology -- Portable Operating System Interface (POSIX), +* The Open Group Base Specifications Issue 6, Copyright (C) 2001-2004 by the Institute +* of Electrical and Electronics Engineers, Inc and The Open Group. In the event of any +* discrepancy between these versions and the original IEEE and The Open Group Standard, +* the original IEEE and The Open Group Standard is the referee document. The original +* Standard can be obtained online at http://www.opengroup.org/unix/online.html. +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* INCLUDE FILES +********************************************************************************************************* +*/ + +#define MICRIUM_SOURCE +#define LIB_MATH_MODULE +#include + + +/* +********************************************************************************************************* +* LOCAL DEFINES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL CONSTANTS +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL DATA TYPES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL TABLES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL GLOBAL VARIABLES +********************************************************************************************************* +*/ + +RAND_NBR Math_RandSeedCur; /* Cur rand nbr seed. */ + + +/* +********************************************************************************************************* +* LOCAL FUNCTION PROTOTYPES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL CONFIGURATION ERRORS +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* Math_Init() +* +* Description : (1) Initialize Mathematic Module : +* +* (a) Initialize random number seed value +* +* +* Argument(s) : none. +* +* Return(s) : none. +* +* Caller(s) : Application. +* +* Note(s) : (2) IEEE Std 1003.1, 2004 Edition, Section 'rand() : DESCRIPTION' states that "if rand() +* is called before any calls to srand() are made, the same sequence shall be generated +* as when srand() is first called with a seed value of 1". +********************************************************************************************************* +*/ + +void Math_Init (void) +{ + Math_RandSetSeed((RAND_NBR)RAND_SEED_INIT_VAL); /* See Note #2. */ +} + + +/* +********************************************************************************************************* +* Math_RandSetSeed() +* +* Description : Set the current pseudo-random number generator seed. +* +* Argument(s) : seed Initial (or current) value to set for the pseudo-random number sequence. +* +* Return(s) : none. +* +* Caller(s) : Application. +* +* Note(s) : (1) IEEE Std 1003.1, 2004 Edition, Section 'rand() : DESCRIPTION' states that "srand() +* ... uses the argument as a seed for a new sequence of pseudo-random numbers to be +* returned by subsequent calls to rand()". +* +* (2) 'Math_RandSeedCur' MUST always be accessed exclusively in critical sections. +* +* See also 'Math_Rand() Note #1b'. +********************************************************************************************************* +*/ + +void Math_RandSetSeed (RAND_NBR seed) +{ + CPU_SR_ALLOC(); + + + CPU_CRITICAL_ENTER(); + Math_RandSeedCur = seed; + CPU_CRITICAL_EXIT(); +} + + +/* +********************************************************************************************************* +* Math_Rand() +* +* Description : Calculate the next pseudo-random number. +* +* Argument(s) : none. +* +* Return(s) : Next pseudo-random number in the sequence after 'Math_RandSeedCur'. +* +* Caller(s) : Application. +* +* Note(s) : (1) (a) The pseudo-random number generator is implemented as a Linear Congruential +* Generator (LCG). +* +* (b) The pseudo-random number generated is in the range [0, RAND_LCG_PARAM_M]. +* +* See also 'Math_RandSeed() Note #1'. +* +* (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'rand() : DESCRIPTION' states that "rand() +* ... need not be reentrant ... [and] is not required to be thread-safe". +* +* (b) However, in order to implement Math_Rand() as re-entrant; 'Math_RandSeedCur' MUST +* always be accessed & updated exclusively in critical sections. +* +* See also 'Math_RandSeed() Note #2'. +********************************************************************************************************* +*/ + +RAND_NBR Math_Rand (void) +{ + RAND_NBR seed; + RAND_NBR rand_nbr; + CPU_SR_ALLOC(); + + + CPU_CRITICAL_ENTER(); + seed = Math_RandSeedCur; + rand_nbr = Math_RandSeed(seed); + Math_RandSeedCur = rand_nbr; + CPU_CRITICAL_EXIT(); + + return (rand_nbr); +} + + +/* +********************************************************************************************************* +* Math_RandSeed() +* +* Description : Calculate the next pseudo-random number. +* +* Argument(s) : seed Initial (or current) value for the pseudo-random number sequence. +* +* Return(s) : Next pseudo-random number in the sequence after 'seed'. +* +* Caller(s) : Math_Rand(), +* Application. +* +* Note(s) : (1) (a) BSD/ANSI-C implements rand() as a Linear Congruential Generator (LCG) : +* +* (A) random_number = [(a * random_number ) + b] modulo m +* n + 1 n +* +* where +* (1) (a) random_number Next random number to generate +* n+1 +* (b) random_number Previous random number generated +* n +* +* (2) a = RAND_LCG_PARAM_A LCG multiplier +* (3) b = RAND_LCG_PARAM_B LCG incrementor +* (4) m = RAND_LCG_PARAM_M + 1 LCG modulus +* +* (b) The pseudo-random number generated is in the range [0, RAND_LCG_PARAM_M]. +* + See also 'lib_math.h RANDOM NUMBER DEFINES Note #1b'. +* +* (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'rand() : DESCRIPTION' states that "rand() +* ... need not be reentrant ... [and] is not required to be thread-safe". +* +* (b) However, Math_RandSeed() is re-entrant since it calculates the next random number +* using ONLY local variables. +********************************************************************************************************* +*/ + +RAND_NBR Math_RandSeed (RAND_NBR seed) +{ + RAND_NBR rand_nbr; + + + rand_nbr = (((RAND_NBR)RAND_LCG_PARAM_A * seed) + (RAND_NBR)RAND_LCG_PARAM_B) % ((RAND_NBR)RAND_LCG_PARAM_M + 1u); + + return (rand_nbr); +} + diff --git a/Middlewares/Third_Party/Micrium/uC-LIB/lib_math.h b/Middlewares/Third_Party/Micrium/uC-LIB/lib_math.h new file mode 100644 index 0000000..ef550a4 --- /dev/null +++ b/Middlewares/Third_Party/Micrium/uC-LIB/lib_math.h @@ -0,0 +1,298 @@ +/* +********************************************************************************************************* +* uC/LIB +* CUSTOM LIBRARY MODULES +* +* (c) Copyright 2004-2014; Micrium, Inc.; Weston, FL +* +* All rights reserved. Protected by international copyright laws. +* +* uC/LIB is provided in source form to registered licensees ONLY. It is +* illegal to distribute this source code to any third party unless you receive +* written permission by an authorized Micrium representative. Knowledge of +* the source code may NOT be used to develop a similar product. +* +* Please help us continue to provide the Embedded community with the finest +* software available. Your honesty is greatly appreciated. +* +* You can find our product's user manual, API reference, release notes and +* more information at: https://doc.micrium.com +* +* You can contact us at: http://www.micrium.com +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* +* MATHEMATIC OPERATIONS +* +* Filename : lib_math.h +* Version : V1.38.01 +* Programmer(s) : SR +* ITJ +********************************************************************************************************* +* Note(s) : (1) NO compiler-supplied standard library functions are used in library or product software. +* +* (a) ALL standard library functions are implemented in the custom library modules : +* +* (1) \\lib_*.* +* +* (2) \\Ports\\\lib*_a.* +* +* where +* directory path for custom library software +* directory name for specific processor (CPU) +* directory name for specific compiler +* +* (b) Product-specific library functions are implemented in individual products. +* +********************************************************************************************************* +* Notice(s) : (1) The Institute of Electrical and Electronics Engineers and The Open Group, have given +* us permission to reprint portions of their documentation. Portions of this text are +* reprinted and reproduced in electronic form from the IEEE Std 1003.1, 2004 Edition, +* Standard for Information Technology -- Portable Operating System Interface (POSIX), +* The Open Group Base Specifications Issue 6, Copyright (C) 2001-2004 by the Institute +* of Electrical and Electronics Engineers, Inc and The Open Group. In the event of any +* discrepancy between these versions and the original IEEE and The Open Group Standard, +* the original IEEE and The Open Group Standard is the referee document. The original +* Standard can be obtained online at http://www.opengroup.org/unix/online.html. +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* MODULE +* +* Note(s) : (1) This mathematics library header file is protected from multiple pre-processor inclusion +* through use of the mathematics library module present pre-processor macro definition. +********************************************************************************************************* +*/ + +#ifndef LIB_MATH_MODULE_PRESENT /* See Note #1. */ +#define LIB_MATH_MODULE_PRESENT + + +/* +********************************************************************************************************* +* INCLUDE FILES +* +* Note(s) : (1) The custom library software files are located in the following directories : +* +* (a) \\lib_*.* +* +* where +* directory path for custom library software +* +* (2) CPU-configuration software files are located in the following directories : +* +* (a) \\cpu_*.* +* (b) \\\\cpu*.* +* +* where +* directory path for common CPU-compiler software +* directory name for specific processor (CPU) +* directory name for specific compiler +* +* (3) Compiler MUST be configured to include as additional include path directories : +* +* (a) '\\' directory See Note #1a +* +* (b) (1) '\\' directory See Note #2a +* (2) '\\\\' directory See Note #2b +* +* (4) NO compiler-supplied standard library functions SHOULD be used. +********************************************************************************************************* +*/ + +#include +#include + +#include + + +/* +********************************************************************************************************* +* EXTERNS +********************************************************************************************************* +*/ + +#ifdef LIB_MATH_MODULE +#define LIB_MATH_EXT +#else +#define LIB_MATH_EXT extern +#endif + + +/* +********************************************************************************************************* +* DEFINES +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* RANDOM NUMBER DEFINES +* +* Note(s) : (1) (a) IEEE Std 1003.1, 2004 Edition, Section 'rand() : DESCRIPTION' states that "if rand() +* is called before any calls to srand() are made, the same sequence shall be generated +* as when srand() is first called with a seed value of 1". +* +* (b) (1) BSD/ANSI-C implements rand() as a Linear Congruential Generator (LCG) : +* +* (A) random_number = [(a * random_number ) + b] modulo m +* n + 1 n +* +* where +* (1) (a) random_number Next random number to generate +* n+1 +* (b) random_number Previous random number generated +* n +* (c) random_number Initial random number seed +* 0 See also Note #1a +* +* (2) a = 1103515245 LCG multiplier +* (3) b = 12345 LCG incrementor +* (4) m = RAND_MAX + 1 LCG modulus See also Note #1b2 +* +* (2) (A) IEEE Std 1003.1, 2004 Edition, Section 'rand() : DESCRIPTION' states that +* "rand() ... shall compute a sequence of pseudo-random integers in the range +* [0, {RAND_MAX}] with a period of at least 2^32". +* +* (B) However, BSD/ANSI-C 'stdlib.h' defines "RAND_MAX" as "0x7fffffff", or 2^31; +* which therefore limits the range AND period to no more than 2^31. +********************************************************************************************************* +*/ + +#define RAND_SEED_INIT_VAL 1u /* See Note #1a. */ + +#define RAND_LCG_PARAM_M 0x7FFFFFFFu /* See Note #1b2B. */ +#define RAND_LCG_PARAM_A 1103515245u /* See Note #1b1A2. */ +#define RAND_LCG_PARAM_B 12345u /* See Note #1b1A3. */ + + +/* +********************************************************************************************************* +* DATA TYPES +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* RANDOM NUMBER DATA TYPE +********************************************************************************************************* +*/ + +typedef CPU_INT32U RAND_NBR; + + +/* +********************************************************************************************************* +* GLOBAL VARIABLES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* MACROS +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* MATH_IS_PWR2() +* +* Description : Determine if a value is a power of 2. +* +* Argument(s) : nbr Value. +* +* Return(s) : DEF_YES, 'nbr' is a power of 2. +* +* DEF_NO, 'nbr' is not a power of 2. +* +* Caller(s) : Application. +* +* Note(s) : none. +********************************************************************************************************* +*/ + +#define MATH_IS_PWR2(nbr) ((((nbr) != 0u) && (((nbr) & ((nbr) - 1u)) == 0u)) ? DEF_YES : DEF_NO) + + +/* +********************************************************************************************************* +* MATH_ROUND_INC_UP_PWR2() +* +* Description : Round value up to the next (power of 2) increment. +* +* Argument(s) : nbr Value to round. +* +* inc Increment to use. MUST be a power of 2. +* +* Return(s) : Rounded up value. +* +* Caller(s) : Application. +* +* Note(s) : none. +********************************************************************************************************* +*/ + +#define MATH_ROUND_INC_UP_PWR2(nbr, inc) (((nbr) & ~((inc) - 1)) + (((nbr) & ((inc) - 1)) == 0 ? 0 : (inc))) + + +/* +********************************************************************************************************* +* MATH_ROUND_INC_UP() +* +* Description : Round value up to the next increment. +* +* Argument(s) : nbr Value to round. +* +* inc Increment to use. +* +* Return(s) : Rounded up value. +* +* Caller(s) : Application. +* +* Note(s) : none. +********************************************************************************************************* +*/ + +#define MATH_ROUND_INC_UP(nbr, inc) (((nbr) + ((inc) - 1)) / (inc) * (inc)) + + +/* +********************************************************************************************************* +* FUNCTION PROTOTYPES +********************************************************************************************************* +*/ + +void Math_Init (void); + + /* ------------------ RAND NBR FNCTS ------------------ */ +void Math_RandSetSeed(RAND_NBR seed); + +RAND_NBR Math_Rand (void); + +RAND_NBR Math_RandSeed (RAND_NBR seed); + + +/* +********************************************************************************************************* +* CONFIGURATION ERRORS +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* MODULE END +* +* Note(s) : (1) See 'lib_math.h MODULE'. +********************************************************************************************************* +*/ + +#endif /* End of lib math module include. */ + diff --git a/Middlewares/Third_Party/Micrium/uC-LIB/lib_mem.c b/Middlewares/Third_Party/Micrium/uC-LIB/lib_mem.c new file mode 100644 index 0000000..0c403a7 --- /dev/null +++ b/Middlewares/Third_Party/Micrium/uC-LIB/lib_mem.c @@ -0,0 +1,2842 @@ +/* +********************************************************************************************************* +* uC/LIB +* CUSTOM LIBRARY MODULES +* +* (c) Copyright 2004-2014; Micrium, Inc.; Weston, FL +* +* All rights reserved. Protected by international copyright laws. +* +* uC/LIB is provided in source form to registered licensees ONLY. It is +* illegal to distribute this source code to any third party unless you receive +* written permission by an authorized Micrium representative. Knowledge of +* the source code may NOT be used to develop a similar product. +* +* Please help us continue to provide the Embedded community with the finest +* software available. Your honesty is greatly appreciated. +* +* You can find our product's user manual, API reference, release notes and +* more information at: https://doc.micrium.com +* +* You can contact us at: http://www.micrium.com +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* +* STANDARD MEMORY OPERATIONS +* +* Filename : lib_mem.c +* Version : V1.38.01 +* Programmer(s) : ITJ +* FGK +* JFD +* FBJ +* EJ +********************************************************************************************************* +* Note(s) : (1) NO compiler-supplied standard library functions are used in library or product software. +* +* (a) ALL standard library functions are implemented in the custom library modules : +* +* (1) \\lib_*.* +* +* (2) \\Ports\\\lib*_a.* +* +* where +* directory path for custom library software +* directory name for specific processor (CPU) +* directory name for specific compiler +* +* (b) Product-specific library functions are implemented in individual products. +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* INCLUDE FILES +********************************************************************************************************* +*/ + +#define MICRIUM_SOURCE +#define LIB_MEM_MODULE +#include "lib_mem.h" +#include "lib_math.h" +#include "lib_str.h" + + +/* +********************************************************************************************************* +* LOCAL DEFINES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL CONSTANTS +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL DATA TYPES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL TABLES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL GLOBAL VARIABLES +********************************************************************************************************* +*/ + + +#if (LIB_MEM_CFG_HEAP_SIZE > 0u) +#ifndef LIB_MEM_CFG_HEAP_BASE_ADDR +CPU_INT08U Mem_Heap[LIB_MEM_CFG_HEAP_SIZE]; /* Mem heap. */ +#endif + +MEM_SEG Mem_SegHeap; /* Heap mem seg. */ +#endif + +MEM_SEG *Mem_SegHeadPtr; /* Ptr to head of seg list. */ + + +/* +********************************************************************************************************* +* LOCAL FUNCTION PROTOTYPES +********************************************************************************************************* +*/ + +static void Mem_SegCreateCritical (const CPU_CHAR *p_name, + MEM_SEG *p_seg, + CPU_ADDR seg_base_addr, + CPU_SIZE_T padding_align, + CPU_SIZE_T size); + +static MEM_SEG *Mem_SegOverlapChkCritical( CPU_ADDR seg_base_addr, + CPU_SIZE_T size, + LIB_ERR *p_err); + +static void *Mem_SegAllocInternal (const CPU_CHAR *p_name, + MEM_SEG *p_seg, + CPU_SIZE_T size, + CPU_SIZE_T align, + CPU_SIZE_T padding_align, + CPU_SIZE_T *p_bytes_reqd, + LIB_ERR *p_err); + +static void *Mem_SegAllocExtCritical ( MEM_SEG *p_seg, + CPU_SIZE_T size, + CPU_SIZE_T align, + CPU_SIZE_T padding_align, + CPU_SIZE_T *p_bytes_reqd, + LIB_ERR *p_err); + +static void Mem_DynPoolCreateInternal(const CPU_CHAR *p_name, + MEM_DYN_POOL *p_pool, + MEM_SEG *p_seg, + CPU_SIZE_T blk_size, + CPU_SIZE_T blk_align, + CPU_SIZE_T blk_padding_align, + CPU_SIZE_T blk_qty_init, + CPU_SIZE_T blk_qty_max, + LIB_ERR *p_err); + +#if (LIB_MEM_CFG_DBG_INFO_EN == DEF_ENABLED) +static void Mem_SegAllocTrackCritical(const CPU_CHAR *p_name, + MEM_SEG *p_seg, + CPU_SIZE_T size, + LIB_ERR *p_err); +#endif + +#if ((LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) && \ + (LIB_MEM_CFG_HEAP_SIZE > 0u)) +static CPU_BOOLEAN Mem_PoolBlkIsValidAddr ( MEM_POOL *p_pool, + void *p_mem); +#endif + + +/* +********************************************************************************************************* +* LOCAL CONFIGURATION ERRORS +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +********************************************************************************************************* +* GLOBAL FUNCTIONS +********************************************************************************************************* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* Mem_Init() +* +* Description : (1) Initializes Memory Management Module : +* +* (a) Initialize heap memory pool +* (b) Initialize memory pool table +* +* +* Argument(s) : none. +* +* Return(s) : none. +* +* Caller(s) : Application. +* +* Note(s) : (2) Mem_Init() MUST be called ... : +* +* (a) ONLY ONCE from a product's application; ... +* (b) BEFORE product's application calls any memory library module function(s) +********************************************************************************************************* +*/ + +void Mem_Init (void) +{ + + /* ------------------ INIT SEG LIST ------------------- */ + Mem_SegHeadPtr = DEF_NULL; + +#if (LIB_MEM_CFG_HEAP_SIZE > 0u) + { + LIB_ERR err; + CPU_ADDR heap_base_addr; + + + /* ------------------ INIT HEAP SEG ------------------- */ +#ifdef LIB_MEM_CFG_HEAP_BASE_ADDR + heap_base_addr = LIB_MEM_CFG_HEAP_BASE_ADDR; +#else + heap_base_addr = (CPU_ADDR)&Mem_Heap[0u]; +#endif + + Mem_SegCreate("Heap", + &Mem_SegHeap, /* Create heap seg. */ + heap_base_addr, + LIB_MEM_CFG_HEAP_SIZE, + LIB_MEM_PADDING_ALIGN_NONE, + &err); + if (err != LIB_MEM_ERR_NONE) { + CPU_SW_EXCEPTION(;); + } + } +#endif +} + + +/* +********************************************************************************************************* +* Mem_Clr() +* +* Description : Clears data buffer (see Note #2). +* +* Argument(s) : pmem Pointer to memory buffer to clear. +* +* size Number of data buffer octets to clear (see Note #1). +* +* Return(s) : none. +* +* Caller(s) : Application. +* +* Note(s) : (1) Null clears allowed (i.e. zero-length clears). +* +* See also 'Mem_Set() Note #1'. +* +* (2) Clear data by setting each data octet to 0. +********************************************************************************************************* +*/ + +void Mem_Clr (void *pmem, + CPU_SIZE_T size) +{ + Mem_Set(pmem, + 0u, /* See Note #2. */ + size); +} + + +/* +********************************************************************************************************* +* Mem_Set() +* +* Description : Fills data buffer with specified data octet. +* +* Argument(s) : pmem Pointer to memory buffer to fill with specified data octet. +* +* data_val Data fill octet value. +* +* size Number of data buffer octets to fill (see Note #1). +* +* Return(s) : none. +* +* Caller(s) : Application. +* +* Note(s) : (1) Null sets allowed (i.e. zero-length sets). +* +* (2) For best CPU performance, optimized to fill data buffer using 'CPU_ALIGN'-sized data +* words. Since many word-aligned processors REQUIRE that multi-octet words be accessed on +* word-aligned addresses, 'CPU_ALIGN'-sized words MUST be accessed on 'CPU_ALIGN'd +* addresses. +* +* (3) Modulo arithmetic is used to determine whether a memory buffer starts on a 'CPU_ALIGN' +* address boundary. +* +* Modulo arithmetic in ANSI-C REQUIREs operations performed on integer values. Thus +* address values MUST be cast to an appropriately-sized integer value PRIOR to any +* 'mem_align_mod' arithmetic operation. +********************************************************************************************************* +*/ + +void Mem_Set (void *pmem, + CPU_INT08U data_val, + CPU_SIZE_T size) +{ + CPU_SIZE_T size_rem; + CPU_ALIGN data_align; + CPU_ALIGN *pmem_align; + CPU_INT08U *pmem_08; + CPU_DATA mem_align_mod; + CPU_DATA i; + + +#if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) + if (size < 1) { /* See Note #1. */ + return; + } + if (pmem == (void *)0) { + return; + } +#endif + + + data_align = 0u; + for (i = 0u; i < sizeof(CPU_ALIGN); i++) { /* Fill each data_align octet with data val. */ + data_align <<= DEF_OCTET_NBR_BITS; + data_align |= (CPU_ALIGN)data_val; + } + + size_rem = size; + mem_align_mod = (CPU_INT08U)((CPU_ADDR)pmem % sizeof(CPU_ALIGN)); /* See Note #3. */ + + pmem_08 = (CPU_INT08U *)pmem; + if (mem_align_mod != 0u) { /* If leading octets avail, ... */ + i = mem_align_mod; + while ((size_rem > 0) && /* ... start mem buf fill with leading octets ... */ + (i < sizeof(CPU_ALIGN ))) { /* ... until next CPU_ALIGN word boundary. */ + *pmem_08++ = data_val; + size_rem -= sizeof(CPU_INT08U); + i++; + } + } + + pmem_align = (CPU_ALIGN *)pmem_08; /* See Note #2. */ + while (size_rem >= sizeof(CPU_ALIGN)) { /* While mem buf aligned on CPU_ALIGN word boundaries, */ + *pmem_align++ = data_align; /* ... fill mem buf with CPU_ALIGN-sized data. */ + size_rem -= sizeof(CPU_ALIGN); + } + + pmem_08 = (CPU_INT08U *)pmem_align; + while (size_rem > 0) { /* Finish mem buf fill with trailing octets. */ + *pmem_08++ = data_val; + size_rem -= sizeof(CPU_INT08U); + } +} + + +/* +********************************************************************************************************* +* Mem_Copy() +* +* Description : Copies data octets from one memory buffer to another memory buffer. +* +* Argument(s) : pdest Pointer to destination memory buffer. +* +* psrc Pointer to source memory buffer. +* +* size Number of octets to copy (see Note #1). +* +* Return(s) : none. +* +* Caller(s) : Application. +* +* Note(s) : (1) Null copies allowed (i.e. zero-length copies). +* +* (2) Memory buffers NOT checked for overlapping. +* +* (a) IEEE Std 1003.1, 2004 Edition, Section 'memcpy() : DESCRIPTION' states that "if +* copying takes place between objects that overlap, the behavior is undefined". +* +* (b) However, data octets from a source memory buffer at a higher address value SHOULD +* successfully copy to a destination memory buffer at a lower address value even +* if any octets of the memory buffers overlap as long as no individual, atomic CPU +* word copy overlaps. +* +* Since Mem_Copy() performs the data octet copy via 'CPU_ALIGN'-sized words &/or +* octets; & since 'CPU_ALIGN'-sized words MUST be accessed on word-aligned addresses +* (see Note #3b), neither 'CPU_ALIGN'-sized words nor octets at unique addresses can +* ever overlap. +* +* Therefore, Mem_Copy() SHOULD be able to successfully copy overlapping memory +* buffers as long as the source memory buffer is at a higher address value than the +* destination memory buffer. +* +* (3) For best CPU performance, optimized to copy data buffer using 'CPU_ALIGN'-sized data +* words. Since many word-aligned processors REQUIRE that multi-octet words be accessed on +* word-aligned addresses, 'CPU_ALIGN'-sized words MUST be accessed on 'CPU_ALIGN'd +* addresses. +* +* (4) Modulo arithmetic is used to determine whether a memory buffer starts on a 'CPU_ALIGN' +* address boundary. +* +* Modulo arithmetic in ANSI-C REQUIREs operations performed on integer values. Thus +* address values MUST be cast to an appropriately-sized integer value PRIOR to any +* 'mem_align_mod' arithmetic operation. +********************************************************************************************************* +*/ + +#if (LIB_MEM_CFG_OPTIMIZE_ASM_EN != DEF_ENABLED) +void Mem_Copy ( void *pdest, + const void *psrc, + CPU_SIZE_T size) +{ + CPU_SIZE_T size_rem; + CPU_SIZE_T mem_gap_octets; + CPU_ALIGN *pmem_align_dest; + const CPU_ALIGN *pmem_align_src; + CPU_INT08U *pmem_08_dest; + const CPU_INT08U *pmem_08_src; + CPU_DATA i; + CPU_DATA mem_align_mod_dest; + CPU_DATA mem_align_mod_src; + CPU_BOOLEAN mem_aligned; + + +#if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) + if (size < 1) { /* See Note #1. */ + return; + } + if (pdest == (void *)0) { + return; + } + if (psrc == (void *)0) { + return; + } +#endif + + + size_rem = size; + + pmem_08_dest = ( CPU_INT08U *)pdest; + pmem_08_src = (const CPU_INT08U *)psrc; + + mem_gap_octets = pmem_08_src - pmem_08_dest; + + + if (mem_gap_octets >= sizeof(CPU_ALIGN)) { /* Avoid bufs overlap. */ + /* See Note #4. */ + mem_align_mod_dest = (CPU_INT08U)((CPU_ADDR)pmem_08_dest % sizeof(CPU_ALIGN)); + mem_align_mod_src = (CPU_INT08U)((CPU_ADDR)pmem_08_src % sizeof(CPU_ALIGN)); + + mem_aligned = (mem_align_mod_dest == mem_align_mod_src) ? DEF_YES : DEF_NO; + + if (mem_aligned == DEF_YES) { /* If mem bufs' alignment offset equal, ... */ + /* ... optimize copy for mem buf alignment. */ + if (mem_align_mod_dest != 0u) { /* If leading octets avail, ... */ + i = mem_align_mod_dest; + while ((size_rem > 0) && /* ... start mem buf copy with leading octets ... */ + (i < sizeof(CPU_ALIGN ))) { /* ... until next CPU_ALIGN word boundary. */ + *pmem_08_dest++ = *pmem_08_src++; + size_rem -= sizeof(CPU_INT08U); + i++; + } + } + + pmem_align_dest = ( CPU_ALIGN *)pmem_08_dest; /* See Note #3. */ + pmem_align_src = (const CPU_ALIGN *)pmem_08_src; + while (size_rem >= sizeof(CPU_ALIGN)) { /* While mem bufs aligned on CPU_ALIGN word boundaries, */ + *pmem_align_dest++ = *pmem_align_src++; /* ... copy psrc to pdest with CPU_ALIGN-sized words. */ + size_rem -= sizeof(CPU_ALIGN); + } + + pmem_08_dest = ( CPU_INT08U *)pmem_align_dest; + pmem_08_src = (const CPU_INT08U *)pmem_align_src; + } + } + + while (size_rem > 0) { /* For unaligned mem bufs or trailing octets, ... */ + *pmem_08_dest++ = *pmem_08_src++; /* ... copy psrc to pdest by octets. */ + size_rem -= sizeof(CPU_INT08U); + } +} +#endif + + +/* +********************************************************************************************************* +* Mem_Move() +* +* Description : Moves data octets from one memory buffer to another memory buffer, or within the same +* memory buffer. Overlapping is correctly handled for all move operations. +* +* Argument(s) : pdest Pointer to destination memory buffer. +* +* psrc Pointer to source memory buffer. +* +* size Number of octets to move (see Note #1). +* +* Return(s) : none. +* +* Caller(s) : Application. +* +* Note(s) : (1) Null move operations allowed (i.e. zero-length). +* +* (2) Memory buffers checked for overlapping. +* +* (3) For best CPU performance, optimized to copy data buffer using 'CPU_ALIGN'-sized data +* words. Since many word-aligned processors REQUIRE that multi-octet words be accessed on +* word-aligned addresses, 'CPU_ALIGN'-sized words MUST be accessed on 'CPU_ALIGN'd +* addresses. +* +* (4) Modulo arithmetic is used to determine whether a memory buffer starts on a 'CPU_ALIGN' +* address boundary. +* +* Modulo arithmetic in ANSI-C REQUIREs operations performed on integer values. Thus +* address values MUST be cast to an appropriately-sized integer value PRIOR to any +* 'mem_align_mod' arithmetic operation. +********************************************************************************************************* +*/ + +void Mem_Move ( void *pdest, + const void *psrc, + CPU_SIZE_T size) +{ + CPU_SIZE_T size_rem; + CPU_SIZE_T mem_gap_octets; + CPU_ALIGN *pmem_align_dest; + const CPU_ALIGN *pmem_align_src; + CPU_INT08U *pmem_08_dest; + const CPU_INT08U *pmem_08_src; + CPU_INT08S i; + CPU_DATA mem_align_mod_dest; + CPU_DATA mem_align_mod_src; + CPU_BOOLEAN mem_aligned; + + +#if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) + if (size < 1) { + return; + } + if (pdest == (void *)0) { + return; + } + if (psrc == (void *)0) { + return; + } +#endif + + pmem_08_src = (const CPU_INT08U *)psrc; + pmem_08_dest = ( CPU_INT08U *)pdest; + if (pmem_08_src > pmem_08_dest) { + Mem_Copy(pdest, psrc, size); + return; + } + + size_rem = size; + + pmem_08_dest = ( CPU_INT08U *)pdest + size - 1; + pmem_08_src = (const CPU_INT08U *)psrc + size - 1; + + mem_gap_octets = pmem_08_dest - pmem_08_src; + + + if (mem_gap_octets >= sizeof(CPU_ALIGN)) { /* Avoid bufs overlap. */ + + /* See Note #4. */ + mem_align_mod_dest = (CPU_INT08U)((CPU_ADDR)pmem_08_dest % sizeof(CPU_ALIGN)); + mem_align_mod_src = (CPU_INT08U)((CPU_ADDR)pmem_08_src % sizeof(CPU_ALIGN)); + + mem_aligned = (mem_align_mod_dest == mem_align_mod_src) ? DEF_YES : DEF_NO; + + if (mem_aligned == DEF_YES) { /* If mem bufs' alignment offset equal, ... */ + /* ... optimize copy for mem buf alignment. */ + if (mem_align_mod_dest != (sizeof(CPU_ALIGN) - 1)) {/* If leading octets avail, ... */ + i = mem_align_mod_dest; + while ((size_rem > 0) && /* ... start mem buf copy with leading octets ... */ + (i >= 0)) { /* ... until next CPU_ALIGN word boundary. */ + *pmem_08_dest-- = *pmem_08_src--; + size_rem -= sizeof(CPU_INT08U); + i--; + } + } + + /* See Note #3. */ + pmem_align_dest = ( CPU_ALIGN *)((CPU_INT08U *)pmem_08_dest - sizeof(CPU_ALIGN) + 1); + pmem_align_src = (const CPU_ALIGN *)((CPU_INT08U *)pmem_08_src - sizeof(CPU_ALIGN) + 1); + while (size_rem >= sizeof(CPU_ALIGN)) { /* While mem bufs aligned on CPU_ALIGN word boundaries, */ + *pmem_align_dest-- = *pmem_align_src--; /* ... copy psrc to pdest with CPU_ALIGN-sized words. */ + size_rem -= sizeof(CPU_ALIGN); + } + + pmem_08_dest = ( CPU_INT08U *)pmem_align_dest + sizeof(CPU_ALIGN) - 1; + pmem_08_src = (const CPU_INT08U *)pmem_align_src + sizeof(CPU_ALIGN) - 1; + + } + } + + while (size_rem > 0) { /* For unaligned mem bufs or trailing octets, ... */ + *pmem_08_dest-- = *pmem_08_src--; /* ... copy psrc to pdest by octets. */ + size_rem -= sizeof(CPU_INT08U); + } +} + + +/* +********************************************************************************************************* +* Mem_Cmp() +* +* Description : Verifies that ALL data octets in two memory buffers are identical in sequence. +* +* Argument(s) : p1_mem Pointer to first memory buffer. +* +* p2_mem Pointer to second memory buffer. +* +* size Number of data buffer octets to compare (see Note #1). +* +* Return(s) : DEF_YES, if 'size' number of data octets are identical in both memory buffers. +* +* DEF_NO, otherwise. +* +* Caller(s) : Application. +* +* Note(s) : (1) Null compares allowed (i.e. zero-length compares); 'DEF_YES' returned to indicate +* identical null compare. +* +* (2) Many memory buffer comparisons vary ONLY in the least significant octets -- e.g. +* network address buffers. Consequently, memory buffer comparison is more efficient +* if the comparison starts from the end of the memory buffers which will abort sooner +* on dissimilar memory buffers that vary only in the least significant octets. +* +* (3) For best CPU performance, optimized to compare data buffers using 'CPU_ALIGN'-sized +* data words. Since many word-aligned processors REQUIRE that multi-octet words be accessed on +* word-aligned addresses, 'CPU_ALIGN'-sized words MUST be accessed on 'CPU_ALIGN'd +* addresses. +* +* (4) Modulo arithmetic is used to determine whether a memory buffer starts on a 'CPU_ALIGN' +* address boundary. +* +* Modulo arithmetic in ANSI-C REQUIREs operations performed on integer values. Thus +* address values MUST be cast to an appropriately-sized integer value PRIOR to any +* 'mem_align_mod' arithmetic operation. +********************************************************************************************************* +*/ + +CPU_BOOLEAN Mem_Cmp (const void *p1_mem, + const void *p2_mem, + CPU_SIZE_T size) +{ + CPU_SIZE_T size_rem; + CPU_ALIGN *p1_mem_align; + CPU_ALIGN *p2_mem_align; + const CPU_INT08U *p1_mem_08; + const CPU_INT08U *p2_mem_08; + CPU_DATA i; + CPU_DATA mem_align_mod_1; + CPU_DATA mem_align_mod_2; + CPU_BOOLEAN mem_aligned; + CPU_BOOLEAN mem_cmp; + + + if (size < 1) { /* See Note #1. */ + return (DEF_YES); + } + if (p1_mem == (void *)0) { + return (DEF_NO); + } + if (p2_mem == (void *)0) { + return (DEF_NO); + } + + + mem_cmp = DEF_YES; /* Assume mem bufs are identical until cmp fails. */ + size_rem = size; + /* Start @ end of mem bufs (see Note #2). */ + p1_mem_08 = (const CPU_INT08U *)p1_mem + size; + p2_mem_08 = (const CPU_INT08U *)p2_mem + size; + /* See Note #4. */ + mem_align_mod_1 = (CPU_INT08U)((CPU_ADDR)p1_mem_08 % sizeof(CPU_ALIGN)); + mem_align_mod_2 = (CPU_INT08U)((CPU_ADDR)p2_mem_08 % sizeof(CPU_ALIGN)); + + mem_aligned = (mem_align_mod_1 == mem_align_mod_2) ? DEF_YES : DEF_NO; + + if (mem_aligned == DEF_YES) { /* If mem bufs' alignment offset equal, ... */ + /* ... optimize cmp for mem buf alignment. */ + if (mem_align_mod_1 != 0u) { /* If trailing octets avail, ... */ + i = mem_align_mod_1; + while ((mem_cmp == DEF_YES) && /* ... cmp mem bufs while identical & ... */ + (size_rem > 0) && /* ... start mem buf cmp with trailing octets ... */ + (i > 0)) { /* ... until next CPU_ALIGN word boundary. */ + p1_mem_08--; + p2_mem_08--; + if (*p1_mem_08 != *p2_mem_08) { /* If ANY data octet(s) NOT identical, cmp fails. */ + mem_cmp = DEF_NO; + } + size_rem -= sizeof(CPU_INT08U); + i--; + } + } + + if (mem_cmp == DEF_YES) { /* If cmp still identical, cmp aligned mem bufs. */ + p1_mem_align = (CPU_ALIGN *)p1_mem_08; /* See Note #3. */ + p2_mem_align = (CPU_ALIGN *)p2_mem_08; + + while ((mem_cmp == DEF_YES) && /* Cmp mem bufs while identical & ... */ + (size_rem >= sizeof(CPU_ALIGN))) { /* ... mem bufs aligned on CPU_ALIGN word boundaries. */ + p1_mem_align--; + p2_mem_align--; + if (*p1_mem_align != *p2_mem_align) { /* If ANY data octet(s) NOT identical, cmp fails. */ + mem_cmp = DEF_NO; + } + size_rem -= sizeof(CPU_ALIGN); + } + + p1_mem_08 = (CPU_INT08U *)p1_mem_align; + p2_mem_08 = (CPU_INT08U *)p2_mem_align; + } + } + + while ((mem_cmp == DEF_YES) && /* Cmp mem bufs while identical ... */ + (size_rem > 0)) { /* ... for unaligned mem bufs or trailing octets. */ + p1_mem_08--; + p2_mem_08--; + if (*p1_mem_08 != *p2_mem_08) { /* If ANY data octet(s) NOT identical, cmp fails. */ + mem_cmp = DEF_NO; + } + size_rem -= sizeof(CPU_INT08U); + } + + return (mem_cmp); +} + + +/* +********************************************************************************************************* +* Mem_HeapAlloc() +* +* Description : Allocates a memory block from the heap memory segment. +* +* Argument(s) : size Size of memory block to allocate (in bytes). +* +* align Alignment of memory block to specific word boundary (in bytes). +* +* p_bytes_reqd Optional pointer to a variable to ... : +* +* (a) Return the number of bytes required to successfully +* allocate the memory block, if any error(s); +* (b) Return 0, otherwise. +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* LIB_MEM_ERR_NONE Operation was successful. +* LIB_MEM_ERR_HEAP_EMPTY No more memory available on heap. +* +* ---------------------RETURNED BY Mem_SegAllocInternal()--------------------- +* LIB_MEM_ERR_INVALID_MEM_ALIGN Invalid memory block alignment requested. +* LIB_MEM_ERR_INVALID_MEM_SIZE Invalid memory block size specified. +* LIB_MEM_ERR_NULL_PTR Error or segment data pointer NULL. +* +* Return(s) : Pointer to memory block, if NO error(s). +* +* Pointer to NULL, otherwise. +* +* Caller(s) : Application. +* +* Note(s) : (1) Pointers to variables that return values MUST be initialized PRIOR to all other +* validation or function handling in case of any error(s). +* +* (2) This function is DEPRECATED and will be removed in a future version of this product. +* Mem_SegAlloc(), Mem_SegAllocExt() or Mem_SegAllocHW() should be used instead. +********************************************************************************************************* +*/ + +#if (LIB_MEM_CFG_HEAP_SIZE > 0u) +void *Mem_HeapAlloc (CPU_SIZE_T size, + CPU_SIZE_T align, + CPU_SIZE_T *p_bytes_reqd, + LIB_ERR *p_err) +{ + void *p_mem; + + + p_mem = Mem_SegAllocInternal(DEF_NULL, + &Mem_SegHeap, + size, + align, + LIB_MEM_CFG_HEAP_PADDING_ALIGN, + p_bytes_reqd, + p_err); + if (*p_err == LIB_MEM_ERR_SEG_OVF) { + *p_err = LIB_MEM_ERR_HEAP_OVF; + } + + return (p_mem); +} +#endif + + +/* +********************************************************************************************************* +* Mem_HeapGetSizeRem() +* +* Description : Gets remaining heap memory size available to allocate. +* +* Argument(s) : align Desired word boundary alignment (in bytes) to return remaining memory size from. +* +* p_err Pointer to variable that will receive the return error code from this function +* +* LIB_MEM_ERR_NONE Operation was successful. +* +* --------------------RETURNED BY Mem_SegRemSizeGet()-------------------- +* LIB_MEM_ERR_NULL_PTR Segment data pointer NULL. +* LIB_MEM_ERR_INVALID_MEM_ALIGN Invalid memory alignment. +* +* Return(s) : Remaining heap memory size (in bytes), if NO error(s). +* +* 0, otherwise. +* +* Caller(s) : Application. +* +* Note(s) : (1) This function is DEPRECATED and will be removed in a future version of this product. +* Mem_SegRemSizeGet() should be used instead. +********************************************************************************************************* +*/ + +#if (LIB_MEM_CFG_HEAP_SIZE > 0u) +CPU_SIZE_T Mem_HeapGetSizeRem (CPU_SIZE_T align, + LIB_ERR *p_err) +{ + CPU_SIZE_T rem_size; + + + rem_size = Mem_SegRemSizeGet(&Mem_SegHeap, + align, + DEF_NULL, + p_err); + if (*p_err != LIB_MEM_ERR_NONE) { + return (0u); + } + + return (rem_size); +} +#endif + + +/* +********************************************************************************************************* +* Mem_SegCreate() +* +* Description : Creates a new memory segment to be used for runtime memory allocation. +* +* Argument(s) : p_name Pointer to segment name. +* +* p_seg Pointer to segment data. Must be allocated by caller. +* +* seg_base_addr Address of segment's first byte. +* +* size Total size of segment, in bytes. +* +* padding_align Padding alignment, in bytes, that will be added to any allocated buffer from +* this memory segment. MUST be a power of 2. LIB_MEM_PADDING_ALIGN_NONE +* means no padding. +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* LIB_MEM_ERR_NONE Operation was successful. +* LIB_MEM_ERR_INVALID_SEG_SIZE Invalid segment size specified. +* LIB_MEM_ERR_INVALID_MEM_ALIGN Invalid padding alignment. +* LIB_MEM_ERR_NULL_PTR Error or segment data pointer NULL. +* +* -------------------RETURNED BY Mem_SegOverlapChkCritical()------------------- +* LIB_MEM_ERR_INVALID_SEG_OVERLAP Segment overlaps another existing segment. +* LIB_MEM_ERR_INVALID_SEG_EXISTS Segment already exists. +* +* Return(s) : None. +* +* Caller(s) : Application. +* +* Note(s) : (1) New segments are checked for overlap with existing segments. A critical section needs +* to be maintained during the whole list search and add procedure to prevent a reentrant +* call from creating another segment overlapping with the one being added. +********************************************************************************************************* +*/ + +void Mem_SegCreate (const CPU_CHAR *p_name, + MEM_SEG *p_seg, + CPU_ADDR seg_base_addr, + CPU_SIZE_T size, + CPU_SIZE_T padding_align, + LIB_ERR *p_err) +{ + CPU_SR_ALLOC(); + + +#if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) + if (p_err == DEF_NULL) { /* Chk for null err ptr. */ + CPU_SW_EXCEPTION(;); + } + + if (p_seg == DEF_NULL) { /* Chk for null seg ptr. */ + *p_err = LIB_MEM_ERR_NULL_PTR; + return; + } + + if (size < 1u) { /* Chk for invalid sized seg. */ + *p_err = LIB_MEM_ERR_INVALID_SEG_SIZE; + return; + } + /* Chk for addr space ovf. */ + if (seg_base_addr + (size - 1u) < seg_base_addr) { + *p_err = LIB_MEM_ERR_INVALID_SEG_SIZE; + return; + } + + if ((padding_align != LIB_MEM_PADDING_ALIGN_NONE) && + (MATH_IS_PWR2(padding_align) != DEF_YES)) { + *p_err = LIB_MEM_ERR_INVALID_MEM_ALIGN; + return; + } +#endif + + CPU_CRITICAL_ENTER(); +#if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) + (void)Mem_SegOverlapChkCritical(seg_base_addr, /* Chk for overlap. */ + size, + p_err); + if (*p_err != LIB_MEM_ERR_NONE) { + CPU_CRITICAL_EXIT(); + return; + } +#endif + + Mem_SegCreateCritical(p_name, /* Create seg. */ + p_seg, + seg_base_addr, + padding_align, + size); + CPU_CRITICAL_EXIT(); + + *p_err = LIB_MEM_ERR_NONE; +} + + +/* +********************************************************************************************************* +* Mem_SegClr() +* +* Description : Clears a memory segment. +* +* Argument(s) : p_seg Pointer to segment data. Must be allocated by caller. +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* LIB_MEM_ERR_NONE Operation was successful. +* LIB_MEM_ERR_NULL_PTR Segment data pointer NULL. +* +* Return(s) : None. +* +* Caller(s) : Application. +* +* Note(s) : (1) This function must be used with extreme caution. It must only be called on memory +* segments that are no longer used. +* +* (2) This function is disabled when debug mode is enabled to avoid heap memory leaks. +********************************************************************************************************* +*/ + +#if (LIB_MEM_CFG_DBG_INFO_EN == DEF_DISABLED) +void Mem_SegClr (MEM_SEG *p_seg, + LIB_ERR *p_err) +{ + CPU_SR_ALLOC(); + + +#if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) + if (p_err == DEF_NULL) { /* Chk for null err ptr. */ + CPU_SW_EXCEPTION(;); + } + + if (p_seg == DEF_NULL) { /* Chk for null seg ptr. */ + *p_err = LIB_MEM_ERR_NULL_PTR; + return; + } +#endif + + CPU_CRITICAL_ENTER(); + p_seg->AddrNext = p_seg->AddrBase; + CPU_CRITICAL_EXIT(); + + *p_err = LIB_MEM_ERR_NONE; +} +#endif + + +/* +********************************************************************************************************* +* Mem_SegRemSizeGet() +* +* Description : Gets free space of memory segment. +* +* Argument(s) : p_seg Pointer to segment data. +* +* align Alignment in bytes to assume for calculation of free space. +* +* p_seg_info Pointer to structure that will receive further segment info data (used size, +* total size, base address and next allocation address). +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* LIB_MEM_ERR_NONE Operation was successful. +* LIB_MEM_ERR_NULL_PTR Segment data pointer NULL. +* LIB_MEM_ERR_INVALID_MEM_ALIGN Invalid memory alignment. +* +* Return(s) : Memory segment remaining size in bytes, if successful. +* 0, otherwise or if memory segment empty. +* +* Caller(s) : Application, +* Mem_HeapGetSizeRem(), +* Mem_OutputUsage(). +* +* Note(s) : None. +********************************************************************************************************* +*/ + +CPU_SIZE_T Mem_SegRemSizeGet (MEM_SEG *p_seg, + CPU_SIZE_T align, + MEM_SEG_INFO *p_seg_info, + LIB_ERR *p_err) +{ + CPU_SIZE_T rem_size; + CPU_SIZE_T total_size; + CPU_SIZE_T used_size; + CPU_ADDR next_addr_align; + CPU_SR_ALLOC(); + + +#if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) + if (p_err == DEF_NULL) { /* Chk for null err ptr. */ + CPU_SW_EXCEPTION(seg_info); + } + + if (MATH_IS_PWR2(align) != DEF_YES) { /* Chk for invalid align val. */ + *p_err = LIB_MEM_ERR_INVALID_MEM_ALIGN; + return (0u); + } +#endif + + if (p_seg == DEF_NULL) { /* Dflt to heap in case p_seg is null. */ +#if (LIB_MEM_CFG_HEAP_SIZE > 0u) + p_seg = &Mem_SegHeap; +#else + *p_err = LIB_MEM_ERR_NULL_PTR; + return (0u); +#endif + } + + CPU_CRITICAL_ENTER(); /* Calc seg stats. */ + next_addr_align = MATH_ROUND_INC_UP_PWR2(p_seg->AddrNext, align); + CPU_CRITICAL_EXIT(); + + total_size = p_seg->AddrEnd - p_seg->AddrBase + 1u; + used_size = next_addr_align - p_seg->AddrBase; + rem_size = total_size - used_size; + + if (p_seg_info != DEF_NULL) { + p_seg_info->TotalSize = total_size; + p_seg_info->UsedSize = used_size; + p_seg_info->AddrBase = p_seg->AddrBase; + p_seg_info->AddrNextAlloc = next_addr_align; + } + + *p_err = LIB_MEM_ERR_NONE; + + return (rem_size); +} + + +/* +********************************************************************************************************* +* Mem_SegAlloc() +* +* Description : Allocates memory from specified segment. Returned memory block will be aligned on a CPU +* word boundary. +* +* Argument(s) : p_name Pointer to allocated object name. Used for allocations tracking. May be DEF_NULL. +* +* p_seg Pointer to segment from which to allocate memory. Will be allocated from +* general-purpose heap if null. +* +* size Size of memory block to allocate, in bytes. +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* LIB_MEM_ERR_NONE Operation was successful. +* +* ------------------RETURNED BY Mem_SegAllocInternal()------------------- +* LIB_MEM_ERR_INVALID_MEM_ALIGN Invalid memory block alignment requested. +* LIB_MEM_ERR_INVALID_MEM_SIZE Invalid memory block size specified. +* LIB_MEM_ERR_NULL_PTR Error or segment data pointer NULL. +* LIB_MEM_ERR_SEG_OVF Allocation would overflow memory segment. +* +* Return(s) : Pointer to allocated memory block, if successful. +* +* DEF_NULL, otherwise. +* +* Caller(s) : Application. +* +* Note(s) : (1) The memory block returned by this function will be aligned on a word boundary. In +* order to specify a specific alignment value, use either Mem_SegAllocExt() or +* Mem_SegAllocHW(). +********************************************************************************************************* +*/ + +void *Mem_SegAlloc (const CPU_CHAR *p_name, + MEM_SEG *p_seg, + CPU_SIZE_T size, + LIB_ERR *p_err) +{ + void *p_blk; + + + if (p_seg == DEF_NULL) { /* Alloc from heap if p_seg is null. */ +#if (LIB_MEM_CFG_HEAP_SIZE > 0u) + p_seg = &Mem_SegHeap; +#else + *p_err = LIB_MEM_ERR_NULL_PTR; + return (DEF_NULL); +#endif + } + + p_blk = Mem_SegAllocInternal(p_name, + p_seg, + size, + sizeof(CPU_ALIGN), + LIB_MEM_PADDING_ALIGN_NONE, + DEF_NULL, + p_err); + + return (p_blk); +} + + +/* +********************************************************************************************************* +* Mem_SegAllocExt() +* +* Description : Allocates memory from specified memory segment. +* +* Argument(s) : p_name Pointer to allocated object name. Used for allocations tracking. May be DEF_NULL. +* +* p_seg Pointer to segment from which to allocate memory. Will be allocated from +* general-purpose heap if null. +* +* size Size of memory block to allocate, in bytes. +* +* align Required alignment of memory block, in bytes. MUST be a power of 2. +* +* p_bytes_reqd Pointer to variable that will receive the number of free bytes missing for +* the allocation to succeed. Set to DEF_NULL to skip calculation. +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* LIB_MEM_ERR_NONE Operation was successful. +* +* ------------------RETURNED BY Mem_SegAllocInternal()------------------- +* LIB_MEM_ERR_INVALID_MEM_ALIGN Invalid memory block alignment requested. +* LIB_MEM_ERR_INVALID_MEM_SIZE Invalid memory block size specified. +* LIB_MEM_ERR_NULL_PTR Error or segment data pointer NULL. +* LIB_MEM_ERR_SEG_OVF Allocation would overflow memory segment. +* +* Return(s) : Pointer to allocated memory block, if successful. +* +* DEF_NULL, otherwise. +* +* Caller(s) : Application. +* +* Note(s) : none. +********************************************************************************************************* +*/ + +void *Mem_SegAllocExt (const CPU_CHAR *p_name, + MEM_SEG *p_seg, + CPU_SIZE_T size, + CPU_SIZE_T align, + CPU_SIZE_T *p_bytes_reqd, + LIB_ERR *p_err) +{ + void *p_blk; + + + if (p_seg == DEF_NULL) { /* Alloc from heap if p_seg is null. */ +#if (LIB_MEM_CFG_HEAP_SIZE > 0u) + p_seg = &Mem_SegHeap; +#else + *p_err = LIB_MEM_ERR_NULL_PTR; + return (DEF_NULL); +#endif + } + + p_blk = Mem_SegAllocInternal(p_name, + p_seg, + size, + align, + LIB_MEM_PADDING_ALIGN_NONE, + p_bytes_reqd, + p_err); + + return (p_blk); +} + + +/* +********************************************************************************************************* +* Mem_SegAllocHW() +* +* Description : Allocates memory from specified segment. The returned buffer will be padded in function +* of memory segment's properties. +* +* Argument(s) : p_name Pointer to allocated object name. Used for allocations tracking. May be DEF_NULL. +* +* p_seg Pointer to segment from which to allocate memory. Will be allocated from +* general-purpose heap if null. +* +* size Size of memory block to allocate, in bytes. +* +* align Required alignment of memory block, in bytes. MUST be a power of 2. +* +* p_bytes_reqd Pointer to variable that will receive the number of free bytes missing for +* the allocation to succeed. Set to DEF_NULL to skip calculation. +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* LIB_MEM_ERR_NONE Operation was successful. +* +* ------------------RETURNED BY Mem_SegAllocInternal()------------------- +* LIB_MEM_ERR_INVALID_MEM_ALIGN Invalid memory block alignment requested. +* LIB_MEM_ERR_INVALID_MEM_SIZE Invalid memory block size specified. +* LIB_MEM_ERR_NULL_PTR Error or segment data pointer NULL. +* LIB_MEM_ERR_SEG_OVF Allocation would overflow memory segment. +* +* Return(s) : Pointer to allocated memory block, if successful. +* +* DEF_NULL, otherwise. +* +* Caller(s) : Application. +* +* Note(s) : none. +********************************************************************************************************* +*/ + +void *Mem_SegAllocHW (const CPU_CHAR *p_name, + MEM_SEG *p_seg, + CPU_SIZE_T size, + CPU_SIZE_T align, + CPU_SIZE_T *p_bytes_reqd, + LIB_ERR *p_err) +{ + void *p_blk; + + + if (p_seg == DEF_NULL) { /* Alloc from heap if p_seg is null. */ +#if (LIB_MEM_CFG_HEAP_SIZE > 0u) + p_seg = &Mem_SegHeap; +#else + *p_err = LIB_MEM_ERR_NULL_PTR; + return (DEF_NULL); +#endif + } + + p_blk = Mem_SegAllocInternal(p_name, + p_seg, + size, + align, + p_seg->PaddingAlign, + p_bytes_reqd, + p_err); + + return (p_blk); +} + + +/* +********************************************************************************************************* +* Mem_PoolCreate() +* +* Description : (1) Creates a memory pool : +* +* (a) Create memory pool from heap or dedicated memory +* (b) Allocate memory pool memory blocks +* (c) Configure memory pool +* +* +* Argument(s) : p_pool Pointer to a memory pool structure to create (see Note #1). +* +* p_mem_base Memory pool segment base address : +* +* (a) Null address Memory pool allocated from general-purpose heap. +* (b) Non-null address Memory pool allocated from dedicated memory +* specified by its base address. +* +* mem_size Size of memory pool segment (in bytes). +* +* blk_nbr Number of memory pool blocks to create. +* +* blk_size Size of memory pool blocks to create (in bytes). +* +* blk_align Alignment of memory pool blocks to specific word boundary (in bytes). +* +* p_bytes_reqd Optional pointer to a variable to ... : +* +* (a) Return the number of bytes required to successfully +* allocate the memory pool, if any error(s); +* (b) Return 0, otherwise. +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* LIB_MEM_ERR_NONE Operation was successful. +* LIB_MEM_ERR_NULL_PTR Pointer to memory pool is null. +* LIB_MEM_ERR_INVALID_BLK_ALIGN Invalid block alignment requested. +* LIB_MEM_ERR_INVALID_BLK_NBR Invalid number of blocks specified. +* LIB_MEM_ERR_INVALID_BLK_SIZE Invalid block size specified. +* LIB_MEM_ERR_INVALID_SEG_SIZE Invalid segment size. +* LIB_MEM_ERR_HEAP_EMPTY No more memory available on heap. +* +* ---------------RETURNED BY Mem_SegOverlapChkCritical()---------------- +* LIB_MEM_ERR_INVALID_SEG_EXISTS Segment already exists. +* LIB_MEM_ERR_INVALID_SEG_OVERLAP Segment overlaps another existing segment. +* +* -----------------RETURNED BY Mem_SegAllocExtCritical()----------------- +* LIB_MEM_ERR_SEG_OVF Allocation would overflow memory segment. +* +* ------------------RETURNED BY Mem_SegAllocInternal()------------------- +* LIB_MEM_ERR_INVALID_MEM_ALIGN Invalid memory block alignment requested. +* LIB_MEM_ERR_INVALID_MEM_SIZE Invalid memory block size specified. +* LIB_MEM_ERR_NULL_PTR Error or segment data pointer NULL. +* LIB_MEM_ERR_SEG_OVF Allocation would overflow memory segment. +* +* -----------------------RETURNED BY Mem_PoolClr()----------------------- +* LIB_MEM_ERR_NULL_PTR Argument 'p_pool' passed a NULL pointer. +* +* Return(s) : none. +* +* Caller(s) : Application. +* +* Note(s) : (1) This function is DEPRECATED and will be removed in a future version of this product. +* Mem_DynPoolCreate() or Mem_DynPoolCreateHW() should be used instead. +********************************************************************************************************* +*/ + +#if (LIB_MEM_CFG_HEAP_SIZE > 0u) +void Mem_PoolCreate (MEM_POOL *p_pool, + void *p_mem_base, + CPU_SIZE_T mem_size, + MEM_POOL_BLK_QTY blk_nbr, + CPU_SIZE_T blk_size, + CPU_SIZE_T blk_align, + CPU_SIZE_T *p_bytes_reqd, + LIB_ERR *p_err) +{ + MEM_SEG *p_seg; + void *p_pool_mem; + CPU_SIZE_T pool_size; + CPU_SIZE_T blk_size_align; + CPU_ADDR pool_addr_end; + MEM_POOL_BLK_QTY blk_ix; + CPU_INT08U *p_blk; + CPU_SR_ALLOC(); + + +#if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) /* --------------- VALIDATE RTN ERR PTR --------------- */ + if (p_err == DEF_NULL) { + CPU_SW_EXCEPTION(;); + } + + /* ------------- VALIDATE MEM POOL CREATE ------------- */ + if (p_pool == DEF_NULL) { + *p_err = LIB_MEM_ERR_NULL_PTR; + return; + } + + if (p_mem_base != DEF_NULL) { + if (mem_size < 1u) { + *p_err = LIB_MEM_ERR_INVALID_SEG_SIZE; + return; + } + } + + if (blk_nbr < 1u) { + *p_err = LIB_MEM_ERR_INVALID_BLK_NBR; + return; + } + + if (blk_size < 1u) { + *p_err = LIB_MEM_ERR_INVALID_BLK_SIZE; + return; + } + + if (MATH_IS_PWR2(blk_align) != DEF_YES) { /* Chk that req alignment is a pwr of 2. */ + *p_err = LIB_MEM_ERR_INVALID_BLK_ALIGN; + return; + } +#endif + + Mem_PoolClr(p_pool, p_err); /* Init mem pool. */ + if (*p_err != LIB_MEM_ERR_NONE) { + return; + } + + /* -------- DETERMINE AND/OR ALLOC SEG TO USE --------- */ + if (p_mem_base == DEF_NULL) { /* Use heap seg. */ + p_seg = &Mem_SegHeap; + } else { /* Use other seg. */ + CPU_CRITICAL_ENTER(); + p_seg = Mem_SegOverlapChkCritical((CPU_ADDR)p_mem_base, + mem_size, + p_err); + switch (*p_err) { + case LIB_MEM_ERR_INVALID_SEG_EXISTS: /* Seg already exists. */ + break; + + case LIB_MEM_ERR_NONE: /* Seg must be created. */ + p_seg = (MEM_SEG *)Mem_SegAllocExtCritical(&Mem_SegHeap, + sizeof(MEM_SEG), + sizeof(CPU_ALIGN), + LIB_MEM_PADDING_ALIGN_NONE, + p_bytes_reqd, + p_err); + if (*p_err != LIB_MEM_ERR_NONE) { + CPU_CRITICAL_EXIT(); + return; + } + +#if (LIB_MEM_CFG_DBG_INFO_EN == DEF_ENABLED) /* Track alloc if req'd. */ + Mem_SegAllocTrackCritical("Unknown segment data", + &Mem_SegHeap, + sizeof(MEM_SEG), + p_err); + if (*p_err != LIB_MEM_ERR_NONE) { + CPU_CRITICAL_EXIT(); + return; + } +#endif + + Mem_SegCreateCritical( DEF_NULL, + p_seg, + (CPU_ADDR)p_mem_base, + LIB_MEM_PADDING_ALIGN_NONE, + mem_size); + break; + + + case LIB_MEM_ERR_INVALID_SEG_OVERLAP: + default: + CPU_CRITICAL_EXIT(); + return; /* Prevent 'break NOT reachable' compiler warning. */ + } + + CPU_CRITICAL_EXIT(); + } + + + /* ---------------- ALLOC MEM FOR POOL ---------------- */ + /* Calc blk size with align. */ + blk_size_align = MATH_ROUND_INC_UP_PWR2(blk_size, blk_align); + pool_size = blk_size_align * blk_nbr; /* Calc required size for pool. */ + + /* Alloc mem for pool. */ + p_pool_mem = (void *)Mem_SegAllocInternal("Unnamed static pool", + p_seg, + pool_size, + blk_align, + LIB_MEM_PADDING_ALIGN_NONE, + p_bytes_reqd, + p_err); + if (*p_err != LIB_MEM_ERR_NONE) { + return; + } + + /* ------------ ALLOC MEM FOR FREE BLK TBL ------------ */ + p_pool->BlkFreeTbl = (void *)Mem_SegAllocInternal("Unnamed static pool free blk tbl", + &Mem_SegHeap, + blk_nbr * sizeof(void *), + sizeof(CPU_ALIGN), + LIB_MEM_PADDING_ALIGN_NONE, + p_bytes_reqd, + p_err); + if (*p_err != LIB_MEM_ERR_NONE) { + return; + } + + /* ------------------ INIT BLK LIST ------------------- */ + p_blk = (CPU_INT08U *)p_pool_mem; + for (blk_ix = 0; blk_ix < blk_nbr; blk_ix++) { + p_pool->BlkFreeTbl[blk_ix] = p_blk; + p_blk += blk_size_align; + } + + + /* ------------------ INIT POOL DATA ------------------ */ + pool_addr_end = (CPU_ADDR)p_pool_mem + (pool_size - 1u); + p_pool->PoolAddrStart = p_pool_mem; + p_pool->PoolAddrEnd = (void *)pool_addr_end; + p_pool->BlkNbr = blk_nbr; + p_pool->BlkSize = blk_size_align; + p_pool->BlkFreeTblIx = blk_nbr; +} +#endif + + +/* +********************************************************************************************************* +* Mem_PoolClr() +* +* Description : Clears a memory pool (see Note #1). +* +* Argument(s) : p_pool Pointer to a memory pool structure to clear (see Note #2). +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* LIB_MEM_ERR_NONE Operation was successful. +* LIB_MEM_ERR_NULL_PTR Argument 'p_pool' passed a NULL pointer. +* +* Return(s) : none. +* +* Caller(s) : Application, +* Mem_PoolCreate(). +* +* Note(s) : (1) (a) Mem_PoolClr() ONLY clears a memory pool structure's variables & should ONLY be +* called to initialize a memory pool structure prior to calling Mem_PoolCreate(). +* +* (b) Mem_PoolClr() does NOT deallocate memory from the memory pool or deallocate the +* memory pool itself & MUST NOT be called after calling Mem_PoolCreate() since +* this will likely corrupt the memory pool management. +* +* (2) Assumes 'p_pool' points to a valid memory pool (if non-NULL). +* +* (3) This function is DEPRECATED and will be removed in a future version of this product. +********************************************************************************************************* +*/ + +#if (LIB_MEM_CFG_HEAP_SIZE > 0u) +void Mem_PoolClr (MEM_POOL *p_pool, + LIB_ERR *p_err) +{ +#if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) /* -------------- VALIDATE RTN ERR PTR --------------- */ + if (p_err == DEF_NULL) { + CPU_SW_EXCEPTION(;); + } + + /* -------------- VALIDATE MEM POOL PTR --------------- */ + if (p_pool == DEF_NULL) { + *p_err = LIB_MEM_ERR_NULL_PTR; + return; + } +#endif + + p_pool->PoolAddrStart = DEF_NULL; + p_pool->PoolAddrEnd = DEF_NULL; + p_pool->BlkSize = 0u; + p_pool->BlkNbr = 0u; + p_pool->BlkFreeTbl = DEF_NULL; + p_pool->BlkFreeTblIx = 0u; + + *p_err = LIB_MEM_ERR_NONE; +} +#endif + + +/* +********************************************************************************************************* +* Mem_PoolBlkGet() +* +* Description : Gets a memory block from memory pool. +* +* Argument(s) : p_pool Pointer to memory pool to get memory block from. +* +* size Size of requested memory (in bytes). +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* LIB_MEM_ERR_NONE Operation was successful. +* LIB_MEM_ERR_INVALID_BLK_SIZE Invalid memory pool block size requested. +* LIB_MEM_ERR_NULL_PTR Argument 'p_pool' passed a NULL pointer. +* LIB_MEM_ERR_POOL_EMPTY NO memory blocks available in memory pool. +* +* Return(s) : Pointer to memory block, if NO error(s). +* +* Pointer to NULL, otherwise. +* +* Caller(s) : Application. +* +* Note(s) : (1) This function is DEPRECATED and will be removed in a future version of this product. +* Mem_DynPoolBlkGet() should be used instead. +********************************************************************************************************* +*/ + +#if (LIB_MEM_CFG_HEAP_SIZE > 0u) +void *Mem_PoolBlkGet (MEM_POOL *p_pool, + CPU_SIZE_T size, + LIB_ERR *p_err) +{ + CPU_INT08U *p_blk; + CPU_SR_ALLOC(); + + + (void)&size; /* Prevent possible 'variable unused' warning. */ + +#if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) /* -------------- VALIDATE MEM POOL GET --------------- */ + if (p_err == DEF_NULL) { /* Validate err ptr. */ + CPU_SW_EXCEPTION(DEF_NULL); + } + + if (p_pool == DEF_NULL) { /* Validate pool ptr. */ + *p_err = LIB_MEM_ERR_NULL_PTR; + return (DEF_NULL); + } + + if (size < 1u) { /* Validate req'd size as non-NULL. */ + *p_err = LIB_MEM_ERR_INVALID_BLK_SIZE; + return (DEF_NULL); + } + + if (size > p_pool->BlkSize) { /* Validate req'd size <= mem pool blk size. */ + *p_err = LIB_MEM_ERR_INVALID_BLK_SIZE; + return (DEF_NULL); + } +#endif + + + /* -------------- GET MEM BLK FROM POOL --------------- */ + p_blk = DEF_NULL; + CPU_CRITICAL_ENTER(); + if (p_pool->BlkFreeTblIx > 0u) { + p_pool->BlkFreeTblIx -= 1u; + p_blk = p_pool->BlkFreeTbl[p_pool->BlkFreeTblIx]; + p_pool->BlkFreeTbl[p_pool->BlkFreeTblIx] = DEF_NULL; + } + CPU_CRITICAL_EXIT(); + + if (p_blk == DEF_NULL) { + *p_err = LIB_MEM_ERR_POOL_EMPTY; + } else { + *p_err = LIB_MEM_ERR_NONE; + } + + return (p_blk); +} +#endif + + +/* +********************************************************************************************************* +* Mem_PoolBlkFree() +* +* Description : Free a memory block to memory pool. +* +* Argument(s) : p_pool Pointer to memory pool to free memory block. +* +* p_blk Pointer to memory block address to free. +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* LIB_MEM_ERR_NONE Operation was successful. +* LIB_MEM_ERR_NULL_PTR Argument 'p_pool'/'p_blk' passed +* a NULL pointer. +* LIB_MEM_ERR_INVALID_BLK_ADDR Invalid memory block address. +* LIB_MEM_ERR_INVALID_BLK_ADDR_IN_POOL Memory block address already +* in memory pool. +* LIB_MEM_ERR_POOL_FULL Pool is full. +* +* Return(s) : none. +* +* Caller(s) : Application. +* +* Note(s) : (1) This function is DEPRECATED and will be removed in a future version of this product. +* Mem_DynPoolBlkFree() should be used instead. +********************************************************************************************************* +*/ + +#if (LIB_MEM_CFG_HEAP_SIZE > 0u) +void Mem_PoolBlkFree (MEM_POOL *p_pool, + void *p_blk, + LIB_ERR *p_err) +{ +#if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) + CPU_SIZE_T tbl_ix; + CPU_BOOLEAN addr_valid; +#endif + CPU_SR_ALLOC(); + + +#if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) /* -------------- VALIDATE MEM POOL FREE -------------- */ + if (p_err == DEF_NULL) { + CPU_SW_EXCEPTION(;); + } + + if (p_pool == DEF_NULL) { /* Validate mem ptrs. */ + *p_err = LIB_MEM_ERR_NULL_PTR; + return; + } + + if (p_blk == DEF_NULL) { + *p_err = LIB_MEM_ERR_NULL_PTR; + return; + } + + addr_valid = Mem_PoolBlkIsValidAddr(p_pool, p_blk); /* Validate mem blk as valid pool blk addr. */ + if (addr_valid != DEF_OK) { + *p_err = LIB_MEM_ERR_INVALID_BLK_ADDR; + return; + } + + CPU_CRITICAL_ENTER(); /* Make sure blk isn't already in free list. */ + for (tbl_ix = 0u; tbl_ix < p_pool->BlkNbr; tbl_ix++) { + if (p_pool->BlkFreeTbl[tbl_ix] == p_blk) { + CPU_CRITICAL_EXIT(); + *p_err = LIB_MEM_ERR_INVALID_BLK_ADDR_IN_POOL; + return; + } + } +#else /* Double-free possibility if not in critical section. */ + CPU_CRITICAL_ENTER(); +#endif + /* --------------- FREE MEM BLK TO POOL --------------- */ + if (p_pool->BlkFreeTblIx >= p_pool->BlkNbr) { + CPU_CRITICAL_EXIT(); + *p_err = LIB_MEM_ERR_POOL_FULL; + return; + } + + p_pool->BlkFreeTbl[p_pool->BlkFreeTblIx] = p_blk; + p_pool->BlkFreeTblIx += 1u; + CPU_CRITICAL_EXIT(); + + *p_err = LIB_MEM_ERR_NONE; +} +#endif + + +/* +********************************************************************************************************* +* Mem_PoolBlkGetNbrAvail() +* +* Description : Get memory pool's remaining number of blocks available to allocate. +* +* Argument(s) : p_pool Pointer to a memory pool structure. +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* LIB_MEM_ERR_NONE Operation was successful. +* LIB_MEM_ERR_NULL_PTR Argument 'p_pool' passed a NULL pointer. +* +* Return(s) : Remaining memory pool blocks, if NO error(s). +* +* 0, otherwise. +* +* Caller(s) : Application. +* +* Note(s) : (1) This function is DEPRECATED and will be removed in a future version of this product. +* Mem_DynPoolBlkNbrAvailGet() should be used instead. +********************************************************************************************************* +*/ + +#if (LIB_MEM_CFG_HEAP_SIZE > 0u) +MEM_POOL_BLK_QTY Mem_PoolBlkGetNbrAvail (MEM_POOL *p_pool, + LIB_ERR *p_err) +{ + CPU_SIZE_T nbr_avail; + CPU_SR_ALLOC(); + + +#if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) + /* --------------- VALIDATE RTN ERR PTR --------------- */ + if (p_err == DEF_NULL) { + CPU_SW_EXCEPTION(0u); + } + /* ---------------- VALIDATE MEM POOL ----------------- */ + if (p_pool == DEF_NULL) { /* Validate mem ptr. */ + *p_err = LIB_MEM_ERR_NULL_PTR; + return (0u); + } +#endif + + CPU_CRITICAL_ENTER(); + nbr_avail = p_pool->BlkFreeTblIx; + CPU_CRITICAL_EXIT(); + + *p_err = LIB_MEM_ERR_NONE; + + return (nbr_avail); +} +#endif + + +/* +********************************************************************************************************* +* Mem_DynPoolCreate() +* +* Description : Creates a dynamic memory pool. +* +* Argument(s) : p_name Pointer to pool name. +* +* p_pool Pointer to pool data. +* +* p_seg Pointer to segment from which to allocate memory. Will be allocated from +* general-purpose heap if null. +* +* blk_size Size of memory block to allocate from pool, in bytes. See Note #1. +* +* blk_align Required alignment of memory block, in bytes. MUST be a power of 2. +* +* blk_qty_init Initial number of elements to be allocated in pool. +* +* blk_qty_max Maximum number of elements that can be allocated from this pool. Set to +* LIB_MEM_BLK_QTY_UNLIMITED if no limit. +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* LIB_MEM_ERR_NONE Operation was successful. +* +* --------------------RETURNED BY Mem_DynPoolCreateInternal()------------------- +* LIB_MEM_ERR_INVALID_BLK_ALIGN Invalid requested block alignment. +* LIB_MEM_ERR_INVALID_BLK_SIZE Invalid requested block size. +* LIB_MEM_ERR_INVALID_BLK_NBR Invalid requested block quantity max. +* LIB_MEM_ERR_NULL_PTR Pool data pointer NULL. +* LIB_MEM_ERR_INVALID_MEM_ALIGN Invalid memory block alignment requested. +* LIB_MEM_ERR_INVALID_MEM_SIZE Invalid memory block size specified. +* LIB_MEM_ERR_NULL_PTR Error or segment data pointer NULL. +* LIB_MEM_ERR_SEG_OVF Allocation would overflow memory segment. +* +* Return(s) : None. +* +* Caller(s) : Application. +* +* Note(s) : (1) 'blk_size' must be big enough to fit a pointer since the pointer to the next free +* block is stored in the block itself (only when free/unused). +********************************************************************************************************* +*/ + +void Mem_DynPoolCreate (const CPU_CHAR *p_name, + MEM_DYN_POOL *p_pool, + MEM_SEG *p_seg, + CPU_SIZE_T blk_size, + CPU_SIZE_T blk_align, + CPU_SIZE_T blk_qty_init, + CPU_SIZE_T blk_qty_max, + LIB_ERR *p_err) +{ + if (p_seg == DEF_NULL) { /* Alloc from heap if p_seg is null. */ +#if (LIB_MEM_CFG_HEAP_SIZE > 0u) + p_seg = &Mem_SegHeap; +#else + *p_err = LIB_MEM_ERR_NULL_PTR; + return (DEF_NULL); +#endif + } + + Mem_DynPoolCreateInternal(p_name, + p_pool, + p_seg, + blk_size, + blk_align, + LIB_MEM_PADDING_ALIGN_NONE, + blk_qty_init, + blk_qty_max, + p_err); +} + + +/* +********************************************************************************************************* +* Mem_DynPoolCreateHW() +* +* Description : Creates a dynamic memory pool. Memory blocks will be padded according to memory segment's +* properties. +* +* Argument(s) : p_name Pointer to pool name. +* +* p_pool Pointer to pool data. +* +* p_seg Pointer to segment from which to allocate memory. Will allocate from +* general-purpose heap if null. +* +* blk_size Size of memory block to allocate from pool, in bytes. See Note #1. +* +* blk_align Required alignment of memory block, in bytes. MUST be a power of 2. +* +* blk_qty_init Initial number of elements to be allocated in pool. +* +* blk_qty_max Maximum number of elements that can be allocated from this pool. Set to +* LIB_MEM_BLK_QTY_UNLIMITED if no limit. +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* LIB_MEM_ERR_NONE Operation was successful. +* +* -------------------RETURNED BY Mem_DynPoolCreateInternal()------------------- +* LIB_MEM_ERR_INVALID_MEM_ALIGN Invalid memory block alignment requested. +* LIB_MEM_ERR_INVALID_MEM_SIZE Invalid memory block size specified. +* LIB_MEM_ERR_NULL_PTR Error or segment data pointer NULL. +* LIB_MEM_ERR_SEG_OVF Allocation would overflow memory segment. +* +* Return(s) : None. +* +* Caller(s) : Application. +* +* Note(s) : (1) 'blk_size' must be big enough to fit a pointer since the pointer to the next free +* block is stored in the block itself (only when free/unused). +********************************************************************************************************* +*/ + +void Mem_DynPoolCreateHW (const CPU_CHAR *p_name, + MEM_DYN_POOL *p_pool, + MEM_SEG *p_seg, + CPU_SIZE_T blk_size, + CPU_SIZE_T blk_align, + CPU_SIZE_T blk_qty_init, + CPU_SIZE_T blk_qty_max, + LIB_ERR *p_err) +{ + if (p_seg == DEF_NULL) { /* Alloc from heap if p_seg is null. */ +#if (LIB_MEM_CFG_HEAP_SIZE > 0u) + p_seg = &Mem_SegHeap; +#else + *p_err = LIB_MEM_ERR_NULL_PTR; + return (DEF_NULL); +#endif + } + + Mem_DynPoolCreateInternal(p_name, + p_pool, + p_seg, + blk_size, + blk_align, + p_seg->PaddingAlign, + blk_qty_init, + blk_qty_max, + p_err); +} + + +/* +********************************************************************************************************* +* Mem_DynPoolBlkGet() +* +* Description : Gets a memory block from specified pool, growing it if needed. +* +* Argument(s) : p_pool Pointer to pool data. +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* LIB_MEM_ERR_NONE Operation was successful. +* LIB_MEM_ERR_NULL_PTR Pool data pointer NULL. +* LIB_MEM_ERR_POOL_EMPTY Pools is empty. +* +* ----------------------RETURNED BY Mem_SegAllocInternal()----------------------- +* LIB_MEM_ERR_INVALID_MEM_ALIGN Invalid memory block alignment requested. +* LIB_MEM_ERR_INVALID_MEM_SIZE Invalid memory block size specified. +* LIB_MEM_ERR_NULL_PTR Error or segment data pointer NULL. +* LIB_MEM_ERR_SEG_OVF Allocation would overflow memory segment. +* +* Return(s) : Pointer to memory block, if successful. +* +* DEF_NULL, otherwise. +* +* Caller(s) : Application. +* +* Note(s) : none. +********************************************************************************************************* +*/ + +void *Mem_DynPoolBlkGet (MEM_DYN_POOL *p_pool, + LIB_ERR *p_err) +{ + void *p_blk; + const CPU_CHAR *p_pool_name; + CPU_SR_ALLOC(); + + +#if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) + if (p_err == DEF_NULL) { /* Chk for NULL err ptr. */ + CPU_SW_EXCEPTION(DEF_NULL); + } + + if (p_pool == DEF_NULL) { /* Chk for NULL pool data ptr. */ + *p_err = LIB_MEM_ERR_NULL_PTR; + return (DEF_NULL); + } +#endif + + /* Ensure pool is not empty if qty is limited. */ + if (p_pool->BlkQtyMax != LIB_MEM_BLK_QTY_UNLIMITED) { + CPU_CRITICAL_ENTER(); + if (p_pool->BlkAllocCnt >= p_pool->BlkQtyMax) { + CPU_CRITICAL_EXIT(); + + *p_err = LIB_MEM_ERR_POOL_EMPTY; + return (DEF_NULL); + } + + p_pool->BlkAllocCnt++; + CPU_CRITICAL_EXIT(); + } + + /* --------------- ALLOC FROM FREE LIST --------------- */ + CPU_CRITICAL_ENTER(); + if (p_pool->BlkFreePtr != DEF_NULL) { + p_blk = p_pool->BlkFreePtr; + p_pool->BlkFreePtr = *((void **)p_blk); + CPU_CRITICAL_EXIT(); + + *p_err = LIB_MEM_ERR_NONE; + + return (p_blk); + } + CPU_CRITICAL_EXIT(); + + /* ------------------ ALLOC NEW BLK ------------------- */ +#if (LIB_MEM_CFG_DBG_INFO_EN == DEF_ENABLED) + p_pool_name = p_pool->NamePtr; +#else + p_pool_name = DEF_NULL; +#endif + p_blk = Mem_SegAllocInternal(p_pool_name, + p_pool->PoolSegPtr, + p_pool->BlkSize, + p_pool->BlkAlign, + p_pool->BlkPaddingAlign, + DEF_NULL, + p_err); + if (*p_err != LIB_MEM_ERR_NONE) { + return (DEF_NULL); + } + + return (p_blk); +} + + +/* +********************************************************************************************************* +* Mem_DynPoolBlkFree() +* +* Description : Frees memory block, making it available for future use. +* +* Argument(s) : p_pool Pointer to pool data. +* +* p_blk Pointer to first byte of memory block. +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* LIB_MEM_ERR_NONE Operation was successful. +* LIB_MEM_ERR_NULL_PTR 'p_pool' or 'p_blk' pointer passed is NULL. +* LIB_MEM_ERR_POOL_FULL Pool is full. +* +* Return(s) : none. +* +* Caller(s) : Application. +* +* Note(s) : none. +********************************************************************************************************* +*/ + +void Mem_DynPoolBlkFree (MEM_DYN_POOL *p_pool, + void *p_blk, + LIB_ERR *p_err) +{ + CPU_SR_ALLOC(); + + +#if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) + if (p_err == DEF_NULL) { /* Chk for NULL err ptr. */ + CPU_SW_EXCEPTION(;); + } + + if (p_pool == DEF_NULL) { /* Chk for NULL pool data ptr. */ + *p_err = LIB_MEM_ERR_NULL_PTR; + return; + } + + if (p_blk == DEF_NULL) { + *p_err = LIB_MEM_ERR_NULL_PTR; + return; + } +#endif + + if (p_pool->BlkQtyMax != LIB_MEM_BLK_QTY_UNLIMITED) { /* Ensure pool is not full. */ + CPU_CRITICAL_ENTER(); + if (p_pool->BlkAllocCnt == 0u) { + CPU_CRITICAL_EXIT(); + + *p_err = LIB_MEM_ERR_POOL_FULL; + return; + } + + p_pool->BlkAllocCnt--; + CPU_CRITICAL_EXIT(); + } + + CPU_CRITICAL_ENTER(); + *((void **)p_blk) = p_pool->BlkFreePtr; + p_pool->BlkFreePtr = p_blk; + CPU_CRITICAL_EXIT(); + + *p_err = LIB_MEM_ERR_NONE; +} + + +/* +********************************************************************************************************* +* Mem_DynPoolBlkNbrAvailGet() +* +* Description : Gets number of available blocks in dynamic memory pool. This call will fail with a +* dynamic memory pool for which no limit was set at creation. +* +* Argument(s) : p_pool Pointer to pool data. +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* LIB_MEM_ERR_NONE Operation was successful. +* LIB_MEM_ERR_NULL_PTR 'p_pool' pointer passed is NULL. +* LIB_MEM_ERR_POOL_UNLIMITED Pool has no specified limit. +* +* Return(s) : Number of blocks available in dynamic memory pool, if successful. +* +* 0, if pool is empty or if an error occurred. +* +* Caller(s) : Application. +* +* Note(s) : None. +********************************************************************************************************* +*/ + +CPU_SIZE_T Mem_DynPoolBlkNbrAvailGet (MEM_DYN_POOL *p_pool, + LIB_ERR *p_err) +{ + CPU_SIZE_T blk_nbr_avail; + CPU_SR_ALLOC(); + + +#if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) + if (p_err == DEF_NULL) { /* Chk for NULL err ptr. */ + CPU_SW_EXCEPTION(;); + } + + if (p_pool == DEF_NULL) { /* Chk for NULL pool data ptr. */ + *p_err = LIB_MEM_ERR_NULL_PTR; + return (0u); + } +#endif + + if (p_pool->BlkQtyMax != LIB_MEM_BLK_QTY_UNLIMITED) { + CPU_CRITICAL_ENTER(); + blk_nbr_avail = p_pool->BlkQtyMax - p_pool->BlkAllocCnt; + CPU_CRITICAL_EXIT(); + + *p_err = LIB_MEM_ERR_NONE; + } else { + blk_nbr_avail = 0u; + *p_err = LIB_MEM_ERR_POOL_UNLIMITED; + } + + return (blk_nbr_avail); +} + + +/* +********************************************************************************************************* +* Mem_OutputUsage() +* +* Description : Outputs memory usage report through 'out_fnct'. +* +* Argument(s) : out_fnct Pointer to output function. +* +* print_details DEF_YES, if the size of each allocation should be printed. +* DEF_NO, otherwise. +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* LIB_MEM_ERR_NONE Operation was successful. +* LIB_MEM_ERR_NULL_PTR 'out_fnct' pointer passed is NULL. +* +* ---------------------RETURNED BY Mem_SegRemSizeGet()-------------------- +* LIB_MEM_ERR_NULL_PTR Segment data pointer NULL. +* LIB_MEM_ERR_INVALID_MEM_ALIGN Invalid memory alignment. +* +* Return(s) : None. +* +* Caller(s) : Application. +* +* Note(s) : none. +********************************************************************************************************* +*/ + +#if (LIB_MEM_CFG_DBG_INFO_EN == DEF_ENABLED) +void Mem_OutputUsage(void (*out_fnct) (CPU_CHAR *), + LIB_ERR *p_err) +{ + CPU_CHAR str[DEF_INT_32U_NBR_DIG_MAX]; + MEM_SEG *p_seg; + CPU_SR_ALLOC(); + + +#if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) + if (p_err == DEF_NULL) { /* Chk for NULL err ptr. */ + CPU_SW_EXCEPTION(;); + } + + if (out_fnct == DEF_NULL) { /* Chk for NULL out fnct ptr. */ + *p_err = LIB_MEM_ERR_NULL_PTR; + return; + } +#endif + + out_fnct("---------------- Memory allocation info ----------------\r\n"); + out_fnct("| Type | Size | Free size | Name\r\n"); + out_fnct("|---------|------------|------------|-------------------\r\n"); + + CPU_CRITICAL_ENTER(); + p_seg = Mem_SegHeadPtr; + while (p_seg != DEF_NULL) { + CPU_SIZE_T rem_size; + MEM_SEG_INFO seg_info; + MEM_ALLOC_INFO *p_alloc; + + + rem_size = Mem_SegRemSizeGet(p_seg, 1u, &seg_info, p_err); + if (*p_err != LIB_MEM_ERR_NONE) { + return; + } + + out_fnct("| Section | "); + + (void)Str_FmtNbr_Int32U(seg_info.TotalSize, + 10u, + DEF_NBR_BASE_DEC, + ' ', + DEF_NO, + DEF_YES, + &str[0u]); + + out_fnct(str); + out_fnct(" | "); + + (void)Str_FmtNbr_Int32U(rem_size, + 10u, + DEF_NBR_BASE_DEC, + ' ', + DEF_NO, + DEF_YES, + &str[0u]); + + out_fnct(str); + out_fnct(" | "); + out_fnct((p_seg->NamePtr != DEF_NULL) ? (CPU_CHAR *)p_seg->NamePtr : (CPU_CHAR *)"Unknown"); + out_fnct("\r\n"); + + p_alloc = p_seg->AllocInfoHeadPtr; + while (p_alloc != DEF_NULL) { + out_fnct("| -> Obj | "); + + (void)Str_FmtNbr_Int32U(p_alloc->Size, + 10u, + DEF_NBR_BASE_DEC, + ' ', + DEF_NO, + DEF_YES, + &str[0u]); + + out_fnct(str); + out_fnct(" | | "); + + out_fnct((p_alloc->NamePtr != DEF_NULL) ? (CPU_CHAR *)p_alloc->NamePtr : (CPU_CHAR *)"Unknown"); + out_fnct("\r\n"); + + p_alloc = p_alloc->NextPtr; + } + + p_seg = p_seg->NextPtr; + } + CPU_CRITICAL_EXIT(); + + *p_err = LIB_MEM_ERR_NONE; +} +#endif + + +/* +********************************************************************************************************* +********************************************************************************************************* +* LOCAL FUNCTIONS +********************************************************************************************************* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* Mem_SegCreateCritical() +* +* Description : Creates a new memory segment to be used for runtime memory allocation or dynamic pools. +* +* Argument(s) : p_name Pointer to segment name. +* +* p_seg Pointer to segment data. Must be allocated by caller. +* ----- Argument validated by caller. +* +* seg_base_addr Segment's first byte address. +* +* padding_align Padding alignment, in bytes, that will be added to any allocated buffer +* from this memory segment. MUST be a power of 2. +* LIB_MEM_PADDING_ALIGN_NONE means no padding. +* ------------- Argument validated by caller. +* +* size Total size of segment, in bytes. +* ---- Argument validated by caller. +* +* Return(s) : Pointer to segment data, if successful. +* +* DEF_NULL, otherwise. +* +* Caller(s) : Mem_PoolCreate(), +* Mem_SegCreate(). +* +* Note(s) : (1) This function MUST be called within a CRITICAL_SECTION. +********************************************************************************************************* +*/ + +static void Mem_SegCreateCritical(const CPU_CHAR *p_name, + MEM_SEG *p_seg, + CPU_ADDR seg_base_addr, + CPU_SIZE_T padding_align, + CPU_SIZE_T size) +{ + p_seg->AddrBase = seg_base_addr; + p_seg->AddrEnd = (seg_base_addr + (size - 1u)); + p_seg->AddrNext = seg_base_addr; + p_seg->NextPtr = Mem_SegHeadPtr; + p_seg->PaddingAlign = padding_align; + +#if (LIB_MEM_CFG_DBG_INFO_EN == DEF_ENABLED) + p_seg->NamePtr = p_name; + p_seg->AllocInfoHeadPtr = DEF_NULL; +#else + (void)&p_name; +#endif + + Mem_SegHeadPtr = p_seg; +} + + +/* +********************************************************************************************************* +* Mem_SegOverlapChkCritical() +* +* Description : Checks if existing memory segment exists or overlaps with specified memory area. +* +* Argument(s) : seg_base_addr Address of first byte of memory area. +* +* size Size of memory area, in bytes. +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* LIB_MEM_ERR_INVALID_SEG_OVERLAP Segment overlaps another existing segment. +* LIB_MEM_ERR_INVALID_SEG_EXISTS Segment already exists. +* +* Return(s) : Pointer to memory segment that overlaps. +* +* DEF_NULL, otherwise. +* +* Caller(s) : Mem_PoolCreate(), +* Mem_SegCreate(). +* +* Note(s) : (1) This function MUST be called within a CRITICAL_SECTION. +********************************************************************************************************* +*/ + +static MEM_SEG *Mem_SegOverlapChkCritical (CPU_ADDR seg_base_addr, + CPU_SIZE_T size, + LIB_ERR *p_err) +{ + MEM_SEG *p_seg_chk; + CPU_ADDR seg_new_end; + CPU_ADDR seg_chk_start; + CPU_ADDR seg_chk_end; + + + seg_new_end = seg_base_addr + (size - 1u); + p_seg_chk = Mem_SegHeadPtr; + + while (p_seg_chk != DEF_NULL) { + seg_chk_start = (CPU_ADDR)p_seg_chk->AddrBase; + seg_chk_end = (CPU_ADDR)p_seg_chk->AddrEnd; + + if ((seg_base_addr == seg_chk_start) && (seg_new_end == seg_chk_end)) { + *p_err = LIB_MEM_ERR_INVALID_SEG_EXISTS; + return (p_seg_chk); + } else if (((seg_base_addr >= seg_chk_start) && (seg_base_addr <= seg_chk_end)) || + ((seg_base_addr <= seg_chk_start) && (seg_new_end >= seg_chk_start))) { + *p_err = LIB_MEM_ERR_INVALID_SEG_OVERLAP; + return (p_seg_chk); + } + + p_seg_chk = p_seg_chk->NextPtr; + } + + *p_err = LIB_MEM_ERR_NONE; + + return (DEF_NULL); +} + + +/* +********************************************************************************************************* +* Mem_SegAllocInternal() +* +* Description : Allocates memory from specified segment. +* +* Argument(s) : p_name Pointer to allocated object name. Used for allocations tracking. May be DEF_NULL. +* +* p_seg Pointer to segment from which to allocate memory. +* ----- Argument validated by caller. +* +* size Size of memory block to allocate, in bytes. +* +* align Required alignment of memory block, in bytes. MUST be a power of 2. +* +* padding_align Padding alignment, in bytes, that will be added to any allocated buffer from +* this memory segment. MUST be a power of 2. LIB_MEM_PADDING_ALIGN_NONE +* means no padding. +* +* p_bytes_reqd Pointer to variable that will receive the number of free bytes missing for +* the allocation to succeed. Set to DEF_NULL to skip calculation. +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* LIB_MEM_ERR_INVALID_MEM_ALIGN Invalid memory block alignment requested. +* LIB_MEM_ERR_INVALID_MEM_SIZE Invalid memory block size specified. +* LIB_MEM_ERR_NULL_PTR Error or segment data pointer NULL. +* +* ------------------RETURNED BY Mem_SegAllocExtCritical()------------------ +* LIB_MEM_ERR_SEG_OVF Allocation would overflow memory segment. +* +* Return(s) : Pointer to allocated memory block, if successful. +* +* DEF_NULL, otherwise. +* +* Caller(s) : Mem_DynPoolBlkGet(), +* Mem_DynPoolCreateInternal(), +* Mem_HeapAlloc(), +* Mem_PoolCreate(), +* Mem_SegAlloc(), +* Mem_SegAllocExt(), +* Mem_SegAllocHW(). +* +* Note(s) : none. +********************************************************************************************************* +*/ + +static void *Mem_SegAllocInternal (const CPU_CHAR *p_name, + MEM_SEG *p_seg, + CPU_SIZE_T size, + CPU_SIZE_T align, + CPU_SIZE_T padding_align, + CPU_SIZE_T *p_bytes_reqd, + LIB_ERR *p_err) +{ + void *p_blk; + CPU_SR_ALLOC(); + + +#if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) + if (p_err == DEF_NULL) { /* Chk for null err ptr. */ + CPU_SW_EXCEPTION(DEF_NULL); + } + + if (size < 1u) { /* Chk for invalid sized mem req. */ + *p_err = LIB_MEM_ERR_INVALID_MEM_SIZE; + return (DEF_NULL); + } + + if (MATH_IS_PWR2(align) != DEF_YES) { /* Chk that align is a pwr of 2. */ + *p_err = LIB_MEM_ERR_INVALID_MEM_ALIGN; + return (DEF_NULL); + } +#endif + + CPU_CRITICAL_ENTER(); + p_blk = Mem_SegAllocExtCritical(p_seg, + size, + align, + padding_align, + p_bytes_reqd, + p_err); + if (*p_err != LIB_MEM_ERR_NONE) { + CPU_CRITICAL_EXIT(); + return (DEF_NULL); + } + +#if (LIB_MEM_CFG_DBG_INFO_EN == DEF_ENABLED) /* Track alloc if req'd. */ + Mem_SegAllocTrackCritical(p_name, + p_seg, + size, + p_err); + if (*p_err != LIB_MEM_ERR_NONE) { + CPU_CRITICAL_EXIT(); + return (DEF_NULL); + } +#else + (void)&p_name; +#endif + CPU_CRITICAL_EXIT(); + + return (p_blk); +} + + +/* +********************************************************************************************************* +* Mem_SegAllocExtCritical() +* +* Description : Allocates memory from specified segment. +* +* Argument(s) : p_seg Pointer to segment from which to allocate memory. +* +* size Size of memory block to allocate, in bytes. +* +* align Required alignment of memory block, in bytes. MUST be a power of 2. +* +* padding_align Padding alignment, in bytes, that will be added to any allocated buffer from +* this memory segment. MUST be a power of 2. LIB_MEM_PADDING_ALIGN_NONE +* means no padding. +* +* p_bytes_reqd Pointer to variable that will receive the number of free bytes missing for +* the allocation to succeed. Set to DEF_NULL to skip calculation. +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* LIB_MEM_ERR_SEG_OVF Allocation would overflow memory segment. +* +* Return(s) : Pointer to allocated memory block, if successful. +* +* DEF_NULL, otherwise. +* +* Caller(s) : Mem_PoolCreate(), +* Mem_SegAllocInternal(), +* Mem_SegAllocTrackCritical(). +* +* Note(s) : (1) This function MUST be called within a CRITICAL_SECTION. +********************************************************************************************************* +*/ + +static void *Mem_SegAllocExtCritical (MEM_SEG *p_seg, + CPU_SIZE_T size, + CPU_SIZE_T align, + CPU_SIZE_T padding_align, + CPU_SIZE_T *p_bytes_reqd, + LIB_ERR *p_err) +{ + CPU_ADDR blk_addr; + CPU_ADDR addr_next; + CPU_SIZE_T size_rem_seg; + CPU_SIZE_T size_tot_blk; + CPU_SIZE_T blk_align = DEF_MAX(align, padding_align); + + + blk_addr = MATH_ROUND_INC_UP_PWR2(p_seg->AddrNext, /* Compute align'ed blk addr. */ + blk_align); + addr_next = MATH_ROUND_INC_UP_PWR2(blk_addr + size, /* Compute addr of next alloc. */ + padding_align); + size_rem_seg = p_seg->AddrEnd - p_seg->AddrNext + 1u; + size_tot_blk = addr_next - p_seg->AddrNext; /* Compute tot blk size including align and padding. */ + if (size_rem_seg < size_tot_blk) { /* If seg doesn't have enough space ... */ + if (p_bytes_reqd != DEF_NULL) { /* ... calc nbr of req'd bytes. */ + *p_bytes_reqd = size_tot_blk - size_rem_seg; + } + + *p_err = LIB_MEM_ERR_SEG_OVF; + return (DEF_NULL); + } + + p_seg->AddrNext = addr_next; + + *p_err = LIB_MEM_ERR_NONE; + + return ((void *)blk_addr); +} + + +/* +********************************************************************************************************* +* Mem_SegAllocTrackCritical() +* +* Description : Tracks segment allocation, adding the 'size' of the allocation under the 'p_name' entry. +* +* Argument(s) : p_name Pointer to the name of the object. This string is not copied and its memory should +* remain accessible at all times. +* +* p_seg Pointer to segment data. +* +* size Allocation size, in bytes. +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* LIB_MEM_ERR_HEAP_EMPTY No more memory available on heap +* +* --------------RETURNED BY Mem_SegAllocExtCritical()--------------- +* LIB_MEM_ERR_SEG_OVF Allocation would overflow memory segment. +* +* Return(s) : none. +* +* Caller(s) : Mem_PoolCreate(), +* Mem_SegAllocInternal(). +* +* Note(s) : none. +********************************************************************************************************* +*/ + +#if (LIB_MEM_CFG_DBG_INFO_EN == DEF_ENABLED) +static void Mem_SegAllocTrackCritical (const CPU_CHAR *p_name, + MEM_SEG *p_seg, + CPU_SIZE_T size, + LIB_ERR *p_err) +{ + MEM_ALLOC_INFO *p_alloc; + + + /* ------- UPDATE ALLOC INFO LIST, IF POSSIBLE -------- */ + p_alloc = p_seg->AllocInfoHeadPtr; + while (p_alloc != DEF_NULL) { + if (p_alloc->NamePtr == p_name) { + p_alloc->Size += size; + *p_err = LIB_MEM_ERR_NONE; + return; + } + + p_alloc = p_alloc->NextPtr; + } + + /* --------- ADD NEW ALLOC INFO ENTRY IN LIST --------- */ + p_alloc = Mem_SegAllocExtCritical(&Mem_SegHeap, /* Alloc new alloc info struct on heap. */ + sizeof(MEM_ALLOC_INFO), + sizeof(CPU_ALIGN), + LIB_MEM_PADDING_ALIGN_NONE, + DEF_NULL, + p_err); + if (*p_err != LIB_MEM_ERR_NONE) { + return; + } + + p_alloc->NamePtr = p_name; /* Populate alloc info. */ + p_alloc->Size = size; + + p_alloc->NextPtr = p_seg->AllocInfoHeadPtr; /* Prepend new item in list. */ + p_seg->AllocInfoHeadPtr = p_alloc; +} +#endif + + +/* +********************************************************************************************************* +* Mem_DynPoolCreateInternal() +* +* Description : Creates a dynamic memory pool. +* +* Argument(s) : p_name Pointer to pool name. +* +* p_pool Pointer to pool data. +* +* p_seg Pointer to segment from which to allocate memory. +* +* blk_size Size of memory block to allocate from pool, in bytes. See Note #1. +* +* blk_align Required alignment of memory block, in bytes. MUST be a power of 2. +* +* blk_padding_align Block's padding alignment, in bytes, that will be added at the end +* of block's buffer. MUST be a power of 2. LIB_MEM_PADDING_ALIGN_NONE +* means no padding. +* +* blk_qty_init Initial number of elements to be allocated in pool. +* +* blk_qty_max Maximum number of elements that can be allocated from this pool. Set to +* LIB_MEM_BLK_QTY_UNLIMITED if no limit. +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* LIB_MEM_ERR_INVALID_BLK_ALIGN Invalid requested block alignment. +* LIB_MEM_ERR_INVALID_BLK_SIZE Invalid requested block size. +* LIB_MEM_ERR_INVALID_BLK_NBR Invalid requested block quantity max. +* LIB_MEM_ERR_NULL_PTR Pool data pointer NULL. +* +* ------------------RETURNED BY Mem_SegAllocInternal()------------------- +* LIB_MEM_ERR_INVALID_MEM_ALIGN Invalid memory block alignment requested. +* LIB_MEM_ERR_INVALID_MEM_SIZE Invalid memory block size specified. +* LIB_MEM_ERR_NULL_PTR Error or segment data pointer NULL. +* LIB_MEM_ERR_SEG_OVF Allocation would overflow memory segment. +* +* Return(s) : None. +* +* Caller(s) : Mem_DynPoolCreate(), +* Mem_DynPoolCreateHW(). +* +* Note(s) : (1) 'blk_size' must be big enough to fit a pointer since the pointer to the next free +* block is stored in the block itself (only when free/unused). +********************************************************************************************************* +*/ + +static void Mem_DynPoolCreateInternal (const CPU_CHAR *p_name, + MEM_DYN_POOL *p_pool, + MEM_SEG *p_seg, + CPU_SIZE_T blk_size, + CPU_SIZE_T blk_align, + CPU_SIZE_T blk_padding_align, + CPU_SIZE_T blk_qty_init, + CPU_SIZE_T blk_qty_max, + LIB_ERR *p_err) +{ + CPU_INT08U *p_blks; + CPU_SIZE_T blk_size_align; + CPU_SIZE_T blk_align_worst = DEF_MAX(blk_align, blk_padding_align); + + +#if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) + if (p_err == DEF_NULL) { /* Chk for NULL err ptr. */ + CPU_SW_EXCEPTION(DEF_NULL); + } + + if (p_pool == DEF_NULL) { /* Chk for NULL pool data ptr. */ + *p_err = LIB_MEM_ERR_NULL_PTR; + return; + } + + if (blk_size < 1u) { /* Chk for inv blk size. */ + *p_err = LIB_MEM_ERR_INVALID_BLK_SIZE; + return; + } + + if ((blk_qty_max != LIB_MEM_BLK_QTY_UNLIMITED) && /* Chk for invalid blk qty. */ + (blk_qty_init > blk_qty_max)) { + *p_err = LIB_MEM_ERR_INVALID_BLK_NBR; + return; + } + + if (MATH_IS_PWR2(blk_align) != DEF_YES) { /* Chk for illegal align spec. */ + *p_err = LIB_MEM_ERR_INVALID_BLK_ALIGN; + return; + } +#endif + + /* Calc blk size with align. */ + if (blk_size < sizeof(void *)) { /* If size if smaller than ptr ... */ + /* ... inc size to ptr size. */ + blk_size_align = MATH_ROUND_INC_UP_PWR2(sizeof(void *), blk_align_worst); + } else { + blk_size_align = MATH_ROUND_INC_UP_PWR2(blk_size, blk_align_worst); + } + + if (blk_qty_init != 0u) { /* Alloc init blks. */ + p_blks = (CPU_INT08U *)Mem_SegAllocInternal(p_name, + p_seg, + blk_size_align * blk_qty_init, + blk_align_worst, + LIB_MEM_PADDING_ALIGN_NONE, + DEF_NULL, + p_err); + if (*p_err != LIB_MEM_ERR_NONE) { + return; + } + } + + + /* ----------------- CREATE POOL DATA ----------------- */ + p_pool->PoolSegPtr = p_seg; + p_pool->BlkSize = blk_size; + p_pool->BlkAlign = blk_align_worst; + p_pool->BlkPaddingAlign = blk_padding_align; + p_pool->BlkQtyMax = blk_qty_max; + p_pool->BlkAllocCnt = 0u; + + if (blk_qty_init != 0u) { /* Init free list. */ + CPU_SIZE_T i; + + + p_pool->BlkFreePtr = (void *)p_blks; + for (i = 0u; i < blk_qty_init - 1u; i++) { + *((void **)p_blks) = p_blks + blk_size_align; + p_blks += blk_size_align; + } + *((void **)p_blks) = DEF_NULL; + } else { + p_pool->BlkFreePtr = DEF_NULL; + } + +#if (LIB_MEM_CFG_DBG_INFO_EN == DEF_ENABLED) + p_pool->NamePtr = p_name; +#endif + + *p_err = LIB_MEM_ERR_NONE; +} + + +/* +********************************************************************************************************* +* Mem_PoolBlkIsValidAddr() +* +* Description : Calculates if a given memory block address is valid for the memory pool. +* +* Argument(s) : p_pool Pointer to memory pool structure to validate memory block address. +* ------ Argument validated by caller. +* +* p_mem Pointer to memory block address to validate. +* ----- Argument validated by caller. +* +* Return(s) : DEF_YES, if valid memory pool block address. +* +* DEF_NO, otherwise. +* +* Caller(s) : Mem_PoolBlkFree(). +* +* Note(s) : none. +********************************************************************************************************* +*/ + +#if ((LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) && \ + (LIB_MEM_CFG_HEAP_SIZE > 0u)) +static CPU_BOOLEAN Mem_PoolBlkIsValidAddr (MEM_POOL *p_pool, + void *p_mem) +{ + CPU_ADDR pool_offset; + + + if ((p_mem < p_pool->PoolAddrStart) || + (p_mem > p_pool->PoolAddrEnd)) { + return (DEF_FALSE); + } + + pool_offset = (CPU_ADDR)p_mem - (CPU_ADDR)p_pool->PoolAddrStart; + if (pool_offset % p_pool->BlkSize != 0u) { + return (DEF_FALSE); + } else { + return (DEF_TRUE); + } +} +#endif diff --git a/Middlewares/Third_Party/Micrium/uC-LIB/lib_mem.h b/Middlewares/Third_Party/Micrium/uC-LIB/lib_mem.h new file mode 100644 index 0000000..2e77a35 --- /dev/null +++ b/Middlewares/Third_Party/Micrium/uC-LIB/lib_mem.h @@ -0,0 +1,1412 @@ +/* +********************************************************************************************************* +* uC/LIB +* CUSTOM LIBRARY MODULES +* +* (c) Copyright 2004-2014; Micrium, Inc.; Weston, FL +* +* All rights reserved. Protected by international copyright laws. +* +* uC/LIB is provided in source form to registered licensees ONLY. It is +* illegal to distribute this source code to any third party unless you receive +* written permission by an authorized Micrium representative. Knowledge of +* the source code may NOT be used to develop a similar product. +* +* Please help us continue to provide the Embedded community with the finest +* software available. Your honesty is greatly appreciated. +* +* You can find our product's user manual, API reference, release notes and +* more information at: https://doc.micrium.com +* +* You can contact us at: http://www.micrium.com +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* +* STANDARD MEMORY OPERATIONS +* +* Filename : lib_mem.h +* Version : V1.38.01 +* Programmer(s) : ITJ +* FBJ +* EJ +* JFD +********************************************************************************************************* +* Note(s) : (1) NO compiler-supplied standard library functions are used in library or product software. +* +* (a) ALL standard library functions are implemented in the custom library modules : +* +* (1) \\lib_*.* +* +* (2) \\Ports\\\lib*_a.* +* +* where +* directory path for custom library software +* directory name for specific processor (CPU) +* directory name for specific compiler +* +* (b) Product-specific library functions are implemented in individual products. +* +* (2) Assumes the following versions (or more recent) of software modules are included in +* the project build : +* +* (a) uC/CPU V1.27 +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* MODULE +* +* Note(s) : (1) This memory library header file is protected from multiple pre-processor inclusion through +* use of the memory library module present pre-processor macro definition. +********************************************************************************************************* +*/ + +#ifndef LIB_MEM_MODULE_PRESENT /* See Note #1. */ +#define LIB_MEM_MODULE_PRESENT + + +/* +********************************************************************************************************* +* INCLUDE FILES +* +* Note(s) : (1) The custom library software files are located in the following directories : +* +* (a) \\lib_cfg.h +* +* (b) \\lib_*.* +* +* where +* directory path for Your Product's Application +* directory path for custom library software +* +* (2) CPU-configuration software files are located in the following directories : +* +* (a) \\cpu_*.* +* (b) \\\\cpu*.* +* +* where +* directory path for common CPU-compiler software +* directory name for specific processor (CPU) +* directory name for specific compiler +* +* (3) Compiler MUST be configured to include as additional include path directories : +* +* (a) '\\' directory See Note #1a +* +* (b) '\\' directory See Note #1b +* +* (c) (1) '\\' directory See Note #2a +* (2) '\\\\' directory See Note #2b +* +* (4) NO compiler-supplied standard library functions SHOULD be used. +********************************************************************************************************* +*/ + +#include +#include + +#include +#include + + +/* +********************************************************************************************************* +* EXTERNS +********************************************************************************************************* +*/ + +#ifdef LIB_MEM_MODULE +#define LIB_MEM_EXT +#else +#define LIB_MEM_EXT extern +#endif + + +/* +********************************************************************************************************* +* DEFINES +********************************************************************************************************* +*/ + +#define LIB_MEM_PADDING_ALIGN_NONE 1u + +#define LIB_MEM_BLK_QTY_UNLIMITED 0u + + +/* +********************************************************************************************************* +* DEFAULT CONFIGURATION +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* MEMORY LIBRARY ARGUMENT CHECK CONFIGURATION +* +* Note(s) : (1) Configure LIB_MEM_CFG_ARG_CHK_EXT_EN to enable/disable the memory library suite external +* argument check feature : +* +* (a) When ENABLED, arguments received from any port interface provided by the developer +* or application are checked/validated. +* +* (b) When DISABLED, NO arguments received from any port interface provided by the developer +* or application are checked/validated. +********************************************************************************************************* +*/ + + /* Cfg external argument check feature (see Note #1) : */ +#ifndef LIB_MEM_CFG_ARG_CHK_EXT_EN +#define LIB_MEM_CFG_ARG_CHK_EXT_EN DEF_DISABLED + /* DEF_DISABLED Argument check DISABLED */ + /* DEF_ENABLED Argument check ENABLED */ +#endif + + +/* +********************************************************************************************************* +* MEMORY LIBRARY ASSEMBLY OPTIMIZATION CONFIGURATION +* +* Note(s) : (1) Configure LIB_MEM_CFG_OPTIMIZE_ASM_EN to enable/disable assembly-optimized memory +* functions. +********************************************************************************************************* +*/ + + /* Cfg assembly-optimized function(s) [see Note #1] : */ +#ifndef LIB_MEM_CFG_OPTIMIZE_ASM_EN +#define LIB_MEM_CFG_OPTIMIZE_ASM_EN DEF_DISABLED + /* DEF_DISABLED Assembly-optimized fnct(s) DISABLED */ + /* DEF_ENABLED Assembly-optimized fnct(s) ENABLED */ +#endif + + +/* +********************************************************************************************************* +* MEMORY ALLOCATION DEBUG INFORMATION CONFIGURATION +* +* Note(s) : (1) Configure LIB_MEM_CFG_DBG_INFO_EN to enable/disable debug information associated to each +* segment allocation. +********************************************************************************************************* +*/ + +#ifndef LIB_MEM_CFG_DBG_INFO_EN +#define LIB_MEM_CFG_DBG_INFO_EN DEF_DISABLED +#endif + + +/* +********************************************************************************************************* +* HEAP PADDING ALIGN CONFIGURATION +* +* Note(s) : (1) Configure LIB_MEM_CFG_HEAP_PADDING_ALIGN to set the padding alignment of any buffer +* allocated from the heap. +********************************************************************************************************* +*/ + +#ifndef LIB_MEM_CFG_HEAP_PADDING_ALIGN +#define LIB_MEM_CFG_HEAP_PADDING_ALIGN LIB_MEM_PADDING_ALIGN_NONE +#endif + + +/* +********************************************************************************************************* +* DATA TYPES +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* LIB MEM TYPE +* +* Note(s) : (1) 'LIB_MEM_TYPE' declared as 'CPU_INT32U' & all 'LIB_MEM_TYPE's #define'd with large, non-trivial +* values to trap & discard invalid/corrupted library memory objects based on 'LIB_MEM_TYPE'. +********************************************************************************************************* +*/ + +typedef CPU_INT32U LIB_MEM_TYPE; + + +/* +********************************************************************************************************* +* MEMORY POOL BLOCK QUANTITY DATA TYPE +********************************************************************************************************* +*/ + +typedef CPU_SIZE_T MEM_POOL_BLK_QTY; + + +/* +********************************************************************************************************* +* MEMORY POOL TABLE IX TYPE +********************************************************************************************************* +*/ + +typedef MEM_POOL_BLK_QTY MEM_POOL_IX; + + +/* +********************************************************************************************************* +* MEMORY ALLOCATION TRACKING INFO DATA TYPE +********************************************************************************************************* +*/ + +#if (LIB_MEM_CFG_DBG_INFO_EN == DEF_ENABLED) +typedef struct mem_alloc_info MEM_ALLOC_INFO; + +struct mem_alloc_info { /* ------------------ MEM ALLOC INFO ------------------ */ + const CPU_CHAR *NamePtr; /* Ptr to name. */ + CPU_SIZE_T Size; /* Total alloc'd size, in bytes. */ + MEM_ALLOC_INFO *NextPtr; /* Ptr to next alloc info in list. */ +}; +#endif + + +/* +********************************************************************************************************* +* MEMORY SEGMENTS DATA TYPES +********************************************************************************************************* +*/ + +typedef struct mem_seg MEM_SEG; /* --------------------- SEG DATA --------------------- */ + +struct mem_seg { + CPU_ADDR AddrBase; /* Seg start addr. */ + CPU_ADDR AddrEnd; /* Seg end addr (last addr). */ + CPU_ADDR AddrNext; /* Next free addr. */ + + MEM_SEG *NextPtr; /* Ptr to next seg. */ + + CPU_SIZE_T PaddingAlign; /* Padding alignment in byte. */ + +#if (LIB_MEM_CFG_DBG_INFO_EN == DEF_ENABLED) + const CPU_CHAR *NamePtr; /* Ptr to seg name. */ + MEM_ALLOC_INFO *AllocInfoHeadPtr; /* Ptr to head of alloc info struct list. */ +#endif +}; + +typedef struct mem_seg_info { /* --------------------- SEG INFO --------------------- */ + CPU_SIZE_T UsedSize; /* Allocated seg octets. */ + CPU_SIZE_T TotalSize; /* Total seg capacity, in octets. */ + + CPU_ADDR AddrBase; + CPU_ADDR AddrNextAlloc; +} MEM_SEG_INFO; + + +/* +********************************************************************************************************* +* (STATIC) MEMORY POOL DATA TYPES +* +* Note(s) : (1) Free static memory pool blocks are indexed in the 'BlkFreeTbl' table. Newly freed blocks +* are added at the first available position in the table and blocks are retrieved from the +* last occupied position, in a LIFO fashion. +* +* /-------------------------------\ +* |/------------\ | +* BlkFreeTbl || Start v v End +* /--------\ || /--------------------------------------------\ +* |p_free_1|---/| | | | | | | +* |--------| | \--------------------------------------------/ +* |p_free_2|----/ ^ | | +* |--------| | |__Blk___| +* |p_free_3|--------/ (Next block to be retrieved.) Size +* |--------| +* | |<-------- (Next block to be freed.) +* \--------/ +* +********************************************************************************************************* +*/ + + /* --------------------- MEM POOL --------------------- */ +typedef struct mem_pool { + void *PoolAddrStart; /* Ptr to start of mem seg for mem pool blks. */ + void *PoolAddrEnd; /* Ptr to end of mem seg for mem pool blks. */ + MEM_POOL_BLK_QTY BlkNbr; /* Nbr of mem pool blks. */ + CPU_SIZE_T BlkSize; /* Size of mem pool blks (in octets). */ + void **BlkFreeTbl; /* Tbl of free mem pool blks. */ + CPU_SIZE_T BlkFreeTblIx; /* Ix of next free blk free tbl entry. */ +} MEM_POOL; + + +/* +********************************************************************************************************* +* DYNAMIC MEMORY POOL DATA TYPE +* +* Note(s) : (1) Dynamic memory pool blocks are not indexed in a table. Only freed blocks are linked using +* a singly linked list, in a LIFO fashion; newly freed blocks are inserted at the head of the +* list and blocks are also retrieved from the head of the list. +* +* (2) Pointers to the next block are only present when a block is free, using the first location +* in the allocated memory block. The user of dynamic memory pool must not assume his data +* will not be overwritten when a block is freed. +* +* /----------------\ +* /----------\ | /----------\ | /----------\ /----------\ +* BlkFreePtr-->|(NextPtr) |---/ | | \--->|(NextPtr) |-->|(NextPtr) |--> DEF_NULL +* |----------| | Blk in | |----------| |----------| +* | | | use | | | | | +* | | | | | | | | +* \----------/ \----------/ \----------/ \----------/ +* +********************************************************************************************************* +*/ + +typedef struct mem_dyn_pool { /* ---------------- DYN MEM POOL DATA ----------------- */ + MEM_SEG *PoolSegPtr; /* Mem pool from which blks are alloc'd. */ + CPU_SIZE_T BlkSize; /* Size of pool blks, in octets. */ + CPU_SIZE_T BlkAlign; /* Align req'd for blks, in octets. */ + CPU_SIZE_T BlkPaddingAlign; /* Padding alignment in bytes for this mem seg. */ + void *BlkFreePtr; /* Ptr to first free blk. */ + + CPU_SIZE_T BlkQtyMax; /* Max qty of blk in dyn mem pool. 0 = unlimited. */ + CPU_SIZE_T BlkAllocCnt; /* Cnt of alloc blk. */ + +#if (LIB_MEM_CFG_DBG_INFO_EN == DEF_ENABLED) + const CPU_CHAR *NamePtr; /* Ptr to mem pool name. */ +#endif +} MEM_DYN_POOL; + + +/* +********************************************************************************************************* +* GLOBAL VARIABLES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* MACRO'S +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* MEMORY DATA VALUE MACRO'S +* +* Note(s) : (1) (a) Some variables & variable buffers to pass & receive data values MUST start on appropriate +* CPU word-aligned addresses. This is required because most word-aligned processors are more +* efficient & may even REQUIRE that multi-octet words start on CPU word-aligned addresses. +* +* (1) For 16-bit word-aligned processors, this means that +* +* all 16- & 32-bit words MUST start on addresses that are multiples of 2 octets +* +* (2) For 32-bit word-aligned processors, this means that +* +* all 16-bit words MUST start on addresses that are multiples of 2 octets +* all 32-bit words MUST start on addresses that are multiples of 4 octets +* +* (b) However, some data values macro's appropriately access data values from any CPU addresses, +* word-aligned or not. Thus for processors that require data word alignment, data words can +* be accessed to/from any CPU address, word-aligned or not, without generating data-word- +* alignment exceptions/faults. +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* ENDIAN WORD ORDER MACRO'S +* +* Description : Convert data values to & from big-, little, or host-endian CPU word order. +* +* Argument(s) : val Data value to convert (see Notes #1 & #2). +* +* Return(s) : Converted data value (see Notes #1 & #2). +* +* Caller(s) : Application. +* +* Note(s) : (1) Convert data values to the desired data-word order : +* +* MEM_VAL_BIG_TO_LITTLE_xx() Convert big- endian data values +* to little- endian data values +* MEM_VAL_LITTLE_TO_BIG_xx() Convert little- endian data values +* to big- endian data values +* MEM_VAL_xxx_TO_HOST_xx() Convert big-/little-endian data values +* to host- endian data values +* MEM_VAL_HOST_TO_xxx_xx() Convert host- endian data values +* to big-/little-endian data values +* +* See also 'cpu.h CPU WORD CONFIGURATION Note #2'. +* +* (2) 'val' data value to convert & any variable to receive the returned conversion MUST +* start on appropriate CPU word-aligned addresses. +* +* See also 'MEMORY DATA VALUE MACRO'S Note #1a'. +* +* (3) MEM_VAL_COPY_xxx() macro's are more efficient than generic endian word order macro's & +* are also independent of CPU data-word-alignment & SHOULD be used whenever possible. +* +* See also 'MEM_VAL_COPY_GET_xxx() Note #4' +* & 'MEM_VAL_COPY_SET_xxx() Note #4'. +* +* (4) Generic endian word order macro's are NOT atomic operations & MUST NOT be used on any +* non-static (i.e. volatile) variables, registers, hardware, etc.; without the caller of +* the macro's providing some form of additional protection (e.g. mutual exclusion). +* +* (5) The 'CPU_CFG_ENDIAN_TYPE' pre-processor 'else'-conditional code SHOULD never be compiled/ +* linked since each 'cpu.h' SHOULD ensure that the CPU data-word-memory order configuration +* constant (CPU_CFG_ENDIAN_TYPE) is configured with an appropriate data-word-memory order +* value (see 'cpu.h CPU WORD CONFIGURATION Note #2'). The 'else'-conditional code is +* included as an extra precaution in case 'cpu.h' is incorrectly configured. +********************************************************************************************************* +*/ + +#if ((CPU_CFG_DATA_SIZE == CPU_WORD_SIZE_64) || \ + (CPU_CFG_DATA_SIZE == CPU_WORD_SIZE_32)) + +#define MEM_VAL_BIG_TO_LITTLE_16(val) ((CPU_INT16U)(((CPU_INT16U)((((CPU_INT16U)(val)) & (CPU_INT16U) 0xFF00u) >> (1u * DEF_OCTET_NBR_BITS))) | \ + ((CPU_INT16U)((((CPU_INT16U)(val)) & (CPU_INT16U) 0x00FFu) << (1u * DEF_OCTET_NBR_BITS))))) + +#define MEM_VAL_BIG_TO_LITTLE_32(val) ((CPU_INT32U)(((CPU_INT32U)((((CPU_INT32U)(val)) & (CPU_INT32U)0xFF000000u) >> (3u * DEF_OCTET_NBR_BITS))) | \ + ((CPU_INT32U)((((CPU_INT32U)(val)) & (CPU_INT32U)0x00FF0000u) >> (1u * DEF_OCTET_NBR_BITS))) | \ + ((CPU_INT32U)((((CPU_INT32U)(val)) & (CPU_INT32U)0x0000FF00u) << (1u * DEF_OCTET_NBR_BITS))) | \ + ((CPU_INT32U)((((CPU_INT32U)(val)) & (CPU_INT32U)0x000000FFu) << (3u * DEF_OCTET_NBR_BITS))))) + +#elif (CPU_CFG_DATA_SIZE == CPU_WORD_SIZE_16) + +#define MEM_VAL_BIG_TO_LITTLE_16(val) ((CPU_INT16U)(((CPU_INT16U)((((CPU_INT16U)(val)) & (CPU_INT16U) 0xFF00u) >> (1u * DEF_OCTET_NBR_BITS))) | \ + ((CPU_INT16U)((((CPU_INT16U)(val)) & (CPU_INT16U) 0x00FFu) << (1u * DEF_OCTET_NBR_BITS))))) + +#define MEM_VAL_BIG_TO_LITTLE_32(val) ((CPU_INT32U)(((CPU_INT32U)((((CPU_INT32U)(val)) & (CPU_INT32U)0xFF000000u) >> (1u * DEF_OCTET_NBR_BITS))) | \ + ((CPU_INT32U)((((CPU_INT32U)(val)) & (CPU_INT32U)0x00FF0000u) << (1u * DEF_OCTET_NBR_BITS))) | \ + ((CPU_INT32U)((((CPU_INT32U)(val)) & (CPU_INT32U)0x0000FF00u) >> (1u * DEF_OCTET_NBR_BITS))) | \ + ((CPU_INT32U)((((CPU_INT32U)(val)) & (CPU_INT32U)0x000000FFu) << (1u * DEF_OCTET_NBR_BITS))))) + +#else + +#define MEM_VAL_BIG_TO_LITTLE_16(val) (val) +#define MEM_VAL_BIG_TO_LITTLE_32(val) (val) + +#endif + + +#define MEM_VAL_LITTLE_TO_BIG_16(val) MEM_VAL_BIG_TO_LITTLE_16(val) +#define MEM_VAL_LITTLE_TO_BIG_32(val) MEM_VAL_BIG_TO_LITTLE_32(val) + + + +#if (CPU_CFG_ENDIAN_TYPE == CPU_ENDIAN_TYPE_BIG) + +#define MEM_VAL_BIG_TO_HOST_16(val) (val) +#define MEM_VAL_BIG_TO_HOST_32(val) (val) +#define MEM_VAL_LITTLE_TO_HOST_16(val) MEM_VAL_LITTLE_TO_BIG_16(val) +#define MEM_VAL_LITTLE_TO_HOST_32(val) MEM_VAL_LITTLE_TO_BIG_32(val) + +#elif (CPU_CFG_ENDIAN_TYPE == CPU_ENDIAN_TYPE_LITTLE) + +#define MEM_VAL_BIG_TO_HOST_16(val) MEM_VAL_BIG_TO_LITTLE_16(val) +#define MEM_VAL_BIG_TO_HOST_32(val) MEM_VAL_BIG_TO_LITTLE_32(val) +#define MEM_VAL_LITTLE_TO_HOST_16(val) (val) +#define MEM_VAL_LITTLE_TO_HOST_32(val) (val) + +#else /* See Note #5. */ + +#error "CPU_CFG_ENDIAN_TYPE illegally #defined in 'cpu.h' " +#error " [See 'cpu.h CONFIGURATION ERRORS']" + +#endif + + +#define MEM_VAL_HOST_TO_BIG_16(val) MEM_VAL_BIG_TO_HOST_16(val) +#define MEM_VAL_HOST_TO_BIG_32(val) MEM_VAL_BIG_TO_HOST_32(val) +#define MEM_VAL_HOST_TO_LITTLE_16(val) MEM_VAL_LITTLE_TO_HOST_16(val) +#define MEM_VAL_HOST_TO_LITTLE_32(val) MEM_VAL_LITTLE_TO_HOST_32(val) + + +/* +********************************************************************************************************* +* MEM_VAL_GET_xxx() +* +* Description : Decode data values from any CPU memory address. +* +* Argument(s) : addr Lowest CPU memory address of data value to decode (see Notes #2 & #3a). +* +* Return(s) : Decoded data value from CPU memory address (see Notes #1 & #3b). +* +* Caller(s) : Application. +* +* Note(s) : (1) Decode data values based on the values' data-word order in CPU memory : +* +* MEM_VAL_GET_xxx_BIG() Decode big- endian data values -- data words' most +* significant octet @ lowest memory address +* MEM_VAL_GET_xxx_LITTLE() Decode little-endian data values -- data words' least +* significant octet @ lowest memory address +* MEM_VAL_GET_xxx() Decode data values using CPU's native or configured +* data-word order +* +* See also 'cpu.h CPU WORD CONFIGURATION Note #2'. +* +* (2) CPU memory addresses/pointers NOT checked for NULL. +* +* (3) (a) MEM_VAL_GET_xxx() macro's decode data values without regard to CPU word-aligned addresses. +* Thus for processors that require data word alignment, data words can be decoded from any +* CPU address, word-aligned or not, without generating data-word-alignment exceptions/faults. +* +* (b) However, any variable to receive the returned data value MUST start on an appropriate CPU +* word-aligned address. +* +* See also 'MEMORY DATA VALUE MACRO'S Note #1'. +* +* (4) MEM_VAL_COPY_GET_xxx() macro's are more efficient than MEM_VAL_GET_xxx() macro's & are +* also independent of CPU data-word-alignment & SHOULD be used whenever possible. +* +* See also 'MEM_VAL_COPY_GET_xxx() Note #4'. +* +* (5) MEM_VAL_GET_xxx() macro's are NOT atomic operations & MUST NOT be used on any non-static +* (i.e. volatile) variables, registers, hardware, etc.; without the caller of the macro's +* providing some form of additional protection (e.g. mutual exclusion). +* +* (6) The 'CPU_CFG_ENDIAN_TYPE' pre-processor 'else'-conditional code SHOULD never be compiled/ +* linked since each 'cpu.h' SHOULD ensure that the CPU data-word-memory order configuration +* constant (CPU_CFG_ENDIAN_TYPE) is configured with an appropriate data-word-memory order +* value (see 'cpu.h CPU WORD CONFIGURATION Note #2'). The 'else'-conditional code is +* included as an extra precaution in case 'cpu.h' is incorrectly configured. +********************************************************************************************************* +*/ + +#define MEM_VAL_GET_INT08U_BIG(addr) ((CPU_INT08U) ((CPU_INT08U)(((CPU_INT08U)(*(((CPU_INT08U *)(addr)) + 0))) << (0u * DEF_OCTET_NBR_BITS)))) + +#define MEM_VAL_GET_INT16U_BIG(addr) ((CPU_INT16U)(((CPU_INT16U)(((CPU_INT16U)(*(((CPU_INT08U *)(addr)) + 0))) << (1u * DEF_OCTET_NBR_BITS))) + \ + ((CPU_INT16U)(((CPU_INT16U)(*(((CPU_INT08U *)(addr)) + 1))) << (0u * DEF_OCTET_NBR_BITS))))) + +#define MEM_VAL_GET_INT32U_BIG(addr) ((CPU_INT32U)(((CPU_INT32U)(((CPU_INT32U)(*(((CPU_INT08U *)(addr)) + 0))) << (3u * DEF_OCTET_NBR_BITS))) + \ + ((CPU_INT32U)(((CPU_INT32U)(*(((CPU_INT08U *)(addr)) + 1))) << (2u * DEF_OCTET_NBR_BITS))) + \ + ((CPU_INT32U)(((CPU_INT32U)(*(((CPU_INT08U *)(addr)) + 2))) << (1u * DEF_OCTET_NBR_BITS))) + \ + ((CPU_INT32U)(((CPU_INT32U)(*(((CPU_INT08U *)(addr)) + 3))) << (0u * DEF_OCTET_NBR_BITS))))) + + + +#define MEM_VAL_GET_INT08U_LITTLE(addr) ((CPU_INT08U) ((CPU_INT08U)(((CPU_INT08U)(*(((CPU_INT08U *)(addr)) + 0))) << (0u * DEF_OCTET_NBR_BITS)))) + +#define MEM_VAL_GET_INT16U_LITTLE(addr) ((CPU_INT16U)(((CPU_INT16U)(((CPU_INT16U)(*(((CPU_INT08U *)(addr)) + 0))) << (0u * DEF_OCTET_NBR_BITS))) + \ + ((CPU_INT16U)(((CPU_INT16U)(*(((CPU_INT08U *)(addr)) + 1))) << (1u * DEF_OCTET_NBR_BITS))))) + +#define MEM_VAL_GET_INT32U_LITTLE(addr) ((CPU_INT32U)(((CPU_INT32U)(((CPU_INT32U)(*(((CPU_INT08U *)(addr)) + 0))) << (0u * DEF_OCTET_NBR_BITS))) + \ + ((CPU_INT32U)(((CPU_INT32U)(*(((CPU_INT08U *)(addr)) + 1))) << (1u * DEF_OCTET_NBR_BITS))) + \ + ((CPU_INT32U)(((CPU_INT32U)(*(((CPU_INT08U *)(addr)) + 2))) << (2u * DEF_OCTET_NBR_BITS))) + \ + ((CPU_INT32U)(((CPU_INT32U)(*(((CPU_INT08U *)(addr)) + 3))) << (3u * DEF_OCTET_NBR_BITS))))) + + + +#if (CPU_CFG_ENDIAN_TYPE == CPU_ENDIAN_TYPE_BIG) + +#define MEM_VAL_GET_INT08U(addr) MEM_VAL_GET_INT08U_BIG(addr) +#define MEM_VAL_GET_INT16U(addr) MEM_VAL_GET_INT16U_BIG(addr) +#define MEM_VAL_GET_INT32U(addr) MEM_VAL_GET_INT32U_BIG(addr) + +#elif (CPU_CFG_ENDIAN_TYPE == CPU_ENDIAN_TYPE_LITTLE) + +#define MEM_VAL_GET_INT08U(addr) MEM_VAL_GET_INT08U_LITTLE(addr) +#define MEM_VAL_GET_INT16U(addr) MEM_VAL_GET_INT16U_LITTLE(addr) +#define MEM_VAL_GET_INT32U(addr) MEM_VAL_GET_INT32U_LITTLE(addr) + +#else /* See Note #6. */ + +#error "CPU_CFG_ENDIAN_TYPE illegally #defined in 'cpu.h' " +#error " [See 'cpu.h CONFIGURATION ERRORS']" + +#endif + + +/* +********************************************************************************************************* +* MEM_VAL_SET_xxx() +* +* Description : Encode data values to any CPU memory address. +* +* Argument(s) : addr Lowest CPU memory address to encode data value (see Notes #2 & #3a). +* +* val Data value to encode (see Notes #1 & #3b). +* +* Return(s) : none. +* +* Caller(s) : Application. +* +* Note(s) : (1) Encode data values into CPU memory based on the values' data-word order : +* +* MEM_VAL_SET_xxx_BIG() Encode big- endian data values -- data words' most +* significant octet @ lowest memory address +* MEM_VAL_SET_xxx_LITTLE() Encode little-endian data values -- data words' least +* significant octet @ lowest memory address +* MEM_VAL_SET_xxx() Encode data values using CPU's native or configured +* data-word order +* +* See also 'cpu.h CPU WORD CONFIGURATION Note #2'. +* +* (2) CPU memory addresses/pointers NOT checked for NULL. +* +* (3) (a) MEM_VAL_SET_xxx() macro's encode data values without regard to CPU word-aligned addresses. +* Thus for processors that require data word alignment, data words can be encoded to any +* CPU address, word-aligned or not, without generating data-word-alignment exceptions/faults. +* +* (b) However, 'val' data value to encode MUST start on an appropriate CPU word-aligned address. +* +* See also 'MEMORY DATA VALUE MACRO'S Note #1'. +* +* (4) MEM_VAL_COPY_SET_xxx() macro's are more efficient than MEM_VAL_SET_xxx() macro's & are +* also independent of CPU data-word-alignment & SHOULD be used whenever possible. +* +* See also 'MEM_VAL_COPY_SET_xxx() Note #4'. +* +* (5) MEM_VAL_SET_xxx() macro's are NOT atomic operations & MUST NOT be used on any non-static +* (i.e. volatile) variables, registers, hardware, etc.; without the caller of the macro's +* providing some form of additional protection (e.g. mutual exclusion). +* +* (6) The 'CPU_CFG_ENDIAN_TYPE' pre-processor 'else'-conditional code SHOULD never be compiled/ +* linked since each 'cpu.h' SHOULD ensure that the CPU data-word-memory order configuration +* constant (CPU_CFG_ENDIAN_TYPE) is configured with an appropriate data-word-memory order +* value (see 'cpu.h CPU WORD CONFIGURATION Note #2'). The 'else'-conditional code is +* included as an extra precaution in case 'cpu.h' is incorrectly configured. +********************************************************************************************************* +*/ + +#define MEM_VAL_SET_INT08U_BIG(addr, val) do { (*(((CPU_INT08U *)(addr)) + 0)) = ((CPU_INT08U)((((CPU_INT08U)(val)) & (CPU_INT08U) 0xFFu) >> (0u * DEF_OCTET_NBR_BITS))); } while (0) + +#define MEM_VAL_SET_INT16U_BIG(addr, val) do { (*(((CPU_INT08U *)(addr)) + 0)) = ((CPU_INT08U)((((CPU_INT16U)(val)) & (CPU_INT16U) 0xFF00u) >> (1u * DEF_OCTET_NBR_BITS))); \ + (*(((CPU_INT08U *)(addr)) + 1)) = ((CPU_INT08U)((((CPU_INT16U)(val)) & (CPU_INT16U) 0x00FFu) >> (0u * DEF_OCTET_NBR_BITS))); } while (0) + +#define MEM_VAL_SET_INT32U_BIG(addr, val) do { (*(((CPU_INT08U *)(addr)) + 0)) = ((CPU_INT08U)((((CPU_INT32U)(val)) & (CPU_INT32U)0xFF000000u) >> (3u * DEF_OCTET_NBR_BITS))); \ + (*(((CPU_INT08U *)(addr)) + 1)) = ((CPU_INT08U)((((CPU_INT32U)(val)) & (CPU_INT32U)0x00FF0000u) >> (2u * DEF_OCTET_NBR_BITS))); \ + (*(((CPU_INT08U *)(addr)) + 2)) = ((CPU_INT08U)((((CPU_INT32U)(val)) & (CPU_INT32U)0x0000FF00u) >> (1u * DEF_OCTET_NBR_BITS))); \ + (*(((CPU_INT08U *)(addr)) + 3)) = ((CPU_INT08U)((((CPU_INT32U)(val)) & (CPU_INT32U)0x000000FFu) >> (0u * DEF_OCTET_NBR_BITS))); } while (0) + + + +#define MEM_VAL_SET_INT08U_LITTLE(addr, val) do { (*(((CPU_INT08U *)(addr)) + 0)) = ((CPU_INT08U)((((CPU_INT08U)(val)) & (CPU_INT08U) 0xFFu) >> (0u * DEF_OCTET_NBR_BITS))); } while (0) + +#define MEM_VAL_SET_INT16U_LITTLE(addr, val) do { (*(((CPU_INT08U *)(addr)) + 0)) = ((CPU_INT08U)((((CPU_INT16U)(val)) & (CPU_INT16U) 0x00FFu) >> (0u * DEF_OCTET_NBR_BITS))); \ + (*(((CPU_INT08U *)(addr)) + 1)) = ((CPU_INT08U)((((CPU_INT16U)(val)) & (CPU_INT16U) 0xFF00u) >> (1u * DEF_OCTET_NBR_BITS))); } while (0) + +#define MEM_VAL_SET_INT32U_LITTLE(addr, val) do { (*(((CPU_INT08U *)(addr)) + 0)) = ((CPU_INT08U)((((CPU_INT32U)(val)) & (CPU_INT32U)0x000000FFu) >> (0u * DEF_OCTET_NBR_BITS))); \ + (*(((CPU_INT08U *)(addr)) + 1)) = ((CPU_INT08U)((((CPU_INT32U)(val)) & (CPU_INT32U)0x0000FF00u) >> (1u * DEF_OCTET_NBR_BITS))); \ + (*(((CPU_INT08U *)(addr)) + 2)) = ((CPU_INT08U)((((CPU_INT32U)(val)) & (CPU_INT32U)0x00FF0000u) >> (2u * DEF_OCTET_NBR_BITS))); \ + (*(((CPU_INT08U *)(addr)) + 3)) = ((CPU_INT08U)((((CPU_INT32U)(val)) & (CPU_INT32U)0xFF000000u) >> (3u * DEF_OCTET_NBR_BITS))); } while (0) + + + +#if (CPU_CFG_ENDIAN_TYPE == CPU_ENDIAN_TYPE_BIG) + +#define MEM_VAL_SET_INT08U(addr, val) MEM_VAL_SET_INT08U_BIG(addr, val) +#define MEM_VAL_SET_INT16U(addr, val) MEM_VAL_SET_INT16U_BIG(addr, val) +#define MEM_VAL_SET_INT32U(addr, val) MEM_VAL_SET_INT32U_BIG(addr, val) + +#elif (CPU_CFG_ENDIAN_TYPE == CPU_ENDIAN_TYPE_LITTLE) + +#define MEM_VAL_SET_INT08U(addr, val) MEM_VAL_SET_INT08U_LITTLE(addr, val) +#define MEM_VAL_SET_INT16U(addr, val) MEM_VAL_SET_INT16U_LITTLE(addr, val) +#define MEM_VAL_SET_INT32U(addr, val) MEM_VAL_SET_INT32U_LITTLE(addr, val) + +#else /* See Note #6. */ + +#error "CPU_CFG_ENDIAN_TYPE illegally #defined in 'cpu.h' " +#error " [See 'cpu.h CONFIGURATION ERRORS']" + +#endif + + +/* +********************************************************************************************************* +* MEM_VAL_COPY_GET_xxx() +* +* Description : Copy & decode data values from any CPU memory address to any CPU memory address. +* +* Argument(s) : addr_dest Lowest CPU memory address to copy/decode source address's data value +* (see Notes #2 & #3). +* +* addr_src Lowest CPU memory address of data value to copy/decode +* (see Notes #2 & #3). +* +* Return(s) : none. +* +* Caller(s) : Application. +* +* Note(s) : (1) Copy/decode data values based on the values' data-word order : +* +* MEM_VAL_COPY_GET_xxx_BIG() Decode big- endian data values -- data words' most +* significant octet @ lowest memory address +* MEM_VAL_COPY_GET_xxx_LITTLE() Decode little-endian data values -- data words' least +* significant octet @ lowest memory address +* MEM_VAL_COPY_GET_xxx() Decode data values using CPU's native or configured +* data-word order +* +* See also 'cpu.h CPU WORD CONFIGURATION Note #2'. +* +* (2) (a) CPU memory addresses/pointers NOT checked for NULL. +* +* (b) CPU memory addresses/buffers NOT checked for overlapping. +* +* (1) IEEE Std 1003.1, 2004 Edition, Section 'memcpy() : DESCRIPTION' states that +* "copying ... between objects that overlap ... is undefined". +* +* (3) MEM_VAL_COPY_GET_xxx() macro's copy/decode data values without regard to CPU word-aligned +* addresses. Thus for processors that require data word alignment, data words can be copied/ +* decoded to/from any CPU address, word-aligned or not, without generating data-word-alignment +* exceptions/faults. +* +* (4) MEM_VAL_COPY_GET_xxx() macro's are more efficient than MEM_VAL_GET_xxx() macro's & are +* also independent of CPU data-word-alignment & SHOULD be used whenever possible. +* +* See also 'MEM_VAL_GET_xxx() Note #4'. +* +* (5) Since octet-order copy/conversion are inverse operations, MEM_VAL_COPY_GET_xxx() & +* MEM_VAL_COPY_SET_xxx() macros are inverse, but identical, operations & are provided +* in both forms for semantics & consistency. +* +* See also 'MEM_VAL_COPY_SET_xxx() Note #5'. +* +* (6) MEM_VAL_COPY_GET_xxx() macro's are NOT atomic operations & MUST NOT be used on any non- +* static (i.e. volatile) variables, registers, hardware, etc.; without the caller of the +* macro's providing some form of additional protection (e.g. mutual exclusion). +* +* (7) The 'CPU_CFG_ENDIAN_TYPE' pre-processor 'else'-conditional code SHOULD never be compiled/ +* linked since each 'cpu.h' SHOULD ensure that the CPU data-word-memory order configuration +* constant (CPU_CFG_ENDIAN_TYPE) is configured with an appropriate data-word-memory order +* value (see 'cpu.h CPU WORD CONFIGURATION Note #2'). The 'else'-conditional code is +* included as an extra precaution in case 'cpu.h' is incorrectly configured. +********************************************************************************************************* +*/ + +#if (CPU_CFG_ENDIAN_TYPE == CPU_ENDIAN_TYPE_BIG) + + +#define MEM_VAL_COPY_GET_INT08U_BIG(addr_dest, addr_src) do { (*(((CPU_INT08U *)(addr_dest)) + 0)) = (*(((CPU_INT08U *)(addr_src)) + 0)); } while (0) + +#define MEM_VAL_COPY_GET_INT16U_BIG(addr_dest, addr_src) do { (*(((CPU_INT08U *)(addr_dest)) + 0)) = (*(((CPU_INT08U *)(addr_src)) + 0)); \ + (*(((CPU_INT08U *)(addr_dest)) + 1)) = (*(((CPU_INT08U *)(addr_src)) + 1)); } while (0) + +#define MEM_VAL_COPY_GET_INT32U_BIG(addr_dest, addr_src) do { (*(((CPU_INT08U *)(addr_dest)) + 0)) = (*(((CPU_INT08U *)(addr_src)) + 0)); \ + (*(((CPU_INT08U *)(addr_dest)) + 1)) = (*(((CPU_INT08U *)(addr_src)) + 1)); \ + (*(((CPU_INT08U *)(addr_dest)) + 2)) = (*(((CPU_INT08U *)(addr_src)) + 2)); \ + (*(((CPU_INT08U *)(addr_dest)) + 3)) = (*(((CPU_INT08U *)(addr_src)) + 3)); } while (0) + + + +#define MEM_VAL_COPY_GET_INT08U_LITTLE(addr_dest, addr_src) do { (*(((CPU_INT08U *)(addr_dest)) + 0)) = (*(((CPU_INT08U *)(addr_src)) + 0)); } while (0) + +#define MEM_VAL_COPY_GET_INT16U_LITTLE(addr_dest, addr_src) do { (*(((CPU_INT08U *)(addr_dest)) + 0)) = (*(((CPU_INT08U *)(addr_src)) + 1)); \ + (*(((CPU_INT08U *)(addr_dest)) + 1)) = (*(((CPU_INT08U *)(addr_src)) + 0)); } while (0) + +#define MEM_VAL_COPY_GET_INT32U_LITTLE(addr_dest, addr_src) do { (*(((CPU_INT08U *)(addr_dest)) + 0)) = (*(((CPU_INT08U *)(addr_src)) + 3)); \ + (*(((CPU_INT08U *)(addr_dest)) + 1)) = (*(((CPU_INT08U *)(addr_src)) + 2)); \ + (*(((CPU_INT08U *)(addr_dest)) + 2)) = (*(((CPU_INT08U *)(addr_src)) + 1)); \ + (*(((CPU_INT08U *)(addr_dest)) + 3)) = (*(((CPU_INT08U *)(addr_src)) + 0)); } while (0) + + + +#define MEM_VAL_COPY_GET_INT08U(addr_dest, addr_src) MEM_VAL_COPY_GET_INT08U_BIG(addr_dest, addr_src) +#define MEM_VAL_COPY_GET_INT16U(addr_dest, addr_src) MEM_VAL_COPY_GET_INT16U_BIG(addr_dest, addr_src) +#define MEM_VAL_COPY_GET_INT32U(addr_dest, addr_src) MEM_VAL_COPY_GET_INT32U_BIG(addr_dest, addr_src) + + + + +#elif (CPU_CFG_ENDIAN_TYPE == CPU_ENDIAN_TYPE_LITTLE) + + +#define MEM_VAL_COPY_GET_INT08U_BIG(addr_dest, addr_src) do { (*(((CPU_INT08U *)(addr_dest)) + 0)) = (*(((CPU_INT08U *)(addr_src)) + 0)); } while (0) + +#define MEM_VAL_COPY_GET_INT16U_BIG(addr_dest, addr_src) do { (*(((CPU_INT08U *)(addr_dest)) + 0)) = (*(((CPU_INT08U *)(addr_src)) + 1)); \ + (*(((CPU_INT08U *)(addr_dest)) + 1)) = (*(((CPU_INT08U *)(addr_src)) + 0)); } while (0) + +#define MEM_VAL_COPY_GET_INT32U_BIG(addr_dest, addr_src) do { (*(((CPU_INT08U *)(addr_dest)) + 0)) = (*(((CPU_INT08U *)(addr_src)) + 3)); \ + (*(((CPU_INT08U *)(addr_dest)) + 1)) = (*(((CPU_INT08U *)(addr_src)) + 2)); \ + (*(((CPU_INT08U *)(addr_dest)) + 2)) = (*(((CPU_INT08U *)(addr_src)) + 1)); \ + (*(((CPU_INT08U *)(addr_dest)) + 3)) = (*(((CPU_INT08U *)(addr_src)) + 0)); } while (0) + + + +#define MEM_VAL_COPY_GET_INT08U_LITTLE(addr_dest, addr_src) do { (*(((CPU_INT08U *)(addr_dest)) + 0)) = (*(((CPU_INT08U *)(addr_src)) + 0)); } while (0) + +#define MEM_VAL_COPY_GET_INT16U_LITTLE(addr_dest, addr_src) do { (*(((CPU_INT08U *)(addr_dest)) + 0)) = (*(((CPU_INT08U *)(addr_src)) + 0)); \ + (*(((CPU_INT08U *)(addr_dest)) + 1)) = (*(((CPU_INT08U *)(addr_src)) + 1)); } while (0) + +#define MEM_VAL_COPY_GET_INT32U_LITTLE(addr_dest, addr_src) do { (*(((CPU_INT08U *)(addr_dest)) + 0)) = (*(((CPU_INT08U *)(addr_src)) + 0)); \ + (*(((CPU_INT08U *)(addr_dest)) + 1)) = (*(((CPU_INT08U *)(addr_src)) + 1)); \ + (*(((CPU_INT08U *)(addr_dest)) + 2)) = (*(((CPU_INT08U *)(addr_src)) + 2)); \ + (*(((CPU_INT08U *)(addr_dest)) + 3)) = (*(((CPU_INT08U *)(addr_src)) + 3)); } while (0) + + + +#define MEM_VAL_COPY_GET_INT08U(addr_dest, addr_src) MEM_VAL_COPY_GET_INT08U_LITTLE(addr_dest, addr_src) +#define MEM_VAL_COPY_GET_INT16U(addr_dest, addr_src) MEM_VAL_COPY_GET_INT16U_LITTLE(addr_dest, addr_src) +#define MEM_VAL_COPY_GET_INT32U(addr_dest, addr_src) MEM_VAL_COPY_GET_INT32U_LITTLE(addr_dest, addr_src) + + + + +#else /* See Note #7. */ + +#error "CPU_CFG_ENDIAN_TYPE illegally #defined in 'cpu.h' " +#error " [See 'cpu.h CONFIGURATION ERRORS']" + +#endif + + +/* +********************************************************************************************************* +* MEM_VAL_COPY_GET_INTU_xxx() +* +* Description : Copy & decode data values from any CPU memory address to any CPU memory address for +* any sized data values. +* +* Argument(s) : addr_dest Lowest CPU memory address to copy/decode source address's data value +* (see Notes #2 & #3). +* +* addr_src Lowest CPU memory address of data value to copy/decode +* (see Notes #2 & #3). +* +* val_size Number of data value octets to copy/decode. +* +* Return(s) : none. +* +* Caller(s) : Application. +* +* Note(s) : (1) Copy/decode data values based on the values' data-word order : +* +* MEM_VAL_COPY_GET_INTU_BIG() Decode big- endian data values -- data words' most +* significant octet @ lowest memory address +* MEM_VAL_COPY_GET_INTU_LITTLE() Decode little-endian data values -- data words' least +* significant octet @ lowest memory address +* MEM_VAL_COPY_GET_INTU() Decode data values using CPU's native or configured +* data-word order +* +* See also 'cpu.h CPU WORD CONFIGURATION Note #2'. +* +* (2) (a) CPU memory addresses/pointers NOT checked for NULL. +* +* (b) CPU memory addresses/buffers NOT checked for overlapping. +* +* (1) IEEE Std 1003.1, 2004 Edition, Section 'memcpy() : DESCRIPTION' states that +* "copying ... between objects that overlap ... is undefined". +* +* (3) MEM_VAL_COPY_GET_INTU_xxx() macro's copy/decode data values without regard to CPU word- +* aligned addresses. Thus for processors that require data word alignment, data words +* can be copied/decoded to/from any CPU address, word-aligned or not, without generating +* data-word-alignment exceptions/faults. +* +* (4) MEM_VAL_COPY_GET_xxx() macro's are more efficient than MEM_VAL_COPY_GET_INTU_xxx() +* macro's & SHOULD be used whenever possible. +* +* See also 'MEM_VAL_COPY_GET_xxx() Note #4'. +* +* (5) Since octet-order copy/conversion are inverse operations, MEM_VAL_COPY_GET_INTU_xxx() & +* MEM_VAL_COPY_SET_INTU_xxx() macros are inverse, but identical, operations & are provided +* in both forms for semantics & consistency. +* +* See also 'MEM_VAL_COPY_SET_INTU_xxx() Note #5'. +* +* (6) MEM_VAL_COPY_GET_INTU_xxx() macro's are NOT atomic operations & MUST NOT be used on any +* non-static (i.e. volatile) variables, registers, hardware, etc.; without the caller of +* the macro's providing some form of additional protection (e.g. mutual exclusion). +* +* (7) MISRA-C 2004 Rule 5.2 states that "identifiers in an inner scope shall not use the same +* name as an indentifier in an outer scope, and therefore hide that identifier". +* +* Therefore, to avoid possible redeclaration of commonly-used loop counter identifier names, +* 'i' & 'j', MEM_VAL_COPY_GET_INTU_xxx() loop counter identifier names are prefixed with a +* single underscore. +* +* (8) The 'CPU_CFG_ENDIAN_TYPE' pre-processor 'else'-conditional code SHOULD never be compiled/ +* linked since each 'cpu.h' SHOULD ensure that the CPU data-word-memory order configuration +* constant (CPU_CFG_ENDIAN_TYPE) is configured with an appropriate data-word-memory order +* value (see 'cpu.h CPU WORD CONFIGURATION Note #2'). The 'else'-conditional code is +* included as an extra precaution in case 'cpu.h' is incorrectly configured. +********************************************************************************************************* +*/ + +#if (CPU_CFG_ENDIAN_TYPE == CPU_ENDIAN_TYPE_BIG) + + +#define MEM_VAL_COPY_GET_INTU_BIG(addr_dest, addr_src, val_size) do { \ + CPU_SIZE_T _i; \ + \ + for (_i = 0; _i < (val_size); _i++) { \ + (*(((CPU_INT08U *)(addr_dest)) + _i)) = (*(((CPU_INT08U *)(addr_src)) + _i)); \ + } \ + } while (0) + + +#define MEM_VAL_COPY_GET_INTU_LITTLE(addr_dest, addr_src, val_size) do { \ + CPU_SIZE_T _i; \ + CPU_SIZE_T _j; \ + \ + \ + _j = (val_size) - 1; \ + \ + for (_i = 0; _i < (val_size); _i++) { \ + (*(((CPU_INT08U *)(addr_dest)) + _i)) = (*(((CPU_INT08U *)(addr_src)) + _j)); \ + _j--; \ + } \ + } while (0) + + +#define MEM_VAL_COPY_GET_INTU(addr_dest, addr_src, val_size) MEM_VAL_COPY_GET_INTU_BIG(addr_dest, addr_src, val_size) + + + + +#elif (CPU_CFG_ENDIAN_TYPE == CPU_ENDIAN_TYPE_LITTLE) + + +#define MEM_VAL_COPY_GET_INTU_BIG(addr_dest, addr_src, val_size) do { \ + CPU_SIZE_T _i; \ + CPU_SIZE_T _j; \ + \ + \ + _j = (val_size) - 1; \ + \ + for (_i = 0; _i < (val_size); _i++) { \ + (*(((CPU_INT08U *)(addr_dest)) + _i)) = (*(((CPU_INT08U *)(addr_src)) + _j)); \ + _j--; \ + } \ + } while (0) + + +#define MEM_VAL_COPY_GET_INTU_LITTLE(addr_dest, addr_src, val_size) do { \ + CPU_SIZE_T _i; \ + \ + for (_i = 0; _i < (val_size); _i++) { \ + (*(((CPU_INT08U *)(addr_dest)) + _i)) = (*(((CPU_INT08U *)(addr_src)) + _i)); \ + } \ + } while (0) + + +#define MEM_VAL_COPY_GET_INTU(addr_dest, addr_src, val_size) MEM_VAL_COPY_GET_INTU_LITTLE(addr_dest, addr_src, val_size) + + + + +#else /* See Note #8. */ + +#error "CPU_CFG_ENDIAN_TYPE illegally #defined in 'cpu.h' " +#error " [See 'cpu.h CONFIGURATION ERRORS']" + +#endif + + +/* +********************************************************************************************************* +* MEM_VAL_COPY_SET_xxx() +* +* Description : Copy & encode data values from any CPU memory address to any CPU memory address. +* +* Argument(s) : addr_dest Lowest CPU memory address to copy/encode source address's data value +* (see Notes #2 & #3). +* +* addr_src Lowest CPU memory address of data value to copy/encode +* (see Notes #2 & #3). +* +* Return(s) : none. +* +* Caller(s) : Application. +* +* Note(s) : (1) Copy/encode data values based on the values' data-word order : +* +* MEM_VAL_COPY_SET_xxx_BIG() Encode big- endian data values -- data words' most +* significant octet @ lowest memory address +* MEM_VAL_COPY_SET_xxx_LITTLE() Encode little-endian data values -- data words' least +* significant octet @ lowest memory address +* MEM_VAL_COPY_SET_xxx() Encode data values using CPU's native or configured +* data-word order +* +* See also 'cpu.h CPU WORD CONFIGURATION Note #2'. +* +* (2) (a) CPU memory addresses/pointers NOT checked for NULL. +* +* (b) CPU memory addresses/buffers NOT checked for overlapping. +* +* (1) IEEE Std 1003.1, 2004 Edition, Section 'memcpy() : DESCRIPTION' states that +* "copying ... between objects that overlap ... is undefined". +* +* (3) MEM_VAL_COPY_SET_xxx() macro's copy/encode data values without regard to CPU word-aligned +* addresses. Thus for processors that require data word alignment, data words can be copied/ +* encoded to/from any CPU address, word-aligned or not, without generating data-word-alignment +* exceptions/faults. +* +* (4) MEM_VAL_COPY_SET_xxx() macro's are more efficient than MEM_VAL_SET_xxx() macro's & are +* also independent of CPU data-word-alignment & SHOULD be used whenever possible. +* +* See also 'MEM_VAL_SET_xxx() Note #4'. +* +* (5) Since octet-order copy/conversion are inverse operations, MEM_VAL_COPY_GET_xxx() & +* MEM_VAL_COPY_SET_xxx() macros are inverse, but identical, operations & are provided +* in both forms for semantics & consistency. +* +* See also 'MEM_VAL_COPY_GET_xxx() Note #5'. +* +* (6) MEM_VAL_COPY_SET_xxx() macro's are NOT atomic operations & MUST NOT be used on any +* non-static (i.e. volatile) variables, registers, hardware, etc.; without the caller +* of the macro's providing some form of additional protection (e.g. mutual exclusion). +********************************************************************************************************* +*/ + + /* See Note #5. */ +#define MEM_VAL_COPY_SET_INT08U_BIG(addr_dest, addr_src) MEM_VAL_COPY_GET_INT08U_BIG(addr_dest, addr_src) +#define MEM_VAL_COPY_SET_INT16U_BIG(addr_dest, addr_src) MEM_VAL_COPY_GET_INT16U_BIG(addr_dest, addr_src) +#define MEM_VAL_COPY_SET_INT32U_BIG(addr_dest, addr_src) MEM_VAL_COPY_GET_INT32U_BIG(addr_dest, addr_src) + +#define MEM_VAL_COPY_SET_INT08U_LITTLE(addr_dest, addr_src) MEM_VAL_COPY_GET_INT08U_LITTLE(addr_dest, addr_src) +#define MEM_VAL_COPY_SET_INT16U_LITTLE(addr_dest, addr_src) MEM_VAL_COPY_GET_INT16U_LITTLE(addr_dest, addr_src) +#define MEM_VAL_COPY_SET_INT32U_LITTLE(addr_dest, addr_src) MEM_VAL_COPY_GET_INT32U_LITTLE(addr_dest, addr_src) + + +#define MEM_VAL_COPY_SET_INT08U(addr_dest, addr_src) MEM_VAL_COPY_GET_INT08U(addr_dest, addr_src) +#define MEM_VAL_COPY_SET_INT16U(addr_dest, addr_src) MEM_VAL_COPY_GET_INT16U(addr_dest, addr_src) +#define MEM_VAL_COPY_SET_INT32U(addr_dest, addr_src) MEM_VAL_COPY_GET_INT32U(addr_dest, addr_src) + + +/* +********************************************************************************************************* +* MEM_VAL_COPY_SET_INTU_xxx() +* +* Description : Copy & encode data values from any CPU memory address to any CPU memory address for +* any sized data values. +* +* Argument(s) : addr_dest Lowest CPU memory address to copy/encode source address's data value +* (see Notes #2 & #3). +* +* addr_src Lowest CPU memory address of data value to copy/encode +* (see Notes #2 & #3). +* +* val_size Number of data value octets to copy/encode. +* +* Return(s) : none. +* +* Caller(s) : Application. +* +* Note(s) : (1) Copy/encode data values based on the values' data-word order : +* +* MEM_VAL_COPY_SET_INTU_BIG() Encode big- endian data values -- data words' most +* significant octet @ lowest memory address +* MEM_VAL_COPY_SET_INTU_LITTLE() Encode little-endian data values -- data words' least +* significant octet @ lowest memory address +* MEM_VAL_COPY_SET_INTU() Encode data values using CPU's native or configured +* data-word order +* +* See also 'cpu.h CPU WORD CONFIGURATION Note #2'. +* +* (2) (a) CPU memory addresses/pointers NOT checked for NULL. +* +* (b) CPU memory addresses/buffers NOT checked for overlapping. +* +* (1) IEEE Std 1003.1, 2004 Edition, Section 'memcpy() : DESCRIPTION' states that +* "copying ... between objects that overlap ... is undefined". +* +* (3) MEM_VAL_COPY_SET_INTU_xxx() macro's copy/encode data values without regard to CPU word- +* aligned addresses. Thus for processors that require data word alignment, data words +* can be copied/encoded to/from any CPU address, word-aligned or not, without generating +* data-word-alignment exceptions/faults. +* +* (4) MEM_VAL_COPY_SET_xxx() macro's are more efficient than MEM_VAL_COPY_SET_INTU_xxx() +* macro's & SHOULD be used whenever possible. +* +* See also 'MEM_VAL_COPY_SET_xxx() Note #4'. +* +* (5) Since octet-order copy/conversion are inverse operations, MEM_VAL_COPY_GET_INTU_xxx() & +* MEM_VAL_COPY_SET_INTU_xxx() macros are inverse, but identical, operations & are provided +* in both forms for semantics & consistency. +* +* See also 'MEM_VAL_COPY_GET_INTU_xxx() Note #5'. +* +* (6) MEM_VAL_COPY_SET_INTU_xxx() macro's are NOT atomic operations & MUST NOT be used on any +* non-static (i.e. volatile) variables, registers, hardware, etc.; without the caller of +* the macro's providing some form of additional protection (e.g. mutual exclusion). +********************************************************************************************************* +*/ + + /* See Note #5. */ +#define MEM_VAL_COPY_SET_INTU_BIG(addr_dest, addr_src, val_size) MEM_VAL_COPY_GET_INTU_BIG(addr_dest, addr_src, val_size) +#define MEM_VAL_COPY_SET_INTU_LITTLE(addr_dest, addr_src, val_size) MEM_VAL_COPY_GET_INTU_LITTLE(addr_dest, addr_src, val_size) +#define MEM_VAL_COPY_SET_INTU(addr_dest, addr_src, val_size) MEM_VAL_COPY_GET_INTU(addr_dest, addr_src, val_size) + + +/* +********************************************************************************************************* +* MEM_VAL_COPY_xxx() +* +* Description : Copy data values from any CPU memory address to any CPU memory address. +* +* Argument(s) : addr_dest Lowest CPU memory address to copy source address's data value +* (see Notes #2 & #3). +* +* addr_src Lowest CPU memory address of data value to copy +* (see Notes #2 & #3). +* +* val_size Number of data value octets to copy. +* +* Return(s) : none. +* +* Caller(s) : Application. +* +* Note(s) : (1) MEM_VAL_COPY_xxx() macro's copy data values based on CPU's native data-word order. +* +* See also 'cpu.h CPU WORD CONFIGURATION Note #2'. +* +* (2) (a) CPU memory addresses/pointers NOT checked for NULL. +* +* (b) CPU memory addresses/buffers NOT checked for overlapping. +* +* (1) IEEE Std 1003.1, 2004 Edition, Section 'memcpy() : DESCRIPTION' states that +* "copying ... between objects that overlap ... is undefined". +* +* (3) MEM_VAL_COPY_xxx() macro's copy data values without regard to CPU word-aligned addresses. +* Thus for processors that require data word alignment, data words can be copied to/from any +* CPU address, word-aligned or not, without generating data-word-alignment exceptions/faults. +* +* (4) MEM_VAL_COPY_xxx() macro's are more efficient than MEM_VAL_COPY() macro & SHOULD be +* used whenever possible. +* +* (5) MEM_VAL_COPY_xxx() macro's are NOT atomic operations & MUST NOT be used on any non-static +* (i.e. volatile) variables, registers, hardware, etc.; without the caller of the macro's +* providing some form of additional protection (e.g. mutual exclusion). +* +* (6) MISRA-C 2004 Rule 5.2 states that "identifiers in an inner scope shall not use the same +* name as an indentifier in an outer scope, and therefore hide that identifier". +* +* Therefore, to avoid possible redeclaration of commonly-used loop counter identifier name, +* 'i', MEM_VAL_COPY() loop counter identifier name is prefixed with a single underscore. +********************************************************************************************************* +*/ + +#define MEM_VAL_COPY_08(addr_dest, addr_src) do { (*(((CPU_INT08U *)(addr_dest)) + 0)) = (*(((CPU_INT08U *)(addr_src)) + 0)); } while (0) + +#define MEM_VAL_COPY_16(addr_dest, addr_src) do { (*(((CPU_INT08U *)(addr_dest)) + 0)) = (*(((CPU_INT08U *)(addr_src)) + 0)); \ + (*(((CPU_INT08U *)(addr_dest)) + 1)) = (*(((CPU_INT08U *)(addr_src)) + 1)); } while (0) + +#define MEM_VAL_COPY_32(addr_dest, addr_src) do { (*(((CPU_INT08U *)(addr_dest)) + 0)) = (*(((CPU_INT08U *)(addr_src)) + 0)); \ + (*(((CPU_INT08U *)(addr_dest)) + 1)) = (*(((CPU_INT08U *)(addr_src)) + 1)); \ + (*(((CPU_INT08U *)(addr_dest)) + 2)) = (*(((CPU_INT08U *)(addr_src)) + 2)); \ + (*(((CPU_INT08U *)(addr_dest)) + 3)) = (*(((CPU_INT08U *)(addr_src)) + 3)); } while (0) + + +#define MEM_VAL_COPY(addr_dest, addr_src, val_size) do { \ + CPU_SIZE_T _i; \ + \ + for (_i = 0; _i < (val_size); _i++) { \ + (*(((CPU_INT08U *)(addr_dest)) +_i)) = (*(((CPU_INT08U *)(addr_src)) +_i)); \ + } \ + } while (0) + + +/* +********************************************************************************************************* +* FUNCTION PROTOTYPES +********************************************************************************************************* +*/ + +void Mem_Init ( void); + + /* ------------------ MEM API FNCTS ------------------ */ +void Mem_Clr ( void *pmem, + CPU_SIZE_T size); + +void Mem_Set ( void *pmem, + CPU_INT08U data_val, + CPU_SIZE_T size); + +void Mem_Copy ( void *pdest, + const void *psrc, + CPU_SIZE_T size); + +void Mem_Move ( void *pdest, + const void *psrc, + CPU_SIZE_T size); + +CPU_BOOLEAN Mem_Cmp (const void *p1_mem, + const void *p2_mem, + CPU_SIZE_T size); + + + /* ----------- MEM HEAP FNCTS (DEPRECATED) ------------ */ +#if (LIB_MEM_CFG_HEAP_SIZE > 0u) +void *Mem_HeapAlloc ( CPU_SIZE_T size, + CPU_SIZE_T align, + CPU_SIZE_T *p_bytes_reqd, + LIB_ERR *p_err); + +CPU_SIZE_T Mem_HeapGetSizeRem ( CPU_SIZE_T align, + LIB_ERR *p_err); +#endif + + /* ------------------ MEM SEG FNCTS ------------------- */ +void Mem_SegCreate (const CPU_CHAR *p_name, + MEM_SEG *p_seg, + CPU_ADDR seg_base_addr, + CPU_SIZE_T size, + CPU_SIZE_T padding_align, + LIB_ERR *p_err); + +void Mem_SegClr ( MEM_SEG *p_seg, + LIB_ERR *p_err); + +void *Mem_SegAlloc (const CPU_CHAR *p_name, + MEM_SEG *p_seg, + CPU_SIZE_T size, + LIB_ERR *p_err); + +void *Mem_SegAllocExt (const CPU_CHAR *p_name, + MEM_SEG *p_seg, + CPU_SIZE_T size, + CPU_SIZE_T align, + CPU_SIZE_T *p_bytes_reqd, + LIB_ERR *p_err); + +void *Mem_SegAllocHW (const CPU_CHAR *p_name, + MEM_SEG *p_seg, + CPU_SIZE_T size, + CPU_SIZE_T align, + CPU_SIZE_T *p_bytes_reqd, + LIB_ERR *p_err); + +CPU_SIZE_T Mem_SegRemSizeGet ( MEM_SEG *p_seg, + CPU_SIZE_T align, + MEM_SEG_INFO *p_seg_info, + LIB_ERR *p_err); + +#if (LIB_MEM_CFG_DBG_INFO_EN == DEF_ENABLED) +void Mem_OutputUsage ( void (*out_fnct) (CPU_CHAR *), + LIB_ERR *p_err); +#endif + + /* -------- STATIC MEM POOL FNCTS (DEPRECATED) -------- */ +void Mem_PoolCreate ( MEM_POOL *p_pool, + void *p_mem_base, + CPU_SIZE_T mem_size, + MEM_POOL_BLK_QTY blk_nbr, + CPU_SIZE_T blk_size, + CPU_SIZE_T blk_align, + CPU_SIZE_T *p_bytes_reqd, + LIB_ERR *p_err); + +void Mem_PoolClr ( MEM_POOL *p_pool, + LIB_ERR *p_err); + +void *Mem_PoolBlkGet ( MEM_POOL *p_pool, + CPU_SIZE_T size, + LIB_ERR *p_err); + +void Mem_PoolBlkFree ( MEM_POOL *p_pool, + void *p_blk, + LIB_ERR *p_err); + +MEM_POOL_BLK_QTY Mem_PoolBlkGetNbrAvail ( MEM_POOL *p_pool, + LIB_ERR *p_err); + + /* -------------- DYNAMIC MEM POOL FNCTS -------------- */ +void Mem_DynPoolCreate (const CPU_CHAR *p_name, + MEM_DYN_POOL *p_pool, + MEM_SEG *p_seg, + CPU_SIZE_T blk_size, + CPU_SIZE_T blk_align, + CPU_SIZE_T blk_qty_init, + CPU_SIZE_T blk_qty_max, + LIB_ERR *p_err); + +void Mem_DynPoolCreateHW (const CPU_CHAR *p_name, + MEM_DYN_POOL *p_pool, + MEM_SEG *p_seg, + CPU_SIZE_T blk_size, + CPU_SIZE_T blk_align, + CPU_SIZE_T blk_qty_init, + CPU_SIZE_T blk_qty_max, + LIB_ERR *p_err); + +void *Mem_DynPoolBlkGet ( MEM_DYN_POOL *p_pool, + LIB_ERR *p_err); + +void Mem_DynPoolBlkFree ( MEM_DYN_POOL *p_pool, + void *p_blk, + LIB_ERR *p_err); + +CPU_SIZE_T Mem_DynPoolBlkNbrAvailGet( MEM_DYN_POOL *p_pool, + LIB_ERR *p_err); + + +/* +********************************************************************************************************* +* CONFIGURATION ERRORS +********************************************************************************************************* +*/ + +#ifndef LIB_MEM_CFG_ARG_CHK_EXT_EN +#error "LIB_MEM_CFG_ARG_CHK_EXT_EN not #define'd in 'lib_cfg.h'" +#error " [MUST be DEF_DISABLED] " +#error " [ || DEF_ENABLED ] " + +#elif ((LIB_MEM_CFG_ARG_CHK_EXT_EN != DEF_DISABLED) && \ + (LIB_MEM_CFG_ARG_CHK_EXT_EN != DEF_ENABLED )) +#error "LIB_MEM_CFG_ARG_CHK_EXT_EN illegally #define'd in 'lib_cfg.h'" +#error " [MUST be DEF_DISABLED] " +#error " [ || DEF_ENABLED ] " +#endif + + + +#ifndef LIB_MEM_CFG_OPTIMIZE_ASM_EN +#error "LIB_MEM_CFG_OPTIMIZE_ASM_EN not #define'd in 'lib_cfg.h'" +#error " [MUST be DEF_DISABLED] " +#error " [ || DEF_ENABLED ] " + +#elif ((LIB_MEM_CFG_OPTIMIZE_ASM_EN != DEF_DISABLED) && \ + (LIB_MEM_CFG_OPTIMIZE_ASM_EN != DEF_ENABLED )) +#error "LIB_MEM_CFG_OPTIMIZE_ASM_EN illegally #define'd in 'lib_cfg.h'" +#error " [MUST be DEF_DISABLED] " +#error " [ || DEF_ENABLED ] " +#endif + + +#ifndef LIB_MEM_CFG_HEAP_SIZE +#error "LIB_MEM_CFG_HEAP_SIZE not #define'd in 'lib_cfg.h'" +#error " [MUST be >= 0] " +#endif + + +#ifdef LIB_MEM_CFG_HEAP_BASE_ADDR +#if (LIB_MEM_CFG_HEAP_BASE_ADDR == 0x0) +#error "LIB_MEM_CFG_HEAP_BASE_ADDR illegally #define'd in 'lib_cfg.h'" +#error " [MUST be > 0x0] " +#endif +#endif + + +#if ((LIB_MEM_CFG_DBG_INFO_EN != DEF_DISABLED) && \ + (LIB_MEM_CFG_DBG_INFO_EN != DEF_ENABLED )) +#error "LIB_MEM_CFG_DBG_INFO_EN illegally defined in 'lib_cfg.h'" +#error " [MUST be DEF_DISABLED] " +#error " [ || DEF_ENABLED ] " + +#elif ((LIB_MEM_CFG_HEAP_SIZE == 0u) && \ + (LIB_MEM_CFG_DBG_INFO_EN == DEF_ENABLED)) +#error "LIB_MEM_CFG_HEAP_SIZE illegally defined in 'lib_cfg.h' " +#error " [MUST be > 0 when LIB_MEM_CFG_DBG_INFO_EN == DEF_ENABLED]" +#endif + + +/* +********************************************************************************************************* +* LIBRARY CONFIGURATION ERRORS +********************************************************************************************************* +*/ + + /* See 'lib_mem.h Note #2a'. */ +#if (CPU_CORE_VERSION < 127u) +#error "CPU_CORE_VERSION [SHOULD be >= V1.27]" +#endif + + +/* +********************************************************************************************************* +* MODULE END +* +* Note(s) : (1) See 'lib_mem.h MODULE'. +********************************************************************************************************* +*/ + +#endif /* End of lib mem module include. */ + diff --git a/Middlewares/Third_Party/Micrium/uC-LIB/lib_str.c b/Middlewares/Third_Party/Micrium/uC-LIB/lib_str.c new file mode 100644 index 0000000..65f0465 --- /dev/null +++ b/Middlewares/Third_Party/Micrium/uC-LIB/lib_str.c @@ -0,0 +1,4041 @@ +/* +********************************************************************************************************* +* uC/LIB +* CUSTOM LIBRARY MODULES +* +* (c) Copyright 2004-2014; Micrium, Inc.; Weston, FL +* +* All rights reserved. Protected by international copyright laws. +* +* uC/LIB is provided in source form to registered licensees ONLY. It is +* illegal to distribute this source code to any third party unless you receive +* written permission by an authorized Micrium representative. Knowledge of +* the source code may NOT be used to develop a similar product. +* +* Please help us continue to provide the Embedded community with the finest +* software available. Your honesty is greatly appreciated. +* +* You can find our product's user manual, API reference, release notes and +* more information at: https://doc.micrium.com +* +* You can contact us at: http://www.micrium.com +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* +* ASCII STRING MANAGEMENT +* +* Filename : lib_str.c +* Version : V1.38.01 +* Programmer(s) : ITJ +* BAN +* JDH +********************************************************************************************************* +* Note(s) : (1) NO compiler-supplied standard library functions are used in library or product software. +* +* (a) ALL standard library functions are implemented in the custom library modules : +* +* (1) \\lib_*.* +* +* (2) \\Ports\\\lib*_a.* +* +* where +* directory path for custom library software +* directory name for specific processor (CPU) +* directory name for specific compiler +* +* (b) Product-specific library functions are implemented in individual products. +* +********************************************************************************************************* +* Notice(s) : (1) The Institute of Electrical and Electronics Engineers and The Open Group, have given +* us permission to reprint portions of their documentation. Portions of this text are +* reprinted and reproduced in electronic form from the IEEE Std 1003.1, 2004 Edition, +* Standard for Information Technology -- Portable Operating System Interface (POSIX), +* The Open Group Base Specifications Issue 6, Copyright (C) 2001-2004 by the Institute +* of Electrical and Electronics Engineers, Inc and The Open Group. In the event of any +* discrepancy between these versions and the original IEEE and The Open Group Standard, +* the original IEEE and The Open Group Standard is the referee document. The original +* Standard can be obtained online at http://www.opengroup.org/unix/online.html. +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* INCLUDE FILES +********************************************************************************************************* +*/ + +#define MICRIUM_SOURCE +#define LIB_STR_MODULE +#include + + +/* +********************************************************************************************************* +* LOCAL DEFINES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL CONSTANTS +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL DATA TYPES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL TABLES +********************************************************************************************************* +*/ + +static const CPU_INT32U Str_MultOvfThTbl_Int32U[] = { + (CPU_INT32U) DEF_INT_32U_MAX_VAL, /* Invalid base 0. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 1u), /* Invalid base 1. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 2u), /* 32-bit mult ovf th for base 2. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 3u), /* 32-bit mult ovf th for base 3. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 4u), /* 32-bit mult ovf th for base 4. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 5u), /* 32-bit mult ovf th for base 5. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 6u), /* 32-bit mult ovf th for base 6. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 7u), /* 32-bit mult ovf th for base 7. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 8u), /* 32-bit mult ovf th for base 8. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 9u), /* 32-bit mult ovf th for base 9. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 10u), /* 32-bit mult ovf th for base 10. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 11u), /* 32-bit mult ovf th for base 11. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 12u), /* 32-bit mult ovf th for base 12. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 13u), /* 32-bit mult ovf th for base 13. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 14u), /* 32-bit mult ovf th for base 14. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 15u), /* 32-bit mult ovf th for base 15. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 16u), /* 32-bit mult ovf th for base 16. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 17u), /* 32-bit mult ovf th for base 17. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 18u), /* 32-bit mult ovf th for base 18. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 19u), /* 32-bit mult ovf th for base 19. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 20u), /* 32-bit mult ovf th for base 20. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 21u), /* 32-bit mult ovf th for base 21. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 22u), /* 32-bit mult ovf th for base 22. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 23u), /* 32-bit mult ovf th for base 23. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 24u), /* 32-bit mult ovf th for base 24. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 25u), /* 32-bit mult ovf th for base 25. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 26u), /* 32-bit mult ovf th for base 26. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 27u), /* 32-bit mult ovf th for base 27. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 28u), /* 32-bit mult ovf th for base 28. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 29u), /* 32-bit mult ovf th for base 29. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 30u), /* 32-bit mult ovf th for base 30. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 31u), /* 32-bit mult ovf th for base 31. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 32u), /* 32-bit mult ovf th for base 32. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 33u), /* 32-bit mult ovf th for base 33. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 34u), /* 32-bit mult ovf th for base 34. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 35u), /* 32-bit mult ovf th for base 35. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 36u) /* 32-bit mult ovf th for base 36. */ +}; + + +/* +********************************************************************************************************* +* LOCAL GLOBAL VARIABLES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL FUNCTION PROTOTYPES +********************************************************************************************************* +*/ + +static CPU_CHAR *Str_FmtNbr_Int32 ( CPU_INT32U nbr, + CPU_INT08U nbr_dig, + CPU_INT08U nbr_base, + CPU_BOOLEAN nbr_neg, + CPU_CHAR lead_char, + CPU_BOOLEAN lower_case, + CPU_BOOLEAN nul, + CPU_CHAR *pstr); + +static CPU_INT32U Str_ParseNbr_Int32(const CPU_CHAR *pstr, + CPU_CHAR **pstr_next, + CPU_INT08U nbr_base, + CPU_BOOLEAN nbr_signed, + CPU_BOOLEAN *pnbr_neg); + + +/* +********************************************************************************************************* +* LOCAL CONFIGURATION ERRORS +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* Str_Len() +* +* Description : Calculate length of a string. +* +* Argument(s) : pstr Pointer to string (see Note #1). +* +* Return(s) : Length of string; number of characters in string before terminating NULL character +* (see Note #2b1). +* +* Caller(s) : Application. +* +* Note(s) : (1) String buffer NOT modified. +* +* (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strlen() : DESCRIPTION' states that : +* +* (1) "The strlen() function shall compute the number of bytes in the string to +* which 's' ('pstr') points," ... +* (2) "not including the terminating null byte." +* +* (b) IEEE Std 1003.1, 2004 Edition, Section 'strlen() : RETURN VALUE' states that : +* +* (1) "The strlen() function shall return the length of 's' ('pstr');" ... +* (2) "no return value shall be reserved to indicate an error." +* +* (3) String length calculation terminates when : +* +* (a) String pointer points to NULL. +* (1) String buffer overlaps with NULL address. +* (2) String length calculated for string up to but NOT beyond or including +* the NULL address. +* +* (b) Terminating NULL character found. +* (1) String length calculated for string up to but NOT including +* the NULL character (see Note #2a2). +********************************************************************************************************* +*/ + +CPU_SIZE_T Str_Len (const CPU_CHAR *pstr) +{ + CPU_SIZE_T len; + + + len = Str_Len_N(pstr, + DEF_INT_CPU_U_MAX_VAL); + + return (len); +} + + +/* +********************************************************************************************************* +* Str_Len_N() +* +* Description : Calculate length of a string, up to a maximum number of characters. +* +* Argument(s) : pstr Pointer to string (see Note #1). +* +* len_max Maximum number of characters to search (see Note #3c). +* +* Return(s) : Length of string; number of characters in string before terminating NULL character, +* if terminating NULL character found (see Note #2b1). +* +* Requested maximum number of characters to search, +* if terminating NULL character NOT found (see Note #3c). +* +* Caller(s) : Application. +* +* Note(s) : (1) String buffer NOT modified. +* +* (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strlen() : DESCRIPTION' states that : +* +* (1) "The strlen() function shall compute the number of bytes in the string to +* which 's' ('pstr') points," ... +* (2) "not including the terminating null byte." +* +* (b) IEEE Std 1003.1, 2004 Edition, Section 'strlen() : RETURN VALUE' states that : +* +* (1) "The strlen() function shall return the length of 's' ('pstr');" ... +* (2) "no return value shall be reserved to indicate an error." +* +* (3) String length calculation terminates when : +* +* (a) String pointer points to NULL. +* (1) String buffer overlaps with NULL address. +* (2) String length calculated for string up to but NOT beyond or including +* the NULL address. +* +* (b) Terminating NULL character found. +* (1) String length calculated for string up to but NOT including +* the NULL character (see Note #2a2). +* +* (c) 'len_max' number of characters searched. +* (1) 'len_max' number of characters does NOT include the terminating NULL character. +********************************************************************************************************* +*/ + +CPU_SIZE_T Str_Len_N (const CPU_CHAR *pstr, + CPU_SIZE_T len_max) +{ + const CPU_CHAR *pstr_len; + CPU_SIZE_T len; + + + pstr_len = pstr; + len = 0u; + while (( pstr_len != (const CPU_CHAR *) 0 ) && /* Calc str len until NULL ptr (see Note #3a) ... */ + (*pstr_len != ( CPU_CHAR )'\0') && /* ... or NULL char found (see Note #3b) ... */ + ( len < ( CPU_SIZE_T)len_max)) { /* ... or max nbr chars srch'd (see Note #3c). */ + pstr_len++; + len++; + } + + return (len); /* Rtn str len (see Note #3b1). */ +} + + +/* +********************************************************************************************************* +* Str_Copy() +* +* Description : Copy source string to destination string buffer. +* +* Argument(s) : pstr_dest Pointer to destination string buffer to receive source string copy (see Note #1a). +* +* pstr_src Pointer to source string to copy into destination string buffer (see Note #1b). +* +* Return(s) : Pointer to destination string, if NO error(s) [see Note #2b1]. +* +* Pointer to NULL, otherwise (see Note #2b2A). +* +* Caller(s) : Application. +* +* Note(s) : (1) (a) Destination buffer size NOT validated; buffer overruns MUST be prevented by caller. +* +* (1) Destination buffer size MUST be large enough to accommodate the entire source +* string size including the terminating NULL character. +* +* (b) Source buffer NOT modified. +* +* (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strcpy() : DESCRIPTION' states that : +* +* (1) "The strcpy() function shall copy the string pointed to by 's2' ('pstr_src') +* ... into the array pointed to by 's1' ('pstr_dest')" ... +* (2) "(including the terminating null byte)." +* +* (b) IEEE Std 1003.1, 2004 Edition, Section 'strcpy() : RETURN VALUE' states that : +* +* (1) "The strcpy() function shall return 's1' ('pstr_dest');" ... +* (2) "no return value is reserved to indicate an error." +* (A) #### This requirement is intentionally NOT implemented in order to return +* NULL for any error(s). +* +* (c) IEEE Std 1003.1, 2004 Edition, Section 'strcpy() : DESCRIPTION' states that "if +* copying takes place between objects that overlap, the behavior is undefined". +* +* (3) String copy terminates when : +* +* (a) Destination/Source string pointer(s) are passed NULL pointers. +* (1) No string copy performed; NULL pointer returned. +* +* (b) Destination/Source string pointer(s) point to NULL. +* (1) String buffer(s) overlap with NULL address; NULL pointer returned. +* +* (c) Source string's terminating NULL character found. +* (1) Entire source string copied into destination string buffer (see Note #2a). +********************************************************************************************************* +*/ + +CPU_CHAR *Str_Copy ( CPU_CHAR *pstr_dest, + const CPU_CHAR *pstr_src) +{ + CPU_CHAR *pstr_rtn; + + + pstr_rtn = Str_Copy_N(pstr_dest, + pstr_src, + DEF_INT_CPU_U_MAX_VAL); + + return (pstr_rtn); +} + + +/* +********************************************************************************************************* +* Str_Copy_N() +* +* Description : Copy source string to destination string buffer, up to a maximum number of characters. +* +* Argument(s) : pstr_dest Pointer to destination string buffer to receive source string copy (see Note #1a). +* +* pstr_src Pointer to source string to copy into destination string buffer (see Note #1b). +* +* len_max Maximum number of characters to copy (see Notes #2a2 & #3d). +* +* Return(s) : Pointer to destination string, if NO error(s) [see Note #2b1]. +* +* Pointer to NULL, otherwise (see Note #2b2A). +* +* Caller(s) : Application. +* +* Note(s) : (1) (a) Destination buffer size NOT validated; buffer overruns MUST be prevented by caller. +* +* (1) Destination buffer size MUST be large enough to accommodate the entire source +* string size including the terminating NULL character. +* +* (b) Source string buffer NOT modified. +* +* (2) (a) (1) IEEE Std 1003.1, 2004 Edition, Section 'strncpy() : DESCRIPTION' states that : +* +* (A) "The strncpy() function shall copy ... the array pointed to by 's2' +* ('pstr_src') to the array pointed to by 's1' ('pstr_dest')"; ... +* (B) but "not more than 'n' ('len_max') bytes" ... +* (C) & "(bytes that follow a null byte are not copied)". +* +* (2) (A) IEEE Std 1003.1, 2004 Edition, Section 'strncpy() : DESCRIPTION' adds that +* "if the array pointed to by 's2' ('pstr_src') is a string that is shorter +* than 'n' ('len_max') bytes, null bytes shall be appended to the copy in +* the array pointed to by 's1' ('pstr_dest'), until 'n' ('len_max') bytes +* in all are written." +* +* (1) #### Since Str_Copy() limits the maximum number of characters to copy +* via Str_Copy_N() by the CPU's maximum number of addressable characters, +* this requirement is intentionally NOT implemented to avoid appending +* a potentially large number of unnecessary terminating NULL characters. +* +* (B) IEEE Std 1003.1, 2004 Edition, Section 'strncpy() : APPLICATION USAGE' also +* states that "if there is no null byte in the first 'n' ('len_max') bytes of +* the array pointed to by 's2' ('pstr_src'), the result is not null-terminated". +* +* (b) IEEE Std 1003.1, 2004 Edition, Section 'strncpy() : RETURN VALUE' states that : +* +* (1) "The strncpy() function shall return 's1' ('pstr_dest');" ... +* (2) "no return value is reserved to indicate an error." +* (A) #### This requirement is intentionally ignored in order to return NULL +* for any error(s). +* +* (c) IEEE Std 1003.1, 2004 Edition, Section 'strncpy() : DESCRIPTION' states that "if +* copying takes place between objects that overlap, the behavior is undefined". +* +* (3) String copy terminates when : +* +* (a) Destination/Source string pointer(s) are passed NULL pointers. +* (1) No string copy performed; NULL pointer returned. +* +* (b) Destination/Source string pointer(s) point to NULL. +* (1) String buffer(s) overlap with NULL address; NULL pointer returned. +* +* (c) Source string's terminating NULL character found. +* (1) Entire source string copied into destination string buffer (see Note #2a1A). +* +* (d) 'len_max' number of characters copied. +* (1) 'len_max' number of characters MAY include the terminating NULL character +* (see Note #2a1C). +* (2) Null copies allowed (i.e. zero-length copies). +* (A) No string copy performed; destination string returned (see Note #2b1). +********************************************************************************************************* +*/ + +CPU_CHAR *Str_Copy_N ( CPU_CHAR *pstr_dest, + const CPU_CHAR *pstr_src, + CPU_SIZE_T len_max) +{ + CPU_CHAR *pstr_copy_dest; + const CPU_CHAR *pstr_copy_src; + CPU_SIZE_T len_copy; + + /* Rtn NULL if str ptr(s) NULL (see Note #3a1). */ + if (pstr_dest == (CPU_CHAR *)0) { + return ((CPU_CHAR *)0); + } + if (pstr_src == (const CPU_CHAR *)0) { + return ((CPU_CHAR *)0); + } + + + pstr_copy_dest = pstr_dest; + pstr_copy_src = pstr_src; + len_copy = 0u; + + while (( pstr_copy_dest != ( CPU_CHAR *) 0 ) && /* Copy str until NULL ptr(s) [see Note #3b] ... */ + ( pstr_copy_src != (const CPU_CHAR *) 0 ) && + (*pstr_copy_src != ( CPU_CHAR )'\0') && /* ... or NULL char found (see Note #3c); ... */ + ( len_copy < ( CPU_SIZE_T)len_max)) { /* ... or max nbr chars copied (see Note #3d). */ + *pstr_copy_dest = *pstr_copy_src; + pstr_copy_dest++; + pstr_copy_src++; + len_copy++; + } + /* Rtn NULL if NULL ptr(s) found (see Note #3b1). */ + if ((pstr_copy_dest == ( CPU_CHAR *)0) || + (pstr_copy_src == (const CPU_CHAR *)0)) { + return ((CPU_CHAR *)0); + } + + if (len_copy < len_max) { /* If copy str len < max buf len (see Note #2a2A), ... */ + *pstr_copy_dest = (CPU_CHAR)'\0'; /* ... copy NULL char (see Note #3c1). */ + } + + + return (pstr_dest); /* Rtn ptr to dest str (see Note #2b1). */ +} + + +/* +********************************************************************************************************* +* Str_Cat() +* +* Description : Append concatenation string to destination string. +* +* Argument(s) : pstr_dest Pointer to destination string to append concatenation string (see Note #1a). +* +* pstr_cat Pointer to concatenation string to append to destination string (see Note #1b). +* +* Return(s) : Pointer to destination string, if NO error(s) [see Note #2b1]. +* +* Pointer to NULL, otherwise (see Note #2b2A). +* +* Caller(s) : Application. +* +* Note(s) : (1) (a) Destination buffer size NOT validated; buffer overruns MUST be prevented by caller. +* +* (1) Destination buffer size MUST be large enough to accommodate the entire +* concatenated string size including the terminating NULL character. +* +* (b) Concatenation string buffer NOT modified. +* +* (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strcat() : DESCRIPTION' states that : +* +* (1) "The strcat() function shall append a copy of the string pointed to by 's2' +* ('pstr_cat') ... to the end of the string pointed to by 's1' ('pstr_dest')." +* +* (2) (A) "The initial byte of 's2' ('pstr_cat') overwrites the null byte at the +* end of 's1' ('pstr_dest')." +* (B) A "terminating null byte" is appended at the end of the concatenated +* destination strings. +* +* (b) IEEE Std 1003.1, 2004 Edition, Section 'strcat() : RETURN VALUE' states that : +* +* (1) "The strcat() function shall return 's1' ('pstr_dest');" ... +* (2) "no return value shall be reserved to indicate an error." +* (A) #### This requirement is intentionally NOT implemented in order to return +* NULL for any error(s). +* +* (c) IEEE Std 1003.1, 2004 Edition, Section 'strcat() : DESCRIPTION' states that "if +* copying takes place between objects that overlap, the behavior is undefined." +* +* (3) String concatenation terminates when : +* +* (a) Destination/Concatenation string pointer(s) are passed NULL pointers. +* (1) No string concatenation performed; NULL pointer returned. +* +* (b) Destination/Concatenation string pointer(s) point to NULL. +* (1) String buffer(s) overlap with NULL address; NULL pointer returned. +* +* (c) Concatenation string's terminating NULL character found. +* (1) Entire concatenation string appended to destination string (see Note #2a1). +********************************************************************************************************* +*/ + +CPU_CHAR *Str_Cat ( CPU_CHAR *pstr_dest, + const CPU_CHAR *pstr_cat) +{ + CPU_CHAR *pstr_rtn; + + + pstr_rtn = Str_Cat_N(pstr_dest, + pstr_cat, + DEF_INT_CPU_U_MAX_VAL); + + return (pstr_rtn); +} + + +/* +********************************************************************************************************* +* Str_Cat_N() +* +* Description : Append concatenation string to destination string, up to a maximum number of characters. +* +* Argument(s) : pstr_dest Pointer to destination string to append concatenation string (see Note #1a). +* +* pstr_cat Pointer to concatenation string to append to destination string (see Note #1b). +* +* len_max Maximum number of characters to concatenate (see Notes #2a1B & #3d). +* +* Return(s) : Pointer to destination string, if NO error(s) [see Note #2b1]. +* +* Pointer to NULL, otherwise (see Note #2b2A). +* +* Caller(s) : Application. +* +* Note(s) : (1) (a) Destination buffer size NOT validated; buffer overruns MUST be prevented by caller. +* +* (1) Destination buffer size MUST be large enough to accommodate the entire +* concatenated string size including the terminating NULL character. +* +* (b) Concatenation string buffer NOT modified. +* +* (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strncat() : DESCRIPTION' states that : +* +* (1) (A) "The strncat() function shall append ... the array pointed to by 's2' +* ('pstr_cat') to the end of the string pointed to by 's1' ('pstr_dest')" ... +* (B) but "not more than 'n' ('len_max') bytes". +* +* (2) (A) "The initial byte of 's2' ('pstr_cat') overwrites the null byte at the +* end of 's1' ('pstr_dest')." +* (B) "(a null byte and bytes that follow it are not appended)." +* (C) "A terminating null byte is always appended to the result." +* +* (b) IEEE Std 1003.1, 2004 Edition, Section 'strncat() : RETURN VALUE' states that : +* +* (1) "The strncat() function shall return 's1' ('pstr_dest');" ... +* (2) "no return value shall be reserved to indicate an error." +* (A) #### This requirement is intentionally NOT implemented in order to return +* NULL for any error(s). +* +* (c) IEEE Std 1003.1, 2004 Edition, Section 'strncat() : DESCRIPTION' states that "if +* copying takes place between objects that overlap, the behavior is undefined." +* +* (3) String concatenation terminates when : +* +* (a) Destination/Concatenation string pointer(s) are passed NULL pointers. +* (1) No string concatenation performed; NULL pointer returned. +* +* (b) Destination/Concatenation string pointer(s) point to NULL. +* (1) String buffer(s) overlap with NULL address; NULL pointer returned. +* +* (c) Concatenation string's terminating NULL character found. +* (1) Entire concatenation string appended to destination string (see Note #2a1A). +* +* (d) 'len_max' number of characters concatenated. +* +* (1) 'len_max' number of characters does NOT include the terminating NULL character +* (see Note #2a2). +* +* (2) Null concatenations allowed (i.e. zero-length concatenations). +* (A) No string concatenation performed; destination string returned +* (see Note #2b1). +********************************************************************************************************* +*/ + +CPU_CHAR *Str_Cat_N ( CPU_CHAR *pstr_dest, + const CPU_CHAR *pstr_cat, + CPU_SIZE_T len_max) +{ + CPU_CHAR *pstr_cat_dest; + const CPU_CHAR *pstr_cat_src; + CPU_SIZE_T len_cat; + + /* Rtn NULL if str ptr(s) NULL (see Note #3a1). */ + if (pstr_dest == (CPU_CHAR *)0) { + return ((CPU_CHAR *)0); + } + if (pstr_cat == (const CPU_CHAR *)0) { + return ((CPU_CHAR *)0); + } + + if (len_max < 1) { /* Rtn dest str if cat len = 0 (see Note #3d2A). */ + return ((CPU_CHAR *)pstr_dest); + } + + + pstr_cat_dest = pstr_dest; + while (( pstr_cat_dest != (CPU_CHAR *) 0 ) && /* Adv to end of cur dest str until NULL ptr ... */ + (*pstr_cat_dest != (CPU_CHAR )'\0')) { /* ... or NULL char found.. */ + pstr_cat_dest++; + } + if (pstr_cat_dest == (CPU_CHAR *)0) { /* Rtn NULL if NULL ptr found (see Note #3b1). */ + return ((CPU_CHAR *)0); + } + + pstr_cat_src = pstr_cat; + len_cat = 0u; + + while (( pstr_cat_dest != ( CPU_CHAR *) 0 ) && /* Cat str until NULL ptr(s) [see Note #3b] ... */ + ( pstr_cat_src != (const CPU_CHAR *) 0 ) && + (*pstr_cat_src != ( CPU_CHAR )'\0') && /* ... or NULL char found (see Note #3c); ... */ + ( len_cat < ( CPU_SIZE_T)len_max)) { /* ... or max nbr chars cat'd (see Note #3d). */ + *pstr_cat_dest = *pstr_cat_src; + pstr_cat_dest++; + pstr_cat_src++; + len_cat++; + } + /* Rtn NULL if NULL ptr(s) found (see Note #3b1). */ + if ((pstr_cat_dest == ( CPU_CHAR *)0) || + (pstr_cat_src == (const CPU_CHAR *)0)) { + return ((CPU_CHAR *)0); + } + + *pstr_cat_dest = (CPU_CHAR)'\0'; /* Append NULL char (see Note #2a2C). */ + + + return (pstr_dest); /* Rtn ptr to dest str (see Note #2b1). */ +} + + +/* +********************************************************************************************************* +* Str_Cmp() +* +* Description : Determine if two strings are identical. +* +* Argument(s) : p1_str Pointer to first string (see Note #1). +* +* p2_str Pointer to second string (see Note #1). +* +* Return(s) : 0, if strings are identical (see Notes #3a1A, #3a2A, & #3b). +* +* Negative value, if 'p1_str' is less than 'p2_str' (see Notes #3a1B1, #3a2B1, & #3c). +* +* Positive value, if 'p1_str' is greater than 'p2_str' (see Notes #3a1B2, #3a2B2, & #3c). +* +* See also Note #2b. +* +* Caller(s) : Application. +* +* Note(s) : (1) String buffers NOT modified. +* +* (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strcmp() : DESCRIPTION' states that "the +* strcmp() function shall compare the string pointed to by 's1' ('p1_str') to the +* string pointed to by 's2' ('p2_str)". +* +* (b) (1) IEEE Std 1003.1, 2004 Edition, Section 'strcmp() : RETURN VALUE' states that +* "upon successful completion, strcmp() shall return an integer greater than, +* equal to, or less than 0". +* +* (2) IEEE Std 1003.1, 2004 Edition, Section 'strcmp() : DESCRIPTION' adds that "the +* sign of a non-zero return value shall be determined by the sign of the difference +* between the values of the first pair of bytes ... that differ in the strings +* being compared". +* +* (3) String comparison terminates when : +* +* (a) (1) (A) BOTH string pointer(s) are passed NULL pointers. +* (1) NULL strings identical; 0 returned. +* +* (B) (1) 'p1_str' passed a NULL pointer. +* (a) Return negative value of character pointed to by 'p2_str'. +* +* (2) 'p2_str' passed a NULL pointer. +* (a) Return positive value of character pointed to by 'p1_str'. +* +* (2) (A) BOTH strings point to NULL. +* (1) Strings overlap with NULL address. +* (2) Strings identical up to but NOT beyond or including the NULL address; +* 0 returned. +* +* (B) (1) 'p1_str_cmp_next' points to NULL. +* (a) 'p1_str' overlaps with NULL address. +* (b) Strings compared up to but NOT beyond or including the NULL address. +* (c) Return negative value of character pointed to by 'p2_str_cmp_next'. +* +* (2) 'p2_str_cmp_next' points to NULL. +* (a) 'p2_str' overlaps with NULL address. +* (b) Strings compared up to but NOT beyond or including the NULL address. +* (c) Return positive value of character pointed to by 'p1_str_cmp_next'. +* +* (b) Terminating NULL character found in both strings. +* (1) Strings identical; 0 returned. +* (2) Only one NULL character test required in conditional since previous condition +* tested character equality. +* +* (c) Non-matching characters found. +* (1) Return signed-integer difference of the character pointed to by 'p2_str' +* from the character pointed to by 'p1_str'. +* +* (4) Since 16-bit signed arithmetic is performed to calculate a non-identical comparison +* return value, 'CPU_CHAR' native data type size MUST be 8-bit. +********************************************************************************************************* +*/ + +CPU_INT16S Str_Cmp (const CPU_CHAR *p1_str, + const CPU_CHAR *p2_str) +{ + CPU_INT16S cmp_val; + + + cmp_val = Str_Cmp_N(p1_str, + p2_str, + DEF_INT_CPU_U_MAX_VAL); + + return (cmp_val); +} + + +/* +********************************************************************************************************* +* Str_Cmp_N() +* +* Description : Determine if two strings are identical for up to a maximum number of characters. +* +* Argument(s) : p1_str Pointer to first string (see Note #1). +* +* p2_str Pointer to second string (see Note #1). +* +* len_max Maximum number of characters to compare (see Note #3d). +* +* Return(s) : 0, if strings are identical (see Notes #3a1A, #3a2A, #3b, & #3d). +* +* Negative value, if 'p1_str' is less than 'p2_str' (see Notes #3a1B1, #3a2B1, & #3c). +* +* Positive value, if 'p1_str' is greater than 'p2_str' (see Notes #3a1B2, #3a2B2, & #3c). +* +* See also Note #2b. +* +* Caller(s) : Application. +* +* Note(s) : (1) String buffers NOT modified. +* +* (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strncmp() : DESCRIPTION' states that : +* +* (1) "The strncmp() function shall compare ... the array pointed to by 's1' ('p1_str') +* to the array pointed to by 's2' ('p2_str)" ... +* (2) but "not more than 'n' ('len_max') bytes" of either array. +* +* (b) (1) IEEE Std 1003.1, 2004 Edition, Section 'strncmp() : RETURN VALUE' states that +* "upon successful completion, strncmp() shall return an integer greater than, +* equal to, or less than 0". +* +* (2) IEEE Std 1003.1, 2004 Edition, Section 'strncmp() : DESCRIPTION' adds that +* "the sign of a non-zero return value is determined by the sign of the difference +* between the values of the first pair of bytes ... that differ in the strings +* being compared". +* +* (3) String comparison terminates when : +* +* (a) (1) (A) BOTH string pointer(s) are passed NULL pointers. +* (1) NULL strings identical; 0 returned. +* +* (B) (1) 'p1_str' passed a NULL pointer. +* (a) Return negative value of character pointed to by 'p2_str'. +* +* (2) 'p2_str' passed a NULL pointer. +* (a) Return positive value of character pointed to by 'p1_str'. +* +* (2) (A) BOTH strings point to NULL. +* (1) Strings overlap with NULL address. +* (2) Strings identical up to but NOT beyond or including the NULL address; +* 0 returned. +* +* (B) (1) 'p1_str_cmp_next' points to NULL. +* (a) 'p1_str' overlaps with NULL address. +* (b) Strings compared up to but NOT beyond or including the NULL address. +* (c) Return negative value of character pointed to by 'p2_str_cmp_next'. +* +* (2) 'p2_str_cmp_next' points to NULL. +* (a) 'p2_str' overlaps with NULL address. +* (b) Strings compared up to but NOT beyond or including the NULL address. +* (c) Return positive value of character pointed to by 'p1_str_cmp_next'. +* +* (b) Terminating NULL character found in both strings. +* (1) Strings identical; 0 returned. +* (2) Only one NULL character test required in conditional since previous condition +* tested character equality. +* +* (c) Non-matching characters found. +* (1) Return signed-integer difference of the character pointed to by 'p2_str' +* from the character pointed to by 'p1_str'. +* +* (d) (1) 'len_max' passed a zero length. +* (A) Zero-length strings identical; 0 returned. +* +* (2) First 'len_max' number of characters identical. +* (A) Strings identical; 0 returned. +* +* See also Note #2a2. +* +* (4) Since 16-bit signed arithmetic is performed to calculate a non-identical comparison +* return value, 'CPU_CHAR' native data type size MUST be 8-bit. +********************************************************************************************************* +*/ + +CPU_INT16S Str_Cmp_N (const CPU_CHAR *p1_str, + const CPU_CHAR *p2_str, + CPU_SIZE_T len_max) +{ + const CPU_CHAR *p1_str_cmp; + const CPU_CHAR *p2_str_cmp; + const CPU_CHAR *p1_str_cmp_next; + const CPU_CHAR *p2_str_cmp_next; + CPU_INT16S cmp_val; + CPU_SIZE_T cmp_len; + + + if (len_max < 1) { /* If cmp len = 0, rtn 0 (see Note #3d1A). */ + return (0); + } + + if (p1_str == (const CPU_CHAR *)0) { + if (p2_str == (const CPU_CHAR *)0) { + return (0); /* If BOTH str ptrs NULL, rtn 0 (see Note #3a1A). */ + } + cmp_val = (CPU_INT16S)((CPU_INT16S)0 - (CPU_INT16S)(*p2_str)); + return (cmp_val); /* If p1_str NULL, rtn neg p2_str val (see Note #3a1B1).*/ + } + if (p2_str == (const CPU_CHAR *)0) { + cmp_val = (CPU_INT16S)(*p1_str); + return (cmp_val); /* If p2_str NULL, rtn pos p1_str val (see Note #3a1B2).*/ + } + + + p1_str_cmp = p1_str; + p2_str_cmp = p2_str; + p1_str_cmp_next = p1_str_cmp; + p2_str_cmp_next = p2_str_cmp; + p1_str_cmp_next++; + p2_str_cmp_next++; + cmp_len = 0u; + + while ((*p1_str_cmp == *p2_str_cmp) && /* Cmp strs until non-matching chars (see Note #3c) ... */ + (*p1_str_cmp != ( CPU_CHAR )'\0') && /* ... or NULL chars (see Note #3b) ... */ + ( p1_str_cmp_next != (const CPU_CHAR *) 0 ) && /* ... or NULL ptr(s) found (see Note #3a2). */ + ( p2_str_cmp_next != (const CPU_CHAR *) 0 ) && + ( cmp_len < ( CPU_SIZE_T)len_max)) { /* ... or max nbr chars cmp'd (see Note #3d2). */ + p1_str_cmp++; + p2_str_cmp++; + p1_str_cmp_next++; + p2_str_cmp_next++; + cmp_len++; + } + + + if (cmp_len == len_max) { /* If strs identical for max len nbr of chars, ... */ + return (0); /* ... rtn 0 (see Note #3d2A). */ + } + + if (*p1_str_cmp != *p2_str_cmp) { /* If strs NOT identical, ... */ + /* ... calc & rtn char diff (see Note #3c1). */ + cmp_val = (CPU_INT16S)((CPU_INT16S)(*p1_str_cmp) - (CPU_INT16S)(*p2_str_cmp)); + + } else if (*p1_str_cmp == (CPU_CHAR)'\0') { /* If NULL char(s) found, ... */ + cmp_val = (CPU_INT16S)0; /* ... strs identical; rtn 0 (see Note #3b). */ + + } else { + if (p1_str_cmp_next == (const CPU_CHAR *)0) { + if (p2_str_cmp_next == (const CPU_CHAR *)0) { /* If BOTH next str ptrs NULL, ... */ + cmp_val = (CPU_INT16S)0; /* ... rtn 0 (see Note #3a2A). */ + } else { /* If p1_str_cmp_next NULL, ... */ + /* ... rtn neg p2_str_cmp_next val (see Note #3a2B1). */ + cmp_val = (CPU_INT16S)((CPU_INT16S)0 - (CPU_INT16S)(*p2_str_cmp_next)); + } + } else { /* If p2_str_cmp_next NULL, ... */ + cmp_val = (CPU_INT16S)(*p1_str_cmp_next); /* ... rtn pos p1_str_cmp_next val (see Note #3a2B2). */ + } + } + + + return (cmp_val); +} + + +/* +********************************************************************************************************* +* Str_CmpIgnoreCase() +* +* Description : Determine if two strings are identical, ignoring case. +* +* Argument(s) : p1_str Pointer to first string (see Note #1). +* +* p2_str Pointer to second string (see Note #1). +* +* Return(s) : 0, if strings are identical (see Notes #3a1A, #3a2A, & #3b). +* +* Negative value, if 'p1_str' is less than 'p2_str' (see Notes #3a1B1, #3a2B1, & #3c). +* +* Positive value, if 'p1_str' is greater than 'p2_str' (see Notes #3a1B2, #3a2B2, & #3c). +* +* See also Note #2b. +* +* Caller(s) : Application. +* +* Note(s) : (1) String buffers NOT modified. +* +* (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strcasecmp() : DESCRIPTION' states that : +* +* (1) (A) "The strcasecmp() function shall compare ... the string pointed to by 's1' +* ('p1_str') to the string pointed to by 's2' ('p2_str')" ... +* (B) "ignoring differences in case". +* +* (2) "strcasecmp() ... shall behave as if the strings had been converted to lowercase +* and then a byte comparison performed." +* +* (b) (1) IEEE Std 1003.1, 2004 Edition, Section 'strcasecmp() : RETURN VALUE' states that +* "upon successful completion, strcasecmp() shall return an integer greater than, +* equal to, or less than 0". +* +* (2) IEEE Std 1003.1, 2004 Edition, Section 'strcmp() : DESCRIPTION' adds that "the +* sign of a non-zero return value shall be determined by the sign of the difference +* between the values of the first pair of bytes ... that differ in the strings +* being compared". +* +* (3) String comparison terminates when : +* +* (a) (1) (A) BOTH string pointer(s) are passed NULL pointers. +* (1) NULL strings identical; 0 returned. +* +* (B) (1) 'p1_str' passed a NULL pointer. +* (a) Return negative value of character pointed to by 'p2_str', converted +* to lower case (see Note #2a2). +* +* (2) 'p2_str' passed a NULL pointer. +* (a) Return positive value of character pointed to by 'p1_str', converted +* to lower case (see Note #2a2). +* +* (2) (A) BOTH strings point to NULL. +* (1) Strings overlap with NULL address. +* (2) Strings identical up to but NOT beyond or including the NULL address; +* 0 returned. +* +* (B) (1) 'p1_str_cmp_next' points to NULL. +* (a) 'p1_str' overlaps with NULL address. +* (b) Strings compared up to but NOT beyond or including the NULL address. +* (c) Return negative value of character pointed to by 'p2_str_cmp_next', +* converted to lower case (see Note #2a2). +* +* (2) 'p2_str_cmp_next' points to NULL. +* (a) 'p2_str' overlaps with NULL address. +* (b) Strings compared up to but NOT beyond or including the NULL address. +* (c) Return positive value of character pointed to by 'p1_str_cmp_next', +* converted to lower case (see Note #2a2). +* +* (b) Terminating NULL character found in both strings. +* (1) Strings identical; 0 returned. +* (2) Only one NULL character test required in conditional since previous condition +* tested character equality. +* +* (c) Non-matching characters found. +* (1) Return signed-integer difference of the character pointed to by 'p2_str', +* converted to lower case, from the character pointed to by 'p1_str', converted +* to lower case. +* +* (4) Since 16-bit signed arithmetic is performed to calculate a non-identical comparison +* return value, 'CPU_CHAR' native data type size MUST be 8-bit. +********************************************************************************************************* +*/ + +CPU_INT16S Str_CmpIgnoreCase (const CPU_CHAR *p1_str, + const CPU_CHAR *p2_str) +{ + CPU_INT16S cmp_val; + + + cmp_val = Str_CmpIgnoreCase_N(p1_str, + p2_str, + DEF_INT_CPU_U_MAX_VAL); + + return (cmp_val); +} + + +/* +********************************************************************************************************* +* Str_CmpIgnoreCase_N() +* +* Description : Determine if two strings are identical for up to a maximum number of characters, +* ignoring case. +* +* Argument(s) : p1_str Pointer to first string (see Note #1). +* +* p2_str Pointer to second string (see Note #1). +* +* len_max Maximum number of characters to compare (see Note #3d). +* +* Return(s) : 0, if strings are identical (see Notes #3a1A, #3a2A, #3b, & #3d). +* +* Negative value, if 'p1_str' is less than 'p2_str' (see Notes #3a1B1, #3a2B1, & #3c). +* +* Positive value, if 'p1_str' is greater than 'p2_str' (see Notes #3a1B2, #3a2B2, & #3c). +* +* See also Note #2b. +* +* Caller(s) : Application. +* +* Note(s) : (1) String buffers NOT modified. +* +* (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strncasecmp() : DESCRIPTION' states that : +* +* (1) (A) "The strncasecmp() function shall compare ... the string pointed to by 's1' +* ('p1_str') to the string pointed to by 's2' ('p2_str')" ... +* (B) "ignoring differences in case" ... +* (C) but "not more than 'n' ('len_max') bytes" of either string. +* +* (2) "strncasecmp() shall behave as if the strings had been converted to lowercase +* and then a byte comparison performed." +* +* (b) (1) IEEE Std 1003.1, 2004 Edition, Section 'strncasecmp() : RETURN VALUE' states that +* "upon successful completion, strncasecmp() shall return an integer greater than, +* equal to, or less than 0". +* +* (2) IEEE Std 1003.1, 2004 Edition, Section 'strcmp() : DESCRIPTION' adds that "the +* sign of a non-zero return value shall be determined by the sign of the difference +* between the values of the first pair of bytes ... that differ in the strings +* being compared". +* +* (3) String comparison terminates when : +* +* (a) (1) (A) BOTH string pointer(s) are passed NULL pointers. +* (1) NULL strings identical; 0 returned. +* +* (B) (1) 'p1_str' passed a NULL pointer. +* (a) Return negative value of character pointed to by 'p2_str', converted +* to lower case (see Note #2a2). +* +* (2) 'p2_str' passed a NULL pointer. +* (a) Return positive value of character pointed to by 'p1_str', converted +* to lower case (see Note #2a2). +* +* (2) (A) BOTH strings point to NULL. +* (1) Strings overlap with NULL address. +* (2) Strings identical up to but NOT beyond or including the NULL address; +* 0 returned. +* +* (B) (1) 'p1_str_cmp_next' points to NULL. +* (a) 'p1_str' overlaps with NULL address. +* (b) Strings compared up to but NOT beyond or including the NULL address. +* (c) Return negative value of character pointed to by 'p2_str_cmp_next', +* converted to lower case (see Note #2a2). +* +* (2) 'p2_str_cmp_next' points to NULL. +* (a) 'p2_str' overlaps with NULL address. +* (b) Strings compared up to but NOT beyond or including the NULL address. +* (c) Return positive value of character pointed to by 'p1_str_cmp_next', +* converted to lower case (see Note #2a2). +* +* (b) Terminating NULL character found in both strings. +* (1) Strings identical; 0 returned. +* (2) Only one NULL character test required in conditional since previous condition +* tested character equality. +* +* (c) Non-matching characters found. +* (1) Return signed-integer difference of the character pointed to by 'p2_str', +* converted to lower case, from the character pointed to by 'p1_str', converted +* to lower case. +* +* (d) (1) 'len_max' passed a zero length. +* (A) Zero-length strings identical; 0 returned. +* +* (2) First 'len_max' number of characters identical. +* (A) Strings identical; 0 returned. +* +* See also Note #2a1C. +*$PAGE* +* (4) Since 16-bit signed arithmetic is performed to calculate a non-identical comparison +* return value, 'CPU_CHAR' native data type size MUST be 8-bit. +********************************************************************************************************* +*/ + +CPU_INT16S Str_CmpIgnoreCase_N (const CPU_CHAR *p1_str, + const CPU_CHAR *p2_str, + CPU_SIZE_T len_max) +{ + const CPU_CHAR *p1_str_cmp; + const CPU_CHAR *p2_str_cmp; + const CPU_CHAR *p1_str_cmp_next; + const CPU_CHAR *p2_str_cmp_next; + CPU_CHAR char_1; + CPU_CHAR char_2; + CPU_INT16S cmp_val; + CPU_SIZE_T cmp_len; + + + if (len_max < 1) { /* If cmp len = 0, rtn 0 (see Note #3d1A). */ + return (0); + } + + if (p1_str == (const CPU_CHAR *)0) { + if (p2_str == (const CPU_CHAR *)0) { + return (0); /* If BOTH str ptrs NULL, rtn 0 (see Note #3a1A). */ + } + char_2 = ASCII_ToLower(*p2_str); + cmp_val = (CPU_INT16S)((CPU_INT16S)0 - (CPU_INT16S)char_2); + return (cmp_val); /* If p1_str NULL, rtn neg p2_str val (see Note #3a1B1).*/ + } + if (p2_str == (const CPU_CHAR *)0) { + char_1 = ASCII_ToLower(*p1_str); + cmp_val = (CPU_INT16S)char_1; + return (cmp_val); /* If p2_str NULL, rtn pos p1_str val (see Note #3a1B2).*/ + } + + + p1_str_cmp = p1_str; + p2_str_cmp = p2_str; + p1_str_cmp_next = p1_str_cmp; + p2_str_cmp_next = p2_str_cmp; + p1_str_cmp_next++; + p2_str_cmp_next++; + char_1 = ASCII_ToLower(*p1_str_cmp); + char_2 = ASCII_ToLower(*p2_str_cmp); + cmp_len = 0u; + + while (( char_1 == char_2) && /* Cmp strs until non-matching chars (see Note #3c) ... */ + (*p1_str_cmp != ( CPU_CHAR )'\0') && /* ... or NULL chars (see Note #3b) ... */ + ( p1_str_cmp_next != (const CPU_CHAR *) 0 ) && /* ... or NULL ptr(s) found (see Note #3a2). */ + ( p2_str_cmp_next != (const CPU_CHAR *) 0 ) && + ( cmp_len < ( CPU_SIZE_T)len_max)) { /* ... or max nbr chars cmp'd (see Note #3d2). */ + p1_str_cmp++; + p2_str_cmp++; + p1_str_cmp_next++; + p2_str_cmp_next++; + cmp_len++; + char_1 = ASCII_ToLower(*p1_str_cmp); + char_2 = ASCII_ToLower(*p2_str_cmp); + } + + + if (cmp_len == len_max) { /* If strs identical for max len nbr of chars, ... */ + return (0); /* ... rtn 0 (see Note #3d2A). */ + } + + if (char_1 != char_2) { /* If strs NOT identical, ... */ + /* ... calc & rtn char diff (see Note #3c1). */ + cmp_val = (CPU_INT16S)((CPU_INT16S)char_1 - (CPU_INT16S)char_2); + + } else if (char_1 == (CPU_CHAR)'\0') { /* If NULL char(s) found, ... */ + cmp_val = (CPU_INT16S)0; /* ... strs identical; rtn 0 (see Note #3b). */ + + } else { + if (p1_str_cmp_next == (const CPU_CHAR *)0) { + if (p2_str_cmp_next == (const CPU_CHAR *)0) { /* If BOTH next str ptrs NULL, ... */ + cmp_val = (CPU_INT16S)0; /* ... rtn 0 (see Note #3a2A). */ + } else { /* If p1_str_cmp_next NULL, ... */ + char_2 = ASCII_ToLower(*p2_str_cmp_next); + /* ... rtn neg p2_str_cmp_next val (see Note #3a2B1). */ + cmp_val = (CPU_INT16S)((CPU_INT16S)0 - (CPU_INT16S)char_2); + } + } else { /* If p2_str_cmp_next NULL, ... */ + char_1 = ASCII_ToLower(*p1_str_cmp_next); + cmp_val = (CPU_INT16S)char_1; /* ... rtn pos p1_str_cmp_next val (see Note #3a2B2). */ + } + } + + + return (cmp_val); +} + + +/* +********************************************************************************************************* +* Str_Char() +* +* Description : Search string for first occurrence of specific character. +* +* Argument(s) : pstr Pointer to string (see Note #1). +* +* srch_char Search character. +* +* Return(s) : Pointer to first occurrence of search character in string, if any (see Note #2b1). +* +* Pointer to NULL, otherwise (see Note #2b2). +* +* Caller(s) : Application. +* +* Note(s) : (1) String buffer NOT modified. +* +* (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strchr() : DESCRIPTION' states that : +* +* (1) "The strchr() function shall locate the first occurrence of 'c' ('srch_char') +* ... in the string pointed to by 's' ('pstr')." +* (2) "The terminating null byte is considered to be part of the string." +* +* (b) IEEE Std 1003.1, 2004 Edition, Section 'strchr() : RETURN VALUE' states that +* "upon completion, strchr() shall return" : +* +* (1) "a pointer to the byte," ... +* (2) "or a null pointer if the byte was not found." +* (A) #### Although NO strchr() specification states to return NULL for +* any other reason(s), NULL is also returned for any error(s). +* +* (3) String search terminates when : +* +* (a) String pointer passed a NULL pointer. +* (1) No string search performed; NULL pointer returned. +* +* (b) String pointer points to NULL. +* (1) String overlaps with NULL address; NULL pointer returned. +* +* (c) String's terminating NULL character found. +* (1) Search character NOT found in search string; NULL pointer returned +* (see Note #2b2). +* (2) Applicable even if search character is the terminating NULL character +* (see Note #2a2). +* +* (d) Search character found. +* (1) Return pointer to first occurrence of search character in search string +* (see Note #2a1). +********************************************************************************************************* +*/ + +CPU_CHAR *Str_Char (const CPU_CHAR *pstr, + CPU_CHAR srch_char) +{ + CPU_CHAR *pstr_rtn; + + + pstr_rtn = Str_Char_N(pstr, + DEF_INT_CPU_U_MAX_VAL, + srch_char); + + return (pstr_rtn); +} + + +/* +********************************************************************************************************* +* Str_Char_N() +* +* Description : Search string for first occurrence of specific character, up to a maximum number +* of characters. +* +* Argument(s) : pstr Pointer to string (see Note #1). +* +* len_max Maximum number of characters to search (see Notes #2c & #3e). +* +* srch_char Search character. +* +* Return(s) : Pointer to first occurrence of search character in string, if any (see Note #2b1). +* +* Pointer to NULL, otherwise (see Note #2b2). +* +* Caller(s) : Application. +* +* Note(s) : (1) String buffer NOT modified. +* +* (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strchr() : DESCRIPTION' states that : +* +* (1) "The strchr() function shall locate the first occurrence of 'c' ('srch_char') +* ... in the string pointed to by 's' ('pstr')." +* (2) "The terminating null byte is considered to be part of the string." +* +* (b) IEEE Std 1003.1, 2004 Edition, Section 'strchr() : RETURN VALUE' states that +* "upon completion, strchr() shall return" : +* +* (1) "a pointer to the byte," ... +* (2) "or a null pointer if the byte was not found." +* (A) #### Although NO strchr() specification states to return NULL for +* any other reason(s), NULL is also returned for any error(s). +* +* (c) Ideally, the 'len_max' argument would be the last argument in this function's +* argument list for consistency with all other custom string library functions. +* However, the 'len_max' argument is sequentially ordered as the second argument +* to comply with most standard library's strnchr() argument list. +* +* (3) String search terminates when : +* +* (a) String pointer passed a NULL pointer. +* (1) No string search performed; NULL pointer returned. +* +* (b) String pointer points to NULL. +* (1) String overlaps with NULL address; NULL pointer returned. +* +* (c) String's terminating NULL character found. +* (1) Search character NOT found in search string; NULL pointer returned +* (see Note #2b2). +* (2) Applicable even if search character is the terminating NULL character +* (see Note #2a2). +* +* (d) Search character found. +* (1) Return pointer to first occurrence of search character in search string +* (see Note #2a1). +* +* (e) 'len_max' number of characters searched. +* (1) Search character NOT found in search string within first 'len_max' number +* of characters; NULL pointer returned. +* (2) 'len_max' number of characters MAY include terminating NULL character +* (see Note #2a2). +********************************************************************************************************* +*/ + +CPU_CHAR *Str_Char_N (const CPU_CHAR *pstr, + CPU_SIZE_T len_max, + CPU_CHAR srch_char) +{ + const CPU_CHAR *pstr_char; + CPU_SIZE_T len_srch; + + + if (pstr == (const CPU_CHAR *)0) { /* Rtn NULL if srch str ptr NULL (see Note #3a1). */ + return ((CPU_CHAR *)0); + } + + if (len_max < 1) { /* Rtn NULL if srch len = 0 (see Note #3e1). */ + return ((CPU_CHAR *)0); + } + + + pstr_char = pstr; + len_srch = 0u; + + while (( pstr_char != (const CPU_CHAR *) 0 ) && /* Srch str until NULL ptr [see Note #3b] ... */ + (*pstr_char != ( CPU_CHAR )'\0') && /* ... or NULL char (see Note #3c) ... */ + (*pstr_char != ( CPU_CHAR )srch_char) && /* ... or srch char found (see Note #3d); ... */ + ( len_srch < ( CPU_SIZE_T)len_max)) { /* ... or max nbr chars srch'd (see Note #3e). */ + pstr_char++; + len_srch++; + } + + + if (pstr_char == (const CPU_CHAR *)0) { /* Rtn NULL if NULL ptr found (see Note #3b1). */ + return ((CPU_CHAR *)0); + } + + if (len_srch >= len_max) { /* Rtn NULL if srch char NOT found ... */ + return ((CPU_CHAR *)0); /* ... within max nbr of chars (see Note #3e1). */ + } + + if (*pstr_char != srch_char) { /* Rtn NULL if srch char NOT found (see Note #3c1). */ + return ((CPU_CHAR *)0); + } + + + return ((CPU_CHAR *)pstr_char); /* Else rtn ptr to found srch char (see Note #3d1). */ +} + + +/* +********************************************************************************************************* +* Str_Char_Last() +* +* Description : Search string for last occurrence of specific character. +* +* Argument(s) : pstr Pointer to string (see Note #1). +* +* srch_char Search character. +* +* Return(s) : Pointer to last occurrence of search character in string, if any (see Note #2b1). +* +* Pointer to NULL, otherwise (see Note #2b2). +* +* Caller(s) : Application. +* +* Note(s) : (1) String buffer NOT modified. +* +* (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strrchr() : DESCRIPTION' states that : +* +* (1) "The strrchr() function shall locate the last occurrence of 'c' ('srch_char') +* ... in the string pointed to by 's' ('pstr')." +* (2) "The terminating null byte is considered to be part of the string." +* +* (b) IEEE Std 1003.1, 2004 Edition, Section 'strrchr() : RETURN VALUE' states that +* "upon successful completion, strrchr() shall return" : +* +* (1) "a pointer to the byte" ... +* (2) "or a null pointer if 'c' ('srch_char') does not occur in the string." +* (A) #### Although NO strrchr() specification states to return NULL for +* any other reason(s), NULL is also returned for any error(s). +* +* (3) String search terminates when : +* +* (a) String pointer passed a NULL pointer. +* (1) No string search performed; NULL pointer returned. +* +* (b) String pointer points to NULL. +* (1) String overlaps with NULL address; NULL pointer returned. +* +* (c) String searched from end to beginning. +* (1) Search character NOT found in search string; NULL pointer returned. +* (2) Applicable even if search character is the terminating NULL character +* (see Note #2a2). +* +* (d) Search character found. +* (1) Return pointer to last occurrence of search character in search string +* (see Note #2a1). +********************************************************************************************************* +*/ + +CPU_CHAR *Str_Char_Last (const CPU_CHAR *pstr, + CPU_CHAR srch_char) +{ + CPU_CHAR *pstr_rtn; + + + pstr_rtn = Str_Char_Last_N(pstr, + DEF_INT_CPU_U_MAX_VAL, + srch_char); + + return (pstr_rtn); +} + + +/* +********************************************************************************************************* +* Str_Char_Last_N() +* +* Description : Search string for last occurrence of specific character, up to a maximum number +* of characters. +* +* Argument(s) : pstr Pointer to string (see Note #1). +* +* len_max Maximum number of characters to search (see Notes #2c & #3e). +* +* srch_char Search character. +* +* Return(s) : Pointer to last occurrence of search character in string, if any (see Note #2b1). +* +* Pointer to NULL, otherwise (see Note #2b2). +* +* Caller(s) : Application. +* +* Note(s) : (1) String buffer NOT modified. +* +* (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strrchr() : DESCRIPTION' states that : +* +* (1) "The strrchr() function shall locate the last occurrence of 'c' ('srch_char') +* ... in the string pointed to by 's' ('pstr')." +* (2) "The terminating null byte is considered to be part of the string." +* +* (b) IEEE Std 1003.1, 2004 Edition, Section 'strrchr() : RETURN VALUE' states that +* "upon successful completion, strrchr() shall return" : +* +* (1) "a pointer to the byte" ... +* (2) "or a null pointer if 'c' ('srch_char') does not occur in the string." +* (A) #### Although NO strrchr() specification states to return NULL for +* any other reason(s), NULL is also returned for any error(s). +* +* (c) Ideally, the 'len_max' argument would be the last argument in this function's +* argument list for consistency with all other custom string library functions. +* However, the 'len_max' argument is sequentially ordered as the second argument +* to comply with most standard library's strnrchr() argument list. +* +* See also 'Str_Char_N() Note #2c'. +* +* (3) String search terminates when : +* +* (a) String pointer passed a NULL pointer. +* (1) No string search performed; NULL pointer returned. +* +* (b) String pointer points to NULL. +* (1) String overlaps with NULL address; NULL pointer returned. +* +* (c) String searched from end to beginning. +* (1) Search character NOT found in search string; NULL pointer returned +* (see Note #2b2). +* (2) Applicable even if search character is the terminating NULL character +* (see Note #2a2). +* +* (d) Search character found. +* (1) Return pointer to last occurrence of search character in search string +* (see Note #2a1). +* +* (e) 'len_max' number of characters searched. +* (1) Search character NOT found in search string within last 'len_max' number +* of characters; NULL pointer returned. +* (2) 'len_max' number of characters MAY include terminating NULL character +* (see Note #2a2). +********************************************************************************************************* +*/ + +CPU_CHAR *Str_Char_Last_N (const CPU_CHAR *pstr, + CPU_SIZE_T len_max, + CPU_CHAR srch_char) +{ + const CPU_CHAR *pstr_char; + CPU_SIZE_T str_len_max; + CPU_SIZE_T str_len; + + + if (pstr == (const CPU_CHAR *)0) { /* Rtn NULL if srch str ptr NULL (see Note #3a1). */ + return ((CPU_CHAR *)0); + } + + if (len_max < 1) { /* Rtn NULL if srch len = 0 (see Note #3e1). */ + return ((CPU_CHAR *)0); + } + + + pstr_char = pstr; + str_len_max = len_max - sizeof((CPU_CHAR)'\0'); /* Str len adj'd for NULL char len. */ + str_len = Str_Len_N(pstr_char, str_len_max); + pstr_char += str_len; + + if (pstr_char == (const CPU_CHAR *)0) { /* Rtn NULL if NULL ptr found (see Note #3b1). */ + return ((CPU_CHAR *)0); + } + + while (( pstr_char != pstr) && /* Srch str from end until beginning (see Note #3c) ... */ + (*pstr_char != srch_char)) { /* ... until srch char found (see Note #3d). */ + pstr_char--; + } + + + if (*pstr_char != srch_char) { /* Rtn NULL if srch char NOT found (see Note #3c1). */ + return ((CPU_CHAR *)0); + } + + + return ((CPU_CHAR *)pstr_char); /* Else rtn ptr to found srch char (see Note #3d1). */ +} + + +/* +********************************************************************************************************* +* Str_Char_Replace() +* +* Description : Search string for specific character and replace it by another specific character. +* +* Argument(s) : pstr Pointer to string (see Note #1). +* +* char_srch Search character. +* +* char_replace Replace character. +* +* Return(s) : Pointer to string, if NO error(s). +* +* Pointer to NULL, otherwise. +* +* Caller(s) : Application. +* +* Note(s) : (1) String buffer modified. +* +* (2) String search terminates when : +* +* (a) String pointer passed a NULL pointer. +* (1) No string search performed; NULL pointer returned. +* +* (b) String pointer points to NULL. +* (1) String overlaps with NULL address; NULL pointer returned. +* +* (c) String's terminating NULL character found. +* (1) Search character NOT found in search string; NULL pointer returned +* (2) Applicable even if search character is the terminating NULL character +* +* (d) Search character found. +* (1) Replace character found by the specified character. +********************************************************************************************************* +*/ + +CPU_CHAR *Str_Char_Replace (CPU_CHAR *pstr, + CPU_CHAR char_srch, + CPU_CHAR char_replace) +{ + CPU_CHAR *pstr_rtn; + + + pstr_rtn = Str_Char_Replace_N(pstr, + char_srch, + char_replace, + DEF_INT_CPU_U_MAX_VAL); + + return (pstr_rtn); +} + + +/* +********************************************************************************************************* +* Str_Char_Replace_N() +* +* Description : Search string for specific character and replace it by another specific character, up to +* a maximum number of characters. +* +* Argument(s) : pstr Pointer to string (see Note #1). +* +* char_srch Search character. +* +* char_replace Replace character. +* +* len_max Maximum number of characters to search (see Notes #2c & #3e). +* +* Return(s) : Pointer to string, if NO error(s). +* +* Pointer to NULL, otherwise. +* +* Caller(s) : Application. +* +* Note(s) : (1) String buffer modified. +* +* (2) String search terminates when : +* +* (a) String pointer passed a NULL pointer. +* (1) No string search performed; NULL pointer returned. +* +* (b) String pointer points to NULL. +* (1) String overlaps with NULL address; NULL pointer returned. +* +* (c) String's terminating NULL character found. +* (1) Search character NOT found in search string; NULL pointer returned +* (2) Applicable even if search character is the terminating NULL character +* +* (d) Search character found. +* (1) Replace character found by the specified character. +* +* (e) 'len_max' number of characters searched. +* (1) Search character NOT found in search string within first 'len_max' number +* of characters; NULL pointer returned. +* (2) 'len_max' number of characters MAY include terminating NULL character +* (see Note #2a2). +********************************************************************************************************* +*/ + +CPU_CHAR *Str_Char_Replace_N (CPU_CHAR *pstr, + CPU_CHAR char_srch, + CPU_CHAR char_replace, + CPU_SIZE_T len_max) +{ + CPU_CHAR *pstr_char; + CPU_SIZE_T len; + + + if (pstr == (const CPU_CHAR *)0) { /* Rtn NULL if srch str ptr NULL (see Note #2a1). */ + return ((CPU_CHAR *)0); + } + + if (len_max < 1) { /* Rtn NULL if srch len = 0 (see Note #2e1). */ + return ((CPU_CHAR *)0); + } + + pstr_char = pstr; + len = len_max; + + while (( pstr_char != (const CPU_CHAR *)0) && /* Srch str until NULL ptr [see Note #2b] ... */ + (*pstr_char != ASCII_CHAR_NULL ) && /* ... or NULL char (see Note #2c) ... */ + ( len > 0)) { /* ... or max nbr chars srch'd (see Note #2e). */ + + if (*pstr_char == char_srch) { + *pstr_char = char_replace; /* Replace char if srch char is found. */ + } + + pstr_char++; + len--; + } + + return (pstr); +} + + +/* +********************************************************************************************************* +* Str_Str() +* +* Description : Search string for first occurence of a specific search string. +* +* Argument(s) : pstr Pointer to string (see Note #1). +* +* pstr_srch Pointer to search string (see Note #1). +* +* Return(s) : Pointer to first occurrence of search string in string, if any (see Note #2b1A). +* +* Pointer to string, if NULL search string (see Note #2b2). +* +* Pointer to NULL, otherwise (see Note #2b1B). +* +* Caller(s) : Application. +* +* Note(s) : (1) String buffers NOT modified. +* +* (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strstr() : DESCRIPTION' states that : +* +* (1) "The strstr() function shall locate the first occurrence in the string +* pointed to by 's1' ('pstr') of the sequence of bytes ... in the string +* pointed to by 's2' ('pstr_srch')" ... +* (2) "(excluding the terminating null byte)." +* +* (b) IEEE Std 1003.1, 2004 Edition, Section 'strstr() : RETURN VALUE' states that : +* +* (1) "Upon successful completion, strstr() shall return" : +* (A) "a pointer to the located string" ... +* (B) "or a null pointer if the string is not found." +* (1) #### Although NO strstr() specification states to return NULL for +* any other reason(s), NULL is also returned for any error(s). +* +* (2) "If 's2' ('pstr_srch') points to a string with zero length, the function +* shall return 's1' ('pstr')." +* +* (3) String search terminates when : +* +* (a) String pointer(s) are passed NULL pointers. +* (1) No string search performed; NULL pointer returned. +* +* (b) String pointer(s) point to NULL. +* (1) String buffer(s) overlap with NULL address; NULL pointer returned. +* +* (c) Search string length equal to zero. +* (1) No string search performed; string pointer returned (see Note #2b2). +* +* (d) Search string length greater than string length. +* (1) No string search performed; NULL pointer returned (see Note #2b1B). +* +* (e) Entire string has been searched. +* (1) Search string not found; NULL pointer returned (see Note #2b1B). +* +* (f) Search string found. +* (1) Return pointer to first occurrence of search string in string (see Note #2b1A). +********************************************************************************************************* +*/ + +CPU_CHAR *Str_Str (const CPU_CHAR *pstr, + const CPU_CHAR *pstr_srch) +{ + CPU_CHAR *pstr_rtn; + + + pstr_rtn = Str_Str_N(pstr, + pstr_srch, + DEF_INT_CPU_U_MAX_VAL); + + return (pstr_rtn); +} + + +/* +********************************************************************************************************* +* Str_Str_N() +* +* Description : Search string for first occurence of a specific search string, up to a maximum number +* of characters. +* +* Argument(s) : pstr Pointer to string (see Note #1). +* +* pstr_srch Pointer to search string (see Note #1). +* +* len_max Maximum number of characters to search (see Note #3g). +* +* Return(s) : Pointer to first occurrence of search string in string, if any (see Note #2b1A). +* +* Pointer to string, if NULL search string (see Note #2b2). +* +* Pointer to NULL, otherwise (see Note #2b1B). +* +* Caller(s) : Application. +* +* Note(s) : (1) String buffers NOT modified. +* +* (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strstr() : DESCRIPTION' states that : +* +* (1) "The strstr() function shall locate the first occurrence in the string +* pointed to by 's1' ('pstr') of the sequence of bytes ... in the string +* pointed to by 's2' ('pstr_srch')" ... +* (2) "(excluding the terminating null byte)." +* +* (b) IEEE Std 1003.1, 2004 Edition, Section 'strstr() : RETURN VALUE' states that : +* +* (1) "Upon successful completion, strstr() shall return" : +* (A) "a pointer to the located string" ... +* (B) "or a null pointer if the string is not found." +* (1) #### Although NO strstr() specification states to return NULL for +* any other reason(s), NULL is also returned for any error(s). +* +* (2) "If 's2' ('pstr_srch') points to a string with zero length, the function +* shall return 's1' ('pstr')." +* +* (3) String search terminates when : +* +* (a) String pointer(s) are passed NULL pointers. +* (1) No string search performed; NULL pointer returned. +* +* (b) String pointer(s) point to NULL. +* (1) String buffer(s) overlap with NULL address; NULL pointer returned. +* +* (c) Search string length equal to zero. +* (1) No string search performed; string pointer returned (see Note #2b2). +* +* (d) Search string length greater than string length. +* (1) No string search performed; NULL pointer returned (see Note #2b1B). +* +* (e) Entire string has been searched. +* (1) Search string not found; NULL pointer returned (see Note #2b1B). +* (2) Maximum size of the search is defined as the subtraction of the +* search string length from the string length. +* +* (f) Search string found. +* (1) Return pointer to first occurrence of search string in string (see Note #2b1A). +* (2) Search string found via Str_Cmp_N(). +* +* (g) 'len_max' number of characters searched. +* (1) 'len_max' number of characters does NOT include terminating NULL character +* (see Note #2a2). +********************************************************************************************************* +*/ + +CPU_CHAR *Str_Str_N (const CPU_CHAR *pstr, + const CPU_CHAR *pstr_srch, + CPU_SIZE_T len_max) +{ + CPU_SIZE_T str_len; + CPU_SIZE_T str_len_srch; + CPU_SIZE_T len_max_srch; + CPU_SIZE_T srch_len; + CPU_SIZE_T srch_ix; + CPU_BOOLEAN srch_done; + CPU_INT16S srch_cmp; + const CPU_CHAR *pstr_str; + const CPU_CHAR *pstr_srch_ix; + + /* Rtn NULL if str ptr(s) NULL (see Note #3a). */ + if (pstr == (const CPU_CHAR *)0) { + return ((CPU_CHAR *)0); + } + if (pstr_srch == (const CPU_CHAR *)0) { + return ((CPU_CHAR *)0); + } + + if (len_max < 1) { /* Rtn NULL if srch len = 0 (see Note #3g). */ + return ((CPU_CHAR *)0); + } + + /* Lim max srch str len (to chk > str len). */ + len_max_srch = (len_max < DEF_INT_CPU_U_MAX_VAL) + ? (len_max + 1u) : DEF_INT_CPU_U_MAX_VAL; + + str_len = Str_Len_N(pstr, len_max); + str_len_srch = Str_Len_N(pstr_srch, len_max_srch); + if (str_len_srch < 1) { /* Rtn ptr to str if srch str len = 0 (see Note #2b2). */ + return ((CPU_CHAR *)pstr); + } + if (str_len_srch > str_len) { /* Rtn NULL if srch str len > str len (see Note #3d). */ + return ((CPU_CHAR *)0); + } + /* Rtn NULL if NULL ptr found (see Note #3b1). */ + pstr_str = pstr + str_len; + if (pstr_str == (const CPU_CHAR *)0) { + return ((CPU_CHAR *)0); + } + pstr_str = pstr_srch + str_len_srch; + if (pstr_str == (const CPU_CHAR *)0) { + return ((CPU_CHAR *)0); + } + + + srch_len = str_len - str_len_srch; /* Calc srch len (see Note #3e2). */ + srch_ix = 0u; + srch_done = DEF_NO; + + do { + pstr_srch_ix = (const CPU_CHAR *)(pstr + srch_ix); + srch_cmp = Str_Cmp_N(pstr_srch_ix, pstr_srch, str_len_srch); + srch_done = (srch_cmp == 0) ? DEF_YES : DEF_NO; + srch_ix++; + } while ((srch_done == DEF_NO) && (srch_ix <= srch_len)); + + + if (srch_cmp != 0) { /* Rtn NULL if srch str NOT found (see Note #3e2). */ + return ((CPU_CHAR *)0); + } + + return ((CPU_CHAR *)pstr_srch_ix); /* Else rtn ptr to found srch str (see Note #3f1). */ +} + + +/* +********************************************************************************************************* +* Str_FmtNbr_Int32U() +* +* Description : Format 32-bit unsigned integer into a multi-digit character string. +* +* Argument(s) : nbr Number to format. +* +* nbr_dig Number of digits to format (see Note #1). +* +* The following may be used to specify the number of digits to format : +* +* DEF_INT_32U_NBR_DIG_MIN Minimum number of 32-bit unsigned digits +* DEF_INT_32U_NBR_DIG_MAX Maximum number of 32-bit unsigned digits +* +* nbr_base Base of number to format (see Note #2). +* +* The following may be used to specify the number base : +* +* DEF_NBR_BASE_BIN Base 2 +* DEF_NBR_BASE_OCT Base 8 +* DEF_NBR_BASE_DEC Base 10 +* DEF_NBR_BASE_HEX Base 16 +* +* lead_char Prepend leading character (see Note #3) : +* +* '\0' Do NOT prepend leading character to string. +* Printable character Prepend leading character to string. +* Unprintable character Format invalid string (see Note #6). +* +* lower_case Format alphabetic characters (if any) in lower case : +* +* DEF_NO Format alphabetic characters in upper case. +* DEF_YES Format alphabetic characters in lower case. +* +* nul Append terminating NULL-character (see Note #4) : +* +* DEF_NO Do NOT append terminating NULL-character to string. +* DEF_YES Append terminating NULL-character to string. +* +* pstr Pointer to character array to return formatted number string (see Note #5). +* +* Return(s) : Pointer to formatted string, if NO error(s). +* +* Pointer to NULL, otherwise. +* +* Caller(s) : Application. +* +* Note(s) : (1) (a) If the number of digits to format ('nbr_dig') is zero; then NO formatting +* is performed except possible NULL-termination of the string (see Note #4). +* +* Example : +* +* nbr = 23456 +* nbr_dig = 0 +* nbr_base = 10 +* +* pstr = "" See Note #6a +* +* (b) If the number of digits to format ('nbr_dig') is less than the number of +* significant integer digits of the number to format ('nbr'); then an invalid +* string is formatted instead of truncating any significant integer digits. +* +* Example : +* +* nbr = 23456 +* nbr_dig = 3 +* nbr_base = 10 +* +* pstr = "???" See Note #6b +* +* (2) The number's base MUST be between 2 & 36, inclusive. +*$PAGE* +* (3) Leading character option prepends leading characters prior to the first non-zero digit. +* +* (a) (1) Leading character MUST be a printable ASCII character. +* +* (2) (A) Leading character MUST NOT be a number base digit, ... +* (B) with the exception of '0'. +* +* (b) The number of leading characters is such that the total number of significant +* integer digits plus the number of leading characters is equal to the requested +* number of integer digits to format ('nbr_dig'). +* +* Example : +* +* nbr = 23456 +* nbr_dig = 7 +* nbr_base = 10 +* lead_char = ' ' +* +* pstr = " 23456" +* +* (c) (1) If the value of the number to format is zero ... +* (2) ... & the number of digits to format is non-zero, ... +* (3) ... but NO leading character available; ... +* (4) ... then one digit of '0' value is formatted. +* +* This is NOT a leading character; but a single integer digit of '0' value. +* +* (4) (a) NULL-character terminate option DISABLED prevents overwriting previous character +* array formatting. +* +* (b) WARNING: Unless 'pstr' character array is pre-/post-terminated, NULL-character +* terminate option DISABLED will cause character string run-on. +* +* (5) (a) Format buffer size NOT validated; buffer overruns MUST be prevented by caller. +* +* (b) To prevent character buffer overrun : +* +* Character array size MUST be >= ('nbr_dig' + +* 1 'NUL' terminator) characters +* +* (6) For any unsuccessful string format or error(s), an invalid string of question marks +* ('?') will be formatted, where the number of question marks is determined by the +* number of digits to format ('nbr_dig') : +* +* Invalid string's { (a) 0 (NULL string) , if 'nbr_dig' = 0 +* number of = { +* question marks { (b) 'nbr_dig' , if 'nbr_dig' > 0 +* +********************************************************************************************************* +*/ + +CPU_CHAR *Str_FmtNbr_Int32U (CPU_INT32U nbr, + CPU_INT08U nbr_dig, + CPU_INT08U nbr_base, + CPU_CHAR lead_char, + CPU_BOOLEAN lower_case, + CPU_BOOLEAN nul, + CPU_CHAR *pstr) +{ + CPU_CHAR *pstr_fmt; + + + pstr_fmt = Str_FmtNbr_Int32(nbr, /* Fmt unsigned int into str. */ + nbr_dig, + nbr_base, + DEF_NO, + lead_char, + lower_case, + nul, + pstr); + + return (pstr_fmt); +} + + +/* +********************************************************************************************************* +* Str_FmtNbr_Int32S() +* +* Description : Format 32-bit signed integer into a multi-digit character string. +* +* Argument(s) : nbr Number to format. +* +* nbr_dig Number of digits to format (see Note #1). +* +* The following may be used to specify the number of digits to format : +* +* DEF_INT_32S_NBR_DIG_MIN + 1 Minimum number of 32-bit signed digits +* DEF_INT_32S_NBR_DIG_MAX + 1 Maximum number of 32-bit signed digits +* (plus 1 digit for possible negative sign) +* +* nbr_base Base of number to format (see Note #2). +* +* The following may be used to specify the number base : +* +* DEF_NBR_BASE_BIN Base 2 +* DEF_NBR_BASE_OCT Base 8 +* DEF_NBR_BASE_DEC Base 10 +* DEF_NBR_BASE_HEX Base 16 +* +* lead_char Prepend leading character (see Note #3) : +* +* '\0' Do NOT prepend leading character to string. +* Printable character Prepend leading character to string. +* Unprintable character Format invalid string (see Note #6). +* +* lower_case Format alphabetic characters (if any) in lower case : +* +* DEF_NO Format alphabetic characters in upper case. +* DEF_YES Format alphabetic characters in lower case. +* +* nul Append terminating NULL-character (see Note #4) : +* +* DEF_NO Do NOT append terminating NULL-character to string. +* DEF_YES Append terminating NULL-character to string. +* +* pstr Pointer to character array to return formatted number string (see Note #5). +* +* Return(s) : Pointer to formatted string, if NO error(s). +* +* Pointer to NULL, otherwise. +* +* Caller(s) : Application. +* +* Note(s) : (1) (a) If the number of digits to format ('nbr_dig') is zero; then NO formatting +* is performed except possible NULL-termination of the string (see Note #4). +* +* Example : +* +* nbr = -23456 +* nbr_dig = 0 +* nbr_base = 10 +* +* pstr = "" See Note #6a +* +* (b) If the number of digits to format ('nbr_dig') is less than the number of +* significant integer digits of the number to format ('nbr'); then an invalid +* string is formatted instead of truncating any significant integer digits. +* +* Example : +* +* nbr = 23456 +* nbr_dig = 3 +* nbr_base = 10 +* +* pstr = "???" See Note #6b +* +* (c) If the number to format ('nbr') is negative but the number of digits to format +* ('nbr_dig') is equal to the number of significant integer digits of the number +* to format ('nbr'); then an invalid string is formatted instead of truncating +* the negative sign. +* +* Example : +* +* nbr = -23456 +* nbr_dig = 5 +* nbr_base = 10 +* +* pstr = "?????" See Note #6b +* +* (2) The number's base MUST be between 2 & 36, inclusive. +*$PAGE* +* (3) Leading character option prepends leading characters prior to the first non-zero digit. +* +* (a) (1) Leading character MUST be a printable ASCII character. +* +* (2) (A) Leading character MUST NOT be a number base digit, ... +* (B) with the exception of '0'. +* +* (b) (1) The number of leading characters is such that the total number of significant +* integer digits plus the number of leading characters plus possible negative +* sign character is equal to the requested number of integer digits to format +* ('nbr_dig'). +* +* Examples : +* +* nbr = 23456 +* nbr_dig = 7 +* nbr_base = 10 +* lead_char = ' ' +* +* pstr = " 23456" +* +* +* nbr = -23456 +* nbr_dig = 7 +* nbr_base = 10 +* lead_char = ' ' +* +* pstr = " -23456" +* +* (2) (A) If the number to format ('nbr') is negative AND the leading character +* ('lead_char') is a '0' digit; then the negative sign character +* prefixes all leading characters prior to the formatted number. +* +* Examples : +* +* nbr = -23456 +* nbr_dig = 8 +* nbr_base = 10 +* lead_char = '0' +* +* pstr = "-0023456" +* +* +* nbr = -43981 +* nbr_dig = 8 +* nbr_base = 16 +* lead_char = '0' +* lower_case = DEF_NO +* +* pstr = "-000ABCD" +* +* (B) If the number to format ('nbr') is negative AND the leading character +* ('lead_char') is NOT a '0' digit; then the negative sign character +* immediately prefixes the most significant digit of the formatted number. +* +* Examples : +* +* nbr = -23456 +* nbr_dig = 8 +* nbr_base = 10 +* lead_char = '#' +* +* pstr = "##-23456" +* +* +* nbr = -43981 +* nbr_dig = 8 +* nbr_base = 16 +* lead_char = '#' +* lower_case = DEF_YES +* +* pstr = "###-abcd" +* +* (c) (1) If the value of the number to format is zero ... +* (2) ... & the number of digits to format is non-zero, ... +* (3) ... but NO leading character available; ... +* (4) ... then one digit of '0' value is formatted. +* +* This is NOT a leading character; but a single integer digit of '0' value. +*$PAGE* +* (4) (a) NULL-character terminate option DISABLED prevents overwriting previous character +* array formatting. +* +* (b) WARNING: Unless 'pstr' character array is pre-/post-terminated, NULL-character +* terminate option DISABLED will cause character string run-on. +* +* (5) (a) Format buffer size NOT validated; buffer overruns MUST be prevented by caller. +* +* (b) To prevent character buffer overrun : +* +* Character array size MUST be >= ('nbr_dig' + +* 1 negative sign + +* 1 'NUL' terminator) characters +* +* (6) For any unsuccessful string format or error(s), an invalid string of question marks +* ('?') will be formatted, where the number of question marks is determined by the +* number of digits to format ('nbr_dig') : +* +* Invalid string's { (a) 0 (NULL string) , if 'nbr_dig' = 0 +* number of = { +* question marks { (b) 'nbr_dig' , if 'nbr_dig' > 0 +* +********************************************************************************************************* +*/ + +CPU_CHAR *Str_FmtNbr_Int32S (CPU_INT32S nbr, + CPU_INT08U nbr_dig, + CPU_INT08U nbr_base, + CPU_CHAR lead_char, + CPU_BOOLEAN lower_case, + CPU_BOOLEAN nul, + CPU_CHAR *pstr) +{ + CPU_CHAR *pstr_fmt; + CPU_INT32S nbr_fmt; + CPU_BOOLEAN nbr_neg; + + + if (nbr < 0) { /* If nbr neg, ... */ + nbr_fmt = -nbr; /* ... negate nbr. */ + nbr_neg = DEF_YES; + } else { + nbr_fmt = nbr; + nbr_neg = DEF_NO; + } + + pstr_fmt = Str_FmtNbr_Int32((CPU_INT32U)nbr_fmt, /* Fmt signed int into str. */ + nbr_dig, + nbr_base, + nbr_neg, + lead_char, + lower_case, + nul, + pstr); + + return (pstr_fmt); +} + + +/* +********************************************************************************************************* +* Str_FmtNbr_32() +* +* Description : Format number into a multi-digit character string. +* +* Argument(s) : nbr Number to format (see Note #1). +* +* nbr_dig Number of decimal digits to format (see Note #2). +* +* nbr_dp Number of decimal point digits to format. +* +* lead_char Prepend leading character (see Note #3) : +* +* '\0' Do NOT prepend leading character to string. +* Printable character Prepend leading character to string. +* Unprintable character Format invalid string (see Note #6d). +* +* nul Append terminating NULL-character (see Note #4) : +* +* DEF_NO Do NOT append terminating NULL-character to string. +* DEF_YES Append terminating NULL-character to string. +* +* pstr Pointer to character array to return formatted number string (see Note #5). +* +* Return(s) : Pointer to formatted string, if NO error(s) [see Note #6c]. +* +* Pointer to NULL, otherwise. +* +* Caller(s) : Application. +* +* Note(s) : (1) (a) The maximum accuracy for 32-bit floating-point numbers : +* +* +* Maximum Accuracy log [Internal-Base ^ (Number-Internal-Base-Digits)] +* 32-bit Floating-point Number = ----------------------------------------------------- +* log [External-Base] +* +* log [2 ^ 24] +* = -------------- +* log [10] +* +* < 7.225 Base-10 Digits +* +* where +* Internal-Base Internal number base of floating- +* point numbers (i.e. 2) +* External-Base External number base of floating- +* point numbers (i.e. 10) +* Number-Internal-Base-Digits Number of internal number base +* significant digits (i.e. 24) +* +* (b) Some CPUs' &/or compilers' floating-point implementations MAY further reduce the +* maximum accuracy. +*$PAGE* +* (2) (a) If the total number of digits to format ('nbr_dig + nbr_dp') is zero; then NO +* formatting is performed except possible NULL-termination of the string (see Note #4). +* +* Example : +* +* nbr = -23456.789 +* nbr_dig = 0 +* nbr_dp = 0 +* +* pstr = "" See Note #7a +* +* (b) (1) If the number of digits to format ('nbr_dig') is less than the number of +* significant integer digits of the number to format ('nbr'); then an invalid +* string is formatted instead of truncating any significant integer digits. +* +* Example : +* +* nbr = 23456.789 +* nbr_dig = 3 +* nbr_dp = 2 +* +* pstr = "??????" See Note #7d +* +* (2) If the number to format ('nbr') is negative but the number of digits to format +* ('nbr_dig') is equal to the number of significant integer digits of the number +* to format ('nbr'); then an invalid string is formatted instead of truncating +* the negative sign. +* +* Example : +* +* nbr = -23456.789 +* nbr_dig = 5 +* nbr_dp = 2 +* +* pstr = "????????" See Note #7d +* +* (3) If the number to format ('nbr') is negative but the number of significant +* integer digits is zero, & the number of digits to format ('nbr_dig') is one +* but the number of decimal point digits to format ('nbr_dp') is zero; then +* an invalid string is formatted instead of truncating the negative sign. +* +* Example : +* +* nbr = -0.7895 +* nbr_dig = 1 +* nbr_dp = 0 +* +* pstr = "?" See Note #7d +* +* (4) (A) If the number to format ('nbr') is negative but the number of significant +* integer digits is zero, & the number of digits to format ('nbr_dig') is +* zero but the number of decimal point digits to format ('nbr_dp') is non- +* zero; then the negative sign immediately prefixes the decimal point -- +* with NO decimal digits formatted, NOT even a single decimal digit of '0'. +* +* Example : +* +* nbr = -0.7895 +* nbr_dig = 0 +* nbr_dp = 2 +* +* pstr = "-.78" +* +* (B) If the number to format ('nbr') is positive but the number of significant +* integer digits is zero, & the number of digits to format ('nbr_dig') is +* zero but the number of decimal point digits to format ('nbr_dp') is non- +* zero; then a single decimal digit of '0' prefixes the decimal point. +* +* This '0' digit is used whenever a negative sign is not formatted (see +* Note #2b4A) so that the formatted string's decimal point is not floating, +* but fixed in the string as the 2nd character. +* +* Example : +* +* nbr = 0.7895 +* nbr_dig = 0 +* nbr_dp = 2 +* +* pstr = "0.78" +*$PAGE* +* (c) (1) If the total number of digits to format ('nbr_dig + nbr_dp') is greater than ... : +* +* (A) ... the maximum accuracy of the CPU's &/or compiler's 32-bit floating-point +* numbers, digits following all significantly-accurate digits of the number to +* format ('nbr') will be inaccurate; ... +* (B) ... the configured maximum accuracy ('LIB_STR_CFG_FP_MAX_NBR_DIG_SIG'), all +* digits or decimal places following all significantly-accurate digits of the +* number to format ('nbr') will be replaced & formatted with zeros ('0'). +* +* Example : +* +* nbr = 123456789.012345 +* nbr_dig = 9 +* nbr_dp = 6 +* LIB_STR_CFG_FP_MAX_NBR_DIG_SIG = 7 +* +* pstr = "123456700.000000" +* +* (2) Therefore, one or more least-significant digit(s) of the number to format ('nbr') +* MAY be rounded & not necessarily truncated due to the inaccuracy of the CPU's +* &/or compiler's floating-point implementation. +* +* See also Note #1. +* +* (3) Leading character option prepends leading characters prior to the first non-zero digit. +* +* (a) (1) Leading character MUST be a printable ASCII character. +* +* (2) (A) Leading character MUST NOT be a base-10 digit, ... +* (B) with the exception of '0'. +* +* (b) (1) The number of leading characters is such that the total number of significant +* integer digits plus the number of leading characters plus possible negative +* sign character is equal to the requested number of integer digits to format +* ('nbr_dig'). +* +* Examples : +* +* nbr = 23456.789 +* nbr_dig = 7 +* nbr_dp = 2 +* lead_char = ' ' +* +* pstr = " 23456.78" +* +* +* nbr = -23456.789 +* nbr_dig = 7 +* nbr_dp = 2 +* lead_char = ' ' +* +* pstr = " -23456.78" +* +* (2) (A) If the number to format ('nbr') is negative AND the leading character +* ('lead_char') is a '0' digit; then the negative sign character +* prefixes all leading characters prior to the formatted number. +* +* Example : +* +* nbr = -23456.789 +* nbr_dig = 8 +* nbr_dp = 2 +* lead_char = '0' +* +* pstr = "-0023456.78" +* +* (B) If the number to format ('nbr') is negative AND the leading character +* ('lead_char') is NOT a '0' digit; then the negative sign character +* immediately prefixes the most significant digit of the formatted number. +* +* Examples : +* +* nbr = -23456.789 +* nbr_dig = 8 +* nbr_dp = 2 +* lead_char = '#' +* +* pstr = "##-23456.78" +* +* (c) (1) If the integer value of the number to format is zero & ... +* (2) ... the number of digits to format is greater than one ... +* (3) ... OR the number is NOT negative, ... +* (4) ... but NO leading character available; ... +* (5) ... then one digit of '0' value is formatted. +* +* This is NOT a leading character; but a single integer digit of '0' value. +* +* See also Note #2b4B. +*$PAGE* +* (4) (a) NULL-character terminate option DISABLED prevents overwriting previous character +* array formatting. +* +* (b) WARNING: Unless 'pstr' character array is pre-/post-terminated, NULL-character +* terminate option DISABLED will cause character string run-on. +* +* (5) (a) Format buffer size NOT validated; buffer overruns MUST be prevented by caller. +* +* (b) To prevent character buffer overrun : +* +* Character array size MUST be >= ('nbr_dig' + +* 'nbr_dp' + +* 1 negative sign + +* 1 decimal point + +* 1 'NUL' terminator) characters +* +* (6) String format terminates when : +* +* (a) Format string pointer is passed a NULL pointer. +* (1) No string formatted; NULL pointer returned. +* +* (b) Total number of digits to format ('nbr_dig + nbr_dp') is zero. +* (1) NULL string formatted (see Note #7a); NULL pointer returned. +* +* (c) Number of digits to format ('nbr_dig') is less than number of significant +* integer digits of the number to format ('nbr'), including possible +* negative sign. +* (1) Invalid string formatted (see Note #7); NULL pointer returned. +* +* (d) Lead character is NOT a valid, printable character (see Note #3a). +* (1) Invalid string formatted (see Note #7); NULL pointer returned. +* +* (e) Number successfully formatted into character string array. +* +* (7) For any unsuccessful string format or error(s), an invalid string of question marks +* ('?') will be formatted, where the number of question marks is determined by the +* number of digits ('nbr_dig') & number of decimal point digits ('nbr_dp') to format : +* +* { (a) 0 (NULL string) , if 'nbr_dig' = 0 AND +* { 'nbr_dp' = 0 +* { +* { (b) 'nbr_dig' , if 'nbr_dig' > 0 AND +* { 'nbr_dp' = 0 +* Invalid string's { +* number of = { (c) ['nbr_dp' + , if 'nbr_dig' = 0 AND +* question marks { 1 (for decimal point) + 'nbr_dp' > 0 +* { 1 (for negative sign) ] +* { +* { (d) ['nbr_dig' + , if 'nbr_dig' > 0 AND +* { 'nbr_dp' + 'nbr_dp' > 0 +* { 1 (for decimal point) ] +* +********************************************************************************************************* +*/ + +#if (LIB_STR_CFG_FP_EN == DEF_ENABLED) +CPU_CHAR *Str_FmtNbr_32 (CPU_FP32 nbr, + CPU_INT08U nbr_dig, + CPU_INT08U nbr_dp, + CPU_CHAR lead_char, + CPU_BOOLEAN nul, + CPU_CHAR *pstr) +{ + CPU_CHAR *pstr_fmt; + CPU_DATA i; + CPU_FP32 nbr_fmt; + CPU_FP32 nbr_log; + CPU_INT32U nbr_shiftd; + CPU_INT16U nbr_dig_max; + CPU_INT16U nbr_dig_sig; + CPU_INT08U nbr_neg_sign; + CPU_INT08U dig_val; + CPU_FP32 dig_exp; + CPU_FP32 dp_exp; + CPU_BOOLEAN lead_char_dig; + CPU_BOOLEAN lead_char_fmtd; + CPU_BOOLEAN lead_char_0; + CPU_BOOLEAN fmt_invalid; + CPU_BOOLEAN print_char; + CPU_BOOLEAN nbr_neg; + CPU_BOOLEAN nbr_neg_fmtd; + + + /* ---------------- VALIDATE FMT ARGS ----------------- */ + if (pstr == (CPU_CHAR *)0) { /* Rtn NULL if str ptr NULL (see Note #6a). */ + return ((CPU_CHAR *)0); + } + + dig_exp = 1.0f; + fmt_invalid = DEF_NO; + lead_char_0 = (lead_char == '0') ? DEF_YES : DEF_NO; /* Chk if lead char a '0' dig (see Note #3b2). */ + nbr_fmt = 0.0f; + nbr_neg = DEF_NO; + + if ((nbr_dig < 1) && (nbr_dp < 1)) { /* If nbr digs/dps = 0, ... */ + fmt_invalid = DEF_YES; /* ... fmt invalid str (see Note #6b). */ + } + + if (lead_char != (CPU_CHAR)'\0') { + print_char = ASCII_IsPrint(lead_char); + if (print_char != DEF_YES) { /* If lead char non-printable (see Note #3a1), ... */ + fmt_invalid = DEF_YES; /* ... fmt invalid str (see Note #6d). */ + + } else if (lead_char != '0') { /* Chk lead char for non-0 dig. */ + lead_char_dig = ASCII_IsDig(lead_char); + if (lead_char_dig == DEF_YES) { /* If lead char non-0 dig (see Note #3a2A), ... */ + fmt_invalid = DEF_YES; /* ... fmt invalid str (see Note #6d). */ + } + } + } + + + /* ----------------- PREPARE NBR FMT ------------------ */ + pstr_fmt = pstr; + + if (fmt_invalid == DEF_NO) { + if (nbr < 0.0f) { /* If nbr neg, ... */ + nbr_fmt = -nbr; /* ... negate nbr. */ + nbr_neg_sign = 1u; + nbr_neg = DEF_YES; + } else { + nbr_fmt = nbr; + nbr_neg_sign = 0u; + nbr_neg = DEF_NO; + } + + nbr_log = nbr_fmt; + nbr_dig_max = 0u; + while (nbr_log >= 1.0f) { /* While base-10 digs avail, ... */ + nbr_dig_max++; /* ... calc max nbr digs. */ + nbr_log /= 10.0f; + } + + if (((nbr_dig >= (nbr_dig_max + nbr_neg_sign)) || /* If req'd nbr digs >= (max nbr digs + neg sign) .. */ + (nbr_dig_max < 1)) && /* .. or NO nbr digs, .. */ + ((nbr_dig > 1) || /* .. but NOT [(req'd nbr dig = 1) AND .. */ + (nbr_dp > 0) || /* .. (req'd nbr dp = 0) AND .. */ + (nbr_neg == DEF_NO))) { /* .. ( nbr neg )] (see Note #2b3). */ + /* .. prepare nbr digs to fmt. */ + for (i = 1u; i < nbr_dig; i++) { + dig_exp *= 10.0f; + } + + nbr_neg_fmtd = DEF_NO; + nbr_dig_sig = 0u; + lead_char_fmtd = DEF_NO; + } else { /* Else if nbr trunc'd, ... */ + fmt_invalid = DEF_YES; /* ... fmt invalid str (see Note #6c). */ + } + } + + + /* ------------------- FMT NBR STR -------------------- */ + for (i = nbr_dig; i > 0; i--) { /* Fmt str for desired nbr digs : */ + if (fmt_invalid == DEF_NO) { + if (nbr_dig_sig < LIB_STR_CFG_FP_MAX_NBR_DIG_SIG) { /* If nbr sig digs < max, fmt str digs; ... */ + nbr_shiftd = (CPU_INT32U)(nbr_fmt / dig_exp); + if ((nbr_shiftd > 0) || /* If shifted nbr > 0 ... */ + (i == 1u)) { /* ... OR on one's dig to fmt (see Note #3c1), ... */ + /* ... calc & fmt dig val; ... */ + if ((nbr_neg == DEF_YES) && /* If nbr neg ... */ + (nbr_neg_fmtd == DEF_NO )) { /* ... but neg sign NOT yet fmt'd; ... */ + + if (lead_char_fmtd == DEF_YES) { /* ... & if lead char(s) fmt'd, ... */ + pstr_fmt--; /* ... replace last lead char w/ ... */ + } + *pstr_fmt++ = '-'; /* ... prepend neg sign (see Notes #2b & #3b). */ + nbr_neg_fmtd = DEF_YES; + } + + if (nbr_shiftd > 0) { /* If shifted nbr > 0, ... */ + dig_val = (CPU_INT08U)(nbr_shiftd % 10u); + *pstr_fmt++ = (CPU_CHAR )(dig_val + '0'); + + nbr_dig_sig++; /* ... inc nbr sig digs; ... */ + + } else if ((nbr_dig > 1) || /* ... else if req'd digs > 1 ... */ + (nbr_neg == DEF_NO)) { /* ... or non-neg nbr, ... */ + *pstr_fmt++ = '0'; /* ... fmt one '0' char (see Note #3c5). */ + } + + } else if ((nbr_neg == DEF_YES) && /* ... else if nbr neg ... */ + (lead_char_0 == DEF_YES) && /* ... & lead char a '0' dig ... */ + (nbr_neg_fmtd == DEF_NO )) { /* ... but neg sign NOT yet fmt'd, ... */ + + *pstr_fmt++ = '-'; /* ... prepend neg sign (see Note #3b); ... */ + nbr_neg_fmtd = DEF_YES; + + } else if (lead_char != (CPU_CHAR)'\0') { /* ... else if avail, ... */ + *pstr_fmt++ = lead_char; /* ... fmt lead char. */ + lead_char_fmtd = DEF_YES; + } + + dig_exp /= 10.0f; /* Shift to next least-sig dig. */ + + } else { /* ... else append non-sig 0's (see Note #2c2). */ + *pstr_fmt++ = '0'; + } + + } else { /* Else fmt '?' for invalid str (see Note #7). */ + *pstr_fmt++ = '?'; + } + } + + + if (nbr_dp > 0) { /* Fmt str for desired nbr dp : */ + if (nbr_dig < 1) { /* If NO digs fmt'd; ... */ + if (fmt_invalid == DEF_NO) { /* ... nbr fmt valid, ... */ + if ((nbr_neg == DEF_YES) && /* ... nbr neg ... */ + (nbr_neg_fmtd == DEF_NO )) { /* ... but neg sign NOT yet fmt'd, ... */ + *pstr_fmt++ = '-'; /* ... prepend neg sign (see Notes #2b & #3b); ... */ + } else { /* ... else prepend 1 dig of '0' (see Note #3c5) ... */ + *pstr_fmt++ = '0'; + } + } else { /* ... else fmt '?' for invalid str (see Note #7). */ + *pstr_fmt++ = '?'; + } + } + + if (fmt_invalid == DEF_NO) { /* If nbr fmt valid, ... */ + *pstr_fmt++ = '.'; /* ... append dp prior to dp conversion. */ + } else { /* Else fmt '?' for invalid str (see Note #7). */ + *pstr_fmt++ = '?'; + } + + dp_exp = 10.0f; + for (i = 0u; i < nbr_dp; i++) { + if (fmt_invalid == DEF_NO) { + /* If nbr sig digs < max, fmt str dps; ... */ + if (nbr_dig_sig < LIB_STR_CFG_FP_MAX_NBR_DIG_SIG) { + nbr_shiftd = (CPU_INT32U)(nbr_fmt * dp_exp); + dig_val = (CPU_INT08U)(nbr_shiftd % 10u); + *pstr_fmt++ = (CPU_CHAR )(dig_val + '0'); + dp_exp *= 10.0f; /* Shift to next least-sig dp. */ + + if ((nbr_shiftd > 0) || /* If shifted nbr > 0 ... */ + (nbr_dig_sig > 0)) { /* ... OR > 0 sig digs already fmt'd, ... */ + nbr_dig_sig++; /* ... inc nbr sig digs. */ + } + + } else { /* ... else append non-sig 0's (see Note #2c2). */ + *pstr_fmt++ = '0'; + } + + } else { /* Else fmt '?' for invalid str (see Note #7). */ + *pstr_fmt++ = '?'; + } + } + } + + + if (nul != DEF_NO) { /* If NOT DISABLED, append NULL char (see Note #4). */ + *pstr_fmt = (CPU_CHAR)'\0'; + } + + + if (fmt_invalid != DEF_NO) { /* Rtn NULL for invalid str fmt (see Notes #6a - #6d). */ + return ((CPU_CHAR *)0); + } + + + return (pstr); /* Rtn ptr to fmt'd str (see Note #6e). */ +} +#endif + + +/* +********************************************************************************************************* +* Str_ParseNbr_Int32U() +* +* Description : Parse 32-bit unsigned integer from string. +* +* Argument(s) : pstr Pointer to string (see Notes #1 & #2a). +* +* pstr_next Optional pointer to a variable to ... : +* +* (a) Return a pointer to first character following the integer string, +* if NO error(s) [see Note #2a2B2]; +* (b) Return a pointer to 'pstr', +* otherwise (see Note #2a2A2). +* +* nbr_base Base of number to parse (see Notes #2a1B1 & #2a2B1). +* +* Return(s) : Parsed integer, if integer parsed with NO overflow (see Note #2a3A). +* +* DEF_INT_32U_MAX_VAL, if integer parsed but overflowed (see Note #2a3A1). +* +* 0, otherwise (see Note #2a3B). +* +* Caller(s) : Application. +* +* Note(s) : (1) String buffer NOT modified. +* +* (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strtoul() : DESCRIPTION' states that "these +* functions shall convert the initial portion of the string pointed to by 'str' ('pstr') +* to a type unsigned long ... representation" : +* +* (1) "First, they decompose the input string into three parts" : +* +* (A) "An initial, possibly empty, sequence of white-space characters [as specified +* by isspace()]." +* +* (1) "The subject sequence is defined as the longest initial subsequence of the +* input string, starting with the first non-white-space character that is of +* the expected form. The subject sequence shall contain no characters if the +* input string is empty or consists entirely of white-space characters." +* +* (B) (1) "A subject sequence interpreted as an integer represented in some radix +* determined by the value of 'base' ('nbr_base')" : +* +* (a) "If the value of 'base' ('nbr_base') is 0, the expected form of the +* subject sequence is that of a decimal constant, octal constant, or +* hexadecimal constant" : +* +* (1) "A decimal constant begins with a non-zero digit, and consists of a +* sequence of decimal digits." +* +* (2) "An octal constant consists of the prefix '0' optionally followed by +* a sequence of the digits '0' to '7' only." +* +* (3) "A hexadecimal constant consists of the prefix '0x' or '0X' followed +* by a sequence of the decimal digits and letters 'a' (or 'A') to 'f' +* (or 'F') with values 10 to 15 respectively." +* +* (b) "If the value of 'base' ('nbr_base') is between 2 and 36, the expected form +* of the subject sequence is a sequence of letters and digits representing +* an integer with the radix specified by 'base' ('nbr_base')" : +* +* (1) (A) "The letters from 'a' (or 'A') to 'z' (or 'Z') inclusive are +* ascribed the values 10 to 35"; ... +* (B) "only letters whose ascribed values are less than that of base +* are permitted." +* +* (2) (A) "If the value of 'base' ('nbr_base') is 16, the characters '0x' or +* '0X' may optionally precede the sequence of letters and digits." +* +* (B) Although NO specification states that "if the value of 'base' +* ('nbr_base') is" 8, the '0' character "may optionally precede +* the sequence of letters and digits"; it seems reasonable to +* allow the '0' character to be optionally parsed. +* +* (2) "A subject sequence .... may be preceded by a '+' or '-' sign." +* +* (a) However, it does NOT seem reasonable to parse & convert a negative number +* integer string into an unsigned integer. +* +* (C) (1) (a) "A final string of one or more unrecognized characters," ... +* (b) "including the terminating null byte of the input string" ... +* (2) "other than a sign or a permissible letter or digit." +*$PAGE* +* (2) Second, "they shall attempt to convert the subject sequence to an unsigned integer" : +* +* (A) "If the subject sequence is empty or does not have the expected form" : +* +* (1) "no conversion [is] performed"; ... +* (2) "the value of 'str' ('pstr') [is] stored in the object pointed to by 'endptr' +* ('pstr_next'), provided that 'endptr' ('pstr_next') is not a null pointer." +* +* (B) "If the subject sequence has the expected form" : +* +* (1) (a) "and the value of 'base' ('nbr_base') is 0, the sequence of characters +* starting with the first digit shall be interpreted as an integer constant." +* +* (b) "and the value of 'base' ('nbr_base') is between 2 and 36, it shall be +* used as the base for conversion, ascribing to each letter its value as +* given above" (see Note #2a1B1b1A). +* +* (2) "A pointer to the final string shall be stored in the object pointed to by +* 'endptr' ('pstr_next'), provided that 'endptr' ('pstr_next') is not a null +* pointer." +* +* (3) Lastly, IEEE Std 1003.1, 2004 Edition, Section 'strtoul() : RETURN VALUE' states that : +* +* (A) "Upon successful completion, these functions shall return the converted value." +* (1) "If the correct value is outside the range of representable values, {ULONG_MAX} +* ... shall be returned." +* +* (B) "If no conversion could be performed, 0 shall be returned." +* +* (b) (1) IEEE Std 1003.1, 2004 Edition, Section 'strtoul() : ERRORS' states that "these functions +* shall fail if" : +* +* (A) "[EINVAL] - The value of 'base' ('nbr_base') is not supported." +* +* (B) "[ERANGE] - The value to be returned is not representable." +* +* (2) IEEE Std 1003.1, 2004 Edition, Section 'strtoul() : ERRORS' states that "these functions +* may fail if" : +* +* (A) "[EINVAL] - No conversion could be performed." +* +* (3) Return integer value & next string pointer should be used to diagnose parse success or failure : +* +* (a) Valid parse string integer : +* +* pstr = " ABCDE xyz" +* nbr_base = 16 +* +* nbr = 703710 +* pstr_next = " xyz" +* +* +* (b) Invalid parse string integer : +* +* pstr = " ABCDE" +* nbr_base = 10 +* +* nbr = 0 +* pstr_next = pstr = " ABCDE" +* +* +* (c) Valid hexadecimal parse string integer : +* +* pstr = " 0xGABCDE" +* nbr_base = 16 +* +* nbr = 0 +* pstr_next = "xGABCDE" +* +* +* (d) Valid decimal parse string integer ('0x' prefix ignored +* following invalid hexadecimal characters) : +* +* pstr = " 0xGABCDE" +* nbr_base = 0 +* +* nbr = 0 +* pstr_next = "xGABCDE" +* +* +* (e) Valid decimal parse string integer ('0' prefix ignored +* following invalid octal characters) : +* +* pstr = " 0GABCDE" +* nbr_base = 0 +* +* nbr = 0 +* pstr_next = "GABCDE" +* +*$PAGE* +* (f) Parse string integer overflow : +* +* pstr = " 12345678901234567890*123456" +* nbr_base = 10 +* +* nbr = DEF_INT_32U_MAX_VAL +* pstr_next = "*123456" +* +* +* (g) Invalid negative unsigned parse string : +* +* pstr = " -12345678901234567890*123456" +* nbr_base = 10 +* +* nbr = 0 +* pstr_next = pstr = " -12345678901234567890*123456" +* +********************************************************************************************************* +*/ + +CPU_INT32U Str_ParseNbr_Int32U (const CPU_CHAR *pstr, + CPU_CHAR **pstr_next, + CPU_INT08U nbr_base) +{ + CPU_INT32U nbr; + + + nbr = Str_ParseNbr_Int32( pstr, /* Parse/convert str ... */ + pstr_next, + nbr_base, + DEF_NO, /* ... as unsigned int (see Note #2a2). */ + (CPU_BOOLEAN *)0); + + return (nbr); +} + + +/* +********************************************************************************************************* +* Str_ParseNbr_Int32S() +* +* Description : Parse 32-bit signed integer from string. +* +* Argument(s) : pstr Pointer to string (see Notes #1 & #2a). +* +* pstr_next Optional pointer to a variable to ... : +* +* (a) Return a pointer to first character following the integer string, +* if NO error(s) [see Note #2a2B2]; +* (b) Return a pointer to 'pstr', +* otherwise (see Note #2a2A2). +* +* nbr_base Base of number to parse (see Notes #2a1B1 & #2a2B1). +* +* Return(s) : Parsed integer, if integer parsed with NO over- or underflow (see Note #2a3A). +* +* DEF_INT_32S_MIN_VAL, if integer parsed but negatively underflowed (see Note #2a3A1a). +* +* DEF_INT_32U_MAX_VAL, if integer parsed but positively overflowed (see Note #2a3A1b). +* +* 0, otherwise (see Note #2a3B). +* +* Caller(s) : Application. +* +* Note(s) : (1) String buffer NOT modified. +* +* (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strtol() : DESCRIPTION' states that "these +* functions shall convert the initial portion of the string pointed to by 'str' ('pstr') +* to a type long ... representation" : +* +* (1) "First, they decompose the input string into three parts" : +* +* (A) "An initial, possibly empty, sequence of white-space characters [as specified +* by isspace()]." +* +* (1) "The subject sequence is defined as the longest initial subsequence of the +* input string, starting with the first non-white-space character that is of +* the expected form. The subject sequence shall contain no characters if the +* input string is empty or consists entirely of white-space characters." +* +* (B) (1) "A subject sequence interpreted as an integer represented in some radix +* determined by the value of 'base' ('nbr_base')" : +* +* (a) "If the value of 'base' ('nbr_base') is 0, the expected form of the +* subject sequence is that of a decimal constant, octal constant, or +* hexadecimal constant" : +* +* (1) "A decimal constant begins with a non-zero digit, and consists of a +* sequence of decimal digits." +* +* (2) "An octal constant consists of the prefix '0' optionally followed by +* a sequence of the digits '0' to '7' only." +* +* (3) "A hexadecimal constant consists of the prefix '0x' or '0X' followed +* by a sequence of the decimal digits and letters 'a' (or 'A') to 'f' +* (or 'F') with values 10 to 15 respectively." +* +* (b) "If the value of 'base' ('nbr_base') is between 2 and 36, the expected form +* of the subject sequence is a sequence of letters and digits representing +* an integer with the radix specified by 'base' ('nbr_base')" : +* +* (1) (A) "The letters from 'a' (or 'A') to 'z' (or 'Z') inclusive are +* ascribed the values 10 to 35"; ... +* (B) "only letters whose ascribed values are less than that of base +* are permitted." +* +* (2) (A) "If the value of 'base' ('nbr_base') is 16, the characters '0x' or +* '0X' may optionally precede the sequence of letters and digits." +* +* (B) Although NO specification states that "if the value of 'base' +* ('nbr_base') is" 8, the '0' character "may optionally precede +* the sequence of letters and digits"; it seems reasonable to +* allow the '0' character to be optionally parsed. +* +* (2) "A subject sequence .... may be preceded by a '+' or '-' sign." +* +* (a) However, it does NOT seem reasonable to parse & convert a negative number +* integer string into an unsigned integer. +* +* (C) (1) (a) "A final string of one or more unrecognized characters," ... +* (b) "including the terminating null byte of the input string" ... +* (2) "other than a sign or a permissible letter or digit." +*$PAGE* +* (2) Second, "they shall attempt to convert the subject sequence to an integer" : +* +* (A) "If the subject sequence is empty or does not have the expected form" : +* +* (1) "no conversion is performed"; ... +* (2) "the value of 'str' ('pstr') is stored in the object pointed to by 'endptr' +* ('pstr_next'), provided that 'endptr' ('pstr_next') is not a null pointer." +* +* (B) "If the subject sequence has the expected form" : +* +* (1) (a) "and the value of 'base' ('nbr_base') is 0, the sequence of characters +* starting with the first digit shall be interpreted as an integer constant." +* +* (b) "and the value of 'base' ('nbr_base') is between 2 and 36, it shall be +* used as the base for conversion, ascribing to each letter its value as +* given above" (see Note #2a1B1b1A). +* +* (2) "A pointer to the final string shall be stored in the object pointed to by +* 'endptr' ('pstr_next'), provided that 'endptr' ('pstr_next') is not a null +* pointer." +* +* (3) Lastly, IEEE Std 1003.1, 2004 Edition, Section 'strtol() : RETURN VALUE' states that : +* +* (A) "Upon successful completion, these functions shall return the converted value." +* +* (1) "If the correct value is outside the range of representable values", either +* of the following "shall be returned" : +* (a) "{LONG_MIN}" or ... +* (b) "{LONG_MAX}" +* +* (B) "If no conversion could be performed, 0 shall be returned." +* +* (b) (1) IEEE Std 1003.1, 2004 Edition, Section 'strtoul() : ERRORS' states that "these functions +* shall fail if" : +* +* (A) "[EINVAL] - The value of 'base' ('nbr_base') is not supported." +* +* (B) "[ERANGE] - The value to be returned is not representable." +* +* (2) IEEE Std 1003.1, 2004 Edition, Section 'strtoul() : ERRORS' states that "these functions +* may fail if" : +* +* (A) "[EINVAL] - No conversion could be performed." +* +* (3) Return integer value & next string pointer should be used to diagnose parse success or failure : +* +* (a) Valid parse string integer : +* +* pstr = " ABCDE xyz" +* nbr_base = 16 +* +* nbr = 703710 +* pstr_next = " xyz" +* +* +* (b) Invalid parse string integer : +* +* pstr = " ABCDE" +* nbr_base = 10 +* +* nbr = 0 +* pstr_next = pstr = " ABCDE" +* +* +* (c) Valid hexadecimal parse string integer : +* +* pstr = " 0xGABCDE" +* nbr_base = 16 +* +* nbr = 0 +* pstr_next = "xGABCDE" +* +* +* (d) Valid decimal parse string integer ('0x' prefix ignored +* following invalid hexadecimal characters) : +* +* pstr = " 0xGABCDE" +* nbr_base = 0 +* +* nbr = 0 +* pstr_next = "xGABCDE" +* +* +* (e) Valid decimal parse string integer ('0' prefix ignored +* following invalid octal characters) : +* +* pstr = " 0GABCDE" +* nbr_base = 0 +* +* nbr = 0 +* pstr_next = "GABCDE" +* +*$PAGE* +* (f) Parse string integer overflow : +* +* pstr = " 12345678901234567890*123456" +* nbr_base = 10 +* +* nbr = DEF_INT_32S_MAX_VAL +* pstr_next = "*123456" +* +* +* (g) Parse string integer underflow : +* +* pstr = " -12345678901234567890*123456" +* nbr_base = 10 +* +* nbr = DEF_INT_32S_MIN_VAL +* pstr_next = "*123456" +* +********************************************************************************************************* +*/ + +CPU_INT32S Str_ParseNbr_Int32S (const CPU_CHAR *pstr, + CPU_CHAR **pstr_next, + CPU_INT08U nbr_base) +{ + CPU_INT32S nbr; + CPU_INT32U nbr_abs; + CPU_BOOLEAN nbr_neg; + + + nbr_abs = Str_ParseNbr_Int32(pstr, /* Parse/convert str ... */ + pstr_next, + nbr_base, + DEF_YES, /* ... as signed int (see Note #2a2). */ + &nbr_neg); + + if (nbr_neg == DEF_NO) { /* Chk for neg nbr & ovf/undf (see Note #2a3A1). */ + nbr = (nbr_abs > (CPU_INT32U) DEF_INT_32S_MAX_VAL) ? (CPU_INT32S)DEF_INT_32S_MAX_VAL + : (CPU_INT32S)nbr_abs; + } else { + nbr = (nbr_abs > (CPU_INT32U)-DEF_INT_32S_MIN_VAL_ONES_CPL) ? (CPU_INT32S)DEF_INT_32S_MIN_VAL + : -(CPU_INT32S)nbr_abs; + } + + return (nbr); +} + + +/* +********************************************************************************************************* +********************************************************************************************************* +* LOCAL FUNCTIONS +********************************************************************************************************* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* Str_FmtNbr_Int32() +* +* Description : Format 32-bit integer into a multi-digit character string. +* +* Argument(s) : nbr Number to format. +* +* nbr_dig Number of digits to format (see Note #1). +* +* nbr_base Base of number to format (see Note #2). +* +* nbr_neg Indicates whether number to format is negative : +* ------- +* DEF_NO Number is non-negative. +* DEF_YES Number is negative. +* +* Argument validated in Str_FmtNbr_Int32U(), +* Str_FmtNbr_Int32S(). +* +* lead_char Prepend leading character (see Note #3) : +* +* '\0' Do NOT prepend leading character to string. +* Printable character Prepend leading character to string. +* Unprintable character Format invalid string (see Note #6e). +* +* lower_case Format alphabetic characters (if any) in lower case : +* +* DEF_NO Format alphabetic characters in upper case. +* DEF_YES Format alphabetic characters in lower case. +* +* nul Append terminating NULL-character (see Note #4) : +* +* DEF_NO Do NOT append terminating NULL-character to string. +* DEF_YES Append terminating NULL-character to string. +* +* pstr Pointer to character array to return formatted number string (see Note #5). +* +* Return(s) : Pointer to formatted string, if NO error(s) [see Note #6f]. +* +* Pointer to NULL, otherwise. +* +* Caller(s) : Str_FmtNbr_Int32U(), +* Str_FmtNbr_Int32S(). +*$PAGE* +* Note(s) : (1) (a) The maximum number of digits to format for 32-bit integer numbers : +* +* +* Maximum Number of [ log (Number) ] +* 32-bit Integer Digits = floor [ -------------- + 1 ] +* to Format [ log (Base) ] +* +* where +* Number Number to format +* Base Base of number to format +* +* (b) (1) If the number of digits to format ('nbr_dig') is zero; then NO formatting +* is performed except possible NULL-termination of the string (see Note #4). +* +* Example : +* +* nbr = -23456 +* nbr_dig = 0 +* nbr_base = 10 +* +* pstr = "" See Note #7a +* +* (2) If the number of digits to format ('nbr_dig') is less than the number of +* significant integer digits of the number to format ('nbr'); then an invalid +* string is formatted instead of truncating any significant integer digits. +* +* Example : +* +* nbr = 23456 +* nbr_dig = 3 +* nbr_base = 10 +* +* pstr = "???" See Note #7b +* +* (3) If the number to format ('nbr') is negative but the number of digits to format +* ('nbr_dig') is equal to the number of significant integer digits of the number +* to format ('nbr'); then an invalid string is formatted instead of truncating +* the negative sign. +* +* Example : +* +* nbr = -23456 +* nbr_dig = 5 +* nbr_base = 10 +* +* pstr = "?????" See Note #7b +* +* (2) The number's base MUST be between 2 & 36, inclusive. +*$PAGE* +* (3) Leading character option prepends leading characters prior to the first non-zero digit. +* +* (a) (1) Leading character MUST be a printable ASCII character. +* +* (2) (A) Leading character MUST NOT be a number base digit, ... +* (B) with the exception of '0'. +* +* (b) (1) The number of leading characters is such that the total number of significant +* integer digits plus the number of leading characters plus possible negative +* sign character is equal to the requested number of integer digits to format +* ('nbr_dig'). +* +* Examples : +* +* nbr = 23456 +* nbr_dig = 7 +* nbr_base = 10 +* lead_char = ' ' +* +* pstr = " 23456" +* +* +* nbr = -23456 +* nbr_dig = 7 +* nbr_base = 10 +* lead_char = ' ' +* +* pstr = " -23456" +* +* (2) (A) If the number to format ('nbr') is negative AND the leading character +* ('lead_char') is a '0' digit; then the negative sign character +* prefixes all leading characters prior to the formatted number. +* +* Examples : +* +* nbr = -23456 +* nbr_dig = 8 +* nbr_base = 10 +* lead_char = '0' +* +* pstr = "-0023456" +* +* +* nbr = -43981 +* nbr_dig = 8 +* nbr_base = 16 +* lead_char = '0' +* lower_case = DEF_NO +* +* pstr = "-000ABCD" +* +* (B) If the number to format ('nbr') is negative AND the leading character +* ('lead_char') is NOT a '0' digit; then the negative sign character +* immediately prefixes the most significant digit of the formatted number. +* +* Examples : +* +* nbr = -23456 +* nbr_dig = 8 +* nbr_base = 10 +* lead_char = '#' +* +* pstr = "##-23456" +* +* +* nbr = -43981 +* nbr_dig = 8 +* nbr_base = 16 +* lead_char = '#' +* lower_case = DEF_YES +* +* pstr = "###-abcd" +* +* (c) (1) If the value of the number to format is zero ... +* (2) ... & the number of digits to format is non-zero, ... +* (3) ... but NO leading character available; ... +* (4) ... then one digit of '0' value is formatted. +* +* This is NOT a leading character; but a single integer digit of '0' value. +*$PAGE* +* (4) (a) NULL-character terminate option DISABLED prevents overwriting previous character +* array formatting. +* +* (b) WARNING: Unless 'pstr' character array is pre-/post-terminated, NULL-character +* terminate option DISABLED will cause character string run-on. +* +* (5) (a) Format buffer size NOT validated; buffer overruns MUST be prevented by caller. +* +* (b) To prevent character buffer overrun : +* +* Character array size MUST be >= ('nbr_dig' + +* 1 negative sign + +* 1 'NUL' terminator) characters +* +* (6) String format terminates when : +* +* (a) Format string pointer is passed a NULL pointer. +* (1) No string formatted; NULL pointer returned. +* +* (b) Number of digits to format ('nbr_dig') is zero. +* (1) NULL string formatted (see Note #7a); NULL pointer returned. +* +* (c) Number of digits to format ('nbr_dig') is less than number of significant +* integer digits of the number to format ('nbr'), including possible +* negative sign. +* (1) Invalid string formatted (see Note #7); NULL pointer returned. +* +* (d) Base is passed an invalid base (see Note #2). +* (1) Invalid string format performed; NULL pointer returned. +* +* (e) Lead character is NOT a valid, printable character (see Note #3a). +* (1) Invalid string formatted (see Note #7); NULL pointer returned. +* +* (f) Number successfully formatted into character string array. +* +* (7) For any unsuccessful string format or error(s), an invalid string of question marks +* ('?') will be formatted, where the number of question marks is determined by the +* number of digits to format ('nbr_dig') : +* +* Invalid string's { (a) 0 (NULL string) , if 'nbr_dig' = 0 +* number of = { +* question marks { (b) 'nbr_dig' , if 'nbr_dig' > 0 +* +********************************************************************************************************* +*/ + +static CPU_CHAR *Str_FmtNbr_Int32 (CPU_INT32U nbr, + CPU_INT08U nbr_dig, + CPU_INT08U nbr_base, + CPU_BOOLEAN nbr_neg, + CPU_CHAR lead_char, + CPU_BOOLEAN lower_case, + CPU_BOOLEAN nul, + CPU_CHAR *pstr) +{ + CPU_CHAR *pstr_fmt; + CPU_DATA i; + CPU_INT32U nbr_fmt; + CPU_INT32U nbr_log; + CPU_INT08U nbr_dig_max; + CPU_INT08U nbr_dig_min; + CPU_INT08U nbr_dig_fmtd; + CPU_INT08U nbr_neg_sign; + CPU_INT08U nbr_lead_char; + CPU_INT08U dig_val; + CPU_INT08U lead_char_delta_0; + CPU_INT08U lead_char_delta_a; + CPU_BOOLEAN lead_char_dig; + CPU_BOOLEAN lead_char_0; + CPU_BOOLEAN fmt_invalid; + CPU_BOOLEAN print_char; + CPU_BOOLEAN nbr_neg_fmtd; + + + /* ---------------- VALIDATE FMT ARGS ----------------- */ + if (pstr == (CPU_CHAR *)0) { /* Rtn NULL if str ptr NULL (see Note #6a). */ + return ((CPU_CHAR *)0); + } + + fmt_invalid = DEF_NO; + lead_char_0 = DEF_NO; + + if (nbr_dig < 1) { /* If nbr digs = 0, ... */ + fmt_invalid = DEF_YES; /* ... fmt invalid str (see Note #6b). */ + } + /* If invalid base, ... */ + if ((nbr_base < 2u) || + (nbr_base > 36u)) { + fmt_invalid = DEF_YES; /* ... fmt invalid str (see Note #6d). */ + } + + if (lead_char != (CPU_CHAR)'\0') { + print_char = ASCII_IsPrint(lead_char); + if (print_char != DEF_YES) { /* If lead char non-printable (see Note #3a1), ... */ + fmt_invalid = DEF_YES; /* ... fmt invalid str (see Note #6e). */ + + } else if (lead_char != '0') { /* Chk lead char for non-0 nbr base dig. */ + lead_char_delta_0 = (CPU_INT08U)(lead_char - '0'); + if (lower_case != DEF_YES) { + lead_char_delta_a = (CPU_INT08U)(lead_char - 'A'); + } else { + lead_char_delta_a = (CPU_INT08U)(lead_char - 'a'); + } + + lead_char_dig = (((nbr_base <= 10u) && (lead_char_delta_0 < nbr_base)) || + ((nbr_base > 10u) && ((lead_char_delta_0 < 10u) || + (lead_char_delta_a < (nbr_base - 10u))))) ? DEF_YES : DEF_NO; + + if (lead_char_dig == DEF_YES) { /* If lead char non-0 nbr base dig (see Note #3a2A), ...*/ + fmt_invalid = DEF_YES; /* ... fmt invalid str (see Note #6e). */ + } + } + } + + + /* ----------------- PREPARE NBR FMT ------------------ */ + pstr_fmt = pstr; + lead_char_0 = DEF_NO; + + if (fmt_invalid == DEF_NO) { + nbr_fmt = nbr; + nbr_log = nbr; + nbr_dig_max = 1u; + while (nbr_log >= nbr_base) { /* While nbr base digs avail, ... */ + nbr_dig_max++; /* ... calc max nbr digs. */ + nbr_log /= nbr_base; + } + + nbr_neg_sign = (nbr_neg == DEF_YES) ? 1u : 0u; + if (nbr_dig >= (nbr_dig_max + nbr_neg_sign)) { /* If req'd nbr digs >= (max nbr digs + neg sign), ... */ + nbr_neg_fmtd = DEF_NO; + nbr_dig_min = DEF_MIN(nbr_dig_max, nbr_dig); + /* ... calc nbr digs to fmt & nbr lead chars. */ + if (lead_char != (CPU_CHAR)'\0') { + nbr_dig_fmtd = nbr_dig; + nbr_lead_char = nbr_dig - + nbr_dig_min - nbr_neg_sign; + } else { + nbr_dig_fmtd = nbr_dig_min + nbr_neg_sign; + nbr_lead_char = 0u; + } + + if (nbr_lead_char > 0) { /* If lead chars to fmt, ... */ + lead_char_0 = (lead_char == '0') /* ... chk if lead char a '0' dig (see Note #3a2B). */ + ? DEF_YES : DEF_NO; + } + + } else { /* Else if nbr trunc'd, ... */ + fmt_invalid = DEF_YES; /* ... fmt invalid str (see Note #6c). */ + } + } + + if (fmt_invalid != DEF_NO) { + nbr_dig_fmtd = nbr_dig; + } + + + /* ------------------- FMT NBR STR -------------------- */ + pstr_fmt += nbr_dig_fmtd; /* Start fmt @ least-sig dig. */ + + if (nul != DEF_NO) { /* If NOT DISABLED, append NULL char (see Note #4). */ + *pstr_fmt = (CPU_CHAR)'\0'; + } + pstr_fmt--; + + + for (i = 0u; i < nbr_dig_fmtd; i++) { /* Fmt str for desired nbr digs : */ + if (fmt_invalid == DEF_NO) { + if ((nbr_fmt > 0) || /* If fmt nbr > 0 ... */ + (i == 0u)) { /* ... OR on one's dig to fmt (see Note #3c1), ... */ + /* ... calc & fmt dig val; ... */ + dig_val = (CPU_INT08U)(nbr_fmt % nbr_base); + if (dig_val < 10u) { + *pstr_fmt-- = (CPU_CHAR)(dig_val + '0'); + } else { + if (lower_case != DEF_YES) { + *pstr_fmt-- = (CPU_CHAR)((dig_val - 10u) + 'A'); + } else { + *pstr_fmt-- = (CPU_CHAR)((dig_val - 10u) + 'a'); + } + } + + nbr_fmt /= nbr_base; /* Shift to next more-sig dig. */ + + } else if ((nbr_neg == DEF_YES) && /* ... else if nbr neg AND ... */ + (((lead_char_0 == DEF_NO ) && /* ... lead char NOT a '0' dig ... */ + (nbr_neg_fmtd == DEF_NO )) || /* ... but neg sign NOT yet fmt'd OR ... */ + ((lead_char_0 != DEF_NO ) && /* ... lead char is a '0' dig ... */ + (i == (nbr_dig_fmtd - 1u))))) { /* ... & on most-sig dig to fmt, ... */ + + *pstr_fmt-- = '-'; /* ... prepend neg sign (see Note #3b); ... */ + nbr_neg_fmtd = DEF_YES; + + } else if (lead_char != (CPU_CHAR)'\0') { /* ... else if avail, ... */ + *pstr_fmt-- = lead_char; /* ... fmt lead char. */ + } + + } else { /* Else fmt '?' for invalid str (see Note #7). */ + *pstr_fmt-- = '?'; + } + } + + + if (fmt_invalid != DEF_NO) { /* Rtn NULL for invalid str fmt (see Notes #6a - #6e). */ + return ((CPU_CHAR *)0); + } + + + return (pstr); /* Rtn ptr to fmt'd str (see Note #6f). */ +} + + +/* +********************************************************************************************************* +* Str_ParseNbr_Int32() +* +* Description : Parse 32-bit integer from string. +* +* Argument(s) : pstr Pointer to string (see Notes #1 & #2a). +* +* pstr_next Optional pointer to a variable to ... : +* +* (a) Return a pointer to first character following the integer string, +* if NO error(s) [see Note #2a2B2]; +* (b) Return a pointer to 'pstr', +* otherwise (see Note #2a2A2). +* +* nbr_base Base of number to parse (see Notes #2a1B1 & #2a2B1). +* +* nbr_signed Indicates whether number to parse is signed : +* +* DEF_NO Number is unsigned. +* DEF_YES Number is signed. +* +* pnbr_neg Pointer to a variable to return if the parsed (signed) number is negative : +* +* DEF_NO Number is non-negative. +* DEF_YES Number is negative. +* +* Return(s) : Parsed integer, if integer parsed with NO overflow (see Note #2a3A). +* +* DEF_INT_32U_MAX_VAL, if integer parsed but overflowed (see Note #2a3A1). +* +* 0, otherwise (see Note #2a3B). +* +* Caller(s) : Str_ParseNbr_Int32U(), +* Str_ParseNbr_Int32S(). +* +* Note(s) : (1) String buffer NOT modified. +* +* (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strtol() : DESCRIPTION' states that "these +* functions shall convert the initial portion of the string pointed to by 'str' ('pstr') +* to a type long ... representation" : +* +* (1) "First, they decompose the input string into three parts" : +* +* (A) "An initial, possibly empty, sequence of white-space characters [as specified +* by isspace()]." +* +* (1) "The subject sequence is defined as the longest initial subsequence of the +* input string, starting with the first non-white-space character that is of +* the expected form. The subject sequence shall contain no characters if the +* input string is empty or consists entirely of white-space characters." +* +* (B) (1) "A subject sequence interpreted as an integer represented in some radix +* determined by the value of 'base' ('nbr_base')" : +* +* (a) "If the value of 'base' ('nbr_base') is 0, the expected form of the +* subject sequence is that of a decimal constant, octal constant, or +* hexadecimal constant" : +* +* (1) "A decimal constant begins with a non-zero digit, and consists of a +* sequence of decimal digits." +* +* (2) "An octal constant consists of the prefix '0' optionally followed by +* a sequence of the digits '0' to '7' only." +* +* (3) "A hexadecimal constant consists of the prefix '0x' or '0X' followed +* by a sequence of the decimal digits and letters 'a' (or 'A') to 'f' +* (or 'F') with values 10 to 15 respectively." +* +* (b) "If the value of 'base' ('nbr_base') is between 2 and 36, the expected form +* of the subject sequence is a sequence of letters and digits representing +* an integer with the radix specified by 'base' ('nbr_base')" : +* +* (1) (A) "The letters from 'a' (or 'A') to 'z' (or 'Z') inclusive are +* ascribed the values 10 to 35"; ... +* (B) "only letters whose ascribed values are less than that of base +* are permitted." +* +* (2) (A) "If the value of 'base' ('nbr_base') is 16, the characters '0x' or +* '0X' may optionally precede the sequence of letters and digits." +* +* (B) Although NO specification states that "if the value of 'base' +* ('nbr_base') is" 8, the '0' character "may optionally precede +* the sequence of letters and digits"; it seems reasonable to +* allow the '0' character to be optionally parsed. +*$PAGE* +* (2) "A subject sequence .... may be preceded by a '+' or '-' sign." +* +* (a) It does NOT seem reasonable to parse & convert a negative number +* integer string into an unsigned integer. However, a negative sign +* for an unsigned integer will automatically be parsed as an invalid +* character (see Note #2aC1). +* +* (C) (1) (a) "A final string of one or more unrecognized characters," ... +* (b) "including the terminating null byte of the input string" ... +* (2) "other than a sign or a permissible letter or digit." +* +* (2) Second, "they shall attempt to convert the subject sequence to an integer" : +* +* (A) "If the subject sequence is empty or does not have the expected form" : +* +* (1) "no conversion is performed"; ... +* (2) "the value of 'str' ('pstr') is stored in the object pointed to by 'endptr' +* ('pstr_next'), provided that 'endptr' ('pstr_next') is not a null pointer." +* +* (B) "If the subject sequence has the expected form" : +* +* (1) (a) "and the value of 'base' ('nbr_base') is 0, the sequence of characters +* starting with the first digit shall be interpreted as an integer constant." +* +* (b) "and the value of 'base' ('nbr_base') is between 2 and 36, it shall be +* used as the base for conversion, ascribing to each letter its value as +* given above" (see Note #2a1B1b1A). +* +* (2) "A pointer to the final string shall be stored in the object pointed to by +* 'endptr' ('pstr_next'), provided that 'endptr' ('pstr_next') is not a null +* pointer." +* +* (3) Lastly, IEEE Std 1003.1, 2004 Edition, Section 'strtol() : RETURN VALUE' states that : +* +* (A) "Upon successful completion, these functions shall return the converted value." +* (1) "If the correct value is outside the range of representable values, {LONG_MIN} +* [or] {LONG_MAX} ... shall be returned." +* +* (B) "If no conversion could be performed, 0 shall be returned." +* +* (b) (1) IEEE Std 1003.1, 2004 Edition, Section 'strtoul() : ERRORS' states that "these functions +* shall fail if" : +* +* (A) "[EINVAL] - The value of 'base' ('nbr_base') is not supported." +* +* (B) "[ERANGE] - The value to be returned is not representable." +* +* (2) IEEE Std 1003.1, 2004 Edition, Section 'strtoul() : ERRORS' states that "these functions +* may fail if" : +* +* (A) "[EINVAL] - No conversion could be performed." +*$PAGE* +* (3) Return integer value & next string pointer should be used to diagnose parse success or failure : +* +* (a) Valid parse string integer : +* +* pstr = " ABCDE xyz" +* nbr_base = 16 +* +* nbr = 703710 +* pstr_next = " xyz" +* +* +* (b) Invalid parse string integer : +* +* pstr = " ABCDE" +* nbr_base = 10 +* +* nbr = 0 +* pstr_next = pstr = " ABCDE" +* +* +* (c) Valid hexadecimal parse string integer : +* +* pstr = " 0xGABCDE" +* nbr_base = 16 +* +* nbr = 0 +* pstr_next = "xGABCDE" +* +* +* (d) Valid decimal parse string integer ('0x' prefix ignored +* following invalid hexadecimal characters) : +* +* pstr = " 0xGABCDE" +* nbr_base = 0 +* +* nbr = 0 +* pstr_next = "xGABCDE" +* +* +* (e) Valid decimal parse string integer ('0' prefix ignored +* following invalid octal characters) : +* +* pstr = " 0GABCDE" +* nbr_base = 0 +* +* nbr = 0 +* pstr_next = "GABCDE" +* +* +* (f) Parse string integer overflow : +* +* pstr = " 12345678901234567890*123456" +* nbr_base = 10 +* +* nbr = DEF_INT_32U_MAX_VAL +* pstr_next = "*123456" +* +* +* (g) Parse string integer underflow : +* +* pstr = " -12345678901234567890*123456" +* nbr_base = 10 +* +* nbr = DEF_INT_32S_MIN_VAL +* pstr_next = "*123456" +* +* +* (4) String parse terminates when : +* +* (a) Base passed an invalid base (see Note #2a1B1b). +* (1) No conversion performed; 0 returned. +* +* (b) (1) Parse string passed a NULL pointer OR empty integer sequence (see Note #2a2A). +* (A) No conversion performed; 0 returned. +* +* (2) Invalid parse string character found (see Note #2a1C). +* (A) Parsed integer returned. +* (B) 'pstr_next' points to invalid character. +* +* (3) Entire parse string converted (see Note #2a2B). +* (A) Parsed integer returned. +* (B) 'pstr_next' points to terminating NULL character. +* +* (5) Pointers to variables that return values MUST be initialized PRIOR to all other +* validation or function handling in case of any error(s). +********************************************************************************************************* +*/ + +static CPU_INT32U Str_ParseNbr_Int32 (const CPU_CHAR *pstr, + CPU_CHAR **pstr_next, + CPU_INT08U nbr_base, + CPU_BOOLEAN nbr_signed, + CPU_BOOLEAN *pnbr_neg) +{ + const CPU_CHAR *pstr_parse; + const CPU_CHAR *pstr_parse_nbr; + CPU_CHAR *pstr_parse_unused; + CPU_CHAR parse_char; + CPU_INT08U parse_dig; + CPU_INT32U nbr; + CPU_BOOLEAN nbr_neg_unused; + CPU_BOOLEAN nbr_dig; + CPU_BOOLEAN nbr_alpha; + CPU_BOOLEAN nbr_hex; + CPU_BOOLEAN nbr_hex_lower; + CPU_BOOLEAN whitespace; + CPU_BOOLEAN neg; + CPU_BOOLEAN ovf; + CPU_BOOLEAN done; + + /* --------------- VALIDATE PARSE ARGS ---------------- */ + if (pstr_next == (CPU_CHAR **) 0) { /* If NOT avail, ... */ + pstr_next = (CPU_CHAR **)&pstr_parse_unused; /* ... re-cfg NULL rtn ptr to unused local var. */ + (void)&pstr_parse_unused; /* Prevent possible 'variable unused' warning. */ + } + *pstr_next = (CPU_CHAR *)pstr; /* Init rtn str for err (see Note #5). */ + + if (pnbr_neg == (CPU_BOOLEAN *) 0) { /* If NOT avail, ... */ + pnbr_neg = (CPU_BOOLEAN *)&nbr_neg_unused; /* ... re-cfg NULL rtn ptr to unused local var. */ + (void)&nbr_neg_unused; /* Prevent possible 'variable unused' warning. */ + } + *pnbr_neg = DEF_NO; /* Init nbr neg for err (see Note #5). */ + + + if (pstr == (CPU_CHAR *)0) { /* Rtn zero if str ptr NULL (see Note #4b1). */ + return (0u); + } + /* Rtn zero if invalid base (see Note #4a). */ + if ((nbr_base == 1u) || + (nbr_base > 36u)) { + return (0u); + } + + + /* ------------- IGNORE PRECEDING CHAR(S) ------------- */ + pstr_parse = pstr; /* Save ptr to init'l str for err (see Note #2a2A2). */ + + whitespace = ASCII_IsSpace(*pstr_parse); + while (whitespace == DEF_YES) { /* Ignore initial white-space char(s) [see Note #2a1A]. */ + pstr_parse++; + whitespace = ASCII_IsSpace(*pstr_parse); + } + + switch (*pstr_parse) { + case '+': /* Ignore pos sign (see Note #2a1B2). */ + pstr_parse++; + neg = DEF_NO; + break; + + + case '-': /* Validate neg sign (see Note #2a1B2a). */ + if (nbr_signed == DEF_YES) { + pstr_parse++; + } + neg = DEF_YES; + break; + + + default: + neg = DEF_NO; + break; + } + + + /* --------- IGNORE NBR BASE PRECEDING CHAR(S) -------- */ + pstr_parse_nbr = pstr_parse; /* Save ptr to str's nbr (see Note #2a1A1). */ + + switch (nbr_base) { + case 0u: /* Determine unspecified nbr base (see Notes #2a1B1a). */ + if (*pstr_parse == '0') { /* If avail, ... */ + pstr_parse++; /* ... adv past '0' prefix (see Note #2a1B1b2). */ + switch (*pstr_parse) { + case 'x': /* For '0x' prefix, ... */ + case 'X': + nbr_base = 16u; /* ... set nbr base = 16 (see Note #2a1B1a3). */ + parse_char = (CPU_CHAR)(*(pstr_parse + 1)); + nbr_hex = ASCII_IsDigHex(parse_char); + if (nbr_hex == DEF_YES) { /* If next char is valid hex dig, ... */ + pstr_parse++; /* ... adv past '0x' prefix (see Note #2a1B1b2A). */ + } + break; + + + default: /* For '0' prefix, ... */ + nbr_base = 8u; /* ... set nbr base = 8 (see Note #2a1B1a2). */ + break; + } + + } else { /* For non-'0' prefix, ... */ + nbr_base = 10u; /* ... set nbr base = 10 (see Note #2a1B1a1). */ + } + break; + + + case 8u: /* See Note #2a1B1a2. */ + if (*pstr_parse == '0') { /* If avail, ... */ + pstr_parse++; /* ... adv past '0' prefix (see Note #2a1B1b2B). */ + } + break; + + + case 16u: /* See Note #2a1B1a3. */ + if (*pstr_parse == '0') { /* If avail, ... */ + pstr_parse++; /* ... adv past '0' prefix (see Note #2a1B1b2). */ + switch (*pstr_parse) { + case 'x': + case 'X': + parse_char = (CPU_CHAR)(*(pstr_parse + 1)); + nbr_hex = ASCII_IsDigHex(parse_char); + if (nbr_hex == DEF_YES) { /* If next char is valid hex dig, ... */ + pstr_parse++; /* ... adv past '0x' prefix (see Note #2a1B1b2A). */ + } + break; + + + default: + break; + } + } + break; + + + default: /* See Note #2a1B1b. */ + break; + } + + + /* ------------------ PARSE INT STR ------------------- */ + nbr = 0u; + ovf = DEF_NO; + done = DEF_NO; + + while (done == DEF_NO) { /* Parse str for desired nbr base digs (see Note #2a2). */ + parse_char = (CPU_CHAR)*pstr_parse; + nbr_alpha = ASCII_IsAlphaNum(parse_char); + if (nbr_alpha == DEF_YES) { /* If valid alpha num nbr dig avail, ... */ + /* ... convert parse char into nbr dig. */ + nbr_dig = ASCII_IsDig(parse_char); + if (nbr_dig == DEF_YES) { + parse_dig = (CPU_INT08U)(parse_char - '0'); + } else { + nbr_hex_lower = ASCII_IsLower(parse_char); + if (nbr_hex_lower == DEF_YES) { + parse_dig = (CPU_INT08U)((parse_char - 'a') + 10u); + } else { + parse_dig = (CPU_INT08U)((parse_char - 'A') + 10u); + } + } + + if (parse_dig < nbr_base) { /* If parse char valid for nbr base ... */ + if (ovf == DEF_NO) { /* ... & nbr NOT yet ovf'd, ... */ + if (nbr <= Str_MultOvfThTbl_Int32U[nbr_base]) { + /* ... merge parse char dig into nbr. */ + nbr *= nbr_base; + nbr += parse_dig; + if (nbr < parse_dig) { + ovf = DEF_YES; + } + } else { + ovf = DEF_YES; + } + } + pstr_parse++; + + } else { /* Invalid char parsed (see Note #2a1C1a). */ + done = DEF_YES; + } + + } else { /* Invalid OR NULL char parsed (see Note #2a1C1). */ + done = DEF_YES; + } + } + + if (ovf == DEF_YES) { /* If nbr ovf'd, ... */ + nbr = DEF_INT_32U_MAX_VAL; /* ... rtn max int val (see Note #2a3A1). */ + } + + + if (pstr_parse != pstr_parse_nbr) { /* If final parse str != init'l parse nbr str, .. */ + *pstr_next = (CPU_CHAR *)pstr_parse; /* .. rtn parse str's next char (see Note #2a2B2); .. */ + } else { + *pstr_next = (CPU_CHAR *)pstr; /* .. else rtn initial parse str (see Note #2a2A2). */ + } + + *pnbr_neg = neg; /* Rtn neg nbr status. */ + + + return (nbr); +} + diff --git a/Middlewares/Third_Party/Micrium/uC-LIB/lib_str.h b/Middlewares/Third_Party/Micrium/uC-LIB/lib_str.h new file mode 100644 index 0000000..c6340a4 --- /dev/null +++ b/Middlewares/Third_Party/Micrium/uC-LIB/lib_str.h @@ -0,0 +1,429 @@ +/* +********************************************************************************************************* +* uC/LIB +* CUSTOM LIBRARY MODULES +* +* (c) Copyright 2004-2014; Micrium, Inc.; Weston, FL +* +* All rights reserved. Protected by international copyright laws. +* +* uC/LIB is provided in source form to registered licensees ONLY. It is +* illegal to distribute this source code to any third party unless you receive +* written permission by an authorized Micrium representative. Knowledge of +* the source code may NOT be used to develop a similar product. +* +* Please help us continue to provide the Embedded community with the finest +* software available. Your honesty is greatly appreciated. +* +* You can find our product's user manual, API reference, release notes and +* more information at: https://doc.micrium.com +* +* You can contact us at: http://www.micrium.com +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* +* ASCII STRING MANAGEMENT +* +* Filename : lib_str.h +* Version : V1.38.01 +* Programmer(s) : ITJ +* JDH +********************************************************************************************************* +* Note(s) : (1) NO compiler-supplied standard library functions are used in library or product software. +* +* (a) ALL standard library functions are implemented in the custom library modules : +* +* (1) \\lib_*.* +* +* (2) \\Ports\\\lib*_a.* +* +* where +* directory path for custom library software +* directory name for specific processor (CPU) +* directory name for specific compiler +* +* (b) Product-specific library functions are implemented in individual products. +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* MODULE +* +* Note(s) : (1) This string library header file is protected from multiple pre-processor inclusion through +* use of the string library module present pre-processor macro definition. +********************************************************************************************************* +*/ + +#ifndef LIB_STR_MODULE_PRESENT /* See Note #1. */ +#define LIB_STR_MODULE_PRESENT + + +/* +********************************************************************************************************* +* ASCII STRING CONFIGURATION DEFINES +* +* Note(s) : (1) Some ASCII string configuration #define's MUST be available PRIOR to including any +* application configuration (see 'INCLUDE FILES Note #1a'). +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* STRING FLOATING POINT DEFINES +* +* Note(s) : (1) (a) (1) The maximum accuracy for 32-bit floating-point numbers : +* +* +* Maximum Accuracy log [Internal-Base ^ (Number-Internal-Base-Digits)] +* 32-bit Floating-point Number = ----------------------------------------------------- +* log [External-Base] +* +* log [2 ^ 24] +* = -------------- +* log [10] +* +* < 7.225 Base-10 Digits +* +* where +* Internal-Base Internal number base of floating- +* point numbers (i.e. 2) +* External-Base External number base of floating- +* point numbers (i.e. 10) +* Number-Internal-Base-Digits Number of internal number base +* significant digits (i.e. 24) +* +* (2) Also, since some 32-bit floating-point calculations are converted to 32-bit +* unsigned numbers, the maximum accuracy is limited to the maximum accuracy +* for 32-bit unsigned numbers of 9 digits. +* +* (b) Some CPUs' &/or compilers' floating-point implementations MAY further reduce the +* maximum accuracy. +********************************************************************************************************* +*/ + +#define LIB_STR_FP_MAX_NBR_DIG_SIG_MIN 1u +#define LIB_STR_FP_MAX_NBR_DIG_SIG_MAX 9u /* See Note #1a2. */ +#define LIB_STR_FP_MAX_NBR_DIG_SIG_DFLT 7u /* See Note #1a1. */ + + +/* +********************************************************************************************************* +* INCLUDE FILES +* +* Note(s) : (1) The custom library software files are located in the following directories : +* +* (a) \\lib_cfg.h +* +* (b) \\lib_*.* +* +* where +* directory path for Your Product's Application +* directory path for custom library software +* +* (2) CPU-configuration software files are located in the following directories : +* +* (a) \\cpu_*.* +* (b) \\\\cpu*.* +* +* where +* directory path for common CPU-compiler software +* directory name for specific processor (CPU) +* directory name for specific compiler +* +* (3) Compiler MUST be configured to include as additional include path directories : +* +* (a) '\\' directory See Note #1a +* +* (b) '\\' directory See Note #1b +* +* (c) (1) '\\' directory See Note #2a +* (2) '\\\\' directory See Note #2b +* +* (4) NO compiler-supplied standard library functions SHOULD be used. +* +* #### The reference to standard library header files SHOULD be removed once all custom +* library functions are implemented WITHOUT reference to ANY standard library function(s). +* +* See also 'STANDARD LIBRARY MACRO'S Note #1'. +********************************************************************************************************* +*/ + +#include + +#include +#include + +#include + +#if 0 /* See Note #4. */ +#include +#endif + + +/* +********************************************************************************************************* +* EXTERNS +********************************************************************************************************* +*/ + +#ifdef LIB_STR_MODULE +#define LIB_STR_EXT +#else +#define LIB_STR_EXT extern +#endif + + +/* +********************************************************************************************************* +* DEFAULT CONFIGURATION +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* STRING FLOATING POINT CONFIGURATION +* +* Note(s) : (1) Configure LIB_STR_CFG_FP_EN to enable/disable floating point string function(s). +* +* (2) Configure LIB_STR_CFG_FP_MAX_NBR_DIG_SIG to configure the maximum number of significant +* digits to calculate &/or display for floating point string function(s). +* +* See also 'STRING FLOATING POINT DEFINES Note #1'. +********************************************************************************************************* +*/ + + /* Configure floating point feature(s) [see Note #1] : */ +#ifndef LIB_STR_CFG_FP_EN +#define LIB_STR_CFG_FP_EN DEF_DISABLED + /* DEF_DISABLED Floating point functions DISABLED */ + /* DEF_ENABLED Floating point functions ENABLED */ +#endif + + /* Configure floating point feature(s)' number of ... */ + /* ... significant digits (see Note #2). */ +#ifndef LIB_STR_CFG_FP_MAX_NBR_DIG_SIG +#define LIB_STR_CFG_FP_MAX_NBR_DIG_SIG LIB_STR_FP_MAX_NBR_DIG_SIG_DFLT +#endif + + +/* +********************************************************************************************************* +* DEFINES +********************************************************************************************************* +*/ + +#define STR_CR_LF "\r\n" +#define STR_LF_CR "\n\r" +#define STR_NEW_LINE STR_CR_LF +#define STR_PARENT_PATH ".." + +#define STR_CR_LF_LEN (sizeof(STR_CR_LF) - 1) +#define STR_LF_CR_LEN (sizeof(STR_LF_CR) - 1) +#define STR_NEW_LINE_LEN (sizeof(STR_NEW_LINE) - 1) +#define STR_PARENT_PATH_LEN (sizeof(STR_PARENT_PATH) - 1) + + +/* +********************************************************************************************************* +* DATA TYPES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* GLOBAL VARIABLES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* MACRO'S +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* STANDARD LIBRARY MACRO'S +* +* Note(s) : (1) NO compiler-supplied standard library functions SHOULD be used. +* +* #### The reference to standard memory functions SHOULD be removed once all custom library +* functions are implemented WITHOUT reference to ANY standard library function(s). +* +* See also 'INCLUDE FILES Note #3'. +********************************************************************************************************* +*/ + + /* See Note #1. */ +#define Str_FmtPrint snprintf +#define Str_FmtScan sscanf + + +/* +********************************************************************************************************* +* FUNCTION PROTOTYPES +********************************************************************************************************* +*/ + + /* ------------------ STR LEN FNCTS ------------------ */ +CPU_SIZE_T Str_Len (const CPU_CHAR *pstr); + +CPU_SIZE_T Str_Len_N (const CPU_CHAR *pstr, + CPU_SIZE_T len_max); + + + /* ------------------ STR COPY FNCTS ------------------ */ +CPU_CHAR *Str_Copy ( CPU_CHAR *pstr_dest, + const CPU_CHAR *pstr_src); + +CPU_CHAR *Str_Copy_N ( CPU_CHAR *pstr_dest, + const CPU_CHAR *pstr_src, + CPU_SIZE_T len_max); + + +CPU_CHAR *Str_Cat ( CPU_CHAR *pstr_dest, + const CPU_CHAR *pstr_cat); + +CPU_CHAR *Str_Cat_N ( CPU_CHAR *pstr_dest, + const CPU_CHAR *pstr_cat, + CPU_SIZE_T len_max); + + + /* ------------------ STR CMP FNCTS ------------------ */ +CPU_INT16S Str_Cmp (const CPU_CHAR *p1_str, + const CPU_CHAR *p2_str); + +CPU_INT16S Str_Cmp_N (const CPU_CHAR *p1_str, + const CPU_CHAR *p2_str, + CPU_SIZE_T len_max); + +CPU_INT16S Str_CmpIgnoreCase (const CPU_CHAR *p1_str, + const CPU_CHAR *p2_str); + +CPU_INT16S Str_CmpIgnoreCase_N(const CPU_CHAR *p1_str, + const CPU_CHAR *p2_str, + CPU_SIZE_T len_max); + + + /* ------------------ STR SRCH FNCTS ------------------ */ +CPU_CHAR *Str_Char (const CPU_CHAR *pstr, + CPU_CHAR srch_char); + +CPU_CHAR *Str_Char_N (const CPU_CHAR *pstr, + CPU_SIZE_T len_max, + CPU_CHAR srch_char); + +CPU_CHAR *Str_Char_Last (const CPU_CHAR *pstr, + CPU_CHAR srch_char); + +CPU_CHAR *Str_Char_Last_N (const CPU_CHAR *pstr, + CPU_SIZE_T len_max, + CPU_CHAR srch_char); + +CPU_CHAR *Str_Char_Replace ( CPU_CHAR *pstr, + CPU_CHAR char_srch, + CPU_CHAR char_replace); + +CPU_CHAR *Str_Char_Replace_N ( CPU_CHAR *pstr, + CPU_CHAR char_srch, + CPU_CHAR char_replace, + CPU_SIZE_T len_max); + +CPU_CHAR *Str_Str (const CPU_CHAR *pstr, + const CPU_CHAR *pstr_srch); + +CPU_CHAR *Str_Str_N (const CPU_CHAR *pstr, + const CPU_CHAR *pstr_srch, + CPU_SIZE_T len_max); + + + /* ------------------ STR FMT FNCTS ------------------ */ +CPU_CHAR *Str_FmtNbr_Int32U ( CPU_INT32U nbr, + CPU_INT08U nbr_dig, + CPU_INT08U nbr_base, + CPU_CHAR lead_char, + CPU_BOOLEAN lower_case, + CPU_BOOLEAN nul, + CPU_CHAR *pstr); + +CPU_CHAR *Str_FmtNbr_Int32S ( CPU_INT32S nbr, + CPU_INT08U nbr_dig, + CPU_INT08U nbr_base, + CPU_CHAR lead_char, + CPU_BOOLEAN lower_case, + CPU_BOOLEAN nul, + CPU_CHAR *pstr); + +#if (LIB_STR_CFG_FP_EN == DEF_ENABLED) +CPU_CHAR *Str_FmtNbr_32 ( CPU_FP32 nbr, + CPU_INT08U nbr_dig, + CPU_INT08U nbr_dp, + CPU_CHAR lead_char, + CPU_BOOLEAN nul, + CPU_CHAR *pstr); +#endif + + + /* ----------------- STR PARSE FNCTS ------------------ */ +CPU_INT32U Str_ParseNbr_Int32U(const CPU_CHAR *pstr, + CPU_CHAR **pstr_next, + CPU_INT08U nbr_base); + +CPU_INT32S Str_ParseNbr_Int32S(const CPU_CHAR *pstr, + CPU_CHAR **pstr_next, + CPU_INT08U nbr_base); + + +/* +********************************************************************************************************* +* CONFIGURATION ERRORS +********************************************************************************************************* +*/ + +#ifndef LIB_STR_CFG_FP_EN +#error "LIB_STR_CFG_FP_EN not #define'd in 'lib_cfg.h'" +#error " [MUST be DEF_DISABLED] " +#error " [ || DEF_ENABLED ] " + +#elif ((LIB_STR_CFG_FP_EN != DEF_DISABLED) && \ + (LIB_STR_CFG_FP_EN != DEF_ENABLED )) +#error "LIB_STR_CFG_FP_EN illegally #define'd in 'lib_cfg.h'" +#error " [MUST be DEF_DISABLED] " +#error " [ || DEF_ENABLED ] " + + +#elif (LIB_STR_CFG_FP_EN == DEF_ENABLED) + +#ifndef LIB_STR_CFG_FP_MAX_NBR_DIG_SIG +#error "LIB_STR_CFG_FP_MAX_NBR_DIG_SIG not #define'd in 'lib_cfg.h' " +#error " [MUST be >= LIB_STR_FP_MAX_NBR_DIG_SIG_MIN]" +#error " [ && <= LIB_STR_FP_MAX_NBR_DIG_SIG_MAX]" + +#elif (DEF_CHK_VAL(LIB_STR_CFG_FP_MAX_NBR_DIG_SIG, \ + LIB_STR_FP_MAX_NBR_DIG_SIG_MIN, \ + LIB_STR_FP_MAX_NBR_DIG_SIG_MAX) != DEF_OK) +#error "LIB_STR_CFG_FP_MAX_NBR_DIG_SIG illegally #define'd in 'lib_cfg.h' " +#error " [MUST be >= LIB_STR_FP_MAX_NBR_DIG_SIG_MIN]" +#error " [ && <= LIB_STR_FP_MAX_NBR_DIG_SIG_MAX]" +#endif + +#endif + + +/* +********************************************************************************************************* +* MODULE END +* +* Note(s) : (1) See 'lib_str.h MODULE'. +********************************************************************************************************* +*/ + +#endif /* End of lib str module include. */ + diff --git a/Middlewares/Third_Party/Micrium/uCOS-II/Ports/ARM-Cortex-M4/IAR/os_cpu.h b/Middlewares/Third_Party/Micrium/uCOS-II/Ports/ARM-Cortex-M4/IAR/os_cpu.h new file mode 100644 index 0000000..11fa92a --- /dev/null +++ b/Middlewares/Third_Party/Micrium/uCOS-II/Ports/ARM-Cortex-M4/IAR/os_cpu.h @@ -0,0 +1,189 @@ +/* +********************************************************************************************************* +* uC/OS-II +* The Real-Time Kernel +* +* +* (c) Copyright 2009-2013; Micrium, Inc.; Weston, FL +* All rights reserved. Protected by international copyright laws. +* +* ARM Cortex-M4 Port +* +* File : OS_CPU.H +* Version : V2.92.09 +* By : JJL +* JBL +* +* LICENSING TERMS: +* --------------- +* uC/OS-II is provided in source form for FREE short-term evaluation, for educational use or +* for peaceful research. If you plan or intend to use uC/OS-II in a commercial application/ +* product then, you need to contact Micrium to properly license uC/OS-II for its use in your +* application/product. We provide ALL the source code for your convenience and to help you +* experience uC/OS-II. The fact that the source is provided does NOT mean that you can use +* it commercially without paying a licensing fee. +* +* Knowledge of the source code may NOT be used to develop a similar product. +* +* Please help us continue to provide the embedded community with the finest software available. +* Your honesty is greatly appreciated. +* +* You can contact us at www.micrium.com, or by phone at +1 (954) 217-2036. +* +* For : ARMv7 Cortex-M4 +* Mode : Thumb-2 ISA +* Toolchain : IAR EWARM +********************************************************************************************************* +*/ + +#ifndef OS_CPU_H +#define OS_CPU_H + +#ifdef OS_CPU_GLOBALS +#define OS_CPU_EXT +#else +#define OS_CPU_EXT extern +#endif + +#ifndef OS_CPU_EXCEPT_STK_SIZE +#define OS_CPU_EXCEPT_STK_SIZE 128u /* Default exception stack size is 128 OS_STK entries */ +#endif + + +/* +********************************************************************************************************* +* DEFINES +********************************************************************************************************* +*/ + +#ifdef __ARMVFP__ +#define OS_CPU_ARM_FP_EN 1u +#else +#define OS_CPU_ARM_FP_EN 0u +#endif + + +/* +********************************************************************************************************* +* OS TICK INTERRUPT PRIORITY CONFIGURATION +* +* Note(s) : (1) For systems that don't need any high, real-time priority interrupts; the tick interrupt +* should be configured as the highest priority interrupt but won't adversely affect system +* operations. +* +* (2) For systems that need one or more high, real-time interrupts; these should be configured +* higher than the tick interrupt which MAY delay execution of the tick interrupt. +* +* (a) If the higher priority interrupts do NOT continually consume CPU cycles but only +* occasionally delay tick interrupts, then the real-time interrupts can successfully +* handle their intermittent/periodic events with the system not losing tick interrupts +* but only increasing the jitter. +* +* (b) If the higher priority interrupts consume enough CPU cycles to continually delay the +* tick interrupt, then the CPU/system is most likely over-burdened & can't be expected +* to handle all its interrupts/tasks. The system time reference gets compromised as a +* result of losing tick interrupts. +********************************************************************************************************* +*/ + +#define OS_CPU_CFG_SYSTICK_PRIO 0u + +/* +********************************************************************************************************* +* DATA TYPES +* (Compiler Specific) +********************************************************************************************************* +*/ + +typedef unsigned char BOOLEAN; +typedef unsigned char INT8U; /* Unsigned 8 bit quantity */ +typedef signed char INT8S; /* Signed 8 bit quantity */ +typedef unsigned short INT16U; /* Unsigned 16 bit quantity */ +typedef signed short INT16S; /* Signed 16 bit quantity */ +typedef unsigned int INT32U; /* Unsigned 32 bit quantity */ +typedef signed int INT32S; /* Signed 32 bit quantity */ +typedef float FP32; /* Single precision floating point */ +typedef double FP64; /* Double precision floating point */ + +typedef unsigned int OS_STK; /* Each stack entry is 32-bit wide */ +typedef unsigned int OS_CPU_SR; /* Define size of CPU status register (PSR = 32 bits) */ + + +/* +********************************************************************************************************* +* Cortex-M4 +* Critical Section Management +* +* Method #1: Disable/Enable interrupts using simple instructions. After critical section, interrupts +* will be enabled even if they were disabled before entering the critical section. +* NOT IMPLEMENTED +* +* Method #2: Disable/Enable interrupts by preserving the state of interrupts. In other words, if +* interrupts were disabled before entering the critical section, they will be disabled when +* leaving the critical section. +* NOT IMPLEMENTED +* +* Method #3: Disable/Enable interrupts by preserving the state of interrupts. Generally speaking you +* would store the state of the interrupt disable flag in the local variable 'cpu_sr' and then +* disable interrupts. 'cpu_sr' is allocated in all of uC/OS-II's functions that need to +* disable interrupts. You would restore the interrupt disable state by copying back 'cpu_sr' +* into the CPU's status register. +********************************************************************************************************* +*/ + +#define OS_CRITICAL_METHOD 3u + +#if OS_CRITICAL_METHOD == 3u +#define OS_ENTER_CRITICAL() {cpu_sr = OS_CPU_SR_Save();} +#define OS_EXIT_CRITICAL() {OS_CPU_SR_Restore(cpu_sr);} +#endif + + +/* +********************************************************************************************************* +* Cortex-M4 Miscellaneous +********************************************************************************************************* +*/ + +#define OS_STK_GROWTH 1u /* Stack grows from HIGH to LOW memory on ARM */ + +#define OS_TASK_SW() OSCtxSw() + + +/* +********************************************************************************************************* +* GLOBAL VARIABLES +********************************************************************************************************* +*/ + +OS_CPU_EXT OS_STK OS_CPU_ExceptStk[OS_CPU_EXCEPT_STK_SIZE]; +OS_CPU_EXT OS_STK *OS_CPU_ExceptStkBase; + + +/* +********************************************************************************************************* +* FUNCTION PROTOTYPES +********************************************************************************************************* +*/ + +#if OS_CRITICAL_METHOD == 3u /* See OS_CPU_A.ASM */ +OS_CPU_SR OS_CPU_SR_Save (void); +void OS_CPU_SR_Restore (OS_CPU_SR cpu_sr); +#endif + +void OSCtxSw (void); +void OSIntCtxSw (void); +void OSStartHighRdy (void); + +void OS_CPU_PendSVHandler (void); + + /* See OS_CPU_C.C */ +void OS_CPU_SysTickHandler (void); +void OS_CPU_SysTickInit (INT32U cnts); + +#if (OS_CPU_ARM_FP_EN > 0u) +void OS_CPU_FP_Reg_Push (OS_STK *stkPtr); +void OS_CPU_FP_Reg_Pop (OS_STK *stkPtr); +#endif + +#endif diff --git a/Middlewares/Third_Party/Micrium/uCOS-II/Ports/ARM-Cortex-M4/IAR/os_cpu_a.asm b/Middlewares/Third_Party/Micrium/uCOS-II/Ports/ARM-Cortex-M4/IAR/os_cpu_a.asm new file mode 100644 index 0000000..680cdf1 --- /dev/null +++ b/Middlewares/Third_Party/Micrium/uCOS-II/Ports/ARM-Cortex-M4/IAR/os_cpu_a.asm @@ -0,0 +1,306 @@ +; +;******************************************************************************************************** +; uC/OS-II +; The Real-Time Kernel +; +; +; (c) Copyright 2009-2013; Micrium, Inc.; Weston, FL +; All rights reserved. Protected by international copyright laws. +; +; ARM Cortex-M4 Port +; +; File : OS_CPU_A.ASM +; Version : V2.92.09 +; By : JJL +; BAN +; JBL +; +; For : ARMv7 Cortex-M4 +; Mode : Thumb-2 ISA +; Toolchain : IAR EWARM +;******************************************************************************************************** +; + +;******************************************************************************************************** +; PUBLIC FUNCTIONS +;******************************************************************************************************** + + EXTERN OSRunning ; External references + EXTERN OSPrioCur + EXTERN OSPrioHighRdy + EXTERN OSTCBCur + EXTERN OSTCBHighRdy + EXTERN OSIntExit + EXTERN OSTaskSwHook + EXTERN OS_CPU_ExceptStkBase + + PUBLIC OS_CPU_SR_Save ; Functions declared in this file + PUBLIC OS_CPU_SR_Restore + PUBLIC OSStartHighRdy + PUBLIC OSCtxSw + PUBLIC OSIntCtxSw + PUBLIC OS_CPU_PendSVHandler + +#ifdef __ARMVFP__ + PUBLIC OS_CPU_FP_Reg_Push + PUBLIC OS_CPU_FP_Reg_Pop +#endif + + +;******************************************************************************************************** +; EQUATES +;******************************************************************************************************** + +NVIC_INT_CTRL EQU 0xE000ED04 ; Interrupt control state register. +NVIC_SYSPRI14 EQU 0xE000ED22 ; System priority register (priority 14). +NVIC_PENDSV_PRI EQU 0xFF ; PendSV priority value (lowest). +NVIC_PENDSVSET EQU 0x10000000 ; Value to trigger PendSV exception. + + +;******************************************************************************************************** +; CODE GENERATION DIRECTIVES +;******************************************************************************************************** + + RSEG CODE:CODE:NOROOT(2) + THUMB + + +;******************************************************************************************************** +; FLOATING POINT REGISTERS PUSH +; void OS_CPU_FP_Reg_Push (OS_STK *stkPtr) +; +; Note(s) : 1) This function saves S0-S31, and FPSCR registers of the Floating Point Unit. +; +; 2) Pseudo-code is: +; a) Get FPSCR register value; +; b) Push value on process stack; +; c) Push remaining regs S0-S31 on process stack; +; d) Update OSTCBCur->OSTCBStkPtr; +;******************************************************************************************************** + +#ifdef __ARMVFP__ +OS_CPU_FP_Reg_Push + MRS R1, PSP ; PSP is process stack pointer + CBZ R1, OS_CPU_FP_nosave ; Skip FP register save the first time + + VMRS R1, FPSCR + STR R1, [R0, #-4]! + VSTMDB R0!, {S0-S31} + LDR R1, =OSTCBCur + LDR R2, [R1] + STR R0, [R2] +OS_CPU_FP_nosave + BX LR +#endif + + +;******************************************************************************************************** +; FLOATING POINT REGISTERS POP +; void OS_CPU_FP_Reg_Pop (OS_STK *stkPtr) +; +; Note(s) : 1) This function restores S0-S31, and FPSCR registers of the Floating Point Unit. +; +; 2) Pseudo-code is: +; a) Restore regs S0-S31 of new process stack; +; b) Restore FPSCR reg value +; c) Update OSTCBHighRdy->OSTCBStkPtr pointer of new proces stack; +;******************************************************************************************************** + +#ifdef __ARMVFP__ +OS_CPU_FP_Reg_Pop + VLDMIA R0!, {S0-S31} + LDMIA R0!, {R1} + VMSR FPSCR, R1 + LDR R1, =OSTCBHighRdy + LDR R2, [R1] + STR R0, [R2] + BX LR +#endif + + +;******************************************************************************************************** +; CRITICAL SECTION METHOD 3 FUNCTIONS +; +; Description: Disable/Enable interrupts by preserving the state of interrupts. Generally speaking you +; would store the state of the interrupt disable flag in the local variable 'cpu_sr' and then +; disable interrupts. 'cpu_sr' is allocated in all of uC/OS-II's functions that need to +; disable interrupts. You would restore the interrupt disable state by copying back 'cpu_sr' +; into the CPU's status register. +; +; Prototypes : OS_CPU_SR OS_CPU_SR_Save(void); +; void OS_CPU_SR_Restore(OS_CPU_SR cpu_sr); +; +; +; Note(s) : 1) These functions are used in general like this: +; +; void Task (void *p_arg) +; { +; #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */ +; OS_CPU_SR cpu_sr; +; #endif +; +; : +; : +; OS_ENTER_CRITICAL(); /* cpu_sr = OS_CPU_SaveSR(); */ +; : +; : +; OS_EXIT_CRITICAL(); /* OS_CPU_RestoreSR(cpu_sr); */ +; : +; : +; } +;******************************************************************************************************** + +OS_CPU_SR_Save + MRS R0, PRIMASK ; Set prio int mask to mask all (except faults) + CPSID I + BX LR + +OS_CPU_SR_Restore + MSR PRIMASK, R0 + BX LR + + +;******************************************************************************************************** +; START MULTITASKING +; void OSStartHighRdy(void) +; +; Note(s) : 1) This function triggers a PendSV exception (essentially, causes a context switch) to cause +; the first task to start. +; +; 2) OSStartHighRdy() MUST: +; a) Setup PendSV exception priority to lowest; +; b) Set initial PSP to 0, to tell context switcher this is first run; +; c) Set the main stack to OS_CPU_ExceptStkBase +; d) Set OSRunning to TRUE; +; e) Trigger PendSV exception; +; f) Enable interrupts (tasks will run with interrupts enabled). +;******************************************************************************************************** + +OSStartHighRdy + LDR R0, =NVIC_SYSPRI14 ; Set the PendSV exception priority + LDR R1, =NVIC_PENDSV_PRI + STRB R1, [R0] + + MOVS R0, #0 ; Set the PSP to 0 for initial context switch call + MSR PSP, R0 + + LDR R0, =OS_CPU_ExceptStkBase ; Initialize the MSP to the OS_CPU_ExceptStkBase + LDR R1, [R0] + MSR MSP, R1 + + LDR R0, =OSRunning ; OSRunning = TRUE + MOVS R1, #1 + STRB R1, [R0] + + LDR R0, =NVIC_INT_CTRL ; Trigger the PendSV exception (causes context switch) + LDR R1, =NVIC_PENDSVSET + STR R1, [R0] + + CPSIE I ; Enable interrupts at processor level + +OSStartHang + B OSStartHang ; Should never get here + + +;******************************************************************************************************** +; PERFORM A CONTEXT SWITCH (From task level) - OSCtxSw() +; +; Note(s) : 1) OSCtxSw() is called when OS wants to perform a task context switch. This function +; triggers the PendSV exception which is where the real work is done. +;******************************************************************************************************** + +OSCtxSw + LDR R0, =NVIC_INT_CTRL ; Trigger the PendSV exception (causes context switch) + LDR R1, =NVIC_PENDSVSET + STR R1, [R0] + BX LR + + +;******************************************************************************************************** +; PERFORM A CONTEXT SWITCH (From interrupt level) - OSIntCtxSw() +; +; Note(s) : 1) OSIntCtxSw() is called by OSIntExit() when it determines a context switch is needed as +; the result of an interrupt. This function simply triggers a PendSV exception which will +; be handled when there are no more interrupts active and interrupts are enabled. +;******************************************************************************************************** + +OSIntCtxSw + LDR R0, =NVIC_INT_CTRL ; Trigger the PendSV exception (causes context switch) + LDR R1, =NVIC_PENDSVSET + STR R1, [R0] + BX LR + + +;******************************************************************************************************** +; HANDLE PendSV EXCEPTION +; void OS_CPU_PendSVHandler(void) +; +; Note(s) : 1) PendSV is used to cause a context switch. This is a recommended method for performing +; context switches with Cortex-M3. This is because the Cortex-M3 auto-saves half of the +; processor context on any exception, and restores same on return from exception. So only +; saving of R4-R11 is required and fixing up the stack pointers. Using the PendSV exception +; this way means that context saving and restoring is identical whether it is initiated from +; a thread or occurs due to an interrupt or exception. +; +; 2) Pseudo-code is: +; a) Get the process SP, if 0 then skip (goto d) the saving part (first context switch); +; b) Save remaining regs r4-r11 on process stack; +; c) Save the process SP in its TCB, OSTCBCur->OSTCBStkPtr = SP; +; d) Call OSTaskSwHook(); +; e) Get current high priority, OSPrioCur = OSPrioHighRdy; +; f) Get current ready thread TCB, OSTCBCur = OSTCBHighRdy; +; g) Get new process SP from TCB, SP = OSTCBHighRdy->OSTCBStkPtr; +; h) Restore R4-R11 from new process stack; +; i) Perform exception return which will restore remaining context. +; +; 3) On entry into PendSV handler: +; a) The following have been saved on the process stack (by processor): +; xPSR, PC, LR, R12, R0-R3 +; b) Processor mode is switched to Handler mode (from Thread mode) +; c) Stack is Main stack (switched from Process stack) +; d) OSTCBCur points to the OS_TCB of the task to suspend +; OSTCBHighRdy points to the OS_TCB of the task to resume +; +; 4) Since PendSV is set to lowest priority in the system (by OSStartHighRdy() above), we +; know that it will only be run when no other exception or interrupt is active, and +; therefore safe to assume that context being switched out was using the process stack (PSP). +;******************************************************************************************************** + +OS_CPU_PendSVHandler + CPSID I ; Prevent interruption during context switch + MRS R0, PSP ; PSP is process stack pointer + CBZ R0, OS_CPU_PendSVHandler_nosave ; Skip register save the first time + + SUBS R0, R0, #0x20 ; Save remaining regs r4-11 on process stack + STM R0, {R4-R11} + + LDR R1, =OSTCBCur ; OSTCBCur->OSTCBStkPtr = SP; + LDR R1, [R1] + STR R0, [R1] ; R0 is SP of process being switched out + + ; At this point, entire context of process has been saved +OS_CPU_PendSVHandler_nosave + PUSH {R14} ; Save LR exc_return value + LDR R0, =OSTaskSwHook ; OSTaskSwHook(); + BLX R0 + POP {R14} + + LDR R0, =OSPrioCur ; OSPrioCur = OSPrioHighRdy; + LDR R1, =OSPrioHighRdy + LDRB R2, [R1] + STRB R2, [R0] + + LDR R0, =OSTCBCur ; OSTCBCur = OSTCBHighRdy; + LDR R1, =OSTCBHighRdy + LDR R2, [R1] + STR R2, [R0] + + LDR R0, [R2] ; R0 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr; + LDM R0, {R4-R11} ; Restore r4-11 from new process stack + ADDS R0, R0, #0x20 + MSR PSP, R0 ; Load PSP with new process SP + ORR LR, LR, #0xF4 ; Ensure exception return uses process stack + CPSIE I + BX LR ; Exception return will restore remaining context + + END diff --git a/Middlewares/Third_Party/Micrium/uCOS-II/Ports/ARM-Cortex-M4/IAR/os_cpu_c.c b/Middlewares/Third_Party/Micrium/uCOS-II/Ports/ARM-Cortex-M4/IAR/os_cpu_c.c new file mode 100644 index 0000000..acdd0b7 --- /dev/null +++ b/Middlewares/Third_Party/Micrium/uCOS-II/Ports/ARM-Cortex-M4/IAR/os_cpu_c.c @@ -0,0 +1,624 @@ +/* +********************************************************************************************************* +* uC/OS-II +* The Real-Time Kernel +* +* +* (c) Copyright 2009-2013; Micrium, Inc.; Weston, FL +* All rights reserved. Protected by international copyright laws. +* +* ARM Cortex-M4 Port +* +* File : OS_CPU_C.C +* Version : V2.92.09 +* By : JJL +* BAN +* +* LICENSING TERMS: +* --------------- +* uC/OS-II is provided in source form for FREE short-term evaluation, for educational use or +* for peaceful research. If you plan or intend to use uC/OS-II in a commercial application/ +* product then, you need to contact Micrium to properly license uC/OS-II for its use in your +* experience uC/OS-II. The fact that the source is provided does NOT mean that you can use +* it commercially without paying a licensing fee. +* +* Knowledge of the source code may NOT be used to develop a similar product. +* +* Please help us continue to provide the embedded community with the finest software available. +* Your honesty is greatly appreciated. +* +* You can contact us at www.micrium.com, or by phone at +1 (954) 217-2036. +* +* For : ARMv7 Cortex-M4 +* Mode : Thumb-2 ISA +* Toolchain : IAR EWARM +********************************************************************************************************* +*/ + +#define OS_CPU_GLOBALS + + +/* +********************************************************************************************************* +* INCLUDE FILES +********************************************************************************************************* +*/ + +#include +#include + + +/* +********************************************************************************************************* +* LOCAL VARIABLES +********************************************************************************************************* +*/ + +#if OS_TMR_EN > 0u +static INT16U OSTmrCtr; +#endif + + +/* +********************************************************************************************************* +* SYS TICK DEFINES +********************************************************************************************************* +*/ + +#define OS_CPU_CM4_NVIC_ST_CTRL (*((volatile INT32U *)0xE000E010uL)) /* SysTick Ctrl & Status Reg. */ +#define OS_CPU_CM4_NVIC_ST_RELOAD (*((volatile INT32U *)0xE000E014uL)) /* SysTick Reload Value Reg. */ +#define OS_CPU_CM4_NVIC_ST_CURRENT (*((volatile INT32U *)0xE000E018uL)) /* SysTick Current Value Reg. */ +#define OS_CPU_CM4_NVIC_ST_CAL (*((volatile INT32U *)0xE000E01CuL)) /* SysTick Cal Value Reg. */ +#define OS_CPU_CM4_NVIC_SHPRI1 (*((volatile INT32U *)0xE000ED18uL)) /* System Handlers 4 to 7 Prio. */ +#define OS_CPU_CM4_NVIC_SHPRI2 (*((volatile INT32U *)0xE000ED1CuL)) /* System Handlers 8 to 11 Prio. */ +#define OS_CPU_CM4_NVIC_SHPRI3 (*((volatile INT32U *)0xE000ED20uL)) /* System Handlers 12 to 15 Prio. */ + + +#define OS_CPU_CM4_NVIC_ST_CTRL_COUNT 0x00010000uL /* Count flag. */ +#define OS_CPU_CM4_NVIC_ST_CTRL_CLK_SRC 0x00000004uL /* Clock Source. */ +#define OS_CPU_CM4_NVIC_ST_CTRL_INTEN 0x00000002uL /* Interrupt enable. */ +#define OS_CPU_CM4_NVIC_ST_CTRL_ENABLE 0x00000001uL /* Counter mode. */ +#define OS_CPU_CM4_NVIC_PRIO_MIN 0xFFu /* Min handler prio. */ + + +/* +********************************************************************************************************* +* OS INITIALIZATION HOOK +* (BEGINNING) +* +* Description: This function is called by OSInit() at the beginning of OSInit(). +* +* Arguments : none +* +* Note(s) : 1) Interrupts should be disabled during this call. +********************************************************************************************************* +*/ +#if OS_CPU_HOOKS_EN > 0u +void OSInitHookBegin (void) +{ + INT32U size; + OS_STK *pstk; + + /* Clear exception stack for stack checking. */ + pstk = &OS_CPU_ExceptStk[0]; + size = OS_CPU_EXCEPT_STK_SIZE; + while (size > 0u) { + size--; + *pstk++ = (OS_STK)0; + } + + /* Align the ISR stack to 8-bytes */ + OS_CPU_ExceptStkBase = (OS_STK *)&OS_CPU_ExceptStk[OS_CPU_EXCEPT_STK_SIZE]; + OS_CPU_ExceptStkBase = (OS_STK *)((OS_STK)(OS_CPU_ExceptStkBase) & 0xFFFFFFF8); + +#if OS_TMR_EN > 0u + OSTmrCtr = 0u; +#endif +} +#endif + + +/* +********************************************************************************************************* +* OS INITIALIZATION HOOK +* (END) +* +* Description: This function is called by OSInit() at the end of OSInit(). +* +* Arguments : none +* +* Note(s) : 1) Interrupts should be disabled during this call. +********************************************************************************************************* +*/ +#if OS_CPU_HOOKS_EN > 0u +void OSInitHookEnd (void) +{ + +} +#endif + + +/* +********************************************************************************************************* +* TASK CREATION HOOK +* +* Description: This function is called when a task is created. +* +* Arguments : ptcb is a pointer to the task control block of the task being created. +* +* Note(s) : 1) Interrupts are disabled during this call. +********************************************************************************************************* +*/ +#if OS_CPU_HOOKS_EN > 0u +void OSTaskCreateHook (OS_TCB *ptcb) +{ +#if OS_APP_HOOKS_EN > 0u + App_TaskCreateHook(ptcb); +#else + (void)ptcb; /* Prevent compiler warning */ +#endif +} +#endif + + +/* +********************************************************************************************************* +* TASK DELETION HOOK +* +* Description: This function is called when a task is deleted. +* +* Arguments : ptcb is a pointer to the task control block of the task being deleted. +* +* Note(s) : 1) Interrupts are disabled during this call. +********************************************************************************************************* +*/ +#if OS_CPU_HOOKS_EN > 0u +void OSTaskDelHook (OS_TCB *ptcb) +{ +#if OS_APP_HOOKS_EN > 0u + App_TaskDelHook(ptcb); +#else + (void)ptcb; /* Prevent compiler warning */ +#endif +} +#endif + + +/* +********************************************************************************************************* +* IDLE TASK HOOK +* +* Description: This function is called by the idle task. This hook has been added to allow you to do +* such things as STOP the CPU to conserve power. +* +* Arguments : none +* +* Note(s) : 1) Interrupts are enabled during this call. +********************************************************************************************************* +*/ +#if OS_CPU_HOOKS_EN > 0u +void OSTaskIdleHook (void) +{ +#if OS_APP_HOOKS_EN > 0u + App_TaskIdleHook(); +#endif +} +#endif + + +/* +********************************************************************************************************* +* TASK RETURN HOOK +* +* Description: This function is called if a task accidentally returns. In other words, a task should +* either be an infinite loop or delete itself when done. +* +* Arguments : ptcb is a pointer to the task control block of the task that is returning. +* +* Note(s) : none +********************************************************************************************************* +*/ + +#if OS_CPU_HOOKS_EN > 0u +void OSTaskReturnHook (OS_TCB *ptcb) +{ +#if OS_APP_HOOKS_EN > 0u + App_TaskReturnHook(ptcb); +#else + (void)ptcb; +#endif +} +#endif + + +/* +********************************************************************************************************* +* STATISTIC TASK HOOK +* +* Description: This function is called every second by uC/OS-II's statistics task. This allows your +* application to add functionality to the statistics task. +* +* Arguments : none +********************************************************************************************************* +*/ + +#if OS_CPU_HOOKS_EN > 0u +void OSTaskStatHook (void) +{ +#if OS_APP_HOOKS_EN > 0u + App_TaskStatHook(); +#endif +} +#endif + + +/* +********************************************************************************************************* +* INITIALIZE A TASK'S STACK +* +* Description: This function is called by either OSTaskCreate() or OSTaskCreateExt() to initialize the +* stack frame of the task being created. This function is highly processor specific. +* +* Arguments : task is a pointer to the task code +* +* p_arg is a pointer to a user supplied data area that will be passed to the task +* when the task first executes. +* +* ptos is a pointer to the top of stack. It is assumed that 'ptos' points to +* a 'free' entry on the task stack. If OS_STK_GROWTH is set to 1 then +* 'ptos' will contain the HIGHEST valid address of the stack. Similarly, if +* OS_STK_GROWTH is set to 0, the 'ptos' will contains the LOWEST valid address +* of the stack. +* +* opt specifies options that can be used to alter the behavior of OSTaskStkInit(). +* (see uCOS_II.H for OS_TASK_OPT_xxx). +* +* Returns : Always returns the location of the new top-of-stack once the processor registers have +* been placed on the stack in the proper order. +* +* Note(s) : (1) Interrupts are enabled when task starts executing. +* +* (2) All tasks run in Thread mode, using process stack. +* +* (3) There are two different stack frames depending on whether the Floating-Point(FP) +* co-processor is enabled or not. +* +* (a) The stack frame shown in the diagram is used when the FP co-processor is not present and +* OS_TASK_OPT_SAVE_FP is disabled. In this case, the FP registers and FP Status Control +* register are not saved in the stack frame. +* +* (b) If the FP co-processor is present but the OS_TASK_OPT_SAVE_FP is not set, then the stack +* frame is saved as shown in diagram (a). Moreover, if OS_TASK_OPT_SAVE_FP is set, then the +* FP registers and FP Status Control register are saved in the stack frame. +* +* (1) When enabling the FP co-processor, make sure to clear bits ASPEN and LSPEN in the +* Floating-Point Context Control Register (FPCCR). +* +* +------------+ +------------+ +* | | | | +* +------------+ +------------+ +* | xPSR | | xPSR | +* +------------+ +------------+ +* |Return Addr | |Return Addr | +* +------------+ +------------+ +* | LR(R14) | | LR(R14) | +* +------------+ +------------+ +* | R12 | | R12 | +* +------------+ +------------+ +* | R3 | | R3 | +* +------------+ +------------+ +* | R2 | | R0 | +* +------------+ +------------+ +* | R1 | | R1 | +* +------------+ +------------+ +* | R0 | | R0 | +* +------------+ +------------+ +* | R11 | | R11 | +* +------------+ +------------+ +* | R10 | | R10 | +* +------------+ +------------+ +* | R9 | | R9 | +* +------------+ +------------+ +* | R8 | | R8 | +* +------------+ +------------+ +* | R7 | | R7 | +* +------------+ +------------+ +* | R6 | | R6 | +* +------------+ +------------+ +* | R5 | | R5 | +* +------------+ +------------+ +* | R4 | | R4 | +* +------------+ +------------+ +* (a) | FPSCR | +* +------------+ +* | S31 | +* +------------+ +* . +* . +* . +* +------------+ +* | S1 | + +------------+ +* | S0 | +* +------------+ +* (b) +* +* (4) The SP must be 8-byte aligned in conforming to the Procedure Call Standard for the ARM architecture +* +* (a) Section 2.1 of the ABI for the ARM Architecture Advisory Note. SP must be 8-byte aligned +* on entry to AAPCS-Conforming functions states : +* +* The Procedure Call Standard for the ARM Architecture [AAPCS] requires primitive +* data types to be naturally aligned according to their sizes (for size = 1, 2, 4, 8 bytes). +* Doing otherwise creates more problems than it solves. +* +* In return for preserving the natural alignment of data, conforming code is permitted +* to rely on that alignment. To support aligning data allocated on the stack, the stack +* pointer (SP) is required to be 8-byte aligned on entry to a conforming function. In +* practice this requirement is met if: +* +* (1) At each call site, the current size of the calling function’s stack frame is a multiple of 8 bytes. +* This places an obligation on compilers and assembly language programmers. +* +* (2) SP is a multiple of 8 when control first enters a program. +* This places an obligation on authors of low level OS, RTOS, and runtime library +* code to align SP at all points at which control first enters +* a body of (AAPCS-conforming) code. +* +* In turn, this requires the value of SP to be aligned to 0 modulo 8: +* +* (3) By exception handlers, before calling AAPCS-conforming code. +* +* (4) By OS/RTOS/run-time system code, before giving control to an application. +* +* (b) Section 2.3.1 corrective steps from the the SP must be 8-byte aligned on entry +* to AAPCS-conforming functions advisory note also states. +* +* " This requirement extends to operating systems and run-time code for all architecture versions +* prior to ARMV7 and to the A, R and M architecture profiles thereafter. Special considerations +* associated with ARMV7M are discussed in §2.3.3" +* +* (1) Even if the SP 8-byte aligment is not a requirement for the ARMv7M profile, the stack is aligned +* to 8-byte boundaries to support legacy execution enviroments. +* +* (c) Section 5.2.1.2 from the Procedure Call Standard for the ARM +* architecture states : "The stack must also conform to the following +* constraint at a public interface: +* +* (1) SP mod 8 = 0. The stack must be double-word aligned" +* +* (d) From the ARM Technical Support Knowledge Base. 8 Byte stack aligment. +* +* "8 byte stack alignment is a requirement of the ARM Architecture Procedure +* Call Standard [AAPCS]. This specifies that functions must maintain an 8 byte +* aligned stack address (e.g. 0x00, 0x08, 0x10, 0x18, 0x20) on all external +* interfaces. In practice this requirement is met if: +* +* (1) At each external interface, the current stack pointer +* is a multiple of 8 bytes. +* +* (2) Your OS maintains 8 byte stack alignment on its external interfaces +* e.g. on task switches" +* +********************************************************************************************************** +*/ + +OS_STK *OSTaskStkInit (void (*task)(void *p_arg), void *p_arg, OS_STK *ptos, INT16U opt) +{ + OS_STK *p_stk; + + + p_stk = ptos + 1u; /* Load stack pointer */ + /* Align the stack to 8-bytes. */ + p_stk = (OS_STK *)((OS_STK)(p_stk) & 0xFFFFFFF8u); + /* Registers stacked as if auto-saved on exception */ + *(--p_stk) = (OS_STK)0x01000000uL; /* xPSR */ + *(--p_stk) = (OS_STK)task; /* Entry Point */ + *(--p_stk) = (OS_STK)OS_TaskReturn; /* R14 (LR) */ + *(--p_stk) = (OS_STK)0x12121212uL; /* R12 */ + *(--p_stk) = (OS_STK)0x03030303uL; /* R3 */ + *(--p_stk) = (OS_STK)0x02020202uL; /* R2 */ + *(--p_stk) = (OS_STK)0x01010101uL; /* R1 */ + *(--p_stk) = (OS_STK)p_arg; /* R0 : argument */ + + /* Remaining registers saved on process stack */ + *(--p_stk) = (OS_STK)0x11111111uL; /* R11 */ + *(--p_stk) = (OS_STK)0x10101010uL; /* R10 */ + *(--p_stk) = (OS_STK)0x09090909uL; /* R9 */ + *(--p_stk) = (OS_STK)0x08080808uL; /* R8 */ + *(--p_stk) = (OS_STK)0x07070707uL; /* R7 */ + *(--p_stk) = (OS_STK)0x06060606uL; /* R6 */ + *(--p_stk) = (OS_STK)0x05050505uL; /* R5 */ + *(--p_stk) = (OS_STK)0x04040404uL; /* R4 */ + +#if (OS_CPU_ARM_FP_EN > 0u) + if ((opt & OS_TASK_OPT_SAVE_FP) != (INT16U)0) { + *--p_stk = (OS_STK)0x02000000u; /* FPSCR */ + /* Initialize S0-S31 floating point registers */ + *--p_stk = (OS_STK)0x41F80000u; /* S31 */ + *--p_stk = (OS_STK)0x41F00000u; /* S30 */ + *--p_stk = (OS_STK)0x41E80000u; /* S29 */ + *--p_stk = (OS_STK)0x41E00000u; /* S28 */ + *--p_stk = (OS_STK)0x41D80000u; /* S27 */ + *--p_stk = (OS_STK)0x41D00000u; /* S26 */ + *--p_stk = (OS_STK)0x41C80000u; /* S25 */ + *--p_stk = (OS_STK)0x41C00000u; /* S24 */ + *--p_stk = (OS_STK)0x41B80000u; /* S23 */ + *--p_stk = (OS_STK)0x41B00000u; /* S22 */ + *--p_stk = (OS_STK)0x41A80000u; /* S21 */ + *--p_stk = (OS_STK)0x41A00000u; /* S20 */ + *--p_stk = (OS_STK)0x41980000u; /* S19 */ + *--p_stk = (OS_STK)0x41900000u; /* S18 */ + *--p_stk = (OS_STK)0x41880000u; /* S17 */ + *--p_stk = (OS_STK)0x41800000u; /* S16 */ + *--p_stk = (OS_STK)0x41700000u; /* S15 */ + *--p_stk = (OS_STK)0x41600000u; /* S14 */ + *--p_stk = (OS_STK)0x41500000u; /* S13 */ + *--p_stk = (OS_STK)0x41400000u; /* S12 */ + *--p_stk = (OS_STK)0x41300000u; /* S11 */ + *--p_stk = (OS_STK)0x41200000u; /* S10 */ + *--p_stk = (OS_STK)0x41100000u; /* S9 */ + *--p_stk = (OS_STK)0x41000000u; /* S8 */ + *--p_stk = (OS_STK)0x40E00000u; /* S7 */ + *--p_stk = (OS_STK)0x40C00000u; /* S6 */ + *--p_stk = (OS_STK)0x40A00000u; /* S5 */ + *--p_stk = (OS_STK)0x40800000u; /* S4 */ + *--p_stk = (OS_STK)0x40400000u; /* S3 */ + *--p_stk = (OS_STK)0x40000000u; /* S2 */ + *--p_stk = (OS_STK)0x3F800000u; /* S1 */ + *--p_stk = (OS_STK)0x00000000u; /* S0 */ + } +#endif + + return (p_stk); +} + + +/* +********************************************************************************************************* +* TASK SWITCH HOOK +* +* Description: This function is called when a task switch is performed. This allows you to perform other +* operations during a context switch. +* +* Arguments : none +* +* Note(s) : 1) Interrupts are disabled during this call. +* 2) It is assumed that the global pointer 'OSTCBHighRdy' points to the TCB of the task that +* will be 'switched in' (i.e. the highest priority task) and, 'OSTCBCur' points to the +* task being switched out (i.e. the preempted task). +********************************************************************************************************* +*/ +#if (OS_CPU_HOOKS_EN > 0u) && (OS_TASK_SW_HOOK_EN > 0u) +void OSTaskSwHook (void) +{ + +#if (OS_CPU_ARM_FP_EN > 0u) + if ((OSTCBCur->OSTCBOpt & OS_TASK_OPT_SAVE_FP) != (INT16U)0) { + OS_CPU_FP_Reg_Push(OSTCBCur->OSTCBStkPtr); + } + + if ((OSTCBHighRdy->OSTCBOpt & OS_TASK_OPT_SAVE_FP) != (INT16U)0) { + OS_CPU_FP_Reg_Pop(OSTCBHighRdy->OSTCBStkPtr); + } +#endif + +#if OS_APP_HOOKS_EN > 0u + App_TaskSwHook(); +#endif +} +#endif + + +/* +********************************************************************************************************* +* OS_TCBInit() HOOK +* +* Description: This function is called by OS_TCBInit() after setting up most of the TCB. +* +* Arguments : ptcb is a pointer to the TCB of the task being created. +* +* Note(s) : 1) Interrupts may or may not be ENABLED during this call. +********************************************************************************************************* +*/ +#if OS_CPU_HOOKS_EN > 0u +void OSTCBInitHook (OS_TCB *ptcb) +{ +#if OS_APP_HOOKS_EN > 0u + App_TCBInitHook(ptcb); +#else + (void)ptcb; /* Prevent compiler warning */ +#endif +} +#endif + + +/* +********************************************************************************************************* +* TICK HOOK +* +* Description: This function is called every tick. +* +* Arguments : none +* +* Note(s) : 1) Interrupts may or may not be ENABLED during this call. +********************************************************************************************************* +*/ +#if (OS_CPU_HOOKS_EN > 0u) && (OS_TIME_TICK_HOOK_EN > 0u) +void OSTimeTickHook (void) +{ +#if OS_APP_HOOKS_EN > 0u + App_TimeTickHook(); +#endif + +#if OS_TMR_EN > 0u + OSTmrCtr++; + if (OSTmrCtr >= (OS_TICKS_PER_SEC / OS_TMR_CFG_TICKS_PER_SEC)) { + OSTmrCtr = 0; + OSTmrSignal(); + } +#endif +} +#endif + + +/* +********************************************************************************************************* +* SYS TICK HANDLER +* +* Description: Handle the system tick (SysTick) interrupt, which is used to generate the uC/OS-II tick +* interrupt. +* +* Arguments : None. +* +* Note(s) : 1) This function MUST be placed on entry 15 of the Cortex-M3 vector table. +********************************************************************************************************* +*/ + +void OS_CPU_SysTickHandler (void) +{ + OS_CPU_SR cpu_sr; + + + OS_ENTER_CRITICAL(); /* Tell uC/OS-II that we are starting an ISR */ + OSIntNesting++; + OS_EXIT_CRITICAL(); + + OSTimeTick(); /* Call uC/OS-II's OSTimeTick() */ + + OSIntExit(); /* Tell uC/OS-II that we are leaving the ISR */ +} + + +/* +********************************************************************************************************* +* INITIALIZE SYS TICK +* +* Description: Initialize the SysTick. +* +* Arguments : cnts Number of SysTick counts between two OS tick interrupts. +* +* Note(s) : 1) This function MUST be called after OSStart() & after processor initialization. +********************************************************************************************************* +*/ + +void OS_CPU_SysTickInit (INT32U cnts) +{ + INT32U prio; + + + OS_CPU_CM4_NVIC_ST_RELOAD = cnts - 1u; + + /* Set SysTick handler prio. */ + prio = OS_CPU_CM4_NVIC_SHPRI3; + prio &= DEF_BIT_FIELD(24, 0); + prio |= DEF_BIT_MASK(OS_CPU_CFG_SYSTICK_PRIO, 24); + + OS_CPU_CM4_NVIC_SHPRI3 = prio; + + /* Enable timer. */ + OS_CPU_CM4_NVIC_ST_CTRL |= OS_CPU_CM4_NVIC_ST_CTRL_CLK_SRC | + OS_CPU_CM4_NVIC_ST_CTRL_ENABLE; + /* Enable timer interrupt. */ + OS_CPU_CM4_NVIC_ST_CTRL |= OS_CPU_CM4_NVIC_ST_CTRL_INTEN; +} diff --git a/Middlewares/Third_Party/Micrium/uCOS-II/Ports/ARM-Cortex-M4/IAR/os_dbg.c b/Middlewares/Third_Party/Micrium/uCOS-II/Ports/ARM-Cortex-M4/IAR/os_dbg.c new file mode 100644 index 0000000..2d36f2a --- /dev/null +++ b/Middlewares/Third_Party/Micrium/uCOS-II/Ports/ARM-Cortex-M4/IAR/os_dbg.c @@ -0,0 +1,315 @@ +/* +********************************************************************************************************* +* uC/OS-II +* The Real-Time Kernel +* DEBUGGER CONSTANTS +* +* (c) Copyright 1992-2009, Micrium, Weston, FL +* All Rights Reserved +* +* File : OS_DBG.C +* By : Jean J. Labrosse +* Version : V2.92.09 +* +* LICENSING TERMS: +* --------------- +* uC/OS-II is provided in source form for FREE evaluation, for educational use or for peaceful research. +* If you plan on using uC/OS-II in a commercial product you need to contact Micriµm to properly license +* its use in your product. We provide ALL the source code for your convenience and to help you experience +* uC/OS-II. The fact that the source is provided does NOT mean that you can use it without paying a +* licensing fee. +********************************************************************************************************* +*/ + +#include + +#define OS_COMPILER_OPT __root + +/* +********************************************************************************************************* +* DEBUG DATA +********************************************************************************************************* +*/ + +OS_COMPILER_OPT INT16U const OSDebugEn = OS_DEBUG_EN; /* Debug constants are defined below */ + +#if OS_DEBUG_EN > 0u + +OS_COMPILER_OPT INT32U const OSEndiannessTest = 0x12345678L; /* Variable to test CPU endianness */ + +OS_COMPILER_OPT INT16U const OSEventEn = OS_EVENT_EN; +OS_COMPILER_OPT INT16U const OSEventMax = OS_MAX_EVENTS; /* Number of event control blocks */ +OS_COMPILER_OPT INT16U const OSEventNameEn = OS_EVENT_NAME_EN; +#if (OS_EVENT_EN > 0u) && (OS_MAX_EVENTS > 0u) +OS_COMPILER_OPT INT16U const OSEventSize = sizeof(OS_EVENT); /* Size in Bytes of OS_EVENT */ +OS_COMPILER_OPT INT16U const OSEventTblSize = sizeof(OSEventTbl); /* Size of OSEventTbl[] in bytes */ +#else +OS_COMPILER_OPT INT16U const OSEventSize = 0u; +OS_COMPILER_OPT INT16U const OSEventTblSize = 0u; +#endif +OS_COMPILER_OPT INT16U const OSEventMultiEn = OS_EVENT_MULTI_EN; + + +OS_COMPILER_OPT INT16U const OSFlagEn = OS_FLAG_EN; +#if (OS_FLAG_EN > 0u) && (OS_MAX_FLAGS > 0u) +OS_COMPILER_OPT INT16U const OSFlagGrpSize = sizeof(OS_FLAG_GRP); /* Size in Bytes of OS_FLAG_GRP */ +OS_COMPILER_OPT INT16U const OSFlagNodeSize = sizeof(OS_FLAG_NODE); /* Size in Bytes of OS_FLAG_NODE */ +OS_COMPILER_OPT INT16U const OSFlagWidth = sizeof(OS_FLAGS); /* Width (in bytes) of OS_FLAGS */ +#else +OS_COMPILER_OPT INT16U const OSFlagGrpSize = 0u; +OS_COMPILER_OPT INT16U const OSFlagNodeSize = 0u; +OS_COMPILER_OPT INT16U const OSFlagWidth = 0u; +#endif +OS_COMPILER_OPT INT16U const OSFlagMax = OS_MAX_FLAGS; +OS_COMPILER_OPT INT16U const OSFlagNameEn = OS_FLAG_NAME_EN; + +OS_COMPILER_OPT INT16U const OSLowestPrio = OS_LOWEST_PRIO; + +OS_COMPILER_OPT INT16U const OSMboxEn = OS_MBOX_EN; + +OS_COMPILER_OPT INT16U const OSMemEn = OS_MEM_EN; +OS_COMPILER_OPT INT16U const OSMemMax = OS_MAX_MEM_PART; /* Number of memory partitions */ +OS_COMPILER_OPT INT16U const OSMemNameEn = OS_MEM_NAME_EN; +#if (OS_MEM_EN > 0u) && (OS_MAX_MEM_PART > 0u) +OS_COMPILER_OPT INT16U const OSMemSize = sizeof(OS_MEM); /* Mem. Partition header sine (bytes) */ +OS_COMPILER_OPT INT16U const OSMemTblSize = sizeof(OSMemTbl); +#else +OS_COMPILER_OPT INT16U const OSMemSize = 0u; +OS_COMPILER_OPT INT16U const OSMemTblSize = 0u; +#endif +OS_COMPILER_OPT INT16U const OSMutexEn = OS_MUTEX_EN; + +OS_COMPILER_OPT INT16U const OSPtrSize = sizeof(void *); /* Size in Bytes of a pointer */ + +OS_COMPILER_OPT INT16U const OSQEn = OS_Q_EN; +OS_COMPILER_OPT INT16U const OSQMax = OS_MAX_QS; /* Number of queues */ +#if (OS_Q_EN > 0u) && (OS_MAX_QS > 0u) +OS_COMPILER_OPT INT16U const OSQSize = sizeof(OS_Q); /* Size in bytes of OS_Q structure */ +#else +OS_COMPILER_OPT INT16U const OSQSize = 0u; +#endif + +OS_COMPILER_OPT INT16U const OSRdyTblSize = OS_RDY_TBL_SIZE; /* Number of bytes in the ready table */ + +OS_COMPILER_OPT INT16U const OSSemEn = OS_SEM_EN; + +OS_COMPILER_OPT INT16U const OSStkWidth = sizeof(OS_STK); /* Size in Bytes of a stack entry */ + +OS_COMPILER_OPT INT16U const OSTaskCreateEn = OS_TASK_CREATE_EN; +OS_COMPILER_OPT INT16U const OSTaskCreateExtEn = OS_TASK_CREATE_EXT_EN; +OS_COMPILER_OPT INT16U const OSTaskDelEn = OS_TASK_DEL_EN; +OS_COMPILER_OPT INT16U const OSTaskIdleStkSize = OS_TASK_IDLE_STK_SIZE; +OS_COMPILER_OPT INT16U const OSTaskProfileEn = OS_TASK_PROFILE_EN; +OS_COMPILER_OPT INT16U const OSTaskMax = OS_MAX_TASKS + OS_N_SYS_TASKS; /* Total max. number of tasks */ +OS_COMPILER_OPT INT16U const OSTaskNameEn = OS_TASK_NAME_EN; +OS_COMPILER_OPT INT16U const OSTaskStatEn = OS_TASK_STAT_EN; +OS_COMPILER_OPT INT16U const OSTaskStatStkSize = OS_TASK_STAT_STK_SIZE; +OS_COMPILER_OPT INT16U const OSTaskStatStkChkEn = OS_TASK_STAT_STK_CHK_EN; +OS_COMPILER_OPT INT16U const OSTaskSwHookEn = OS_TASK_SW_HOOK_EN; +OS_COMPILER_OPT INT16U const OSTaskRegTblSize = OS_TASK_REG_TBL_SIZE; + +OS_COMPILER_OPT INT16U const OSTCBPrioTblMax = OS_LOWEST_PRIO + 1u; /* Number of entries in OSTCBPrioTbl[] */ +OS_COMPILER_OPT INT16U const OSTCBSize = sizeof(OS_TCB); /* Size in Bytes of OS_TCB */ +OS_COMPILER_OPT INT16U const OSTicksPerSec = OS_TICKS_PER_SEC; +OS_COMPILER_OPT INT16U const OSTimeTickHookEn = OS_TIME_TICK_HOOK_EN; +OS_COMPILER_OPT INT16U const OSVersionNbr = OS_VERSION; + +OS_COMPILER_OPT INT16U const OSTmrEn = OS_TMR_EN; +OS_COMPILER_OPT INT16U const OSTmrCfgMax = OS_TMR_CFG_MAX; +OS_COMPILER_OPT INT16U const OSTmrCfgNameEn = OS_TMR_CFG_NAME_EN; +OS_COMPILER_OPT INT16U const OSTmrCfgWheelSize = OS_TMR_CFG_WHEEL_SIZE; +OS_COMPILER_OPT INT16U const OSTmrCfgTicksPerSec = OS_TMR_CFG_TICKS_PER_SEC; + +#if (OS_TMR_EN > 0u) && (OS_TMR_CFG_MAX > 0u) +OS_COMPILER_OPT INT16U const OSTmrSize = sizeof(OS_TMR); +OS_COMPILER_OPT INT16U const OSTmrTblSize = sizeof(OSTmrTbl); +OS_COMPILER_OPT INT16U const OSTmrWheelSize = sizeof(OS_TMR_WHEEL); +OS_COMPILER_OPT INT16U const OSTmrWheelTblSize = sizeof(OSTmrWheelTbl); +#else +OS_COMPILER_OPT INT16U const OSTmrSize = 0u; +OS_COMPILER_OPT INT16U const OSTmrTblSize = 0u; +OS_COMPILER_OPT INT16U const OSTmrWheelSize = 0u; +OS_COMPILER_OPT INT16U const OSTmrWheelTblSize = 0u; +#endif + +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* DEBUG DATA +* TOTAL DATA SPACE (i.e. RAM) USED BY uC/OS-II +********************************************************************************************************* +*/ +#if OS_DEBUG_EN > 0u + +OS_COMPILER_OPT INT16U const OSDataSize = sizeof(OSCtxSwCtr) +#if (OS_EVENT_EN > 0u) && (OS_MAX_EVENTS > 0u) + + sizeof(OSEventFreeList) + + sizeof(OSEventTbl) +#endif +#if (OS_FLAG_EN > 0u) && (OS_MAX_FLAGS > 0u) + + sizeof(OSFlagTbl) + + sizeof(OSFlagFreeList) +#endif +#if OS_TASK_STAT_EN > 0u + + sizeof(OSCPUUsage) + + sizeof(OSIdleCtrMax) + + sizeof(OSIdleCtrRun) + + sizeof(OSStatRdy) + + sizeof(OSTaskStatStk) +#endif +#if OS_TICK_STEP_EN > 0u + + sizeof(OSTickStepState) +#endif +#if (OS_MEM_EN > 0u) && (OS_MAX_MEM_PART > 0u) + + sizeof(OSMemFreeList) + + sizeof(OSMemTbl) +#endif +#if (OS_Q_EN > 0u) && (OS_MAX_QS > 0u) + + sizeof(OSQFreeList) + + sizeof(OSQTbl) +#endif +#if OS_TIME_GET_SET_EN > 0u + + sizeof(OSTime) +#endif +#if (OS_TMR_EN > 0u) && (OS_TMR_CFG_MAX > 0u) + + sizeof(OSTmrFree) + + sizeof(OSTmrUsed) + + sizeof(OSTmrTime) + + sizeof(OSTmrSem) + + sizeof(OSTmrSemSignal) + + sizeof(OSTmrTbl) + + sizeof(OSTmrFreeList) + + sizeof(OSTmrTaskStk) + + sizeof(OSTmrWheelTbl) +#endif + + sizeof(OSIntNesting) + + sizeof(OSLockNesting) + + sizeof(OSPrioCur) + + sizeof(OSPrioHighRdy) + + sizeof(OSRdyGrp) + + sizeof(OSRdyTbl) + + sizeof(OSRunning) + + sizeof(OSTaskCtr) + + sizeof(OSIdleCtr) + + sizeof(OSTaskIdleStk) + + sizeof(OSTCBCur) + + sizeof(OSTCBFreeList) + + sizeof(OSTCBHighRdy) + + sizeof(OSTCBList) + + sizeof(OSTCBPrioTbl) + + sizeof(OSTCBTbl); + +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* OS DEBUG INITIALIZATION +* +* Description: This function is used to make sure that debug variables that are unused in the application +* are not optimized away. This function might not be necessary for all compilers. In this +* case, you should simply DELETE the code in this function while still leaving the declaration +* of the function itself. +* +* Arguments : none +* +* Returns : none +* +* Note(s) : (1) This code doesn't do anything, it simply prevents the compiler from optimizing out +* the 'const' variables which are declared in this file. +* (2) You may decide to 'compile out' the code (by using #if 0/#endif) INSIDE the function +* if your compiler DOES NOT optimize out the 'const' variables above. +********************************************************************************************************* +*/ + +#if OS_DEBUG_EN > 0u +void OSDebugInit (void) +{ + void *ptemp; + + + ptemp = (void *)&OSDebugEn; + + ptemp = (void *)&OSEndiannessTest; + + ptemp = (void *)&OSEventMax; + ptemp = (void *)&OSEventNameEn; + ptemp = (void *)&OSEventEn; + ptemp = (void *)&OSEventSize; + ptemp = (void *)&OSEventTblSize; + ptemp = (void *)&OSEventMultiEn; + + ptemp = (void *)&OSFlagEn; + ptemp = (void *)&OSFlagGrpSize; + ptemp = (void *)&OSFlagNodeSize; + ptemp = (void *)&OSFlagWidth; + ptemp = (void *)&OSFlagMax; + ptemp = (void *)&OSFlagNameEn; + + ptemp = (void *)&OSLowestPrio; + + ptemp = (void *)&OSMboxEn; + + ptemp = (void *)&OSMemEn; + ptemp = (void *)&OSMemMax; + ptemp = (void *)&OSMemNameEn; + ptemp = (void *)&OSMemSize; + ptemp = (void *)&OSMemTblSize; + + ptemp = (void *)&OSMutexEn; + + ptemp = (void *)&OSPtrSize; + + ptemp = (void *)&OSQEn; + ptemp = (void *)&OSQMax; + ptemp = (void *)&OSQSize; + + ptemp = (void *)&OSRdyTblSize; + + ptemp = (void *)&OSSemEn; + + ptemp = (void *)&OSStkWidth; + + ptemp = (void *)&OSTaskCreateEn; + ptemp = (void *)&OSTaskCreateExtEn; + ptemp = (void *)&OSTaskDelEn; + ptemp = (void *)&OSTaskIdleStkSize; + ptemp = (void *)&OSTaskProfileEn; + ptemp = (void *)&OSTaskMax; + ptemp = (void *)&OSTaskNameEn; + ptemp = (void *)&OSTaskStatEn; + ptemp = (void *)&OSTaskStatStkSize; + ptemp = (void *)&OSTaskStatStkChkEn; + ptemp = (void *)&OSTaskSwHookEn; + + ptemp = (void *)&OSTCBPrioTblMax; + ptemp = (void *)&OSTCBSize; + + ptemp = (void *)&OSTicksPerSec; + ptemp = (void *)&OSTimeTickHookEn; + +#if OS_TMR_EN > 0u + ptemp = (void *)&OSTmrTbl[0]; + ptemp = (void *)&OSTmrWheelTbl[0]; + + ptemp = (void *)&OSTmrEn; + ptemp = (void *)&OSTmrCfgMax; + ptemp = (void *)&OSTmrCfgNameEn; + ptemp = (void *)&OSTmrCfgWheelSize; + ptemp = (void *)&OSTmrCfgTicksPerSec; + ptemp = (void *)&OSTmrSize; + ptemp = (void *)&OSTmrTblSize; + + ptemp = (void *)&OSTmrWheelSize; + ptemp = (void *)&OSTmrWheelTblSize; +#endif + + ptemp = (void *)&OSVersionNbr; + + ptemp = (void *)&OSDataSize; + + ptemp = ptemp; /* Prevent compiler warning for 'ptemp' not being used! */ +} +#endif diff --git a/Middlewares/Third_Party/Micrium/uCOS-II/Source/os.h b/Middlewares/Third_Party/Micrium/uCOS-II/Source/os.h new file mode 100644 index 0000000..98c30c7 --- /dev/null +++ b/Middlewares/Third_Party/Micrium/uCOS-II/Source/os.h @@ -0,0 +1,29 @@ +/* +********************************************************************************************************* +* uC/OS-II +* The Real-Time Kernel +* +* (c) Copyright 1992-2013, Micrium, Weston, FL +* All Rights Reserved +* +* File : os.h +* By : Jean J. Labrosse +* Version : V2.92.10 +* +* LICENSING TERMS: +* --------------- +* uC/OS-II is provided in source form for FREE evaluation, for educational use or for peaceful research. +* If you plan on using uC/OS-II in a commercial product you need to contact Micrium to properly license +* its use in your product. We provide ALL the source code for your convenience and to help you experience +* uC/OS-II. The fact that the source is provided does NOT mean that you can use it without paying a +* licensing fee. +* +* Note : This file is included in the uC/OS-II for compatibility with uC/OS-III and should not be used +* in normal circumstances. +********************************************************************************************************* +*/ + +#include + + +typedef INT8U OS_ERR; diff --git a/Middlewares/Third_Party/Micrium/uCOS-II/Source/os_core.c b/Middlewares/Third_Party/Micrium/uCOS-II/Source/os_core.c new file mode 100644 index 0000000..53a3a6c --- /dev/null +++ b/Middlewares/Third_Party/Micrium/uCOS-II/Source/os_core.c @@ -0,0 +1,2092 @@ +/* +********************************************************************************************************* +* uC/OS-II +* The Real-Time Kernel +* CORE FUNCTIONS +* +* (c) Copyright 1992-2013, Micrium, Weston, FL +* All Rights Reserved +* +* File : OS_CORE.C +* By : Jean J. Labrosse +* Version : V2.92.10 +* +* LICENSING TERMS: +* --------------- +* uC/OS-II is provided in source form for FREE evaluation, for educational use or for peaceful research. +* If you plan on using uC/OS-II in a commercial product you need to contact Micrium to properly license +* its use in your product. We provide ALL the source code for your convenience and to help you experience +* uC/OS-II. The fact that the source is provided does NOT mean that you can use it without paying a +* licensing fee. +********************************************************************************************************* +*/ + +#define MICRIUM_SOURCE + +#ifndef OS_MASTER_FILE +#define OS_GLOBALS +#include +#endif + +/* +********************************************************************************************************* +* PRIORITY RESOLUTION TABLE +* +* Note: Index into table is bit pattern to resolve highest priority +* Indexed value corresponds to highest priority bit position (i.e. 0..7) +********************************************************************************************************* +*/ + +INT8U const OSUnMapTbl[256] = { + 0u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, /* 0x00 to 0x0F */ + 4u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, /* 0x10 to 0x1F */ + 5u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, /* 0x20 to 0x2F */ + 4u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, /* 0x30 to 0x3F */ + 6u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, /* 0x40 to 0x4F */ + 4u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, /* 0x50 to 0x5F */ + 5u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, /* 0x60 to 0x6F */ + 4u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, /* 0x70 to 0x7F */ + 7u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, /* 0x80 to 0x8F */ + 4u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, /* 0x90 to 0x9F */ + 5u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, /* 0xA0 to 0xAF */ + 4u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, /* 0xB0 to 0xBF */ + 6u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, /* 0xC0 to 0xCF */ + 4u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, /* 0xD0 to 0xDF */ + 5u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, /* 0xE0 to 0xEF */ + 4u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u /* 0xF0 to 0xFF */ +}; + +/*$PAGE*/ +/* +********************************************************************************************************* +* FUNCTION PROTOTYPES +********************************************************************************************************* +*/ + +static void OS_InitEventList(void); + +static void OS_InitMisc(void); + +static void OS_InitRdyList(void); + +static void OS_InitTaskIdle(void); + +#if OS_TASK_STAT_EN > 0u +static void OS_InitTaskStat(void); +#endif + +static void OS_InitTCBList(void); + +static void OS_SchedNew(void); + +/*$PAGE*/ +/* +********************************************************************************************************* +* GET THE NAME OF A SEMAPHORE, MUTEX, MAILBOX or QUEUE +* +* Description: This function is used to obtain the name assigned to a semaphore, mutex, mailbox or queue. +* +* Arguments : pevent is a pointer to the event group. 'pevent' can point either to a semaphore, +* a mutex, a mailbox or a queue. Where this function is concerned, the actual +* type is irrelevant. +* +* pname is a pointer to a pointer to an ASCII string that will receive the name of the semaphore, +* mutex, mailbox or queue. +* +* perr is a pointer to an error code that can contain one of the following values: +* +* OS_ERR_NONE if the name was copied to 'pname' +* OS_ERR_EVENT_TYPE if 'pevent' is not pointing to the proper event +* control block type. +* OS_ERR_PNAME_NULL You passed a NULL pointer for 'pname' +* OS_ERR_PEVENT_NULL if you passed a NULL pointer for 'pevent' +* OS_ERR_NAME_GET_ISR if you are trying to call this function from an ISR +* +* Returns : The length of the string or 0 if the 'pevent' is a NULL pointer. +********************************************************************************************************* +*/ + +#if (OS_EVENT_EN) && (OS_EVENT_NAME_EN > 0u) +INT8U OSEventNameGet (OS_EVENT *pevent, + INT8U **pname, + INT8U *perr) +{ + INT8U len; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#ifdef OS_SAFETY_CRITICAL + if (perr == (INT8U *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return (0u); + } +#endif + +#if OS_ARG_CHK_EN > 0u + if (pevent == (OS_EVENT *)0) { /* Is 'pevent' a NULL pointer? */ + *perr = OS_ERR_PEVENT_NULL; + return (0u); + } + if (pname == (INT8U **)0) { /* Is 'pname' a NULL pointer? */ + *perr = OS_ERR_PNAME_NULL; + return (0u); + } +#endif + if (OSIntNesting > 0u) { /* See if trying to call from an ISR */ + *perr = OS_ERR_NAME_GET_ISR; + return (0u); + } + switch (pevent->OSEventType) { + case OS_EVENT_TYPE_SEM: + case OS_EVENT_TYPE_MUTEX: + case OS_EVENT_TYPE_MBOX: + case OS_EVENT_TYPE_Q: + break; + + default: + *perr = OS_ERR_EVENT_TYPE; + return (0u); + } + OS_ENTER_CRITICAL(); + *pname = pevent->OSEventName; + len = OS_StrLen(*pname); + OS_EXIT_CRITICAL(); + *perr = OS_ERR_NONE; + return (len); +} +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* ASSIGN A NAME TO A SEMAPHORE, MUTEX, MAILBOX or QUEUE +* +* Description: This function assigns a name to a semaphore, mutex, mailbox or queue. +* +* Arguments : pevent is a pointer to the event group. 'pevent' can point either to a semaphore, +* a mutex, a mailbox or a queue. Where this function is concerned, it doesn't +* matter the actual type. +* +* pname is a pointer to an ASCII string that will be used as the name of the semaphore, +* mutex, mailbox or queue. +* +* perr is a pointer to an error code that can contain one of the following values: +* +* OS_ERR_NONE if the requested task is resumed +* OS_ERR_EVENT_TYPE if 'pevent' is not pointing to the proper event +* control block type. +* OS_ERR_PNAME_NULL You passed a NULL pointer for 'pname' +* OS_ERR_PEVENT_NULL if you passed a NULL pointer for 'pevent' +* OS_ERR_NAME_SET_ISR if you called this function from an ISR +* +* Returns : None +********************************************************************************************************* +*/ + +#if (OS_EVENT_EN) && (OS_EVENT_NAME_EN > 0u) +void OSEventNameSet (OS_EVENT *pevent, + INT8U *pname, + INT8U *perr) +{ +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#ifdef OS_SAFETY_CRITICAL + if (perr == (INT8U *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return; + } +#endif + +#if OS_ARG_CHK_EN > 0u + if (pevent == (OS_EVENT *)0) { /* Is 'pevent' a NULL pointer? */ + *perr = OS_ERR_PEVENT_NULL; + return; + } + if (pname == (INT8U *)0) { /* Is 'pname' a NULL pointer? */ + *perr = OS_ERR_PNAME_NULL; + return; + } +#endif + if (OSIntNesting > 0u) { /* See if trying to call from an ISR */ + *perr = OS_ERR_NAME_SET_ISR; + return; + } + switch (pevent->OSEventType) { + case OS_EVENT_TYPE_SEM: + case OS_EVENT_TYPE_MUTEX: + case OS_EVENT_TYPE_MBOX: + case OS_EVENT_TYPE_Q: + break; + + default: + *perr = OS_ERR_EVENT_TYPE; + return; + } + OS_ENTER_CRITICAL(); + pevent->OSEventName = pname; + OS_EXIT_CRITICAL(); + *perr = OS_ERR_NONE; +} +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* PEND ON MULTIPLE EVENTS +* +* Description: This function waits for multiple events. If multiple events are ready at the start of the +* pend call, then all available events are returned as ready. If the task must pend on the +* multiple events, then only the first posted or aborted event is returned as ready. +* +* Arguments : pevents_pend is a pointer to a NULL-terminated array of event control blocks to wait for. +* +* pevents_rdy is a pointer to an array to return which event control blocks are available +* or ready. The size of the array MUST be greater than or equal to the size +* of the 'pevents_pend' array, including terminating NULL. +* +* pmsgs_rdy is a pointer to an array to return messages from any available message-type +* events. The size of the array MUST be greater than or equal to the size of +* the 'pevents_pend' array, excluding the terminating NULL. Since NULL +* messages are valid messages, this array cannot be NULL-terminated. Instead, +* every available message-type event returns its messages in the 'pmsgs_rdy' +* array at the same index as the event is returned in the 'pevents_rdy' array. +* All other 'pmsgs_rdy' array indices are filled with NULL messages. +* +* timeout is an optional timeout period (in clock ticks). If non-zero, your task will +* wait for the resources up to the amount of time specified by this argument. +* If you specify 0, however, your task will wait forever for the specified +* events or, until the resources becomes available (or the events occur). +* +* perr is a pointer to where an error message will be deposited. Possible error +* messages are: +* +* OS_ERR_NONE The call was successful and your task owns the resources +* or, the events you are waiting for occurred; check the +* 'pevents_rdy' array for which events are available. +* OS_ERR_PEND_ABORT The wait on the events was aborted; check the +* 'pevents_rdy' array for which events were aborted. +* OS_ERR_TIMEOUT The events were not received within the specified +* 'timeout'. +* OS_ERR_PEVENT_NULL If 'pevents_pend', 'pevents_rdy', or 'pmsgs_rdy' is a +* NULL pointer. +* OS_ERR_EVENT_TYPE If you didn't pass a pointer to an array of semaphores, +* mailboxes, and/or queues. +* OS_ERR_PEND_ISR If you called this function from an ISR and the result +* would lead to a suspension. +* OS_ERR_PEND_LOCKED If you called this function when the scheduler is locked. +* +* Returns : > 0 the number of events returned as ready or aborted. +* == 0 if no events are returned as ready because of timeout or upon error. +* +* Notes : 1) a. Validate 'pevents_pend' array as valid OS_EVENTs : +* +* semaphores, mailboxes, queues +* +* b. Return ALL available events and messages, if any +* +* c. Add current task priority as pending to each events's wait list +* Performed in OS_EventTaskWaitMulti() +* +* d. Wait on any of multiple events +* +* e. Remove current task priority as pending from each events's wait list +* Performed in OS_EventTaskRdy(), if events posted or aborted +* +* f. Return any event posted or aborted, if any +* else +* Return timeout +* +* 2) 'pevents_rdy' initialized to NULL PRIOR to all other validation or function handling in +* case of any error(s). +********************************************************************************************************* +*/ +/*$PAGE*/ +#if ((OS_EVENT_EN) && (OS_EVENT_MULTI_EN > 0u)) +INT16U OSEventPendMulti (OS_EVENT **pevents_pend, + OS_EVENT **pevents_rdy, + void **pmsgs_rdy, + INT32U timeout, + INT8U *perr) +{ + OS_EVENT **pevents; + OS_EVENT *pevent; +#if ((OS_Q_EN > 0u) && (OS_MAX_QS > 0u)) + OS_Q *pq; +#endif + BOOLEAN events_rdy; + INT16U events_rdy_nbr; + INT8U events_stat; +#if (OS_CRITICAL_METHOD == 3u) /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#ifdef OS_SAFETY_CRITICAL + if (perr == (INT8U *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return (0u); + } +#endif + +#if (OS_ARG_CHK_EN > 0u) + if (pevents_pend == (OS_EVENT **)0) { /* Validate 'pevents_pend' */ + *perr = OS_ERR_PEVENT_NULL; + return (0u); + } + if (*pevents_pend == (OS_EVENT *)0) { /* Validate 'pevents_pend' */ + *perr = OS_ERR_PEVENT_NULL; + return (0u); + } + if (pevents_rdy == (OS_EVENT **)0) { /* Validate 'pevents_rdy' */ + *perr = OS_ERR_PEVENT_NULL; + return (0u); + } + if (pmsgs_rdy == (void **)0) { /* Validate 'pmsgs_rdy' */ + *perr = OS_ERR_PEVENT_NULL; + return (0u); + } +#endif + + *pevents_rdy = (OS_EVENT *)0; /* Init array to NULL in case of errors */ + + pevents = pevents_pend; + pevent = *pevents; + while (pevent != (OS_EVENT *)0) { + switch (pevent->OSEventType) { /* Validate event block types */ +#if (OS_SEM_EN > 0u) + case OS_EVENT_TYPE_SEM: + break; +#endif +#if (OS_MBOX_EN > 0u) + case OS_EVENT_TYPE_MBOX: + break; +#endif +#if ((OS_Q_EN > 0u) && (OS_MAX_QS > 0u)) + case OS_EVENT_TYPE_Q: + break; +#endif + + case OS_EVENT_TYPE_MUTEX: + case OS_EVENT_TYPE_FLAG: + default: + *perr = OS_ERR_EVENT_TYPE; + return (0u); + } + pevents++; + pevent = *pevents; + } + + if (OSIntNesting > 0u) { /* See if called from ISR ... */ + *perr = OS_ERR_PEND_ISR; /* ... can't PEND from an ISR */ + return (0u); + } + if (OSLockNesting > 0u) { /* See if called with scheduler locked ... */ + *perr = OS_ERR_PEND_LOCKED; /* ... can't PEND when locked */ + return (0u); + } + +/*$PAGE*/ + events_rdy = OS_FALSE; + events_rdy_nbr = 0u; + events_stat = OS_STAT_RDY; + pevents = pevents_pend; + pevent = *pevents; + OS_ENTER_CRITICAL(); + while (pevent != (OS_EVENT *)0) { /* See if any events already available */ + switch (pevent->OSEventType) { +#if (OS_SEM_EN > 0u) + case OS_EVENT_TYPE_SEM: + if (pevent->OSEventCnt > 0u) { /* If semaphore count > 0, resource available; */ + pevent->OSEventCnt--; /* ... decrement semaphore, ... */ + *pevents_rdy++ = pevent; /* ... and return available semaphore event */ + events_rdy = OS_TRUE; + *pmsgs_rdy++ = (void *)0; /* NO message returned for semaphores */ + events_rdy_nbr++; + + } else { + events_stat |= OS_STAT_SEM; /* Configure multi-pend for semaphore events */ + } + break; +#endif + +#if (OS_MBOX_EN > 0u) + case OS_EVENT_TYPE_MBOX: + if (pevent->OSEventPtr != (void *)0) { /* If mailbox NOT empty; ... */ + /* ... return available message, ... */ + *pmsgs_rdy++ = (void *)pevent->OSEventPtr; + pevent->OSEventPtr = (void *)0; + *pevents_rdy++ = pevent; /* ... and return available mailbox event */ + events_rdy = OS_TRUE; + events_rdy_nbr++; + + } else { + events_stat |= OS_STAT_MBOX; /* Configure multi-pend for mailbox events */ + } + break; +#endif + +#if ((OS_Q_EN > 0u) && (OS_MAX_QS > 0u)) + case OS_EVENT_TYPE_Q: + pq = (OS_Q *)pevent->OSEventPtr; + if (pq->OSQEntries > 0u) { /* If queue NOT empty; ... */ + /* ... return available message, ... */ + *pmsgs_rdy++ = (void *)*pq->OSQOut++; + if (pq->OSQOut == pq->OSQEnd) { /* If OUT ptr at queue end, ... */ + pq->OSQOut = pq->OSQStart; /* ... wrap to queue start */ + } + pq->OSQEntries--; /* Update number of queue entries */ + *pevents_rdy++ = pevent; /* ... and return available queue event */ + events_rdy = OS_TRUE; + events_rdy_nbr++; + + } else { + events_stat |= OS_STAT_Q; /* Configure multi-pend for queue events */ + } + break; +#endif + + case OS_EVENT_TYPE_MUTEX: + case OS_EVENT_TYPE_FLAG: + default: + OS_EXIT_CRITICAL(); + *pevents_rdy = (OS_EVENT *)0; /* NULL terminate return event array */ + *perr = OS_ERR_EVENT_TYPE; + return (events_rdy_nbr); + } + pevents++; + pevent = *pevents; + } + + if ( events_rdy == OS_TRUE) { /* Return any events already available */ + *pevents_rdy = (OS_EVENT *)0; /* NULL terminate return event array */ + OS_EXIT_CRITICAL(); + *perr = OS_ERR_NONE; + return (events_rdy_nbr); + } +/*$PAGE*/ + /* Otherwise, must wait until any event occurs */ + OSTCBCur->OSTCBStat |= events_stat | /* Resource not available, ... */ + OS_STAT_MULTI; /* ... pend on multiple events */ + OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK; + OSTCBCur->OSTCBDly = timeout; /* Store pend timeout in TCB */ + OS_EventTaskWaitMulti(pevents_pend); /* Suspend task until events or timeout occurs */ + + OS_EXIT_CRITICAL(); + OS_Sched(); /* Find next highest priority task ready */ + OS_ENTER_CRITICAL(); + + switch (OSTCBCur->OSTCBStatPend) { /* Handle event posted, aborted, or timed-out */ + case OS_STAT_PEND_OK: + case OS_STAT_PEND_ABORT: + pevent = OSTCBCur->OSTCBEventPtr; + if (pevent != (OS_EVENT *)0) { /* If task event ptr != NULL, ... */ + *pevents_rdy++ = pevent; /* ... return available event ... */ + *pevents_rdy = (OS_EVENT *)0; /* ... & NULL terminate return event array */ + events_rdy_nbr = 1; + + } else { /* Else NO event available, handle as timeout */ + OSTCBCur->OSTCBStatPend = OS_STAT_PEND_TO; + OS_EventTaskRemoveMulti(OSTCBCur, pevents_pend); + } + break; + + case OS_STAT_PEND_TO: /* If events timed out, ... */ + default: /* ... remove task from events' wait lists */ + OS_EventTaskRemoveMulti(OSTCBCur, pevents_pend); + break; + } + + switch (OSTCBCur->OSTCBStatPend) { + case OS_STAT_PEND_OK: + switch (pevent->OSEventType) { /* Return event's message */ +#if (OS_SEM_EN > 0u) + case OS_EVENT_TYPE_SEM: + *pmsgs_rdy++ = (void *)0; /* NO message returned for semaphores */ + break; +#endif + +#if ((OS_MBOX_EN > 0u) || \ + ((OS_Q_EN > 0u) && (OS_MAX_QS > 0u))) + case OS_EVENT_TYPE_MBOX: + case OS_EVENT_TYPE_Q: + *pmsgs_rdy++ = (void *)OSTCBCur->OSTCBMsg; /* Return received message */ + break; +#endif + + case OS_EVENT_TYPE_MUTEX: + case OS_EVENT_TYPE_FLAG: + default: + OS_EXIT_CRITICAL(); + *pevents_rdy = (OS_EVENT *)0; /* NULL terminate return event array */ + *perr = OS_ERR_EVENT_TYPE; + return (events_rdy_nbr); + } + *perr = OS_ERR_NONE; + break; + + case OS_STAT_PEND_ABORT: + *pmsgs_rdy++ = (void *)0; /* NO message returned for abort */ + *perr = OS_ERR_PEND_ABORT; /* Indicate that event aborted */ + break; + + case OS_STAT_PEND_TO: + default: + *pmsgs_rdy++ = (void *)0; /* NO message returned for timeout */ + *perr = OS_ERR_TIMEOUT; /* Indicate that events timed out */ + break; + } + + OSTCBCur->OSTCBStat = OS_STAT_RDY; /* Set task status to ready */ + OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK; /* Clear pend status */ + OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; /* Clear event pointers */ + OSTCBCur->OSTCBEventMultiPtr = (OS_EVENT **)0; +#if ((OS_MBOX_EN > 0u) || \ + ((OS_Q_EN > 0u) && (OS_MAX_QS > 0u))) + OSTCBCur->OSTCBMsg = (void *)0; /* Clear task message */ +#endif + OS_EXIT_CRITICAL(); + + return (events_rdy_nbr); +} +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* INITIALIZATION +* +* Description: This function is used to initialize the internals of uC/OS-II and MUST be called prior to +* creating any uC/OS-II object and, prior to calling OSStart(). +* +* Arguments : none +* +* Returns : none +********************************************************************************************************* +*/ + +void OSInit (void) +{ +#if OS_TASK_CREATE_EXT_EN > 0u +#if defined(OS_TLS_TBL_SIZE) && (OS_TLS_TBL_SIZE > 0u) + INT8U err; +#endif +#endif + + OSInitHookBegin(); /* Call port specific initialization code */ + + OS_InitMisc(); /* Initialize miscellaneous variables */ + + OS_InitRdyList(); /* Initialize the Ready List */ + + OS_InitTCBList(); /* Initialize the free list of OS_TCBs */ + + OS_InitEventList(); /* Initialize the free list of OS_EVENTs */ + +#if (OS_FLAG_EN > 0u) && (OS_MAX_FLAGS > 0u) + OS_FlagInit(); /* Initialize the event flag structures */ +#endif + +#if (OS_MEM_EN > 0u) && (OS_MAX_MEM_PART > 0u) + OS_MemInit(); /* Initialize the memory manager */ +#endif + +#if (OS_Q_EN > 0u) && (OS_MAX_QS > 0u) + OS_QInit(); /* Initialize the message queue structures */ +#endif + +#if OS_TASK_CREATE_EXT_EN > 0u +#if defined(OS_TLS_TBL_SIZE) && (OS_TLS_TBL_SIZE > 0u) + OS_TLS_Init(&err); /* Initialize TLS, before creating tasks */ + if (err != OS_ERR_NONE) { + return; + } +#endif +#endif + + OS_InitTaskIdle(); /* Create the Idle Task */ +#if OS_TASK_STAT_EN > 0u + OS_InitTaskStat(); /* Create the Statistic Task */ +#endif + +#if OS_TMR_EN > 0u + OSTmr_Init(); /* Initialize the Timer Manager */ +#endif + + OSInitHookEnd(); /* Call port specific init. code */ + +#if OS_DEBUG_EN > 0u + OSDebugInit(); +#endif +} +/*$PAGE*/ +/* +********************************************************************************************************* +* ENTER ISR +* +* Description: This function is used to notify uC/OS-II that you are about to service an interrupt +* service routine (ISR). This allows uC/OS-II to keep track of interrupt nesting and thus +* only perform rescheduling at the last nested ISR. +* +* Arguments : none +* +* Returns : none +* +* Notes : 1) This function should be called with interrupts already disabled +* 2) Your ISR can directly increment OSIntNesting without calling this function because +* OSIntNesting has been declared 'global'. +* 3) You MUST still call OSIntExit() even though you increment OSIntNesting directly. +* 4) You MUST invoke OSIntEnter() and OSIntExit() in pair. In other words, for every call +* to OSIntEnter() at the beginning of the ISR you MUST have a call to OSIntExit() at the +* end of the ISR. +* 5) You are allowed to nest interrupts up to 255 levels deep. +* 6) I removed the OS_ENTER_CRITICAL() and OS_EXIT_CRITICAL() around the increment because +* OSIntEnter() is always called with interrupts disabled. +********************************************************************************************************* +*/ + +void OSIntEnter (void) +{ + if (OSRunning == OS_TRUE) { + if (OSIntNesting < 255u) { + OSIntNesting++; /* Increment ISR nesting level */ + } + } +} +/*$PAGE*/ +/* +********************************************************************************************************* +* EXIT ISR +* +* Description: This function is used to notify uC/OS-II that you have completed servicing an ISR. When +* the last nested ISR has completed, uC/OS-II will call the scheduler to determine whether +* a new, high-priority task, is ready to run. +* +* Arguments : none +* +* Returns : none +* +* Notes : 1) You MUST invoke OSIntEnter() and OSIntExit() in pair. In other words, for every call +* to OSIntEnter() at the beginning of the ISR you MUST have a call to OSIntExit() at the +* end of the ISR. +* 2) Rescheduling is prevented when the scheduler is locked (see OS_SchedLock()) +********************************************************************************************************* +*/ + +void OSIntExit (void) +{ +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + + if (OSRunning == OS_TRUE) { + OS_ENTER_CRITICAL(); + if (OSIntNesting > 0u) { /* Prevent OSIntNesting from wrapping */ + OSIntNesting--; + } + if (OSIntNesting == 0u) { /* Reschedule only if all ISRs complete ... */ + if (OSLockNesting == 0u) { /* ... and not locked. */ + OS_SchedNew(); + OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy]; + if (OSPrioHighRdy != OSPrioCur) { /* No Ctx Sw if current task is highest rdy */ +#if OS_TASK_PROFILE_EN > 0u + OSTCBHighRdy->OSTCBCtxSwCtr++; /* Inc. # of context switches to this task */ +#endif + OSCtxSwCtr++; /* Keep track of the number of ctx switches */ + +#if OS_TASK_CREATE_EXT_EN > 0u +#if defined(OS_TLS_TBL_SIZE) && (OS_TLS_TBL_SIZE > 0u) + OS_TLS_TaskSw(); +#endif +#endif + + OSIntCtxSw(); /* Perform interrupt level ctx switch */ + } + } + } + OS_EXIT_CRITICAL(); + } +} +/*$PAGE*/ +/* +********************************************************************************************************* +* INDICATE THAT IT'S NO LONGER SAFE TO CREATE OBJECTS +* +* Description: This function is called by the application code to indicate that all initialization has +* been completed and that kernel objects are no longer allowed to be created. +* +* Arguments : none +* +* Returns : none +* +* Note(s) : 1) You should call this function when you no longer want to allow application code to +* create kernel objects. +* 2) You need to define the macro 'OS_SAFETY_CRITICAL_IEC61508' +********************************************************************************************************* +*/ + +#ifdef OS_SAFETY_CRITICAL_IEC61508 +void OSSafetyCriticalStart (void) +{ + OSSafetyCriticalStartFlag = OS_TRUE; +} + +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* PREVENT SCHEDULING +* +* Description: This function is used to prevent rescheduling to take place. This allows your application +* to prevent context switches until you are ready to permit context switching. +* +* Arguments : none +* +* Returns : none +* +* Notes : 1) You MUST invoke OSSchedLock() and OSSchedUnlock() in pair. In other words, for every +* call to OSSchedLock() you MUST have a call to OSSchedUnlock(). +********************************************************************************************************* +*/ + +#if OS_SCHED_LOCK_EN > 0u +void OSSchedLock (void) +{ +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + + if (OSRunning == OS_TRUE) { /* Make sure multitasking is running */ + OS_ENTER_CRITICAL(); + if (OSIntNesting == 0u) { /* Can't call from an ISR */ + if (OSLockNesting < 255u) { /* Prevent OSLockNesting from wrapping back to 0 */ + OSLockNesting++; /* Increment lock nesting level */ + } + } + OS_EXIT_CRITICAL(); + } +} +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* ENABLE SCHEDULING +* +* Description: This function is used to re-allow rescheduling. +* +* Arguments : none +* +* Returns : none +* +* Notes : 1) You MUST invoke OSSchedLock() and OSSchedUnlock() in pair. In other words, for every +* call to OSSchedLock() you MUST have a call to OSSchedUnlock(). +********************************************************************************************************* +*/ + +#if OS_SCHED_LOCK_EN > 0u +void OSSchedUnlock (void) +{ +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + + if (OSRunning == OS_TRUE) { /* Make sure multitasking is running */ + OS_ENTER_CRITICAL(); + if (OSIntNesting == 0u) { /* Can't call from an ISR */ + if (OSLockNesting > 0u) { /* Do not decrement if already 0 */ + OSLockNesting--; /* Decrement lock nesting level */ + if (OSLockNesting == 0u) { /* See if scheduler is enabled */ + OS_EXIT_CRITICAL(); + OS_Sched(); /* See if a HPT is ready */ + } else { + OS_EXIT_CRITICAL(); + } + } else { + OS_EXIT_CRITICAL(); + } + } else { + OS_EXIT_CRITICAL(); + } + } +} +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* START MULTITASKING +* +* Description: This function is used to start the multitasking process which lets uC/OS-II manages the +* task that you have created. Before you can call OSStart(), you MUST have called OSInit() +* and you MUST have created at least one task. +* +* Arguments : none +* +* Returns : none +* +* Note : OSStartHighRdy() MUST: +* a) Call OSTaskSwHook() then, +* b) Set OSRunning to OS_TRUE. +* c) Load the context of the task pointed to by OSTCBHighRdy. +* d_ Execute the task. +********************************************************************************************************* +*/ + +void OSStart (void) +{ + if (OSRunning == OS_FALSE) { + OS_SchedNew(); /* Find highest priority's task priority number */ + OSPrioCur = OSPrioHighRdy; + OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy]; /* Point to highest priority task ready to run */ + OSTCBCur = OSTCBHighRdy; + OSStartHighRdy(); /* Execute target specific code to start task */ + } +} +/*$PAGE*/ +/* +********************************************************************************************************* +* STATISTICS INITIALIZATION +* +* Description: This function is called by your application to establish CPU usage by first determining +* how high a 32-bit counter would count to in 1 second if no other tasks were to execute +* during that time. CPU usage is then determined by a low priority task which keeps track +* of this 32-bit counter every second but this time, with other tasks running. CPU usage is +* determined by: +* +* OSIdleCtr +* CPU Usage (%) = 100 * (1 - ------------) +* OSIdleCtrMax +* +* Arguments : none +* +* Returns : none +********************************************************************************************************* +*/ + +#if OS_TASK_STAT_EN > 0u +void OSStatInit (void) +{ +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + + OSTimeDly(2u); /* Synchronize with clock tick */ + OS_ENTER_CRITICAL(); + OSIdleCtr = 0uL; /* Clear idle counter */ + OS_EXIT_CRITICAL(); + OSTimeDly(OS_TICKS_PER_SEC / 10u); /* Determine MAX. idle counter value for 1/10 second */ + OS_ENTER_CRITICAL(); + OSIdleCtrMax = OSIdleCtr; /* Store maximum idle counter count in 1/10 second */ + OSStatRdy = OS_TRUE; + OS_EXIT_CRITICAL(); +} +#endif +/*$PAGE*/ +/* +********************************************************************************************************* +* PROCESS SYSTEM TICK +* +* Description: This function is used to signal to uC/OS-II the occurrence of a 'system tick' (also known +* as a 'clock tick'). This function should be called by the ticker ISR but, can also be +* called by a high priority task. +* +* Arguments : none +* +* Returns : none +********************************************************************************************************* +*/ + +void OSTimeTick (void) +{ + OS_TCB *ptcb; +#if OS_TICK_STEP_EN > 0u + BOOLEAN step; +#endif +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#if OS_TIME_TICK_HOOK_EN > 0u + OSTimeTickHook(); /* Call user definable hook */ +#endif +#if OS_TIME_GET_SET_EN > 0u + OS_ENTER_CRITICAL(); /* Update the 32-bit tick counter */ + OSTime++; + OS_EXIT_CRITICAL(); +#endif + if (OSRunning == OS_TRUE) { +#if OS_TICK_STEP_EN > 0u + switch (OSTickStepState) { /* Determine whether we need to process a tick */ + case OS_TICK_STEP_DIS: /* Yes, stepping is disabled */ + step = OS_TRUE; + break; + + case OS_TICK_STEP_WAIT: /* No, waiting for uC/OS-View to set ... */ + step = OS_FALSE; /* .. OSTickStepState to OS_TICK_STEP_ONCE */ + break; + + case OS_TICK_STEP_ONCE: /* Yes, process tick once and wait for next ... */ + step = OS_TRUE; /* ... step command from uC/OS-View */ + OSTickStepState = OS_TICK_STEP_WAIT; + break; + + default: /* Invalid case, correct situation */ + step = OS_TRUE; + OSTickStepState = OS_TICK_STEP_DIS; + break; + } + if (step == OS_FALSE) { /* Return if waiting for step command */ + return; + } +#endif + ptcb = OSTCBList; /* Point at first TCB in TCB list */ + while (ptcb->OSTCBPrio != OS_TASK_IDLE_PRIO) { /* Go through all TCBs in TCB list */ + OS_ENTER_CRITICAL(); + if (ptcb->OSTCBDly != 0u) { /* No, Delayed or waiting for event with TO */ + ptcb->OSTCBDly--; /* Decrement nbr of ticks to end of delay */ + if (ptcb->OSTCBDly == 0u) { /* Check for timeout */ + + if ((ptcb->OSTCBStat & OS_STAT_PEND_ANY) != OS_STAT_RDY) { + ptcb->OSTCBStat &= (INT8U)~(INT8U)OS_STAT_PEND_ANY; /* Yes, Clear status flag */ + ptcb->OSTCBStatPend = OS_STAT_PEND_TO; /* Indicate PEND timeout */ + } else { + ptcb->OSTCBStatPend = OS_STAT_PEND_OK; + } + + if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) == OS_STAT_RDY) { /* Is task suspended? */ + OSRdyGrp |= ptcb->OSTCBBitY; /* No, Make ready */ + OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX; + } + } + } + ptcb = ptcb->OSTCBNext; /* Point at next TCB in TCB list */ + OS_EXIT_CRITICAL(); + } + } +} + +/*$PAGE*/ +/* +********************************************************************************************************* +* GET VERSION +* +* Description: This function is used to return the version number of uC/OS-II. The returned value +* corresponds to uC/OS-II's version number multiplied by 10000. In other words, version +* 2.01.00 would be returned as 20100. +* +* Arguments : none +* +* Returns : The version number of uC/OS-II multiplied by 10000. +********************************************************************************************************* +*/ + +INT16U OSVersion (void) +{ + return (OS_VERSION); +} + +/*$PAGE*/ +/* +********************************************************************************************************* +* DUMMY FUNCTION +* +* Description: This function doesn't do anything. It is called by OSTaskDel(). +* +* Arguments : none +* +* Returns : none +********************************************************************************************************* +*/ + +#if OS_TASK_DEL_EN > 0u +void OS_Dummy (void) +{ +} +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* MAKE TASK READY TO RUN BASED ON EVENT OCCURING +* +* Description: This function is called by other uC/OS-II services and is used to ready a task that was +* waiting for an event to occur. +* +* Arguments : pevent is a pointer to the event control block corresponding to the event. +* +* pmsg is a pointer to a message. This pointer is used by message oriented services +* such as MAILBOXEs and QUEUEs. The pointer is not used when called by other +* service functions. +* +* msk is a mask that is used to clear the status byte of the TCB. For example, +* OSSemPost() will pass OS_STAT_SEM, OSMboxPost() will pass OS_STAT_MBOX etc. +* +* pend_stat is used to indicate the readied task's pending status: +* +* OS_STAT_PEND_OK Task ready due to a post (or delete), not a timeout or +* an abort. +* OS_STAT_PEND_ABORT Task ready due to an abort. +* +* Returns : none +* +* Note : This function is INTERNAL to uC/OS-II and your application should not call it. +********************************************************************************************************* +*/ +#if (OS_EVENT_EN) +INT8U OS_EventTaskRdy (OS_EVENT *pevent, + void *pmsg, + INT8U msk, + INT8U pend_stat) +{ + OS_TCB *ptcb; + INT8U y; + INT8U x; + INT8U prio; +#if OS_LOWEST_PRIO > 63u + OS_PRIO *ptbl; +#endif + + +#if OS_LOWEST_PRIO <= 63u + y = OSUnMapTbl[pevent->OSEventGrp]; /* Find HPT waiting for message */ + x = OSUnMapTbl[pevent->OSEventTbl[y]]; + prio = (INT8U)((y << 3u) + x); /* Find priority of task getting the msg */ +#else + if ((pevent->OSEventGrp & 0xFFu) != 0u) { /* Find HPT waiting for message */ + y = OSUnMapTbl[ pevent->OSEventGrp & 0xFFu]; + } else { + y = OSUnMapTbl[(OS_PRIO)(pevent->OSEventGrp >> 8u) & 0xFFu] + 8u; + } + ptbl = &pevent->OSEventTbl[y]; + if ((*ptbl & 0xFFu) != 0u) { + x = OSUnMapTbl[*ptbl & 0xFFu]; + } else { + x = OSUnMapTbl[(OS_PRIO)(*ptbl >> 8u) & 0xFFu] + 8u; + } + prio = (INT8U)((y << 4u) + x); /* Find priority of task getting the msg */ +#endif + + ptcb = OSTCBPrioTbl[prio]; /* Point to this task's OS_TCB */ + ptcb->OSTCBDly = 0u; /* Prevent OSTimeTick() from readying task */ +#if ((OS_Q_EN > 0u) && (OS_MAX_QS > 0u)) || (OS_MBOX_EN > 0u) + ptcb->OSTCBMsg = pmsg; /* Send message directly to waiting task */ +#else + pmsg = pmsg; /* Prevent compiler warning if not used */ +#endif + ptcb->OSTCBStat &= (INT8U)~msk; /* Clear bit associated with event type */ + ptcb->OSTCBStatPend = pend_stat; /* Set pend status of post or abort */ + /* See if task is ready (could be susp'd) */ + if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) == OS_STAT_RDY) { + OSRdyGrp |= ptcb->OSTCBBitY; /* Put task in the ready to run list */ + OSRdyTbl[y] |= ptcb->OSTCBBitX; + } + + OS_EventTaskRemove(ptcb, pevent); /* Remove this task from event wait list */ +#if (OS_EVENT_MULTI_EN > 0u) + if (ptcb->OSTCBEventMultiPtr != (OS_EVENT **)0) { /* Remove this task from events' wait lists */ + OS_EventTaskRemoveMulti(ptcb, ptcb->OSTCBEventMultiPtr); + ptcb->OSTCBEventPtr = (OS_EVENT *)pevent;/* Return event as first multi-pend event ready*/ + } +#endif + + return (prio); +} +#endif +/*$PAGE*/ +/* +********************************************************************************************************* +* MAKE TASK WAIT FOR EVENT TO OCCUR +* +* Description: This function is called by other uC/OS-II services to suspend a task because an event has +* not occurred. +* +* Arguments : pevent is a pointer to the event control block for which the task will be waiting for. +* +* Returns : none +* +* Note : This function is INTERNAL to uC/OS-II and your application should not call it. +********************************************************************************************************* +*/ +#if (OS_EVENT_EN) +void OS_EventTaskWait (OS_EVENT *pevent) +{ + INT8U y; + + + OSTCBCur->OSTCBEventPtr = pevent; /* Store ptr to ECB in TCB */ + + pevent->OSEventTbl[OSTCBCur->OSTCBY] |= OSTCBCur->OSTCBBitX; /* Put task in waiting list */ + pevent->OSEventGrp |= OSTCBCur->OSTCBBitY; + + y = OSTCBCur->OSTCBY; /* Task no longer ready */ + OSRdyTbl[y] &= (OS_PRIO)~OSTCBCur->OSTCBBitX; + if (OSRdyTbl[y] == 0u) { /* Clear event grp bit if this was only task pending */ + OSRdyGrp &= (OS_PRIO)~OSTCBCur->OSTCBBitY; + } +} +#endif +/*$PAGE*/ +/* +********************************************************************************************************* +* MAKE TASK WAIT FOR ANY OF MULTIPLE EVENTS TO OCCUR +* +* Description: This function is called by other uC/OS-II services to suspend a task because any one of +* multiple events has not occurred. +* +* Arguments : pevents_wait is a pointer to an array of event control blocks, NULL-terminated, for +* which the task will be waiting for. +* +* Returns : none. +* +* Note : This function is INTERNAL to uC/OS-II and your application should not call it. +********************************************************************************************************* +*/ +#if ((OS_EVENT_EN) && (OS_EVENT_MULTI_EN > 0u)) +void OS_EventTaskWaitMulti (OS_EVENT **pevents_wait) +{ + OS_EVENT **pevents; + OS_EVENT *pevent; + INT8U y; + + + OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; + OSTCBCur->OSTCBEventMultiPtr = (OS_EVENT **)pevents_wait; /* Store ptr to ECBs in TCB */ + + pevents = pevents_wait; + pevent = *pevents; + while (pevent != (OS_EVENT *)0) { /* Put task in waiting lists */ + pevent->OSEventTbl[OSTCBCur->OSTCBY] |= OSTCBCur->OSTCBBitX; + pevent->OSEventGrp |= OSTCBCur->OSTCBBitY; + pevents++; + pevent = *pevents; + } + + y = OSTCBCur->OSTCBY; /* Task no longer ready */ + OSRdyTbl[y] &= (OS_PRIO)~OSTCBCur->OSTCBBitX; + if (OSRdyTbl[y] == 0u) { /* Clear event grp bit if this was only task pending */ + OSRdyGrp &= (OS_PRIO)~OSTCBCur->OSTCBBitY; + } +} +#endif +/*$PAGE*/ +/* +********************************************************************************************************* +* REMOVE TASK FROM EVENT WAIT LIST +* +* Description: Remove a task from an event's wait list. +* +* Arguments : ptcb is a pointer to the task to remove. +* +* pevent is a pointer to the event control block. +* +* Returns : none +* +* Note : This function is INTERNAL to uC/OS-II and your application should not call it. +********************************************************************************************************* +*/ +#if (OS_EVENT_EN) +void OS_EventTaskRemove (OS_TCB *ptcb, + OS_EVENT *pevent) +{ + INT8U y; + + + y = ptcb->OSTCBY; + pevent->OSEventTbl[y] &= (OS_PRIO)~ptcb->OSTCBBitX; /* Remove task from wait list */ + if (pevent->OSEventTbl[y] == 0u) { + pevent->OSEventGrp &= (OS_PRIO)~ptcb->OSTCBBitY; + } + ptcb->OSTCBEventPtr = (OS_EVENT *)0; /* Unlink OS_EVENT from OS_TCB */ +} +#endif +/*$PAGE*/ +/* +********************************************************************************************************* +* REMOVE TASK FROM MULTIPLE EVENTS WAIT LISTS +* +* Description: Remove a task from multiple events' wait lists. +* +* Arguments : ptcb is a pointer to the task to remove. +* +* pevents_multi is a pointer to the array of event control blocks, NULL-terminated. +* +* Returns : none +* +* Note : This function is INTERNAL to uC/OS-II and your application should not call it. +********************************************************************************************************* +*/ +#if ((OS_EVENT_EN) && (OS_EVENT_MULTI_EN > 0u)) +void OS_EventTaskRemoveMulti (OS_TCB *ptcb, + OS_EVENT **pevents_multi) +{ + OS_EVENT **pevents; + OS_EVENT *pevent; + INT8U y; + OS_PRIO bity; + OS_PRIO bitx; + + + y = ptcb->OSTCBY; + bity = ptcb->OSTCBBitY; + bitx = ptcb->OSTCBBitX; + pevents = pevents_multi; + pevent = *pevents; + while (pevent != (OS_EVENT *)0) { /* Remove task from all events' wait lists */ + pevent->OSEventTbl[y] &= (OS_PRIO)~bitx; + if (pevent->OSEventTbl[y] == 0u) { + pevent->OSEventGrp &= (OS_PRIO)~bity; + } + pevents++; + pevent = *pevents; + } +} +#endif +/*$PAGE*/ +/* +********************************************************************************************************* +* INITIALIZE EVENT CONTROL BLOCK'S WAIT LIST +* +* Description: This function is called by other uC/OS-II services to initialize the event wait list. +* +* Arguments : pevent is a pointer to the event control block allocated to the event. +* +* Returns : none +* +* Note : This function is INTERNAL to uC/OS-II and your application should not call it. +********************************************************************************************************* +*/ +#if (OS_EVENT_EN) +void OS_EventWaitListInit (OS_EVENT *pevent) +{ + INT8U i; + + + pevent->OSEventGrp = 0u; /* No task waiting on event */ + for (i = 0u; i < OS_EVENT_TBL_SIZE; i++) { + pevent->OSEventTbl[i] = 0u; + } +} +#endif +/*$PAGE*/ +/* +********************************************************************************************************* +* INITIALIZATION +* INITIALIZE THE FREE LIST OF EVENT CONTROL BLOCKS +* +* Description: This function is called by OSInit() to initialize the free list of event control blocks. +* +* Arguments : none +* +* Returns : none +********************************************************************************************************* +*/ + +static void OS_InitEventList (void) +{ +#if (OS_EVENT_EN) && (OS_MAX_EVENTS > 0u) +#if (OS_MAX_EVENTS > 1u) + INT16U ix; + INT16U ix_next; + OS_EVENT *pevent1; + OS_EVENT *pevent2; + + + OS_MemClr((INT8U *)&OSEventTbl[0], sizeof(OSEventTbl)); /* Clear the event table */ + for (ix = 0u; ix < (OS_MAX_EVENTS - 1u); ix++) { /* Init. list of free EVENT control blocks */ + ix_next = ix + 1u; + pevent1 = &OSEventTbl[ix]; + pevent2 = &OSEventTbl[ix_next]; + pevent1->OSEventType = OS_EVENT_TYPE_UNUSED; + pevent1->OSEventPtr = pevent2; +#if OS_EVENT_NAME_EN > 0u + pevent1->OSEventName = (INT8U *)(void *)"?"; /* Unknown name */ +#endif + } + pevent1 = &OSEventTbl[ix]; + pevent1->OSEventType = OS_EVENT_TYPE_UNUSED; + pevent1->OSEventPtr = (OS_EVENT *)0; +#if OS_EVENT_NAME_EN > 0u + pevent1->OSEventName = (INT8U *)(void *)"?"; /* Unknown name */ +#endif + OSEventFreeList = &OSEventTbl[0]; +#else + OSEventFreeList = &OSEventTbl[0]; /* Only have ONE event control block */ + OSEventFreeList->OSEventType = OS_EVENT_TYPE_UNUSED; + OSEventFreeList->OSEventPtr = (OS_EVENT *)0; +#if OS_EVENT_NAME_EN > 0u + OSEventFreeList->OSEventName = (INT8U *)"?"; /* Unknown name */ +#endif +#endif +#endif +} +/*$PAGE*/ +/* +********************************************************************************************************* +* INITIALIZATION +* INITIALIZE MISCELLANEOUS VARIABLES +* +* Description: This function is called by OSInit() to initialize miscellaneous variables. +* +* Arguments : none +* +* Returns : none +********************************************************************************************************* +*/ + +static void OS_InitMisc (void) +{ +#if OS_TIME_GET_SET_EN > 0u + OSTime = 0uL; /* Clear the 32-bit system clock */ +#endif + + OSIntNesting = 0u; /* Clear the interrupt nesting counter */ + OSLockNesting = 0u; /* Clear the scheduling lock counter */ + + OSTaskCtr = 0u; /* Clear the number of tasks */ + + OSRunning = OS_FALSE; /* Indicate that multitasking not started */ + + OSCtxSwCtr = 0u; /* Clear the context switch counter */ + OSIdleCtr = 0uL; /* Clear the 32-bit idle counter */ + +#if OS_TASK_STAT_EN > 0u + OSIdleCtrRun = 0uL; + OSIdleCtrMax = 0uL; + OSStatRdy = OS_FALSE; /* Statistic task is not ready */ +#endif + +#ifdef OS_SAFETY_CRITICAL_IEC61508 + OSSafetyCriticalStartFlag = OS_FALSE; /* Still allow creation of objects */ +#endif + +#if OS_TASK_REG_TBL_SIZE > 0u + OSTaskRegNextAvailID = 0u; /* Initialize the task register ID */ +#endif +} +/*$PAGE*/ +/* +********************************************************************************************************* +* INITIALIZATION +* INITIALIZE THE READY LIST +* +* Description: This function is called by OSInit() to initialize the Ready List. +* +* Arguments : none +* +* Returns : none +********************************************************************************************************* +*/ + +static void OS_InitRdyList (void) +{ + INT8U i; + + + OSRdyGrp = 0u; /* Clear the ready list */ + for (i = 0u; i < OS_RDY_TBL_SIZE; i++) { + OSRdyTbl[i] = 0u; + } + + OSPrioCur = 0u; + OSPrioHighRdy = 0u; + + OSTCBHighRdy = (OS_TCB *)0; + OSTCBCur = (OS_TCB *)0; +} + +/*$PAGE*/ +/* +********************************************************************************************************* +* INITIALIZATION +* CREATING THE IDLE TASK +* +* Description: This function creates the Idle Task. +* +* Arguments : none +* +* Returns : none +********************************************************************************************************* +*/ + +static void OS_InitTaskIdle (void) +{ +#if OS_TASK_NAME_EN > 0u + INT8U err; +#endif + + +#if OS_TASK_CREATE_EXT_EN > 0u + #if OS_STK_GROWTH == 1u + (void)OSTaskCreateExt(OS_TaskIdle, + (void *)0, /* No arguments passed to OS_TaskIdle() */ + &OSTaskIdleStk[OS_TASK_IDLE_STK_SIZE - 1u],/* Set Top-Of-Stack */ + OS_TASK_IDLE_PRIO, /* Lowest priority level */ + OS_TASK_IDLE_ID, + &OSTaskIdleStk[0], /* Set Bottom-Of-Stack */ + OS_TASK_IDLE_STK_SIZE, + (void *)0, /* No TCB extension */ + OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);/* Enable stack checking + clear stack */ + #else + (void)OSTaskCreateExt(OS_TaskIdle, + (void *)0, /* No arguments passed to OS_TaskIdle() */ + &OSTaskIdleStk[0], /* Set Top-Of-Stack */ + OS_TASK_IDLE_PRIO, /* Lowest priority level */ + OS_TASK_IDLE_ID, + &OSTaskIdleStk[OS_TASK_IDLE_STK_SIZE - 1u],/* Set Bottom-Of-Stack */ + OS_TASK_IDLE_STK_SIZE, + (void *)0, /* No TCB extension */ + OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);/* Enable stack checking + clear stack */ + #endif +#else + #if OS_STK_GROWTH == 1u + (void)OSTaskCreate(OS_TaskIdle, + (void *)0, + &OSTaskIdleStk[OS_TASK_IDLE_STK_SIZE - 1u], + OS_TASK_IDLE_PRIO); + #else + (void)OSTaskCreate(OS_TaskIdle, + (void *)0, + &OSTaskIdleStk[0], + OS_TASK_IDLE_PRIO); + #endif +#endif + +#if OS_TASK_NAME_EN > 0u + OSTaskNameSet(OS_TASK_IDLE_PRIO, (INT8U *)(void *)"uC/OS-II Idle", &err); +#endif +} +/*$PAGE*/ +/* +********************************************************************************************************* +* INITIALIZATION +* CREATING THE STATISTIC TASK +* +* Description: This function creates the Statistic Task. +* +* Arguments : none +* +* Returns : none +********************************************************************************************************* +*/ + +#if OS_TASK_STAT_EN > 0u +static void OS_InitTaskStat (void) +{ +#if OS_TASK_NAME_EN > 0u + INT8U err; +#endif + + +#if OS_TASK_CREATE_EXT_EN > 0u + #if OS_STK_GROWTH == 1u + (void)OSTaskCreateExt(OS_TaskStat, + (void *)0, /* No args passed to OS_TaskStat()*/ + &OSTaskStatStk[OS_TASK_STAT_STK_SIZE - 1u], /* Set Top-Of-Stack */ + OS_TASK_STAT_PRIO, /* One higher than the idle task */ + OS_TASK_STAT_ID, + &OSTaskStatStk[0], /* Set Bottom-Of-Stack */ + OS_TASK_STAT_STK_SIZE, + (void *)0, /* No TCB extension */ + OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR); /* Enable stack checking + clear */ + #else + (void)OSTaskCreateExt(OS_TaskStat, + (void *)0, /* No args passed to OS_TaskStat()*/ + &OSTaskStatStk[0], /* Set Top-Of-Stack */ + OS_TASK_STAT_PRIO, /* One higher than the idle task */ + OS_TASK_STAT_ID, + &OSTaskStatStk[OS_TASK_STAT_STK_SIZE - 1u], /* Set Bottom-Of-Stack */ + OS_TASK_STAT_STK_SIZE, + (void *)0, /* No TCB extension */ + OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR); /* Enable stack checking + clear */ + #endif +#else + #if OS_STK_GROWTH == 1u + (void)OSTaskCreate(OS_TaskStat, + (void *)0, /* No args passed to OS_TaskStat()*/ + &OSTaskStatStk[OS_TASK_STAT_STK_SIZE - 1u], /* Set Top-Of-Stack */ + OS_TASK_STAT_PRIO); /* One higher than the idle task */ + #else + (void)OSTaskCreate(OS_TaskStat, + (void *)0, /* No args passed to OS_TaskStat()*/ + &OSTaskStatStk[0], /* Set Top-Of-Stack */ + OS_TASK_STAT_PRIO); /* One higher than the idle task */ + #endif +#endif + +#if OS_TASK_NAME_EN > 0u + OSTaskNameSet(OS_TASK_STAT_PRIO, (INT8U *)(void *)"uC/OS-II Stat", &err); +#endif +} +#endif +/*$PAGE*/ +/* +********************************************************************************************************* +* INITIALIZATION +* INITIALIZE THE FREE LIST OF TASK CONTROL BLOCKS +* +* Description: This function is called by OSInit() to initialize the free list of OS_TCBs. +* +* Arguments : none +* +* Returns : none +********************************************************************************************************* +*/ + +static void OS_InitTCBList (void) +{ + INT8U ix; + INT8U ix_next; + OS_TCB *ptcb1; + OS_TCB *ptcb2; + + + OS_MemClr((INT8U *)&OSTCBTbl[0], sizeof(OSTCBTbl)); /* Clear all the TCBs */ + OS_MemClr((INT8U *)&OSTCBPrioTbl[0], sizeof(OSTCBPrioTbl)); /* Clear the priority table */ + for (ix = 0u; ix < (OS_MAX_TASKS + OS_N_SYS_TASKS - 1u); ix++) { /* Init. list of free TCBs */ + ix_next = ix + 1u; + ptcb1 = &OSTCBTbl[ix]; + ptcb2 = &OSTCBTbl[ix_next]; + ptcb1->OSTCBNext = ptcb2; +#if OS_TASK_NAME_EN > 0u + ptcb1->OSTCBTaskName = (INT8U *)(void *)"?"; /* Unknown name */ +#endif + } + ptcb1 = &OSTCBTbl[ix]; + ptcb1->OSTCBNext = (OS_TCB *)0; /* Last OS_TCB */ +#if OS_TASK_NAME_EN > 0u + ptcb1->OSTCBTaskName = (INT8U *)(void *)"?"; /* Unknown name */ +#endif + OSTCBList = (OS_TCB *)0; /* TCB lists initializations */ + OSTCBFreeList = &OSTCBTbl[0]; +} +/*$PAGE*/ +/* +********************************************************************************************************* +* CLEAR A SECTION OF MEMORY +* +* Description: This function is called by other uC/OS-II services to clear a contiguous block of RAM. +* +* Arguments : pdest is the start of the RAM to clear (i.e. write 0x00 to) +* +* size is the number of bytes to clear. +* +* Returns : none +* +* Notes : 1) This function is INTERNAL to uC/OS-II and your application should not call it. +* 2) Note that we can only clear up to 64K bytes of RAM. This is not an issue because none +* of the uses of this function gets close to this limit. +* 3) The clear is done one byte at a time since this will work on any processor irrespective +* of the alignment of the destination. +********************************************************************************************************* +*/ + +void OS_MemClr (INT8U *pdest, + INT16U size) +{ + while (size > 0u) { + *pdest++ = (INT8U)0; + size--; + } +} +/*$PAGE*/ +/* +********************************************************************************************************* +* COPY A BLOCK OF MEMORY +* +* Description: This function is called by other uC/OS-II services to copy a block of memory from one +* location to another. +* +* Arguments : pdest is a pointer to the 'destination' memory block +* +* psrc is a pointer to the 'source' memory block +* +* size is the number of bytes to copy. +* +* Returns : none +* +* Notes : 1) This function is INTERNAL to uC/OS-II and your application should not call it. There is +* no provision to handle overlapping memory copy. However, that's not a problem since this +* is not a situation that will happen. +* 2) Note that we can only copy up to 64K bytes of RAM +* 3) The copy is done one byte at a time since this will work on any processor irrespective +* of the alignment of the source and destination. +********************************************************************************************************* +*/ + +void OS_MemCopy (INT8U *pdest, + INT8U *psrc, + INT16U size) +{ + while (size > 0u) { + *pdest++ = *psrc++; + size--; + } +} +/*$PAGE*/ +/* +********************************************************************************************************* +* SCHEDULER +* +* Description: This function is called by other uC/OS-II services to determine whether a new, high +* priority task has been made ready to run. This function is invoked by TASK level code +* and is not used to reschedule tasks from ISRs (see OSIntExit() for ISR rescheduling). +* +* Arguments : none +* +* Returns : none +* +* Notes : 1) This function is INTERNAL to uC/OS-II and your application should not call it. +* 2) Rescheduling is prevented when the scheduler is locked (see OS_SchedLock()) +********************************************************************************************************* +*/ + +void OS_Sched (void) +{ +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + + OS_ENTER_CRITICAL(); + if (OSIntNesting == 0u) { /* Schedule only if all ISRs done and ... */ + if (OSLockNesting == 0u) { /* ... scheduler is not locked */ + OS_SchedNew(); + OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy]; + if (OSPrioHighRdy != OSPrioCur) { /* No Ctx Sw if current task is highest rdy */ +#if OS_TASK_PROFILE_EN > 0u + OSTCBHighRdy->OSTCBCtxSwCtr++; /* Inc. # of context switches to this task */ +#endif + OSCtxSwCtr++; /* Increment context switch counter */ + +#if OS_TASK_CREATE_EXT_EN > 0u +#if defined(OS_TLS_TBL_SIZE) && (OS_TLS_TBL_SIZE > 0u) + OS_TLS_TaskSw(); +#endif +#endif + + OS_TASK_SW(); /* Perform a context switch */ + } + } + } + OS_EXIT_CRITICAL(); +} + + +/* +********************************************************************************************************* +* FIND HIGHEST PRIORITY TASK READY TO RUN +* +* Description: This function is called by other uC/OS-II services to determine the highest priority task +* that is ready to run. The global variable 'OSPrioHighRdy' is changed accordingly. +* +* Arguments : none +* +* Returns : none +* +* Notes : 1) This function is INTERNAL to uC/OS-II and your application should not call it. +* 2) Interrupts are assumed to be disabled when this function is called. +********************************************************************************************************* +*/ + +static void OS_SchedNew (void) +{ +#if OS_LOWEST_PRIO <= 63u /* See if we support up to 64 tasks */ + INT8U y; + + + y = OSUnMapTbl[OSRdyGrp]; + OSPrioHighRdy = (INT8U)((y << 3u) + OSUnMapTbl[OSRdyTbl[y]]); +#else /* We support up to 256 tasks */ + INT8U y; + OS_PRIO *ptbl; + + + if ((OSRdyGrp & 0xFFu) != 0u) { + y = OSUnMapTbl[OSRdyGrp & 0xFFu]; + } else { + y = OSUnMapTbl[(OS_PRIO)(OSRdyGrp >> 8u) & 0xFFu] + 8u; + } + ptbl = &OSRdyTbl[y]; + if ((*ptbl & 0xFFu) != 0u) { + OSPrioHighRdy = (INT8U)((y << 4u) + OSUnMapTbl[(*ptbl & 0xFFu)]); + } else { + OSPrioHighRdy = (INT8U)((y << 4u) + OSUnMapTbl[(OS_PRIO)(*ptbl >> 8u) & 0xFFu] + 8u); + } +#endif +} + +/*$PAGE*/ +/* +********************************************************************************************************* +* DETERMINE THE LENGTH OF AN ASCII STRING +* +* Description: This function is called by other uC/OS-II services to determine the size of an ASCII string +* (excluding the NUL character). +* +* Arguments : psrc is a pointer to the string for which we need to know the size. +* +* Returns : The size of the string (excluding the NUL terminating character) +* +* Notes : 1) This function is INTERNAL to uC/OS-II and your application should not call it. +* 2) The string to check must be less than 255 characters long. +********************************************************************************************************* +*/ + +#if (OS_EVENT_NAME_EN > 0u) || (OS_FLAG_NAME_EN > 0u) || (OS_MEM_NAME_EN > 0u) || (OS_TASK_NAME_EN > 0u) || (OS_TMR_CFG_NAME_EN > 0u) +INT8U OS_StrLen (INT8U *psrc) +{ + INT8U len; + + +#if OS_ARG_CHK_EN > 0u + if (psrc == (INT8U *)0) { + return (0u); + } +#endif + + len = 0u; + while (*psrc != OS_ASCII_NUL) { + psrc++; + len++; + } + return (len); +} +#endif +/*$PAGE*/ +/* +********************************************************************************************************* +* IDLE TASK +* +* Description: This task is internal to uC/OS-II and executes whenever no other higher priority tasks +* executes because they are ALL waiting for event(s) to occur. +* +* Arguments : none +* +* Returns : none +* +* Note(s) : 1) OSTaskIdleHook() is called after the critical section to ensure that interrupts will be +* enabled for at least a few instructions. On some processors (ex. Philips XA), enabling +* and then disabling interrupts didn't allow the processor enough time to have interrupts +* enabled before they were disabled again. uC/OS-II would thus never recognize +* interrupts. +* 2) This hook has been added to allow you to do such things as STOP the CPU to conserve +* power. +********************************************************************************************************* +*/ + +void OS_TaskIdle (void *p_arg) +{ +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + + p_arg = p_arg; /* Prevent compiler warning for not using 'p_arg' */ + for (;;) { + OS_ENTER_CRITICAL(); + OSIdleCtr++; + OS_EXIT_CRITICAL(); + OSTaskIdleHook(); /* Call user definable HOOK */ + } +} +/*$PAGE*/ +/* +********************************************************************************************************* +* STATISTICS TASK +* +* Description: This task is internal to uC/OS-II and is used to compute some statistics about the +* multitasking environment. Specifically, OS_TaskStat() computes the CPU usage. +* CPU usage is determined by: +* +* OSIdleCtr +* OSCPUUsage = 100 * (1 - ------------) (units are in %) +* OSIdleCtrMax +* +* Arguments : parg this pointer is not used at this time. +* +* Returns : none +* +* Notes : 1) This task runs at a priority level higher than the idle task. In fact, it runs at the +* next higher priority, OS_TASK_IDLE_PRIO-1. +* 2) You can disable this task by setting the configuration #define OS_TASK_STAT_EN to 0. +* 3) You MUST have at least a delay of 2/10 seconds to allow for the system to establish the +* maximum value for the idle counter. +********************************************************************************************************* +*/ + +#if OS_TASK_STAT_EN > 0u +void OS_TaskStat (void *p_arg) +{ +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + + p_arg = p_arg; /* Prevent compiler warning for not using 'p_arg' */ + while (OSStatRdy == OS_FALSE) { + OSTimeDly(2u * OS_TICKS_PER_SEC / 10u); /* Wait until statistic task is ready */ + } + OSIdleCtrMax /= 100uL; + if (OSIdleCtrMax == 0uL) { + OSCPUUsage = 0u; +#if OS_TASK_SUSPEND_EN > 0u + (void)OSTaskSuspend(OS_PRIO_SELF); +#else + for (;;) { + OSTimeDly(OS_TICKS_PER_SEC); + } +#endif + } + OS_ENTER_CRITICAL(); + OSIdleCtr = OSIdleCtrMax * 100uL; /* Set initial CPU usage as 0% */ + OS_EXIT_CRITICAL(); + for (;;) { + OS_ENTER_CRITICAL(); + OSIdleCtrRun = OSIdleCtr; /* Obtain the of the idle counter for the past second */ + OSIdleCtr = 0uL; /* Reset the idle counter for the next second */ + OS_EXIT_CRITICAL(); + OSCPUUsage = (INT8U)(100uL - OSIdleCtrRun / OSIdleCtrMax); + OSTaskStatHook(); /* Invoke user definable hook */ +#if (OS_TASK_STAT_STK_CHK_EN > 0u) && (OS_TASK_CREATE_EXT_EN > 0u) + OS_TaskStatStkChk(); /* Check the stacks for each task */ +#endif + OSTimeDly(OS_TICKS_PER_SEC / 10u); /* Accumulate OSIdleCtr for the next 1/10 second */ + } +} +#endif +/*$PAGE*/ +/* +********************************************************************************************************* +* CHECK ALL TASK STACKS +* +* Description: This function is called by OS_TaskStat() to check the stacks of each active task. +* +* Arguments : none +* +* Returns : none +********************************************************************************************************* +*/ + +#if (OS_TASK_STAT_STK_CHK_EN > 0u) && (OS_TASK_CREATE_EXT_EN > 0u) +void OS_TaskStatStkChk (void) +{ + OS_TCB *ptcb; + OS_STK_DATA stk_data; + INT8U err; + INT8U prio; + + + for (prio = 0u; prio <= OS_TASK_IDLE_PRIO; prio++) { + err = OSTaskStkChk(prio, &stk_data); + if (err == OS_ERR_NONE) { + ptcb = OSTCBPrioTbl[prio]; + if (ptcb != (OS_TCB *)0) { /* Make sure task 'ptcb' is ... */ + if (ptcb != OS_TCB_RESERVED) { /* ... still valid. */ +#if OS_TASK_PROFILE_EN > 0u + #if OS_STK_GROWTH == 1u + ptcb->OSTCBStkBase = ptcb->OSTCBStkBottom + ptcb->OSTCBStkSize; + #else + ptcb->OSTCBStkBase = ptcb->OSTCBStkBottom - ptcb->OSTCBStkSize; + #endif + ptcb->OSTCBStkUsed = stk_data.OSUsed; /* Store number of entries used */ +#endif + } + } + } + } +} +#endif +/*$PAGE*/ +/* +********************************************************************************************************* +* INITIALIZE TCB +* +* Description: This function is internal to uC/OS-II and is used to initialize a Task Control Block when +* a task is created (see OSTaskCreate() and OSTaskCreateExt()). +* +* Arguments : prio is the priority of the task being created +* +* ptos is a pointer to the task's top-of-stack assuming that the CPU registers +* have been placed on the stack. Note that the top-of-stack corresponds to a +* 'high' memory location is OS_STK_GROWTH is set to 1 and a 'low' memory +* location if OS_STK_GROWTH is set to 0. Note that stack growth is CPU +* specific. +* +* pbos is a pointer to the bottom of stack. A NULL pointer is passed if called by +* 'OSTaskCreate()'. +* +* id is the task's ID (0..65535) +* +* stk_size is the size of the stack (in 'stack units'). If the stack units are INT8Us +* then, 'stk_size' contains the number of bytes for the stack. If the stack +* units are INT32Us then, the stack contains '4 * stk_size' bytes. The stack +* units are established by the #define constant OS_STK which is CPU +* specific. 'stk_size' is 0 if called by 'OSTaskCreate()'. +* +* pext is a pointer to a user supplied memory area that is used to extend the task +* control block. This allows you to store the contents of floating-point +* registers, MMU registers or anything else you could find useful during a +* context switch. You can even assign a name to each task and store this name +* in this TCB extension. A NULL pointer is passed if called by OSTaskCreate(). +* +* opt options as passed to 'OSTaskCreateExt()' or, +* 0 if called from 'OSTaskCreate()'. +* +* Returns : OS_ERR_NONE if the call was successful +* OS_ERR_TASK_NO_MORE_TCB if there are no more free TCBs to be allocated and thus, the task +* cannot be created. +* +* Note : This function is INTERNAL to uC/OS-II and your application should not call it. +********************************************************************************************************* +*/ + +INT8U OS_TCBInit (INT8U prio, + OS_STK *ptos, + OS_STK *pbos, + INT16U id, + INT32U stk_size, + void *pext, + INT16U opt) +{ + OS_TCB *ptcb; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif +#if OS_TASK_REG_TBL_SIZE > 0u + INT8U i; +#endif +#if OS_TASK_CREATE_EXT_EN > 0u +#if defined(OS_TLS_TBL_SIZE) && (OS_TLS_TBL_SIZE > 0u) + INT8U j; +#endif +#endif + + + OS_ENTER_CRITICAL(); + ptcb = OSTCBFreeList; /* Get a free TCB from the free TCB list */ + if (ptcb != (OS_TCB *)0) { + OSTCBFreeList = ptcb->OSTCBNext; /* Update pointer to free TCB list */ + OS_EXIT_CRITICAL(); + ptcb->OSTCBStkPtr = ptos; /* Load Stack pointer in TCB */ + ptcb->OSTCBPrio = prio; /* Load task priority into TCB */ + ptcb->OSTCBStat = OS_STAT_RDY; /* Task is ready to run */ + ptcb->OSTCBStatPend = OS_STAT_PEND_OK; /* Clear pend status */ + ptcb->OSTCBDly = 0u; /* Task is not delayed */ + +#if OS_TASK_CREATE_EXT_EN > 0u + ptcb->OSTCBExtPtr = pext; /* Store pointer to TCB extension */ + ptcb->OSTCBStkSize = stk_size; /* Store stack size */ + ptcb->OSTCBStkBottom = pbos; /* Store pointer to bottom of stack */ + ptcb->OSTCBOpt = opt; /* Store task options */ + ptcb->OSTCBId = id; /* Store task ID */ +#else + pext = pext; /* Prevent compiler warning if not used */ + stk_size = stk_size; + pbos = pbos; + opt = opt; + id = id; +#endif + +#if OS_TASK_DEL_EN > 0u + ptcb->OSTCBDelReq = OS_ERR_NONE; +#endif + +#if OS_LOWEST_PRIO <= 63u /* Pre-compute X, Y */ + ptcb->OSTCBY = (INT8U)(prio >> 3u); + ptcb->OSTCBX = (INT8U)(prio & 0x07u); +#else /* Pre-compute X, Y */ + ptcb->OSTCBY = (INT8U)((INT8U)(prio >> 4u) & 0xFFu); + ptcb->OSTCBX = (INT8U) (prio & 0x0Fu); +#endif + /* Pre-compute BitX and BitY */ + ptcb->OSTCBBitY = (OS_PRIO)(1uL << ptcb->OSTCBY); + ptcb->OSTCBBitX = (OS_PRIO)(1uL << ptcb->OSTCBX); + +#if (OS_EVENT_EN) + ptcb->OSTCBEventPtr = (OS_EVENT *)0; /* Task is not pending on an event */ +#if (OS_EVENT_MULTI_EN > 0u) + ptcb->OSTCBEventMultiPtr = (OS_EVENT **)0; /* Task is not pending on any events */ +#endif +#endif + +#if (OS_FLAG_EN > 0u) && (OS_MAX_FLAGS > 0u) && (OS_TASK_DEL_EN > 0u) + ptcb->OSTCBFlagNode = (OS_FLAG_NODE *)0; /* Task is not pending on an event flag */ +#endif + +#if (OS_MBOX_EN > 0u) || ((OS_Q_EN > 0u) && (OS_MAX_QS > 0u)) + ptcb->OSTCBMsg = (void *)0; /* No message received */ +#endif + +#if OS_TASK_PROFILE_EN > 0u + ptcb->OSTCBCtxSwCtr = 0uL; /* Initialize profiling variables */ + ptcb->OSTCBCyclesStart = 0uL; + ptcb->OSTCBCyclesTot = 0uL; + ptcb->OSTCBStkBase = (OS_STK *)0; + ptcb->OSTCBStkUsed = 0uL; +#endif + +#if OS_TASK_NAME_EN > 0u + ptcb->OSTCBTaskName = (INT8U *)(void *)"?"; +#endif + +#if OS_TASK_REG_TBL_SIZE > 0u /* Initialize the task variables */ + for (i = 0u; i < OS_TASK_REG_TBL_SIZE; i++) { + ptcb->OSTCBRegTbl[i] = 0u; + } +#endif + + OSTCBInitHook(ptcb); + + OS_ENTER_CRITICAL(); + OSTCBPrioTbl[prio] = ptcb; + OS_EXIT_CRITICAL(); + + OSTaskCreateHook(ptcb); /* Call user defined hook */ + +#if OS_TASK_CREATE_EXT_EN > 0u +#if defined(OS_TLS_TBL_SIZE) && (OS_TLS_TBL_SIZE > 0u) + for (j = 0u; j < OS_TLS_TBL_SIZE; j++) { + ptcb->OSTCBTLSTbl[j] = (OS_TLS)0; + } + OS_TLS_TaskCreate(ptcb); /* Call TLS hook */ +#endif +#endif + + OS_ENTER_CRITICAL(); + ptcb->OSTCBNext = OSTCBList; /* Link into TCB chain */ + ptcb->OSTCBPrev = (OS_TCB *)0; + if (OSTCBList != (OS_TCB *)0) { + OSTCBList->OSTCBPrev = ptcb; + } + OSTCBList = ptcb; + OSRdyGrp |= ptcb->OSTCBBitY; /* Make task ready to run */ + OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX; + OSTaskCtr++; /* Increment the #tasks counter */ + OS_EXIT_CRITICAL(); + return (OS_ERR_NONE); + } + OS_EXIT_CRITICAL(); + return (OS_ERR_TASK_NO_MORE_TCB); +} diff --git a/Middlewares/Third_Party/Micrium/uCOS-II/Source/os_flag.c b/Middlewares/Third_Party/Micrium/uCOS-II/Source/os_flag.c new file mode 100644 index 0000000..ee27d05 --- /dev/null +++ b/Middlewares/Third_Party/Micrium/uCOS-II/Source/os_flag.c @@ -0,0 +1,1231 @@ +/* +********************************************************************************************************* +* uC/OS-II +* The Real-Time Kernel +* EVENT FLAG MANAGEMENT +* +* (c) Copyright 1992-2013, Micrium, Weston, FL +* All Rights Reserved +* +* File : OS_FLAG.C +* By : Jean J. Labrosse +* Version : V2.92.11 +* +* LICENSING TERMS: +* --------------- +* uC/OS-II is provided in source form for FREE evaluation, for educational use or for peaceful research. +* If you plan on using uC/OS-II in a commercial product you need to contact Micrium to properly license +* its use in your product. We provide ALL the source code for your convenience and to help you experience +* uC/OS-II. The fact that the source is provided does NOT mean that you can use it without paying a +* licensing fee. +********************************************************************************************************* +*/ + +#define MICRIUM_SOURCE + +#ifndef OS_MASTER_FILE +#include +#endif + +#if (OS_FLAG_EN > 0u) && (OS_MAX_FLAGS > 0u) +/* +********************************************************************************************************* +* LOCAL PROTOTYPES +********************************************************************************************************* +*/ + +static void OS_FlagBlock(OS_FLAG_GRP *pgrp, OS_FLAG_NODE *pnode, OS_FLAGS flags, INT8U wait_type, INT32U timeout); +static BOOLEAN OS_FlagTaskRdy(OS_FLAG_NODE *pnode, OS_FLAGS flags_rdy, INT8U pend_stat); + +/*$PAGE*/ +/* +********************************************************************************************************* +* CHECK THE STATUS OF FLAGS IN AN EVENT FLAG GROUP +* +* Description: This function is called to check the status of a combination of bits to be set or cleared +* in an event flag group. Your application can check for ANY bit to be set/cleared or ALL +* bits to be set/cleared. +* +* This call does not block if the desired flags are not present. +* +* Arguments : pgrp is a pointer to the desired event flag group. +* +* flags Is a bit pattern indicating which bit(s) (i.e. flags) you wish to check. +* The bits you want are specified by setting the corresponding bits in +* 'flags'. e.g. if your application wants to wait for bits 0 and 1 then +* 'flags' would contain 0x03. +* +* wait_type specifies whether you want ALL bits to be set/cleared or ANY of the bits +* to be set/cleared. +* You can specify the following argument: +* +* OS_FLAG_WAIT_CLR_ALL You will check ALL bits in 'flags' to be clear (0) +* OS_FLAG_WAIT_CLR_ANY You will check ANY bit in 'flags' to be clear (0) +* OS_FLAG_WAIT_SET_ALL You will check ALL bits in 'flags' to be set (1) +* OS_FLAG_WAIT_SET_ANY You will check ANY bit in 'flags' to be set (1) +* +* NOTE: Add OS_FLAG_CONSUME if you want the event flag to be 'consumed' by +* the call. Example, to wait for any flag in a group AND then clear +* the flags that are present, set 'wait_type' to: +* +* OS_FLAG_WAIT_SET_ANY + OS_FLAG_CONSUME +* +* perr is a pointer to an error code and can be: +* OS_ERR_NONE No error +* OS_ERR_EVENT_TYPE You are not pointing to an event flag group +* OS_ERR_FLAG_WAIT_TYPE You didn't specify a proper 'wait_type' argument. +* OS_ERR_FLAG_INVALID_PGRP You passed a NULL pointer instead of the event flag +* group handle. +* OS_ERR_FLAG_NOT_RDY The desired flags you are waiting for are not +* available. +* +* Returns : The flags in the event flag group that made the task ready or, 0 if a timeout or an error +* occurred. +* +* Called from: Task or ISR +* +* Note(s) : 1) IMPORTANT, the behavior of this function has changed from PREVIOUS versions. The +* function NOW returns the flags that were ready INSTEAD of the current state of the +* event flags. +********************************************************************************************************* +*/ + +#if OS_FLAG_ACCEPT_EN > 0u +OS_FLAGS OSFlagAccept (OS_FLAG_GRP *pgrp, + OS_FLAGS flags, + INT8U wait_type, + INT8U *perr) +{ + OS_FLAGS flags_rdy; + INT8U result; + BOOLEAN consume; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#ifdef OS_SAFETY_CRITICAL + if (perr == (INT8U *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return ((OS_FLAGS)0); + } +#endif + +#if OS_ARG_CHK_EN > 0u + if (pgrp == (OS_FLAG_GRP *)0) { /* Validate 'pgrp' */ + *perr = OS_ERR_FLAG_INVALID_PGRP; + return ((OS_FLAGS)0); + } +#endif + if (pgrp->OSFlagType != OS_EVENT_TYPE_FLAG) { /* Validate event block type */ + *perr = OS_ERR_EVENT_TYPE; + return ((OS_FLAGS)0); + } + result = (INT8U)(wait_type & OS_FLAG_CONSUME); + if (result != (INT8U)0) { /* See if we need to consume the flags */ + wait_type &= ~OS_FLAG_CONSUME; + consume = OS_TRUE; + } else { + consume = OS_FALSE; + } +/*$PAGE*/ + *perr = OS_ERR_NONE; /* Assume NO error until proven otherwise. */ + OS_ENTER_CRITICAL(); + switch (wait_type) { + case OS_FLAG_WAIT_SET_ALL: /* See if all required flags are set */ + flags_rdy = (OS_FLAGS)(pgrp->OSFlagFlags & flags); /* Extract only the bits we want */ + if (flags_rdy == flags) { /* Must match ALL the bits that we want */ + if (consume == OS_TRUE) { /* See if we need to consume the flags */ + pgrp->OSFlagFlags &= (OS_FLAGS)~flags_rdy; /* Clear ONLY the flags we wanted */ + } + } else { + *perr = OS_ERR_FLAG_NOT_RDY; + } + OS_EXIT_CRITICAL(); + break; + + case OS_FLAG_WAIT_SET_ANY: + flags_rdy = (OS_FLAGS)(pgrp->OSFlagFlags & flags); /* Extract only the bits we want */ + if (flags_rdy != (OS_FLAGS)0) { /* See if any flag set */ + if (consume == OS_TRUE) { /* See if we need to consume the flags */ + pgrp->OSFlagFlags &= (OS_FLAGS)~flags_rdy; /* Clear ONLY the flags we got */ + } + } else { + *perr = OS_ERR_FLAG_NOT_RDY; + } + OS_EXIT_CRITICAL(); + break; + +#if OS_FLAG_WAIT_CLR_EN > 0u + case OS_FLAG_WAIT_CLR_ALL: /* See if all required flags are cleared */ + flags_rdy = (OS_FLAGS)~pgrp->OSFlagFlags & flags; /* Extract only the bits we want */ + if (flags_rdy == flags) { /* Must match ALL the bits that we want */ + if (consume == OS_TRUE) { /* See if we need to consume the flags */ + pgrp->OSFlagFlags |= flags_rdy; /* Set ONLY the flags that we wanted */ + } + } else { + *perr = OS_ERR_FLAG_NOT_RDY; + } + OS_EXIT_CRITICAL(); + break; + + case OS_FLAG_WAIT_CLR_ANY: + flags_rdy = (OS_FLAGS)~pgrp->OSFlagFlags & flags; /* Extract only the bits we want */ + if (flags_rdy != (OS_FLAGS)0) { /* See if any flag cleared */ + if (consume == OS_TRUE) { /* See if we need to consume the flags */ + pgrp->OSFlagFlags |= flags_rdy; /* Set ONLY the flags that we got */ + } + } else { + *perr = OS_ERR_FLAG_NOT_RDY; + } + OS_EXIT_CRITICAL(); + break; +#endif + + default: + OS_EXIT_CRITICAL(); + flags_rdy = (OS_FLAGS)0; + *perr = OS_ERR_FLAG_WAIT_TYPE; + break; + } + return (flags_rdy); +} +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* CREATE AN EVENT FLAG +* +* Description: This function is called to create an event flag group. +* +* Arguments : flags Contains the initial value to store in the event flag group. +* +* perr is a pointer to an error code which will be returned to your application: +* OS_ERR_NONE if the call was successful. +* OS_ERR_CREATE_ISR if you attempted to create an Event Flag from an +* ISR. +* OS_ERR_FLAG_GRP_DEPLETED if there are no more event flag groups +* +* Returns : A pointer to an event flag group or a NULL pointer if no more groups are available. +* +* Called from: Task ONLY +********************************************************************************************************* +*/ + +OS_FLAG_GRP *OSFlagCreate (OS_FLAGS flags, + INT8U *perr) +{ + OS_FLAG_GRP *pgrp; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#ifdef OS_SAFETY_CRITICAL + if (perr == (INT8U *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return ((OS_FLAG_GRP *)0); + } +#endif + +#ifdef OS_SAFETY_CRITICAL_IEC61508 + if (OSSafetyCriticalStartFlag == OS_TRUE) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return ((OS_FLAG_GRP *)0); + } +#endif + + if (OSIntNesting > 0u) { /* See if called from ISR ... */ + *perr = OS_ERR_CREATE_ISR; /* ... can't CREATE from an ISR */ + return ((OS_FLAG_GRP *)0); + } + OS_ENTER_CRITICAL(); + pgrp = OSFlagFreeList; /* Get next free event flag */ + if (pgrp != (OS_FLAG_GRP *)0) { /* See if we have event flag groups available */ + /* Adjust free list */ + OSFlagFreeList = (OS_FLAG_GRP *)OSFlagFreeList->OSFlagWaitList; + pgrp->OSFlagType = OS_EVENT_TYPE_FLAG; /* Set to event flag group type */ + pgrp->OSFlagFlags = flags; /* Set to desired initial value */ + pgrp->OSFlagWaitList = (void *)0; /* Clear list of tasks waiting on flags */ +#if OS_FLAG_NAME_EN > 0u + pgrp->OSFlagName = (INT8U *)(void *)"?"; +#endif + OS_EXIT_CRITICAL(); + *perr = OS_ERR_NONE; + } else { + OS_EXIT_CRITICAL(); + *perr = OS_ERR_FLAG_GRP_DEPLETED; + } + return (pgrp); /* Return pointer to event flag group */ +} + +/*$PAGE*/ +/* +********************************************************************************************************* +* DELETE AN EVENT FLAG GROUP +* +* Description: This function deletes an event flag group and readies all tasks pending on the event flag +* group. +* +* Arguments : pgrp is a pointer to the desired event flag group. +* +* opt determines delete options as follows: +* opt == OS_DEL_NO_PEND Deletes the event flag group ONLY if no task pending +* opt == OS_DEL_ALWAYS Deletes the event flag group even if tasks are +* waiting. In this case, all the tasks pending will be +* readied. +* +* perr is a pointer to an error code that can contain one of the following values: +* OS_ERR_NONE The call was successful and the event flag group was +* deleted +* OS_ERR_DEL_ISR If you attempted to delete the event flag group from +* an ISR +* OS_ERR_FLAG_INVALID_PGRP If 'pgrp' is a NULL pointer. +* OS_ERR_EVENT_TYPE If you didn't pass a pointer to an event flag group +* OS_ERR_INVALID_OPT An invalid option was specified +* OS_ERR_TASK_WAITING One or more tasks were waiting on the event flag +* group. +* +* Returns : pgrp upon error +* (OS_EVENT *)0 if the event flag group was successfully deleted. +* +* Note(s) : 1) This function must be used with care. Tasks that would normally expect the presence of +* the event flag group MUST check the return code of OSFlagAccept() and OSFlagPend(). +* 2) This call can potentially disable interrupts for a long time. The interrupt disable +* time is directly proportional to the number of tasks waiting on the event flag group. +* 3) All tasks that were waiting for the event flag will be readied and returned an +* OS_ERR_PEND_ABORT if OSFlagDel() was called with OS_DEL_ALWAYS +********************************************************************************************************* +*/ + +#if OS_FLAG_DEL_EN > 0u +OS_FLAG_GRP *OSFlagDel (OS_FLAG_GRP *pgrp, + INT8U opt, + INT8U *perr) +{ + BOOLEAN tasks_waiting; + OS_FLAG_NODE *pnode; + OS_FLAG_GRP *pgrp_return; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#ifdef OS_SAFETY_CRITICAL + if (perr == (INT8U *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return ((OS_FLAG_GRP *)0); + } +#endif + +#if OS_ARG_CHK_EN > 0u + if (pgrp == (OS_FLAG_GRP *)0) { /* Validate 'pgrp' */ + *perr = OS_ERR_FLAG_INVALID_PGRP; + return (pgrp); + } +#endif + if (OSIntNesting > 0u) { /* See if called from ISR ... */ + *perr = OS_ERR_DEL_ISR; /* ... can't DELETE from an ISR */ + return (pgrp); + } + if (pgrp->OSFlagType != OS_EVENT_TYPE_FLAG) { /* Validate event group type */ + *perr = OS_ERR_EVENT_TYPE; + return (pgrp); + } + OS_ENTER_CRITICAL(); + if (pgrp->OSFlagWaitList != (void *)0) { /* See if any tasks waiting on event flags */ + tasks_waiting = OS_TRUE; /* Yes */ + } else { + tasks_waiting = OS_FALSE; /* No */ + } + switch (opt) { + case OS_DEL_NO_PEND: /* Delete group if no task waiting */ + if (tasks_waiting == OS_FALSE) { +#if OS_FLAG_NAME_EN > 0u + pgrp->OSFlagName = (INT8U *)(void *)"?"; +#endif + pgrp->OSFlagType = OS_EVENT_TYPE_UNUSED; + pgrp->OSFlagWaitList = (void *)OSFlagFreeList; /* Return group to free list */ + pgrp->OSFlagFlags = (OS_FLAGS)0; + OSFlagFreeList = pgrp; + OS_EXIT_CRITICAL(); + *perr = OS_ERR_NONE; + pgrp_return = (OS_FLAG_GRP *)0; /* Event Flag Group has been deleted */ + } else { + OS_EXIT_CRITICAL(); + *perr = OS_ERR_TASK_WAITING; + pgrp_return = pgrp; + } + break; + + case OS_DEL_ALWAYS: /* Always delete the event flag group */ + pnode = (OS_FLAG_NODE *)pgrp->OSFlagWaitList; + while (pnode != (OS_FLAG_NODE *)0) { /* Ready ALL tasks waiting for flags */ + (void)OS_FlagTaskRdy(pnode, (OS_FLAGS)0, OS_STAT_PEND_ABORT); + pnode = (OS_FLAG_NODE *)pnode->OSFlagNodeNext; + } +#if OS_FLAG_NAME_EN > 0u + pgrp->OSFlagName = (INT8U *)(void *)"?"; +#endif + pgrp->OSFlagType = OS_EVENT_TYPE_UNUSED; + pgrp->OSFlagWaitList = (void *)OSFlagFreeList;/* Return group to free list */ + pgrp->OSFlagFlags = (OS_FLAGS)0; + OSFlagFreeList = pgrp; + OS_EXIT_CRITICAL(); + if (tasks_waiting == OS_TRUE) { /* Reschedule only if task(s) were waiting */ + OS_Sched(); /* Find highest priority task ready to run */ + } + *perr = OS_ERR_NONE; + pgrp_return = (OS_FLAG_GRP *)0; /* Event Flag Group has been deleted */ + break; + + default: + OS_EXIT_CRITICAL(); + *perr = OS_ERR_INVALID_OPT; + pgrp_return = pgrp; + break; + } + return (pgrp_return); +} +#endif +/*$PAGE*/ +/* +********************************************************************************************************* +* GET THE NAME OF AN EVENT FLAG GROUP +* +* Description: This function is used to obtain the name assigned to an event flag group +* +* Arguments : pgrp is a pointer to the event flag group. +* +* pname is pointer to a pointer to an ASCII string that will receive the name of the event flag +* group. +* +* perr is a pointer to an error code that can contain one of the following values: +* +* OS_ERR_NONE if the requested task is resumed +* OS_ERR_EVENT_TYPE if 'pevent' is not pointing to an event flag group +* OS_ERR_PNAME_NULL You passed a NULL pointer for 'pname' +* OS_ERR_FLAG_INVALID_PGRP if you passed a NULL pointer for 'pgrp' +* OS_ERR_NAME_GET_ISR if you called this function from an ISR +* +* Returns : The length of the string or 0 if the 'pgrp' is a NULL pointer. +********************************************************************************************************* +*/ + +#if OS_FLAG_NAME_EN > 0u +INT8U OSFlagNameGet (OS_FLAG_GRP *pgrp, + INT8U **pname, + INT8U *perr) +{ + INT8U len; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#ifdef OS_SAFETY_CRITICAL + if (perr == (INT8U *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return (0u); + } +#endif + +#if OS_ARG_CHK_EN > 0u + if (pgrp == (OS_FLAG_GRP *)0) { /* Is 'pgrp' a NULL pointer? */ + *perr = OS_ERR_FLAG_INVALID_PGRP; + return (0u); + } + if (pname == (INT8U **)0) { /* Is 'pname' a NULL pointer? */ + *perr = OS_ERR_PNAME_NULL; + return (0u); + } +#endif + if (OSIntNesting > 0u) { /* See if trying to call from an ISR */ + *perr = OS_ERR_NAME_GET_ISR; + return (0u); + } + OS_ENTER_CRITICAL(); + if (pgrp->OSFlagType != OS_EVENT_TYPE_FLAG) { + OS_EXIT_CRITICAL(); + *perr = OS_ERR_EVENT_TYPE; + return (0u); + } + *pname = pgrp->OSFlagName; + len = OS_StrLen(*pname); + OS_EXIT_CRITICAL(); + *perr = OS_ERR_NONE; + return (len); +} +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* ASSIGN A NAME TO AN EVENT FLAG GROUP +* +* Description: This function assigns a name to an event flag group. +* +* Arguments : pgrp is a pointer to the event flag group. +* +* pname is a pointer to an ASCII string that will be used as the name of the event flag +* group. +* +* perr is a pointer to an error code that can contain one of the following values: +* +* OS_ERR_NONE if the requested task is resumed +* OS_ERR_EVENT_TYPE if 'pevent' is not pointing to an event flag group +* OS_ERR_PNAME_NULL You passed a NULL pointer for 'pname' +* OS_ERR_FLAG_INVALID_PGRP if you passed a NULL pointer for 'pgrp' +* OS_ERR_NAME_SET_ISR if you called this function from an ISR +* +* Returns : None +********************************************************************************************************* +*/ + +#if OS_FLAG_NAME_EN > 0u +void OSFlagNameSet (OS_FLAG_GRP *pgrp, + INT8U *pname, + INT8U *perr) +{ +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#ifdef OS_SAFETY_CRITICAL + if (perr == (INT8U *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return; + } +#endif + +#if OS_ARG_CHK_EN > 0u + if (pgrp == (OS_FLAG_GRP *)0) { /* Is 'pgrp' a NULL pointer? */ + *perr = OS_ERR_FLAG_INVALID_PGRP; + return; + } + if (pname == (INT8U *)0) { /* Is 'pname' a NULL pointer? */ + *perr = OS_ERR_PNAME_NULL; + return; + } +#endif + if (OSIntNesting > 0u) { /* See if trying to call from an ISR */ + *perr = OS_ERR_NAME_SET_ISR; + return; + } + OS_ENTER_CRITICAL(); + if (pgrp->OSFlagType != OS_EVENT_TYPE_FLAG) { + OS_EXIT_CRITICAL(); + *perr = OS_ERR_EVENT_TYPE; + return; + } + pgrp->OSFlagName = pname; + OS_EXIT_CRITICAL(); + *perr = OS_ERR_NONE; + return; +} +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* WAIT ON AN EVENT FLAG GROUP +* +* Description: This function is called to wait for a combination of bits to be set in an event flag +* group. Your application can wait for ANY bit to be set or ALL bits to be set. +* +* Arguments : pgrp is a pointer to the desired event flag group. +* +* flags Is a bit pattern indicating which bit(s) (i.e. flags) you wish to wait for. +* The bits you want are specified by setting the corresponding bits in +* 'flags'. e.g. if your application wants to wait for bits 0 and 1 then +* 'flags' would contain 0x03. +* +* wait_type specifies whether you want ALL bits to be set or ANY of the bits to be set. +* You can specify the following argument: +* +* OS_FLAG_WAIT_CLR_ALL You will wait for ALL bits in 'mask' to be clear (0) +* OS_FLAG_WAIT_SET_ALL You will wait for ALL bits in 'mask' to be set (1) +* OS_FLAG_WAIT_CLR_ANY You will wait for ANY bit in 'mask' to be clear (0) +* OS_FLAG_WAIT_SET_ANY You will wait for ANY bit in 'mask' to be set (1) +* +* NOTE: Add OS_FLAG_CONSUME if you want the event flag to be 'consumed' by +* the call. Example, to wait for any flag in a group AND then clear +* the flags that are present, set 'wait_type' to: +* +* OS_FLAG_WAIT_SET_ANY + OS_FLAG_CONSUME +* +* timeout is an optional timeout (in clock ticks) that your task will wait for the +* desired bit combination. If you specify 0, however, your task will wait +* forever at the specified event flag group or, until a message arrives. +* +* perr is a pointer to an error code and can be: +* OS_ERR_NONE The desired bits have been set within the specified +* 'timeout'. +* OS_ERR_PEND_ISR If you tried to PEND from an ISR +* OS_ERR_FLAG_INVALID_PGRP If 'pgrp' is a NULL pointer. +* OS_ERR_EVENT_TYPE You are not pointing to an event flag group +* OS_ERR_TIMEOUT The bit(s) have not been set in the specified +* 'timeout'. +* OS_ERR_PEND_ABORT The wait on the flag was aborted. +* OS_ERR_FLAG_WAIT_TYPE You didn't specify a proper 'wait_type' argument. +* +* Returns : The flags in the event flag group that made the task ready or, 0 if a timeout or an error +* occurred. +* +* Called from: Task ONLY +* +* Note(s) : 1) IMPORTANT, the behavior of this function has changed from PREVIOUS versions. The +* function NOW returns the flags that were ready INSTEAD of the current state of the +* event flags. +********************************************************************************************************* +*/ + +OS_FLAGS OSFlagPend (OS_FLAG_GRP *pgrp, + OS_FLAGS flags, + INT8U wait_type, + INT32U timeout, + INT8U *perr) +{ + OS_FLAG_NODE node; + OS_FLAGS flags_rdy; + INT8U result; + INT8U pend_stat; + BOOLEAN consume; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#ifdef OS_SAFETY_CRITICAL + if (perr == (INT8U *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return ((OS_FLAGS)0); + } +#endif + +#if OS_ARG_CHK_EN > 0u + if (pgrp == (OS_FLAG_GRP *)0) { /* Validate 'pgrp' */ + *perr = OS_ERR_FLAG_INVALID_PGRP; + return ((OS_FLAGS)0); + } +#endif + if (OSIntNesting > 0u) { /* See if called from ISR ... */ + *perr = OS_ERR_PEND_ISR; /* ... can't PEND from an ISR */ + return ((OS_FLAGS)0); + } + if (OSLockNesting > 0u) { /* See if called with scheduler locked ... */ + *perr = OS_ERR_PEND_LOCKED; /* ... can't PEND when locked */ + return ((OS_FLAGS)0); + } + if (pgrp->OSFlagType != OS_EVENT_TYPE_FLAG) { /* Validate event block type */ + *perr = OS_ERR_EVENT_TYPE; + return ((OS_FLAGS)0); + } + result = (INT8U)(wait_type & OS_FLAG_CONSUME); + if (result != (INT8U)0) { /* See if we need to consume the flags */ + wait_type &= (INT8U)~(INT8U)OS_FLAG_CONSUME; + consume = OS_TRUE; + } else { + consume = OS_FALSE; + } +/*$PAGE*/ + OS_ENTER_CRITICAL(); + switch (wait_type) { + case OS_FLAG_WAIT_SET_ALL: /* See if all required flags are set */ + flags_rdy = (OS_FLAGS)(pgrp->OSFlagFlags & flags); /* Extract only the bits we want */ + if (flags_rdy == flags) { /* Must match ALL the bits that we want */ + if (consume == OS_TRUE) { /* See if we need to consume the flags */ + pgrp->OSFlagFlags &= (OS_FLAGS)~flags_rdy; /* Clear ONLY the flags we wanted */ + } + OSTCBCur->OSTCBFlagsRdy = flags_rdy; /* Save flags that were ready */ + OS_EXIT_CRITICAL(); /* Yes, condition met, return to caller */ + *perr = OS_ERR_NONE; + return (flags_rdy); + } else { /* Block task until events occur or timeout */ + OS_FlagBlock(pgrp, &node, flags, wait_type, timeout); + OS_EXIT_CRITICAL(); + } + break; + + case OS_FLAG_WAIT_SET_ANY: + flags_rdy = (OS_FLAGS)(pgrp->OSFlagFlags & flags); /* Extract only the bits we want */ + if (flags_rdy != (OS_FLAGS)0) { /* See if any flag set */ + if (consume == OS_TRUE) { /* See if we need to consume the flags */ + pgrp->OSFlagFlags &= (OS_FLAGS)~flags_rdy; /* Clear ONLY the flags that we got */ + } + OSTCBCur->OSTCBFlagsRdy = flags_rdy; /* Save flags that were ready */ + OS_EXIT_CRITICAL(); /* Yes, condition met, return to caller */ + *perr = OS_ERR_NONE; + return (flags_rdy); + } else { /* Block task until events occur or timeout */ + OS_FlagBlock(pgrp, &node, flags, wait_type, timeout); + OS_EXIT_CRITICAL(); + } + break; + +#if OS_FLAG_WAIT_CLR_EN > 0u + case OS_FLAG_WAIT_CLR_ALL: /* See if all required flags are cleared */ + flags_rdy = (OS_FLAGS)~pgrp->OSFlagFlags & flags; /* Extract only the bits we want */ + if (flags_rdy == flags) { /* Must match ALL the bits that we want */ + if (consume == OS_TRUE) { /* See if we need to consume the flags */ + pgrp->OSFlagFlags |= flags_rdy; /* Set ONLY the flags that we wanted */ + } + OSTCBCur->OSTCBFlagsRdy = flags_rdy; /* Save flags that were ready */ + OS_EXIT_CRITICAL(); /* Yes, condition met, return to caller */ + *perr = OS_ERR_NONE; + return (flags_rdy); + } else { /* Block task until events occur or timeout */ + OS_FlagBlock(pgrp, &node, flags, wait_type, timeout); + OS_EXIT_CRITICAL(); + } + break; + + case OS_FLAG_WAIT_CLR_ANY: + flags_rdy = (OS_FLAGS)~pgrp->OSFlagFlags & flags; /* Extract only the bits we want */ + if (flags_rdy != (OS_FLAGS)0) { /* See if any flag cleared */ + if (consume == OS_TRUE) { /* See if we need to consume the flags */ + pgrp->OSFlagFlags |= flags_rdy; /* Set ONLY the flags that we got */ + } + OSTCBCur->OSTCBFlagsRdy = flags_rdy; /* Save flags that were ready */ + OS_EXIT_CRITICAL(); /* Yes, condition met, return to caller */ + *perr = OS_ERR_NONE; + return (flags_rdy); + } else { /* Block task until events occur or timeout */ + OS_FlagBlock(pgrp, &node, flags, wait_type, timeout); + OS_EXIT_CRITICAL(); + } + break; +#endif + + default: + OS_EXIT_CRITICAL(); + flags_rdy = (OS_FLAGS)0; + *perr = OS_ERR_FLAG_WAIT_TYPE; + return (flags_rdy); + } +/*$PAGE*/ + OS_Sched(); /* Find next HPT ready to run */ + OS_ENTER_CRITICAL(); + if (OSTCBCur->OSTCBStatPend != OS_STAT_PEND_OK) { /* Have we timed-out or aborted? */ + pend_stat = OSTCBCur->OSTCBStatPend; + OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK; + OS_FlagUnlink(&node); + OSTCBCur->OSTCBStat = OS_STAT_RDY; /* Yes, make task ready-to-run */ + OS_EXIT_CRITICAL(); + flags_rdy = (OS_FLAGS)0; + switch (pend_stat) { + case OS_STAT_PEND_ABORT: + *perr = OS_ERR_PEND_ABORT; /* Indicate that we aborted waiting */ + break; + + case OS_STAT_PEND_TO: + default: + *perr = OS_ERR_TIMEOUT; /* Indicate that we timed-out waiting */ + break; + } + return (flags_rdy); + } + flags_rdy = OSTCBCur->OSTCBFlagsRdy; + if (consume == OS_TRUE) { /* See if we need to consume the flags */ + switch (wait_type) { + case OS_FLAG_WAIT_SET_ALL: + case OS_FLAG_WAIT_SET_ANY: /* Clear ONLY the flags we got */ + pgrp->OSFlagFlags &= (OS_FLAGS)~flags_rdy; + break; + +#if OS_FLAG_WAIT_CLR_EN > 0u + case OS_FLAG_WAIT_CLR_ALL: + case OS_FLAG_WAIT_CLR_ANY: /* Set ONLY the flags we got */ + pgrp->OSFlagFlags |= flags_rdy; + break; +#endif + default: + OS_EXIT_CRITICAL(); + *perr = OS_ERR_FLAG_WAIT_TYPE; + return ((OS_FLAGS)0); + } + } + OS_EXIT_CRITICAL(); + *perr = OS_ERR_NONE; /* Event(s) must have occurred */ + return (flags_rdy); +} +/*$PAGE*/ +/* +********************************************************************************************************* +* GET FLAGS WHO CAUSED TASK TO BECOME READY +* +* Description: This function is called to obtain the flags that caused the task to become ready to run. +* In other words, this function allows you to tell "Who done it!". +* +* Arguments : None +* +* Returns : The flags that caused the task to be ready. +* +* Called from: Task ONLY +********************************************************************************************************* +*/ + +OS_FLAGS OSFlagPendGetFlagsRdy (void) +{ + OS_FLAGS flags; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + + OS_ENTER_CRITICAL(); + flags = OSTCBCur->OSTCBFlagsRdy; + OS_EXIT_CRITICAL(); + return (flags); +} + +/*$PAGE*/ +/* +********************************************************************************************************* +* POST EVENT FLAG BIT(S) +* +* Description: This function is called to set or clear some bits in an event flag group. The bits to +* set or clear are specified by a 'bit mask'. +* +* Arguments : pgrp is a pointer to the desired event flag group. +* +* flags If 'opt' (see below) is OS_FLAG_SET, each bit that is set in 'flags' will +* set the corresponding bit in the event flag group. e.g. to set bits 0, 4 +* and 5 you would set 'flags' to: +* +* 0x31 (note, bit 0 is least significant bit) +* +* If 'opt' (see below) is OS_FLAG_CLR, each bit that is set in 'flags' will +* CLEAR the corresponding bit in the event flag group. e.g. to clear bits 0, +* 4 and 5 you would specify 'flags' as: +* +* 0x31 (note, bit 0 is least significant bit) +* +* opt indicates whether the flags will be: +* set (OS_FLAG_SET) or +* cleared (OS_FLAG_CLR) +* +* perr is a pointer to an error code and can be: +* OS_ERR_NONE The call was successfull +* OS_ERR_FLAG_INVALID_PGRP You passed a NULL pointer +* OS_ERR_EVENT_TYPE You are not pointing to an event flag group +* OS_ERR_FLAG_INVALID_OPT You specified an invalid option +* +* Returns : the new value of the event flags bits that are still set. +* +* Called From: Task or ISR +* +* WARNING(s) : 1) The execution time of this function depends on the number of tasks waiting on the event +* flag group. +* 2) The amount of time interrupts are DISABLED depends on the number of tasks waiting on +* the event flag group. +********************************************************************************************************* +*/ +OS_FLAGS OSFlagPost (OS_FLAG_GRP *pgrp, + OS_FLAGS flags, + INT8U opt, + INT8U *perr) +{ + OS_FLAG_NODE *pnode; + BOOLEAN sched; + OS_FLAGS flags_cur; + OS_FLAGS flags_rdy; + BOOLEAN rdy; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#ifdef OS_SAFETY_CRITICAL + if (perr == (INT8U *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return ((OS_FLAGS)0); + } +#endif + +#if OS_ARG_CHK_EN > 0u + if (pgrp == (OS_FLAG_GRP *)0) { /* Validate 'pgrp' */ + *perr = OS_ERR_FLAG_INVALID_PGRP; + return ((OS_FLAGS)0); + } +#endif + if (pgrp->OSFlagType != OS_EVENT_TYPE_FLAG) { /* Make sure we are pointing to an event flag grp */ + *perr = OS_ERR_EVENT_TYPE; + return ((OS_FLAGS)0); + } +/*$PAGE*/ + OS_ENTER_CRITICAL(); + switch (opt) { + case OS_FLAG_CLR: + pgrp->OSFlagFlags &= (OS_FLAGS)~flags; /* Clear the flags specified in the group */ + break; + + case OS_FLAG_SET: + pgrp->OSFlagFlags |= flags; /* Set the flags specified in the group */ + break; + + default: + OS_EXIT_CRITICAL(); /* INVALID option */ + *perr = OS_ERR_FLAG_INVALID_OPT; + return ((OS_FLAGS)0); + } + sched = OS_FALSE; /* Indicate that we don't need rescheduling */ + pnode = (OS_FLAG_NODE *)pgrp->OSFlagWaitList; + while (pnode != (OS_FLAG_NODE *)0) { /* Go through all tasks waiting on event flag(s) */ + switch (pnode->OSFlagNodeWaitType) { + case OS_FLAG_WAIT_SET_ALL: /* See if all req. flags are set for current node */ + flags_rdy = (OS_FLAGS)(pgrp->OSFlagFlags & pnode->OSFlagNodeFlags); + if (flags_rdy == pnode->OSFlagNodeFlags) { /* Make task RTR, event(s) Rx'd */ + rdy = OS_FlagTaskRdy(pnode, flags_rdy, OS_STAT_PEND_OK); + if (rdy == OS_TRUE) { + sched = OS_TRUE; /* When done we will reschedule */ + } + } + break; + + case OS_FLAG_WAIT_SET_ANY: /* See if any flag set */ + flags_rdy = (OS_FLAGS)(pgrp->OSFlagFlags & pnode->OSFlagNodeFlags); + if (flags_rdy != (OS_FLAGS)0) { /* Make task RTR, event(s) Rx'd */ + rdy = OS_FlagTaskRdy(pnode, flags_rdy, OS_STAT_PEND_OK); + if (rdy == OS_TRUE) { + sched = OS_TRUE; /* When done we will reschedule */ + } + } + break; + +#if OS_FLAG_WAIT_CLR_EN > 0u + case OS_FLAG_WAIT_CLR_ALL: /* See if all req. flags are set for current node */ + flags_rdy = (OS_FLAGS)~pgrp->OSFlagFlags & pnode->OSFlagNodeFlags; + if (flags_rdy == pnode->OSFlagNodeFlags) { /* Make task RTR, event(s) Rx'd */ + rdy = OS_FlagTaskRdy(pnode, flags_rdy, OS_STAT_PEND_OK); + if (rdy == OS_TRUE) { + sched = OS_TRUE; /* When done we will reschedule */ + } + } + break; + + case OS_FLAG_WAIT_CLR_ANY: /* See if any flag set */ + flags_rdy = (OS_FLAGS)~pgrp->OSFlagFlags & pnode->OSFlagNodeFlags; + if (flags_rdy != (OS_FLAGS)0) { /* Make task RTR, event(s) Rx'd */ + rdy = OS_FlagTaskRdy(pnode, flags_rdy, OS_STAT_PEND_OK); + if (rdy == OS_TRUE) { + sched = OS_TRUE; /* When done we will reschedule */ + } + } + break; +#endif + default: + OS_EXIT_CRITICAL(); + *perr = OS_ERR_FLAG_WAIT_TYPE; + return ((OS_FLAGS)0); + } + pnode = (OS_FLAG_NODE *)pnode->OSFlagNodeNext; /* Point to next task waiting for event flag(s) */ + } + OS_EXIT_CRITICAL(); + if (sched == OS_TRUE) { + OS_Sched(); + } + OS_ENTER_CRITICAL(); + flags_cur = pgrp->OSFlagFlags; + OS_EXIT_CRITICAL(); + *perr = OS_ERR_NONE; + return (flags_cur); +} +/*$PAGE*/ +/* +********************************************************************************************************* +* QUERY EVENT FLAG +* +* Description: This function is used to check the value of the event flag group. +* +* Arguments : pgrp is a pointer to the desired event flag group. +* +* perr is a pointer to an error code returned to the called: +* OS_ERR_NONE The call was successfull +* OS_ERR_FLAG_INVALID_PGRP You passed a NULL pointer +* OS_ERR_EVENT_TYPE You are not pointing to an event flag group +* +* Returns : The current value of the event flag group. +* +* Called From: Task or ISR +********************************************************************************************************* +*/ + +#if OS_FLAG_QUERY_EN > 0u +OS_FLAGS OSFlagQuery (OS_FLAG_GRP *pgrp, + INT8U *perr) +{ + OS_FLAGS flags; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#ifdef OS_SAFETY_CRITICAL + if (perr == (INT8U *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return ((OS_FLAGS)0); + } +#endif + +#if OS_ARG_CHK_EN > 0u + if (pgrp == (OS_FLAG_GRP *)0) { /* Validate 'pgrp' */ + *perr = OS_ERR_FLAG_INVALID_PGRP; + return ((OS_FLAGS)0); + } +#endif + if (pgrp->OSFlagType != OS_EVENT_TYPE_FLAG) { /* Validate event block type */ + *perr = OS_ERR_EVENT_TYPE; + return ((OS_FLAGS)0); + } + OS_ENTER_CRITICAL(); + flags = pgrp->OSFlagFlags; + OS_EXIT_CRITICAL(); + *perr = OS_ERR_NONE; + return (flags); /* Return the current value of the event flags */ +} +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* SUSPEND TASK UNTIL EVENT FLAG(s) RECEIVED OR TIMEOUT OCCURS +* +* Description: This function is internal to uC/OS-II and is used to put a task to sleep until the desired +* event flag bit(s) are set. +* +* Arguments : pgrp is a pointer to the desired event flag group. +* +* pnode is a pointer to a structure which contains data about the task waiting for +* event flag bit(s) to be set. +* +* flags Is a bit pattern indicating which bit(s) (i.e. flags) you wish to check. +* The bits you want are specified by setting the corresponding bits in +* 'flags'. e.g. if your application wants to wait for bits 0 and 1 then +* 'flags' would contain 0x03. +* +* wait_type specifies whether you want ALL bits to be set/cleared or ANY of the bits +* to be set/cleared. +* You can specify the following argument: +* +* OS_FLAG_WAIT_CLR_ALL You will check ALL bits in 'mask' to be clear (0) +* OS_FLAG_WAIT_CLR_ANY You will check ANY bit in 'mask' to be clear (0) +* OS_FLAG_WAIT_SET_ALL You will check ALL bits in 'mask' to be set (1) +* OS_FLAG_WAIT_SET_ANY You will check ANY bit in 'mask' to be set (1) +* +* timeout is the desired amount of time that the task will wait for the event flag +* bit(s) to be set. +* +* Returns : none +* +* Called by : OSFlagPend() OS_FLAG.C +* +* Note(s) : This function is INTERNAL to uC/OS-II and your application should not call it. +********************************************************************************************************* +*/ + +static void OS_FlagBlock (OS_FLAG_GRP *pgrp, + OS_FLAG_NODE *pnode, + OS_FLAGS flags, + INT8U wait_type, + INT32U timeout) +{ + OS_FLAG_NODE *pnode_next; + INT8U y; + + + OSTCBCur->OSTCBStat |= OS_STAT_FLAG; + OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK; + OSTCBCur->OSTCBDly = timeout; /* Store timeout in task's TCB */ +#if OS_TASK_DEL_EN > 0u + OSTCBCur->OSTCBFlagNode = pnode; /* TCB to link to node */ +#endif + pnode->OSFlagNodeFlags = flags; /* Save the flags that we need to wait for */ + pnode->OSFlagNodeWaitType = wait_type; /* Save the type of wait we are doing */ + pnode->OSFlagNodeTCB = (void *)OSTCBCur; /* Link to task's TCB */ + pnode->OSFlagNodeNext = pgrp->OSFlagWaitList; /* Add node at beginning of event flag wait list */ + pnode->OSFlagNodePrev = (void *)0; + pnode->OSFlagNodeFlagGrp = (void *)pgrp; /* Link to Event Flag Group */ + pnode_next = (OS_FLAG_NODE *)pgrp->OSFlagWaitList; + if (pnode_next != (void *)0) { /* Is this the first NODE to insert? */ + pnode_next->OSFlagNodePrev = pnode; /* No, link in doubly linked list */ + } + pgrp->OSFlagWaitList = (void *)pnode; + + y = OSTCBCur->OSTCBY; /* Suspend current task until flag(s) received */ + OSRdyTbl[y] &= (OS_PRIO)~OSTCBCur->OSTCBBitX; + if (OSRdyTbl[y] == 0x00u) { + OSRdyGrp &= (OS_PRIO)~OSTCBCur->OSTCBBitY; + } +} + +/*$PAGE*/ +/* +********************************************************************************************************* +* INITIALIZE THE EVENT FLAG MODULE +* +* Description: This function is called by uC/OS-II to initialize the event flag module. Your application +* MUST NOT call this function. In other words, this function is internal to uC/OS-II. +* +* Arguments : none +* +* Returns : none +* +* WARNING : You MUST NOT call this function from your code. This is an INTERNAL function to uC/OS-II. +********************************************************************************************************* +*/ + +void OS_FlagInit (void) +{ +#if OS_MAX_FLAGS == 1u + OSFlagFreeList = (OS_FLAG_GRP *)&OSFlagTbl[0]; /* Only ONE event flag group! */ + OSFlagFreeList->OSFlagType = OS_EVENT_TYPE_UNUSED; + OSFlagFreeList->OSFlagWaitList = (void *)0; + OSFlagFreeList->OSFlagFlags = (OS_FLAGS)0; +#if OS_FLAG_NAME_EN > 0u + OSFlagFreeList->OSFlagName = (INT8U *)"?"; +#endif +#endif + +#if OS_MAX_FLAGS >= 2u + INT16U ix; + INT16U ix_next; + OS_FLAG_GRP *pgrp1; + OS_FLAG_GRP *pgrp2; + + + OS_MemClr((INT8U *)&OSFlagTbl[0], sizeof(OSFlagTbl)); /* Clear the flag group table */ + for (ix = 0u; ix < (OS_MAX_FLAGS - 1u); ix++) { /* Init. list of free EVENT FLAGS */ + ix_next = ix + 1u; + pgrp1 = &OSFlagTbl[ix]; + pgrp2 = &OSFlagTbl[ix_next]; + pgrp1->OSFlagType = OS_EVENT_TYPE_UNUSED; + pgrp1->OSFlagWaitList = (void *)pgrp2; +#if OS_FLAG_NAME_EN > 0u + pgrp1->OSFlagName = (INT8U *)(void *)"?"; /* Unknown name */ +#endif + } + pgrp1 = &OSFlagTbl[ix]; + pgrp1->OSFlagType = OS_EVENT_TYPE_UNUSED; + pgrp1->OSFlagWaitList = (void *)0; +#if OS_FLAG_NAME_EN > 0u + pgrp1->OSFlagName = (INT8U *)(void *)"?"; /* Unknown name */ +#endif + OSFlagFreeList = &OSFlagTbl[0]; +#endif +} + +/*$PAGE*/ +/* +********************************************************************************************************* +* MAKE TASK READY-TO-RUN, EVENT(s) OCCURRED +* +* Description: This function is internal to uC/OS-II and is used to make a task ready-to-run because the +* desired event flag bits have been set. +* +* Arguments : pnode is a pointer to a structure which contains data about the task waiting for +* event flag bit(s) to be set. +* +* flags_rdy contains the bit pattern of the event flags that cause the task to become +* ready-to-run. +* +* pend_stat is used to indicate the readied task's pending status: +* +* +* Returns : OS_TRUE If the task has been placed in the ready list and thus needs scheduling +* OS_FALSE The task is still not ready to run and thus scheduling is not necessary +* +* Called by : OSFlagsPost() OS_FLAG.C +* +* Note(s) : 1) This function assumes that interrupts are disabled. +* 2) This function is INTERNAL to uC/OS-II and your application should not call it. +********************************************************************************************************* +*/ + +static BOOLEAN OS_FlagTaskRdy (OS_FLAG_NODE *pnode, + OS_FLAGS flags_rdy, + INT8U pend_stat) +{ + OS_TCB *ptcb; + BOOLEAN sched; + + + ptcb = (OS_TCB *)pnode->OSFlagNodeTCB; /* Point to TCB of waiting task */ + ptcb->OSTCBDly = 0u; + ptcb->OSTCBFlagsRdy = flags_rdy; + ptcb->OSTCBStat &= (INT8U)~(INT8U)OS_STAT_FLAG; + ptcb->OSTCBStatPend = pend_stat; + if (ptcb->OSTCBStat == OS_STAT_RDY) { /* Task now ready? */ + OSRdyGrp |= ptcb->OSTCBBitY; /* Put task into ready list */ + OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX; + sched = OS_TRUE; + } else { + sched = OS_FALSE; + } + OS_FlagUnlink(pnode); + return (sched); +} + +/*$PAGE*/ +/* +********************************************************************************************************* +* UNLINK EVENT FLAG NODE FROM WAITING LIST +* +* Description: This function is internal to uC/OS-II and is used to unlink an event flag node from a +* list of tasks waiting for the event flag. +* +* Arguments : pnode is a pointer to a structure which contains data about the task waiting for +* event flag bit(s) to be set. +* +* Returns : none +* +* Called by : OS_FlagTaskRdy() OS_FLAG.C +* OSFlagPend() OS_FLAG.C +* OSTaskDel() OS_TASK.C +* +* Note(s) : 1) This function assumes that interrupts are disabled. +* 2) This function is INTERNAL to uC/OS-II and your application should not call it. +********************************************************************************************************* +*/ + +void OS_FlagUnlink (OS_FLAG_NODE *pnode) +{ +#if OS_TASK_DEL_EN > 0u + OS_TCB *ptcb; +#endif + OS_FLAG_GRP *pgrp; + OS_FLAG_NODE *pnode_prev; + OS_FLAG_NODE *pnode_next; + + + pnode_prev = (OS_FLAG_NODE *)pnode->OSFlagNodePrev; + pnode_next = (OS_FLAG_NODE *)pnode->OSFlagNodeNext; + if (pnode_prev == (OS_FLAG_NODE *)0) { /* Is it first node in wait list? */ + pgrp = (OS_FLAG_GRP *)pnode->OSFlagNodeFlagGrp; + pgrp->OSFlagWaitList = (void *)pnode_next; /* Update list for new 1st node */ + if (pnode_next != (OS_FLAG_NODE *)0) { + pnode_next->OSFlagNodePrev = (OS_FLAG_NODE *)0; /* Link new 1st node PREV to NULL */ + } + } else { /* No, A node somewhere in the list */ + pnode_prev->OSFlagNodeNext = pnode_next; /* Link around the node to unlink */ + if (pnode_next != (OS_FLAG_NODE *)0) { /* Was this the LAST node? */ + pnode_next->OSFlagNodePrev = pnode_prev; /* No, Link around current node */ + } + } +#if OS_TASK_DEL_EN > 0u + ptcb = (OS_TCB *)pnode->OSFlagNodeTCB; + ptcb->OSTCBFlagNode = (OS_FLAG_NODE *)0; +#endif +} +#endif diff --git a/Middlewares/Third_Party/Micrium/uCOS-II/Source/os_mbox.c b/Middlewares/Third_Party/Micrium/uCOS-II/Source/os_mbox.c new file mode 100644 index 0000000..0322474 --- /dev/null +++ b/Middlewares/Third_Party/Micrium/uCOS-II/Source/os_mbox.c @@ -0,0 +1,654 @@ +/* +********************************************************************************************************* +* uC/OS-II +* The Real-Time Kernel +* MESSAGE MAILBOX MANAGEMENT +* +* (c) Copyright 1992-2013, Micrium, Weston, FL +* All Rights Reserved +* +* File : OS_MBOX.C +* By : Jean J. Labrosse +* Version : V2.92.11 +* +* LICENSING TERMS: +* --------------- +* uC/OS-II is provided in source form for FREE evaluation, for educational use or for peaceful research. +* If you plan on using uC/OS-II in a commercial product you need to contact Micrium to properly license +* its use in your product. We provide ALL the source code for your convenience and to help you experience +* uC/OS-II. The fact that the source is provided does NOT mean that you can use it without paying a +* licensing fee. +********************************************************************************************************* +*/ + +#define MICRIUM_SOURCE + +#ifndef OS_MASTER_FILE +#include +#endif + +#if OS_MBOX_EN > 0u +/* +********************************************************************************************************* +* ACCEPT MESSAGE FROM MAILBOX +* +* Description: This function checks the mailbox to see if a message is available. Unlike OSMboxPend(), +* OSMboxAccept() does not suspend the calling task if a message is not available. +* +* Arguments : pevent is a pointer to the event control block +* +* Returns : != (void *)0 is the message in the mailbox if one is available. The mailbox is cleared +* so the next time OSMboxAccept() is called, the mailbox will be empty. +* == (void *)0 if the mailbox is empty or, +* if 'pevent' is a NULL pointer or, +* if you didn't pass the proper event pointer. +********************************************************************************************************* +*/ + +#if OS_MBOX_ACCEPT_EN > 0u +void *OSMboxAccept (OS_EVENT *pevent) +{ + void *pmsg; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#if OS_ARG_CHK_EN > 0u + if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */ + return ((void *)0); + } +#endif + if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) { /* Validate event block type */ + return ((void *)0); + } + OS_ENTER_CRITICAL(); + pmsg = pevent->OSEventPtr; + pevent->OSEventPtr = (void *)0; /* Clear the mailbox */ + OS_EXIT_CRITICAL(); + return (pmsg); /* Return the message received (or NULL) */ +} +#endif +/*$PAGE*/ +/* +********************************************************************************************************* +* CREATE A MESSAGE MAILBOX +* +* Description: This function creates a message mailbox if free event control blocks are available. +* +* Arguments : pmsg is a pointer to a message that you wish to deposit in the mailbox. If +* you set this value to the NULL pointer (i.e. (void *)0) then the mailbox +* will be considered empty. +* +* Returns : != (OS_EVENT *)0 is a pointer to the event control clock (OS_EVENT) associated with the +* created mailbox +* == (OS_EVENT *)0 if no event control blocks were available +********************************************************************************************************* +*/ + +OS_EVENT *OSMboxCreate (void *pmsg) +{ + OS_EVENT *pevent; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#ifdef OS_SAFETY_CRITICAL_IEC61508 + if (OSSafetyCriticalStartFlag == OS_TRUE) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return ((OS_EVENT *)0); + } +#endif + + if (OSIntNesting > 0u) { /* See if called from ISR ... */ + return ((OS_EVENT *)0); /* ... can't CREATE from an ISR */ + } + OS_ENTER_CRITICAL(); + pevent = OSEventFreeList; /* Get next free event control block */ + if (OSEventFreeList != (OS_EVENT *)0) { /* See if pool of free ECB pool was empty */ + OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr; + } + OS_EXIT_CRITICAL(); + if (pevent != (OS_EVENT *)0) { + pevent->OSEventType = OS_EVENT_TYPE_MBOX; + pevent->OSEventCnt = 0u; + pevent->OSEventPtr = pmsg; /* Deposit message in event control block */ +#if OS_EVENT_NAME_EN > 0u + pevent->OSEventName = (INT8U *)(void *)"?"; +#endif + OS_EventWaitListInit(pevent); + } + return (pevent); /* Return pointer to event control block */ +} +/*$PAGE*/ +/* +********************************************************************************************************* +* DELETE A MAIBOX +* +* Description: This function deletes a mailbox and readies all tasks pending on the mailbox. +* +* Arguments : pevent is a pointer to the event control block associated with the desired +* mailbox. +* +* opt determines delete options as follows: +* opt == OS_DEL_NO_PEND Delete the mailbox ONLY if no task pending +* opt == OS_DEL_ALWAYS Deletes the mailbox even if tasks are waiting. +* In this case, all the tasks pending will be readied. +* +* perr is a pointer to an error code that can contain one of the following values: +* OS_ERR_NONE The call was successful and the mailbox was deleted +* OS_ERR_DEL_ISR If you attempted to delete the mailbox from an ISR +* OS_ERR_INVALID_OPT An invalid option was specified +* OS_ERR_TASK_WAITING One or more tasks were waiting on the mailbox +* OS_ERR_EVENT_TYPE If you didn't pass a pointer to a mailbox +* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer. +* +* Returns : pevent upon error +* (OS_EVENT *)0 if the mailbox was successfully deleted. +* +* Note(s) : 1) This function must be used with care. Tasks that would normally expect the presence of +* the mailbox MUST check the return code of OSMboxPend(). +* 2) OSMboxAccept() callers will not know that the intended mailbox has been deleted! +* 3) This call can potentially disable interrupts for a long time. The interrupt disable +* time is directly proportional to the number of tasks waiting on the mailbox. +* 4) Because ALL tasks pending on the mailbox will be readied, you MUST be careful in +* applications where the mailbox is used for mutual exclusion because the resource(s) +* will no longer be guarded by the mailbox. +* 5) All tasks that were waiting for the mailbox will be readied and returned an +* OS_ERR_PEND_ABORT if OSMboxDel() was called with OS_DEL_ALWAYS +********************************************************************************************************* +*/ + +#if OS_MBOX_DEL_EN > 0u +OS_EVENT *OSMboxDel (OS_EVENT *pevent, + INT8U opt, + INT8U *perr) +{ + BOOLEAN tasks_waiting; + OS_EVENT *pevent_return; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#ifdef OS_SAFETY_CRITICAL + if (perr == (INT8U *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return ((OS_EVENT *)0); + } +#endif + +#if OS_ARG_CHK_EN > 0u + if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */ + *perr = OS_ERR_PEVENT_NULL; + return (pevent); + } +#endif + if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) { /* Validate event block type */ + *perr = OS_ERR_EVENT_TYPE; + return (pevent); + } + if (OSIntNesting > 0u) { /* See if called from ISR ... */ + *perr = OS_ERR_DEL_ISR; /* ... can't DELETE from an ISR */ + return (pevent); + } + OS_ENTER_CRITICAL(); + if (pevent->OSEventGrp != 0u) { /* See if any tasks waiting on mailbox */ + tasks_waiting = OS_TRUE; /* Yes */ + } else { + tasks_waiting = OS_FALSE; /* No */ + } + switch (opt) { + case OS_DEL_NO_PEND: /* Delete mailbox only if no task waiting */ + if (tasks_waiting == OS_FALSE) { +#if OS_EVENT_NAME_EN > 0u + pevent->OSEventName = (INT8U *)(void *)"?"; +#endif + pevent->OSEventType = OS_EVENT_TYPE_UNUSED; + pevent->OSEventPtr = OSEventFreeList; /* Return Event Control Block to free list */ + pevent->OSEventCnt = 0u; + OSEventFreeList = pevent; /* Get next free event control block */ + OS_EXIT_CRITICAL(); + *perr = OS_ERR_NONE; + pevent_return = (OS_EVENT *)0; /* Mailbox has been deleted */ + } else { + OS_EXIT_CRITICAL(); + *perr = OS_ERR_TASK_WAITING; + pevent_return = pevent; + } + break; + + case OS_DEL_ALWAYS: /* Always delete the mailbox */ + while (pevent->OSEventGrp != 0u) { /* Ready ALL tasks waiting for mailbox */ + (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_MBOX, OS_STAT_PEND_ABORT); + } +#if OS_EVENT_NAME_EN > 0u + pevent->OSEventName = (INT8U *)(void *)"?"; +#endif + pevent->OSEventType = OS_EVENT_TYPE_UNUSED; + pevent->OSEventPtr = OSEventFreeList; /* Return Event Control Block to free list */ + pevent->OSEventCnt = 0u; + OSEventFreeList = pevent; /* Get next free event control block */ + OS_EXIT_CRITICAL(); + if (tasks_waiting == OS_TRUE) { /* Reschedule only if task(s) were waiting */ + OS_Sched(); /* Find highest priority task ready to run */ + } + *perr = OS_ERR_NONE; + pevent_return = (OS_EVENT *)0; /* Mailbox has been deleted */ + break; + + default: + OS_EXIT_CRITICAL(); + *perr = OS_ERR_INVALID_OPT; + pevent_return = pevent; + break; + } + return (pevent_return); +} +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* PEND ON MAILBOX FOR A MESSAGE +* +* Description: This function waits for a message to be sent to a mailbox +* +* Arguments : pevent is a pointer to the event control block associated with the desired mailbox +* +* timeout is an optional timeout period (in clock ticks). If non-zero, your task will +* wait for a message to arrive at the mailbox up to the amount of time +* specified by this argument. If you specify 0, however, your task will wait +* forever at the specified mailbox or, until a message arrives. +* +* perr is a pointer to where an error message will be deposited. Possible error +* messages are: +* +* OS_ERR_NONE The call was successful and your task received a +* message. +* OS_ERR_TIMEOUT A message was not received within the specified 'timeout'. +* OS_ERR_PEND_ABORT The wait on the mailbox was aborted. +* OS_ERR_EVENT_TYPE Invalid event type +* OS_ERR_PEND_ISR If you called this function from an ISR and the result +* would lead to a suspension. +* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer +* OS_ERR_PEND_LOCKED If you called this function when the scheduler is locked +* +* Returns : != (void *)0 is a pointer to the message received +* == (void *)0 if no message was received or, +* if 'pevent' is a NULL pointer or, +* if you didn't pass the proper pointer to the event control block. +********************************************************************************************************* +*/ +/*$PAGE*/ +void *OSMboxPend (OS_EVENT *pevent, + INT32U timeout, + INT8U *perr) +{ + void *pmsg; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#ifdef OS_SAFETY_CRITICAL + if (perr == (INT8U *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return ((void *)0); + } +#endif + +#if OS_ARG_CHK_EN > 0u + if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */ + *perr = OS_ERR_PEVENT_NULL; + return ((void *)0); + } +#endif + if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) { /* Validate event block type */ + *perr = OS_ERR_EVENT_TYPE; + return ((void *)0); + } + if (OSIntNesting > 0u) { /* See if called from ISR ... */ + *perr = OS_ERR_PEND_ISR; /* ... can't PEND from an ISR */ + return ((void *)0); + } + if (OSLockNesting > 0u) { /* See if called with scheduler locked ... */ + *perr = OS_ERR_PEND_LOCKED; /* ... can't PEND when locked */ + return ((void *)0); + } + OS_ENTER_CRITICAL(); + pmsg = pevent->OSEventPtr; + if (pmsg != (void *)0) { /* See if there is already a message */ + pevent->OSEventPtr = (void *)0; /* Clear the mailbox */ + OS_EXIT_CRITICAL(); + *perr = OS_ERR_NONE; + return (pmsg); /* Return the message received (or NULL) */ + } + OSTCBCur->OSTCBStat |= OS_STAT_MBOX; /* Message not available, task will pend */ + OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK; + OSTCBCur->OSTCBDly = timeout; /* Load timeout in TCB */ + OS_EventTaskWait(pevent); /* Suspend task until event or timeout occurs */ + OS_EXIT_CRITICAL(); + OS_Sched(); /* Find next highest priority task ready to run */ + OS_ENTER_CRITICAL(); + switch (OSTCBCur->OSTCBStatPend) { /* See if we timed-out or aborted */ + case OS_STAT_PEND_OK: + pmsg = OSTCBCur->OSTCBMsg; + *perr = OS_ERR_NONE; + break; + + case OS_STAT_PEND_ABORT: + pmsg = (void *)0; + *perr = OS_ERR_PEND_ABORT; /* Indicate that we aborted */ + break; + + case OS_STAT_PEND_TO: + default: + OS_EventTaskRemove(OSTCBCur, pevent); + pmsg = (void *)0; + *perr = OS_ERR_TIMEOUT; /* Indicate that we didn't get event within TO */ + break; + } + OSTCBCur->OSTCBStat = OS_STAT_RDY; /* Set task status to ready */ + OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK; /* Clear pend status */ + OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; /* Clear event pointers */ +#if (OS_EVENT_MULTI_EN > 0u) + OSTCBCur->OSTCBEventMultiPtr = (OS_EVENT **)0; +#endif + OSTCBCur->OSTCBMsg = (void *)0; /* Clear received message */ + OS_EXIT_CRITICAL(); + return (pmsg); /* Return received message */ +} +/*$PAGE*/ +/* +********************************************************************************************************* +* ABORT WAITING ON A MESSAGE MAILBOX +* +* Description: This function aborts & readies any tasks currently waiting on a mailbox. This function +* should be used to fault-abort the wait on the mailbox, rather than to normally signal +* the mailbox via OSMboxPost() or OSMboxPostOpt(). +* +* Arguments : pevent is a pointer to the event control block associated with the desired mailbox. +* +* opt determines the type of ABORT performed: +* OS_PEND_OPT_NONE ABORT wait for a single task (HPT) waiting on the +* mailbox +* OS_PEND_OPT_BROADCAST ABORT wait for ALL tasks that are waiting on the +* mailbox +* +* perr is a pointer to where an error message will be deposited. Possible error +* messages are: +* +* OS_ERR_NONE No tasks were waiting on the mailbox. +* OS_ERR_PEND_ABORT At least one task waiting on the mailbox was readied +* and informed of the aborted wait; check return value +* for the number of tasks whose wait on the mailbox +* was aborted. +* OS_ERR_EVENT_TYPE If you didn't pass a pointer to a mailbox. +* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer. +* +* Returns : == 0 if no tasks were waiting on the mailbox, or upon error. +* > 0 if one or more tasks waiting on the mailbox are now readied and informed. +********************************************************************************************************* +*/ + +#if OS_MBOX_PEND_ABORT_EN > 0u +INT8U OSMboxPendAbort (OS_EVENT *pevent, + INT8U opt, + INT8U *perr) +{ + INT8U nbr_tasks; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#ifdef OS_SAFETY_CRITICAL + if (perr == (INT8U *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return (0u); + } +#endif + +#if OS_ARG_CHK_EN > 0u + if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */ + *perr = OS_ERR_PEVENT_NULL; + return (0u); + } +#endif + if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) { /* Validate event block type */ + *perr = OS_ERR_EVENT_TYPE; + return (0u); + } + OS_ENTER_CRITICAL(); + if (pevent->OSEventGrp != 0u) { /* See if any task waiting on mailbox? */ + nbr_tasks = 0u; + switch (opt) { + case OS_PEND_OPT_BROADCAST: /* Do we need to abort ALL waiting tasks? */ + while (pevent->OSEventGrp != 0u) { /* Yes, ready ALL tasks waiting on mailbox */ + (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_MBOX, OS_STAT_PEND_ABORT); + nbr_tasks++; + } + break; + + case OS_PEND_OPT_NONE: + default: /* No, ready HPT waiting on mailbox */ + (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_MBOX, OS_STAT_PEND_ABORT); + nbr_tasks++; + break; + } + OS_EXIT_CRITICAL(); + OS_Sched(); /* Find HPT ready to run */ + *perr = OS_ERR_PEND_ABORT; + return (nbr_tasks); + } + OS_EXIT_CRITICAL(); + *perr = OS_ERR_NONE; + return (0u); /* No tasks waiting on mailbox */ +} +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* POST MESSAGE TO A MAILBOX +* +* Description: This function sends a message to a mailbox +* +* Arguments : pevent is a pointer to the event control block associated with the desired mailbox +* +* pmsg is a pointer to the message to send. You MUST NOT send a NULL pointer. +* +* Returns : OS_ERR_NONE The call was successful and the message was sent +* OS_ERR_MBOX_FULL If the mailbox already contains a message. You can can only send one +* message at a time and thus, the message MUST be consumed before you +* are allowed to send another one. +* OS_ERR_EVENT_TYPE If you are attempting to post to a non mailbox. +* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer +* OS_ERR_POST_NULL_PTR If you are attempting to post a NULL pointer +* +* Note(s) : 1) HPT means Highest Priority Task +********************************************************************************************************* +*/ + +#if OS_MBOX_POST_EN > 0u +INT8U OSMboxPost (OS_EVENT *pevent, + void *pmsg) +{ +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#if OS_ARG_CHK_EN > 0u + if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */ + return (OS_ERR_PEVENT_NULL); + } + if (pmsg == (void *)0) { /* Make sure we are not posting a NULL pointer */ + return (OS_ERR_POST_NULL_PTR); + } +#endif + if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) { /* Validate event block type */ + return (OS_ERR_EVENT_TYPE); + } + OS_ENTER_CRITICAL(); + if (pevent->OSEventGrp != 0u) { /* See if any task pending on mailbox */ + /* Ready HPT waiting on event */ + (void)OS_EventTaskRdy(pevent, pmsg, OS_STAT_MBOX, OS_STAT_PEND_OK); + OS_EXIT_CRITICAL(); + OS_Sched(); /* Find highest priority task ready to run */ + return (OS_ERR_NONE); + } + if (pevent->OSEventPtr != (void *)0) { /* Make sure mailbox doesn't already have a msg */ + OS_EXIT_CRITICAL(); + return (OS_ERR_MBOX_FULL); + } + pevent->OSEventPtr = pmsg; /* Place message in mailbox */ + OS_EXIT_CRITICAL(); + return (OS_ERR_NONE); +} +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* POST MESSAGE TO A MAILBOX +* +* Description: This function sends a message to a mailbox +* +* Arguments : pevent is a pointer to the event control block associated with the desired mailbox +* +* pmsg is a pointer to the message to send. You MUST NOT send a NULL pointer. +* +* opt determines the type of POST performed: +* OS_POST_OPT_NONE POST to a single waiting task +* (Identical to OSMboxPost()) +* OS_POST_OPT_BROADCAST POST to ALL tasks that are waiting on the mailbox +* +* OS_POST_OPT_NO_SCHED Indicates that the scheduler will NOT be invoked +* +* Returns : OS_ERR_NONE The call was successful and the message was sent +* OS_ERR_MBOX_FULL If the mailbox already contains a message. You can can only send one +* message at a time and thus, the message MUST be consumed before you +* are allowed to send another one. +* OS_ERR_EVENT_TYPE If you are attempting to post to a non mailbox. +* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer +* OS_ERR_POST_NULL_PTR If you are attempting to post a NULL pointer +* +* Note(s) : 1) HPT means Highest Priority Task +* +* Warning : Interrupts can be disabled for a long time if you do a 'broadcast'. In fact, the +* interrupt disable time is proportional to the number of tasks waiting on the mailbox. +********************************************************************************************************* +*/ + +#if OS_MBOX_POST_OPT_EN > 0u +INT8U OSMboxPostOpt (OS_EVENT *pevent, + void *pmsg, + INT8U opt) +{ +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#if OS_ARG_CHK_EN > 0u + if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */ + return (OS_ERR_PEVENT_NULL); + } + if (pmsg == (void *)0) { /* Make sure we are not posting a NULL pointer */ + return (OS_ERR_POST_NULL_PTR); + } +#endif + if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) { /* Validate event block type */ + return (OS_ERR_EVENT_TYPE); + } + OS_ENTER_CRITICAL(); + if (pevent->OSEventGrp != 0u) { /* See if any task pending on mailbox */ + if ((opt & OS_POST_OPT_BROADCAST) != 0x00u) { /* Do we need to post msg to ALL waiting tasks ? */ + while (pevent->OSEventGrp != 0u) { /* Yes, Post to ALL tasks waiting on mailbox */ + (void)OS_EventTaskRdy(pevent, pmsg, OS_STAT_MBOX, OS_STAT_PEND_OK); + } + } else { /* No, Post to HPT waiting on mbox */ + (void)OS_EventTaskRdy(pevent, pmsg, OS_STAT_MBOX, OS_STAT_PEND_OK); + } + OS_EXIT_CRITICAL(); + if ((opt & OS_POST_OPT_NO_SCHED) == 0u) { /* See if scheduler needs to be invoked */ + OS_Sched(); /* Find HPT ready to run */ + } + return (OS_ERR_NONE); + } + if (pevent->OSEventPtr != (void *)0) { /* Make sure mailbox doesn't already have a msg */ + OS_EXIT_CRITICAL(); + return (OS_ERR_MBOX_FULL); + } + pevent->OSEventPtr = pmsg; /* Place message in mailbox */ + OS_EXIT_CRITICAL(); + return (OS_ERR_NONE); +} +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* QUERY A MESSAGE MAILBOX +* +* Description: This function obtains information about a message mailbox. +* +* Arguments : pevent is a pointer to the event control block associated with the desired mailbox +* +* p_mbox_data is a pointer to a structure that will contain information about the message +* mailbox. +* +* Returns : OS_ERR_NONE The call was successful and the message was sent +* OS_ERR_EVENT_TYPE If you are attempting to obtain data from a non mailbox. +* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer +* OS_ERR_PDATA_NULL If 'p_mbox_data' is a NULL pointer +********************************************************************************************************* +*/ + +#if OS_MBOX_QUERY_EN > 0u +INT8U OSMboxQuery (OS_EVENT *pevent, + OS_MBOX_DATA *p_mbox_data) +{ + INT8U i; + OS_PRIO *psrc; + OS_PRIO *pdest; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#if OS_ARG_CHK_EN > 0u + if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */ + return (OS_ERR_PEVENT_NULL); + } + if (p_mbox_data == (OS_MBOX_DATA *)0) { /* Validate 'p_mbox_data' */ + return (OS_ERR_PDATA_NULL); + } +#endif + if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) { /* Validate event block type */ + return (OS_ERR_EVENT_TYPE); + } + OS_ENTER_CRITICAL(); + p_mbox_data->OSEventGrp = pevent->OSEventGrp; /* Copy message mailbox wait list */ + psrc = &pevent->OSEventTbl[0]; + pdest = &p_mbox_data->OSEventTbl[0]; + for (i = 0u; i < OS_EVENT_TBL_SIZE; i++) { + *pdest++ = *psrc++; + } + p_mbox_data->OSMsg = pevent->OSEventPtr; /* Get message from mailbox */ + OS_EXIT_CRITICAL(); + return (OS_ERR_NONE); +} +#endif /* OS_MBOX_QUERY_EN */ +#endif /* OS_MBOX_EN */ diff --git a/Middlewares/Third_Party/Micrium/uCOS-II/Source/os_mem.c b/Middlewares/Third_Party/Micrium/uCOS-II/Source/os_mem.c new file mode 100644 index 0000000..fea5a6d --- /dev/null +++ b/Middlewares/Third_Party/Micrium/uCOS-II/Source/os_mem.c @@ -0,0 +1,462 @@ +/* +********************************************************************************************************* +* uC/OS-II +* The Real-Time Kernel +* MEMORY MANAGEMENT +* +* (c) Copyright 1992-2013, Micrium, Weston, FL +* All Rights Reserved +* +* File : OS_MEM.C +* By : Jean J. Labrosse +* Version : V2.92.11 +* +* LICENSING TERMS: +* --------------- +* uC/OS-II is provided in source form for FREE evaluation, for educational use or for peaceful research. +* If you plan on using uC/OS-II in a commercial product you need to contact Micrium to properly license +* its use in your product. We provide ALL the source code for your convenience and to help you experience +* uC/OS-II. The fact that the source is provided does NOT mean that you can use it without paying a +* licensing fee. +********************************************************************************************************* +*/ + +#define MICRIUM_SOURCE + +#ifndef OS_MASTER_FILE +#include +#endif + +#if (OS_MEM_EN > 0u) && (OS_MAX_MEM_PART > 0u) +/* +********************************************************************************************************* +* CREATE A MEMORY PARTITION +* +* Description : Create a fixed-sized memory partition that will be managed by uC/OS-II. +* +* Arguments : addr is the starting address of the memory partition +* +* nblks is the number of memory blocks to create from the partition. +* +* blksize is the size (in bytes) of each block in the memory partition. +* +* perr is a pointer to a variable containing an error message which will be set by +* this function to either: +* +* OS_ERR_NONE if the memory partition has been created correctly. +* OS_ERR_MEM_INVALID_ADDR if you are specifying an invalid address for the memory +* storage of the partition or, the block does not align +* on a pointer boundary +* OS_ERR_MEM_INVALID_PART no free partitions available +* OS_ERR_MEM_INVALID_BLKS user specified an invalid number of blocks (must be >= 2) +* OS_ERR_MEM_INVALID_SIZE user specified an invalid block size +* - must be greater than the size of a pointer +* - must be able to hold an integral number of pointers +* Returns : != (OS_MEM *)0 is the partition was created +* == (OS_MEM *)0 if the partition was not created because of invalid arguments or, no +* free partition is available. +********************************************************************************************************* +*/ + +OS_MEM *OSMemCreate (void *addr, + INT32U nblks, + INT32U blksize, + INT8U *perr) +{ + OS_MEM *pmem; + INT8U *pblk; + void **plink; + INT32U loops; + INT32U i; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#ifdef OS_SAFETY_CRITICAL + if (perr == (INT8U *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return ((OS_MEM *)0); + } +#endif + +#ifdef OS_SAFETY_CRITICAL_IEC61508 + if (OSSafetyCriticalStartFlag == OS_TRUE) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return ((OS_MEM *)0); + } +#endif + +#if OS_ARG_CHK_EN > 0u + if (addr == (void *)0) { /* Must pass a valid address for the memory part.*/ + *perr = OS_ERR_MEM_INVALID_ADDR; + return ((OS_MEM *)0); + } + if (((INT32U)addr & (sizeof(void *) - 1u)) != 0u){ /* Must be pointer size aligned */ + *perr = OS_ERR_MEM_INVALID_ADDR; + return ((OS_MEM *)0); + } + if (nblks < 2u) { /* Must have at least 2 blocks per partition */ + *perr = OS_ERR_MEM_INVALID_BLKS; + return ((OS_MEM *)0); + } + if (blksize < sizeof(void *)) { /* Must contain space for at least a pointer */ + *perr = OS_ERR_MEM_INVALID_SIZE; + return ((OS_MEM *)0); + } +#endif + OS_ENTER_CRITICAL(); + pmem = OSMemFreeList; /* Get next free memory partition */ + if (OSMemFreeList != (OS_MEM *)0) { /* See if pool of free partitions was empty */ + OSMemFreeList = (OS_MEM *)OSMemFreeList->OSMemFreeList; + } + OS_EXIT_CRITICAL(); + if (pmem == (OS_MEM *)0) { /* See if we have a memory partition */ + *perr = OS_ERR_MEM_INVALID_PART; + return ((OS_MEM *)0); + } + plink = (void **)addr; /* Create linked list of free memory blocks */ + pblk = (INT8U *)addr; + loops = nblks - 1u; + for (i = 0u; i < loops; i++) { + pblk += blksize; /* Point to the FOLLOWING block */ + *plink = (void *)pblk; /* Save pointer to NEXT block in CURRENT block */ + plink = (void **)pblk; /* Position to NEXT block */ + } + *plink = (void *)0; /* Last memory block points to NULL */ + pmem->OSMemAddr = addr; /* Store start address of memory partition */ + pmem->OSMemFreeList = addr; /* Initialize pointer to pool of free blocks */ + pmem->OSMemNFree = nblks; /* Store number of free blocks in MCB */ + pmem->OSMemNBlks = nblks; + pmem->OSMemBlkSize = blksize; /* Store block size of each memory blocks */ + *perr = OS_ERR_NONE; + return (pmem); +} +/*$PAGE*/ +/* +********************************************************************************************************* +* GET A MEMORY BLOCK +* +* Description : Get a memory block from a partition +* +* Arguments : pmem is a pointer to the memory partition control block +* +* perr is a pointer to a variable containing an error message which will be set by this +* function to either: +* +* OS_ERR_NONE if the memory partition has been created correctly. +* OS_ERR_MEM_NO_FREE_BLKS if there are no more free memory blocks to allocate to caller +* OS_ERR_MEM_INVALID_PMEM if you passed a NULL pointer for 'pmem' +* +* Returns : A pointer to a memory block if no error is detected +* A pointer to NULL if an error is detected +********************************************************************************************************* +*/ + +void *OSMemGet (OS_MEM *pmem, + INT8U *perr) +{ + void *pblk; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#ifdef OS_SAFETY_CRITICAL + if (perr == (INT8U *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return ((void *)0); + } +#endif + +#if OS_ARG_CHK_EN > 0u + if (pmem == (OS_MEM *)0) { /* Must point to a valid memory partition */ + *perr = OS_ERR_MEM_INVALID_PMEM; + return ((void *)0); + } +#endif + OS_ENTER_CRITICAL(); + if (pmem->OSMemNFree > 0u) { /* See if there are any free memory blocks */ + pblk = pmem->OSMemFreeList; /* Yes, point to next free memory block */ + pmem->OSMemFreeList = *(void **)pblk; /* Adjust pointer to new free list */ + pmem->OSMemNFree--; /* One less memory block in this partition */ + OS_EXIT_CRITICAL(); + *perr = OS_ERR_NONE; /* No error */ + return (pblk); /* Return memory block to caller */ + } + OS_EXIT_CRITICAL(); + *perr = OS_ERR_MEM_NO_FREE_BLKS; /* No, Notify caller of empty memory partition */ + return ((void *)0); /* Return NULL pointer to caller */ +} +/*$PAGE*/ +/* +********************************************************************************************************* +* GET THE NAME OF A MEMORY PARTITION +* +* Description: This function is used to obtain the name assigned to a memory partition. +* +* Arguments : pmem is a pointer to the memory partition +* +* pname is a pointer to a pointer to an ASCII string that will receive the name of the memory partition. +* +* perr is a pointer to an error code that can contain one of the following values: +* +* OS_ERR_NONE if the name was copied to 'pname' +* OS_ERR_MEM_INVALID_PMEM if you passed a NULL pointer for 'pmem' +* OS_ERR_PNAME_NULL You passed a NULL pointer for 'pname' +* OS_ERR_NAME_GET_ISR You called this function from an ISR +* +* Returns : The length of the string or 0 if 'pmem' is a NULL pointer. +********************************************************************************************************* +*/ + +#if OS_MEM_NAME_EN > 0u +INT8U OSMemNameGet (OS_MEM *pmem, + INT8U **pname, + INT8U *perr) +{ + INT8U len; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#ifdef OS_SAFETY_CRITICAL + if (perr == (INT8U *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return (0u); + } +#endif + +#if OS_ARG_CHK_EN > 0u + if (pmem == (OS_MEM *)0) { /* Is 'pmem' a NULL pointer? */ + *perr = OS_ERR_MEM_INVALID_PMEM; + return (0u); + } + if (pname == (INT8U **)0) { /* Is 'pname' a NULL pointer? */ + *perr = OS_ERR_PNAME_NULL; + return (0u); + } +#endif + if (OSIntNesting > 0u) { /* See if trying to call from an ISR */ + *perr = OS_ERR_NAME_GET_ISR; + return (0u); + } + OS_ENTER_CRITICAL(); + *pname = pmem->OSMemName; + len = OS_StrLen(*pname); + OS_EXIT_CRITICAL(); + *perr = OS_ERR_NONE; + return (len); +} +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* ASSIGN A NAME TO A MEMORY PARTITION +* +* Description: This function assigns a name to a memory partition. +* +* Arguments : pmem is a pointer to the memory partition +* +* pname is a pointer to an ASCII string that contains the name of the memory partition. +* +* perr is a pointer to an error code that can contain one of the following values: +* +* OS_ERR_NONE if the name was copied to 'pname' +* OS_ERR_MEM_INVALID_PMEM if you passed a NULL pointer for 'pmem' +* OS_ERR_PNAME_NULL You passed a NULL pointer for 'pname' +* OS_ERR_MEM_NAME_TOO_LONG if the name doesn't fit in the storage area +* OS_ERR_NAME_SET_ISR if you called this function from an ISR +* +* Returns : None +********************************************************************************************************* +*/ + +#if OS_MEM_NAME_EN > 0u +void OSMemNameSet (OS_MEM *pmem, + INT8U *pname, + INT8U *perr) +{ +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#ifdef OS_SAFETY_CRITICAL + if (perr == (INT8U *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return; + } +#endif + +#if OS_ARG_CHK_EN > 0u + if (pmem == (OS_MEM *)0) { /* Is 'pmem' a NULL pointer? */ + *perr = OS_ERR_MEM_INVALID_PMEM; + return; + } + if (pname == (INT8U *)0) { /* Is 'pname' a NULL pointer? */ + *perr = OS_ERR_PNAME_NULL; + return; + } +#endif + if (OSIntNesting > 0u) { /* See if trying to call from an ISR */ + *perr = OS_ERR_NAME_SET_ISR; + return; + } + OS_ENTER_CRITICAL(); + pmem->OSMemName = pname; + OS_EXIT_CRITICAL(); + *perr = OS_ERR_NONE; +} +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* RELEASE A MEMORY BLOCK +* +* Description : Returns a memory block to a partition +* +* Arguments : pmem is a pointer to the memory partition control block +* +* pblk is a pointer to the memory block being released. +* +* Returns : OS_ERR_NONE if the memory block was inserted into the partition +* OS_ERR_MEM_FULL if you are returning a memory block to an already FULL memory +* partition (You freed more blocks than you allocated!) +* OS_ERR_MEM_INVALID_PMEM if you passed a NULL pointer for 'pmem' +* OS_ERR_MEM_INVALID_PBLK if you passed a NULL pointer for the block to release. +********************************************************************************************************* +*/ + +INT8U OSMemPut (OS_MEM *pmem, + void *pblk) +{ +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#if OS_ARG_CHK_EN > 0u + if (pmem == (OS_MEM *)0) { /* Must point to a valid memory partition */ + return (OS_ERR_MEM_INVALID_PMEM); + } + if (pblk == (void *)0) { /* Must release a valid block */ + return (OS_ERR_MEM_INVALID_PBLK); + } +#endif + OS_ENTER_CRITICAL(); + if (pmem->OSMemNFree >= pmem->OSMemNBlks) { /* Make sure all blocks not already returned */ + OS_EXIT_CRITICAL(); + return (OS_ERR_MEM_FULL); + } + *(void **)pblk = pmem->OSMemFreeList; /* Insert released block into free block list */ + pmem->OSMemFreeList = pblk; + pmem->OSMemNFree++; /* One more memory block in this partition */ + OS_EXIT_CRITICAL(); + return (OS_ERR_NONE); /* Notify caller that memory block was released */ +} +/*$PAGE*/ +/* +********************************************************************************************************* +* QUERY MEMORY PARTITION +* +* Description : This function is used to determine the number of free memory blocks and the number of +* used memory blocks from a memory partition. +* +* Arguments : pmem is a pointer to the memory partition control block +* +* p_mem_data is a pointer to a structure that will contain information about the memory +* partition. +* +* Returns : OS_ERR_NONE if no errors were found. +* OS_ERR_MEM_INVALID_PMEM if you passed a NULL pointer for 'pmem' +* OS_ERR_MEM_INVALID_PDATA if you passed a NULL pointer to the data recipient. +********************************************************************************************************* +*/ + +#if OS_MEM_QUERY_EN > 0u +INT8U OSMemQuery (OS_MEM *pmem, + OS_MEM_DATA *p_mem_data) +{ +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#if OS_ARG_CHK_EN > 0u + if (pmem == (OS_MEM *)0) { /* Must point to a valid memory partition */ + return (OS_ERR_MEM_INVALID_PMEM); + } + if (p_mem_data == (OS_MEM_DATA *)0) { /* Must release a valid storage area for the data */ + return (OS_ERR_MEM_INVALID_PDATA); + } +#endif + OS_ENTER_CRITICAL(); + p_mem_data->OSAddr = pmem->OSMemAddr; + p_mem_data->OSFreeList = pmem->OSMemFreeList; + p_mem_data->OSBlkSize = pmem->OSMemBlkSize; + p_mem_data->OSNBlks = pmem->OSMemNBlks; + p_mem_data->OSNFree = pmem->OSMemNFree; + OS_EXIT_CRITICAL(); + p_mem_data->OSNUsed = p_mem_data->OSNBlks - p_mem_data->OSNFree; + return (OS_ERR_NONE); +} +#endif /* OS_MEM_QUERY_EN */ +/*$PAGE*/ +/* +********************************************************************************************************* +* INITIALIZE MEMORY PARTITION MANAGER +* +* Description : This function is called by uC/OS-II to initialize the memory partition manager. Your +* application MUST NOT call this function. +* +* Arguments : none +* +* Returns : none +* +* Note(s) : This function is INTERNAL to uC/OS-II and your application should not call it. +********************************************************************************************************* +*/ + +void OS_MemInit (void) +{ +#if OS_MAX_MEM_PART == 1u + OS_MemClr((INT8U *)&OSMemTbl[0], sizeof(OSMemTbl)); /* Clear the memory partition table */ + OSMemFreeList = (OS_MEM *)&OSMemTbl[0]; /* Point to beginning of free list */ +#if OS_MEM_NAME_EN > 0u + OSMemFreeList->OSMemName = (INT8U *)"?"; /* Unknown name */ +#endif +#endif + +#if OS_MAX_MEM_PART >= 2u + OS_MEM *pmem; + INT16U i; + + + OS_MemClr((INT8U *)&OSMemTbl[0], sizeof(OSMemTbl)); /* Clear the memory partition table */ + for (i = 0u; i < (OS_MAX_MEM_PART - 1u); i++) { /* Init. list of free memory partitions */ + pmem = &OSMemTbl[i]; /* Point to memory control block (MCB) */ + pmem->OSMemFreeList = (void *)&OSMemTbl[i + 1u]; /* Chain list of free partitions */ +#if OS_MEM_NAME_EN > 0u + pmem->OSMemName = (INT8U *)(void *)"?"; +#endif + } + pmem = &OSMemTbl[i]; + pmem->OSMemFreeList = (void *)0; /* Initialize last node */ +#if OS_MEM_NAME_EN > 0u + pmem->OSMemName = (INT8U *)(void *)"?"; +#endif + + OSMemFreeList = &OSMemTbl[0]; /* Point to beginning of free list */ +#endif +} +#endif /* OS_MEM_EN */ diff --git a/Middlewares/Third_Party/Micrium/uCOS-II/Source/os_mutex.c b/Middlewares/Third_Party/Micrium/uCOS-II/Source/os_mutex.c new file mode 100644 index 0000000..b75ae18 --- /dev/null +++ b/Middlewares/Third_Party/Micrium/uCOS-II/Source/os_mutex.c @@ -0,0 +1,763 @@ +/* +********************************************************************************************************* +* uC/OS-II +* The Real-Time Kernel +* MUTUAL EXCLUSION SEMAPHORE MANAGEMENT +* +* (c) Copyright 1992-2013, Micrium, Weston, FL +* All Rights Reserved +* +* File : OS_MUTEX.C +* By : Jean J. Labrosse +* Version : V2.92.11 +* +* LICENSING TERMS: +* --------------- +* uC/OS-II is provided in source form for FREE evaluation, for educational use or for peaceful research. +* If you plan on using uC/OS-II in a commercial product you need to contact Micrium to properly license +* its use in your product. We provide ALL the source code for your convenience and to help you experience +* uC/OS-II. The fact that the source is provided does NOT mean that you can use it without paying a +* licensing fee. +********************************************************************************************************* +*/ + +#define MICRIUM_SOURCE + +#ifndef OS_MASTER_FILE +#include +#endif + + +#if OS_MUTEX_EN > 0u +/* +********************************************************************************************************* +* LOCAL CONSTANTS +********************************************************************************************************* +*/ + +#define OS_MUTEX_KEEP_LOWER_8 ((INT16U)0x00FFu) +#define OS_MUTEX_KEEP_UPPER_8 ((INT16U)0xFF00u) + +#define OS_MUTEX_AVAILABLE ((INT16U)0x00FFu) + +/* +********************************************************************************************************* +* LOCAL CONSTANTS +********************************************************************************************************* +*/ + +static void OSMutex_RdyAtPrio(OS_TCB *ptcb, INT8U prio); + +/*$PAGE*/ +/* +********************************************************************************************************* +* ACCEPT MUTUAL EXCLUSION SEMAPHORE +* +* Description: This function checks the mutual exclusion semaphore to see if a resource is available. +* Unlike OSMutexPend(), OSMutexAccept() does not suspend the calling task if the resource is +* not available or the event did not occur. +* +* Arguments : pevent is a pointer to the event control block +* +* perr is a pointer to an error code which will be returned to your application: +* OS_ERR_NONE if the call was successful. +* OS_ERR_EVENT_TYPE if 'pevent' is not a pointer to a mutex +* OS_ERR_PEVENT_NULL 'pevent' is a NULL pointer +* OS_ERR_PEND_ISR if you called this function from an ISR +* OS_ERR_PCP_LOWER If the priority of the task that owns the Mutex is +* HIGHER (i.e. a lower number) than the PCP. This error +* indicates that you did not set the PCP higher (lower +* number) than ALL the tasks that compete for the Mutex. +* Unfortunately, this is something that could not be +* detected when the Mutex is created because we don't know +* what tasks will be using the Mutex. +* +* Returns : == OS_TRUE if the resource is available, the mutual exclusion semaphore is acquired +* == OS_FALSE a) if the resource is not available +* b) you didn't pass a pointer to a mutual exclusion semaphore +* c) you called this function from an ISR +* +* Warning(s) : This function CANNOT be called from an ISR because mutual exclusion semaphores are +* intended to be used by tasks only. +********************************************************************************************************* +*/ + +#if OS_MUTEX_ACCEPT_EN > 0u +BOOLEAN OSMutexAccept (OS_EVENT *pevent, + INT8U *perr) +{ + INT8U pcp; /* Priority Ceiling Priority (PCP) */ +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#ifdef OS_SAFETY_CRITICAL + if (perr == (INT8U *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return (OS_FALSE); + } +#endif + +#if OS_ARG_CHK_EN > 0u + if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */ + *perr = OS_ERR_PEVENT_NULL; + return (OS_FALSE); + } +#endif + if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { /* Validate event block type */ + *perr = OS_ERR_EVENT_TYPE; + return (OS_FALSE); + } + if (OSIntNesting > 0u) { /* Make sure it's not called from an ISR */ + *perr = OS_ERR_PEND_ISR; + return (OS_FALSE); + } + OS_ENTER_CRITICAL(); /* Get value (0 or 1) of Mutex */ + pcp = (INT8U)(pevent->OSEventCnt >> 8u); /* Get PCP from mutex */ + if ((pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8) == OS_MUTEX_AVAILABLE) { + pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8; /* Mask off LSByte (Acquire Mutex) */ + pevent->OSEventCnt |= OSTCBCur->OSTCBPrio; /* Save current task priority in LSByte */ + pevent->OSEventPtr = (void *)OSTCBCur; /* Link TCB of task owning Mutex */ + if ((pcp != OS_PRIO_MUTEX_CEIL_DIS) && + (OSTCBCur->OSTCBPrio <= pcp)) { /* PCP 'must' have a SMALLER prio ... */ + OS_EXIT_CRITICAL(); /* ... than current task! */ + *perr = OS_ERR_PCP_LOWER; + } else { + OS_EXIT_CRITICAL(); + *perr = OS_ERR_NONE; + } + return (OS_TRUE); + } + OS_EXIT_CRITICAL(); + *perr = OS_ERR_NONE; + return (OS_FALSE); +} +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* CREATE A MUTUAL EXCLUSION SEMAPHORE +* +* Description: This function creates a mutual exclusion semaphore. +* +* Arguments : prio is the priority to use when accessing the mutual exclusion semaphore. In +* other words, when the semaphore is acquired and a higher priority task +* attempts to obtain the semaphore then the priority of the task owning the +* semaphore is raised to this priority. It is assumed that you will specify +* a priority that is LOWER in value than ANY of the tasks competing for the +* mutex. If the priority is specified as OS_PRIO_MUTEX_CEIL_DIS, then the +* priority ceiling promotion is disabled. This way, the tasks accessing the +* semaphore do not have their priority promoted. +* +* perr is a pointer to an error code which will be returned to your application: +* OS_ERR_NONE if the call was successful. +* OS_ERR_CREATE_ISR if you attempted to create a MUTEX from an ISR +* OS_ERR_PRIO_EXIST if a task at the priority ceiling priority +* already exist. +* OS_ERR_PEVENT_NULL No more event control blocks available. +* OS_ERR_PRIO_INVALID if the priority you specify is higher that the +* maximum allowed (i.e. > OS_LOWEST_PRIO) +* +* Returns : != (void *)0 is a pointer to the event control clock (OS_EVENT) associated with the +* created mutex. +* == (void *)0 if an error is detected. +* +* Note(s) : 1) The LEAST significant 8 bits of '.OSEventCnt' hold the priority number of the task +* owning the mutex or 0xFF if no task owns the mutex. +* +* 2) The MOST significant 8 bits of '.OSEventCnt' hold the priority number used to +* reduce priority inversion or 0xFF (OS_PRIO_MUTEX_CEIL_DIS) if priority ceiling +* promotion is disabled. +********************************************************************************************************* +*/ + +OS_EVENT *OSMutexCreate (INT8U prio, + INT8U *perr) +{ + OS_EVENT *pevent; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#ifdef OS_SAFETY_CRITICAL + if (perr == (INT8U *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return ((OS_EVENT *)0); + } +#endif + +#ifdef OS_SAFETY_CRITICAL_IEC61508 + if (OSSafetyCriticalStartFlag == OS_TRUE) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return ((OS_EVENT *)0); + } +#endif + +#if OS_ARG_CHK_EN > 0u + if (prio != OS_PRIO_MUTEX_CEIL_DIS) { + if (prio >= OS_LOWEST_PRIO) { /* Validate PCP */ + *perr = OS_ERR_PRIO_INVALID; + return ((OS_EVENT *)0); + } + } +#endif + if (OSIntNesting > 0u) { /* See if called from ISR ... */ + *perr = OS_ERR_CREATE_ISR; /* ... can't CREATE mutex from an ISR */ + return ((OS_EVENT *)0); + } + OS_ENTER_CRITICAL(); + if (prio != OS_PRIO_MUTEX_CEIL_DIS) { + if (OSTCBPrioTbl[prio] != (OS_TCB *)0) { /* Mutex priority must not already exist */ + OS_EXIT_CRITICAL(); /* Task already exist at priority ... */ + *perr = OS_ERR_PRIO_EXIST; /* ... ceiling priority */ + return ((OS_EVENT *)0); + } + OSTCBPrioTbl[prio] = OS_TCB_RESERVED; /* Reserve the table entry */ + } + + pevent = OSEventFreeList; /* Get next free event control block */ + if (pevent == (OS_EVENT *)0) { /* See if an ECB was available */ + if (prio != OS_PRIO_MUTEX_CEIL_DIS) { + OSTCBPrioTbl[prio] = (OS_TCB *)0; /* No, Release the table entry */ + } + OS_EXIT_CRITICAL(); + *perr = OS_ERR_PEVENT_NULL; /* No more event control blocks */ + return (pevent); + } + OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr; /* Adjust the free list */ + OS_EXIT_CRITICAL(); + pevent->OSEventType = OS_EVENT_TYPE_MUTEX; + pevent->OSEventCnt = (INT16U)((INT16U)prio << 8u) | OS_MUTEX_AVAILABLE; /* Resource is avail. */ + pevent->OSEventPtr = (void *)0; /* No task owning the mutex */ +#if OS_EVENT_NAME_EN > 0u + pevent->OSEventName = (INT8U *)(void *)"?"; +#endif + OS_EventWaitListInit(pevent); + *perr = OS_ERR_NONE; + return (pevent); +} + +/*$PAGE*/ +/* +********************************************************************************************************* +* DELETE A MUTEX +* +* Description: This function deletes a mutual exclusion semaphore and readies all tasks pending on the it. +* +* Arguments : pevent is a pointer to the event control block associated with the desired mutex. +* +* opt determines delete options as follows: +* opt == OS_DEL_NO_PEND Delete mutex ONLY if no task pending +* opt == OS_DEL_ALWAYS Deletes the mutex even if tasks are waiting. +* In this case, all the tasks pending will be readied. +* +* perr is a pointer to an error code that can contain one of the following values: +* OS_ERR_NONE The call was successful and the mutex was deleted +* OS_ERR_DEL_ISR If you attempted to delete the MUTEX from an ISR +* OS_ERR_INVALID_OPT An invalid option was specified +* OS_ERR_TASK_WAITING One or more tasks were waiting on the mutex +* OS_ERR_EVENT_TYPE If you didn't pass a pointer to a mutex +* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer. +* +* Returns : pevent upon error +* (OS_EVENT *)0 if the mutex was successfully deleted. +* +* Note(s) : 1) This function must be used with care. Tasks that would normally expect the presence of +* the mutex MUST check the return code of OSMutexPend(). +* +* 2) This call can potentially disable interrupts for a long time. The interrupt disable +* time is directly proportional to the number of tasks waiting on the mutex. +* +* 3) Because ALL tasks pending on the mutex will be readied, you MUST be careful because the +* resource(s) will no longer be guarded by the mutex. +* +* 4) IMPORTANT: In the 'OS_DEL_ALWAYS' case, we assume that the owner of the Mutex (if there +* is one) is ready-to-run and is thus NOT pending on another kernel object or +* has delayed itself. In other words, if a task owns the mutex being deleted, +* that task will be made ready-to-run at its original priority. +********************************************************************************************************* +*/ + +#if OS_MUTEX_DEL_EN > 0u +OS_EVENT *OSMutexDel (OS_EVENT *pevent, + INT8U opt, + INT8U *perr) +{ + BOOLEAN tasks_waiting; + OS_EVENT *pevent_return; + INT8U pcp; /* Priority ceiling priority */ + INT8U prio; + OS_TCB *ptcb; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#ifdef OS_SAFETY_CRITICAL + if (perr == (INT8U *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return ((OS_EVENT *)0); + } +#endif + +#if OS_ARG_CHK_EN > 0u + if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */ + *perr = OS_ERR_PEVENT_NULL; + return (pevent); + } +#endif + if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { /* Validate event block type */ + *perr = OS_ERR_EVENT_TYPE; + return (pevent); + } + if (OSIntNesting > 0u) { /* See if called from ISR ... */ + *perr = OS_ERR_DEL_ISR; /* ... can't DELETE from an ISR */ + return (pevent); + } + OS_ENTER_CRITICAL(); + if (pevent->OSEventGrp != 0u) { /* See if any tasks waiting on mutex */ + tasks_waiting = OS_TRUE; /* Yes */ + } else { + tasks_waiting = OS_FALSE; /* No */ + } + switch (opt) { + case OS_DEL_NO_PEND: /* DELETE MUTEX ONLY IF NO TASK WAITING --- */ + if (tasks_waiting == OS_FALSE) { +#if OS_EVENT_NAME_EN > 0u + pevent->OSEventName = (INT8U *)(void *)"?"; +#endif + pcp = (INT8U)(pevent->OSEventCnt >> 8u); + if (pcp != OS_PRIO_MUTEX_CEIL_DIS) { + OSTCBPrioTbl[pcp] = (OS_TCB *)0; /* Free up the PCP */ + } + pevent->OSEventType = OS_EVENT_TYPE_UNUSED; + pevent->OSEventPtr = OSEventFreeList; /* Return Event Control Block to free list */ + pevent->OSEventCnt = 0u; + OSEventFreeList = pevent; + OS_EXIT_CRITICAL(); + *perr = OS_ERR_NONE; + pevent_return = (OS_EVENT *)0; /* Mutex has been deleted */ + } else { + OS_EXIT_CRITICAL(); + *perr = OS_ERR_TASK_WAITING; + pevent_return = pevent; + } + break; + + case OS_DEL_ALWAYS: /* ALWAYS DELETE THE MUTEX ---------------- */ + pcp = (INT8U)(pevent->OSEventCnt >> 8u); /* Get PCP of mutex */ + if (pcp != OS_PRIO_MUTEX_CEIL_DIS) { + prio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8); /* Get owner's orig prio */ + ptcb = (OS_TCB *)pevent->OSEventPtr; + if (ptcb != (OS_TCB *)0) { /* See if any task owns the mutex */ + if (ptcb->OSTCBPrio == pcp) { /* See if original prio was changed */ + OSMutex_RdyAtPrio(ptcb, prio); /* Yes, Restore the task's original prio */ + } + } + } + while (pevent->OSEventGrp != 0u) { /* Ready ALL tasks waiting for mutex */ + (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_MUTEX, OS_STAT_PEND_ABORT); + } +#if OS_EVENT_NAME_EN > 0u + pevent->OSEventName = (INT8U *)(void *)"?"; +#endif + pcp = (INT8U)(pevent->OSEventCnt >> 8u); + if (pcp != OS_PRIO_MUTEX_CEIL_DIS) { + OSTCBPrioTbl[pcp] = (OS_TCB *)0; /* Free up the PCP */ + } + pevent->OSEventType = OS_EVENT_TYPE_UNUSED; + pevent->OSEventPtr = OSEventFreeList; /* Return Event Control Block to free list */ + pevent->OSEventCnt = 0u; + OSEventFreeList = pevent; /* Get next free event control block */ + OS_EXIT_CRITICAL(); + if (tasks_waiting == OS_TRUE) { /* Reschedule only if task(s) were waiting */ + OS_Sched(); /* Find highest priority task ready to run */ + } + *perr = OS_ERR_NONE; + pevent_return = (OS_EVENT *)0; /* Mutex has been deleted */ + break; + + default: + OS_EXIT_CRITICAL(); + *perr = OS_ERR_INVALID_OPT; + pevent_return = pevent; + break; + } + return (pevent_return); +} +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* PEND ON MUTUAL EXCLUSION SEMAPHORE +* +* Description: This function waits for a mutual exclusion semaphore. +* +* Arguments : pevent is a pointer to the event control block associated with the desired +* mutex. +* +* timeout is an optional timeout period (in clock ticks). If non-zero, your task will +* wait for the resource up to the amount of time specified by this argument. +* If you specify 0, however, your task will wait forever at the specified +* mutex or, until the resource becomes available. +* +* perr is a pointer to where an error message will be deposited. Possible error +* messages are: +* OS_ERR_NONE The call was successful and your task owns the mutex +* OS_ERR_TIMEOUT The mutex was not available within the specified 'timeout'. +* OS_ERR_PEND_ABORT The wait on the mutex was aborted. +* OS_ERR_EVENT_TYPE If you didn't pass a pointer to a mutex +* OS_ERR_PEVENT_NULL 'pevent' is a NULL pointer +* OS_ERR_PEND_ISR If you called this function from an ISR and the result +* would lead to a suspension. +* OS_ERR_PCP_LOWER If the priority of the task that owns the Mutex is +* HIGHER (i.e. a lower number) than the PCP. This error +* indicates that you did not set the PCP higher (lower +* number) than ALL the tasks that compete for the Mutex. +* Unfortunately, this is something that could not be +* detected when the Mutex is created because we don't know +* what tasks will be using the Mutex. +* OS_ERR_PEND_LOCKED If you called this function when the scheduler is locked +* +* Returns : none +* +* Note(s) : 1) The task that owns the Mutex MUST NOT pend on any other event while it owns the mutex. +* +* 2) You MUST NOT change the priority of the task that owns the mutex +********************************************************************************************************* +*/ + +void OSMutexPend (OS_EVENT *pevent, + INT32U timeout, + INT8U *perr) +{ + INT8U pcp; /* Priority Ceiling Priority (PCP) */ + INT8U mprio; /* Mutex owner priority */ + BOOLEAN rdy; /* Flag indicating task was ready */ + OS_TCB *ptcb; + OS_EVENT *pevent2; + INT8U y; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#ifdef OS_SAFETY_CRITICAL + if (perr == (INT8U *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return; + } +#endif + +#if OS_ARG_CHK_EN > 0u + if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */ + *perr = OS_ERR_PEVENT_NULL; + return; + } +#endif + if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { /* Validate event block type */ + *perr = OS_ERR_EVENT_TYPE; + return; + } + if (OSIntNesting > 0u) { /* See if called from ISR ... */ + *perr = OS_ERR_PEND_ISR; /* ... can't PEND from an ISR */ + return; + } + if (OSLockNesting > 0u) { /* See if called with scheduler locked ... */ + *perr = OS_ERR_PEND_LOCKED; /* ... can't PEND when locked */ + return; + } +/*$PAGE*/ + OS_ENTER_CRITICAL(); + pcp = (INT8U)(pevent->OSEventCnt >> 8u); /* Get PCP from mutex */ + /* Is Mutex available? */ + if ((INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8) == OS_MUTEX_AVAILABLE) { + pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8; /* Yes, Acquire the resource */ + pevent->OSEventCnt |= OSTCBCur->OSTCBPrio; /* Save priority of owning task */ + pevent->OSEventPtr = (void *)OSTCBCur; /* Point to owning task's OS_TCB */ + if ((pcp != OS_PRIO_MUTEX_CEIL_DIS) && + (OSTCBCur->OSTCBPrio <= pcp)) { /* PCP 'must' have a SMALLER prio ... */ + OS_EXIT_CRITICAL(); /* ... than current task! */ + *perr = OS_ERR_PCP_LOWER; + } else { + OS_EXIT_CRITICAL(); + *perr = OS_ERR_NONE; + } + return; + } + if (pcp != OS_PRIO_MUTEX_CEIL_DIS) { + mprio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8); /* Get priority of mutex owner */ + ptcb = (OS_TCB *)(pevent->OSEventPtr); /* Point to TCB of mutex owner */ + if (ptcb->OSTCBPrio > pcp) { /* Need to promote prio of owner?*/ + if (mprio > OSTCBCur->OSTCBPrio) { + y = ptcb->OSTCBY; + if ((OSRdyTbl[y] & ptcb->OSTCBBitX) != 0u) { /* See if mutex owner is ready */ + OSRdyTbl[y] &= (OS_PRIO)~ptcb->OSTCBBitX; /* Yes, Remove owner from Rdy ...*/ + if (OSRdyTbl[y] == 0u) { /* ... list at current prio */ + OSRdyGrp &= (OS_PRIO)~ptcb->OSTCBBitY; + } + rdy = OS_TRUE; + } else { + pevent2 = ptcb->OSTCBEventPtr; + if (pevent2 != (OS_EVENT *)0) { /* Remove from event wait list */ + y = ptcb->OSTCBY; + pevent2->OSEventTbl[y] &= (OS_PRIO)~ptcb->OSTCBBitX; + if (pevent2->OSEventTbl[y] == 0u) { + pevent2->OSEventGrp &= (OS_PRIO)~ptcb->OSTCBBitY; + } + } + rdy = OS_FALSE; /* No */ + } + ptcb->OSTCBPrio = pcp; /* Change owner task prio to PCP */ +#if OS_LOWEST_PRIO <= 63u + ptcb->OSTCBY = (INT8U)( ptcb->OSTCBPrio >> 3u); + ptcb->OSTCBX = (INT8U)( ptcb->OSTCBPrio & 0x07u); +#else + ptcb->OSTCBY = (INT8U)((INT8U)(ptcb->OSTCBPrio >> 4u) & 0xFFu); + ptcb->OSTCBX = (INT8U)( ptcb->OSTCBPrio & 0x0Fu); +#endif + ptcb->OSTCBBitY = (OS_PRIO)(1uL << ptcb->OSTCBY); + ptcb->OSTCBBitX = (OS_PRIO)(1uL << ptcb->OSTCBX); + + if (rdy == OS_TRUE) { /* If task was ready at owner's priority ...*/ + OSRdyGrp |= ptcb->OSTCBBitY; /* ... make it ready at new priority. */ + OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX; + } else { + pevent2 = ptcb->OSTCBEventPtr; + if (pevent2 != (OS_EVENT *)0) { /* Add to event wait list */ + pevent2->OSEventGrp |= ptcb->OSTCBBitY; + pevent2->OSEventTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX; + } + } + OSTCBPrioTbl[pcp] = ptcb; + } + } + } + OSTCBCur->OSTCBStat |= OS_STAT_MUTEX; /* Mutex not available, pend current task */ + OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK; + OSTCBCur->OSTCBDly = timeout; /* Store timeout in current task's TCB */ + OS_EventTaskWait(pevent); /* Suspend task until event or timeout occurs */ + OS_EXIT_CRITICAL(); + OS_Sched(); /* Find next highest priority task ready */ + OS_ENTER_CRITICAL(); + switch (OSTCBCur->OSTCBStatPend) { /* See if we timed-out or aborted */ + case OS_STAT_PEND_OK: + *perr = OS_ERR_NONE; + break; + + case OS_STAT_PEND_ABORT: + *perr = OS_ERR_PEND_ABORT; /* Indicate that we aborted getting mutex */ + break; + + case OS_STAT_PEND_TO: + default: + OS_EventTaskRemove(OSTCBCur, pevent); + *perr = OS_ERR_TIMEOUT; /* Indicate that we didn't get mutex within TO */ + break; + } + OSTCBCur->OSTCBStat = OS_STAT_RDY; /* Set task status to ready */ + OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK; /* Clear pend status */ + OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; /* Clear event pointers */ +#if (OS_EVENT_MULTI_EN > 0u) + OSTCBCur->OSTCBEventMultiPtr = (OS_EVENT **)0; +#endif + OS_EXIT_CRITICAL(); +} +/*$PAGE*/ +/* +********************************************************************************************************* +* POST TO A MUTUAL EXCLUSION SEMAPHORE +* +* Description: This function signals a mutual exclusion semaphore +* +* Arguments : pevent is a pointer to the event control block associated with the desired +* mutex. +* +* Returns : OS_ERR_NONE The call was successful and the mutex was signaled. +* OS_ERR_EVENT_TYPE If you didn't pass a pointer to a mutex +* OS_ERR_PEVENT_NULL 'pevent' is a NULL pointer +* OS_ERR_POST_ISR Attempted to post from an ISR (not valid for MUTEXes) +* OS_ERR_NOT_MUTEX_OWNER The task that did the post is NOT the owner of the MUTEX. +* OS_ERR_PCP_LOWER If the priority of the new task that owns the Mutex is +* HIGHER (i.e. a lower number) than the PCP. This error +* indicates that you did not set the PCP higher (lower +* number) than ALL the tasks that compete for the Mutex. +* Unfortunately, this is something that could not be +* detected when the Mutex is created because we don't know +* what tasks will be using the Mutex. +********************************************************************************************************* +*/ + +INT8U OSMutexPost (OS_EVENT *pevent) +{ + INT8U pcp; /* Priority ceiling priority */ + INT8U prio; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + + if (OSIntNesting > 0u) { /* See if called from ISR ... */ + return (OS_ERR_POST_ISR); /* ... can't POST mutex from an ISR */ + } +#if OS_ARG_CHK_EN > 0u + if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */ + return (OS_ERR_PEVENT_NULL); + } +#endif + if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { /* Validate event block type */ + return (OS_ERR_EVENT_TYPE); + } + OS_ENTER_CRITICAL(); + pcp = (INT8U)(pevent->OSEventCnt >> 8u); /* Get priority ceiling priority of mutex */ + prio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8); /* Get owner's original priority */ + if (OSTCBCur != (OS_TCB *)pevent->OSEventPtr) { /* See if posting task owns the MUTEX */ + OS_EXIT_CRITICAL(); + return (OS_ERR_NOT_MUTEX_OWNER); + } + if (pcp != OS_PRIO_MUTEX_CEIL_DIS) { + if (OSTCBCur->OSTCBPrio == pcp) { /* Did we have to raise current task's priority? */ + OSMutex_RdyAtPrio(OSTCBCur, prio); /* Restore the task's original priority */ + } + OSTCBPrioTbl[pcp] = OS_TCB_RESERVED; /* Reserve table entry */ + } + if (pevent->OSEventGrp != 0u) { /* Any task waiting for the mutex? */ + /* Yes, Make HPT waiting for mutex ready */ + prio = OS_EventTaskRdy(pevent, (void *)0, OS_STAT_MUTEX, OS_STAT_PEND_OK); + pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8; /* Save priority of mutex's new owner */ + pevent->OSEventCnt |= prio; + pevent->OSEventPtr = OSTCBPrioTbl[prio]; /* Link to new mutex owner's OS_TCB */ + if ((pcp != OS_PRIO_MUTEX_CEIL_DIS) && + (prio <= pcp)) { /* PCP 'must' have a SMALLER prio ... */ + OS_EXIT_CRITICAL(); /* ... than current task! */ + OS_Sched(); /* Find highest priority task ready to run */ + return (OS_ERR_PCP_LOWER); + } else { + OS_EXIT_CRITICAL(); + OS_Sched(); /* Find highest priority task ready to run */ + return (OS_ERR_NONE); + } + } + pevent->OSEventCnt |= OS_MUTEX_AVAILABLE; /* No, Mutex is now available */ + pevent->OSEventPtr = (void *)0; + OS_EXIT_CRITICAL(); + return (OS_ERR_NONE); +} +/*$PAGE*/ +/* +********************************************************************************************************* +* QUERY A MUTUAL EXCLUSION SEMAPHORE +* +* Description: This function obtains information about a mutex +* +* Arguments : pevent is a pointer to the event control block associated with the desired mutex +* +* p_mutex_data is a pointer to a structure that will contain information about the mutex +* +* Returns : OS_ERR_NONE The call was successful and the message was sent +* OS_ERR_QUERY_ISR If you called this function from an ISR +* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer +* OS_ERR_PDATA_NULL If 'p_mutex_data' is a NULL pointer +* OS_ERR_EVENT_TYPE If you are attempting to obtain data from a non mutex. +********************************************************************************************************* +*/ + +#if OS_MUTEX_QUERY_EN > 0u +INT8U OSMutexQuery (OS_EVENT *pevent, + OS_MUTEX_DATA *p_mutex_data) +{ + INT8U i; + OS_PRIO *psrc; + OS_PRIO *pdest; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + + if (OSIntNesting > 0u) { /* See if called from ISR ... */ + return (OS_ERR_QUERY_ISR); /* ... can't QUERY mutex from an ISR */ + } +#if OS_ARG_CHK_EN > 0u + if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */ + return (OS_ERR_PEVENT_NULL); + } + if (p_mutex_data == (OS_MUTEX_DATA *)0) { /* Validate 'p_mutex_data' */ + return (OS_ERR_PDATA_NULL); + } +#endif + if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { /* Validate event block type */ + return (OS_ERR_EVENT_TYPE); + } + OS_ENTER_CRITICAL(); + p_mutex_data->OSMutexPCP = (INT8U)(pevent->OSEventCnt >> 8u); + p_mutex_data->OSOwnerPrio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8); + if (p_mutex_data->OSOwnerPrio == 0xFFu) { + p_mutex_data->OSValue = OS_TRUE; + } else { + p_mutex_data->OSValue = OS_FALSE; + } + p_mutex_data->OSEventGrp = pevent->OSEventGrp; /* Copy wait list */ + psrc = &pevent->OSEventTbl[0]; + pdest = &p_mutex_data->OSEventTbl[0]; + for (i = 0u; i < OS_EVENT_TBL_SIZE; i++) { + *pdest++ = *psrc++; + } + OS_EXIT_CRITICAL(); + return (OS_ERR_NONE); +} +#endif /* OS_MUTEX_QUERY_EN */ + +/*$PAGE*/ +/* +********************************************************************************************************* +* RESTORE A TASK BACK TO ITS ORIGINAL PRIORITY +* +* Description: This function makes a task ready at the specified priority +* +* Arguments : ptcb is a pointer to OS_TCB of the task to make ready +* +* prio is the desired priority +* +* Returns : none +********************************************************************************************************* +*/ + +static void OSMutex_RdyAtPrio (OS_TCB *ptcb, + INT8U prio) +{ + INT8U y; + + + y = ptcb->OSTCBY; /* Remove owner from ready list at 'pcp' */ + OSRdyTbl[y] &= (OS_PRIO)~ptcb->OSTCBBitX; + if (OSRdyTbl[y] == 0u) { + OSRdyGrp &= (OS_PRIO)~ptcb->OSTCBBitY; + } + ptcb->OSTCBPrio = prio; + OSPrioCur = prio; /* The current task is now at this priority */ +#if OS_LOWEST_PRIO <= 63u + ptcb->OSTCBY = (INT8U)((INT8U)(prio >> 3u) & 0x07u); + ptcb->OSTCBX = (INT8U)(prio & 0x07u); +#else + ptcb->OSTCBY = (INT8U)((INT8U)(prio >> 4u) & 0x0Fu); + ptcb->OSTCBX = (INT8U) (prio & 0x0Fu); +#endif + ptcb->OSTCBBitY = (OS_PRIO)(1uL << ptcb->OSTCBY); + ptcb->OSTCBBitX = (OS_PRIO)(1uL << ptcb->OSTCBX); + OSRdyGrp |= ptcb->OSTCBBitY; /* Make task ready at original priority */ + OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX; + OSTCBPrioTbl[prio] = ptcb; +} + + +#endif /* OS_MUTEX_EN */ diff --git a/Middlewares/Third_Party/Micrium/uCOS-II/Source/os_q.c b/Middlewares/Third_Party/Micrium/uCOS-II/Source/os_q.c new file mode 100644 index 0000000..29dba06 --- /dev/null +++ b/Middlewares/Third_Party/Micrium/uCOS-II/Source/os_q.c @@ -0,0 +1,901 @@ +/* +********************************************************************************************************* +* uC/OS-II +* The Real-Time Kernel +* MESSAGE QUEUE MANAGEMENT +* +* (c) Copyright 1992-2013, Micrium, Weston, FL +* All Rights Reserved +* +* File : OS_Q.C +* By : Jean J. Labrosse +* Version : V2.92.11 +* +* LICENSING TERMS: +* --------------- +* uC/OS-II is provided in source form for FREE evaluation, for educational use or for peaceful research. +* If you plan on using uC/OS-II in a commercial product you need to contact Micrium to properly license +* its use in your product. We provide ALL the source code for your convenience and to help you experience +* uC/OS-II. The fact that the source is provided does NOT mean that you can use it without paying a +* licensing fee. +********************************************************************************************************* +*/ + +#define MICRIUM_SOURCE + +#ifndef OS_MASTER_FILE +#include +#endif + +#if (OS_Q_EN > 0u) && (OS_MAX_QS > 0u) +/* +********************************************************************************************************* +* ACCEPT MESSAGE FROM QUEUE +* +* Description: This function checks the queue to see if a message is available. Unlike OSQPend(), +* OSQAccept() does not suspend the calling task if a message is not available. +* +* Arguments : pevent is a pointer to the event control block +* +* perr is a pointer to where an error message will be deposited. Possible error +* messages are: +* +* OS_ERR_NONE The call was successful and your task received a +* message. +* OS_ERR_EVENT_TYPE You didn't pass a pointer to a queue +* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer +* OS_ERR_Q_EMPTY The queue did not contain any messages +* +* Returns : != (void *)0 is the message in the queue if one is available. The message is removed +* from the so the next time OSQAccept() is called, the queue will contain +* one less entry. +* == (void *)0 if you received a NULL pointer message +* if the queue is empty or, +* if 'pevent' is a NULL pointer or, +* if you passed an invalid event type +* +* Note(s) : As of V2.60, you can now pass NULL pointers through queues. Because of this, the argument +* 'perr' has been added to the API to tell you about the outcome of the call. +********************************************************************************************************* +*/ + +#if OS_Q_ACCEPT_EN > 0u +void *OSQAccept (OS_EVENT *pevent, + INT8U *perr) +{ + void *pmsg; + OS_Q *pq; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#ifdef OS_SAFETY_CRITICAL + if (perr == (INT8U *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return ((void *)0); + } +#endif + +#if OS_ARG_CHK_EN > 0u + if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */ + *perr = OS_ERR_PEVENT_NULL; + return ((void *)0); + } +#endif + if (pevent->OSEventType != OS_EVENT_TYPE_Q) {/* Validate event block type */ + *perr = OS_ERR_EVENT_TYPE; + return ((void *)0); + } + OS_ENTER_CRITICAL(); + pq = (OS_Q *)pevent->OSEventPtr; /* Point at queue control block */ + if (pq->OSQEntries > 0u) { /* See if any messages in the queue */ + pmsg = *pq->OSQOut++; /* Yes, extract oldest message from the queue */ + pq->OSQEntries--; /* Update the number of entries in the queue */ + if (pq->OSQOut == pq->OSQEnd) { /* Wrap OUT pointer if we are at the end of the queue */ + pq->OSQOut = pq->OSQStart; + } + *perr = OS_ERR_NONE; + } else { + *perr = OS_ERR_Q_EMPTY; + pmsg = (void *)0; /* Queue is empty */ + } + OS_EXIT_CRITICAL(); + return (pmsg); /* Return message received (or NULL) */ +} +#endif +/*$PAGE*/ +/* +********************************************************************************************************* +* CREATE A MESSAGE QUEUE +* +* Description: This function creates a message queue if free event control blocks are available. +* +* Arguments : start is a pointer to the base address of the message queue storage area. The +* storage area MUST be declared as an array of pointers to 'void' as follows +* +* void *MessageStorage[size] +* +* size is the number of elements in the storage area +* +* Returns : != (OS_EVENT *)0 is a pointer to the event control clock (OS_EVENT) associated with the +* created queue +* == (OS_EVENT *)0 if no event control blocks were available or an error was detected +********************************************************************************************************* +*/ + +OS_EVENT *OSQCreate (void **start, + INT16U size) +{ + OS_EVENT *pevent; + OS_Q *pq; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#ifdef OS_SAFETY_CRITICAL_IEC61508 + if (OSSafetyCriticalStartFlag == OS_TRUE) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return ((OS_EVENT *)0); + } +#endif + + if (OSIntNesting > 0u) { /* See if called from ISR ... */ + return ((OS_EVENT *)0); /* ... can't CREATE from an ISR */ + } + OS_ENTER_CRITICAL(); + pevent = OSEventFreeList; /* Get next free event control block */ + if (OSEventFreeList != (OS_EVENT *)0) { /* See if pool of free ECB pool was empty */ + OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr; + } + OS_EXIT_CRITICAL(); + if (pevent != (OS_EVENT *)0) { /* See if we have an event control block */ + OS_ENTER_CRITICAL(); + pq = OSQFreeList; /* Get a free queue control block */ + if (pq != (OS_Q *)0) { /* Were we able to get a queue control block ? */ + OSQFreeList = OSQFreeList->OSQPtr; /* Yes, Adjust free list pointer to next free*/ + OS_EXIT_CRITICAL(); + pq->OSQStart = start; /* Initialize the queue */ + pq->OSQEnd = &start[size]; + pq->OSQIn = start; + pq->OSQOut = start; + pq->OSQSize = size; + pq->OSQEntries = 0u; + pevent->OSEventType = OS_EVENT_TYPE_Q; + pevent->OSEventCnt = 0u; + pevent->OSEventPtr = pq; +#if OS_EVENT_NAME_EN > 0u + pevent->OSEventName = (INT8U *)(void *)"?"; +#endif + OS_EventWaitListInit(pevent); /* Initialize the wait list */ + } else { + pevent->OSEventPtr = (void *)OSEventFreeList; /* No, Return event control block on error */ + OSEventFreeList = pevent; + OS_EXIT_CRITICAL(); + pevent = (OS_EVENT *)0; + } + } + return (pevent); +} +/*$PAGE*/ +/* +********************************************************************************************************* +* DELETE A MESSAGE QUEUE +* +* Description: This function deletes a message queue and readies all tasks pending on the queue. +* +* Arguments : pevent is a pointer to the event control block associated with the desired +* queue. +* +* opt determines delete options as follows: +* opt == OS_DEL_NO_PEND Delete the queue ONLY if no task pending +* opt == OS_DEL_ALWAYS Deletes the queue even if tasks are waiting. +* In this case, all the tasks pending will be readied. +* +* perr is a pointer to an error code that can contain one of the following values: +* OS_ERR_NONE The call was successful and the queue was deleted +* OS_ERR_DEL_ISR If you tried to delete the queue from an ISR +* OS_ERR_INVALID_OPT An invalid option was specified +* OS_ERR_TASK_WAITING One or more tasks were waiting on the queue +* OS_ERR_EVENT_TYPE If you didn't pass a pointer to a queue +* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer. +* +* Returns : pevent upon error +* (OS_EVENT *)0 if the queue was successfully deleted. +* +* Note(s) : 1) This function must be used with care. Tasks that would normally expect the presence of +* the queue MUST check the return code of OSQPend(). +* 2) OSQAccept() callers will not know that the intended queue has been deleted unless +* they check 'pevent' to see that it's a NULL pointer. +* 3) This call can potentially disable interrupts for a long time. The interrupt disable +* time is directly proportional to the number of tasks waiting on the queue. +* 4) Because ALL tasks pending on the queue will be readied, you MUST be careful in +* applications where the queue is used for mutual exclusion because the resource(s) +* will no longer be guarded by the queue. +* 5) If the storage for the message queue was allocated dynamically (i.e. using a malloc() +* type call) then your application MUST release the memory storage by call the counterpart +* call of the dynamic allocation scheme used. If the queue storage was created statically +* then, the storage can be reused. +* 6) All tasks that were waiting for the queue will be readied and returned an +* OS_ERR_PEND_ABORT if OSQDel() was called with OS_DEL_ALWAYS +********************************************************************************************************* +*/ + +#if OS_Q_DEL_EN > 0u +OS_EVENT *OSQDel (OS_EVENT *pevent, + INT8U opt, + INT8U *perr) +{ + BOOLEAN tasks_waiting; + OS_EVENT *pevent_return; + OS_Q *pq; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#ifdef OS_SAFETY_CRITICAL + if (perr == (INT8U *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return ((OS_EVENT *)0); + } +#endif + +#if OS_ARG_CHK_EN > 0u + if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */ + *perr = OS_ERR_PEVENT_NULL; + return (pevent); + } +#endif + if (pevent->OSEventType != OS_EVENT_TYPE_Q) { /* Validate event block type */ + *perr = OS_ERR_EVENT_TYPE; + return (pevent); + } + if (OSIntNesting > 0u) { /* See if called from ISR ... */ + *perr = OS_ERR_DEL_ISR; /* ... can't DELETE from an ISR */ + return (pevent); + } + OS_ENTER_CRITICAL(); + if (pevent->OSEventGrp != 0u) { /* See if any tasks waiting on queue */ + tasks_waiting = OS_TRUE; /* Yes */ + } else { + tasks_waiting = OS_FALSE; /* No */ + } + switch (opt) { + case OS_DEL_NO_PEND: /* Delete queue only if no task waiting */ + if (tasks_waiting == OS_FALSE) { +#if OS_EVENT_NAME_EN > 0u + pevent->OSEventName = (INT8U *)(void *)"?"; +#endif + pq = (OS_Q *)pevent->OSEventPtr; /* Return OS_Q to free list */ + pq->OSQPtr = OSQFreeList; + OSQFreeList = pq; + pevent->OSEventType = OS_EVENT_TYPE_UNUSED; + pevent->OSEventPtr = OSEventFreeList; /* Return Event Control Block to free list */ + pevent->OSEventCnt = 0u; + OSEventFreeList = pevent; /* Get next free event control block */ + OS_EXIT_CRITICAL(); + *perr = OS_ERR_NONE; + pevent_return = (OS_EVENT *)0; /* Queue has been deleted */ + } else { + OS_EXIT_CRITICAL(); + *perr = OS_ERR_TASK_WAITING; + pevent_return = pevent; + } + break; + + case OS_DEL_ALWAYS: /* Always delete the queue */ + while (pevent->OSEventGrp != 0u) { /* Ready ALL tasks waiting for queue */ + (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_Q, OS_STAT_PEND_ABORT); + } +#if OS_EVENT_NAME_EN > 0u + pevent->OSEventName = (INT8U *)(void *)"?"; +#endif + pq = (OS_Q *)pevent->OSEventPtr; /* Return OS_Q to free list */ + pq->OSQPtr = OSQFreeList; + OSQFreeList = pq; + pevent->OSEventType = OS_EVENT_TYPE_UNUSED; + pevent->OSEventPtr = OSEventFreeList; /* Return Event Control Block to free list */ + pevent->OSEventCnt = 0u; + OSEventFreeList = pevent; /* Get next free event control block */ + OS_EXIT_CRITICAL(); + if (tasks_waiting == OS_TRUE) { /* Reschedule only if task(s) were waiting */ + OS_Sched(); /* Find highest priority task ready to run */ + } + *perr = OS_ERR_NONE; + pevent_return = (OS_EVENT *)0; /* Queue has been deleted */ + break; + + default: + OS_EXIT_CRITICAL(); + *perr = OS_ERR_INVALID_OPT; + pevent_return = pevent; + break; + } + return (pevent_return); +} +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* FLUSH QUEUE +* +* Description : This function is used to flush the contents of the message queue. +* +* Arguments : none +* +* Returns : OS_ERR_NONE upon success +* OS_ERR_EVENT_TYPE If you didn't pass a pointer to a queue +* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer +* +* WARNING : You should use this function with great care because, when to flush the queue, you LOOSE +* the references to what the queue entries are pointing to and thus, you could cause +* 'memory leaks'. In other words, the data you are pointing to that's being referenced +* by the queue entries should, most likely, need to be de-allocated (i.e. freed). +********************************************************************************************************* +*/ + +#if OS_Q_FLUSH_EN > 0u +INT8U OSQFlush (OS_EVENT *pevent) +{ + OS_Q *pq; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#if OS_ARG_CHK_EN > 0u + if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */ + return (OS_ERR_PEVENT_NULL); + } + if (pevent->OSEventType != OS_EVENT_TYPE_Q) { /* Validate event block type */ + return (OS_ERR_EVENT_TYPE); + } +#endif + OS_ENTER_CRITICAL(); + pq = (OS_Q *)pevent->OSEventPtr; /* Point to queue storage structure */ + pq->OSQIn = pq->OSQStart; + pq->OSQOut = pq->OSQStart; + pq->OSQEntries = 0u; + OS_EXIT_CRITICAL(); + return (OS_ERR_NONE); +} +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* PEND ON A QUEUE FOR A MESSAGE +* +* Description: This function waits for a message to be sent to a queue +* +* Arguments : pevent is a pointer to the event control block associated with the desired queue +* +* timeout is an optional timeout period (in clock ticks). If non-zero, your task will +* wait for a message to arrive at the queue up to the amount of time +* specified by this argument. If you specify 0, however, your task will wait +* forever at the specified queue or, until a message arrives. +* +* perr is a pointer to where an error message will be deposited. Possible error +* messages are: +* +* OS_ERR_NONE The call was successful and your task received a +* message. +* OS_ERR_TIMEOUT A message was not received within the specified 'timeout'. +* OS_ERR_PEND_ABORT The wait on the queue was aborted. +* OS_ERR_EVENT_TYPE You didn't pass a pointer to a queue +* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer +* OS_ERR_PEND_ISR If you called this function from an ISR and the result +* would lead to a suspension. +* OS_ERR_PEND_LOCKED If you called this function with the scheduler is locked +* +* Returns : != (void *)0 is a pointer to the message received +* == (void *)0 if you received a NULL pointer message or, +* if no message was received or, +* if 'pevent' is a NULL pointer or, +* if you didn't pass a pointer to a queue. +* +* Note(s) : As of V2.60, this function allows you to receive NULL pointer messages. +********************************************************************************************************* +*/ + +void *OSQPend (OS_EVENT *pevent, + INT32U timeout, + INT8U *perr) +{ + void *pmsg; + OS_Q *pq; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#ifdef OS_SAFETY_CRITICAL + if (perr == (INT8U *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return ((void *)0); + } +#endif + +#if OS_ARG_CHK_EN > 0u + if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */ + *perr = OS_ERR_PEVENT_NULL; + return ((void *)0); + } +#endif + if (pevent->OSEventType != OS_EVENT_TYPE_Q) {/* Validate event block type */ + *perr = OS_ERR_EVENT_TYPE; + return ((void *)0); + } + if (OSIntNesting > 0u) { /* See if called from ISR ... */ + *perr = OS_ERR_PEND_ISR; /* ... can't PEND from an ISR */ + return ((void *)0); + } + if (OSLockNesting > 0u) { /* See if called with scheduler locked ... */ + *perr = OS_ERR_PEND_LOCKED; /* ... can't PEND when locked */ + return ((void *)0); + } + OS_ENTER_CRITICAL(); + pq = (OS_Q *)pevent->OSEventPtr; /* Point at queue control block */ + if (pq->OSQEntries > 0u) { /* See if any messages in the queue */ + pmsg = *pq->OSQOut++; /* Yes, extract oldest message from the queue */ + pq->OSQEntries--; /* Update the number of entries in the queue */ + if (pq->OSQOut == pq->OSQEnd) { /* Wrap OUT pointer if we are at the end of the queue */ + pq->OSQOut = pq->OSQStart; + } + OS_EXIT_CRITICAL(); + *perr = OS_ERR_NONE; + return (pmsg); /* Return message received */ + } + OSTCBCur->OSTCBStat |= OS_STAT_Q; /* Task will have to pend for a message to be posted */ + OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK; + OSTCBCur->OSTCBDly = timeout; /* Load timeout into TCB */ + OS_EventTaskWait(pevent); /* Suspend task until event or timeout occurs */ + OS_EXIT_CRITICAL(); + OS_Sched(); /* Find next highest priority task ready to run */ + OS_ENTER_CRITICAL(); + switch (OSTCBCur->OSTCBStatPend) { /* See if we timed-out or aborted */ + case OS_STAT_PEND_OK: /* Extract message from TCB (Put there by QPost) */ + pmsg = OSTCBCur->OSTCBMsg; + *perr = OS_ERR_NONE; + break; + + case OS_STAT_PEND_ABORT: + pmsg = (void *)0; + *perr = OS_ERR_PEND_ABORT; /* Indicate that we aborted */ + break; + + case OS_STAT_PEND_TO: + default: + OS_EventTaskRemove(OSTCBCur, pevent); + pmsg = (void *)0; + *perr = OS_ERR_TIMEOUT; /* Indicate that we didn't get event within TO */ + break; + } + OSTCBCur->OSTCBStat = OS_STAT_RDY; /* Set task status to ready */ + OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK; /* Clear pend status */ + OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; /* Clear event pointers */ +#if (OS_EVENT_MULTI_EN > 0u) + OSTCBCur->OSTCBEventMultiPtr = (OS_EVENT **)0; +#endif + OSTCBCur->OSTCBMsg = (void *)0; /* Clear received message */ + OS_EXIT_CRITICAL(); + return (pmsg); /* Return received message */ +} +/*$PAGE*/ +/* +********************************************************************************************************* +* ABORT WAITING ON A MESSAGE QUEUE +* +* Description: This function aborts & readies any tasks currently waiting on a queue. This function +* should be used to fault-abort the wait on the queue, rather than to normally signal +* the queue via OSQPost(), OSQPostFront() or OSQPostOpt(). +* +* Arguments : pevent is a pointer to the event control block associated with the desired queue. +* +* opt determines the type of ABORT performed: +* OS_PEND_OPT_NONE ABORT wait for a single task (HPT) waiting on the +* queue +* OS_PEND_OPT_BROADCAST ABORT wait for ALL tasks that are waiting on the +* queue +* +* perr is a pointer to where an error message will be deposited. Possible error +* messages are: +* +* OS_ERR_NONE No tasks were waiting on the queue. +* OS_ERR_PEND_ABORT At least one task waiting on the queue was readied +* and informed of the aborted wait; check return value +* for the number of tasks whose wait on the queue +* was aborted. +* OS_ERR_EVENT_TYPE If you didn't pass a pointer to a queue. +* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer. +* +* Returns : == 0 if no tasks were waiting on the queue, or upon error. +* > 0 if one or more tasks waiting on the queue are now readied and informed. +********************************************************************************************************* +*/ + +#if OS_Q_PEND_ABORT_EN > 0u +INT8U OSQPendAbort (OS_EVENT *pevent, + INT8U opt, + INT8U *perr) +{ + INT8U nbr_tasks; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#ifdef OS_SAFETY_CRITICAL + if (perr == (INT8U *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return (0u); + } +#endif + +#if OS_ARG_CHK_EN > 0u + if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */ + *perr = OS_ERR_PEVENT_NULL; + return (0u); + } +#endif + if (pevent->OSEventType != OS_EVENT_TYPE_Q) { /* Validate event block type */ + *perr = OS_ERR_EVENT_TYPE; + return (0u); + } + OS_ENTER_CRITICAL(); + if (pevent->OSEventGrp != 0u) { /* See if any task waiting on queue? */ + nbr_tasks = 0u; + switch (opt) { + case OS_PEND_OPT_BROADCAST: /* Do we need to abort ALL waiting tasks? */ + while (pevent->OSEventGrp != 0u) { /* Yes, ready ALL tasks waiting on queue */ + (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_Q, OS_STAT_PEND_ABORT); + nbr_tasks++; + } + break; + + case OS_PEND_OPT_NONE: + default: /* No, ready HPT waiting on queue */ + (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_Q, OS_STAT_PEND_ABORT); + nbr_tasks++; + break; + } + OS_EXIT_CRITICAL(); + OS_Sched(); /* Find HPT ready to run */ + *perr = OS_ERR_PEND_ABORT; + return (nbr_tasks); + } + OS_EXIT_CRITICAL(); + *perr = OS_ERR_NONE; + return (0u); /* No tasks waiting on queue */ +} +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* POST MESSAGE TO A QUEUE +* +* Description: This function sends a message to a queue +* +* Arguments : pevent is a pointer to the event control block associated with the desired queue +* +* pmsg is a pointer to the message to send. +* +* Returns : OS_ERR_NONE The call was successful and the message was sent +* OS_ERR_Q_FULL If the queue cannot accept any more messages because it is full. +* OS_ERR_EVENT_TYPE If you didn't pass a pointer to a queue. +* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer +* +* Note(s) : As of V2.60, this function allows you to send NULL pointer messages. +********************************************************************************************************* +*/ + +#if OS_Q_POST_EN > 0u +INT8U OSQPost (OS_EVENT *pevent, + void *pmsg) +{ + OS_Q *pq; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#if OS_ARG_CHK_EN > 0u + if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */ + return (OS_ERR_PEVENT_NULL); + } +#endif + if (pevent->OSEventType != OS_EVENT_TYPE_Q) { /* Validate event block type */ + return (OS_ERR_EVENT_TYPE); + } + OS_ENTER_CRITICAL(); + if (pevent->OSEventGrp != 0u) { /* See if any task pending on queue */ + /* Ready highest priority task waiting on event */ + (void)OS_EventTaskRdy(pevent, pmsg, OS_STAT_Q, OS_STAT_PEND_OK); + OS_EXIT_CRITICAL(); + OS_Sched(); /* Find highest priority task ready to run */ + return (OS_ERR_NONE); + } + pq = (OS_Q *)pevent->OSEventPtr; /* Point to queue control block */ + if (pq->OSQEntries >= pq->OSQSize) { /* Make sure queue is not full */ + OS_EXIT_CRITICAL(); + return (OS_ERR_Q_FULL); + } + *pq->OSQIn++ = pmsg; /* Insert message into queue */ + pq->OSQEntries++; /* Update the nbr of entries in the queue */ + if (pq->OSQIn == pq->OSQEnd) { /* Wrap IN ptr if we are at end of queue */ + pq->OSQIn = pq->OSQStart; + } + OS_EXIT_CRITICAL(); + return (OS_ERR_NONE); +} +#endif +/*$PAGE*/ +/* +********************************************************************************************************* +* POST MESSAGE TO THE FRONT OF A QUEUE +* +* Description: This function sends a message to a queue but unlike OSQPost(), the message is posted at +* the front instead of the end of the queue. Using OSQPostFront() allows you to send +* 'priority' messages. +* +* Arguments : pevent is a pointer to the event control block associated with the desired queue +* +* pmsg is a pointer to the message to send. +* +* Returns : OS_ERR_NONE The call was successful and the message was sent +* OS_ERR_Q_FULL If the queue cannot accept any more messages because it is full. +* OS_ERR_EVENT_TYPE If you didn't pass a pointer to a queue. +* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer +* +* Note(s) : As of V2.60, this function allows you to send NULL pointer messages. +********************************************************************************************************* +*/ + +#if OS_Q_POST_FRONT_EN > 0u +INT8U OSQPostFront (OS_EVENT *pevent, + void *pmsg) +{ + OS_Q *pq; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#if OS_ARG_CHK_EN > 0u + if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */ + return (OS_ERR_PEVENT_NULL); + } +#endif + if (pevent->OSEventType != OS_EVENT_TYPE_Q) { /* Validate event block type */ + return (OS_ERR_EVENT_TYPE); + } + OS_ENTER_CRITICAL(); + if (pevent->OSEventGrp != 0u) { /* See if any task pending on queue */ + /* Ready highest priority task waiting on event */ + (void)OS_EventTaskRdy(pevent, pmsg, OS_STAT_Q, OS_STAT_PEND_OK); + OS_EXIT_CRITICAL(); + OS_Sched(); /* Find highest priority task ready to run */ + return (OS_ERR_NONE); + } + pq = (OS_Q *)pevent->OSEventPtr; /* Point to queue control block */ + if (pq->OSQEntries >= pq->OSQSize) { /* Make sure queue is not full */ + OS_EXIT_CRITICAL(); + return (OS_ERR_Q_FULL); + } + if (pq->OSQOut == pq->OSQStart) { /* Wrap OUT ptr if we are at the 1st queue entry */ + pq->OSQOut = pq->OSQEnd; + } + pq->OSQOut--; + *pq->OSQOut = pmsg; /* Insert message into queue */ + pq->OSQEntries++; /* Update the nbr of entries in the queue */ + OS_EXIT_CRITICAL(); + return (OS_ERR_NONE); +} +#endif +/*$PAGE*/ +/* +********************************************************************************************************* +* POST MESSAGE TO A QUEUE +* +* Description: This function sends a message to a queue. This call has been added to reduce code size +* since it can replace both OSQPost() and OSQPostFront(). Also, this function adds the +* capability to broadcast a message to ALL tasks waiting on the message queue. +* +* Arguments : pevent is a pointer to the event control block associated with the desired queue +* +* pmsg is a pointer to the message to send. +* +* opt determines the type of POST performed: +* OS_POST_OPT_NONE POST to a single waiting task +* (Identical to OSQPost()) +* OS_POST_OPT_BROADCAST POST to ALL tasks that are waiting on the queue +* OS_POST_OPT_FRONT POST as LIFO (Simulates OSQPostFront()) +* OS_POST_OPT_NO_SCHED Indicates that the scheduler will NOT be invoked +* +* Returns : OS_ERR_NONE The call was successful and the message was sent +* OS_ERR_Q_FULL If the queue cannot accept any more messages because it is full. +* OS_ERR_EVENT_TYPE If you didn't pass a pointer to a queue. +* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer +* +* Warning : Interrupts can be disabled for a long time if you do a 'broadcast'. In fact, the +* interrupt disable time is proportional to the number of tasks waiting on the queue. +********************************************************************************************************* +*/ + +#if OS_Q_POST_OPT_EN > 0u +INT8U OSQPostOpt (OS_EVENT *pevent, + void *pmsg, + INT8U opt) +{ + OS_Q *pq; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#if OS_ARG_CHK_EN > 0u + if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */ + return (OS_ERR_PEVENT_NULL); + } +#endif + if (pevent->OSEventType != OS_EVENT_TYPE_Q) { /* Validate event block type */ + return (OS_ERR_EVENT_TYPE); + } + OS_ENTER_CRITICAL(); + if (pevent->OSEventGrp != 0x00u) { /* See if any task pending on queue */ + if ((opt & OS_POST_OPT_BROADCAST) != 0x00u) { /* Do we need to post msg to ALL waiting tasks ? */ + while (pevent->OSEventGrp != 0u) { /* Yes, Post to ALL tasks waiting on queue */ + (void)OS_EventTaskRdy(pevent, pmsg, OS_STAT_Q, OS_STAT_PEND_OK); + } + } else { /* No, Post to HPT waiting on queue */ + (void)OS_EventTaskRdy(pevent, pmsg, OS_STAT_Q, OS_STAT_PEND_OK); + } + OS_EXIT_CRITICAL(); + if ((opt & OS_POST_OPT_NO_SCHED) == 0u) { /* See if scheduler needs to be invoked */ + OS_Sched(); /* Find highest priority task ready to run */ + } + return (OS_ERR_NONE); + } + pq = (OS_Q *)pevent->OSEventPtr; /* Point to queue control block */ + if (pq->OSQEntries >= pq->OSQSize) { /* Make sure queue is not full */ + OS_EXIT_CRITICAL(); + return (OS_ERR_Q_FULL); + } + if ((opt & OS_POST_OPT_FRONT) != 0x00u) { /* Do we post to the FRONT of the queue? */ + if (pq->OSQOut == pq->OSQStart) { /* Yes, Post as LIFO, Wrap OUT pointer if we ... */ + pq->OSQOut = pq->OSQEnd; /* ... are at the 1st queue entry */ + } + pq->OSQOut--; + *pq->OSQOut = pmsg; /* Insert message into queue */ + } else { /* No, Post as FIFO */ + *pq->OSQIn++ = pmsg; /* Insert message into queue */ + if (pq->OSQIn == pq->OSQEnd) { /* Wrap IN ptr if we are at end of queue */ + pq->OSQIn = pq->OSQStart; + } + } + pq->OSQEntries++; /* Update the nbr of entries in the queue */ + OS_EXIT_CRITICAL(); + return (OS_ERR_NONE); +} +#endif +/*$PAGE*/ +/* +********************************************************************************************************* +* QUERY A MESSAGE QUEUE +* +* Description: This function obtains information about a message queue. +* +* Arguments : pevent is a pointer to the event control block associated with the desired queue +* +* p_q_data is a pointer to a structure that will contain information about the message +* queue. +* +* Returns : OS_ERR_NONE The call was successful and the message was sent +* OS_ERR_EVENT_TYPE If you are attempting to obtain data from a non queue. +* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer +* OS_ERR_PDATA_NULL If 'p_q_data' is a NULL pointer +********************************************************************************************************* +*/ + +#if OS_Q_QUERY_EN > 0u +INT8U OSQQuery (OS_EVENT *pevent, + OS_Q_DATA *p_q_data) +{ + OS_Q *pq; + INT8U i; + OS_PRIO *psrc; + OS_PRIO *pdest; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#if OS_ARG_CHK_EN > 0u + if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */ + return (OS_ERR_PEVENT_NULL); + } + if (p_q_data == (OS_Q_DATA *)0) { /* Validate 'p_q_data' */ + return (OS_ERR_PDATA_NULL); + } +#endif + if (pevent->OSEventType != OS_EVENT_TYPE_Q) { /* Validate event block type */ + return (OS_ERR_EVENT_TYPE); + } + OS_ENTER_CRITICAL(); + p_q_data->OSEventGrp = pevent->OSEventGrp; /* Copy message queue wait list */ + psrc = &pevent->OSEventTbl[0]; + pdest = &p_q_data->OSEventTbl[0]; + for (i = 0u; i < OS_EVENT_TBL_SIZE; i++) { + *pdest++ = *psrc++; + } + pq = (OS_Q *)pevent->OSEventPtr; + if (pq->OSQEntries > 0u) { + p_q_data->OSMsg = *pq->OSQOut; /* Get next message to return if available */ + } else { + p_q_data->OSMsg = (void *)0; + } + p_q_data->OSNMsgs = pq->OSQEntries; + p_q_data->OSQSize = pq->OSQSize; + OS_EXIT_CRITICAL(); + return (OS_ERR_NONE); +} +#endif /* OS_Q_QUERY_EN */ + +/*$PAGE*/ +/* +********************************************************************************************************* +* QUEUE MODULE INITIALIZATION +* +* Description : This function is called by uC/OS-II to initialize the message queue module. Your +* application MUST NOT call this function. +* +* Arguments : none +* +* Returns : none +* +* Note(s) : This function is INTERNAL to uC/OS-II and your application should not call it. +********************************************************************************************************* +*/ + +void OS_QInit (void) +{ +#if OS_MAX_QS == 1u + OSQFreeList = &OSQTbl[0]; /* Only ONE queue! */ + OSQFreeList->OSQPtr = (OS_Q *)0; +#endif + +#if OS_MAX_QS >= 2u + INT16U ix; + INT16U ix_next; + OS_Q *pq1; + OS_Q *pq2; + + + + OS_MemClr((INT8U *)&OSQTbl[0], sizeof(OSQTbl)); /* Clear the queue table */ + for (ix = 0u; ix < (OS_MAX_QS - 1u); ix++) { /* Init. list of free QUEUE control blocks */ + ix_next = ix + 1u; + pq1 = &OSQTbl[ix]; + pq2 = &OSQTbl[ix_next]; + pq1->OSQPtr = pq2; + } + pq1 = &OSQTbl[ix]; + pq1->OSQPtr = (OS_Q *)0; + OSQFreeList = &OSQTbl[0]; +#endif +} +#endif /* OS_Q_EN */ diff --git a/Middlewares/Third_Party/Micrium/uCOS-II/Source/os_sem.c b/Middlewares/Third_Party/Micrium/uCOS-II/Source/os_sem.c new file mode 100644 index 0000000..93bfb1a --- /dev/null +++ b/Middlewares/Third_Party/Micrium/uCOS-II/Source/os_sem.c @@ -0,0 +1,637 @@ +/* +********************************************************************************************************* +* uC/OS-II +* The Real-Time Kernel +* SEMAPHORE MANAGEMENT +* +* (c) Copyright 1992-2013, Micrium, Weston, FL +* All Rights Reserved +* +* File : OS_SEM.C +* By : Jean J. Labrosse +* Version : V2.92.11 +* +* LICENSING TERMS: +* --------------- +* uC/OS-II is provided in source form for FREE evaluation, for educational use or for peaceful research. +* If you plan on using uC/OS-II in a commercial product you need to contact Micrium to properly license +* its use in your product. We provide ALL the source code for your convenience and to help you experience +* uC/OS-II. The fact that the source is provided does NOT mean that you can use it without paying a +* licensing fee. +********************************************************************************************************* +*/ + +#define MICRIUM_SOURCE + +#ifndef OS_MASTER_FILE +#include +#endif + +#if OS_SEM_EN > 0u +/*$PAGE*/ +/* +********************************************************************************************************* +* ACCEPT SEMAPHORE +* +* Description: This function checks the semaphore to see if a resource is available or, if an event +* occurred. Unlike OSSemPend(), OSSemAccept() does not suspend the calling task if the +* resource is not available or the event did not occur. +* +* Arguments : pevent is a pointer to the event control block +* +* Returns : > 0 if the resource is available or the event did not occur the semaphore is +* decremented to obtain the resource. +* == 0 if the resource is not available or the event did not occur or, +* if 'pevent' is a NULL pointer or, +* if you didn't pass a pointer to a semaphore +********************************************************************************************************* +*/ + +#if OS_SEM_ACCEPT_EN > 0u +INT16U OSSemAccept (OS_EVENT *pevent) +{ + INT16U cnt; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#if OS_ARG_CHK_EN > 0u + if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */ + return (0u); + } +#endif + if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event block type */ + return (0u); + } + OS_ENTER_CRITICAL(); + cnt = pevent->OSEventCnt; + if (cnt > 0u) { /* See if resource is available */ + pevent->OSEventCnt--; /* Yes, decrement semaphore and notify caller */ + } + OS_EXIT_CRITICAL(); + return (cnt); /* Return semaphore count */ +} +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* CREATE A SEMAPHORE +* +* Description: This function creates a semaphore. +* +* Arguments : cnt is the initial value for the semaphore. If the value is 0, no resource is +* available (or no event has occurred). You initialize the semaphore to a +* non-zero value to specify how many resources are available (e.g. if you have +* 10 resources, you would initialize the semaphore to 10). +* +* Returns : != (void *)0 is a pointer to the event control block (OS_EVENT) associated with the +* created semaphore +* == (void *)0 if no event control blocks were available +********************************************************************************************************* +*/ + +OS_EVENT *OSSemCreate (INT16U cnt) +{ + OS_EVENT *pevent; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#ifdef OS_SAFETY_CRITICAL_IEC61508 + if (OSSafetyCriticalStartFlag == OS_TRUE) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return ((OS_EVENT *)0); + } +#endif + + if (OSIntNesting > 0u) { /* See if called from ISR ... */ + return ((OS_EVENT *)0); /* ... can't CREATE from an ISR */ + } + OS_ENTER_CRITICAL(); + pevent = OSEventFreeList; /* Get next free event control block */ + if (OSEventFreeList != (OS_EVENT *)0) { /* See if pool of free ECB pool was empty */ + OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr; + } + OS_EXIT_CRITICAL(); + if (pevent != (OS_EVENT *)0) { /* Get an event control block */ + pevent->OSEventType = OS_EVENT_TYPE_SEM; + pevent->OSEventCnt = cnt; /* Set semaphore value */ + pevent->OSEventPtr = (void *)0; /* Unlink from ECB free list */ +#if OS_EVENT_NAME_EN > 0u + pevent->OSEventName = (INT8U *)(void *)"?"; +#endif + OS_EventWaitListInit(pevent); /* Initialize to 'nobody waiting' on sem. */ + } + return (pevent); +} + +/*$PAGE*/ +/* +********************************************************************************************************* +* DELETE A SEMAPHORE +* +* Description: This function deletes a semaphore and readies all tasks pending on the semaphore. +* +* Arguments : pevent is a pointer to the event control block associated with the desired +* semaphore. +* +* opt determines delete options as follows: +* opt == OS_DEL_NO_PEND Delete semaphore ONLY if no task pending +* opt == OS_DEL_ALWAYS Deletes the semaphore even if tasks are waiting. +* In this case, all the tasks pending will be readied. +* +* perr is a pointer to an error code that can contain one of the following values: +* OS_ERR_NONE The call was successful and the semaphore was deleted +* OS_ERR_DEL_ISR If you attempted to delete the semaphore from an ISR +* OS_ERR_INVALID_OPT An invalid option was specified +* OS_ERR_TASK_WAITING One or more tasks were waiting on the semaphore +* OS_ERR_EVENT_TYPE If you didn't pass a pointer to a semaphore +* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer. +* +* Returns : pevent upon error +* (OS_EVENT *)0 if the semaphore was successfully deleted. +* +* Note(s) : 1) This function must be used with care. Tasks that would normally expect the presence of +* the semaphore MUST check the return code of OSSemPend(). +* 2) OSSemAccept() callers will not know that the intended semaphore has been deleted unless +* they check 'pevent' to see that it's a NULL pointer. +* 3) This call can potentially disable interrupts for a long time. The interrupt disable +* time is directly proportional to the number of tasks waiting on the semaphore. +* 4) Because ALL tasks pending on the semaphore will be readied, you MUST be careful in +* applications where the semaphore is used for mutual exclusion because the resource(s) +* will no longer be guarded by the semaphore. +* 5) All tasks that were waiting for the semaphore will be readied and returned an +* OS_ERR_PEND_ABORT if OSSemDel() was called with OS_DEL_ALWAYS +********************************************************************************************************* +*/ + +#if OS_SEM_DEL_EN > 0u +OS_EVENT *OSSemDel (OS_EVENT *pevent, + INT8U opt, + INT8U *perr) +{ + BOOLEAN tasks_waiting; + OS_EVENT *pevent_return; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#ifdef OS_SAFETY_CRITICAL + if (perr == (INT8U *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return ((OS_EVENT *)0); + } +#endif + +#if OS_ARG_CHK_EN > 0u + if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */ + *perr = OS_ERR_PEVENT_NULL; + return (pevent); + } +#endif + if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event block type */ + *perr = OS_ERR_EVENT_TYPE; + return (pevent); + } + if (OSIntNesting > 0u) { /* See if called from ISR ... */ + *perr = OS_ERR_DEL_ISR; /* ... can't DELETE from an ISR */ + return (pevent); + } + OS_ENTER_CRITICAL(); + if (pevent->OSEventGrp != 0u) { /* See if any tasks waiting on semaphore */ + tasks_waiting = OS_TRUE; /* Yes */ + } else { + tasks_waiting = OS_FALSE; /* No */ + } + switch (opt) { + case OS_DEL_NO_PEND: /* Delete semaphore only if no task waiting */ + if (tasks_waiting == OS_FALSE) { +#if OS_EVENT_NAME_EN > 0u + pevent->OSEventName = (INT8U *)(void *)"?"; +#endif + pevent->OSEventType = OS_EVENT_TYPE_UNUSED; + pevent->OSEventPtr = OSEventFreeList; /* Return Event Control Block to free list */ + pevent->OSEventCnt = 0u; + OSEventFreeList = pevent; /* Get next free event control block */ + OS_EXIT_CRITICAL(); + *perr = OS_ERR_NONE; + pevent_return = (OS_EVENT *)0; /* Semaphore has been deleted */ + } else { + OS_EXIT_CRITICAL(); + *perr = OS_ERR_TASK_WAITING; + pevent_return = pevent; + } + break; + + case OS_DEL_ALWAYS: /* Always delete the semaphore */ + while (pevent->OSEventGrp != 0u) { /* Ready ALL tasks waiting for semaphore */ + (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM, OS_STAT_PEND_ABORT); + } +#if OS_EVENT_NAME_EN > 0u + pevent->OSEventName = (INT8U *)(void *)"?"; +#endif + pevent->OSEventType = OS_EVENT_TYPE_UNUSED; + pevent->OSEventPtr = OSEventFreeList; /* Return Event Control Block to free list */ + pevent->OSEventCnt = 0u; + OSEventFreeList = pevent; /* Get next free event control block */ + OS_EXIT_CRITICAL(); + if (tasks_waiting == OS_TRUE) { /* Reschedule only if task(s) were waiting */ + OS_Sched(); /* Find highest priority task ready to run */ + } + *perr = OS_ERR_NONE; + pevent_return = (OS_EVENT *)0; /* Semaphore has been deleted */ + break; + + default: + OS_EXIT_CRITICAL(); + *perr = OS_ERR_INVALID_OPT; + pevent_return = pevent; + break; + } + return (pevent_return); +} +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* PEND ON SEMAPHORE +* +* Description: This function waits for a semaphore. +* +* Arguments : pevent is a pointer to the event control block associated with the desired +* semaphore. +* +* timeout is an optional timeout period (in clock ticks). If non-zero, your task will +* wait for the resource up to the amount of time specified by this argument. +* If you specify 0, however, your task will wait forever at the specified +* semaphore or, until the resource becomes available (or the event occurs). +* +* perr is a pointer to where an error message will be deposited. Possible error +* messages are: +* +* OS_ERR_NONE The call was successful and your task owns the resource +* or, the event you are waiting for occurred. +* OS_ERR_TIMEOUT The semaphore was not received within the specified +* 'timeout'. +* OS_ERR_PEND_ABORT The wait on the semaphore was aborted. +* OS_ERR_EVENT_TYPE If you didn't pass a pointer to a semaphore. +* OS_ERR_PEND_ISR If you called this function from an ISR and the result +* would lead to a suspension. +* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer. +* OS_ERR_PEND_LOCKED If you called this function when the scheduler is locked +* +* Returns : none +********************************************************************************************************* +*/ +/*$PAGE*/ +void OSSemPend (OS_EVENT *pevent, + INT32U timeout, + INT8U *perr) +{ +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#ifdef OS_SAFETY_CRITICAL + if (perr == (INT8U *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return; + } +#endif + +#if OS_ARG_CHK_EN > 0u + if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */ + *perr = OS_ERR_PEVENT_NULL; + return; + } +#endif + if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event block type */ + *perr = OS_ERR_EVENT_TYPE; + return; + } + if (OSIntNesting > 0u) { /* See if called from ISR ... */ + *perr = OS_ERR_PEND_ISR; /* ... can't PEND from an ISR */ + return; + } + if (OSLockNesting > 0u) { /* See if called with scheduler locked ... */ + *perr = OS_ERR_PEND_LOCKED; /* ... can't PEND when locked */ + return; + } + OS_ENTER_CRITICAL(); + if (pevent->OSEventCnt > 0u) { /* If sem. is positive, resource available ... */ + pevent->OSEventCnt--; /* ... decrement semaphore only if positive. */ + OS_EXIT_CRITICAL(); + *perr = OS_ERR_NONE; + return; + } + /* Otherwise, must wait until event occurs */ + OSTCBCur->OSTCBStat |= OS_STAT_SEM; /* Resource not available, pend on semaphore */ + OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK; + OSTCBCur->OSTCBDly = timeout; /* Store pend timeout in TCB */ + OS_EventTaskWait(pevent); /* Suspend task until event or timeout occurs */ + OS_EXIT_CRITICAL(); + OS_Sched(); /* Find next highest priority task ready */ + OS_ENTER_CRITICAL(); + switch (OSTCBCur->OSTCBStatPend) { /* See if we timed-out or aborted */ + case OS_STAT_PEND_OK: + *perr = OS_ERR_NONE; + break; + + case OS_STAT_PEND_ABORT: + *perr = OS_ERR_PEND_ABORT; /* Indicate that we aborted */ + break; + + case OS_STAT_PEND_TO: + default: + OS_EventTaskRemove(OSTCBCur, pevent); + *perr = OS_ERR_TIMEOUT; /* Indicate that we didn't get event within TO */ + break; + } + OSTCBCur->OSTCBStat = OS_STAT_RDY; /* Set task status to ready */ + OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK; /* Clear pend status */ + OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; /* Clear event pointers */ +#if (OS_EVENT_MULTI_EN > 0u) + OSTCBCur->OSTCBEventMultiPtr = (OS_EVENT **)0; +#endif + OS_EXIT_CRITICAL(); +} + +/*$PAGE*/ +/* +********************************************************************************************************* +* ABORT WAITING ON A SEMAPHORE +* +* Description: This function aborts & readies any tasks currently waiting on a semaphore. This function +* should be used to fault-abort the wait on the semaphore, rather than to normally signal +* the semaphore via OSSemPost(). +* +* Arguments : pevent is a pointer to the event control block associated with the desired +* semaphore. +* +* opt determines the type of ABORT performed: +* OS_PEND_OPT_NONE ABORT wait for a single task (HPT) waiting on the +* semaphore +* OS_PEND_OPT_BROADCAST ABORT wait for ALL tasks that are waiting on the +* semaphore +* +* perr is a pointer to where an error message will be deposited. Possible error +* messages are: +* +* OS_ERR_NONE No tasks were waiting on the semaphore. +* OS_ERR_PEND_ABORT At least one task waiting on the semaphore was readied +* and informed of the aborted wait; check return value +* for the number of tasks whose wait on the semaphore +* was aborted. +* OS_ERR_EVENT_TYPE If you didn't pass a pointer to a semaphore. +* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer. +* +* Returns : == 0 if no tasks were waiting on the semaphore, or upon error. +* > 0 if one or more tasks waiting on the semaphore are now readied and informed. +********************************************************************************************************* +*/ + +#if OS_SEM_PEND_ABORT_EN > 0u +INT8U OSSemPendAbort (OS_EVENT *pevent, + INT8U opt, + INT8U *perr) +{ + INT8U nbr_tasks; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#ifdef OS_SAFETY_CRITICAL + if (perr == (INT8U *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return (0u); + } +#endif + +#if OS_ARG_CHK_EN > 0u + if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */ + *perr = OS_ERR_PEVENT_NULL; + return (0u); + } +#endif + if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event block type */ + *perr = OS_ERR_EVENT_TYPE; + return (0u); + } + OS_ENTER_CRITICAL(); + if (pevent->OSEventGrp != 0u) { /* See if any task waiting on semaphore? */ + nbr_tasks = 0u; + switch (opt) { + case OS_PEND_OPT_BROADCAST: /* Do we need to abort ALL waiting tasks? */ + while (pevent->OSEventGrp != 0u) { /* Yes, ready ALL tasks waiting on semaphore */ + (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM, OS_STAT_PEND_ABORT); + nbr_tasks++; + } + break; + + case OS_PEND_OPT_NONE: + default: /* No, ready HPT waiting on semaphore */ + (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM, OS_STAT_PEND_ABORT); + nbr_tasks++; + break; + } + OS_EXIT_CRITICAL(); + OS_Sched(); /* Find HPT ready to run */ + *perr = OS_ERR_PEND_ABORT; + return (nbr_tasks); + } + OS_EXIT_CRITICAL(); + *perr = OS_ERR_NONE; + return (0u); /* No tasks waiting on semaphore */ +} +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* POST TO A SEMAPHORE +* +* Description: This function signals a semaphore +* +* Arguments : pevent is a pointer to the event control block associated with the desired +* semaphore. +* +* Returns : OS_ERR_NONE The call was successful and the semaphore was signaled. +* OS_ERR_SEM_OVF If the semaphore count exceeded its limit. In other words, you have +* signaled the semaphore more often than you waited on it with either +* OSSemAccept() or OSSemPend(). +* OS_ERR_EVENT_TYPE If you didn't pass a pointer to a semaphore +* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer. +********************************************************************************************************* +*/ + +INT8U OSSemPost (OS_EVENT *pevent) +{ +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#if OS_ARG_CHK_EN > 0u + if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */ + return (OS_ERR_PEVENT_NULL); + } +#endif + if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event block type */ + return (OS_ERR_EVENT_TYPE); + } + OS_ENTER_CRITICAL(); + if (pevent->OSEventGrp != 0u) { /* See if any task waiting for semaphore */ + /* Ready HPT waiting on event */ + (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM, OS_STAT_PEND_OK); + OS_EXIT_CRITICAL(); + OS_Sched(); /* Find HPT ready to run */ + return (OS_ERR_NONE); + } + if (pevent->OSEventCnt < 65535u) { /* Make sure semaphore will not overflow */ + pevent->OSEventCnt++; /* Increment semaphore count to register event */ + OS_EXIT_CRITICAL(); + return (OS_ERR_NONE); + } + OS_EXIT_CRITICAL(); /* Semaphore value has reached its maximum */ + return (OS_ERR_SEM_OVF); +} + +/*$PAGE*/ +/* +********************************************************************************************************* +* QUERY A SEMAPHORE +* +* Description: This function obtains information about a semaphore +* +* Arguments : pevent is a pointer to the event control block associated with the desired +* semaphore +* +* p_sem_data is a pointer to a structure that will contain information about the +* semaphore. +* +* Returns : OS_ERR_NONE The call was successful and the message was sent +* OS_ERR_EVENT_TYPE If you are attempting to obtain data from a non semaphore. +* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer. +* OS_ERR_PDATA_NULL If 'p_sem_data' is a NULL pointer +********************************************************************************************************* +*/ + +#if OS_SEM_QUERY_EN > 0u +INT8U OSSemQuery (OS_EVENT *pevent, + OS_SEM_DATA *p_sem_data) +{ + INT8U i; + OS_PRIO *psrc; + OS_PRIO *pdest; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#if OS_ARG_CHK_EN > 0u + if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */ + return (OS_ERR_PEVENT_NULL); + } + if (p_sem_data == (OS_SEM_DATA *)0) { /* Validate 'p_sem_data' */ + return (OS_ERR_PDATA_NULL); + } +#endif + if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event block type */ + return (OS_ERR_EVENT_TYPE); + } + OS_ENTER_CRITICAL(); + p_sem_data->OSEventGrp = pevent->OSEventGrp; /* Copy message mailbox wait list */ + psrc = &pevent->OSEventTbl[0]; + pdest = &p_sem_data->OSEventTbl[0]; + for (i = 0u; i < OS_EVENT_TBL_SIZE; i++) { + *pdest++ = *psrc++; + } + p_sem_data->OSCnt = pevent->OSEventCnt; /* Get semaphore count */ + OS_EXIT_CRITICAL(); + return (OS_ERR_NONE); +} +#endif /* OS_SEM_QUERY_EN */ + +/*$PAGE*/ +/* +********************************************************************************************************* +* SET SEMAPHORE +* +* Description: This function sets the semaphore count to the value specified as an argument. Typically, +* this value would be 0. +* +* You would typically use this function when a semaphore is used as a signaling mechanism +* and, you want to reset the count value. +* +* Arguments : pevent is a pointer to the event control block +* +* cnt is the new value for the semaphore count. You would pass 0 to reset the +* semaphore count. +* +* perr is a pointer to an error code returned by the function as follows: +* +* OS_ERR_NONE The call was successful and the semaphore value was set. +* OS_ERR_EVENT_TYPE If you didn't pass a pointer to a semaphore. +* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer. +* OS_ERR_TASK_WAITING If tasks are waiting on the semaphore. +********************************************************************************************************* +*/ + +#if OS_SEM_SET_EN > 0u +void OSSemSet (OS_EVENT *pevent, + INT16U cnt, + INT8U *perr) +{ +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#ifdef OS_SAFETY_CRITICAL + if (perr == (INT8U *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return; + } +#endif + +#if OS_ARG_CHK_EN > 0u + if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */ + *perr = OS_ERR_PEVENT_NULL; + return; + } +#endif + if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event block type */ + *perr = OS_ERR_EVENT_TYPE; + return; + } + OS_ENTER_CRITICAL(); + *perr = OS_ERR_NONE; + if (pevent->OSEventCnt > 0u) { /* See if semaphore already has a count */ + pevent->OSEventCnt = cnt; /* Yes, set it to the new value specified. */ + } else { /* No */ + if (pevent->OSEventGrp == 0u) { /* See if task(s) waiting? */ + pevent->OSEventCnt = cnt; /* No, OK to set the value */ + } else { + *perr = OS_ERR_TASK_WAITING; + } + } + OS_EXIT_CRITICAL(); +} +#endif + +#endif /* OS_SEM_EN */ diff --git a/Middlewares/Third_Party/Micrium/uCOS-II/Source/os_task.c b/Middlewares/Third_Party/Micrium/uCOS-II/Source/os_task.c new file mode 100644 index 0000000..8d11a72 --- /dev/null +++ b/Middlewares/Third_Party/Micrium/uCOS-II/Source/os_task.c @@ -0,0 +1,1343 @@ +/* +********************************************************************************************************* +* uC/OS-II +* The Real-Time Kernel +* TASK MANAGEMENT +* +* (c) Copyright 1992-2013, Micrium, Weston, FL +* All Rights Reserved +* +* File : OS_TASK.C +* By : Jean J. Labrosse +* Version : V2.92.11 +* +* LICENSING TERMS: +* --------------- +* uC/OS-II is provided in source form for FREE evaluation, for educational use or for peaceful research. +* If you plan on using uC/OS-II in a commercial product you need to contact Micrium to properly license +* its use in your product. We provide ALL the source code for your convenience and to help you experience +* uC/OS-II. The fact that the source is provided does NOT mean that you can use it without paying a +* licensing fee. +********************************************************************************************************* +*/ + +#define MICRIUM_SOURCE + +#ifndef OS_MASTER_FILE +#include +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* CHANGE PRIORITY OF A TASK +* +* Description: This function allows you to change the priority of a task dynamically. Note that the new +* priority MUST be available. +* +* Arguments : oldp is the old priority +* +* newp is the new priority +* +* Returns : OS_ERR_NONE is the call was successful +* OS_ERR_PRIO_INVALID if the priority you specify is higher that the maximum allowed +* (i.e. >= OS_LOWEST_PRIO) +* OS_ERR_PRIO_EXIST if the new priority already exist. +* OS_ERR_PRIO there is no task with the specified OLD priority (i.e. the OLD task does +* not exist. +* OS_ERR_TASK_NOT_EXIST if the task is assigned to a Mutex PIP. +********************************************************************************************************* +*/ + +#if OS_TASK_CHANGE_PRIO_EN > 0u +INT8U OSTaskChangePrio (INT8U oldprio, + INT8U newprio) +{ +#if (OS_EVENT_EN) + OS_EVENT *pevent; +#if (OS_EVENT_MULTI_EN > 0u) + OS_EVENT **pevents; +#endif +#endif + OS_TCB *ptcb; + INT8U y_new; + INT8U x_new; + INT8U y_old; + OS_PRIO bity_new; + OS_PRIO bitx_new; + OS_PRIO bity_old; + OS_PRIO bitx_old; +#if OS_CRITICAL_METHOD == 3u + OS_CPU_SR cpu_sr = 0u; /* Storage for CPU status register */ +#endif + + +/*$PAGE*/ +#if OS_ARG_CHK_EN > 0u + if (oldprio >= OS_LOWEST_PRIO) { + if (oldprio != OS_PRIO_SELF) { + return (OS_ERR_PRIO_INVALID); + } + } + if (newprio >= OS_LOWEST_PRIO) { + return (OS_ERR_PRIO_INVALID); + } +#endif + OS_ENTER_CRITICAL(); + if (OSTCBPrioTbl[newprio] != (OS_TCB *)0) { /* New priority must not already exist */ + OS_EXIT_CRITICAL(); + return (OS_ERR_PRIO_EXIST); + } + if (oldprio == OS_PRIO_SELF) { /* See if changing self */ + oldprio = OSTCBCur->OSTCBPrio; /* Yes, get priority */ + } + ptcb = OSTCBPrioTbl[oldprio]; + if (ptcb == (OS_TCB *)0) { /* Does task to change exist? */ + OS_EXIT_CRITICAL(); /* No, can't change its priority! */ + return (OS_ERR_PRIO); + } + if (ptcb == OS_TCB_RESERVED) { /* Is task assigned to Mutex */ + OS_EXIT_CRITICAL(); /* No, can't change its priority! */ + return (OS_ERR_TASK_NOT_EXIST); + } +#if OS_LOWEST_PRIO <= 63u + y_new = (INT8U)(newprio >> 3u); /* Yes, compute new TCB fields */ + x_new = (INT8U)(newprio & 0x07u); +#else + y_new = (INT8U)((INT8U)(newprio >> 4u) & 0x0Fu); + x_new = (INT8U)(newprio & 0x0Fu); +#endif + bity_new = (OS_PRIO)(1uL << y_new); + bitx_new = (OS_PRIO)(1uL << x_new); + + OSTCBPrioTbl[oldprio] = (OS_TCB *)0; /* Remove TCB from old priority */ + OSTCBPrioTbl[newprio] = ptcb; /* Place pointer to TCB @ new priority */ + y_old = ptcb->OSTCBY; + bity_old = ptcb->OSTCBBitY; + bitx_old = ptcb->OSTCBBitX; + if ((OSRdyTbl[y_old] & bitx_old) != 0u) { /* If task is ready make it not */ + OSRdyTbl[y_old] &= (OS_PRIO)~bitx_old; + if (OSRdyTbl[y_old] == 0u) { + OSRdyGrp &= (OS_PRIO)~bity_old; + } + OSRdyGrp |= bity_new; /* Make new priority ready to run */ + OSRdyTbl[y_new] |= bitx_new; + } + +#if (OS_EVENT_EN) + pevent = ptcb->OSTCBEventPtr; + if (pevent != (OS_EVENT *)0) { + pevent->OSEventTbl[y_old] &= (OS_PRIO)~bitx_old; /* Remove old task prio from wait list */ + if (pevent->OSEventTbl[y_old] == 0u) { + pevent->OSEventGrp &= (OS_PRIO)~bity_old; + } + pevent->OSEventGrp |= bity_new; /* Add new task prio to wait list */ + pevent->OSEventTbl[y_new] |= bitx_new; + } +#if (OS_EVENT_MULTI_EN > 0u) + if (ptcb->OSTCBEventMultiPtr != (OS_EVENT **)0) { + pevents = ptcb->OSTCBEventMultiPtr; + pevent = *pevents; + while (pevent != (OS_EVENT *)0) { + pevent->OSEventTbl[y_old] &= (OS_PRIO)~bitx_old; /* Remove old task prio from wait lists */ + if (pevent->OSEventTbl[y_old] == 0u) { + pevent->OSEventGrp &= (OS_PRIO)~bity_old; + } + pevent->OSEventGrp |= bity_new; /* Add new task prio to wait lists */ + pevent->OSEventTbl[y_new] |= bitx_new; + pevents++; + pevent = *pevents; + } + } +#endif +#endif + + ptcb->OSTCBPrio = newprio; /* Set new task priority */ + ptcb->OSTCBY = y_new; + ptcb->OSTCBX = x_new; + ptcb->OSTCBBitY = bity_new; + ptcb->OSTCBBitX = bitx_new; + OS_EXIT_CRITICAL(); + if (OSRunning == OS_TRUE) { + OS_Sched(); /* Find new highest priority task */ + } + return (OS_ERR_NONE); +} +#endif +/*$PAGE*/ +/* +********************************************************************************************************* +* CREATE A TASK +* +* Description: This function is used to have uC/OS-II manage the execution of a task. Tasks can either +* be created prior to the start of multitasking or by a running task. A task cannot be +* created by an ISR. +* +* Arguments : task is a pointer to the task's code +* +* p_arg is a pointer to an optional data area which can be used to pass parameters to +* the task when the task first executes. Where the task is concerned it thinks +* it was invoked and passed the argument 'p_arg' as follows: +* +* void Task (void *p_arg) +* { +* for (;;) { +* Task code; +* } +* } +* +* ptos is a pointer to the task's top of stack. If the configuration constant +* OS_STK_GROWTH is set to 1, the stack is assumed to grow downward (i.e. from high +* memory to low memory). 'pstk' will thus point to the highest (valid) memory +* location of the stack. If OS_STK_GROWTH is set to 0, 'pstk' will point to the +* lowest memory location of the stack and the stack will grow with increasing +* memory locations. +* +* prio is the task's priority. A unique priority MUST be assigned to each task and the +* lower the number, the higher the priority. +* +* Returns : OS_ERR_NONE if the function was successful. +* OS_ERR_PRIO_EXIST if the task priority already exist +* (each task MUST have a unique priority). +* OS_ERR_PRIO_INVALID if the priority you specify is higher that the maximum +* allowed (i.e. >= OS_LOWEST_PRIO) +* OS_ERR_TASK_CREATE_ISR if you tried to create a task from an ISR. +* OS_ERR_ILLEGAL_CREATE_RUN_TIME if you tried to create a task after safety critical +* operation started. +********************************************************************************************************* +*/ + +#if OS_TASK_CREATE_EN > 0u +INT8U OSTaskCreate (void (*task)(void *p_arg), + void *p_arg, + OS_STK *ptos, + INT8U prio) +{ + OS_STK *psp; + INT8U err; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#ifdef OS_SAFETY_CRITICAL_IEC61508 + if (OSSafetyCriticalStartFlag == OS_TRUE) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return (OS_ERR_ILLEGAL_CREATE_RUN_TIME); + } +#endif + +#if OS_ARG_CHK_EN > 0u + if (prio > OS_LOWEST_PRIO) { /* Make sure priority is within allowable range */ + return (OS_ERR_PRIO_INVALID); + } +#endif + OS_ENTER_CRITICAL(); + if (OSIntNesting > 0u) { /* Make sure we don't create the task from within an ISR */ + OS_EXIT_CRITICAL(); + return (OS_ERR_TASK_CREATE_ISR); + } + if (OSTCBPrioTbl[prio] == (OS_TCB *)0) { /* Make sure task doesn't already exist at this priority */ + OSTCBPrioTbl[prio] = OS_TCB_RESERVED;/* Reserve the priority to prevent others from doing ... */ + /* ... the same thing until task is created. */ + OS_EXIT_CRITICAL(); + psp = OSTaskStkInit(task, p_arg, ptos, 0u); /* Initialize the task's stack */ + err = OS_TCBInit(prio, psp, (OS_STK *)0, 0u, 0u, (void *)0, 0u); + if (err == OS_ERR_NONE) { + if (OSRunning == OS_TRUE) { /* Find highest priority task if multitasking has started */ + OS_Sched(); + } + } else { + OS_ENTER_CRITICAL(); + OSTCBPrioTbl[prio] = (OS_TCB *)0;/* Make this priority available to others */ + OS_EXIT_CRITICAL(); + } + return (err); + } + OS_EXIT_CRITICAL(); + return (OS_ERR_PRIO_EXIST); +} +#endif +/*$PAGE*/ +/* +********************************************************************************************************* +* CREATE A TASK (Extended Version) +* +* Description: This function is used to have uC/OS-II manage the execution of a task. Tasks can either +* be created prior to the start of multitasking or by a running task. A task cannot be +* created by an ISR. This function is similar to OSTaskCreate() except that it allows +* additional information about a task to be specified. +* +* Arguments : task is a pointer to the task's code +* +* p_arg is a pointer to an optional data area which can be used to pass parameters to +* the task when the task first executes. Where the task is concerned it thinks +* it was invoked and passed the argument 'p_arg' as follows: +* +* void Task (void *p_arg) +* { +* for (;;) { +* Task code; +* } +* } +* +* ptos is a pointer to the task's top of stack. If the configuration constant +* OS_STK_GROWTH is set to 1, the stack is assumed to grow downward (i.e. from high +* memory to low memory). 'ptos' will thus point to the highest (valid) memory +* location of the stack. If OS_STK_GROWTH is set to 0, 'ptos' will point to the +* lowest memory location of the stack and the stack will grow with increasing +* memory locations. 'ptos' MUST point to a valid 'free' data item. +* +* prio is the task's priority. A unique priority MUST be assigned to each task and the +* lower the number, the higher the priority. +* +* id is the task's ID (0..65535) +* +* pbos is a pointer to the task's bottom of stack. If the configuration constant +* OS_STK_GROWTH is set to 1, the stack is assumed to grow downward (i.e. from high +* memory to low memory). 'pbos' will thus point to the LOWEST (valid) memory +* location of the stack. If OS_STK_GROWTH is set to 0, 'pbos' will point to the +* HIGHEST memory location of the stack and the stack will grow with increasing +* memory locations. 'pbos' MUST point to a valid 'free' data item. +* +* stk_size is the size of the stack in number of elements. If OS_STK is set to INT8U, +* 'stk_size' corresponds to the number of bytes available. If OS_STK is set to +* INT16U, 'stk_size' contains the number of 16-bit entries available. Finally, if +* OS_STK is set to INT32U, 'stk_size' contains the number of 32-bit entries +* available on the stack. +* +* pext is a pointer to a user supplied memory location which is used as a TCB extension. +* For example, this user memory can hold the contents of floating-point registers +* during a context switch, the time each task takes to execute, the number of times +* the task has been switched-in, etc. +* +* opt contains additional information (or options) about the behavior of the task. The +* LOWER 8-bits are reserved by uC/OS-II while the upper 8 bits can be application +* specific. See OS_TASK_OPT_??? in uCOS-II.H. Current choices are: +* +* OS_TASK_OPT_STK_CHK Stack checking to be allowed for the task +* OS_TASK_OPT_STK_CLR Clear the stack when the task is created +* OS_TASK_OPT_SAVE_FP If the CPU has floating-point registers, save them +* during a context switch. +* +* Returns : OS_ERR_NONE if the function was successful. +* OS_ERR_PRIO_EXIST if the task priority already exist +* (each task MUST have a unique priority). +* OS_ERR_PRIO_INVALID if the priority you specify is higher that the maximum +* allowed (i.e. > OS_LOWEST_PRIO) +* OS_ERR_TASK_CREATE_ISR if you tried to create a task from an ISR. +* OS_ERR_ILLEGAL_CREATE_RUN_TIME if you tried to create a task after safety critical +* operation started. +********************************************************************************************************* +*/ +/*$PAGE*/ +#if OS_TASK_CREATE_EXT_EN > 0u +INT8U OSTaskCreateExt (void (*task)(void *p_arg), + void *p_arg, + OS_STK *ptos, + INT8U prio, + INT16U id, + OS_STK *pbos, + INT32U stk_size, + void *pext, + INT16U opt) +{ + OS_STK *psp; + INT8U err; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#ifdef OS_SAFETY_CRITICAL_IEC61508 + if (OSSafetyCriticalStartFlag == OS_TRUE) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return (OS_ERR_ILLEGAL_CREATE_RUN_TIME); + } +#endif + +#if OS_ARG_CHK_EN > 0u + if (prio > OS_LOWEST_PRIO) { /* Make sure priority is within allowable range */ + return (OS_ERR_PRIO_INVALID); + } +#endif + OS_ENTER_CRITICAL(); + if (OSIntNesting > 0u) { /* Make sure we don't create the task from within an ISR */ + OS_EXIT_CRITICAL(); + return (OS_ERR_TASK_CREATE_ISR); + } + if (OSTCBPrioTbl[prio] == (OS_TCB *)0) { /* Make sure task doesn't already exist at this priority */ + OSTCBPrioTbl[prio] = OS_TCB_RESERVED;/* Reserve the priority to prevent others from doing ... */ + /* ... the same thing until task is created. */ + OS_EXIT_CRITICAL(); + +#if (OS_TASK_STAT_STK_CHK_EN > 0u) + OS_TaskStkClr(pbos, stk_size, opt); /* Clear the task stack (if needed) */ +#endif + + psp = OSTaskStkInit(task, p_arg, ptos, opt); /* Initialize the task's stack */ + err = OS_TCBInit(prio, psp, pbos, id, stk_size, pext, opt); + if (err == OS_ERR_NONE) { + if (OSRunning == OS_TRUE) { /* Find HPT if multitasking has started */ + OS_Sched(); + } + } else { + OS_ENTER_CRITICAL(); + OSTCBPrioTbl[prio] = (OS_TCB *)0; /* Make this priority avail. to others */ + OS_EXIT_CRITICAL(); + } + return (err); + } + OS_EXIT_CRITICAL(); + return (OS_ERR_PRIO_EXIST); +} +#endif +/*$PAGE*/ +/* +********************************************************************************************************* +* DELETE A TASK +* +* Description: This function allows you to delete a task. The calling task can delete itself by +* its own priority number. The deleted task is returned to the dormant state and can be +* re-activated by creating the deleted task again. +* +* Arguments : prio is the priority of the task to delete. Note that you can explicitly delete +* the current task without knowing its priority level by setting 'prio' to +* OS_PRIO_SELF. +* +* Returns : OS_ERR_NONE if the call is successful +* OS_ERR_TASK_DEL_IDLE if you attempted to delete uC/OS-II's idle task +* OS_ERR_PRIO_INVALID if the priority you specify is higher that the maximum allowed +* (i.e. >= OS_LOWEST_PRIO) or, you have not specified OS_PRIO_SELF. +* OS_ERR_TASK_DEL if the task is assigned to a Mutex PIP. +* OS_ERR_TASK_NOT_EXIST if the task you want to delete does not exist. +* OS_ERR_TASK_DEL_ISR if you tried to delete a task from an ISR +* +* Notes : 1) To reduce interrupt latency, OSTaskDel() 'disables' the task: +* a) by making it not ready +* b) by removing it from any wait lists +* c) by preventing OSTimeTick() from making the task ready to run. +* The task can then be 'unlinked' from the miscellaneous structures in uC/OS-II. +* 2) The function OS_Dummy() is called after OS_EXIT_CRITICAL() because, on most processors, +* the next instruction following the enable interrupt instruction is ignored. +* 3) An ISR cannot delete a task. +* 4) The lock nesting counter is incremented because, for a brief instant, if the current +* task is being deleted, the current task would not be able to be rescheduled because it +* is removed from the ready list. Incrementing the nesting counter prevents another task +* from being schedule. This means that an ISR would return to the current task which is +* being deleted. The rest of the deletion would thus be able to be completed. +********************************************************************************************************* +*/ + +#if OS_TASK_DEL_EN > 0u +INT8U OSTaskDel (INT8U prio) +{ +#if (OS_FLAG_EN > 0u) && (OS_MAX_FLAGS > 0u) + OS_FLAG_NODE *pnode; +#endif + OS_TCB *ptcb; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + + if (OSIntNesting > 0u) { /* See if trying to delete from ISR */ + return (OS_ERR_TASK_DEL_ISR); + } + if (prio == OS_TASK_IDLE_PRIO) { /* Not allowed to delete idle task */ + return (OS_ERR_TASK_DEL_IDLE); + } +#if OS_ARG_CHK_EN > 0u + if (prio >= OS_LOWEST_PRIO) { /* Task priority valid ? */ + if (prio != OS_PRIO_SELF) { + return (OS_ERR_PRIO_INVALID); + } + } +#endif + +/*$PAGE*/ + OS_ENTER_CRITICAL(); + if (prio == OS_PRIO_SELF) { /* See if requesting to delete self */ + prio = OSTCBCur->OSTCBPrio; /* Set priority to delete to current */ + } + ptcb = OSTCBPrioTbl[prio]; + if (ptcb == (OS_TCB *)0) { /* Task to delete must exist */ + OS_EXIT_CRITICAL(); + return (OS_ERR_TASK_NOT_EXIST); + } + if (ptcb == OS_TCB_RESERVED) { /* Must not be assigned to Mutex */ + OS_EXIT_CRITICAL(); + return (OS_ERR_TASK_DEL); + } + + OSRdyTbl[ptcb->OSTCBY] &= (OS_PRIO)~ptcb->OSTCBBitX; + if (OSRdyTbl[ptcb->OSTCBY] == 0u) { /* Make task not ready */ + OSRdyGrp &= (OS_PRIO)~ptcb->OSTCBBitY; + } + +#if (OS_EVENT_EN) + if (ptcb->OSTCBEventPtr != (OS_EVENT *)0) { + OS_EventTaskRemove(ptcb, ptcb->OSTCBEventPtr); /* Remove this task from any event wait list */ + } +#if (OS_EVENT_MULTI_EN > 0u) + if (ptcb->OSTCBEventMultiPtr != (OS_EVENT **)0) { /* Remove this task from any events' wait lists*/ + OS_EventTaskRemoveMulti(ptcb, ptcb->OSTCBEventMultiPtr); + } +#endif +#endif + +#if (OS_FLAG_EN > 0u) && (OS_MAX_FLAGS > 0u) + pnode = ptcb->OSTCBFlagNode; + if (pnode != (OS_FLAG_NODE *)0) { /* If task is waiting on event flag */ + OS_FlagUnlink(pnode); /* Remove from wait list */ + } +#endif + + ptcb->OSTCBDly = 0u; /* Prevent OSTimeTick() from updating */ + ptcb->OSTCBStat = OS_STAT_RDY; /* Prevent task from being resumed */ + ptcb->OSTCBStatPend = OS_STAT_PEND_OK; + if (OSLockNesting < 255u) { /* Make sure we don't context switch */ + OSLockNesting++; + } + OS_EXIT_CRITICAL(); /* Enabling INT. ignores next instruc. */ + OS_Dummy(); /* ... Dummy ensures that INTs will be */ + OS_ENTER_CRITICAL(); /* ... disabled HERE! */ + if (OSLockNesting > 0u) { /* Remove context switch lock */ + OSLockNesting--; + } + OSTaskDelHook(ptcb); /* Call user defined hook */ + +#if OS_TASK_CREATE_EXT_EN > 0u +#if defined(OS_TLS_TBL_SIZE) && (OS_TLS_TBL_SIZE > 0u) + OS_TLS_TaskDel(ptcb); /* Call TLS hook */ +#endif +#endif + + OSTaskCtr--; /* One less task being managed */ + OSTCBPrioTbl[prio] = (OS_TCB *)0; /* Clear old priority entry */ + if (ptcb->OSTCBPrev == (OS_TCB *)0) { /* Remove from TCB chain */ + ptcb->OSTCBNext->OSTCBPrev = (OS_TCB *)0; + OSTCBList = ptcb->OSTCBNext; + } else { + ptcb->OSTCBPrev->OSTCBNext = ptcb->OSTCBNext; + ptcb->OSTCBNext->OSTCBPrev = ptcb->OSTCBPrev; + } + ptcb->OSTCBNext = OSTCBFreeList; /* Return TCB to free TCB list */ + OSTCBFreeList = ptcb; +#if OS_TASK_NAME_EN > 0u + ptcb->OSTCBTaskName = (INT8U *)(void *)"?"; +#endif + OS_EXIT_CRITICAL(); + if (OSRunning == OS_TRUE) { + OS_Sched(); /* Find new highest priority task */ + } + return (OS_ERR_NONE); +} +#endif +/*$PAGE*/ +/* +********************************************************************************************************* +* REQUEST THAT A TASK DELETE ITSELF +* +* Description: This function is used to: +* a) notify a task to delete itself. +* b) to see if a task requested that the current task delete itself. +* This function is a little tricky to understand. Basically, you have a task that needs +* to be deleted however, this task has resources that it has allocated (memory buffers, +* semaphores, mailboxes, queues etc.). The task cannot be deleted otherwise these +* resources would not be freed. The requesting task calls OSTaskDelReq() to indicate that +* the task needs to be deleted. Deleting of the task is however, deferred to the task to +* be deleted. For example, suppose that task #10 needs to be deleted. The requesting task +* example, task #5, would call OSTaskDelReq(10). When task #10 gets to execute, it calls +* this function by specifying OS_PRIO_SELF and monitors the returned value. If the return +* value is OS_ERR_TASK_DEL_REQ, another task requested a task delete. Task #10 would look like +* this: +* +* void Task(void *p_arg) +* { +* . +* . +* while (1) { +* OSTimeDly(1); +* if (OSTaskDelReq(OS_PRIO_SELF) == OS_ERR_TASK_DEL_REQ) { +* Release any owned resources; +* De-allocate any dynamic memory; +* OSTaskDel(OS_PRIO_SELF); +* } +* } +* } +* +* Arguments : prio is the priority of the task to request the delete from +* +* Returns : OS_ERR_NONE if the task exist and the request has been registered +* OS_ERR_TASK_NOT_EXIST if the task has been deleted. This allows the caller to know whether +* the request has been executed. +* OS_ERR_TASK_DEL if the task is assigned to a Mutex. +* OS_ERR_TASK_DEL_IDLE if you requested to delete uC/OS-II's idle task +* OS_ERR_PRIO_INVALID if the priority you specify is higher that the maximum allowed +* (i.e. >= OS_LOWEST_PRIO) or, you have not specified OS_PRIO_SELF. +* OS_ERR_TASK_DEL_REQ if a task (possibly another task) requested that the running task be +* deleted. +********************************************************************************************************* +*/ +/*$PAGE*/ +#if OS_TASK_DEL_EN > 0u +INT8U OSTaskDelReq (INT8U prio) +{ + INT8U stat; + OS_TCB *ptcb; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + + if (prio == OS_TASK_IDLE_PRIO) { /* Not allowed to delete idle task */ + return (OS_ERR_TASK_DEL_IDLE); + } +#if OS_ARG_CHK_EN > 0u + if (prio >= OS_LOWEST_PRIO) { /* Task priority valid ? */ + if (prio != OS_PRIO_SELF) { + return (OS_ERR_PRIO_INVALID); + } + } +#endif + if (prio == OS_PRIO_SELF) { /* See if a task is requesting to ... */ + OS_ENTER_CRITICAL(); /* ... this task to delete itself */ + stat = OSTCBCur->OSTCBDelReq; /* Return request status to caller */ + OS_EXIT_CRITICAL(); + return (stat); + } + OS_ENTER_CRITICAL(); + ptcb = OSTCBPrioTbl[prio]; + if (ptcb == (OS_TCB *)0) { /* Task to delete must exist */ + OS_EXIT_CRITICAL(); + return (OS_ERR_TASK_NOT_EXIST); /* Task must already be deleted */ + } + if (ptcb == OS_TCB_RESERVED) { /* Must NOT be assigned to a Mutex */ + OS_EXIT_CRITICAL(); + return (OS_ERR_TASK_DEL); + } + ptcb->OSTCBDelReq = OS_ERR_TASK_DEL_REQ; /* Set flag indicating task to be DEL. */ + OS_EXIT_CRITICAL(); + return (OS_ERR_NONE); +} +#endif +/*$PAGE*/ +/* +********************************************************************************************************* +* GET THE NAME OF A TASK +* +* Description: This function is called to obtain the name of a task. +* +* Arguments : prio is the priority of the task that you want to obtain the name from. +* +* pname is a pointer to a pointer to an ASCII string that will receive the name of the task. +* +* perr is a pointer to an error code that can contain one of the following values: +* +* OS_ERR_NONE if the requested task is resumed +* OS_ERR_TASK_NOT_EXIST if the task has not been created or is assigned to a Mutex +* OS_ERR_PRIO_INVALID if you specified an invalid priority: +* A higher value than the idle task or not OS_PRIO_SELF. +* OS_ERR_PNAME_NULL You passed a NULL pointer for 'pname' +* OS_ERR_NAME_GET_ISR You called this function from an ISR +* +* +* Returns : The length of the string or 0 if the task does not exist. +********************************************************************************************************* +*/ + +#if OS_TASK_NAME_EN > 0u +INT8U OSTaskNameGet (INT8U prio, + INT8U **pname, + INT8U *perr) +{ + OS_TCB *ptcb; + INT8U len; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#ifdef OS_SAFETY_CRITICAL + if (perr == (INT8U *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return (0u); + } +#endif + +#if OS_ARG_CHK_EN > 0u + if (prio > OS_LOWEST_PRIO) { /* Task priority valid ? */ + if (prio != OS_PRIO_SELF) { + *perr = OS_ERR_PRIO_INVALID; /* No */ + return (0u); + } + } + if (pname == (INT8U **)0) { /* Is 'pname' a NULL pointer? */ + *perr = OS_ERR_PNAME_NULL; /* Yes */ + return (0u); + } +#endif + if (OSIntNesting > 0u) { /* See if trying to call from an ISR */ + *perr = OS_ERR_NAME_GET_ISR; + return (0u); + } + OS_ENTER_CRITICAL(); + if (prio == OS_PRIO_SELF) { /* See if caller desires it's own name */ + prio = OSTCBCur->OSTCBPrio; + } + ptcb = OSTCBPrioTbl[prio]; + if (ptcb == (OS_TCB *)0) { /* Does task exist? */ + OS_EXIT_CRITICAL(); /* No */ + *perr = OS_ERR_TASK_NOT_EXIST; + return (0u); + } + if (ptcb == OS_TCB_RESERVED) { /* Task assigned to a Mutex? */ + OS_EXIT_CRITICAL(); /* Yes */ + *perr = OS_ERR_TASK_NOT_EXIST; + return (0u); + } + *pname = ptcb->OSTCBTaskName; + len = OS_StrLen(*pname); + OS_EXIT_CRITICAL(); + *perr = OS_ERR_NONE; + return (len); +} +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* ASSIGN A NAME TO A TASK +* +* Description: This function is used to set the name of a task. +* +* Arguments : prio is the priority of the task that you want the assign a name to. +* +* pname is a pointer to an ASCII string that contains the name of the task. +* +* perr is a pointer to an error code that can contain one of the following values: +* +* OS_ERR_NONE if the requested task is resumed +* OS_ERR_TASK_NOT_EXIST if the task has not been created or is assigned to a Mutex +* OS_ERR_PNAME_NULL You passed a NULL pointer for 'pname' +* OS_ERR_PRIO_INVALID if you specified an invalid priority: +* A higher value than the idle task or not OS_PRIO_SELF. +* OS_ERR_NAME_SET_ISR if you called this function from an ISR +* +* Returns : None +********************************************************************************************************* +*/ +#if OS_TASK_NAME_EN > 0u +void OSTaskNameSet (INT8U prio, + INT8U *pname, + INT8U *perr) +{ + OS_TCB *ptcb; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#ifdef OS_SAFETY_CRITICAL + if (perr == (INT8U *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return; + } +#endif + +#if OS_ARG_CHK_EN > 0u + if (prio > OS_LOWEST_PRIO) { /* Task priority valid ? */ + if (prio != OS_PRIO_SELF) { + *perr = OS_ERR_PRIO_INVALID; /* No */ + return; + } + } + if (pname == (INT8U *)0) { /* Is 'pname' a NULL pointer? */ + *perr = OS_ERR_PNAME_NULL; /* Yes */ + return; + } +#endif + if (OSIntNesting > 0u) { /* See if trying to call from an ISR */ + *perr = OS_ERR_NAME_SET_ISR; + return; + } + OS_ENTER_CRITICAL(); + if (prio == OS_PRIO_SELF) { /* See if caller desires to set it's own name */ + prio = OSTCBCur->OSTCBPrio; + } + ptcb = OSTCBPrioTbl[prio]; + if (ptcb == (OS_TCB *)0) { /* Does task exist? */ + OS_EXIT_CRITICAL(); /* No */ + *perr = OS_ERR_TASK_NOT_EXIST; + return; + } + if (ptcb == OS_TCB_RESERVED) { /* Task assigned to a Mutex? */ + OS_EXIT_CRITICAL(); /* Yes */ + *perr = OS_ERR_TASK_NOT_EXIST; + return; + } + ptcb->OSTCBTaskName = pname; + OS_EXIT_CRITICAL(); + *perr = OS_ERR_NONE; +} +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* RESUME A SUSPENDED TASK +* +* Description: This function is called to resume a previously suspended task. This is the only call that +* will remove an explicit task suspension. +* +* Arguments : prio is the priority of the task to resume. +* +* Returns : OS_ERR_NONE if the requested task is resumed +* OS_ERR_PRIO_INVALID if the priority you specify is higher that the maximum allowed +* (i.e. >= OS_LOWEST_PRIO) +* OS_ERR_TASK_RESUME_PRIO if the task to resume does not exist +* OS_ERR_TASK_NOT_EXIST if the task is assigned to a Mutex PIP +* OS_ERR_TASK_NOT_SUSPENDED if the task to resume has not been suspended +********************************************************************************************************* +*/ + +#if OS_TASK_SUSPEND_EN > 0u +INT8U OSTaskResume (INT8U prio) +{ + OS_TCB *ptcb; +#if OS_CRITICAL_METHOD == 3u /* Storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#if OS_ARG_CHK_EN > 0u + if (prio >= OS_LOWEST_PRIO) { /* Make sure task priority is valid */ + return (OS_ERR_PRIO_INVALID); + } +#endif + OS_ENTER_CRITICAL(); + ptcb = OSTCBPrioTbl[prio]; + if (ptcb == (OS_TCB *)0) { /* Task to suspend must exist */ + OS_EXIT_CRITICAL(); + return (OS_ERR_TASK_RESUME_PRIO); + } + if (ptcb == OS_TCB_RESERVED) { /* See if assigned to Mutex */ + OS_EXIT_CRITICAL(); + return (OS_ERR_TASK_NOT_EXIST); + } + if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) != OS_STAT_RDY) { /* Task must be suspended */ + ptcb->OSTCBStat &= (INT8U)~(INT8U)OS_STAT_SUSPEND; /* Remove suspension */ + if ((ptcb->OSTCBStat & OS_STAT_PEND_ANY) == OS_STAT_RDY) { /* See if task is now ready */ + if (ptcb->OSTCBDly == 0u) { + OSRdyGrp |= ptcb->OSTCBBitY; /* Yes, Make task ready to run */ + OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX; + OS_EXIT_CRITICAL(); + if (OSRunning == OS_TRUE) { + OS_Sched(); /* Find new highest priority task */ + } + } else { + OS_EXIT_CRITICAL(); + } + } else { /* Must be pending on event */ + OS_EXIT_CRITICAL(); + } + return (OS_ERR_NONE); + } + OS_EXIT_CRITICAL(); + return (OS_ERR_TASK_NOT_SUSPENDED); +} +#endif +/*$PAGE*/ +/* +********************************************************************************************************* +* STACK CHECKING +* +* Description: This function is called to check the amount of free memory left on the specified task's +* stack. +* +* Arguments : prio is the task priority +* +* p_stk_data is a pointer to a data structure of type OS_STK_DATA. +* +* Returns : OS_ERR_NONE upon success +* OS_ERR_PRIO_INVALID if the priority you specify is higher that the maximum allowed +* (i.e. > OS_LOWEST_PRIO) or, you have not specified OS_PRIO_SELF. +* OS_ERR_TASK_NOT_EXIST if the desired task has not been created or is assigned to a Mutex PIP +* OS_ERR_TASK_OPT if you did NOT specified OS_TASK_OPT_STK_CHK when the task was created +* OS_ERR_PDATA_NULL if 'p_stk_data' is a NULL pointer +********************************************************************************************************* +*/ +#if (OS_TASK_STAT_STK_CHK_EN > 0u) && (OS_TASK_CREATE_EXT_EN > 0u) +INT8U OSTaskStkChk (INT8U prio, + OS_STK_DATA *p_stk_data) +{ + OS_TCB *ptcb; + OS_STK *pchk; + INT32U nfree; + INT32U size; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#if OS_ARG_CHK_EN > 0u + if (prio > OS_LOWEST_PRIO) { /* Make sure task priority is valid */ + if (prio != OS_PRIO_SELF) { + return (OS_ERR_PRIO_INVALID); + } + } + if (p_stk_data == (OS_STK_DATA *)0) { /* Validate 'p_stk_data' */ + return (OS_ERR_PDATA_NULL); + } +#endif + p_stk_data->OSFree = 0u; /* Assume failure, set to 0 size */ + p_stk_data->OSUsed = 0u; + OS_ENTER_CRITICAL(); + if (prio == OS_PRIO_SELF) { /* See if check for SELF */ + prio = OSTCBCur->OSTCBPrio; + } + ptcb = OSTCBPrioTbl[prio]; + if (ptcb == (OS_TCB *)0) { /* Make sure task exist */ + OS_EXIT_CRITICAL(); + return (OS_ERR_TASK_NOT_EXIST); + } + if (ptcb == OS_TCB_RESERVED) { + OS_EXIT_CRITICAL(); + return (OS_ERR_TASK_NOT_EXIST); + } + if ((ptcb->OSTCBOpt & OS_TASK_OPT_STK_CHK) == 0u) { /* Make sure stack checking option is set */ + OS_EXIT_CRITICAL(); + return (OS_ERR_TASK_OPT); + } + nfree = 0u; + size = ptcb->OSTCBStkSize; + pchk = ptcb->OSTCBStkBottom; + OS_EXIT_CRITICAL(); +#if OS_STK_GROWTH == 1u + while (*pchk++ == (OS_STK)0) { /* Compute the number of zero entries on the stk */ + nfree++; + } +#else + while (*pchk-- == (OS_STK)0) { + nfree++; + } +#endif + p_stk_data->OSFree = nfree; /* Store number of free entries on the stk */ + p_stk_data->OSUsed = size - nfree; /* Compute number of entries used on the stk */ + return (OS_ERR_NONE); +} +#endif +/*$PAGE*/ +/* +********************************************************************************************************* +* SUSPEND A TASK +* +* Description: This function is called to suspend a task. The task can be the calling task if the +* priority passed to OSTaskSuspend() is the priority of the calling task or OS_PRIO_SELF. +* +* Arguments : prio is the priority of the task to suspend. If you specify OS_PRIO_SELF, the +* calling task will suspend itself and rescheduling will occur. +* +* Returns : OS_ERR_NONE if the requested task is suspended +* OS_ERR_TASK_SUSPEND_IDLE if you attempted to suspend the idle task which is not allowed. +* OS_ERR_PRIO_INVALID if the priority you specify is higher that the maximum allowed +* (i.e. >= OS_LOWEST_PRIO) or, you have not specified OS_PRIO_SELF. +* OS_ERR_TASK_SUSPEND_PRIO if the task to suspend does not exist +* OS_ERR_TASK_NOT_EXITS if the task is assigned to a Mutex PIP +* +* Note : You should use this function with great care. If you suspend a task that is waiting for +* an event (i.e. a message, a semaphore, a queue ...) you will prevent this task from +* running when the event arrives. +********************************************************************************************************* +*/ + +#if OS_TASK_SUSPEND_EN > 0u +INT8U OSTaskSuspend (INT8U prio) +{ + BOOLEAN self; + OS_TCB *ptcb; + INT8U y; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#if OS_ARG_CHK_EN > 0u + if (prio == OS_TASK_IDLE_PRIO) { /* Not allowed to suspend idle task */ + return (OS_ERR_TASK_SUSPEND_IDLE); + } + if (prio >= OS_LOWEST_PRIO) { /* Task priority valid ? */ + if (prio != OS_PRIO_SELF) { + return (OS_ERR_PRIO_INVALID); + } + } +#endif + OS_ENTER_CRITICAL(); + if (prio == OS_PRIO_SELF) { /* See if suspend SELF */ + prio = OSTCBCur->OSTCBPrio; + self = OS_TRUE; + } else if (prio == OSTCBCur->OSTCBPrio) { /* See if suspending self */ + self = OS_TRUE; + } else { + self = OS_FALSE; /* No suspending another task */ + } + ptcb = OSTCBPrioTbl[prio]; + if (ptcb == (OS_TCB *)0) { /* Task to suspend must exist */ + OS_EXIT_CRITICAL(); + return (OS_ERR_TASK_SUSPEND_PRIO); + } + if (ptcb == OS_TCB_RESERVED) { /* See if assigned to Mutex */ + OS_EXIT_CRITICAL(); + return (OS_ERR_TASK_NOT_EXIST); + } + y = ptcb->OSTCBY; + OSRdyTbl[y] &= (OS_PRIO)~ptcb->OSTCBBitX; /* Make task not ready */ + if (OSRdyTbl[y] == 0u) { + OSRdyGrp &= (OS_PRIO)~ptcb->OSTCBBitY; + } + ptcb->OSTCBStat |= OS_STAT_SUSPEND; /* Status of task is 'SUSPENDED' */ + OS_EXIT_CRITICAL(); + if (self == OS_TRUE) { /* Context switch only if SELF */ + OS_Sched(); /* Find new highest priority task */ + } + return (OS_ERR_NONE); +} +#endif +/*$PAGE*/ +/* +********************************************************************************************************* +* QUERY A TASK +* +* Description: This function is called to obtain a copy of the desired task's TCB. +* +* Arguments : prio is the priority of the task to obtain information from. +* +* p_task_data is a pointer to where the desired task's OS_TCB will be stored. +* +* Returns : OS_ERR_NONE if the requested task is suspended +* OS_ERR_PRIO_INVALID if the priority you specify is higher that the maximum allowed +* (i.e. > OS_LOWEST_PRIO) or, you have not specified OS_PRIO_SELF. +* OS_ERR_PRIO if the desired task has not been created +* OS_ERR_TASK_NOT_EXIST if the task is assigned to a Mutex PIP +* OS_ERR_PDATA_NULL if 'p_task_data' is a NULL pointer +********************************************************************************************************* +*/ + +#if OS_TASK_QUERY_EN > 0u +INT8U OSTaskQuery (INT8U prio, + OS_TCB *p_task_data) +{ + OS_TCB *ptcb; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + +#if OS_ARG_CHK_EN > 0u + if (prio > OS_LOWEST_PRIO) { /* Task priority valid ? */ + if (prio != OS_PRIO_SELF) { + return (OS_ERR_PRIO_INVALID); + } + } + if (p_task_data == (OS_TCB *)0) { /* Validate 'p_task_data' */ + return (OS_ERR_PDATA_NULL); + } +#endif + OS_ENTER_CRITICAL(); + if (prio == OS_PRIO_SELF) { /* See if suspend SELF */ + prio = OSTCBCur->OSTCBPrio; + } + ptcb = OSTCBPrioTbl[prio]; + if (ptcb == (OS_TCB *)0) { /* Task to query must exist */ + OS_EXIT_CRITICAL(); + return (OS_ERR_PRIO); + } + if (ptcb == OS_TCB_RESERVED) { /* Task to query must not be assigned to a Mutex */ + OS_EXIT_CRITICAL(); + return (OS_ERR_TASK_NOT_EXIST); + } + /* Copy TCB into user storage area */ + OS_MemCopy((INT8U *)p_task_data, (INT8U *)ptcb, sizeof(OS_TCB)); + OS_EXIT_CRITICAL(); + return (OS_ERR_NONE); +} +#endif +/*$PAGE*/ +/* +********************************************************************************************************* +* GET THE CURRENT VALUE OF A TASK REGISTER +* +* Description: This function is called to obtain the current value of a task register. Task registers +* are application specific and can be used to store task specific values such as 'error +* numbers' (i.e. errno), statistics, etc. Each task register can hold a 32-bit value. +* +* Arguments : prio is the priority of the task you want to get the task register from. If you +* specify OS_PRIO_SELF then the task register of the current task will be obtained. +* +* id is the 'id' of the desired task register. Note that the 'id' must be less +* than OS_TASK_REG_TBL_SIZE +* +* perr is a pointer to a variable that will hold an error code related to this call. +* +* OS_ERR_NONE if the call was successful +* OS_ERR_PRIO_INVALID if you specified an invalid priority +* OS_ERR_ID_INVALID if the 'id' is not between 0 and OS_TASK_REG_TBL_SIZE-1 +* +* Returns : The current value of the task's register or 0 if an error is detected. +* +* Note(s) : The maximum number of task variables is 254 +********************************************************************************************************* +*/ + +#if OS_TASK_REG_TBL_SIZE > 0u +INT32U OSTaskRegGet (INT8U prio, + INT8U id, + INT8U *perr) +{ +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + INT32U value; + OS_TCB *ptcb; + + + +#ifdef OS_SAFETY_CRITICAL + if (perr == (INT8U *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return (0u); + } +#endif + +#if OS_ARG_CHK_EN > 0u + if (prio >= OS_LOWEST_PRIO) { + if (prio != OS_PRIO_SELF) { + *perr = OS_ERR_PRIO_INVALID; + return (0u); + } + } + if (id >= OS_TASK_REG_TBL_SIZE) { + *perr = OS_ERR_ID_INVALID; + return (0u); + } +#endif + OS_ENTER_CRITICAL(); + if (prio == OS_PRIO_SELF) { /* See if need to get register from current task */ + ptcb = OSTCBCur; + } else { + ptcb = OSTCBPrioTbl[prio]; + } + value = ptcb->OSTCBRegTbl[id]; + OS_EXIT_CRITICAL(); + *perr = OS_ERR_NONE; + return (value); +} +#endif + +/*$PAGE*/ +/* +************************************************************************************************************************ +* ALLOCATE THE NEXT AVAILABLE TASK REGISTER ID +* +* Description: This function is called to obtain a task register ID. This function thus allows task registers IDs to be +* allocated dynamically instead of statically. +* +* Arguments : p_err is a pointer to a variable that will hold an error code related to this call. +* +* OS_ERR_NONE if the call was successful +* OS_ERR_NO_MORE_ID_AVAIL if you are attempting to assign more task register IDs than you +* have available through OS_TASK_REG_TBL_SIZE. +* +* Returns : The next available task register 'id' or OS_TASK_REG_TBL_SIZE if an error is detected. +************************************************************************************************************************ +*/ + +#if OS_TASK_REG_TBL_SIZE > 0u +INT8U OSTaskRegGetID (INT8U *perr) +{ +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + INT8U id; + + +#ifdef OS_SAFETY_CRITICAL + if (perr == (INT8U *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return ((INT8U)OS_TASK_REG_TBL_SIZE); + } +#endif + + OS_ENTER_CRITICAL(); + if (OSTaskRegNextAvailID >= OS_TASK_REG_TBL_SIZE) { /* See if we exceeded the number of IDs available */ + *perr = OS_ERR_NO_MORE_ID_AVAIL; /* Yes, cannot allocate more task register IDs */ + OS_EXIT_CRITICAL(); + return ((INT8U)OS_TASK_REG_TBL_SIZE); + } + + id = OSTaskRegNextAvailID; /* Assign the next available ID */ + OSTaskRegNextAvailID++; /* Increment available ID for next request */ + OS_EXIT_CRITICAL(); + *perr = OS_ERR_NONE; + return (id); +} +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* SET THE CURRENT VALUE OF A TASK VARIABLE +* +* Description: This function is called to change the current value of a task register. Task registers +* are application specific and can be used to store task specific values such as 'error +* numbers' (i.e. errno), statistics, etc. Each task register can hold a 32-bit value. +* +* Arguments : prio is the priority of the task you want to set the task register for. If you +* specify OS_PRIO_SELF then the task register of the current task will be obtained. +* +* id is the 'id' of the desired task register. Note that the 'id' must be less +* than OS_TASK_REG_TBL_SIZE +* +* value is the desired value for the task register. +* +* perr is a pointer to a variable that will hold an error code related to this call. +* +* OS_ERR_NONE if the call was successful +* OS_ERR_PRIO_INVALID if you specified an invalid priority +* OS_ERR_ID_INVALID if the 'id' is not between 0 and OS_TASK_REG_TBL_SIZE-1 +* +* Returns : The current value of the task's variable or 0 if an error is detected. +* +* Note(s) : The maximum number of task variables is 254 +********************************************************************************************************* +*/ + +#if OS_TASK_REG_TBL_SIZE > 0u +void OSTaskRegSet (INT8U prio, + INT8U id, + INT32U value, + INT8U *perr) +{ +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + OS_TCB *ptcb; + + +#ifdef OS_SAFETY_CRITICAL + if (perr == (INT8U *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return; + } +#endif + +#if OS_ARG_CHK_EN > 0u + if (prio >= OS_LOWEST_PRIO) { + if (prio != OS_PRIO_SELF) { + *perr = OS_ERR_PRIO_INVALID; + return; + } + } + if (id >= OS_TASK_REG_TBL_SIZE) { + *perr = OS_ERR_ID_INVALID; + return; + } +#endif + OS_ENTER_CRITICAL(); + if (prio == OS_PRIO_SELF) { /* See if need to get register from current task */ + ptcb = OSTCBCur; + } else { + ptcb = OSTCBPrioTbl[prio]; + } + ptcb->OSTCBRegTbl[id] = value; + OS_EXIT_CRITICAL(); + *perr = OS_ERR_NONE; +} +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* CATCH ACCIDENTAL TASK RETURN +* +* Description: This function is called if a task accidentally returns without deleting itself. In other +* words, a task should either be an infinite loop or delete itself if it's done. +* +* Arguments : none +* +* Returns : none +* +* Note(s) : This function is INTERNAL to uC/OS-II and your application should not call it. +********************************************************************************************************* +*/ + +void OS_TaskReturn (void) +{ + OSTaskReturnHook(OSTCBCur); /* Call hook to let user decide on what to do */ + +#if OS_TASK_DEL_EN > 0u + (void)OSTaskDel(OS_PRIO_SELF); /* Delete task if it accidentally returns! */ +#else + for (;;) { + OSTimeDly(OS_TICKS_PER_SEC); + } +#endif +} + +/*$PAGE*/ +/* +********************************************************************************************************* +* CLEAR TASK STACK +* +* Description: This function is used to clear the stack of a task (i.e. write all zeros) +* +* Arguments : pbos is a pointer to the task's bottom of stack. If the configuration constant +* OS_STK_GROWTH is set to 1, the stack is assumed to grow downward (i.e. from high +* memory to low memory). 'pbos' will thus point to the lowest (valid) memory +* location of the stack. If OS_STK_GROWTH is set to 0, 'pbos' will point to the +* highest memory location of the stack and the stack will grow with increasing +* memory locations. 'pbos' MUST point to a valid 'free' data item. +* +* size is the number of 'stack elements' to clear. +* +* opt contains additional information (or options) about the behavior of the task. The +* LOWER 8-bits are reserved by uC/OS-II while the upper 8 bits can be application +* specific. See OS_TASK_OPT_??? in uCOS-II.H. +* +* Returns : none +********************************************************************************************************* +*/ +#if (OS_TASK_STAT_STK_CHK_EN > 0u) && (OS_TASK_CREATE_EXT_EN > 0u) +void OS_TaskStkClr (OS_STK *pbos, + INT32U size, + INT16U opt) +{ + if ((opt & OS_TASK_OPT_STK_CHK) != 0x0000u) { /* See if stack checking has been enabled */ + if ((opt & OS_TASK_OPT_STK_CLR) != 0x0000u) { /* See if stack needs to be cleared */ +#if OS_STK_GROWTH == 1u + while (size > 0u) { /* Stack grows from HIGH to LOW memory */ + size--; + *pbos++ = (OS_STK)0; /* Clear from bottom of stack and up! */ + } +#else + while (size > 0u) { /* Stack grows from LOW to HIGH memory */ + size--; + *pbos-- = (OS_STK)0; /* Clear from bottom of stack and down */ + } +#endif + } + } +} + +#endif diff --git a/Middlewares/Third_Party/Micrium/uCOS-II/Source/os_time.c b/Middlewares/Third_Party/Micrium/uCOS-II/Source/os_time.c new file mode 100644 index 0000000..d3a9a11 --- /dev/null +++ b/Middlewares/Third_Party/Micrium/uCOS-II/Source/os_time.c @@ -0,0 +1,265 @@ +/* +********************************************************************************************************* +* uC/OS-II +* The Real-Time Kernel +* TIME MANAGEMENT +* +* (c) Copyright 1992-2013, Micrium, Weston, FL +* All Rights Reserved +* +* File : OS_TIME.C +* By : Jean J. Labrosse +* Version : V2.92.11 +* +* LICENSING TERMS: +* --------------- +* uC/OS-II is provided in source form for FREE evaluation, for educational use or for peaceful research. +* If you plan on using uC/OS-II in a commercial product you need to contact Micrium to properly license +* its use in your product. We provide ALL the source code for your convenience and to help you experience +* uC/OS-II. The fact that the source is provided does NOT mean that you can use it without paying a +* licensing fee. +********************************************************************************************************* +*/ + +#define MICRIUM_SOURCE + +#ifndef OS_MASTER_FILE +#include +#endif + +/* +********************************************************************************************************* +* DELAY TASK 'n' TICKS +* +* Description: This function is called to delay execution of the currently running task until the +* specified number of system ticks expires. This, of course, directly equates to delaying +* the current task for some time to expire. No delay will result If the specified delay is +* 0. If the specified delay is greater than 0 then, a context switch will result. +* +* Arguments : ticks is the time delay that the task will be suspended in number of clock 'ticks'. +* Note that by specifying 0, the task will not be delayed. +* +* Returns : none +********************************************************************************************************* +*/ + +void OSTimeDly (INT32U ticks) +{ + INT8U y; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + + if (OSIntNesting > 0u) { /* See if trying to call from an ISR */ + return; + } + if (OSLockNesting > 0u) { /* See if called with scheduler locked */ + return; + } + if (ticks > 0u) { /* 0 means no delay! */ + OS_ENTER_CRITICAL(); + y = OSTCBCur->OSTCBY; /* Delay current task */ + OSRdyTbl[y] &= (OS_PRIO)~OSTCBCur->OSTCBBitX; + if (OSRdyTbl[y] == 0u) { + OSRdyGrp &= (OS_PRIO)~OSTCBCur->OSTCBBitY; + } + OSTCBCur->OSTCBDly = ticks; /* Load ticks in TCB */ + OS_EXIT_CRITICAL(); + OS_Sched(); /* Find next task to run! */ + } +} +/*$PAGE*/ +/* +********************************************************************************************************* +* DELAY TASK FOR SPECIFIED TIME +* +* Description: This function is called to delay execution of the currently running task until some time +* expires. This call allows you to specify the delay time in HOURS, MINUTES, SECONDS and +* MILLISECONDS instead of ticks. +* +* Arguments : hours specifies the number of hours that the task will be delayed (max. is 255) +* minutes specifies the number of minutes (max. 59) +* seconds specifies the number of seconds (max. 59) +* ms specifies the number of milliseconds (max. 999) +* +* Returns : OS_ERR_NONE +* OS_ERR_TIME_INVALID_MINUTES +* OS_ERR_TIME_INVALID_SECONDS +* OS_ERR_TIME_INVALID_MS +* OS_ERR_TIME_ZERO_DLY +* OS_ERR_TIME_DLY_ISR +* +* Note(s) : The resolution on the milliseconds depends on the tick rate. For example, you can't do +* a 10 mS delay if the ticker interrupts every 100 mS. In this case, the delay would be +* set to 0. The actual delay is rounded to the nearest tick. +********************************************************************************************************* +*/ + +#if OS_TIME_DLY_HMSM_EN > 0u +INT8U OSTimeDlyHMSM (INT8U hours, + INT8U minutes, + INT8U seconds, + INT16U ms) +{ + INT32U ticks; + + + if (OSIntNesting > 0u) { /* See if trying to call from an ISR */ + return (OS_ERR_TIME_DLY_ISR); + } + if (OSLockNesting > 0u) { /* See if called with scheduler locked */ + return (OS_ERR_SCHED_LOCKED); + } +#if OS_ARG_CHK_EN > 0u + if (hours == 0u) { + if (minutes == 0u) { + if (seconds == 0u) { + if (ms == 0u) { + return (OS_ERR_TIME_ZERO_DLY); + } + } + } + } + if (minutes > 59u) { + return (OS_ERR_TIME_INVALID_MINUTES); /* Validate arguments to be within range */ + } + if (seconds > 59u) { + return (OS_ERR_TIME_INVALID_SECONDS); + } + if (ms > 999u) { + return (OS_ERR_TIME_INVALID_MS); + } +#endif + /* Compute the total number of clock ticks required.. */ + /* .. (rounded to the nearest tick) */ + ticks = ((INT32U)hours * 3600uL + (INT32U)minutes * 60uL + (INT32U)seconds) * OS_TICKS_PER_SEC + + OS_TICKS_PER_SEC * ((INT32U)ms + 500uL / OS_TICKS_PER_SEC) / 1000uL; + OSTimeDly(ticks); + return (OS_ERR_NONE); +} +#endif +/*$PAGE*/ +/* +********************************************************************************************************* +* RESUME A DELAYED TASK +* +* Description: This function is used resume a task that has been delayed through a call to either +* OSTimeDly() or OSTimeDlyHMSM(). Note that you can call this function to resume a +* task that is waiting for an event with timeout. This would make the task look +* like a timeout occurred. +* +* Arguments : prio specifies the priority of the task to resume +* +* Returns : OS_ERR_NONE Task has been resumed +* OS_ERR_PRIO_INVALID if the priority you specify is higher that the maximum allowed +* (i.e. >= OS_LOWEST_PRIO) +* OS_ERR_TIME_NOT_DLY Task is not waiting for time to expire +* OS_ERR_TASK_NOT_EXIST The desired task has not been created or has been assigned to a Mutex. +********************************************************************************************************* +*/ + +#if OS_TIME_DLY_RESUME_EN > 0u +INT8U OSTimeDlyResume (INT8U prio) +{ + OS_TCB *ptcb; +#if OS_CRITICAL_METHOD == 3u /* Storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + + if (prio >= OS_LOWEST_PRIO) { + return (OS_ERR_PRIO_INVALID); + } + OS_ENTER_CRITICAL(); + ptcb = OSTCBPrioTbl[prio]; /* Make sure that task exist */ + if (ptcb == (OS_TCB *)0) { + OS_EXIT_CRITICAL(); + return (OS_ERR_TASK_NOT_EXIST); /* The task does not exist */ + } + if (ptcb == OS_TCB_RESERVED) { + OS_EXIT_CRITICAL(); + return (OS_ERR_TASK_NOT_EXIST); /* The task does not exist */ + } + if (ptcb->OSTCBDly == 0u) { /* See if task is delayed */ + OS_EXIT_CRITICAL(); + return (OS_ERR_TIME_NOT_DLY); /* Indicate that task was not delayed */ + } + + ptcb->OSTCBDly = 0u; /* Clear the time delay */ + if ((ptcb->OSTCBStat & OS_STAT_PEND_ANY) != OS_STAT_RDY) { + ptcb->OSTCBStat &= ~OS_STAT_PEND_ANY; /* Yes, Clear status flag */ + ptcb->OSTCBStatPend = OS_STAT_PEND_TO; /* Indicate PEND timeout */ + } else { + ptcb->OSTCBStatPend = OS_STAT_PEND_OK; + } + if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) == OS_STAT_RDY) { /* Is task suspended? */ + OSRdyGrp |= ptcb->OSTCBBitY; /* No, Make ready */ + OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX; + OS_EXIT_CRITICAL(); + OS_Sched(); /* See if this is new highest priority */ + } else { + OS_EXIT_CRITICAL(); /* Task may be suspended */ + } + return (OS_ERR_NONE); +} +#endif +/*$PAGE*/ +/* +********************************************************************************************************* +* GET CURRENT SYSTEM TIME +* +* Description: This function is used by your application to obtain the current value of the 32-bit +* counter which keeps track of the number of clock ticks. +* +* Arguments : none +* +* Returns : The current value of OSTime +********************************************************************************************************* +*/ + +#if OS_TIME_GET_SET_EN > 0u +INT32U OSTimeGet (void) +{ + INT32U ticks; +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + + OS_ENTER_CRITICAL(); + ticks = OSTime; + OS_EXIT_CRITICAL(); + return (ticks); +} +#endif + +/* +********************************************************************************************************* +* SET SYSTEM CLOCK +* +* Description: This function sets the 32-bit counter which keeps track of the number of clock ticks. +* +* Arguments : ticks specifies the new value that OSTime needs to take. +* +* Returns : none +********************************************************************************************************* +*/ + +#if OS_TIME_GET_SET_EN > 0u +void OSTimeSet (INT32U ticks) +{ +#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ + OS_CPU_SR cpu_sr = 0u; +#endif + + + + OS_ENTER_CRITICAL(); + OSTime = ticks; + OS_EXIT_CRITICAL(); +} +#endif diff --git a/Middlewares/Third_Party/Micrium/uCOS-II/Source/os_tmr.c b/Middlewares/Third_Party/Micrium/uCOS-II/Source/os_tmr.c new file mode 100644 index 0000000..7d1b48c --- /dev/null +++ b/Middlewares/Third_Party/Micrium/uCOS-II/Source/os_tmr.c @@ -0,0 +1,1089 @@ +/* +********************************************************************************************************* +* uC/OS-II +* The Real-Time Kernel +* TIMER MANAGEMENT +* +* (c) Copyright 1992-2013, Micrium, Weston, FL +* All Rights Reserved +* +* +* File : OS_TMR.C +* By : Jean J. Labrosse +* Version : V2.92.11 +* +* LICENSING TERMS: +* --------------- +* uC/OS-II is provided in source form for FREE evaluation, for educational use or for peaceful research. +* If you plan on using uC/OS-II in a commercial product you need to contact Micrium to properly license +* its use in your product. We provide ALL the source code for your convenience and to help you experience +* uC/OS-II. The fact that the source is provided does NOT mean that you can use it without paying a +* licensing fee. +********************************************************************************************************* +*/ + +#define MICRIUM_SOURCE + +#ifndef OS_MASTER_FILE +#include +#endif + +/* +********************************************************************************************************* +* NOTES +* +* 1) Your application MUST define the following #define constants: +* +* OS_TASK_TMR_PRIO The priority of the Timer management task +* OS_TASK_TMR_STK_SIZE The size of the Timer management task's stack +* +* 2) You must call OSTmrSignal() to notify the Timer management task that it's time to update the timers. +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* CONSTANTS +********************************************************************************************************* +*/ + +#define OS_TMR_LINK_DLY 0u +#define OS_TMR_LINK_PERIODIC 1u + +/* +********************************************************************************************************* +* LOCAL PROTOTYPES +********************************************************************************************************* +*/ + +#if OS_TMR_EN > 0u +static OS_TMR *OSTmr_Alloc (void); +static void OSTmr_Free (OS_TMR *ptmr); +static void OSTmr_InitTask (void); +static void OSTmr_Link (OS_TMR *ptmr, INT8U type); +static void OSTmr_Unlink (OS_TMR *ptmr); +static void OSTmr_Task (void *p_arg); +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* CREATE A TIMER +* +* Description: This function is called by your application code to create a timer. +* +* Arguments : dly Initial delay. +* If the timer is configured for ONE-SHOT mode, this is the timeout used. +* If the timer is configured for PERIODIC mode, this is the first timeout to +* wait for before the timer starts entering periodic mode. +* +* period The 'period' being repeated for the timer. +* If you specified 'OS_TMR_OPT_PERIODIC' as an option, when the timer +* expires, it will automatically restart with the same period. +* +* opt Specifies either: +* OS_TMR_OPT_ONE_SHOT The timer counts down only once +* OS_TMR_OPT_PERIODIC The timer counts down and then reloads itself +* +* callback Is a pointer to a callback function that will be called when the timer expires. +* The callback function must be declared as follows: +* +* void MyCallback (OS_TMR *ptmr, void *p_arg); +* +* callback_arg Is an argument (a pointer) that is passed to the callback function when it is called. +* +* pname Is a pointer to an ASCII string that is used to name the timer. Names are +* useful for debugging. +* +* perr Is a pointer to an error code. '*perr' will contain one of the following: +* OS_ERR_NONE +* OS_ERR_TMR_INVALID_DLY you specified an invalid delay +* OS_ERR_TMR_INVALID_PERIOD you specified an invalid period +* OS_ERR_TMR_INVALID_OPT you specified an invalid option +* OS_ERR_TMR_ISR if the call was made from an ISR +* OS_ERR_TMR_NON_AVAIL if there are no free timers from the timer pool +* +* Returns : A pointer to an OS_TMR data structure. +* This is the 'handle' that your application will use to reference the timer created. +********************************************************************************************************* +*/ + +#if OS_TMR_EN > 0u +OS_TMR *OSTmrCreate (INT32U dly, + INT32U period, + INT8U opt, + OS_TMR_CALLBACK callback, + void *callback_arg, + INT8U *pname, + INT8U *perr) +{ + OS_TMR *ptmr; + + +#ifdef OS_SAFETY_CRITICAL + if (perr == (INT8U *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return ((OS_TMR *)0); + } +#endif + +#ifdef OS_SAFETY_CRITICAL_IEC61508 + if (OSSafetyCriticalStartFlag == OS_TRUE) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return ((OS_TMR *)0); + } +#endif + +#if OS_ARG_CHK_EN > 0u + switch (opt) { /* Validate arguments */ + case OS_TMR_OPT_PERIODIC: + if (period == 0u) { + *perr = OS_ERR_TMR_INVALID_PERIOD; + return ((OS_TMR *)0); + } + break; + + case OS_TMR_OPT_ONE_SHOT: + if (dly == 0u) { + *perr = OS_ERR_TMR_INVALID_DLY; + return ((OS_TMR *)0); + } + break; + + default: + *perr = OS_ERR_TMR_INVALID_OPT; + return ((OS_TMR *)0); + } +#endif + if (OSIntNesting > 0u) { /* See if trying to call from an ISR */ + *perr = OS_ERR_TMR_ISR; + return ((OS_TMR *)0); + } + OSSchedLock(); + ptmr = OSTmr_Alloc(); /* Obtain a timer from the free pool */ + if (ptmr == (OS_TMR *)0) { + OSSchedUnlock(); + *perr = OS_ERR_TMR_NON_AVAIL; + return ((OS_TMR *)0); + } + ptmr->OSTmrState = OS_TMR_STATE_STOPPED; /* Indicate that timer is not running yet */ + ptmr->OSTmrDly = dly; + ptmr->OSTmrPeriod = period; + ptmr->OSTmrOpt = opt; + ptmr->OSTmrCallback = callback; + ptmr->OSTmrCallbackArg = callback_arg; +#if OS_TMR_CFG_NAME_EN > 0u + if (pname == (INT8U *)0) { /* Is 'pname' a NULL pointer? */ + ptmr->OSTmrName = (INT8U *)(void *)"?"; + } else { + ptmr->OSTmrName = pname; + } +#endif + OSSchedUnlock(); + *perr = OS_ERR_NONE; + return (ptmr); +} +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* DELETE A TIMER +* +* Description: This function is called by your application code to delete a timer. +* +* Arguments : ptmr Is a pointer to the timer to stop and delete. +* +* perr Is a pointer to an error code. '*perr' will contain one of the following: +* OS_ERR_NONE +* OS_ERR_TMR_INVALID 'ptmr' is a NULL pointer +* OS_ERR_TMR_INVALID_TYPE 'ptmr' is not pointing to an OS_TMR +* OS_ERR_TMR_ISR if the function was called from an ISR +* OS_ERR_TMR_INACTIVE if the timer was not created +* OS_ERR_TMR_INVALID_STATE the timer is in an invalid state +* +* Returns : OS_TRUE If the call was successful +* OS_FALSE If not +********************************************************************************************************* +*/ + +#if OS_TMR_EN > 0u +BOOLEAN OSTmrDel (OS_TMR *ptmr, + INT8U *perr) +{ +#ifdef OS_SAFETY_CRITICAL + if (perr == (INT8U *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return (OS_FALSE); + } +#endif + +#if OS_ARG_CHK_EN > 0u + if (ptmr == (OS_TMR *)0) { + *perr = OS_ERR_TMR_INVALID; + return (OS_FALSE); + } +#endif + if (ptmr->OSTmrType != OS_TMR_TYPE) { /* Validate timer structure */ + *perr = OS_ERR_TMR_INVALID_TYPE; + return (OS_FALSE); + } + if (OSIntNesting > 0u) { /* See if trying to call from an ISR */ + *perr = OS_ERR_TMR_ISR; + return (OS_FALSE); + } + OSSchedLock(); + switch (ptmr->OSTmrState) { + case OS_TMR_STATE_RUNNING: + OSTmr_Unlink(ptmr); /* Remove from current wheel spoke */ + OSTmr_Free(ptmr); /* Return timer to free list of timers */ + OSSchedUnlock(); + *perr = OS_ERR_NONE; + return (OS_TRUE); + + case OS_TMR_STATE_STOPPED: /* Timer has not started or ... */ + case OS_TMR_STATE_COMPLETED: /* ... timer has completed the ONE-SHOT time */ + OSTmr_Free(ptmr); /* Return timer to free list of timers */ + OSSchedUnlock(); + *perr = OS_ERR_NONE; + return (OS_TRUE); + + case OS_TMR_STATE_UNUSED: /* Already deleted */ + OSSchedUnlock(); + *perr = OS_ERR_TMR_INACTIVE; + return (OS_FALSE); + + default: + OSSchedUnlock(); + *perr = OS_ERR_TMR_INVALID_STATE; + return (OS_FALSE); + } +} +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* GET THE NAME OF A TIMER +* +* Description: This function is called to obtain the name of a timer. +* +* Arguments : ptmr Is a pointer to the timer to obtain the name for +* +* pdest Is a pointer to pointer to where the name of the timer will be placed. +* +* perr Is a pointer to an error code. '*perr' will contain one of the following: +* OS_ERR_NONE The call was successful +* OS_ERR_TMR_INVALID_DEST 'pdest' is a NULL pointer +* OS_ERR_TMR_INVALID 'ptmr' is a NULL pointer +* OS_ERR_TMR_INVALID_TYPE 'ptmr' is not pointing to an OS_TMR +* OS_ERR_NAME_GET_ISR if the call was made from an ISR +* OS_ERR_TMR_INACTIVE 'ptmr' points to a timer that is not active +* OS_ERR_TMR_INVALID_STATE the timer is in an invalid state +* +* Returns : The length of the string or 0 if the timer does not exist. +********************************************************************************************************* +*/ + +#if OS_TMR_EN > 0u && OS_TMR_CFG_NAME_EN > 0u +INT8U OSTmrNameGet (OS_TMR *ptmr, + INT8U **pdest, + INT8U *perr) +{ + INT8U len; + + +#ifdef OS_SAFETY_CRITICAL + if (perr == (INT8U *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return (0u); + } +#endif + +#if OS_ARG_CHK_EN > 0u + if (pdest == (INT8U **)0) { + *perr = OS_ERR_TMR_INVALID_DEST; + return (0u); + } + if (ptmr == (OS_TMR *)0) { + *perr = OS_ERR_TMR_INVALID; + return (0u); + } +#endif + if (ptmr->OSTmrType != OS_TMR_TYPE) { /* Validate timer structure */ + *perr = OS_ERR_TMR_INVALID_TYPE; + return (0u); + } + if (OSIntNesting > 0u) { /* See if trying to call from an ISR */ + *perr = OS_ERR_NAME_GET_ISR; + return (0u); + } + OSSchedLock(); + switch (ptmr->OSTmrState) { + case OS_TMR_STATE_RUNNING: + case OS_TMR_STATE_STOPPED: + case OS_TMR_STATE_COMPLETED: + *pdest = ptmr->OSTmrName; + len = OS_StrLen(*pdest); + OSSchedUnlock(); + *perr = OS_ERR_NONE; + return (len); + + case OS_TMR_STATE_UNUSED: /* Timer is not allocated */ + OSSchedUnlock(); + *perr = OS_ERR_TMR_INACTIVE; + return (0u); + + default: + OSSchedUnlock(); + *perr = OS_ERR_TMR_INVALID_STATE; + return (0u); + } +} +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* GET HOW MUCH TIME IS LEFT BEFORE A TIMER EXPIRES +* +* Description: This function is called to get the number of ticks before a timer times out. +* +* Arguments : ptmr Is a pointer to the timer to obtain the remaining time from. +* +* perr Is a pointer to an error code. '*perr' will contain one of the following: +* OS_ERR_NONE +* OS_ERR_TMR_INVALID 'ptmr' is a NULL pointer +* OS_ERR_TMR_INVALID_TYPE 'ptmr' is not pointing to an OS_TMR +* OS_ERR_TMR_ISR if the call was made from an ISR +* OS_ERR_TMR_INACTIVE 'ptmr' points to a timer that is not active +* OS_ERR_TMR_INVALID_STATE the timer is in an invalid state +* +* Returns : The time remaining for the timer to expire. The time represents 'timer' increments. +* In other words, if OSTmr_Task() is signaled every 1/10 of a second then the returned +* value represents the number of 1/10 of a second remaining before the timer expires. +********************************************************************************************************* +*/ + +#if OS_TMR_EN > 0u +INT32U OSTmrRemainGet (OS_TMR *ptmr, + INT8U *perr) +{ + INT32U remain; + + +#ifdef OS_SAFETY_CRITICAL + if (perr == (INT8U *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return (0u); + } +#endif + +#if OS_ARG_CHK_EN > 0u + if (ptmr == (OS_TMR *)0) { + *perr = OS_ERR_TMR_INVALID; + return (0u); + } +#endif + if (ptmr->OSTmrType != OS_TMR_TYPE) { /* Validate timer structure */ + *perr = OS_ERR_TMR_INVALID_TYPE; + return (0u); + } + if (OSIntNesting > 0u) { /* See if trying to call from an ISR */ + *perr = OS_ERR_TMR_ISR; + return (0u); + } + OSSchedLock(); + switch (ptmr->OSTmrState) { + case OS_TMR_STATE_RUNNING: + remain = ptmr->OSTmrMatch - OSTmrTime; /* Determine how much time is left to timeout */ + OSSchedUnlock(); + *perr = OS_ERR_NONE; + return (remain); + + case OS_TMR_STATE_STOPPED: /* It's assumed that the timer has not started yet */ + switch (ptmr->OSTmrOpt) { + case OS_TMR_OPT_PERIODIC: + if (ptmr->OSTmrDly == 0u) { + remain = ptmr->OSTmrPeriod; + } else { + remain = ptmr->OSTmrDly; + } + OSSchedUnlock(); + *perr = OS_ERR_NONE; + break; + + case OS_TMR_OPT_ONE_SHOT: + default: + remain = ptmr->OSTmrDly; + OSSchedUnlock(); + *perr = OS_ERR_NONE; + break; + } + return (remain); + + case OS_TMR_STATE_COMPLETED: /* Only ONE-SHOT that timed out can be in this state */ + OSSchedUnlock(); + *perr = OS_ERR_NONE; + return (0u); + + case OS_TMR_STATE_UNUSED: + OSSchedUnlock(); + *perr = OS_ERR_TMR_INACTIVE; + return (0u); + + default: + OSSchedUnlock(); + *perr = OS_ERR_TMR_INVALID_STATE; + return (0u); + } +} +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* FIND OUT WHAT STATE A TIMER IS IN +* +* Description: This function is called to determine what state the timer is in: +* +* OS_TMR_STATE_UNUSED the timer has not been created +* OS_TMR_STATE_STOPPED the timer has been created but has not been started or has been stopped +* OS_TMR_STATE_COMPLETED the timer is in ONE-SHOT mode and has completed it's timeout +* OS_TMR_STATE_RUNNING the timer is currently running +* +* Arguments : ptmr Is a pointer to the desired timer +* +* perr Is a pointer to an error code. '*perr' will contain one of the following: +* OS_ERR_NONE +* OS_ERR_TMR_INVALID 'ptmr' is a NULL pointer +* OS_ERR_TMR_INVALID_TYPE 'ptmr' is not pointing to an OS_TMR +* OS_ERR_TMR_ISR if the call was made from an ISR +* OS_ERR_TMR_INACTIVE 'ptmr' points to a timer that is not active +* OS_ERR_TMR_INVALID_STATE if the timer is not in a valid state +* +* Returns : The current state of the timer (see description). +********************************************************************************************************* +*/ + +#if OS_TMR_EN > 0u +INT8U OSTmrStateGet (OS_TMR *ptmr, + INT8U *perr) +{ + INT8U state; + + +#ifdef OS_SAFETY_CRITICAL + if (perr == (INT8U *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return (0u); + } +#endif + +#if OS_ARG_CHK_EN > 0u + if (ptmr == (OS_TMR *)0) { + *perr = OS_ERR_TMR_INVALID; + return (0u); + } +#endif + if (ptmr->OSTmrType != OS_TMR_TYPE) { /* Validate timer structure */ + *perr = OS_ERR_TMR_INVALID_TYPE; + return (0u); + } + if (OSIntNesting > 0u) { /* See if trying to call from an ISR */ + *perr = OS_ERR_TMR_ISR; + return (0u); + } + OSSchedLock(); + state = ptmr->OSTmrState; + switch (state) { + case OS_TMR_STATE_UNUSED: + case OS_TMR_STATE_STOPPED: + case OS_TMR_STATE_COMPLETED: + case OS_TMR_STATE_RUNNING: + *perr = OS_ERR_NONE; + break; + + default: + *perr = OS_ERR_TMR_INVALID_STATE; + break; + } + OSSchedUnlock(); + return (state); +} +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* START A TIMER +* +* Description: This function is called by your application code to start a timer. +* +* Arguments : ptmr Is a pointer to an OS_TMR +* +* perr Is a pointer to an error code. '*perr' will contain one of the following: +* OS_ERR_NONE +* OS_ERR_TMR_INVALID +* OS_ERR_TMR_INVALID_TYPE 'ptmr' is not pointing to an OS_TMR +* OS_ERR_TMR_ISR if the call was made from an ISR +* OS_ERR_TMR_INACTIVE if the timer was not created +* OS_ERR_TMR_INVALID_STATE the timer is in an invalid state +* +* Returns : OS_TRUE if the timer was started +* OS_FALSE if an error was detected +********************************************************************************************************* +*/ + +#if OS_TMR_EN > 0u +BOOLEAN OSTmrStart (OS_TMR *ptmr, + INT8U *perr) +{ +#ifdef OS_SAFETY_CRITICAL + if (perr == (INT8U *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return (OS_FALSE); + } +#endif + +#if OS_ARG_CHK_EN > 0u + if (ptmr == (OS_TMR *)0) { + *perr = OS_ERR_TMR_INVALID; + return (OS_FALSE); + } +#endif + if (ptmr->OSTmrType != OS_TMR_TYPE) { /* Validate timer structure */ + *perr = OS_ERR_TMR_INVALID_TYPE; + return (OS_FALSE); + } + if (OSIntNesting > 0u) { /* See if trying to call from an ISR */ + *perr = OS_ERR_TMR_ISR; + return (OS_FALSE); + } + OSSchedLock(); + switch (ptmr->OSTmrState) { + case OS_TMR_STATE_RUNNING: /* Restart the timer */ + OSTmr_Unlink(ptmr); /* ... Stop the timer */ + OSTmr_Link(ptmr, OS_TMR_LINK_DLY); /* ... Link timer to timer wheel */ + OSSchedUnlock(); + *perr = OS_ERR_NONE; + return (OS_TRUE); + + case OS_TMR_STATE_STOPPED: /* Start the timer */ + case OS_TMR_STATE_COMPLETED: + OSTmr_Link(ptmr, OS_TMR_LINK_DLY); /* ... Link timer to timer wheel */ + OSSchedUnlock(); + *perr = OS_ERR_NONE; + return (OS_TRUE); + + case OS_TMR_STATE_UNUSED: /* Timer not created */ + OSSchedUnlock(); + *perr = OS_ERR_TMR_INACTIVE; + return (OS_FALSE); + + default: + OSSchedUnlock(); + *perr = OS_ERR_TMR_INVALID_STATE; + return (OS_FALSE); + } +} +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* STOP A TIMER +* +* Description: This function is called by your application code to stop a timer. +* +* Arguments : ptmr Is a pointer to the timer to stop. +* +* opt Allows you to specify an option to this functions which can be: +* +* OS_TMR_OPT_NONE Do nothing special but stop the timer +* OS_TMR_OPT_CALLBACK Execute the callback function, pass it the +* callback argument specified when the timer +* was created. +* OS_TMR_OPT_CALLBACK_ARG Execute the callback function, pass it the +* callback argument specified in THIS function call. +* +* callback_arg Is a pointer to a 'new' callback argument that can be passed to the callback +* function instead of the timer's callback argument. In other words, use +* 'callback_arg' passed in THIS function INSTEAD of ptmr->OSTmrCallbackArg. +* +* perr Is a pointer to an error code. '*perr' will contain one of the following: +* OS_ERR_NONE +* OS_ERR_TMR_INVALID 'ptmr' is a NULL pointer +* OS_ERR_TMR_INVALID_TYPE 'ptmr' is not pointing to an OS_TMR +* OS_ERR_TMR_ISR if the function was called from an ISR +* OS_ERR_TMR_INACTIVE if the timer was not created +* OS_ERR_TMR_INVALID_OPT if you specified an invalid option for 'opt' +* OS_ERR_TMR_STOPPED if the timer was already stopped +* OS_ERR_TMR_INVALID_STATE the timer is in an invalid state +* OS_ERR_TMR_NO_CALLBACK if the timer does not have a callback function defined +* +* Returns : OS_TRUE If we stopped the timer (if the timer is already stopped, we also return OS_TRUE) +* OS_FALSE If not +********************************************************************************************************* +*/ + +#if OS_TMR_EN > 0u +BOOLEAN OSTmrStop (OS_TMR *ptmr, + INT8U opt, + void *callback_arg, + INT8U *perr) +{ + OS_TMR_CALLBACK pfnct; + + +#ifdef OS_SAFETY_CRITICAL + if (perr == (INT8U *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return (OS_FALSE); + } +#endif + +#if OS_ARG_CHK_EN > 0u + if (ptmr == (OS_TMR *)0) { + *perr = OS_ERR_TMR_INVALID; + return (OS_FALSE); + } +#endif + if (ptmr->OSTmrType != OS_TMR_TYPE) { /* Validate timer structure */ + *perr = OS_ERR_TMR_INVALID_TYPE; + return (OS_FALSE); + } + if (OSIntNesting > 0u) { /* See if trying to call from an ISR */ + *perr = OS_ERR_TMR_ISR; + return (OS_FALSE); + } + OSSchedLock(); + switch (ptmr->OSTmrState) { + case OS_TMR_STATE_RUNNING: + OSTmr_Unlink(ptmr); /* Remove from current wheel spoke */ + *perr = OS_ERR_NONE; + switch (opt) { + case OS_TMR_OPT_CALLBACK: + pfnct = ptmr->OSTmrCallback; /* Execute callback function if available ... */ + if (pfnct != (OS_TMR_CALLBACK)0) { + (*pfnct)((void *)ptmr, ptmr->OSTmrCallbackArg); /* Use callback arg when timer was created */ + } else { + *perr = OS_ERR_TMR_NO_CALLBACK; + } + break; + + case OS_TMR_OPT_CALLBACK_ARG: + pfnct = ptmr->OSTmrCallback; /* Execute callback function if available ... */ + if (pfnct != (OS_TMR_CALLBACK)0) { + (*pfnct)((void *)ptmr, callback_arg); /* ... using the 'callback_arg' provided in call */ + } else { + *perr = OS_ERR_TMR_NO_CALLBACK; + } + break; + + case OS_TMR_OPT_NONE: + break; + + default: + *perr = OS_ERR_TMR_INVALID_OPT; + break; + } + OSSchedUnlock(); + return (OS_TRUE); + + case OS_TMR_STATE_COMPLETED: /* Timer has already completed the ONE-SHOT or ... */ + case OS_TMR_STATE_STOPPED: /* ... timer has not started yet. */ + OSSchedUnlock(); + *perr = OS_ERR_TMR_STOPPED; + return (OS_TRUE); + + case OS_TMR_STATE_UNUSED: /* Timer was not created */ + OSSchedUnlock(); + *perr = OS_ERR_TMR_INACTIVE; + return (OS_FALSE); + + default: + OSSchedUnlock(); + *perr = OS_ERR_TMR_INVALID_STATE; + return (OS_FALSE); + } +} +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* SIGNAL THAT IT'S TIME TO UPDATE THE TIMERS +* +* Description: This function is typically called by the ISR that occurs at the timer tick rate and is +* used to signal to OSTmr_Task() that it's time to update the timers. +* +* Arguments : none +* +* Returns : OS_ERR_NONE The call was successful and the timer task was signaled. +* OS_ERR_SEM_OVF If OSTmrSignal() was called more often than OSTmr_Task() can handle +* the timers. This would indicate that your system is heavily loaded. +* OS_ERR_EVENT_TYPE Unlikely you would get this error because the semaphore used for +* signaling is created by uC/OS-II. +* OS_ERR_PEVENT_NULL Again, unlikely you would ever get this error because the semaphore +* used for signaling is created by uC/OS-II. +********************************************************************************************************* +*/ + +#if OS_TMR_EN > 0u +INT8U OSTmrSignal (void) +{ + INT8U err; + + + err = OSSemPost(OSTmrSemSignal); + return (err); +} +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* ALLOCATE AND FREE A TIMER +* +* Description: This function is called to allocate a timer. +* +* Arguments : none +* +* Returns : a pointer to a timer if one is available +********************************************************************************************************* +*/ + +#if OS_TMR_EN > 0u +static OS_TMR *OSTmr_Alloc (void) +{ + OS_TMR *ptmr; + + + if (OSTmrFreeList == (OS_TMR *)0) { + return ((OS_TMR *)0); + } + ptmr = (OS_TMR *)OSTmrFreeList; + OSTmrFreeList = (OS_TMR *)ptmr->OSTmrNext; + ptmr->OSTmrNext = (OS_TCB *)0; + ptmr->OSTmrPrev = (OS_TCB *)0; + OSTmrUsed++; + OSTmrFree--; + return (ptmr); +} +#endif + + +/* +********************************************************************************************************* +* RETURN A TIMER TO THE FREE LIST +* +* Description: This function is called to return a timer object to the free list of timers. +* +* Arguments : ptmr is a pointer to the timer to free +* +* Returns : none +********************************************************************************************************* +*/ + +#if OS_TMR_EN > 0u +static void OSTmr_Free (OS_TMR *ptmr) +{ + ptmr->OSTmrState = OS_TMR_STATE_UNUSED; /* Clear timer object fields */ + ptmr->OSTmrOpt = OS_TMR_OPT_NONE; + ptmr->OSTmrPeriod = 0u; + ptmr->OSTmrMatch = 0u; + ptmr->OSTmrCallback = (OS_TMR_CALLBACK)0; + ptmr->OSTmrCallbackArg = (void *)0; +#if OS_TMR_CFG_NAME_EN > 0u + ptmr->OSTmrName = (INT8U *)(void *)"?"; +#endif + + ptmr->OSTmrPrev = (OS_TCB *)0; /* Chain timer to free list */ + ptmr->OSTmrNext = OSTmrFreeList; + OSTmrFreeList = ptmr; + + OSTmrUsed--; /* Update timer object statistics */ + OSTmrFree++; +} +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* INITIALIZATION +* INITIALIZE THE FREE LIST OF TIMERS +* +* Description: This function is called by OSInit() to initialize the free list of OS_TMRs. +* +* Arguments : none +* +* Returns : none +********************************************************************************************************* +*/ + +#if OS_TMR_EN > 0u +void OSTmr_Init (void) +{ +#if OS_EVENT_NAME_EN > 0u + INT8U err; +#endif + INT16U ix; + INT16U ix_next; + OS_TMR *ptmr1; + OS_TMR *ptmr2; + + + OS_MemClr((INT8U *)&OSTmrTbl[0], sizeof(OSTmrTbl)); /* Clear all the TMRs */ + OS_MemClr((INT8U *)&OSTmrWheelTbl[0], sizeof(OSTmrWheelTbl)); /* Clear the timer wheel */ + + for (ix = 0u; ix < (OS_TMR_CFG_MAX - 1u); ix++) { /* Init. list of free TMRs */ + ix_next = ix + 1u; + ptmr1 = &OSTmrTbl[ix]; + ptmr2 = &OSTmrTbl[ix_next]; + ptmr1->OSTmrType = OS_TMR_TYPE; + ptmr1->OSTmrState = OS_TMR_STATE_UNUSED; /* Indicate that timer is inactive */ + ptmr1->OSTmrNext = (void *)ptmr2; /* Link to next timer */ +#if OS_TMR_CFG_NAME_EN > 0u + ptmr1->OSTmrName = (INT8U *)(void *)"?"; +#endif + } + ptmr1 = &OSTmrTbl[ix]; + ptmr1->OSTmrType = OS_TMR_TYPE; + ptmr1->OSTmrState = OS_TMR_STATE_UNUSED; /* Indicate that timer is inactive */ + ptmr1->OSTmrNext = (void *)0; /* Last OS_TMR */ +#if OS_TMR_CFG_NAME_EN > 0u + ptmr1->OSTmrName = (INT8U *)(void *)"?"; +#endif + OSTmrTime = 0u; + OSTmrUsed = 0u; + OSTmrFree = OS_TMR_CFG_MAX; + OSTmrFreeList = &OSTmrTbl[0]; + OSTmrSem = OSSemCreate(1u); + OSTmrSemSignal = OSSemCreate(0u); + +#if OS_EVENT_NAME_EN > 0u /* Assign names to semaphores */ + OSEventNameSet(OSTmrSem, (INT8U *)(void *)"uC/OS-II TmrLock", &err); + OSEventNameSet(OSTmrSemSignal, (INT8U *)(void *)"uC/OS-II TmrSignal", &err); +#endif + + OSTmr_InitTask(); +} +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* INITIALIZE THE TIMER MANAGEMENT TASK +* +* Description: This function is called by OSTmrInit() to create the timer management task. +* * Arguments : none +* +* Returns : none +********************************************************************************************************* +*/ + +#if OS_TMR_EN > 0u +static void OSTmr_InitTask (void) +{ +#if OS_TASK_NAME_EN > 0u + INT8U err; +#endif + + +#if OS_TASK_CREATE_EXT_EN > 0u + #if OS_STK_GROWTH == 1u + (void)OSTaskCreateExt(OSTmr_Task, + (void *)0, /* No arguments passed to OSTmrTask() */ + &OSTmrTaskStk[OS_TASK_TMR_STK_SIZE - 1u], /* Set Top-Of-Stack */ + OS_TASK_TMR_PRIO, + OS_TASK_TMR_ID, + &OSTmrTaskStk[0], /* Set Bottom-Of-Stack */ + OS_TASK_TMR_STK_SIZE, + (void *)0, /* No TCB extension */ + OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR); /* Enable stack checking + clear stack */ + #else + (void)OSTaskCreateExt(OSTmr_Task, + (void *)0, /* No arguments passed to OSTmrTask() */ + &OSTmrTaskStk[0], /* Set Top-Of-Stack */ + OS_TASK_TMR_PRIO, + OS_TASK_TMR_ID, + &OSTmrTaskStk[OS_TASK_TMR_STK_SIZE - 1u], /* Set Bottom-Of-Stack */ + OS_TASK_TMR_STK_SIZE, + (void *)0, /* No TCB extension */ + OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR); /* Enable stack checking + clear stack */ + #endif +#else + #if OS_STK_GROWTH == 1u + (void)OSTaskCreate(OSTmr_Task, + (void *)0, + &OSTmrTaskStk[OS_TASK_TMR_STK_SIZE - 1u], + OS_TASK_TMR_PRIO); + #else + (void)OSTaskCreate(OSTmr_Task, + (void *)0, + &OSTmrTaskStk[0], + OS_TASK_TMR_PRIO); + #endif +#endif + +#if OS_TASK_NAME_EN > 0u + OSTaskNameSet(OS_TASK_TMR_PRIO, (INT8U *)(void *)"uC/OS-II Tmr", &err); +#endif +} +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* INSERT A TIMER INTO THE TIMER WHEEL +* +* Description: This function is called to insert the timer into the timer wheel. The timer is always +* inserted at the beginning of the list. +* +* Arguments : ptmr Is a pointer to the timer to insert. +* +* type Is either: +* OS_TMR_LINK_PERIODIC Means to re-insert the timer after a period expired +* OS_TMR_LINK_DLY Means to insert the timer the first time +* +* Returns : none +********************************************************************************************************* +*/ + +#if OS_TMR_EN > 0u +static void OSTmr_Link (OS_TMR *ptmr, + INT8U type) +{ + OS_TMR *ptmr1; + OS_TMR_WHEEL *pspoke; + INT16U spoke; + + + ptmr->OSTmrState = OS_TMR_STATE_RUNNING; + if (type == OS_TMR_LINK_PERIODIC) { /* Determine when timer will expire */ + ptmr->OSTmrMatch = ptmr->OSTmrPeriod + OSTmrTime; + } else { + if (ptmr->OSTmrDly == 0u) { + ptmr->OSTmrMatch = ptmr->OSTmrPeriod + OSTmrTime; + } else { + ptmr->OSTmrMatch = ptmr->OSTmrDly + OSTmrTime; + } + } + spoke = (INT16U)(ptmr->OSTmrMatch % OS_TMR_CFG_WHEEL_SIZE); + pspoke = &OSTmrWheelTbl[spoke]; + + if (pspoke->OSTmrFirst == (OS_TMR *)0) { /* Link into timer wheel */ + pspoke->OSTmrFirst = ptmr; + ptmr->OSTmrNext = (OS_TMR *)0; + pspoke->OSTmrEntries = 1u; + } else { + ptmr1 = pspoke->OSTmrFirst; /* Point to first timer in the spoke */ + pspoke->OSTmrFirst = ptmr; + ptmr->OSTmrNext = (void *)ptmr1; + ptmr1->OSTmrPrev = (void *)ptmr; + pspoke->OSTmrEntries++; + } + ptmr->OSTmrPrev = (void *)0; /* Timer always inserted as first node in list */ +} +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* REMOVE A TIMER FROM THE TIMER WHEEL +* +* Description: This function is called to remove the timer from the timer wheel. +* +* Arguments : ptmr Is a pointer to the timer to remove. +* +* Returns : none +********************************************************************************************************* +*/ + +#if OS_TMR_EN > 0u +static void OSTmr_Unlink (OS_TMR *ptmr) +{ + OS_TMR *ptmr1; + OS_TMR *ptmr2; + OS_TMR_WHEEL *pspoke; + INT16U spoke; + + + spoke = (INT16U)(ptmr->OSTmrMatch % OS_TMR_CFG_WHEEL_SIZE); + pspoke = &OSTmrWheelTbl[spoke]; + + if (pspoke->OSTmrFirst == ptmr) { /* See if timer to remove is at the beginning of list */ + ptmr1 = (OS_TMR *)ptmr->OSTmrNext; + pspoke->OSTmrFirst = (OS_TMR *)ptmr1; + if (ptmr1 != (OS_TMR *)0) { + ptmr1->OSTmrPrev = (void *)0; + } + } else { + ptmr1 = (OS_TMR *)ptmr->OSTmrPrev; /* Remove timer from somewhere in the list */ + ptmr2 = (OS_TMR *)ptmr->OSTmrNext; + ptmr1->OSTmrNext = ptmr2; + if (ptmr2 != (OS_TMR *)0) { + ptmr2->OSTmrPrev = (void *)ptmr1; + } + } + ptmr->OSTmrState = OS_TMR_STATE_STOPPED; + ptmr->OSTmrNext = (void *)0; + ptmr->OSTmrPrev = (void *)0; + pspoke->OSTmrEntries--; +} +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* TIMER MANAGEMENT TASK +* +* Description: This task is created by OSTmrInit(). +* +* Arguments : none +* +* Returns : none +********************************************************************************************************* +*/ + +#if OS_TMR_EN > 0u +static void OSTmr_Task (void *p_arg) +{ + INT8U err; + OS_TMR *ptmr; + OS_TMR *ptmr_next; + OS_TMR_CALLBACK pfnct; + OS_TMR_WHEEL *pspoke; + INT16U spoke; + + + p_arg = p_arg; /* Prevent compiler warning for not using 'p_arg' */ + for (;;) { + OSSemPend(OSTmrSemSignal, 0u, &err); /* Wait for signal indicating time to update timers */ + OSSchedLock(); + OSTmrTime++; /* Increment the current time */ + spoke = (INT16U)(OSTmrTime % OS_TMR_CFG_WHEEL_SIZE); /* Position on current timer wheel entry */ + pspoke = &OSTmrWheelTbl[spoke]; + ptmr = pspoke->OSTmrFirst; + while (ptmr != (OS_TMR *)0) { + ptmr_next = (OS_TMR *)ptmr->OSTmrNext; /* Point to next timer to update because current ... */ + /* ... timer could get unlinked from the wheel. */ + if (OSTmrTime == ptmr->OSTmrMatch) { /* Process each timer that expires */ + OSTmr_Unlink(ptmr); /* Remove from current wheel spoke */ + if (ptmr->OSTmrOpt == OS_TMR_OPT_PERIODIC) { + OSTmr_Link(ptmr, OS_TMR_LINK_PERIODIC); /* Recalculate new position of timer in wheel */ + } else { + ptmr->OSTmrState = OS_TMR_STATE_COMPLETED; /* Indicate that the timer has completed */ + } + pfnct = ptmr->OSTmrCallback; /* Execute callback function if available */ + if (pfnct != (OS_TMR_CALLBACK)0) { + (*pfnct)((void *)ptmr, ptmr->OSTmrCallbackArg); + } + } + ptmr = ptmr_next; + } + OSSchedUnlock(); + } +} +#endif diff --git a/Middlewares/Third_Party/Micrium/uCOS-II/Source/ucos_ii.h b/Middlewares/Third_Party/Micrium/uCOS-II/Source/ucos_ii.h new file mode 100644 index 0000000..8fc083a --- /dev/null +++ b/Middlewares/Third_Party/Micrium/uCOS-II/Source/ucos_ii.h @@ -0,0 +1,1982 @@ +/* +********************************************************************************************************* +* uC/OS-II +* The Real-Time Kernel +* +* (c) Copyright 1992-2013, Micrium, Weston, FL +* All Rights Reserved +* +* File : uCOS_II.H +* By : Jean J. Labrosse +* Version : V2.92.11 +* +* LICENSING TERMS: +* --------------- +* uC/OS-II is provided in source form for FREE evaluation, for educational use or for peaceful research. +* If you plan on using uC/OS-II in a commercial product you need to contact Micrium to properly license +* its use in your product. We provide ALL the source code for your convenience and to help you experience +* uC/OS-II. The fact that the source is provided does NOT mean that you can use it without paying a +* licensing fee. +********************************************************************************************************* +*/ + +#ifndef OS_uCOS_II_H +#define OS_uCOS_II_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* +********************************************************************************************************* +* uC/OS-II VERSION NUMBER +********************************************************************************************************* +*/ + +#define OS_VERSION 29211u /* Version of uC/OS-II (Vx.yy mult. by 10000) */ + +/* +********************************************************************************************************* +* INCLUDE HEADER FILES +********************************************************************************************************* +*/ + +#include +#include +#include + +/* +********************************************************************************************************* +* MISCELLANEOUS +********************************************************************************************************* +*/ + +#ifdef OS_GLOBALS +#define OS_EXT +#else +#define OS_EXT extern +#endif + +#ifndef OS_FALSE +#define OS_FALSE 0u +#endif + +#ifndef OS_TRUE +#define OS_TRUE 1u +#endif + +#define OS_ASCII_NUL (INT8U)0 + +#define OS_PRIO_SELF 0xFFu /* Indicate SELF priority */ +#define OS_PRIO_MUTEX_CEIL_DIS 0xFFu /* Disable mutex priority ceiling promotion */ + +#if OS_TASK_STAT_EN > 0u +#define OS_N_SYS_TASKS 2u /* Number of system tasks */ +#else +#define OS_N_SYS_TASKS 1u +#endif + +#define OS_TASK_STAT_PRIO (OS_LOWEST_PRIO - 1u) /* Statistic task priority */ +#define OS_TASK_IDLE_PRIO (OS_LOWEST_PRIO) /* IDLE task priority */ + +#if OS_LOWEST_PRIO <= 63u +#define OS_EVENT_TBL_SIZE ((OS_LOWEST_PRIO) / 8u + 1u) /* Size of event table */ +#define OS_RDY_TBL_SIZE ((OS_LOWEST_PRIO) / 8u + 1u) /* Size of ready table */ +#else +#define OS_EVENT_TBL_SIZE ((OS_LOWEST_PRIO) / 16u + 1u)/* Size of event table */ +#define OS_RDY_TBL_SIZE ((OS_LOWEST_PRIO) / 16u + 1u)/* Size of ready table */ +#endif + +#define OS_TASK_IDLE_ID 65535u /* ID numbers for Idle, Stat and Timer tasks */ +#define OS_TASK_STAT_ID 65534u +#define OS_TASK_TMR_ID 65533u + +#define OS_EVENT_EN (((OS_Q_EN > 0u) && (OS_MAX_QS > 0u)) || (OS_MBOX_EN > 0u) || (OS_SEM_EN > 0u) || (OS_MUTEX_EN > 0u)) + +#define OS_TCB_RESERVED ((OS_TCB *)1) + +/*$PAGE*/ +/* +********************************************************************************************************* +* TASK STATUS (Bit definition for OSTCBStat) +********************************************************************************************************* +*/ +#define OS_STAT_RDY 0x00u /* Ready to run */ +#define OS_STAT_SEM 0x01u /* Pending on semaphore */ +#define OS_STAT_MBOX 0x02u /* Pending on mailbox */ +#define OS_STAT_Q 0x04u /* Pending on queue */ +#define OS_STAT_SUSPEND 0x08u /* Task is suspended */ +#define OS_STAT_MUTEX 0x10u /* Pending on mutual exclusion semaphore */ +#define OS_STAT_FLAG 0x20u /* Pending on event flag group */ +#define OS_STAT_MULTI 0x80u /* Pending on multiple events */ + +#define OS_STAT_PEND_ANY (OS_STAT_SEM | OS_STAT_MBOX | OS_STAT_Q | OS_STAT_MUTEX | OS_STAT_FLAG) + +/* +********************************************************************************************************* +* TASK PEND STATUS (Status codes for OSTCBStatPend) +********************************************************************************************************* +*/ +#define OS_STAT_PEND_OK 0u /* Pending status OK, not pending, or pending complete */ +#define OS_STAT_PEND_TO 1u /* Pending timed out */ +#define OS_STAT_PEND_ABORT 2u /* Pending aborted */ + +/* +********************************************************************************************************* +* OS_EVENT types +********************************************************************************************************* +*/ +#define OS_EVENT_TYPE_UNUSED 0u +#define OS_EVENT_TYPE_MBOX 1u +#define OS_EVENT_TYPE_Q 2u +#define OS_EVENT_TYPE_SEM 3u +#define OS_EVENT_TYPE_MUTEX 4u +#define OS_EVENT_TYPE_FLAG 5u + +#define OS_TMR_TYPE 100u /* Used to identify Timers ... */ + /* ... (Must be different value than OS_EVENT_TYPE_xxx) */ + +/* +********************************************************************************************************* +* EVENT FLAGS +********************************************************************************************************* +*/ +#define OS_FLAG_WAIT_CLR_ALL 0u /* Wait for ALL the bits specified to be CLR (i.e. 0) */ +#define OS_FLAG_WAIT_CLR_AND 0u + +#define OS_FLAG_WAIT_CLR_ANY 1u /* Wait for ANY of the bits specified to be CLR (i.e. 0) */ +#define OS_FLAG_WAIT_CLR_OR 1u + +#define OS_FLAG_WAIT_SET_ALL 2u /* Wait for ALL the bits specified to be SET (i.e. 1) */ +#define OS_FLAG_WAIT_SET_AND 2u + +#define OS_FLAG_WAIT_SET_ANY 3u /* Wait for ANY of the bits specified to be SET (i.e. 1) */ +#define OS_FLAG_WAIT_SET_OR 3u + + +#define OS_FLAG_CONSUME 0x80u /* Consume the flags if condition(s) satisfied */ + + +#define OS_FLAG_CLR 0u +#define OS_FLAG_SET 1u + +/* +********************************************************************************************************* +* Values for OSTickStepState +* +* Note(s): This feature is used by uC/OS-View. +********************************************************************************************************* +*/ + +#if OS_TICK_STEP_EN > 0u +#define OS_TICK_STEP_DIS 0u /* Stepping is disabled, tick runs as normal */ +#define OS_TICK_STEP_WAIT 1u /* Waiting for uC/OS-View to set OSTickStepState to _ONCE */ +#define OS_TICK_STEP_ONCE 2u /* Process tick once and wait for next cmd from uC/OS-View */ +#endif + +/* +********************************************************************************************************* +* Possible values for 'opt' argument of OSSemDel(), OSMboxDel(), OSQDel() and OSMutexDel() +********************************************************************************************************* +*/ +#define OS_DEL_NO_PEND 0u +#define OS_DEL_ALWAYS 1u + +/* +********************************************************************************************************* +* OS???Pend() OPTIONS +* +* These #defines are used to establish the options for OS???PendAbort(). +********************************************************************************************************* +*/ +#define OS_PEND_OPT_NONE 0u /* NO option selected */ +#define OS_PEND_OPT_BROADCAST 1u /* Broadcast action to ALL tasks waiting */ + +/* +********************************************************************************************************* +* OS???PostOpt() OPTIONS +* +* These #defines are used to establish the options for OSMboxPostOpt() and OSQPostOpt(). +********************************************************************************************************* +*/ +#define OS_POST_OPT_NONE 0x00u /* NO option selected */ +#define OS_POST_OPT_BROADCAST 0x01u /* Broadcast message to ALL tasks waiting */ +#define OS_POST_OPT_FRONT 0x02u /* Post to highest priority task waiting */ +#define OS_POST_OPT_NO_SCHED 0x04u /* Do not call the scheduler if this option is selected */ + +/* +********************************************************************************************************* +* TASK OPTIONS (see OSTaskCreateExt()) +********************************************************************************************************* +*/ +#define OS_TASK_OPT_NONE 0x0000u /* NO option selected */ +#define OS_TASK_OPT_STK_CHK 0x0001u /* Enable stack checking for the task */ +#define OS_TASK_OPT_STK_CLR 0x0002u /* Clear the stack when the task is create */ +#define OS_TASK_OPT_SAVE_FP 0x0004u /* Save the contents of any floating-point registers */ +#define OS_TASK_OPT_NO_TLS 0x0008u /* Specify that task doesn't needs TLS */ + +/* +********************************************************************************************************* +* TIMER OPTIONS (see OSTmrStart() and OSTmrStop()) +********************************************************************************************************* +*/ +#define OS_TMR_OPT_NONE 0u /* No option selected */ + +#define OS_TMR_OPT_ONE_SHOT 1u /* Timer will not automatically restart when it expires */ +#define OS_TMR_OPT_PERIODIC 2u /* Timer will automatically restart when it expires */ + +#define OS_TMR_OPT_CALLBACK 3u /* OSTmrStop() option to call 'callback' w/ timer arg. */ +#define OS_TMR_OPT_CALLBACK_ARG 4u /* OSTmrStop() option to call 'callback' w/ new arg. */ + +/* +********************************************************************************************************* +* TIMER STATES +********************************************************************************************************* +*/ +#define OS_TMR_STATE_UNUSED 0u +#define OS_TMR_STATE_STOPPED 1u +#define OS_TMR_STATE_COMPLETED 2u +#define OS_TMR_STATE_RUNNING 3u + +/* +********************************************************************************************************* +* ERROR CODES +********************************************************************************************************* +*/ +#define OS_ERR_NONE 0u + +#define OS_ERR_EVENT_TYPE 1u +#define OS_ERR_PEND_ISR 2u +#define OS_ERR_POST_NULL_PTR 3u +#define OS_ERR_PEVENT_NULL 4u +#define OS_ERR_POST_ISR 5u +#define OS_ERR_QUERY_ISR 6u +#define OS_ERR_INVALID_OPT 7u +#define OS_ERR_ID_INVALID 8u +#define OS_ERR_PDATA_NULL 9u + +#define OS_ERR_TIMEOUT 10u +#define OS_ERR_EVENT_NAME_TOO_LONG 11u +#define OS_ERR_PNAME_NULL 12u +#define OS_ERR_PEND_LOCKED 13u +#define OS_ERR_PEND_ABORT 14u +#define OS_ERR_DEL_ISR 15u +#define OS_ERR_CREATE_ISR 16u +#define OS_ERR_NAME_GET_ISR 17u +#define OS_ERR_NAME_SET_ISR 18u +#define OS_ERR_ILLEGAL_CREATE_RUN_TIME 19u + +#define OS_ERR_MBOX_FULL 20u + +#define OS_ERR_Q_FULL 30u +#define OS_ERR_Q_EMPTY 31u + +#define OS_ERR_PRIO_EXIST 40u +#define OS_ERR_PRIO 41u +#define OS_ERR_PRIO_INVALID 42u + +#define OS_ERR_SCHED_LOCKED 50u +#define OS_ERR_SEM_OVF 51u + +#define OS_ERR_TASK_CREATE_ISR 60u +#define OS_ERR_TASK_DEL 61u +#define OS_ERR_TASK_DEL_IDLE 62u +#define OS_ERR_TASK_DEL_REQ 63u +#define OS_ERR_TASK_DEL_ISR 64u +#define OS_ERR_TASK_NAME_TOO_LONG 65u +#define OS_ERR_TASK_NO_MORE_TCB 66u +#define OS_ERR_TASK_NOT_EXIST 67u +#define OS_ERR_TASK_NOT_SUSPENDED 68u +#define OS_ERR_TASK_OPT 69u +#define OS_ERR_TASK_RESUME_PRIO 70u +#define OS_ERR_TASK_SUSPEND_IDLE 71u +#define OS_ERR_TASK_SUSPEND_PRIO 72u +#define OS_ERR_TASK_WAITING 73u + +#define OS_ERR_TIME_NOT_DLY 80u +#define OS_ERR_TIME_INVALID_MINUTES 81u +#define OS_ERR_TIME_INVALID_SECONDS 82u +#define OS_ERR_TIME_INVALID_MS 83u +#define OS_ERR_TIME_ZERO_DLY 84u +#define OS_ERR_TIME_DLY_ISR 85u + +#define OS_ERR_MEM_INVALID_PART 90u +#define OS_ERR_MEM_INVALID_BLKS 91u +#define OS_ERR_MEM_INVALID_SIZE 92u +#define OS_ERR_MEM_NO_FREE_BLKS 93u +#define OS_ERR_MEM_FULL 94u +#define OS_ERR_MEM_INVALID_PBLK 95u +#define OS_ERR_MEM_INVALID_PMEM 96u +#define OS_ERR_MEM_INVALID_PDATA 97u +#define OS_ERR_MEM_INVALID_ADDR 98u +#define OS_ERR_MEM_NAME_TOO_LONG 99u + +#define OS_ERR_NOT_MUTEX_OWNER 100u + +#define OS_ERR_FLAG_INVALID_PGRP 110u +#define OS_ERR_FLAG_WAIT_TYPE 111u +#define OS_ERR_FLAG_NOT_RDY 112u +#define OS_ERR_FLAG_INVALID_OPT 113u +#define OS_ERR_FLAG_GRP_DEPLETED 114u +#define OS_ERR_FLAG_NAME_TOO_LONG 115u + +#define OS_ERR_PCP_LOWER 120u + +#define OS_ERR_TMR_INVALID_DLY 130u +#define OS_ERR_TMR_INVALID_PERIOD 131u +#define OS_ERR_TMR_INVALID_OPT 132u +#define OS_ERR_TMR_INVALID_NAME 133u +#define OS_ERR_TMR_NON_AVAIL 134u +#define OS_ERR_TMR_INACTIVE 135u +#define OS_ERR_TMR_INVALID_DEST 136u +#define OS_ERR_TMR_INVALID_TYPE 137u +#define OS_ERR_TMR_INVALID 138u +#define OS_ERR_TMR_ISR 139u +#define OS_ERR_TMR_NAME_TOO_LONG 140u +#define OS_ERR_TMR_INVALID_STATE 141u +#define OS_ERR_TMR_STOPPED 142u +#define OS_ERR_TMR_NO_CALLBACK 143u + +#define OS_ERR_NO_MORE_ID_AVAIL 150u + +#define OS_ERR_TLS_NO_MORE_AVAIL 160u +#define OS_ERR_TLS_ID_INVALID 161u +#define OS_ERR_TLS_NOT_EN 162u +#define OS_ERR_TLS_DESTRUCT_ASSIGNED 163u +#define OS_ERR_OS_NOT_RUNNING 164u + +/*$PAGE*/ +/* +********************************************************************************************************* +* THREAD LOCAL STORAGE (TLS) +********************************************************************************************************* +*/ + +#if OS_TASK_CREATE_EXT_EN > 0u +#if defined(OS_TLS_TBL_SIZE) && (OS_TLS_TBL_SIZE > 0u) +typedef void *OS_TLS; + +typedef INT8U OS_TLS_ID; +#endif +#endif + +/* +********************************************************************************************************* +* EVENT CONTROL BLOCK +********************************************************************************************************* +*/ + +#if OS_LOWEST_PRIO <= 63u +typedef INT8U OS_PRIO; +#else +typedef INT16U OS_PRIO; +#endif + +#if (OS_EVENT_EN) && (OS_MAX_EVENTS > 0u) +typedef struct os_event { + INT8U OSEventType; /* Type of event control block (see OS_EVENT_TYPE_xxxx) */ + void *OSEventPtr; /* Pointer to message or queue structure */ + INT16U OSEventCnt; /* Semaphore Count (not used if other EVENT type) */ + OS_PRIO OSEventGrp; /* Group corresponding to tasks waiting for event to occur */ + OS_PRIO OSEventTbl[OS_EVENT_TBL_SIZE]; /* List of tasks waiting for event to occur */ + +#if OS_EVENT_NAME_EN > 0u + INT8U *OSEventName; +#endif +} OS_EVENT; +#endif + + +/* +********************************************************************************************************* +* EVENT FLAGS CONTROL BLOCK +********************************************************************************************************* +*/ + +#if (OS_FLAG_EN > 0u) && (OS_MAX_FLAGS > 0u) + +#if OS_FLAGS_NBITS == 8u /* Determine the size of OS_FLAGS (8, 16 or 32 bits) */ +typedef INT8U OS_FLAGS; +#endif + +#if OS_FLAGS_NBITS == 16u +typedef INT16U OS_FLAGS; +#endif + +#if OS_FLAGS_NBITS == 32u +typedef INT32U OS_FLAGS; +#endif + + +typedef struct os_flag_grp { /* Event Flag Group */ + INT8U OSFlagType; /* Should be set to OS_EVENT_TYPE_FLAG */ + void *OSFlagWaitList; /* Pointer to first NODE of task waiting on event flag */ + OS_FLAGS OSFlagFlags; /* 8, 16 or 32 bit flags */ +#if OS_FLAG_NAME_EN > 0u + INT8U *OSFlagName; +#endif +} OS_FLAG_GRP; + + + +typedef struct os_flag_node { /* Event Flag Wait List Node */ + void *OSFlagNodeNext; /* Pointer to next NODE in wait list */ + void *OSFlagNodePrev; /* Pointer to previous NODE in wait list */ + void *OSFlagNodeTCB; /* Pointer to TCB of waiting task */ + void *OSFlagNodeFlagGrp; /* Pointer to Event Flag Group */ + OS_FLAGS OSFlagNodeFlags; /* Event flag to wait on */ + INT8U OSFlagNodeWaitType; /* Type of wait: */ + /* OS_FLAG_WAIT_AND */ + /* OS_FLAG_WAIT_ALL */ + /* OS_FLAG_WAIT_OR */ + /* OS_FLAG_WAIT_ANY */ +} OS_FLAG_NODE; +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* MESSAGE MAILBOX DATA +********************************************************************************************************* +*/ + +#if OS_MBOX_EN > 0u +typedef struct os_mbox_data { + void *OSMsg; /* Pointer to message in mailbox */ + OS_PRIO OSEventTbl[OS_EVENT_TBL_SIZE]; /* List of tasks waiting for event to occur */ + OS_PRIO OSEventGrp; /* Group corresponding to tasks waiting for event to occur */ +} OS_MBOX_DATA; +#endif + +/* +********************************************************************************************************* +* MEMORY PARTITION DATA STRUCTURES +********************************************************************************************************* +*/ + +#if (OS_MEM_EN > 0u) && (OS_MAX_MEM_PART > 0u) +typedef struct os_mem { /* MEMORY CONTROL BLOCK */ + void *OSMemAddr; /* Pointer to beginning of memory partition */ + void *OSMemFreeList; /* Pointer to list of free memory blocks */ + INT32U OSMemBlkSize; /* Size (in bytes) of each block of memory */ + INT32U OSMemNBlks; /* Total number of blocks in this partition */ + INT32U OSMemNFree; /* Number of memory blocks remaining in this partition */ +#if OS_MEM_NAME_EN > 0u + INT8U *OSMemName; /* Memory partition name */ +#endif +} OS_MEM; + + +typedef struct os_mem_data { + void *OSAddr; /* Ptr to the beginning address of the memory partition */ + void *OSFreeList; /* Ptr to the beginning of the free list of memory blocks */ + INT32U OSBlkSize; /* Size (in bytes) of each memory block */ + INT32U OSNBlks; /* Total number of blocks in the partition */ + INT32U OSNFree; /* Number of memory blocks free */ + INT32U OSNUsed; /* Number of memory blocks used */ +} OS_MEM_DATA; +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* MUTUAL EXCLUSION SEMAPHORE DATA +********************************************************************************************************* +*/ + +#if OS_MUTEX_EN > 0u +typedef struct os_mutex_data { + OS_PRIO OSEventTbl[OS_EVENT_TBL_SIZE]; /* List of tasks waiting for event to occur */ + OS_PRIO OSEventGrp; /* Group corresponding to tasks waiting for event to occur */ + BOOLEAN OSValue; /* Mutex value (OS_FALSE = used, OS_TRUE = available) */ + INT8U OSOwnerPrio; /* Mutex owner's task priority or 0xFF if no owner */ + INT8U OSMutexPCP; /* Priority Ceiling Priority or 0xFF if PCP disabled */ +} OS_MUTEX_DATA; +#endif + +/* +********************************************************************************************************* +* MESSAGE QUEUE DATA +********************************************************************************************************* +*/ + +#if OS_Q_EN > 0u +typedef struct os_q { /* QUEUE CONTROL BLOCK */ + struct os_q *OSQPtr; /* Link to next queue control block in list of free blocks */ + void **OSQStart; /* Ptr to start of queue data */ + void **OSQEnd; /* Ptr to end of queue data */ + void **OSQIn; /* Ptr to where next message will be inserted in the Q */ + void **OSQOut; /* Ptr to where next message will be extracted from the Q */ + INT16U OSQSize; /* Size of queue (maximum number of entries) */ + INT16U OSQEntries; /* Current number of entries in the queue */ +} OS_Q; + + +typedef struct os_q_data { + void *OSMsg; /* Pointer to next message to be extracted from queue */ + INT16U OSNMsgs; /* Number of messages in message queue */ + INT16U OSQSize; /* Size of message queue */ + OS_PRIO OSEventTbl[OS_EVENT_TBL_SIZE]; /* List of tasks waiting for event to occur */ + OS_PRIO OSEventGrp; /* Group corresponding to tasks waiting for event to occur */ +} OS_Q_DATA; +#endif + +/* +********************************************************************************************************* +* SEMAPHORE DATA +********************************************************************************************************* +*/ + +#if OS_SEM_EN > 0u +typedef struct os_sem_data { + INT16U OSCnt; /* Semaphore count */ + OS_PRIO OSEventTbl[OS_EVENT_TBL_SIZE]; /* List of tasks waiting for event to occur */ + OS_PRIO OSEventGrp; /* Group corresponding to tasks waiting for event to occur */ +} OS_SEM_DATA; +#endif + +/* +********************************************************************************************************* +* TASK STACK DATA +********************************************************************************************************* +*/ + +#if OS_TASK_CREATE_EXT_EN > 0u +typedef struct os_stk_data { + INT32U OSFree; /* Number of free entries on the stack */ + INT32U OSUsed; /* Number of entries used on the stack */ +} OS_STK_DATA; +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* TASK CONTROL BLOCK +********************************************************************************************************* +*/ + +typedef struct os_tcb { + OS_STK *OSTCBStkPtr; /* Pointer to current top of stack */ + +#if OS_TASK_CREATE_EXT_EN > 0u + void *OSTCBExtPtr; /* Pointer to user definable data for TCB extension */ + OS_STK *OSTCBStkBottom; /* Pointer to bottom of stack */ + INT32U OSTCBStkSize; /* Size of task stack (in number of stack elements) */ + INT16U OSTCBOpt; /* Task options as passed by OSTaskCreateExt() */ + INT16U OSTCBId; /* Task ID (0..65535) */ +#endif + + struct os_tcb *OSTCBNext; /* Pointer to next TCB in the TCB list */ + struct os_tcb *OSTCBPrev; /* Pointer to previous TCB in the TCB list */ + +#if OS_TASK_CREATE_EXT_EN > 0u +#if defined(OS_TLS_TBL_SIZE) && (OS_TLS_TBL_SIZE > 0u) + OS_TLS OSTCBTLSTbl[OS_TLS_TBL_SIZE]; +#endif +#endif + +#if (OS_EVENT_EN) + OS_EVENT *OSTCBEventPtr; /* Pointer to event control block */ +#endif + +#if (OS_EVENT_EN) && (OS_EVENT_MULTI_EN > 0u) + OS_EVENT **OSTCBEventMultiPtr; /* Pointer to multiple event control blocks */ +#endif + +#if ((OS_Q_EN > 0u) && (OS_MAX_QS > 0u)) || (OS_MBOX_EN > 0u) + void *OSTCBMsg; /* Message received from OSMboxPost() or OSQPost() */ +#endif + +#if (OS_FLAG_EN > 0u) && (OS_MAX_FLAGS > 0u) +#if OS_TASK_DEL_EN > 0u + OS_FLAG_NODE *OSTCBFlagNode; /* Pointer to event flag node */ +#endif + OS_FLAGS OSTCBFlagsRdy; /* Event flags that made task ready to run */ +#endif + + INT32U OSTCBDly; /* Nbr ticks to delay task or, timeout waiting for event */ + INT8U OSTCBStat; /* Task status */ + INT8U OSTCBStatPend; /* Task PEND status */ + INT8U OSTCBPrio; /* Task priority (0 == highest) */ + + INT8U OSTCBX; /* Bit position in group corresponding to task priority */ + INT8U OSTCBY; /* Index into ready table corresponding to task priority */ + OS_PRIO OSTCBBitX; /* Bit mask to access bit position in ready table */ + OS_PRIO OSTCBBitY; /* Bit mask to access bit position in ready group */ + +#if OS_TASK_DEL_EN > 0u + INT8U OSTCBDelReq; /* Indicates whether a task needs to delete itself */ +#endif + +#if OS_TASK_PROFILE_EN > 0u + INT32U OSTCBCtxSwCtr; /* Number of time the task was switched in */ + INT32U OSTCBCyclesTot; /* Total number of clock cycles the task has been running */ + INT32U OSTCBCyclesStart; /* Snapshot of cycle counter at start of task resumption */ + OS_STK *OSTCBStkBase; /* Pointer to the beginning of the task stack */ + INT32U OSTCBStkUsed; /* Number of bytes used from the stack */ +#endif + +#if OS_TASK_NAME_EN > 0u + INT8U *OSTCBTaskName; +#endif + +#if OS_TASK_REG_TBL_SIZE > 0u + INT32U OSTCBRegTbl[OS_TASK_REG_TBL_SIZE]; +#endif +} OS_TCB; + +/*$PAGE*/ +/* +********************************************************************************************************* +* TIMER DATA TYPES +********************************************************************************************************* +*/ + +#if OS_TMR_EN > 0u +typedef void (*OS_TMR_CALLBACK)(void *ptmr, void *parg); + + + +typedef struct os_tmr { + INT8U OSTmrType; /* Should be set to OS_TMR_TYPE */ + OS_TMR_CALLBACK OSTmrCallback; /* Function to call when timer expires */ + void *OSTmrCallbackArg; /* Argument to pass to function when timer expires */ + void *OSTmrNext; /* Double link list pointers */ + void *OSTmrPrev; + INT32U OSTmrMatch; /* Timer expires when OSTmrTime == OSTmrMatch */ + INT32U OSTmrDly; /* Delay time before periodic update starts */ + INT32U OSTmrPeriod; /* Period to repeat timer */ +#if OS_TMR_CFG_NAME_EN > 0u + INT8U *OSTmrName; /* Name to give the timer */ +#endif + INT8U OSTmrOpt; /* Options (see OS_TMR_OPT_xxx) */ + INT8U OSTmrState; /* Indicates the state of the timer: */ + /* OS_TMR_STATE_UNUSED */ + /* OS_TMR_STATE_RUNNING */ + /* OS_TMR_STATE_STOPPED */ +} OS_TMR; + + + +typedef struct os_tmr_wheel { + OS_TMR *OSTmrFirst; /* Pointer to first timer in linked list */ + INT16U OSTmrEntries; +} OS_TMR_WHEEL; +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* THREAD LOCAL STORAGE (TLS) +********************************************************************************************************* +*/ + +#if OS_TASK_CREATE_EXT_EN > 0u +#if defined(OS_TLS_TBL_SIZE) && (OS_TLS_TBL_SIZE > 0u) +typedef void (*OS_TLS_DESTRUCT_PTR)(OS_TCB *ptcb, + OS_TLS_ID id, + OS_TLS value); +#endif +#endif + +/* +********************************************************************************************************* +* GLOBAL VARIABLES +********************************************************************************************************* +*/ + +OS_EXT INT32U OSCtxSwCtr; /* Counter of number of context switches */ + +#if (OS_EVENT_EN) && (OS_MAX_EVENTS > 0u) +OS_EXT OS_EVENT *OSEventFreeList; /* Pointer to list of free EVENT control blocks */ +OS_EXT OS_EVENT OSEventTbl[OS_MAX_EVENTS];/* Table of EVENT control blocks */ +#endif + +#if (OS_FLAG_EN > 0u) && (OS_MAX_FLAGS > 0u) +OS_EXT OS_FLAG_GRP OSFlagTbl[OS_MAX_FLAGS]; /* Table containing event flag groups */ +OS_EXT OS_FLAG_GRP *OSFlagFreeList; /* Pointer to free list of event flag groups */ +#endif + +#if OS_TASK_STAT_EN > 0u +OS_EXT INT8U OSCPUUsage; /* Percentage of CPU used */ +OS_EXT INT32U OSIdleCtrMax; /* Max. value that idle ctr can take in 1 sec. */ +OS_EXT INT32U OSIdleCtrRun; /* Val. reached by idle ctr at run time in 1 sec. */ +OS_EXT BOOLEAN OSStatRdy; /* Flag indicating that the statistic task is rdy */ +OS_EXT OS_STK OSTaskStatStk[OS_TASK_STAT_STK_SIZE]; /* Statistics task stack */ +#endif + +OS_EXT INT8U OSIntNesting; /* Interrupt nesting level */ + +OS_EXT INT8U OSLockNesting; /* Multitasking lock nesting level */ + +OS_EXT INT8U OSPrioCur; /* Priority of current task */ +OS_EXT INT8U OSPrioHighRdy; /* Priority of highest priority task */ + +OS_EXT OS_PRIO OSRdyGrp; /* Ready list group */ +OS_EXT OS_PRIO OSRdyTbl[OS_RDY_TBL_SIZE]; /* Table of tasks which are ready to run */ + +OS_EXT BOOLEAN OSRunning; /* Flag indicating that kernel is running */ + +OS_EXT INT8U OSTaskCtr; /* Number of tasks created */ + +OS_EXT volatile INT32U OSIdleCtr; /* Idle counter */ + +#ifdef OS_SAFETY_CRITICAL_IEC61508 +OS_EXT BOOLEAN OSSafetyCriticalStartFlag; +#endif + +OS_EXT OS_STK OSTaskIdleStk[OS_TASK_IDLE_STK_SIZE]; /* Idle task stack */ + + +OS_EXT OS_TCB *OSTCBCur; /* Pointer to currently running TCB */ +OS_EXT OS_TCB *OSTCBFreeList; /* Pointer to list of free TCBs */ +OS_EXT OS_TCB *OSTCBHighRdy; /* Pointer to highest priority TCB R-to-R */ +OS_EXT OS_TCB *OSTCBList; /* Pointer to doubly linked list of TCBs */ +OS_EXT OS_TCB *OSTCBPrioTbl[OS_LOWEST_PRIO + 1u]; /* Table of pointers to created TCBs */ +OS_EXT OS_TCB OSTCBTbl[OS_MAX_TASKS + OS_N_SYS_TASKS]; /* Table of TCBs */ + +#if OS_TICK_STEP_EN > 0u +OS_EXT INT8U OSTickStepState; /* Indicates the state of the tick step feature */ +#endif + +#if (OS_MEM_EN > 0u) && (OS_MAX_MEM_PART > 0u) +OS_EXT OS_MEM *OSMemFreeList; /* Pointer to free list of memory partitions */ +OS_EXT OS_MEM OSMemTbl[OS_MAX_MEM_PART];/* Storage for memory partition manager */ +#endif + +#if (OS_Q_EN > 0u) && (OS_MAX_QS > 0u) +OS_EXT OS_Q *OSQFreeList; /* Pointer to list of free QUEUE control blocks */ +OS_EXT OS_Q OSQTbl[OS_MAX_QS]; /* Table of QUEUE control blocks */ +#endif + +#if OS_TASK_REG_TBL_SIZE > 0u +OS_EXT INT8U OSTaskRegNextAvailID; /* Next available Task register ID */ +#endif + +#if OS_TIME_GET_SET_EN > 0u +OS_EXT volatile INT32U OSTime; /* Current value of system time (in ticks) */ +#endif + +#if OS_TMR_EN > 0u +OS_EXT INT16U OSTmrFree; /* Number of free entries in the timer pool */ +OS_EXT INT16U OSTmrUsed; /* Number of timers used */ +OS_EXT INT32U OSTmrTime; /* Current timer time */ + +OS_EXT OS_EVENT *OSTmrSem; /* Sem. used to gain exclusive access to timers */ +OS_EXT OS_EVENT *OSTmrSemSignal; /* Sem. used to signal the update of timers */ + +OS_EXT OS_TMR OSTmrTbl[OS_TMR_CFG_MAX]; /* Table containing pool of timers */ +OS_EXT OS_TMR *OSTmrFreeList; /* Pointer to free list of timers */ +OS_EXT OS_STK OSTmrTaskStk[OS_TASK_TMR_STK_SIZE]; + +OS_EXT OS_TMR_WHEEL OSTmrWheelTbl[OS_TMR_CFG_WHEEL_SIZE]; +#endif + +extern INT8U const OSUnMapTbl[256]; /* Priority->Index lookup table */ + +/*$PAGE*/ +/* +********************************************************************************************************* +* FUNCTION PROTOTYPES +* (Target Independent Functions) +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* MISCELLANEOUS +********************************************************************************************************* +*/ + +#if (OS_EVENT_EN) + +#if (OS_EVENT_NAME_EN > 0u) +INT8U OSEventNameGet (OS_EVENT *pevent, + INT8U **pname, + INT8U *perr); + +void OSEventNameSet (OS_EVENT *pevent, + INT8U *pname, + INT8U *perr); +#endif + +#if (OS_EVENT_MULTI_EN > 0u) +INT16U OSEventPendMulti (OS_EVENT **pevents_pend, + OS_EVENT **pevents_rdy, + void **pmsgs_rdy, + INT32U timeout, + INT8U *perr); +#endif + +#endif + +/* +********************************************************************************************************* +* TASK LOCAL STORAGE (TLS) SUPPORT +********************************************************************************************************* +*/ + +#if OS_TASK_CREATE_EXT_EN > 0u +#if defined(OS_TLS_TBL_SIZE) && (OS_TLS_TBL_SIZE > 0u) + +OS_TLS_ID OS_TLS_GetID (INT8U *perr); + +OS_TLS OS_TLS_GetValue (OS_TCB *ptcb, + OS_TLS_ID id, + INT8U *perr); + +void OS_TLS_Init (INT8U *perr); + +void OS_TLS_SetValue (OS_TCB *ptcb, + OS_TLS_ID id, + OS_TLS value, + INT8U *perr); + +void OS_TLS_SetDestruct (OS_TLS_ID id, + OS_TLS_DESTRUCT_PTR pdestruct, + INT8U *perr); + +void OS_TLS_TaskCreate (OS_TCB *ptcb); + +void OS_TLS_TaskDel (OS_TCB *ptcb); + +void OS_TLS_TaskSw (void); + +#endif +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* EVENT FLAGS MANAGEMENT +********************************************************************************************************* +*/ + +#if (OS_FLAG_EN > 0u) && (OS_MAX_FLAGS > 0u) + +#if OS_FLAG_ACCEPT_EN > 0u +OS_FLAGS OSFlagAccept (OS_FLAG_GRP *pgrp, + OS_FLAGS flags, + INT8U wait_type, + INT8U *perr); +#endif + +OS_FLAG_GRP *OSFlagCreate (OS_FLAGS flags, + INT8U *perr); + +#if OS_FLAG_DEL_EN > 0u +OS_FLAG_GRP *OSFlagDel (OS_FLAG_GRP *pgrp, + INT8U opt, + INT8U *perr); +#endif + +#if (OS_FLAG_EN > 0u) && (OS_FLAG_NAME_EN > 0u) +INT8U OSFlagNameGet (OS_FLAG_GRP *pgrp, + INT8U **pname, + INT8U *perr); + +void OSFlagNameSet (OS_FLAG_GRP *pgrp, + INT8U *pname, + INT8U *perr); +#endif + +OS_FLAGS OSFlagPend (OS_FLAG_GRP *pgrp, + OS_FLAGS flags, + INT8U wait_type, + INT32U timeout, + INT8U *perr); + +OS_FLAGS OSFlagPendGetFlagsRdy (void); +OS_FLAGS OSFlagPost (OS_FLAG_GRP *pgrp, + OS_FLAGS flags, + INT8U opt, + INT8U *perr); + +#if OS_FLAG_QUERY_EN > 0u +OS_FLAGS OSFlagQuery (OS_FLAG_GRP *pgrp, + INT8U *perr); +#endif +#endif + +/* +********************************************************************************************************* +* MESSAGE MAILBOX MANAGEMENT +********************************************************************************************************* +*/ + +#if OS_MBOX_EN > 0u + +#if OS_MBOX_ACCEPT_EN > 0u +void *OSMboxAccept (OS_EVENT *pevent); +#endif + +OS_EVENT *OSMboxCreate (void *pmsg); + +#if OS_MBOX_DEL_EN > 0u +OS_EVENT *OSMboxDel (OS_EVENT *pevent, + INT8U opt, + INT8U *perr); +#endif + +void *OSMboxPend (OS_EVENT *pevent, + INT32U timeout, + INT8U *perr); + +#if OS_MBOX_PEND_ABORT_EN > 0u +INT8U OSMboxPendAbort (OS_EVENT *pevent, + INT8U opt, + INT8U *perr); +#endif + +#if OS_MBOX_POST_EN > 0u +INT8U OSMboxPost (OS_EVENT *pevent, + void *pmsg); +#endif + +#if OS_MBOX_POST_OPT_EN > 0u +INT8U OSMboxPostOpt (OS_EVENT *pevent, + void *pmsg, + INT8U opt); +#endif + +#if OS_MBOX_QUERY_EN > 0u +INT8U OSMboxQuery (OS_EVENT *pevent, + OS_MBOX_DATA *p_mbox_data); +#endif +#endif + +/* +********************************************************************************************************* +* MEMORY MANAGEMENT +********************************************************************************************************* +*/ + +#if (OS_MEM_EN > 0u) && (OS_MAX_MEM_PART > 0u) + +OS_MEM *OSMemCreate (void *addr, + INT32U nblks, + INT32U blksize, + INT8U *perr); + +void *OSMemGet (OS_MEM *pmem, + INT8U *perr); +#if OS_MEM_NAME_EN > 0u +INT8U OSMemNameGet (OS_MEM *pmem, + INT8U **pname, + INT8U *perr); + +void OSMemNameSet (OS_MEM *pmem, + INT8U *pname, + INT8U *perr); +#endif +INT8U OSMemPut (OS_MEM *pmem, + void *pblk); + +#if OS_MEM_QUERY_EN > 0u +INT8U OSMemQuery (OS_MEM *pmem, + OS_MEM_DATA *p_mem_data); +#endif + +#endif + +/* +********************************************************************************************************* +* MUTUAL EXCLUSION SEMAPHORE MANAGEMENT +********************************************************************************************************* +*/ + +#if OS_MUTEX_EN > 0u + +#if OS_MUTEX_ACCEPT_EN > 0u +BOOLEAN OSMutexAccept (OS_EVENT *pevent, + INT8U *perr); +#endif + +OS_EVENT *OSMutexCreate (INT8U prio, + INT8U *perr); + +#if OS_MUTEX_DEL_EN > 0u +OS_EVENT *OSMutexDel (OS_EVENT *pevent, + INT8U opt, + INT8U *perr); +#endif + +void OSMutexPend (OS_EVENT *pevent, + INT32U timeout, + INT8U *perr); + +INT8U OSMutexPost (OS_EVENT *pevent); + +#if OS_MUTEX_QUERY_EN > 0u +INT8U OSMutexQuery (OS_EVENT *pevent, + OS_MUTEX_DATA *p_mutex_data); +#endif + +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* MESSAGE QUEUE MANAGEMENT +********************************************************************************************************* +*/ + +#if (OS_Q_EN > 0u) && (OS_MAX_QS > 0u) + +#if OS_Q_ACCEPT_EN > 0u +void *OSQAccept (OS_EVENT *pevent, + INT8U *perr); +#endif + +OS_EVENT *OSQCreate (void **start, + INT16U size); + +#if OS_Q_DEL_EN > 0u +OS_EVENT *OSQDel (OS_EVENT *pevent, + INT8U opt, + INT8U *perr); +#endif + +#if OS_Q_FLUSH_EN > 0u +INT8U OSQFlush (OS_EVENT *pevent); +#endif + +void *OSQPend (OS_EVENT *pevent, + INT32U timeout, + INT8U *perr); + +#if OS_Q_PEND_ABORT_EN > 0u +INT8U OSQPendAbort (OS_EVENT *pevent, + INT8U opt, + INT8U *perr); +#endif + +#if OS_Q_POST_EN > 0u +INT8U OSQPost (OS_EVENT *pevent, + void *pmsg); +#endif + +#if OS_Q_POST_FRONT_EN > 0u +INT8U OSQPostFront (OS_EVENT *pevent, + void *pmsg); +#endif + +#if OS_Q_POST_OPT_EN > 0u +INT8U OSQPostOpt (OS_EVENT *pevent, + void *pmsg, + INT8U opt); +#endif + +#if OS_Q_QUERY_EN > 0u +INT8U OSQQuery (OS_EVENT *pevent, + OS_Q_DATA *p_q_data); +#endif + +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* SEMAPHORE MANAGEMENT +********************************************************************************************************* +*/ +#if OS_SEM_EN > 0u + +#if OS_SEM_ACCEPT_EN > 0u +INT16U OSSemAccept (OS_EVENT *pevent); +#endif + +OS_EVENT *OSSemCreate (INT16U cnt); + +#if OS_SEM_DEL_EN > 0u +OS_EVENT *OSSemDel (OS_EVENT *pevent, + INT8U opt, + INT8U *perr); +#endif + +void OSSemPend (OS_EVENT *pevent, + INT32U timeout, + INT8U *perr); + +#if OS_SEM_PEND_ABORT_EN > 0u +INT8U OSSemPendAbort (OS_EVENT *pevent, + INT8U opt, + INT8U *perr); +#endif + +INT8U OSSemPost (OS_EVENT *pevent); + +#if OS_SEM_QUERY_EN > 0u +INT8U OSSemQuery (OS_EVENT *pevent, + OS_SEM_DATA *p_sem_data); +#endif + +#if OS_SEM_SET_EN > 0u +void OSSemSet (OS_EVENT *pevent, + INT16U cnt, + INT8U *perr); +#endif + +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* TASK MANAGEMENT +********************************************************************************************************* +*/ +#if OS_TASK_CHANGE_PRIO_EN > 0u +INT8U OSTaskChangePrio (INT8U oldprio, + INT8U newprio); +#endif + +#if OS_TASK_CREATE_EN > 0u +INT8U OSTaskCreate (void (*task)(void *p_arg), + void *p_arg, + OS_STK *ptos, + INT8U prio); +#endif + +#if OS_TASK_CREATE_EXT_EN > 0u +INT8U OSTaskCreateExt (void (*task)(void *p_arg), + void *p_arg, + OS_STK *ptos, + INT8U prio, + INT16U id, + OS_STK *pbos, + INT32U stk_size, + void *pext, + INT16U opt); +#endif + +#if OS_TASK_DEL_EN > 0u +INT8U OSTaskDel (INT8U prio); +INT8U OSTaskDelReq (INT8U prio); +#endif + +#if OS_TASK_NAME_EN > 0u +INT8U OSTaskNameGet (INT8U prio, + INT8U **pname, + INT8U *perr); + +void OSTaskNameSet (INT8U prio, + INT8U *pname, + INT8U *perr); +#endif + +#if OS_TASK_SUSPEND_EN > 0u +INT8U OSTaskResume (INT8U prio); +INT8U OSTaskSuspend (INT8U prio); +#endif + +#if (OS_TASK_STAT_STK_CHK_EN > 0u) && (OS_TASK_CREATE_EXT_EN > 0u) +INT8U OSTaskStkChk (INT8U prio, + OS_STK_DATA *p_stk_data); +#endif + +#if OS_TASK_QUERY_EN > 0u +INT8U OSTaskQuery (INT8U prio, + OS_TCB *p_task_data); +#endif + + + +#if OS_TASK_REG_TBL_SIZE > 0u +INT32U OSTaskRegGet (INT8U prio, + INT8U id, + INT8U *perr); + +INT8U OSTaskRegGetID (INT8U *perr); + +void OSTaskRegSet (INT8U prio, + INT8U id, + INT32U value, + INT8U *perr); +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* TIME MANAGEMENT +********************************************************************************************************* +*/ + +void OSTimeDly (INT32U ticks); + +#if OS_TIME_DLY_HMSM_EN > 0u +INT8U OSTimeDlyHMSM (INT8U hours, + INT8U minutes, + INT8U seconds, + INT16U ms); +#endif + +#if OS_TIME_DLY_RESUME_EN > 0u +INT8U OSTimeDlyResume (INT8U prio); +#endif + +#if OS_TIME_GET_SET_EN > 0u +INT32U OSTimeGet (void); +void OSTimeSet (INT32U ticks); +#endif + +void OSTimeTick (void); + +/* +********************************************************************************************************* +* TIMER MANAGEMENT +********************************************************************************************************* +*/ + +#if OS_TMR_EN > 0u +OS_TMR *OSTmrCreate (INT32U dly, + INT32U period, + INT8U opt, + OS_TMR_CALLBACK callback, + void *callback_arg, + INT8U *pname, + INT8U *perr); + +BOOLEAN OSTmrDel (OS_TMR *ptmr, + INT8U *perr); + +#if OS_TMR_CFG_NAME_EN > 0u +INT8U OSTmrNameGet (OS_TMR *ptmr, + INT8U **pdest, + INT8U *perr); +#endif +INT32U OSTmrRemainGet (OS_TMR *ptmr, + INT8U *perr); + +INT8U OSTmrStateGet (OS_TMR *ptmr, + INT8U *perr); + +BOOLEAN OSTmrStart (OS_TMR *ptmr, + INT8U *perr); + +BOOLEAN OSTmrStop (OS_TMR *ptmr, + INT8U opt, + void *callback_arg, + INT8U *perr); + +INT8U OSTmrSignal (void); +#endif + +/* +********************************************************************************************************* +* MISCELLANEOUS +********************************************************************************************************* +*/ + +void OSInit (void); + +void OSIntEnter (void); +void OSIntExit (void); + +#ifdef OS_SAFETY_CRITICAL_IEC61508 +void OSSafetyCriticalStart (void); +#endif + +#if OS_SCHED_LOCK_EN > 0u +void OSSchedLock (void); +void OSSchedUnlock (void); +#endif + +void OSStart (void); + +void OSStatInit (void); + +INT16U OSVersion (void); + +/*$PAGE*/ +/* +********************************************************************************************************* +* INTERNAL FUNCTION PROTOTYPES +* (Your application MUST NOT call these functions) +********************************************************************************************************* +*/ + +#if OS_TASK_DEL_EN > 0u +void OS_Dummy (void); +#endif + +#if (OS_EVENT_EN) +INT8U OS_EventTaskRdy (OS_EVENT *pevent, + void *pmsg, + INT8U msk, + INT8U pend_stat); + +void OS_EventTaskWait (OS_EVENT *pevent); + +void OS_EventTaskRemove (OS_TCB *ptcb, + OS_EVENT *pevent); + +#if (OS_EVENT_MULTI_EN > 0u) +void OS_EventTaskWaitMulti (OS_EVENT **pevents_wait); + +void OS_EventTaskRemoveMulti (OS_TCB *ptcb, + OS_EVENT **pevents_multi); +#endif + +void OS_EventWaitListInit (OS_EVENT *pevent); +#endif + +#if (OS_FLAG_EN > 0u) && (OS_MAX_FLAGS > 0u) +void OS_FlagInit (void); +void OS_FlagUnlink (OS_FLAG_NODE *pnode); +#endif + +void OS_MemClr (INT8U *pdest, + INT16U size); + +void OS_MemCopy (INT8U *pdest, + INT8U *psrc, + INT16U size); + +#if (OS_MEM_EN > 0u) && (OS_MAX_MEM_PART > 0u) +void OS_MemInit (void); +#endif + +#if OS_Q_EN > 0u +void OS_QInit (void); +#endif + +void OS_Sched (void); + +#if (OS_EVENT_NAME_EN > 0u) || (OS_FLAG_NAME_EN > 0u) || (OS_MEM_NAME_EN > 0u) || (OS_TASK_NAME_EN > 0u) +INT8U OS_StrLen (INT8U *psrc); +#endif + +void OS_TaskIdle (void *p_arg); + +void OS_TaskReturn (void); + +#if OS_TASK_STAT_EN > 0u +void OS_TaskStat (void *p_arg); +#endif + +#if (OS_TASK_STAT_STK_CHK_EN > 0u) && (OS_TASK_CREATE_EXT_EN > 0u) +void OS_TaskStkClr (OS_STK *pbos, + INT32U size, + INT16U opt); +#endif + +#if (OS_TASK_STAT_STK_CHK_EN > 0u) && (OS_TASK_CREATE_EXT_EN > 0u) +void OS_TaskStatStkChk (void); +#endif + +INT8U OS_TCBInit (INT8U prio, + OS_STK *ptos, + OS_STK *pbos, + INT16U id, + INT32U stk_size, + void *pext, + INT16U opt); + +#if OS_TMR_EN > 0u +void OSTmr_Init (void); +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* FUNCTION PROTOTYPES +* (Target Specific Functions) +********************************************************************************************************* +*/ + +#if OS_DEBUG_EN > 0u +void OSDebugInit (void); +#endif + +void OSInitHookBegin (void); +void OSInitHookEnd (void); + +void OSTaskCreateHook (OS_TCB *ptcb); +void OSTaskDelHook (OS_TCB *ptcb); + +void OSTaskIdleHook (void); + +void OSTaskReturnHook (OS_TCB *ptcb); + +void OSTaskStatHook (void); +OS_STK *OSTaskStkInit (void (*task)(void *p_arg), + void *p_arg, + OS_STK *ptos, + INT16U opt); + +#if OS_TASK_SW_HOOK_EN > 0u +void OSTaskSwHook (void); +#endif + +void OSTCBInitHook (OS_TCB *ptcb); + +#if OS_TIME_TICK_HOOK_EN > 0u +void OSTimeTickHook (void); +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* FUNCTION PROTOTYPES +* (Application Specific Functions) +********************************************************************************************************* +*/ + +#if OS_APP_HOOKS_EN > 0u +void App_TaskCreateHook (OS_TCB *ptcb); +void App_TaskDelHook (OS_TCB *ptcb); +void App_TaskIdleHook (void); + +void App_TaskReturnHook (OS_TCB *ptcb); + +void App_TaskStatHook (void); + +#if OS_TASK_SW_HOOK_EN > 0u +void App_TaskSwHook (void); +#endif + +void App_TCBInitHook (OS_TCB *ptcb); + +#if OS_TIME_TICK_HOOK_EN > 0u +void App_TimeTickHook (void); +#endif +#endif + +/* +********************************************************************************************************* +* FUNCTION PROTOTYPES +* +* IMPORTANT: These prototypes MUST be placed in OS_CPU.H +********************************************************************************************************* +*/ + +#if 0 +void OSStartHighRdy (void); +void OSIntCtxSw (void); +void OSCtxSw (void); +#endif + +/*$PAGE*/ +/* +********************************************************************************************************* +* LOOK FOR MISSING #define CONSTANTS +* +* This section is used to generate ERROR messages at compile time if certain #define constants are +* MISSING in OS_CFG.H. This allows you to quickly determine the source of the error. +* +* You SHOULD NOT change this section UNLESS you would like to add more comments as to the source of the +* compile time error. +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* EVENT FLAGS +********************************************************************************************************* +*/ + +#ifndef OS_FLAG_EN +#error "OS_CFG.H, Missing OS_FLAG_EN: Enable (1) or Disable (0) code generation for Event Flags" +#else + #ifndef OS_MAX_FLAGS + #error "OS_CFG.H, Missing OS_MAX_FLAGS: Max. number of Event Flag Groups in your application" + #else + #if OS_MAX_FLAGS > 65500u + #error "OS_CFG.H, OS_MAX_FLAGS must be <= 65500" + #endif + #endif + + #ifndef OS_FLAGS_NBITS + #error "OS_CFG.H, Missing OS_FLAGS_NBITS: Determine #bits used for event flags, MUST be either 8, 16 or 32" + #endif + + #ifndef OS_FLAG_WAIT_CLR_EN + #error "OS_CFG.H, Missing OS_FLAG_WAIT_CLR_EN: Include code for Wait on Clear EVENT FLAGS" + #endif + + #ifndef OS_FLAG_ACCEPT_EN + #error "OS_CFG.H, Missing OS_FLAG_ACCEPT_EN: Include code for OSFlagAccept()" + #endif + + #ifndef OS_FLAG_DEL_EN + #error "OS_CFG.H, Missing OS_FLAG_DEL_EN: Include code for OSFlagDel()" + #endif + + #ifndef OS_FLAG_NAME_EN + #error "OS_CFG.H, Missing OS_FLAG_NAME_EN: Enable flag group names" + #endif + + #ifndef OS_FLAG_QUERY_EN + #error "OS_CFG.H, Missing OS_FLAG_QUERY_EN: Include code for OSFlagQuery()" + #endif +#endif + +/* +********************************************************************************************************* +* MESSAGE MAILBOXES +********************************************************************************************************* +*/ + +#ifndef OS_MBOX_EN +#error "OS_CFG.H, Missing OS_MBOX_EN: Enable (1) or Disable (0) code generation for MAILBOXES" +#else + #ifndef OS_MBOX_ACCEPT_EN + #error "OS_CFG.H, Missing OS_MBOX_ACCEPT_EN: Include code for OSMboxAccept()" + #endif + + #ifndef OS_MBOX_DEL_EN + #error "OS_CFG.H, Missing OS_MBOX_DEL_EN: Include code for OSMboxDel()" + #endif + + #ifndef OS_MBOX_PEND_ABORT_EN + #error "OS_CFG.H, Missing OS_MBOX_PEND_ABORT_EN: Include code for OSMboxPendAbort()" + #endif + + #ifndef OS_MBOX_POST_EN + #error "OS_CFG.H, Missing OS_MBOX_POST_EN: Include code for OSMboxPost()" + #endif + + #ifndef OS_MBOX_POST_OPT_EN + #error "OS_CFG.H, Missing OS_MBOX_POST_OPT_EN: Include code for OSMboxPostOpt()" + #endif + + #ifndef OS_MBOX_QUERY_EN + #error "OS_CFG.H, Missing OS_MBOX_QUERY_EN: Include code for OSMboxQuery()" + #endif +#endif + +/* +********************************************************************************************************* +* MEMORY MANAGEMENT +********************************************************************************************************* +*/ + +#ifndef OS_MEM_EN +#error "OS_CFG.H, Missing OS_MEM_EN: Enable (1) or Disable (0) code generation for MEMORY MANAGER" +#else + #ifndef OS_MAX_MEM_PART + #error "OS_CFG.H, Missing OS_MAX_MEM_PART: Max. number of memory partitions" + #else + #if OS_MAX_MEM_PART > 65500u + #error "OS_CFG.H, OS_MAX_MEM_PART must be <= 65500" + #endif + #endif + + #ifndef OS_MEM_NAME_EN + #error "OS_CFG.H, Missing OS_MEM_NAME_EN: Enable memory partition names" + #endif + + #ifndef OS_MEM_QUERY_EN + #error "OS_CFG.H, Missing OS_MEM_QUERY_EN: Include code for OSMemQuery()" + #endif +#endif + +/* +********************************************************************************************************* +* MUTUAL EXCLUSION SEMAPHORES +********************************************************************************************************* +*/ + +#ifndef OS_MUTEX_EN +#error "OS_CFG.H, Missing OS_MUTEX_EN: Enable (1) or Disable (0) code generation for MUTEX" +#else + #ifndef OS_MUTEX_ACCEPT_EN + #error "OS_CFG.H, Missing OS_MUTEX_ACCEPT_EN: Include code for OSMutexAccept()" + #endif + + #ifndef OS_MUTEX_DEL_EN + #error "OS_CFG.H, Missing OS_MUTEX_DEL_EN: Include code for OSMutexDel()" + #endif + + #ifndef OS_MUTEX_QUERY_EN + #error "OS_CFG.H, Missing OS_MUTEX_QUERY_EN: Include code for OSMutexQuery()" + #endif +#endif + +/* +********************************************************************************************************* +* MESSAGE QUEUES +********************************************************************************************************* +*/ + +#ifndef OS_Q_EN +#error "OS_CFG.H, Missing OS_Q_EN: Enable (1) or Disable (0) code generation for QUEUES" +#else + #ifndef OS_MAX_QS + #error "OS_CFG.H, Missing OS_MAX_QS: Max. number of queue control blocks" + #else + #if OS_MAX_QS > 65500u + #error "OS_CFG.H, OS_MAX_QS must be <= 65500" + #endif + #endif + + #ifndef OS_Q_ACCEPT_EN + #error "OS_CFG.H, Missing OS_Q_ACCEPT_EN: Include code for OSQAccept()" + #endif + + #ifndef OS_Q_DEL_EN + #error "OS_CFG.H, Missing OS_Q_DEL_EN: Include code for OSQDel()" + #endif + + #ifndef OS_Q_FLUSH_EN + #error "OS_CFG.H, Missing OS_Q_FLUSH_EN: Include code for OSQFlush()" + #endif + + #ifndef OS_Q_PEND_ABORT_EN + #error "OS_CFG.H, Missing OS_Q_PEND_ABORT_EN: Include code for OSQPendAbort()" + #endif + + #ifndef OS_Q_POST_EN + #error "OS_CFG.H, Missing OS_Q_POST_EN: Include code for OSQPost()" + #endif + + #ifndef OS_Q_POST_FRONT_EN + #error "OS_CFG.H, Missing OS_Q_POST_FRONT_EN: Include code for OSQPostFront()" + #endif + + #ifndef OS_Q_POST_OPT_EN + #error "OS_CFG.H, Missing OS_Q_POST_OPT_EN: Include code for OSQPostOpt()" + #endif + + #ifndef OS_Q_QUERY_EN + #error "OS_CFG.H, Missing OS_Q_QUERY_EN: Include code for OSQQuery()" + #endif +#endif + +/* +********************************************************************************************************* +* SEMAPHORES +********************************************************************************************************* +*/ + +#ifndef OS_SEM_EN +#error "OS_CFG.H, Missing OS_SEM_EN: Enable (1) or Disable (0) code generation for SEMAPHORES" +#else + #ifndef OS_SEM_ACCEPT_EN + #error "OS_CFG.H, Missing OS_SEM_ACCEPT_EN: Include code for OSSemAccept()" + #endif + + #ifndef OS_SEM_DEL_EN + #error "OS_CFG.H, Missing OS_SEM_DEL_EN: Include code for OSSemDel()" + #endif + + #ifndef OS_SEM_PEND_ABORT_EN + #error "OS_CFG.H, Missing OS_SEM_PEND_ABORT_EN: Include code for OSSemPendAbort()" + #endif + + #ifndef OS_SEM_QUERY_EN + #error "OS_CFG.H, Missing OS_SEM_QUERY_EN: Include code for OSSemQuery()" + #endif + + #ifndef OS_SEM_SET_EN + #error "OS_CFG.H, Missing OS_SEM_SET_EN: Include code for OSSemSet()" + #endif +#endif + +/* +********************************************************************************************************* +* TASK MANAGEMENT +********************************************************************************************************* +*/ + +#ifndef OS_MAX_TASKS +#error "OS_CFG.H, Missing OS_MAX_TASKS: Max. number of tasks in your application" +#else + #if OS_MAX_TASKS < 2u + #error "OS_CFG.H, OS_MAX_TASKS must be >= 2" + #endif + + #if OS_MAX_TASKS > ((OS_LOWEST_PRIO - OS_N_SYS_TASKS) + 1u) + #error "OS_CFG.H, OS_MAX_TASKS must be <= OS_LOWEST_PRIO - OS_N_SYS_TASKS + 1" + #endif + +#endif + +#if OS_LOWEST_PRIO > 254u +#error "OS_CFG.H, OS_LOWEST_PRIO must be <= 254 in V2.8x and higher" +#endif + +#ifndef OS_TASK_IDLE_STK_SIZE +#error "OS_CFG.H, Missing OS_TASK_IDLE_STK_SIZE: Idle task stack size" +#endif + +#ifndef OS_TASK_STAT_EN +#error "OS_CFG.H, Missing OS_TASK_STAT_EN: Enable (1) or Disable(0) the statistics task" +#endif + +#ifndef OS_TASK_STAT_STK_SIZE +#error "OS_CFG.H, Missing OS_TASK_STAT_STK_SIZE: Statistics task stack size" +#endif + +#ifndef OS_TASK_STAT_STK_CHK_EN +#error "OS_CFG.H, Missing OS_TASK_STAT_STK_CHK_EN: Check task stacks from statistics task" +#endif + +#ifndef OS_TASK_CHANGE_PRIO_EN +#error "OS_CFG.H, Missing OS_TASK_CHANGE_PRIO_EN: Include code for OSTaskChangePrio()" +#endif + +#ifndef OS_TASK_CREATE_EN +#error "OS_CFG.H, Missing OS_TASK_CREATE_EN: Include code for OSTaskCreate()" +#endif + +#ifndef OS_TASK_CREATE_EXT_EN +#error "OS_CFG.H, Missing OS_TASK_CREATE_EXT_EN: Include code for OSTaskCreateExt()" +#else + #if (OS_TASK_CREATE_EXT_EN == 0u) && (OS_TASK_CREATE_EN == 0u) + #error "OS_CFG.H, OS_TASK_CREATE_EXT_EN or OS_TASK_CREATE_EN must be Enable (1)" + #endif +#endif + +#ifndef OS_TASK_DEL_EN +#error "OS_CFG.H, Missing OS_TASK_DEL_EN: Include code for OSTaskDel()" +#endif + +#ifndef OS_TASK_NAME_EN +#error "OS_CFG.H, Missing OS_TASK_NAME_EN: Enable task names" +#endif + +#ifndef OS_TASK_SUSPEND_EN +#error "OS_CFG.H, Missing OS_TASK_SUSPEND_EN: Include code for OSTaskSuspend() and OSTaskResume()" +#endif + +#ifndef OS_TASK_QUERY_EN +#error "OS_CFG.H, Missing OS_TASK_QUERY_EN: Include code for OSTaskQuery()" +#endif + +#ifndef OS_TASK_REG_TBL_SIZE +#error "OS_CFG.H, Missing OS_TASK_REG_TBL_SIZE: Include code for task specific registers" +#else + #if OS_TASK_REG_TBL_SIZE > 255u + #error "OS_CFG.H, OS_TASK_REG_TBL_SIZE must be <= 255" + #endif +#endif + +/* +********************************************************************************************************* +* TIME MANAGEMENT +********************************************************************************************************* +*/ + +#ifndef OS_TICKS_PER_SEC +#error "OS_CFG.H, Missing OS_TICKS_PER_SEC: Sets the number of ticks in one second" +#endif + +#ifndef OS_TIME_DLY_HMSM_EN +#error "OS_CFG.H, Missing OS_TIME_DLY_HMSM_EN: Include code for OSTimeDlyHMSM()" +#endif + +#ifndef OS_TIME_DLY_RESUME_EN +#error "OS_CFG.H, Missing OS_TIME_DLY_RESUME_EN: Include code for OSTimeDlyResume()" +#endif + +#ifndef OS_TIME_GET_SET_EN +#error "OS_CFG.H, Missing OS_TIME_GET_SET_EN: Include code for OSTimeGet() and OSTimeSet()" +#endif + +/* +********************************************************************************************************* +* TIMER MANAGEMENT +********************************************************************************************************* +*/ + +#ifndef OS_TMR_EN +#error "OS_CFG.H, Missing OS_TMR_EN: When (1) enables code generation for Timer Management" +#elif OS_TMR_EN > 0u + #if OS_SEM_EN == 0u + #error "OS_CFG.H, Semaphore management is required (set OS_SEM_EN to 1) when enabling Timer Management." + #error " Timer management require TWO semaphores." + #endif + + #ifndef OS_TMR_CFG_MAX + #error "OS_CFG.H, Missing OS_TMR_CFG_MAX: Determines the total number of timers in an application (2 .. 65500)" + #else + #if OS_TMR_CFG_MAX < 2u + #error "OS_CFG.H, OS_TMR_CFG_MAX should be between 2 and 65500" + #endif + + #if OS_TMR_CFG_MAX > 65500u + #error "OS_CFG.H, OS_TMR_CFG_MAX should be between 2 and 65500" + #endif + #endif + + #ifndef OS_TMR_CFG_WHEEL_SIZE + #error "OS_CFG.H, Missing OS_TMR_CFG_WHEEL_SIZE: Sets the size of the timer wheel (1 .. 1023)" + #else + #if OS_TMR_CFG_WHEEL_SIZE < 2u + #error "OS_CFG.H, OS_TMR_CFG_WHEEL_SIZE should be between 2 and 1024" + #endif + + #if OS_TMR_CFG_WHEEL_SIZE > 1024u + #error "OS_CFG.H, OS_TMR_CFG_WHEEL_SIZE should be between 2 and 1024" + #endif + #endif + + #ifndef OS_TMR_CFG_NAME_EN + #error "OS_CFG.H, Missing OS_TMR_CFG_NAME_EN: Enable Timer names" + #endif + + #ifndef OS_TMR_CFG_TICKS_PER_SEC + #error "OS_CFG.H, Missing OS_TMR_CFG_TICKS_PER_SEC: Determines the rate at which the timer management task will run (Hz)" + #endif + + #ifndef OS_TASK_TMR_STK_SIZE + #error "OS_CFG.H, Missing OS_TASK_TMR_STK_SIZE: Determines the size of the Timer Task's stack" + #endif +#endif + + +/* +********************************************************************************************************* +* MISCELLANEOUS +********************************************************************************************************* +*/ + +#ifndef OS_ARG_CHK_EN +#error "OS_CFG.H, Missing OS_ARG_CHK_EN: Enable (1) or Disable (0) argument checking" +#endif + + +#ifndef OS_CPU_HOOKS_EN +#error "OS_CFG.H, Missing OS_CPU_HOOKS_EN: uC/OS-II hooks are found in the processor port files when 1" +#endif + + +#ifndef OS_APP_HOOKS_EN +#error "OS_CFG.H, Missing OS_APP_HOOKS_EN: Application-defined hooks are called from the uC/OS-II hooks" +#endif + + +#ifndef OS_DEBUG_EN +#error "OS_CFG.H, Missing OS_DEBUG_EN: Allows you to include variables for debugging or not" +#endif + + +#ifndef OS_LOWEST_PRIO +#error "OS_CFG.H, Missing OS_LOWEST_PRIO: Defines the lowest priority that can be assigned" +#endif + + +#ifndef OS_MAX_EVENTS +#error "OS_CFG.H, Missing OS_MAX_EVENTS: Max. number of event control blocks in your application" +#else + #if OS_MAX_EVENTS > 65500u + #error "OS_CFG.H, OS_MAX_EVENTS must be <= 65500" + #endif +#endif + + +#ifndef OS_SCHED_LOCK_EN +#error "OS_CFG.H, Missing OS_SCHED_LOCK_EN: Include code for OSSchedLock() and OSSchedUnlock()" +#endif + + +#ifndef OS_EVENT_MULTI_EN +#error "OS_CFG.H, Missing OS_EVENT_MULTI_EN: Include code for OSEventPendMulti()" +#endif + + +#ifndef OS_TASK_PROFILE_EN +#error "OS_CFG.H, Missing OS_TASK_PROFILE_EN: Include data structure for run-time task profiling" +#endif + + +#ifndef OS_TASK_SW_HOOK_EN +#error "OS_CFG.H, Missing OS_TASK_SW_HOOK_EN: Allows you to include the code for OSTaskSwHook() or not" +#endif + + +#ifndef OS_TICK_STEP_EN +#error "OS_CFG.H, Missing OS_TICK_STEP_EN: Allows to 'step' one tick at a time with uC/OS-View" +#endif + + +#ifndef OS_TIME_TICK_HOOK_EN +#error "OS_CFG.H, Missing OS_TIME_TICK_HOOK_EN: Allows you to include the code for OSTimeTickHook() or not" +#endif + +/* +********************************************************************************************************* +* SAFETY CRITICAL USE +********************************************************************************************************* +*/ + +#ifdef SAFETY_CRITICAL_RELEASE + +#if OS_ARG_CHK_EN < 1u +#error "OS_CFG.H, OS_ARG_CHK_EN must be enabled for safety-critical release code" +#endif + +#if OS_APP_HOOKS_EN > 0u +#error "OS_CFG.H, OS_APP_HOOKS_EN must be disabled for safety-critical release code" +#endif + +#if OS_DEBUG_EN > 0u +#error "OS_CFG.H, OS_DEBUG_EN must be disabled for safety-critical release code" +#endif + +#ifdef CANTATA +#error "OS_CFG.H, CANTATA must be disabled for safety-critical release code" +#endif + +#ifdef OS_SCHED_LOCK_EN +#error "OS_CFG.H, OS_SCHED_LOCK_EN must be disabled for safety-critical release code" +#endif + +#ifdef VSC_VALIDATION_MODE +#error "OS_CFG.H, VSC_VALIDATION_MODE must be disabled for safety-critical release code" +#endif + +#if OS_TASK_STAT_EN > 0u +#error "OS_CFG.H, OS_TASK_STAT_EN must be disabled for safety-critical release code" +#endif + +#if OS_TICK_STEP_EN > 0u +#error "OS_CFG.H, OS_TICK_STEP_EN must be disabled for safety-critical release code" +#endif + +#if OS_FLAG_EN > 0u + #if OS_FLAG_DEL_EN > 0 + #error "OS_CFG.H, OS_FLAG_DEL_EN must be disabled for safety-critical release code" + #endif +#endif + +#if OS_MBOX_EN > 0u + #if OS_MBOX_DEL_EN > 0u + #error "OS_CFG.H, OS_MBOX_DEL_EN must be disabled for safety-critical release code" + #endif +#endif + +#if OS_MUTEX_EN > 0u + #if OS_MUTEX_DEL_EN > 0u + #error "OS_CFG.H, OS_MUTEX_DEL_EN must be disabled for safety-critical release code" + #endif +#endif + +#if OS_Q_EN > 0u + #if OS_Q_DEL_EN > 0u + #error "OS_CFG.H, OS_Q_DEL_EN must be disabled for safety-critical release code" + #endif +#endif + +#if OS_SEM_EN > 0u + #if OS_SEM_DEL_EN > 0u + #error "OS_CFG.H, OS_SEM_DEL_EN must be disabled for safety-critical release code" + #endif +#endif + +#if OS_TASK_DEL_EN > 0u +#error "OS_CFG.H, OS_TASK_DEL_EN must be disabled for safety-critical release code" +#endif + +#if OS_CRITICAL_METHOD != 3u +#error "OS_CPU.H, OS_CRITICAL_METHOD must be type 3 for safety-critical release code" +#endif + +#endif /* ------------------------ SAFETY_CRITICAL_RELEASE ------------------------ */ + +#ifdef __cplusplus +} +#endif + +#endif