diff --git a/fsw/shared/generic_imu_device.c b/fsw/shared/generic_imu_device.c new file mode 100644 index 0000000..084bd60 --- /dev/null +++ b/fsw/shared/generic_imu_device.c @@ -0,0 +1,208 @@ +/******************************************************************************* +** File: generic_imu_device.c +** +** Purpose: +** This file contains the source code for the GENERIC_IMU device. +** +*******************************************************************************/ + +/* +** Include Files +*/ +#include "generic_imu_device.h" + +// Both of the below constants are defined to allow the greatest possible precision +// without overflow on a range of -10tx_frame.can_id = GENERIC_IMU_CFG_CAN_ID; + device->tx_frame.can_dlc = data_len; + CFE_PSP_MemCpy((void*)device->tx_frame.data, data, CAN_MAX_DLEN); + + /* RX Frame */ + device->rx_frame.can_id = GENERIC_IMU_CFG_CAN_ID; + device->rx_frame.can_dlc = 0; + CFE_PSP_MemSet((void*)device->rx_frame.data, 0x00, CAN_MAX_DLEN); +} + +/* +** Generic read data from device +*/ +int32_t GENERIC_IMU_ReadData(can_info_t *canDevice, uint8_t data_length) +{ + int32_t status = OS_SUCCESS; + + /* Wait until all data received or timeout occurs */ + status = can_master_transaction(canDevice); + if (status != CAN_SUCCESS) + { + #ifdef GENERIC_IMU_CFG_DEBUG + OS_printf("GENERIC_IMU_ReadData: GENERIC_IMU_ReadData can_master_transaction failed with %d error! \n", status); + #endif + status = CAN_ERROR; + } + return status; +} + + +/* +** Generic command to device +** Note that confirming the echoed response is specific to this implementation +*/ +int32_t GENERIC_IMU_CommandDevice(can_info_t *canDevice, uint8_t cmd_code) +{ + int32_t status = OS_SUCCESS; + uint8_t write_data[GENERIC_IMU_DEVICE_CMD_SIZE] = {0}; + + /* Prepare command */ + write_data[0] = GENERIC_IMU_DEVICE_HDR; + write_data[1] = cmd_code; + + GENERIC_IMU_FramePrep(canDevice, write_data, GENERIC_IMU_DEVICE_CMD_SIZE); + status = GENERIC_IMU_ReadData(canDevice, GENERIC_IMU_DEVICE_CMD_SIZE); + if (status != OS_SUCCESS) + { + #ifdef GENERIC_IMU_CFG_DEBUG + OS_printf("GENERIC_IMU_CommandDevice - GENERIC_IMU_ReadData returned %d \n", status); + #endif + } + return status; +} + + +/* +** Request housekeeping command +*/ +int32_t GENERIC_IMU_RequestHK(can_info_t *canDevice, GENERIC_IMU_Device_HK_tlm_t* data) +{ + int32_t status = OS_SUCCESS; + + status = GENERIC_IMU_CommandDevice(canDevice, GENERIC_IMU_DEVICE_REQ_HK_CMD); + if (status == OS_SUCCESS) + { + #ifdef GENERIC_IMU_CFG_DEBUG + OS_printf(" GENERIC_IMU_RequestHK[%d] = ", canDevice->rx_frame.can_dlc); + for (uint32_t i = 0; i < canDevice->rx_frame.can_dlc; i++) + { + OS_printf("%02x", canDevice->rx_frame.data[i]); + } + OS_printf("\n"); + #endif + + data->DeviceCounter = canDevice->rx_frame.data[0] << 24; + data->DeviceCounter |= canDevice->rx_frame.data[1] << 16; + data->DeviceCounter |= canDevice->rx_frame.data[2] << 8; + data->DeviceCounter |= canDevice->rx_frame.data[3]; + + data->DeviceStatus = canDevice->rx_frame.data[4] << 24; + data->DeviceStatus |= canDevice->rx_frame.data[5] << 16; + data->DeviceStatus |= canDevice->rx_frame.data[6] << 8; + data->DeviceStatus |= canDevice->rx_frame.data[7]; + + #ifdef GENERIC_IMU_CFG_DEBUG + OS_printf(" Counter = 0x%08x \n", data->DeviceCounter); + OS_printf(" Status = 0x%08x \n", data->DeviceStatus); + #endif + } + return status; +} + + +/* +** Request Axis +*/ +int32_t GENERIC_IMU_RequestAxis(can_info_t *canDevice, GENERIC_IMU_Device_Axis_Data_t* data, uint8_t cmd_code) +{ + int32_t status = OS_SUCCESS; + uint32_t la_tmp; + uint32_t aa_tmp; + + status = GENERIC_IMU_CommandDevice(canDevice, cmd_code); + if (status == OS_SUCCESS) + { + #ifdef GENERIC_IMU_CFG_DEBUG + OS_printf(" GENERIC_IMU_RequestAxis %d, [%d] = ", cmd_code, canDevice->rx_frame.can_dlc); + for (uint32_t i = 0; i < canDevice->rx_frame.can_dlc; i++) + { + OS_printf("%02x", canDevice->rx_frame.data[i]); + } + OS_printf("\n"); + #endif + + /* Verify return frame length */ + + /* Proces data */ + la_tmp = canDevice->rx_frame.data[0] << 24; + la_tmp |= canDevice->rx_frame.data[1] << 16; + la_tmp |= canDevice->rx_frame.data[2] << 8; + la_tmp |= canDevice->rx_frame.data[3]; + + aa_tmp = canDevice->rx_frame.data[4] << 24; + aa_tmp |= canDevice->rx_frame.data[5] << 16; + aa_tmp |= canDevice->rx_frame.data[6] << 8; + aa_tmp |= canDevice->rx_frame.data[7]; + + /* Float conversion */ + data->LinearAcc = (float) ((la_tmp - (LIN_CONV_CONST*10.0)) / LIN_CONV_CONST); + data->AngularAcc = (float) ((aa_tmp - (ANG_CONV_CONST*400.0)) / ANG_CONV_CONST); + } + else + { + #ifdef GENERIC_IMU_CFG_DEBUG + OS_printf(" GENERIC_IMU_RequestAxis: Invalid data read! \n"); + #endif + status = OS_ERROR; + } + return status; +} + + +/* +** Request data command +*/ +int32_t GENERIC_IMU_RequestData(can_info_t *canDevice, GENERIC_IMU_Device_Data_tlm_t* data) +{ + int32_t status = OS_SUCCESS; + + status = GENERIC_IMU_RequestAxis(canDevice, &data->X_Data, GENERIC_IMU_DEVICE_REQ_X_DATA_CMD); + if (status == OS_SUCCESS) + { + status = GENERIC_IMU_RequestAxis(canDevice, &data->Y_Data, GENERIC_IMU_DEVICE_REQ_Y_DATA_CMD); + if (status == OS_SUCCESS) + { + status = GENERIC_IMU_RequestAxis(canDevice, &data->Z_Data, GENERIC_IMU_DEVICE_REQ_Z_DATA_CMD); + } + } + + #ifdef GENERIC_IMU_CFG_DEBUG + if (status != OS_SUCCESS) + { + OS_printf(" GENERIC_IMU_RequestData: Error %d reported in GENERIC_IMU_RequestAxis \n", status); + } + OS_printf("GENERIC_IMU_RequestData\n"); + OS_printf(" Linear X = 0x%08x, ", data->X_Data.LinearAcc); + OS_printf("%f \n", data->X_Data.LinearAcc); + OS_printf(" Angular X = 0x%08x, ", data->X_Data.AngularAcc); + OS_printf("%f \n", data->X_Data.AngularAcc); + OS_printf(" Linear Y = 0x%08x, ", data->Y_Data.LinearAcc); + OS_printf("%f \n", data->Y_Data.LinearAcc); + OS_printf(" Angular Y = 0x%08x, ", data->Y_Data.AngularAcc); + OS_printf("%f \n", data->Y_Data.AngularAcc); + OS_printf(" Linear Z = 0x%08x, ", data->Z_Data.LinearAcc); + OS_printf("%f \n", data->Z_Data.LinearAcc); + OS_printf(" Angular Z = 0x%08x, ", data->Z_Data.AngularAcc); + OS_printf("%f \n", data->Z_Data.AngularAcc); + OS_printf("\n"); + #endif + + return status; +} + diff --git a/fsw/shared/generic_imu_device.h b/fsw/shared/generic_imu_device.h new file mode 100644 index 0000000..9048ece --- /dev/null +++ b/fsw/shared/generic_imu_device.h @@ -0,0 +1,98 @@ +/******************************************************************************* +** File: generic_imu_device.h +** +** Purpose: +** This is the header file for the GENERIC_IMU device. +** +*******************************************************************************/ +#ifndef _GENERIC_IMU_DEVICE_H_ +#define _GENERIC_IMU_DEVICE_H_ + +/* +** Required header files. +*/ +#include "device_cfg.h" +#include "hwlib.h" +#include "generic_imu_platform_cfg.h" + + +/* +** Type definitions +** TODO: Make specific to your application +*/ +#define GENERIC_IMU_DEVICE_HDR 0x80 +#define GENERIC_IMU_DEVICE_CMD_SIZE 2 +#define GENERIC_IMU_DEVICE_HDR_TRL_LEN 1 + +#define GENERIC_IMU_DEVICE_NOOP_CMD 0x00 +#define GENERIC_IMU_DEVICE_REQ_HK_CMD 0x01 +#define GENERIC_IMU_DEVICE_REQ_X_DATA_CMD 0x02 +#define GENERIC_IMU_DEVICE_REQ_Y_DATA_CMD 0x03 +#define GENERIC_IMU_DEVICE_REQ_Z_DATA_CMD 0x04 + + +/* +** GENERIC_IMU device housekeeping telemetry definition +*/ +typedef struct +{ + uint32_t DeviceCounter; + uint32_t DeviceStatus; + +} __attribute__((packed)) GENERIC_IMU_Device_HK_tlm_t; +#define GENERIC_IMU_DEVICE_HK_LNGTH sizeof ( GENERIC_IMU_Device_HK_tlm_t ) +#define GENERIC_IMU_DEVICE_HK_SIZE GENERIC_IMU_DEVICE_HK_LNGTH + GENERIC_IMU_DEVICE_HDR_TRL_LEN + +/* +** IMU Command Message +*/ +typedef struct +{ + uint8_t CmdHeader[sizeof(CFE_MSG_CommandHeader_t)]; + uint8_t msg_type; + uint8_t cmd_id; + uint8_t src_mask; + uint8_t dest_mask; + uint8_t data_len; + uint8_t data[CAN_MAX_DLEN]; +} __attribute__((packed)) GENERIC_IMU_Cmd_t; +#define GENERIC_IMU_CMD_LEN (sizeof(GENERIC_IMU_Cmd_t)) + + +/* +** GENERIC_IMU device data definition for each individual axis +*/ +typedef struct +{ + float LinearAcc; + float AngularAcc; +} __attribute__((packed)) GENERIC_IMU_Device_Axis_Data_t; +#define GENERIC_IMU_DEVICE_AXIS_DATA_LNGTH sizeof ( GENERIC_IMU_Device_Axis_Data_t ) +#define GENERIC_IMU_DEVICE_X_DATA_SIZE GENERIC_IMU_DEVICE_X_DATA_LNGTH + GENERIC_IMU_DEVICE_HDR_TRL_LEN + + +/* +** GENERIC_IMU device data telemetry definition +*/ +typedef struct +{ + GENERIC_IMU_Device_Axis_Data_t X_Data; + GENERIC_IMU_Device_Axis_Data_t Y_Data; + GENERIC_IMU_Device_Axis_Data_t Z_Data; + +} __attribute__((packed)) GENERIC_IMU_Device_Data_tlm_t; +#define GENERIC_IMU_DEVICE_DATA_LNGTH sizeof ( GENERIC_IMU_Device_Data_tlm_t ) +#define GENERIC_IMU_DEVICE_DATA_SIZE GENERIC_IMU_DEVICE_DATA_LNGTH + GENERIC_IMU_DEVICE_HDR_TRL_LEN + + +/* +** Prototypes +*/ +void GENERIC_IMU_FramePrep(can_info_t *device, uint8_t* data, uint8_t data_len); +int32_t GENERIC_IMU_ReadData(can_info_t *canDevice, uint8_t data_length); +int32_t GENERIC_IMU_CommandDevice(can_info_t *canDevice, uint8_t cmd_code); +int32_t GENERIC_IMU_RequestHK(can_info_t *canDevice, GENERIC_IMU_Device_HK_tlm_t* data); +int32_t GENERIC_IMU_RequestAxis(can_info_t *canDevice, GENERIC_IMU_Device_Axis_Data_t* data, uint8_t cmd_code); +int32_t GENERIC_IMU_RequestData(can_info_t *canDevice, GENERIC_IMU_Device_Data_tlm_t* data); + +#endif /* _GENERIC_IMU_DEVICE_H_ */ diff --git a/fsw/standalone/CMakeLists.txt b/fsw/standalone/CMakeLists.txt new file mode 100644 index 0000000..3fc9d9c --- /dev/null +++ b/fsw/standalone/CMakeLists.txt @@ -0,0 +1,65 @@ +cmake_minimum_required(VERSION 2.6.4) + +project (generic_imu_checkout) + +if (NOT DEFINED TGTNAME) + message(FATAL_ERROR "TGTNAME must be defined on the cmake command line (e.g. \"-DTGTNAME=cpu1\")") +endif() + +include(../../../ComponentSettings.cmake) + +if(${TGTNAME} STREQUAL cpu1) + find_path(_ITC_CMAKE_MODULES_ + NAMES FindITC_Common.cmake + PATHS ${ITC_CMAKE_MODULES} + ${ITC_DEV_ROOT}/cmake/modules + $ENV{ITC_DEV_ROOT}/cmake/modules + /usr/local/cmake/modules + /usr/cmake/modules) + if(NOT _ITC_CMAKE_MODULES_) + message(WARNING "Unable to find ITC CMake Modules") + endif() + set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${_ITC_CMAKE_MODULES_}) + + find_package(NOSENGINE REQUIRED QUIET COMPONENTS common transport client uart can i2c spi) +endif() + +include_directories("./") +include_directories("../cfs/platform_inc") +include_directories("../cfs/src") +include_directories("../shared") +include_directories("../../../../fsw/apps/hwlib/fsw/public_inc") + +set(generic_imu_checkout_src + generic_imu_checkout.c + ../shared/generic_imu_device.c +) + +if(${TGTNAME} STREQUAL cpu1) + include_directories("../../../../fsw/apps/hwlib/sim/inc") + set(generic_imu_checkout_src + ${generic_imu_checkout_src} + ../../../../fsw/apps/hwlib/sim/src/libuart.c + ../../../../fsw/apps/hwlib/sim/src/libcan.c + ../../../../fsw/apps/hwlib/sim/src/libi2c.c + ../../../../fsw/apps/hwlib/sim/src/libspi.c + ../../../../fsw/apps/hwlib/sim/src/nos_link.c + ) + set(generic_imu_checkout_libs + ${ITC_Common_LIBRARIES} + ${NOSENGINE_LIBRARIES} + ) +endif() +if(${TGTNAME} STREQUAL cpu2) + set(generic_imu_checkout_src + ${generic_imu_checkout_src} + ../../../../fsw/apps/hwlib/fsw/linux/libuart.c + ) +endif() + +add_executable(generic_imu_checkout ${generic_imu_checkout_src}) +target_link_libraries(generic_imu_checkout ${generic_imu_checkout_libs}) + +if(${TGTNAME} STREQUAL cpu1) + set_target_properties(generic_imu_checkout PROPERTIES COMPILE_FLAGS "-g" LINK_FLAGS "-g") +endif() diff --git a/fsw/standalone/device_cfg.h b/fsw/standalone/device_cfg.h new file mode 100644 index 0000000..745bf0c --- /dev/null +++ b/fsw/standalone/device_cfg.h @@ -0,0 +1,15 @@ +#ifndef _GENERIC_imu_CHECKOUT_DEVICE_CFG_H_ +#define _GENERIC_imu_CHECKOUT_DEVICE_CFG_H_ + +/* +** GENERIC_imu Checkout Configuration +*/ +#define GENERIC_imu_CFG +/* Note: NOS3 uart requires matching handle and bus number */ +#define GENERIC_imu_CFG_STRING "/dev/usart_16" +#define GENERIC_imu_CFG_HANDLE 16 +#define GENERIC_imu_CFG_BAUDRATE_HZ 115200 +#define GENERIC_imu_CFG_MS_TIMEOUT 250 +#define GENERIC_imu_CFG_DEBUG + +#endif /* _GENERIC_imu_CHECKOUT_DEVICE_CFG_H_ */ diff --git a/fsw/standalone/generic_imu_checkout.c b/fsw/standalone/generic_imu_checkout.c new file mode 100644 index 0000000..414b795 --- /dev/null +++ b/fsw/standalone/generic_imu_checkout.c @@ -0,0 +1,286 @@ +/******************************************************************************* +** File: generic_imu_checkout.c +** +** Purpose: +** This checkout can be run without cFS and is used to quickly develop and +** test functions required for a specific component. +** +*******************************************************************************/ + +/* +** Include Files +*/ +#include "generic_imu_checkout.h" + +/* +** Global Variables +*/ +uart_info_t Generic_imuUart; +GENERIC_imu_Device_HK_tlm_t Generic_imuHK; +GENERIC_imu_Device_Data_tlm_t Generic_imuData; + +/* +** Component Functions +*/ +void print_help(void) +{ + printf(PROMPT "command [args]\n" + "---------------------------------------------------------------------\n" + "help - Display help \n" + "exit - Exit app \n" + "noop - No operation command to device \n" + " n - ^ \n" + "hk - Request device housekeeping \n" + " h - ^ \n" + "generic_imu - Request generic_imu data \n" + " s - ^ \n" + "cfg # - Send configuration # \n" + " c # - ^ \n" + "\n" + ); +} + + +int get_command(const char* str) +{ + int status = CMD_UNKNOWN; + char lcmd[MAX_INPUT_TOKEN_SIZE]; + strncpy(lcmd, str, MAX_INPUT_TOKEN_SIZE); + + /* Convert command to lower case */ + to_lower(lcmd); + + if(strcmp(lcmd, "help") == 0) + { + status = CMD_HELP; + } + else if(strcmp(lcmd, "exit") == 0) + { + status = CMD_EXIT; + } + else if(strcmp(lcmd, "noop") == 0) + { + status = CMD_NOOP; + } + else if(strcmp(lcmd, "n") == 0) + { + status = CMD_NOOP; + } + else if(strcmp(lcmd, "hk") == 0) + { + status = CMD_HK; + } + else if(strcmp(lcmd, "h") == 0) + { + status = CMD_HK; + } + else if(strcmp(lcmd, "generic_imu") == 0) + { + status = CMD_GENERIC_imu; + } + else if(strcmp(lcmd, "s") == 0) + { + status = CMD_GENERIC_imu; + } + else if(strcmp(lcmd, "cfg") == 0) + { + status = CMD_CFG; + } + else if(strcmp(lcmd, "c") == 0) + { + status = CMD_CFG; + } + return status; +} + + +int process_command(int cc, int num_tokens, char tokens[MAX_INPUT_TOKENS][MAX_INPUT_TOKEN_SIZE]) +{ + int32_t status = OS_SUCCESS; + int32_t exit_status = OS_SUCCESS; + uint32_t config; + + /* Process command */ + switch(cc) + { + case CMD_HELP: + print_help(); + break; + + case CMD_EXIT: + exit_status = OS_ERROR; + break; + + case CMD_NOOP: + if (check_number_arguments(num_tokens, 0) == OS_SUCCESS) + { + status = GENERIC_imu_CommandDevice(&Generic_imuUart, GENERIC_imu_DEVICE_NOOP_CMD, 0); + if (status == OS_SUCCESS) + { + OS_printf("NOOP command success\n"); + } + else + { + OS_printf("NOOP command failed!\n"); + } + } + break; + + case CMD_HK: + if (check_number_arguments(num_tokens, 0) == OS_SUCCESS) + { + status = GENERIC_imu_RequestHK(&Generic_imuUart, &Generic_imuHK); + if (status == OS_SUCCESS) + { + OS_printf("GENERIC_imu_RequestHK command success\n"); + } + else + { + OS_printf("GENERIC_imu_RequestHK command failed!\n"); + } + } + break; + + case CMD_GENERIC_imu: + if (check_number_arguments(num_tokens, 0) == OS_SUCCESS) + { + status = GENERIC_imu_RequestData(&Generic_imuUart, &Generic_imuData); + if (status == OS_SUCCESS) + { + OS_printf("GENERIC_imu_RequestData command success\n"); + } + else + { + OS_printf("GENERIC_imu_RequestData command failed!\n"); + } + } + break; + + case CMD_CFG: + if (check_number_arguments(num_tokens, 1) == OS_SUCCESS) + { + config = atoi(tokens[0]); + status = GENERIC_imu_CommandDevice(&Generic_imuUart, GENERIC_imu_DEVICE_CFG_CMD, config); + if (status == OS_SUCCESS) + { + OS_printf("Configuration command success with value %u\n", config); + } + else + { + OS_printf("Configuration command failed!\n"); + } + } + break; + + default: + OS_printf("Invalid command format, type 'help' for more info\n"); + break; + } + return exit_status; +} + + +int main(int argc, char *argv[]) +{ + int status = OS_SUCCESS; + char input_buf[MAX_INPUT_BUF]; + char input_tokens[MAX_INPUT_TOKENS][MAX_INPUT_TOKEN_SIZE]; + int num_input_tokens; + int cmd; + char* token_ptr; + uint8_t run_status = OS_SUCCESS; + + /* Initialize HWLIB */ + #ifdef _NOS_ENGINE_LINK_ + nos_init_link(); + #endif + + /* Open device specific protocols */ + Generic_imuUart.deviceString = GENERIC_imu_CFG_STRING; + Generic_imuUart.handle = GENERIC_imu_CFG_HANDLE; + Generic_imuUart.isOpen = PORT_CLOSED; + Generic_imuUart.baud = GENERIC_imu_CFG_BAUDRATE_HZ; + status = uart_init_port(&Generic_imuUart); + if (status == OS_SUCCESS) + { + printf("UART device %s configured with baudrate %d \n", Generic_imuUart.deviceString, Generic_imuUart.baud); + } + else + { + printf("UART device %s failed to initialize! \n", Generic_imuUart.deviceString); + run_status = OS_ERROR; + } + + /* Main loop */ + print_help(); + while(run_status == OS_SUCCESS) + { + num_input_tokens = -1; + cmd = CMD_UNKNOWN; + + /* Read user input */ + printf(PROMPT); + fgets(input_buf, MAX_INPUT_BUF, stdin); + + /* Tokenize line buffer */ + token_ptr = strtok(input_buf, " \t\n"); + while((num_input_tokens < MAX_INPUT_TOKENS) && (token_ptr != NULL)) + { + if(num_input_tokens == -1) + { + /* First token is command */ + cmd = get_command(token_ptr); + } + else + { + strncpy(input_tokens[num_input_tokens], token_ptr, MAX_INPUT_TOKEN_SIZE); + } + token_ptr = strtok(NULL, " \t\n"); + num_input_tokens++; + } + + /* Process command if valid */ + if(num_input_tokens >= 0) + { + /* Process command */ + run_status = process_command(cmd, num_input_tokens, input_tokens); + } + } + + // Close the device + uart_close_port(&Generic_imuUart); + + #ifdef _NOS_ENGINE_LINK_ + nos_destroy_link(); + #endif + + OS_printf("Cleanly exiting generic_imu application...\n\n"); + return 1; +} + + +/* +** Generic Functions +*/ +int check_number_arguments(int actual, int expected) +{ + int status = OS_SUCCESS; + if (actual != expected) + { + status = OS_ERROR; + OS_printf("Invalid command format, type 'help' for more info\n"); + } + return status; +} + +void to_lower(char* str) +{ + char* ptr = str; + while(*ptr) + { + *ptr = tolower((unsigned char) *ptr); + ptr++; + } + return; +} + diff --git a/fsw/standalone/generic_imu_checkout.h b/fsw/standalone/generic_imu_checkout.h new file mode 100644 index 0000000..a23c496 --- /dev/null +++ b/fsw/standalone/generic_imu_checkout.h @@ -0,0 +1,67 @@ +/******************************************************************************* +** File: generic_imu_checkout.h +** +** Purpose: +** This is the header file for the GENERIC_imu checkout. +** +*******************************************************************************/ +#ifndef _GENERIC_imu_CHECKOUT_H_ +#define _GENERIC_imu_CHECKOUT_H_ + +/* +** Includes +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hwlib.h" +#include "device_cfg.h" +#include "generic_imu_device.h" + +#if TGTNAME == cpu1 + #include "nos_link.h" +#endif + +/* +** Standard Defines +*/ +#define PROMPT "generic_imu> " +#define MAX_INPUT_BUF 512 +#define MAX_INPUT_TOKENS 64 +#define MAX_INPUT_TOKEN_SIZE 50 +#define TELEM_BUF_LEN 8 + +/* +** Command Defines +*/ +#define CMD_UNKNOWN -1 +#define CMD_HELP 0 +#define CMD_EXIT 1 +#define CMD_NOOP 2 +#define CMD_HK 3 +#define CMD_GENERIC_imu 4 +#define CMD_CFG 5 + +/* +** Prototypes +*/ +void print_help(void); +int get_command(const char* str); +int main(int argc, char *argv[]); + +/* +** Generic Prototypes +*/ +int check_number_arguments(int actual, int expected); +void to_lower(char* str); + +#endif /* _GENERIC_imu_CHECKOUT_H_ */ diff --git a/fsw/unit-test/CMakeLists.txt b/fsw/unit-test/CMakeLists.txt new file mode 100644 index 0000000..fd69324 --- /dev/null +++ b/fsw/unit-test/CMakeLists.txt @@ -0,0 +1,46 @@ +################################################################## +# +# Coverage Unit Test build recipe +# +# This CMake file contains the recipe for building the generic_imu unit tests. +# It is invoked from the parent directory when unit tests are enabled. +# +################################################################## + +# +# +# NOTE on the subdirectory structures here: +# +# - "inc" provides local header files shared between the coveragetest, +# wrappers, and overrides source code units +# - "coveragetest" contains source code for the actual unit test cases +# The primary objective is to get line/path coverage on the FSW +# code units. +# + +# Use the UT assert public API, and allow direct +# inclusion of source files that are normally private +include_directories(${PROJECT_SOURCE_DIR}/fsw/src) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/inc) +include_directories(${hwlib_MISSION_DIR}/fsw/public_inc) + + +# Add a coverage test executable called "generic_imu-ALL" that +# covers all of the functions in generic_imu_app. +# +# Also note in a more complex app/lib the coverage test can also +# be broken down into smaller units (in which case one should use +# a unique suffix other than "ALL" for each unit). For example, +# OSAL implements a separate coverage test per source unit. +add_cfe_coverage_test(generic_imu ALL + "coveragetest/coveragetest_generic_imu_app.c" + "../src/generic_imu_app.c" + "../src/generic_imu_device.c" + "../../../../fsw/apps/hwlib/fsw/stubs/libuart.c" +) + +# The generic_imu uses library functions provided by generic_imu_lib so must be linked +# with the generic_imu_lib stub library (this is mainly just an example of how this +# can be done). +#add_cfe_coverage_dependency(generic_imu ALL generic_imu_lib) + diff --git a/fsw/unit-test/coveragetest/coveragetest_generic_imu_app.c b/fsw/unit-test/coveragetest/coveragetest_generic_imu_app.c new file mode 100644 index 0000000..0aec9a8 --- /dev/null +++ b/fsw/unit-test/coveragetest/coveragetest_generic_imu_app.c @@ -0,0 +1,467 @@ +/* +** 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: coveragetest_generic_imu_app.c +** +** Purpose: +** Coverage Unit Test cases for the GENERIC_imu Application +** +** Notes: +** This implements various test cases to exercise all code +** paths through all functions defined in the GENERIC_imu application. +** +** It is primarily focused at providing examples of the various +** stub configurations, hook functions, and wrapper calls that +** are often needed when coercing certain code paths through +** complex functions. +*/ + +/* + * Includes + */ + +#include "generic_imu_app_coveragetest_common.h" +#include "ut_generic_imu_app.h" + +/* to get the GENERIC_imu_LIB_Function() declaration */ + +typedef struct +{ + uint16 ExpectedEvent; + uint32 MatchCount; + const char *ExpectedFormat; +} UT_CheckEvent_t; + +/* + * An example hook function to check for a specific event. + */ +static int32 UT_CheckEvent_Hook(void *UserObj, int32 StubRetcode, uint32 CallCount, const UT_StubContext_t *Context, + va_list va) +{ + UT_CheckEvent_t *State = UserObj; + uint16 EventId; + const char * Spec; + + /* + * The CFE_EVS_SendEvent stub passes the EventID as the + * first context argument. + */ + if (Context->ArgCount > 0) + { + EventId = UT_Hook_GetArgValueByName(Context, "EventID", uint16); + if (EventId == State->ExpectedEvent) + { + if (State->ExpectedFormat != NULL) + { + Spec = UT_Hook_GetArgValueByName(Context, "Spec", const char *); + if (Spec != NULL) + { + /* + * Example of how to validate the full argument set. + * ------------------------------------------------ + * + * If really desired one can call something like: + * + * char TestText[CFE_MISSION_EVS_MAX_MESSAGE_LENGTH]; + * vsnprintf(TestText, sizeof(TestText), Spec, va); + * + * And then compare the output (TestText) to the expected fully-rendered string. + * + * NOTE: While this can be done, use with discretion - This isn't really + * verifying that the FSW code unit generated the correct event text, + * rather it is validating what the system snprintf() library function + * produces when passed the format string and args. + * + * This type of check has been demonstrated to make tests very fragile, + * because it is influenced by many factors outside the control of the + * test case. + * + * __This derived string is not an actual output of the unit under test__ + */ + if (strcmp(Spec, State->ExpectedFormat) == 0) + { + ++State->MatchCount; + } + } + } + else + { + ++State->MatchCount; + } + } + } + + return 0; +} + +/* + * Helper function to set up for event checking + * This attaches the hook function to CFE_EVS_SendEvent + */ +static void UT_CheckEvent_Setup(UT_CheckEvent_t *Evt, uint16 ExpectedEvent, const char *ExpectedFormat) +{ + memset(Evt, 0, sizeof(*Evt)); + Evt->ExpectedEvent = ExpectedEvent; + Evt->ExpectedFormat = ExpectedFormat; + UT_SetVaHookFunction(UT_KEY(CFE_EVS_SendEvent), UT_CheckEvent_Hook, Evt); +} + +/* +********************************************************************************** +** TEST CASE FUNCTIONS +********************************************************************************** +*/ + +void Test_GENERIC_imu_AppMain(void) +{ + CFE_SB_MsgId_t MsgId = CFE_SB_INVALID_MSG_ID; + + /* + * Test Case For: + * void GENERIC_imu_AppMain( void ) + */ + + UT_CheckEvent_t EventTest; + + /* + * GENERIC_imu_AppMain does not return a value, + * but it has several internal decision points + * that need to be exercised here. + * + * First call it in "nominal" mode where all + * dependent calls should be successful by default. + */ + GENERIC_imu_AppMain(); + + /* + * Confirm that CFE_ES_ExitApp() was called at the end of execution + */ + UtAssert_True(UT_GetStubCount(UT_KEY(CFE_ES_ExitApp)) == 1, "CFE_ES_ExitApp() called"); + + /* + * Now set up individual cases for each of the error paths. + * The first is for GENERIC_imu_AppInit(). As this is in the same + * code unit, it is not a stub where the return code can be + * easily set. In order to get this to fail, an underlying + * call needs to fail, and the error gets propagated through. + * The call to CFE_EVS_Register is the first opportunity. + * Any identifiable (non-success) return code should work. + */ + UT_SetDeferredRetcode(UT_KEY(CFE_EVS_Register), 1, CFE_EVS_INVALID_PARAMETER); + + /* + * Just call the function again. It does not return + * the value, so there is nothing to test for here directly. + * However, it should show up in the coverage report that + * the GENERIC_imu_AppInit() failure path was taken. + */ + GENERIC_imu_AppMain(); + + /* + * This can validate that the internal "RunStatus" was + * set to CFE_ES_RunStatus_APP_ERROR, by querying the struct directly. + * + * It is always advisable to include the _actual_ values + * when asserting on conditions, so if/when it fails, the + * log will show what the incorrect value was. + */ + UtAssert_True(GENERIC_imu_AppData.RunStatus == CFE_ES_RunStatus_APP_ERROR, + "GENERIC_imu_AppData.RunStatus (%lu) == CFE_ES_RunStatus_APP_ERROR", + (unsigned long)GENERIC_imu_AppData.RunStatus); + + /* + * Note that CFE_ES_RunLoop returns a boolean value, + * so in order to exercise the internal "while" loop, + * it needs to return TRUE. But this also needs to return + * FALSE in order to get out of the loop, otherwise + * it will stay there infinitely. + * + * The deferred retcode will accomplish this. + */ + UT_SetDeferredRetcode(UT_KEY(CFE_ES_RunLoop), 1, true); + + /* Set up buffer for command processing */ + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &MsgId, sizeof(MsgId), false); + + /* + * Invoke again + */ + GENERIC_imu_AppMain(); + + /* + * Confirm that CFE_SB_ReceiveBuffer() (inside the loop) was called + */ + UtAssert_True(UT_GetStubCount(UT_KEY(CFE_SB_ReceiveBuffer)) == 1, "CFE_SB_ReceiveBuffer() called"); + + /* + * Now also make the CFE_SB_ReceiveBuffer call fail, + * to exercise that error path. This sends an + * event which can be checked with a hook function. + */ + UT_SetDeferredRetcode(UT_KEY(CFE_ES_RunLoop), 1, true); + UT_SetDeferredRetcode(UT_KEY(CFE_SB_ReceiveBuffer), 1, CFE_SB_PIPE_RD_ERR); + UT_CheckEvent_Setup(&EventTest, GENERIC_imu_PIPE_ERR_EID, "GENERIC_imu: SB Pipe Read Error = %d"); + + /* + * Invoke again + */ + GENERIC_imu_AppMain(); + + /* + * Confirm that the event was generated + */ + UtAssert_True(EventTest.MatchCount == 1, "GENERIC_imu_PIPE_ERR_EID generated (%u)", + (unsigned int)EventTest.MatchCount); +} + +void Test_GENERIC_imu_AppInit(void) +{ + /* + * Test Case For: + * int32 GENERIC_imu_AppInit( void ) + */ + + /* nominal case should return CFE_SUCCESS */ + UT_TEST_FUNCTION_RC(GENERIC_imu_AppInit(), CFE_SUCCESS); + + /* trigger a failure for each of the sub-calls, + * and confirm a write to syslog for each. + * Note that this count accumulates, because the status + * is _not_ reset between these test cases. */ + UT_SetDeferredRetcode(UT_KEY(CFE_EVS_Register), 1, CFE_EVS_INVALID_PARAMETER); + UT_TEST_FUNCTION_RC(GENERIC_imu_AppInit(), CFE_EVS_INVALID_PARAMETER); + UtAssert_True(UT_GetStubCount(UT_KEY(CFE_ES_WriteToSysLog)) == 1, "CFE_ES_WriteToSysLog() called"); + + UT_SetDeferredRetcode(UT_KEY(CFE_SB_CreatePipe), 1, CFE_SB_BAD_ARGUMENT); + UT_TEST_FUNCTION_RC(GENERIC_imu_AppInit(), CFE_SB_BAD_ARGUMENT); + + UT_SetDeferredRetcode(UT_KEY(CFE_SB_Subscribe), 1, CFE_SB_BAD_ARGUMENT); + UT_TEST_FUNCTION_RC(GENERIC_imu_AppInit(), CFE_SB_BAD_ARGUMENT); + + UT_SetDeferredRetcode(UT_KEY(CFE_SB_Subscribe), 2, CFE_SB_BAD_ARGUMENT); + UT_TEST_FUNCTION_RC(GENERIC_imu_AppInit(), CFE_SB_BAD_ARGUMENT); +} + +void Test_GENERIC_imu_ProcessCommandPacket(void) +{ + /* + * Test Case For: + * void GENERIC_imu_ProcessCommandPacket + */ + /* a buffer large enough for any command message */ + union + { + CFE_SB_Buffer_t SBBuf; + GENERIC_imu_NoArgs_cmd_t Noop; + } TestMsg; + CFE_SB_MsgId_t TestMsgId; + CFE_MSG_FcnCode_t FcnCode; + size_t MsgSize; + UT_CheckEvent_t EventTest; + + memset(&TestMsg, 0, sizeof(TestMsg)); + UT_CheckEvent_Setup(&EventTest, GENERIC_imu_PROCESS_CMD_ERR_EID, NULL); + + /* + * The CFE_MSG_GetMsgId() stub uses a data buffer to hold the + * message ID values to return. + */ + TestMsgId = CFE_SB_ValueToMsgId(GENERIC_imu_CMD_MID); + FcnCode = GENERIC_imu_NOOP_CC; + MsgSize = sizeof(TestMsg.Noop); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &TestMsgId, sizeof(TestMsgId), false); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &TestMsgId, sizeof(TestMsgId), false); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetFcnCode), &FcnCode, sizeof(FcnCode), false); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetSize), &MsgSize, sizeof(MsgSize), false); + GENERIC_imu_ProcessCommandPacket(); + UtAssert_True(EventTest.MatchCount == 0, "GENERIC_imu_CMD_ERR_EID not generated (%u)", + (unsigned int)EventTest.MatchCount); + + /* invalid message id */ + TestMsgId = CFE_SB_INVALID_MSG_ID; + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &TestMsgId, sizeof(TestMsgId), false); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetFcnCode), &FcnCode, sizeof(FcnCode), false); + GENERIC_imu_ProcessCommandPacket(); + UtAssert_True(EventTest.MatchCount == 1, "GENERIC_imu_CMD_ERR_EID generated (%u)", + (unsigned int)EventTest.MatchCount); +} + +void Test_GENERIC_imu_ProcessGroundCommand(void) +{ + /* + * Test Case For: + * void GENERIC_imu_ProcessGroundCommand + */ + CFE_SB_MsgId_t TestMsgId = CFE_SB_ValueToMsgId(GENERIC_imu_CMD_MID); + CFE_MSG_FcnCode_t FcnCode; + size_t Size; + + /* a buffer large enough for any command message */ + union + { + CFE_SB_Buffer_t SBBuf; + GENERIC_imu_NoArgs_cmd_t Noop; + GENERIC_imu_NoArgs_cmd_t Reset; + } TestMsg; + UT_CheckEvent_t EventTest; + + memset(&TestMsg, 0, sizeof(TestMsg)); + + /* + * call with each of the supported command codes + * The CFE_MSG_GetFcnCode stub allows the code to be + * set to whatever is needed. There is no return + * value here and the actual implementation of these + * commands have separate test cases, so this just + * needs to exercise the "switch" statement. + */ + + /* test dispatch of NOOP */ + FcnCode = GENERIC_imu_NOOP_CC; + Size = sizeof(TestMsg.Noop); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &TestMsgId, sizeof(TestMsgId), false); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetFcnCode), &FcnCode, sizeof(FcnCode), false); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetSize), &Size, sizeof(Size), false); + UT_CheckEvent_Setup(&EventTest, GENERIC_imu_CMD_NOOP_INF_EID, NULL); + GENERIC_imu_ProcessGroundCommand(); + UtAssert_True(EventTest.MatchCount == 1, "GENERIC_imu_CMD_NOOP_INF_EID generated (%u)", + (unsigned int)EventTest.MatchCount); + + /* test dispatch of RESET */ + FcnCode = GENERIC_imu_RESET_COUNTERS_CC; + Size = sizeof(TestMsg.Reset); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &TestMsgId, sizeof(TestMsgId), false); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetFcnCode), &FcnCode, sizeof(FcnCode), false); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetSize), &Size, sizeof(Size), false); + UT_CheckEvent_Setup(&EventTest, GENERIC_imu_CMD_RESET_INF_EID, NULL); + GENERIC_imu_ProcessGroundCommand(); + UtAssert_True(EventTest.MatchCount == 1, "GENERIC_imu_CMD_RESET_INF_EID generated (%u)", + (unsigned int)EventTest.MatchCount); + + /* test an invalid CC */ + FcnCode = 99; + Size = sizeof(TestMsg.Noop); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &TestMsgId, sizeof(TestMsgId), false); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetFcnCode), &FcnCode, sizeof(FcnCode), false); + UT_CheckEvent_Setup(&EventTest, GENERIC_imu_CMD_ERR_EID, NULL); + GENERIC_imu_ProcessGroundCommand(); + UtAssert_True(EventTest.MatchCount == 1, "GENERIC_imu_CMD_ERR_EID generated (%u)", + (unsigned int)EventTest.MatchCount); +} + +void Test_GENERIC_imu_ReportHousekeeping(void) +{ + /* + * Test Case For: + * void GENERIC_imu_ReportHousekeeping() + */ + CFE_MSG_Message_t *MsgSend; + CFE_MSG_Message_t *MsgTimestamp; + CFE_SB_MsgId_t MsgId = CFE_SB_ValueToMsgId(GENERIC_imu_REQ_HK_TLM); + + /* Set message id to return so GENERIC_imu_Housekeeping will be called */ + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &MsgId, sizeof(MsgId), false); + + /* Set up to capture send message address */ + UT_SetDataBuffer(UT_KEY(CFE_SB_TransmitMsg), &MsgSend, sizeof(MsgSend), false); + + /* Set up to capture timestamp message address */ + UT_SetDataBuffer(UT_KEY(CFE_SB_TimeStampMsg), &MsgTimestamp, sizeof(MsgTimestamp), false); + + /* Call unit under test, NULL pointer confirms command access is through APIs */ + GENERIC_imu_ReportHousekeeping(); + + /* Confirm message sent*/ + UtAssert_True(UT_GetStubCount(UT_KEY(CFE_SB_TransmitMsg)) == 1, "CFE_SB_TransmitMsg() called once"); + UtAssert_True(MsgSend == &GENERIC_imu_AppData.HkTelemetryPkt.TlmHeader.Msg, "CFE_SB_TransmitMsg() address matches expected"); + + /* Confirm timestamp msg address */ + UtAssert_True(UT_GetStubCount(UT_KEY(CFE_SB_TimeStampMsg)) == 1, "CFE_SB_TimeStampMsg() called once"); + UtAssert_True(MsgTimestamp == &GENERIC_imu_AppData.HkTelemetryPkt.TlmHeader.Msg, + "CFE_SB_TimeStampMsg() address matches expected"); +} + +void Test_GENERIC_imu_VerifyCmdLength(void) +{ + /* + * Test Case For: + * bool GENERIC_imu_VerifyCmdLength + */ + UT_CheckEvent_t EventTest; + size_t size = 1; + CFE_MSG_FcnCode_t fcncode = 2; + CFE_SB_MsgId_t msgid = CFE_SB_ValueToMsgId(GENERIC_imu_CMD_MID); + + /* + * test a match case + */ + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetSize), &size, sizeof(size), false); + UT_CheckEvent_Setup(&EventTest, GENERIC_imu_LEN_ERR_EID, NULL); + + GENERIC_imu_VerifyCmdLength(NULL, size); + + /* + * Confirm that the event was NOT generated + */ + UtAssert_True(EventTest.MatchCount == 0, "GENERIC_imu_LEN_ERR_EID NOT generated (%u)", + (unsigned int)EventTest.MatchCount); + + /* + * test a mismatch case + */ + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetSize), &size, sizeof(size), false); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &msgid, sizeof(msgid), false); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetFcnCode), &fcncode, sizeof(fcncode), false); + UT_CheckEvent_Setup(&EventTest, GENERIC_imu_LEN_ERR_EID, NULL); + GENERIC_imu_VerifyCmdLength(NULL, size + 1); + + /* + * Confirm that the event WAS generated + */ + UtAssert_True(EventTest.MatchCount == 1, "GENERIC_imu_LEN_ERR_EID generated (%u)", + (unsigned int)EventTest.MatchCount); +} + +/* + * Setup function prior to every test + */ +void Generic_imu_UT_Setup(void) +{ + UT_ResetState(0); +} + +/* + * Teardown function after every test + */ +void Generic_imu_UT_TearDown(void) {} + +/* + * Register the test cases to execute with the unit test tool + */ +void UtTest_Setup(void) +{ + ADD_TEST(GENERIC_imu_AppMain); + ADD_TEST(GENERIC_imu_AppInit); + ADD_TEST(GENERIC_imu_ProcessCommandPacket); + ADD_TEST(GENERIC_imu_ProcessGroundCommand); + ADD_TEST(GENERIC_imu_ReportHousekeeping); + ADD_TEST(GENERIC_imu_VerifyCmdLength); +} diff --git a/fsw/unit-test/coveragetest/generic_imu_app_coveragetest_common.h b/fsw/unit-test/coveragetest/generic_imu_app_coveragetest_common.h new file mode 100644 index 0000000..d9ddf4e --- /dev/null +++ b/fsw/unit-test/coveragetest/generic_imu_app_coveragetest_common.h @@ -0,0 +1,67 @@ +/* +** 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 + * + * Common definitions for all generic_imu_app coverage tests + */ + +#ifndef GENERIC_imu_APP_COVERAGETEST_COMMON_H +#define GENERIC_imu_APP_COVERAGETEST_COMMON_H + +/* + * Includes + */ + +#include "utassert.h" +#include "uttest.h" +#include "utstubs.h" + +#include "cfe.h" +#include "generic_imu_events.h" +#include "generic_imu_app.h" + +/* + * Macro to call a function and check its int32 return code + */ +#define UT_TEST_FUNCTION_RC(func, exp) \ + { \ + int32 rcexp = exp; \ + int32 rcact = func; \ + UtAssert_True(rcact == rcexp, "%s (%ld) == %s (%ld)", #func, (long)rcact, #exp, (long)rcexp); \ + } + +/* + * Macro to add a test case to the list of tests to execute + */ +#define ADD_TEST(test) UtTest_Add((Test_##test), Generic_imu_UT_Setup, Generic_imu_UT_TearDown, #test) + +/* + * Setup function prior to every test + */ +void Generic_imu_UT_Setup(void); + +/* + * Teardown function after every test + */ +void Generic_imu_UT_TearDown(void); + +#endif /* GENERIC_imu_APP_COVERAGETEST_COMMON_H */ diff --git a/fsw/unit-test/inc/ut_generic_imu_app.h b/fsw/unit-test/inc/ut_generic_imu_app.h new file mode 100644 index 0000000..ed37f6f --- /dev/null +++ b/fsw/unit-test/inc/ut_generic_imu_app.h @@ -0,0 +1,51 @@ +/* +** 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 + * + * + * Purpose: + * Extra scaffolding functions for the generic_imu_app unit test + * + * Notes: + * This is an extra UT-specific extern declaration + * to obtain access to an internal data structure + * + * UT often needs to modify internal data structures in ways that + * actual applications never would (bypassing the normal API) in + * order to exercise or set up for off-nominal cases. + */ + +#ifndef UT_GENERIC_imu_APP_H +#define UT_GENERIC_imu_APP_H + +/* + * Necessary to include these here to get the definition of the + * "GENERIC_imu_APP_Data_t" typedef. + */ +#include "generic_imu_app.h" + +/* + * Allow UT access to the global "GENERIC_imu_APP_Data" object. + */ +//extern GENERIC_imu_AppData_t GENERIC_imu_APP_Data; + +#endif /* UT_GENERIC_imu_APP_H */