From bfbd1b22e8a77d4611fe600adab0d0a94b1462c3 Mon Sep 17 00:00:00 2001 From: Joseph Hickey Date: Fri, 26 Mar 2021 14:57:14 -0400 Subject: [PATCH] Fix #171, use OSAL timebase for CFE timers Add a new PSP module that instantiates an OSAL abstract timebase for use with cFE services. This single module is then used across all 3 implementations (mcp750, pc-linux, pc-rtems) and does not need to be duplicated. --- fsw/inc/cfe_psp.h | 7 + fsw/mcp750-vxworks/inc/cfe_psp_config.h | 10 ++ fsw/mcp750-vxworks/psp_module_list.cmake | 3 +- fsw/mcp750-vxworks/src/cfe_psp_start.c | 28 ---- fsw/modules/soft_timebase/CMakeLists.txt | 3 + .../soft_timebase/cfe_psp_soft_timebase.c | 82 ++++++++++ fsw/pc-linux/inc/cfe_psp_config.h | 13 ++ fsw/pc-linux/psp_module_list.cmake | 3 +- fsw/pc-linux/src/cfe_psp_start.c | 142 ------------------ fsw/pc-rtems/inc/cfe_psp_config.h | 13 ++ fsw/pc-rtems/psp_module_list.cmake | 3 +- fsw/pc-rtems/src/cfe_psp_start.c | 48 ------ 12 files changed, 134 insertions(+), 221 deletions(-) create mode 100644 fsw/modules/soft_timebase/CMakeLists.txt create mode 100644 fsw/modules/soft_timebase/cfe_psp_soft_timebase.c diff --git a/fsw/inc/cfe_psp.h b/fsw/inc/cfe_psp.h index 47202913..19da8be7 100644 --- a/fsw/inc/cfe_psp.h +++ b/fsw/inc/cfe_psp.h @@ -153,6 +153,13 @@ #define CFE_PSP_MISSION_REV (GLOBAL_PSP_CONFIGDATA.PSP_VersionInfo.MissionRev) #define CFE_PSP_VERSION (GLOBAL_PSP_CONFIGDATA.PSP_VersionInfo.VersionString) +/** + * \brief The name of the software/RTOS timebase for general system timers. + * + * This name may be referred to by CFE TIME and/or SCH when setting up its own timers. + */ +#define CFE_PSP_SOFT_TIMEBASE_NAME "cFS-Master" + /* ** Type Definitions */ diff --git a/fsw/mcp750-vxworks/inc/cfe_psp_config.h b/fsw/mcp750-vxworks/inc/cfe_psp_config.h index fc88a42f..d109d5e1 100644 --- a/fsw/mcp750-vxworks/inc/cfe_psp_config.h +++ b/fsw/mcp750-vxworks/inc/cfe_psp_config.h @@ -51,6 +51,16 @@ */ #define CFE_PSP_MAX_EXCEPTION_ENTRIES 4 +/* + * The tick period that will be configured in the RTOS for the simulated + * time base, in microseconds. This in turn is used to drive the 1hz clock + * and other functions. + * + * On the MCP750 the sysClockRate runs at 60Hz so this is the same period + * that the cFE software timebase will be configured at. + */ +#define CFE_PSP_SOFT_TIMEBASE_PERIOD 16666 + /* ** Typedef for the layout of the vxWorks boot record structure ** diff --git a/fsw/mcp750-vxworks/psp_module_list.cmake b/fsw/mcp750-vxworks/psp_module_list.cmake index ba9cd802..e9e6bb66 100644 --- a/fsw/mcp750-vxworks/psp_module_list.cmake +++ b/fsw/mcp750-vxworks/psp_module_list.cmake @@ -1,4 +1,5 @@ -# This is a list of modules that is included as a fixed/base set +# This is a list of modules that is included as a fixed/base set # when this PSP is selected. They must exist under fsw/modules +soft_timebase eeprom_direct diff --git a/fsw/mcp750-vxworks/src/cfe_psp_start.c b/fsw/mcp750-vxworks/src/cfe_psp_start.c index c8c2484d..a64c6f3c 100644 --- a/fsw/mcp750-vxworks/src/cfe_psp_start.c +++ b/fsw/mcp750-vxworks/src/cfe_psp_start.c @@ -74,7 +74,6 @@ IMPORT void sysPciWrite32(UINT32, UINT32); #define CFE_PSP_MAIN_FUNCTION (*GLOBAL_CONFIGDATA.CfeConfig->SystemMain) #define CFE_PSP_NONVOL_STARTUP_FILE (GLOBAL_CONFIGDATA.CfeConfig->NonvolStartupFile) -#define CFE_PSP_1HZ_FUNCTION (*GLOBAL_CONFIGDATA.CfeConfig->System1HzISR) /****************************************************************************** ** Function: OS_Application_Startup() @@ -232,30 +231,3 @@ void OS_Application_Startup(void) */ CFE_PSP_MAIN_FUNCTION(reset_type, reset_subtype, 1, CFE_PSP_NONVOL_STARTUP_FILE); } - -/****************************************************************************** -** Function: OS_Application_Run() -** -** Purpose: -** Idle Loop entry point from OSAL BSP. -** -** Arguments: -** (none) -** -** Return: -** (none) -*/ -void OS_Application_Run(void) -{ - int TicksPerSecond; - - /* - ** Main loop for default task and simulated 1hz - */ - for (;;) - { - TicksPerSecond = sysClkRateGet(); - (void)taskDelay(TicksPerSecond); - CFE_PSP_1HZ_FUNCTION(); - } -} diff --git a/fsw/modules/soft_timebase/CMakeLists.txt b/fsw/modules/soft_timebase/CMakeLists.txt new file mode 100644 index 00000000..29a077dc --- /dev/null +++ b/fsw/modules/soft_timebase/CMakeLists.txt @@ -0,0 +1,3 @@ + +# Create the module +add_psp_module(soft_timebase cfe_psp_soft_timebase.c) diff --git a/fsw/modules/soft_timebase/cfe_psp_soft_timebase.c b/fsw/modules/soft_timebase/cfe_psp_soft_timebase.c new file mode 100644 index 00000000..b9d9e4fb --- /dev/null +++ b/fsw/modules/soft_timebase/cfe_psp_soft_timebase.c @@ -0,0 +1,82 @@ +/* +** GSC-18128-1, "Core Flight Executive Version 6.7" +** +** Copyright (c) 2006-2019 United States Government as represented by +** the Administrator of the National Aeronautics and Space Administration. +** All Rights Reserved. +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +/** + * \file cfe_psp_soft_timebase.c + * + * A PSP module that instantiates an RTOS-backed OSAL timebase to provide + * various timing services. This in turn may be used to drive CFE TIME 1Hz + * signal, the CFS SCH major/minor frame sync and other periodic services + * in CFE. + * + * This module can be used on systems which do not have a hardware + * source for the 1Hz signal or timing info (i.e. simulation, test + * and debug platforms, etc). + */ + +#include "cfe_psp.h" +#include "cfe_psp_module.h" +#include "cfe_psp_config.h" + +CFE_PSP_MODULE_DECLARE_SIMPLE(soft_timebase); + +/* + * Global state data for this module (not exposed publicly) + */ +static struct +{ + osal_id_t sys_timebase_id; +} PSP_SoftTimebase_Global; + +void soft_timebase_Init(uint32 PspModuleId) +{ + int32 status; + + memset(&PSP_SoftTimebase_Global, 0, sizeof(PSP_SoftTimebase_Global)); + + /* Set up the OSAL timebase using the well-known name */ + status = OS_TimeBaseCreate(&PSP_SoftTimebase_Global.sys_timebase_id, CFE_PSP_SOFT_TIMEBASE_NAME, NULL); + if (status == OS_SUCCESS) + { + /* Set the timebase to trigger with desired resolution */ + status = OS_TimeBaseSet(PSP_SoftTimebase_Global.sys_timebase_id, CFE_PSP_SOFT_TIMEBASE_PERIOD, + CFE_PSP_SOFT_TIMEBASE_PERIOD); + } + + /* + * The only way this can fail is through a misconfiguration or API incompatibility - + * if it fails, it means all timing related functions are likely to be broken, + * CFE TIME may not work correctly, and background jobs will not run. + * + * Might even be worth a CFE_PSP_Panic(), but it still may be possible + * to boot CFE and (maybe) save the system by uploading a file with the bug fixed. + */ + if (status != OS_SUCCESS) + { + printf("CFE_PSP: *** Failed to configure software timebase \'%s\', status = %d! ***\n", + CFE_PSP_SOFT_TIMEBASE_NAME, (int)status); + } + else + { + /* Inform the user that this module is in use */ + printf("CFE_PSP: Instantiated software timebase \'%s\' running at %lu usec\n", CFE_PSP_SOFT_TIMEBASE_NAME, + (unsigned long)CFE_PSP_SOFT_TIMEBASE_PERIOD); + } +} diff --git a/fsw/pc-linux/inc/cfe_psp_config.h b/fsw/pc-linux/inc/cfe_psp_config.h index 02c66a2a..316a9529 100644 --- a/fsw/pc-linux/inc/cfe_psp_config.h +++ b/fsw/pc-linux/inc/cfe_psp_config.h @@ -65,6 +65,19 @@ /* use the "USR1" signal to wake the idle thread when an exception occurs */ #define CFE_PSP_EXCEPTION_EVENT_SIGNAL SIGUSR1 +/* + * The tick period that will be configured in the RTOS for the simulated + * time base, in microseconds. This in turn is used to drive the 1hz clock + * and other functions. + * + * To minimize jitter in the resulting callbacks, it should be an even + * divisor of 1000000 usec. + * + * Note - 10ms/100Hz is chosen to also allow this same timebase to be + * used to drive the CFS SCH minor frame callbacks in its default config. + */ +#define CFE_PSP_SOFT_TIMEBASE_PERIOD 10000 + /* ** Global variables */ diff --git a/fsw/pc-linux/psp_module_list.cmake b/fsw/pc-linux/psp_module_list.cmake index 54ffb4c5..0f295787 100644 --- a/fsw/pc-linux/psp_module_list.cmake +++ b/fsw/pc-linux/psp_module_list.cmake @@ -1,4 +1,5 @@ -# This is a list of modules that is included as a fixed/base set +# This is a list of modules that is included as a fixed/base set # when this PSP is selected. They must exist under fsw/modules +soft_timebase eeprom_mmap_file diff --git a/fsw/pc-linux/src/cfe_psp_start.c b/fsw/pc-linux/src/cfe_psp_start.c index ff0479ea..4e709a62 100644 --- a/fsw/pc-linux/src/cfe_psp_start.c +++ b/fsw/pc-linux/src/cfe_psp_start.c @@ -113,10 +113,8 @@ typedef struct /* ** Prototypes for this module */ -void CFE_PSP_TimerHandler(int signum); void CFE_PSP_DisplayUsage(char *Name); void CFE_PSP_ProcessArgumentDefaults(CFE_PSP_CommandData_t *CommandDataDefault); -void CFE_PSP_SetupLocal1Hz(void); /* ** Global variables @@ -212,8 +210,6 @@ void OS_Application_Startup(void) { uint32 reset_type; uint32 reset_subtype; - int32 time_status; - osal_id_t sys_timebase_id; osal_id_t fs_id; int opt = 0; int longIndex = 0; @@ -342,41 +338,6 @@ void OS_Application_Startup(void) memset(&CFE_PSP_IdleTaskState, 0, sizeof(CFE_PSP_IdleTaskState)); CFE_PSP_IdleTaskState.ThreadID = pthread_self(); - /* - ** Set up the timebase, if OSAL supports it - ** Done here so that the modules can also use it, if desired - ** - ** This is a clock named "cFS-Master" that will serve to drive - ** all time-related CFE functions including the 1Hz signal. - ** - ** Note the timebase is only prepared here; the application is - ** not ready to receive a callback yet, as it hasn't been started. - ** CFE TIME registers its own callback when it is ready to do so. - */ - time_status = OS_TimeBaseCreate(&sys_timebase_id, "cFS-Master", NULL); - if (time_status == OS_SUCCESS) - { - /* - * Set the clock to trigger with 50ms resolution - slow enough that - * it will not hog CPU resources but fast enough to have sufficient resolution - * for most general timing purposes. - * (It may be better to move this to the mission config file) - */ - time_status = OS_TimeBaseSet(sys_timebase_id, 50000, 50000); - } - else - { - /* - * Cannot create a timebase in OSAL. - * - * Note: Most likely this is due to building with - * the old/classic POSIX OSAL which does not support this. - * - * See below for workaround. - */ - sys_timebase_id = OS_OBJECT_ID_UNDEFINED; - } - /* ** Set up the virtual FS mapping for the "/cf" directory ** On this platform it is just a local/relative dir of the same name. @@ -453,15 +414,6 @@ void OS_Application_Startup(void) ** Call cFE entry point. */ CFE_PSP_MAIN_FUNCTION(reset_type, reset_subtype, 1, CFE_PSP_NONVOL_STARTUP_FILE); - - /* - * Backward compatibility for old OSAL. - */ - if (!OS_ObjectIdDefined(sys_timebase_id) || time_status != OS_SUCCESS) - { - OS_printf("CFE_PSP: WARNING - Compatibility mode - using local 1Hz Interrupt\n"); - CFE_PSP_SetupLocal1Hz(); - } } void OS_Application_Run(void) @@ -522,31 +474,6 @@ void OS_Application_Run(void) OS_DeleteAllObjects(); } -/****************************************************************************** -** Function: CFE_PSP_TimerHandler() -** -** Purpose: -** 1hz "isr" routine for linux/OSX -** This timer handler will execute 4 times a second. -** -** Arguments: -** (none) -** -** Return: -** (none) -*/ -void CFE_PSP_TimerHandler(int signum) -{ - /* - ** call the CFE_TIME 1hz ISR - */ - if ((TimerCounter % 4) == 0) - CFE_PSP_1HZ_FUNCTION(); - - /* update timer counter */ - TimerCounter++; -} - /****************************************************************************** ** Function: CFE_PSP_DisplayUsage ** @@ -639,72 +566,3 @@ void CFE_PSP_ProcessArgumentDefaults(CFE_PSP_CommandData_t *CommandDataDefault) CommandDataDefault->GotCpuName = 1; } } - -/****************************************************************************** -** Function: CFE_PSP_SetupLocal1Hz -** -** Purpose: -** This is a backward-compatible timer setup that is invoked when -** there is a failure to set up the timebase in OSAL. It is basically -** the old way of doing things. -** -** IMPORTANT: Note this is technically incorrect as it gives the -** callback directly in the context of the signal handler. It is -** against spec to use most OSAL functions within a signal. -** -** This is included merely to mimic the previous system behavior. It -** should be removed in a future version of the PSP. -** -** -** Arguments: -** (none) -** -** Return: -** (none) -** -*/ - -void CFE_PSP_SetupLocal1Hz(void) -{ - struct sigaction sa; - struct itimerval timer; - int ret; - - /* - ** Init timer counter - */ - TimerCounter = 0; - - /* - ** Install timer_handler as the signal handler for SIGALRM. - */ - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = &CFE_PSP_TimerHandler; - - /* - ** Configure the timer to expire after 250ms - ** - ** (this is historical; the actual callback is invoked - ** only on every 4th timer tick. previous versions of the - ** PSP did it this way, so this is preserved here). - */ - timer.it_value.tv_sec = 0; - timer.it_value.tv_usec = 250000; - timer.it_interval.tv_sec = 0; - timer.it_interval.tv_usec = 250000; - - ret = sigaction(SIGALRM, &sa, NULL); - - if (ret < 0) - { - OS_printf("CFE_PSP: sigaction() error %d: %s \n", ret, strerror(errno)); - } - else - { - ret = setitimer(ITIMER_REAL, &timer, NULL); - if (ret < 0) - { - OS_printf("CFE_PSP: setitimer() error %d: %s \n", ret, strerror(errno)); - } - } -} diff --git a/fsw/pc-rtems/inc/cfe_psp_config.h b/fsw/pc-rtems/inc/cfe_psp_config.h index 376d2f75..2ef50afe 100644 --- a/fsw/pc-rtems/inc/cfe_psp_config.h +++ b/fsw/pc-rtems/inc/cfe_psp_config.h @@ -43,6 +43,19 @@ */ #define CFE_PSP_MAX_EXCEPTION_ENTRIES 1 +/* + * The tick period that will be configured in the RTOS for the simulated + * time base, in microseconds. This in turn is used to drive the 1hz clock + * and other functions. + * + * To minimize jitter in the resulting callbacks, it should be an even + * divisor of 1000000 usec. + * + * Note - 10ms/100Hz is chosen to also allow this same timebase to be + * used to drive the CFS SCH minor frame callbacks in its default config. + */ +#define CFE_PSP_SOFT_TIMEBASE_PERIOD 10000 + /* ** Typedef for the layout of the header in the reserved memory block */ diff --git a/fsw/pc-rtems/psp_module_list.cmake b/fsw/pc-rtems/psp_module_list.cmake index 38b24e37..4eb1ac4f 100644 --- a/fsw/pc-rtems/psp_module_list.cmake +++ b/fsw/pc-rtems/psp_module_list.cmake @@ -1,4 +1,5 @@ -# This is a list of modules that is included as a fixed/base set +# This is a list of modules that is included as a fixed/base set # when this PSP is selected. They must exist under fsw/modules eeprom_stub +soft_timebase diff --git a/fsw/pc-rtems/src/cfe_psp_start.c b/fsw/pc-rtems/src/cfe_psp_start.c index 66361c4a..d3057131 100644 --- a/fsw/pc-rtems/src/cfe_psp_start.c +++ b/fsw/pc-rtems/src/cfe_psp_start.c @@ -131,51 +131,6 @@ int CFE_PSP_Setup(void) return RTEMS_SUCCESSFUL; } -/****************************************************************************** -** Function: CFE_PSP_SetupSystemTimer -** -** Purpose: -** BSP system time base and timer object setup. -** This does the necessary work to start the 1Hz time tick required by CFE -** -** Arguments: -** (none) -** -** Return: -** (none) -** -** NOTE: -** The handles to the timebase/timer objects are "start and forget" -** as they are supposed to run forever as long as CFE runs. -** -** If needed for e.g. additional timer creation, they can be recovered -** using an OSAL GetIdByName() call. -** -** This is preferred anyway -- far cleaner than trying to pass the uint32 value -** up to the application somehow. -*/ - -void CFE_PSP_SetupSystemTimer(void) -{ - osal_id_t SystemTimebase; - int32 Status; - - Status = OS_TimeBaseCreate(&SystemTimebase, "cFS-Master", NULL); - if (Status == OS_SUCCESS) - { - Status = OS_TimeBaseSet(SystemTimebase, 250000, 250000); - } - - /* - * If anything failed, cFE/cFS will not run properly, so a panic is appropriate - */ - if (Status != OS_SUCCESS) - { - OS_printf("CFE_PSP: Error configuring cFS timing: %d\n", (int)Status); - CFE_PSP_Panic(Status); - } -} - /* ** A simple entry point to start from the BSP loader ** @@ -263,9 +218,6 @@ void CFE_PSP_Main(void) */ CFE_PSP_ModuleInit(); - /* Prepare the system timing resources */ - CFE_PSP_SetupSystemTimer(); - /* ** Determine Reset type by reading the hardware reset register. */