Merge remote-tracking branch 'origin/development' into gaisser_countdown_timer

This commit is contained in:
Steffen Gaisser 2021-09-27 21:06:20 +02:00
commit 1b38f84edc
858 changed files with 10826 additions and 2599 deletions

View File

@ -1,17 +1,81 @@
## Changes from ASTP 1.0.0 to 1.1.0
# Changed from ASTP 1.1.0 to 1.2.0
## API Changes
### FSFW Architecture
- New src folder which contains all source files except the HAL, contributed code and test code
- External and internal API mostly stayed the same
- Folder names are now all smaller case: internalError was renamed to internalerror and
FreeRTOS was renamed to freertos
- Warning if optional headers are used but the modules was not added to the source files to compile
### HAL
- HAL added back into FSFW. It is tightly bound to the FSFW, and compiling it as a static library
made using it more complicated than necessary
## Bugfixes
### FreeRTOS QueueMapManager
- Fixed a bug which causes the first generated Queue ID to be invalid
## Enhancements
### FSFW Architecture
- See API changes chapter. This change will keep the internal API consistent in the future
# Changes from ASTP 1.0.0 to 1.1.0
## API Changes
### PUS
- Added PUS C support
- SUBSYSTEM_IDs added for PUS Services
- Added new Parameter which must be defined in config: fsfwconfig::FSFW_MAX_TM_PACKET_SIZE
### ObjectManager
- ObjectManager is now a singelton
### Configuration
- Additional configuration option fsfwconfig::FSFW_MAX_TM_PACKET_SIZE which
need to be specified in FSFWConfig.h
### CMake
- Changed Cmake FSFW_ADDITIONAL_INC_PATH to FSFW_ADDITIONAL_INC_PATHS
## Bugfixes
- timemanager/TimeStamperIF.h: Timestamp config was not used correctly, leading to different timestamp sizes than configured in fsfwconfig::FSFW_MISSION_TIMESTAMP_SIZE
- TCP server fixes
## Enhancements
### FreeRTOS Queue Handles
- Fixed an internal issue how FreeRTOS MessageQueues were handled
### Linux OSAL
- Better printf error messages
### CMake
- Check for C++11 as mininimum required Version
### Debug Output
- Changed Warning color to magenta, which is well readable on both dark and light mode IDEs
## Changes from ASTP 0.0.1 to 1.0.0
# Changes from ASTP 0.0.1 to 1.0.0
### Host OSAL

View File

@ -3,20 +3,33 @@ cmake_minimum_required(VERSION 3.13)
option(FSFW_GENERATE_SECTIONS
"Generate function and data sections. Required to remove unused code" ON
)
if(FSFW_GENERATE_SECTIONS)
option(FSFW_REMOVE_UNUSED_CODE "Remove unused code" ON)
endif()
option(FSFW_WARNING_SHADOW_LOCAL_GCC "Enable -Wshadow=local warning in GCC" ON)
# Options to exclude parts of the FSFW from compilation.
option(FSFW_USE_RMAP "Compile with RMAP" ON)
option(FSFW_USE_DATALINKLAYER "Compile with Data Link Layer" ON)
option(FSFW_ADD_INTERNAL_TESTS "Add internal unit tests" ON)
option(FSFW_ADD_UNITTESTS "Add regular unittests. Requires Catch2" OFF)
option(FSFW_ADD_HAL "Add Hardware Abstraction Layer" ON)
# Optional sources
option(FSFW_ADD_PUS "Compile with PUS sources" ON)
option(FSFW_ADD_MONITORING "Compile with monitoring components" ON)
option(FSFW_ADD_RMAP "Compile with RMAP" OFF)
option(FSFW_ADD_DATALINKLAYER "Compile with Data Link Layer" OFF)
option(FSFW_ADD_COORDINATES "Compile with coordinate components" OFF)
option(FSFW_ADD_TMSTORAGE "Compile with tm storage components" OFF)
# Contrib sources
option(FSFW_ADD_SGP4_PROPAGATOR "Add SGP4 propagator code" OFF)
set(LIB_FSFW_NAME fsfw)
add_library(${LIB_FSFW_NAME})
set(FSFW_CORE_INC_PATH "inc")
set_property(CACHE OS_FSFW PROPERTY STRINGS host linux rtems freertos)
set_property(CACHE FSFW_OSAL PROPERTY STRINGS host linux rtems freertos)
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 11)
@ -25,100 +38,61 @@ elseif(${CMAKE_CXX_STANDARD} LESS 11)
message(FATAL_ERROR "Compiling the FSFW requires a minimum of C++11 support")
endif()
if(NOT OS_FSFW)
message(STATUS "No OS for FSFW via OS_FSFW set. Assuming host OS")
# Backwards comptability
if(OS_FSFW AND NOT FSFW_OSAL)
message(WARNING "Please pass the FSFW OSAL as FSFW_OSAL instead of OS_FSFW")
set(FSFW_OSAL OS_FSFW)
endif()
if(NOT FSFW_OSAL)
message(STATUS "No OS for FSFW via FSFW_OSAL set. Assuming host OS")
# Assume host OS and autodetermine from OS_FSFW
if(UNIX)
set(OS_FSFW "linux"
set(FSFW_OSAL "linux"
CACHE STRING
"OS abstraction layer used in the FSFW"
)
elseif(WIN32)
set(OS_FSFW "host"
set(FSFW_OSAL "host"
CACHE STRING "OS abstraction layer used in the FSFW"
)
endif()
endif()
set(FSFW_OSAL_DEFINITION FSFW_HOST)
set(FSFW_OSAL_DEFINITION FSFW_OSAL_HOST)
if(${OS_FSFW} STREQUAL host)
set(OS_FSFW_NAME "Host")
elseif(${OS_FSFW} STREQUAL linux)
set(OS_FSFW_NAME "Linux")
set(FSFW_OSAL_DEFINITION FSFW_LINUX)
elseif(${OS_FSFW} STREQUAL freertos)
set(OS_FSFW_NAME "FreeRTOS")
set(FSFW_OSAL_DEFINITION FSFW_FREERTOS)
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
if(FSFW_OSAL MATCHES host)
set(OS_FSFW_NAME "Host")
set(FSFW_OSAL_HOST ON)
elseif(FSFW_OSAL MATCHES linux)
set(OS_FSFW_NAME "Linux")
set(FSFW_OSAL_LINUX ON)
elseif(FSFW_OSAL MATCHES freertos)
set(OS_FSFW_NAME "FreeRTOS")
set(FSFW_OSAL_FREERTOS ON)
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
${LIB_OS_NAME}
)
elseif(${OS_FSFW} STREQUAL rtems)
set(OS_FSFW_NAME "RTEMS")
set(FSFW_OSAL_DEFINITION FSFW_RTEMS)
)
elseif(FSFW_OSAL STREQUAL rtems)
set(OS_FSFW_NAME "RTEMS")
set(FSFW_OSAL_RTEMS ON)
else()
message(WARNING
"Invalid operating system for FSFW specified! Setting to host.."
)
set(OS_FSFW_NAME "Host")
set(OS_FSFW "host")
message(WARNING
"Invalid operating system for FSFW specified! Setting to host.."
)
set(OS_FSFW_NAME "Host")
set(OS_FSFW "host")
endif()
target_compile_definitions(${LIB_FSFW_NAME} PRIVATE
${FSFW_OSAL_DEFINITION}
)
target_compile_definitions(${LIB_FSFW_NAME} INTERFACE
${FSFW_OSAL_DEFINITION}
)
message(STATUS "Compiling FSFW for the ${OS_FSFW_NAME} operating system.")
add_subdirectory(action)
add_subdirectory(container)
add_subdirectory(controller)
add_subdirectory(coordinates)
if(FSFW_USE_DATALINKLAYER)
add_subdirectory(datalinklayer)
add_subdirectory(src)
add_subdirectory(tests)
if(FSFW_ADD_HAL)
add_subdirectory(hal)
endif()
add_subdirectory(datapool)
add_subdirectory(datapoollocal)
add_subdirectory(housekeeping)
add_subdirectory(devicehandlers)
add_subdirectory(events)
add_subdirectory(fdir)
add_subdirectory(globalfunctions)
add_subdirectory(health)
add_subdirectory(internalError)
add_subdirectory(ipc)
add_subdirectory(memory)
add_subdirectory(modes)
add_subdirectory(monitoring)
add_subdirectory(objectmanager)
add_subdirectory(osal)
add_subdirectory(parameters)
add_subdirectory(power)
add_subdirectory(pus)
if(FSFW_USE_RMAP)
add_subdirectory(rmap)
endif()
add_subdirectory(serialize)
add_subdirectory(serviceinterface)
add_subdirectory(storagemanager)
add_subdirectory(subsystem)
add_subdirectory(tasks)
add_subdirectory(tcdistribution)
add_subdirectory(thermal)
add_subdirectory(timemanager)
add_subdirectory(tmstorage)
add_subdirectory(tmtcpacket)
add_subdirectory(tmtcservices)
add_subdirectory(unittest)
add_subdirectory(contrib)
# The project CMakeLists file has to set the FSFW_CONFIG_PATH and add it.
# If this is not given, we include the default configuration and emit a warning.
@ -191,6 +165,7 @@ endif()
target_include_directories(${LIB_FSFW_NAME} INTERFACE
${CMAKE_SOURCE_DIR}
${FSFW_CONFIG_PATH_ABSOLUTE}
${FSFW_CORE_INC_PATH}
${FSFW_ADD_INC_PATHS_ABS}
)
@ -200,6 +175,7 @@ target_include_directories(${LIB_FSFW_NAME} INTERFACE
target_include_directories(${LIB_FSFW_NAME} PRIVATE
${CMAKE_SOURCE_DIR}
${FSFW_CONFIG_PATH_ABSOLUTE}
${FSFW_CORE_INC_PATH}
${FSFW_ADD_INC_PATHS_ABS}
)

7
FSFW.h
View File

@ -1,7 +0,0 @@
#ifndef FSFW_FSFW_H_
#define FSFW_FSFW_H_
#include "FSFWConfig.h"
#endif /* FSFW_FSFW_H_ */

View File

@ -1,12 +0,0 @@
#ifndef FSFW_DEFAULTCFG_VERSION_H_
#define FSFW_DEFAULTCFG_VERSION_H_
const char* const FSFW_VERSION_NAME = "ASTP";
#define FSFW_VERSION 1
#define FSFW_SUBVERSION 0
#define FSFW_REVISION 0
#endif /* FSFW_DEFAULTCFG_VERSION_H_ */

View File

@ -1,4 +1,4 @@
![FSFW Logo](logo/FSFW_Logo_V3_bw.png)
![FSFW Logo](misc/logo/FSFW_Logo_V3_bw.png)
# Flight Software Framework (FSFW)

9
contrib/CMakeLists.txt Normal file
View File

@ -0,0 +1,9 @@
target_include_directories(${LIB_FSFW_NAME} PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
)
target_include_directories(${LIB_FSFW_NAME} INTERFACE
${CMAKE_CURRENT_SOURCE_DIR}
)
add_subdirectory(fsfw_contrib)

View File

@ -0,0 +1,11 @@
if(FSFW_ADD_SGP4_PROPAGATOR)
target_sources(${LIB_FSFW_NAME} PRIVATE
sgp4/sgp4unit.cpp
)
target_include_directories(${LIB_FSFW_NAME} PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/sgp4
)
target_include_directories(${LIB_FSFW_NAME} INTERFACE
${CMAKE_CURRENT_SOURCE_DIR}/sgp4
)
endif()

View File

@ -1,12 +0,0 @@
#ifndef FSFW_DATAPOOLLOCAL_DATAPOOLLOCAL_H_
#define FSFW_DATAPOOLLOCAL_DATAPOOLLOCAL_H_
/* Collected related headers */
#include "LocalPoolVariable.h"
#include "LocalPoolVector.h"
#include "StaticLocalDataSet.h"
#include "LocalDataSet.h"
#include "SharedLocalDataSet.h"
#endif /* FSFW_DATAPOOLLOCAL_DATAPOOLLOCAL_H_ */

View File

@ -1,15 +0,0 @@
CXXSRC += $(wildcard $(CURRENTPATH)/ipc/*.cpp)
CXXSRC += $(wildcard $(CURRENTPATH)/objects/*.cpp)
CXXSRC += $(wildcard $(CURRENTPATH)/pollingsequence/*.cpp)
CXXSRC += $(wildcard $(CURRENTPATH)/events/*.cpp)
CXXSRC += $(wildcard $(CURRENTPATH)/tmtc/*.cpp)
CXXSRC += $(wildcard $(CURRENTPATH)/devices/*.cpp)
INCLUDES += $(CURRENTPATH)
INCLUDES += $(CURRENTPATH)/objects
INCLUDES += $(CURRENTPATH)/returnvalues
INCLUDES += $(CURRENTPATH)/tmtc
INCLUDES += $(CURRENTPATH)/events
INCLUDES += $(CURRENTPATH)/devices
INCLUDES += $(CURRENTPATH)/pollingsequence
INCLUDES += $(CURRENTPATH)/ipc

View File

@ -1,7 +0,0 @@
target_sources(${LIB_FSFW_NAME}
PRIVATE
EventManager.cpp
EventMessage.cpp
)
add_subdirectory(eventmatching)

75
fsfw.mk
View File

@ -1,75 +0,0 @@
# This submake file needs to be included by the primary Makefile.
# This file needs FRAMEWORK_PATH and OS_FSFW set correctly by another Makefile.
# Valid API settings: rtems, linux, freeRTOS, host
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/action/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/container/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/contrib/sgp4/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/controller/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/coordinates/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/datalinklayer/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/datapool/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/datapoollocal/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/datapoollocal/internal/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/housekeeping/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/devicehandlers/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/events/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/events/eventmatching/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/fdir/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/globalfunctions/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/globalfunctions/matching/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/globalfunctions/math/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/health/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/internalError/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/ipc/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/memory/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/modes/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/monitoring/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/objectmanager/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/osal/*.cpp)
# select the OS
ifeq ($(OS_FSFW),rtems)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/osal/rtems/*.cpp)
else ifeq ($(OS_FSFW),linux)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/osal/linux/*.cpp)
else ifeq ($(OS_FSFW),freeRTOS)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/osal/FreeRTOS/*.cpp)
else ifeq ($(OS_FSFW),host)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/osal/host/*.cpp)
ifeq ($(OS),Windows_NT)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/osal/windows/*.cpp)
else
# For now, the linux UDP bridge sources needs to be included manually by upper makefile
# for host OS because we can't be sure the OS is linux.
# Following lines can be used to do this:
# CXXSRC += $(FRAMEWORK_PATH)/osal/linux/TcUnixUdpPollingTask.cpp
# CXXSRC += $(FRAMEWORK_PATH)/osal/linux/TmTcUnixUdpBridge.cpp
endif
else
$(error invalid OS_FSFW specified, valid OS_FSFW are rtems, linux, freeRTOS, host)
endif
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/parameters/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/power/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/returnvalues/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/rmap/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/serialize/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/serviceinterface/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/storagemanager/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/subsystem/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/subsystem/modes/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/tasks/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/tcdistribution/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/thermal/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/timemanager/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/tmstorage/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/tmtcpacket/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/tmtcpacket/packetmatcher/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/tmtcpacket/pus/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/tmtcservices/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/pus/*.cpp)

View File

@ -1,124 +0,0 @@
#include "../globalfunctions/DleEncoder.h"
DleEncoder::DleEncoder() {}
DleEncoder::~DleEncoder() {}
ReturnValue_t DleEncoder::encode(const uint8_t* sourceStream,
size_t sourceLen, uint8_t* destStream, size_t maxDestLen,
size_t* encodedLen, bool addStxEtx) {
if (maxDestLen < 2) {
return STREAM_TOO_SHORT;
}
size_t encodedIndex = 0, sourceIndex = 0;
uint8_t nextByte;
if (addStxEtx) {
destStream[0] = STX_CHAR;
++encodedIndex;
}
while (encodedIndex < maxDestLen and sourceIndex < sourceLen)
{
nextByte = sourceStream[sourceIndex];
// STX, ETX and CR characters in the stream need to be escaped with DLE
if (nextByte == STX_CHAR or nextByte == ETX_CHAR or nextByte == CARRIAGE_RETURN) {
if (encodedIndex + 1 >= maxDestLen) {
return STREAM_TOO_SHORT;
}
else {
destStream[encodedIndex] = DLE_CHAR;
++encodedIndex;
/* Escaped byte will be actual byte + 0x40. This prevents
* STX, ETX, and carriage return characters from appearing
* in the encoded data stream at all, so when polling an
* encoded stream, the transmission can be stopped at ETX.
* 0x40 was chosen at random with special requirements:
* - Prevent going from one control char to another
* - Prevent overflow for common characters */
destStream[encodedIndex] = nextByte + 0x40;
}
}
// DLE characters are simply escaped with DLE.
else if (nextByte == DLE_CHAR) {
if (encodedIndex + 1 >= maxDestLen) {
return STREAM_TOO_SHORT;
}
else {
destStream[encodedIndex] = DLE_CHAR;
++encodedIndex;
destStream[encodedIndex] = DLE_CHAR;
}
}
else {
destStream[encodedIndex] = nextByte;
}
++encodedIndex;
++sourceIndex;
}
if (sourceIndex == sourceLen and encodedIndex < maxDestLen) {
if (addStxEtx) {
destStream[encodedIndex] = ETX_CHAR;
++encodedIndex;
}
*encodedLen = encodedIndex;
return RETURN_OK;
}
else {
return STREAM_TOO_SHORT;
}
}
ReturnValue_t DleEncoder::decode(const uint8_t *sourceStream,
size_t sourceStreamLen, size_t *readLen, uint8_t *destStream,
size_t maxDestStreamlen, size_t *decodedLen) {
size_t encodedIndex = 0, decodedIndex = 0;
uint8_t nextByte;
if (*sourceStream != STX_CHAR) {
return DECODING_ERROR;
}
++encodedIndex;
while ((encodedIndex < sourceStreamLen) && (decodedIndex < maxDestStreamlen)
&& (sourceStream[encodedIndex] != ETX_CHAR)
&& (sourceStream[encodedIndex] != STX_CHAR)) {
if (sourceStream[encodedIndex] == DLE_CHAR) {
nextByte = sourceStream[encodedIndex + 1];
// The next byte is a DLE character that was escaped by another
// DLE character, so we can write it to the destination stream.
if (nextByte == DLE_CHAR) {
destStream[decodedIndex] = nextByte;
}
else {
/* The next byte is a STX, DTX or 0x0D character which
* was escaped by a DLE character. The actual byte was
* also encoded by adding + 0x40 to prevent having control chars,
* in the stream at all, so we convert it back. */
if (nextByte == 0x42 or nextByte == 0x43 or nextByte == 0x4D) {
destStream[decodedIndex] = nextByte - 0x40;
}
else {
return DECODING_ERROR;
}
}
++encodedIndex;
}
else {
destStream[decodedIndex] = sourceStream[encodedIndex];
}
++encodedIndex;
++decodedIndex;
}
if (sourceStream[encodedIndex] != ETX_CHAR) {
*readLen = ++encodedIndex;
return DECODING_ERROR;
}
else {
*readLen = ++encodedIndex;
*decodedLen = decodedIndex;
return RETURN_OK;
}
}

View File

@ -1,79 +0,0 @@
#ifndef FRAMEWORK_GLOBALFUNCTIONS_DLEENCODER_H_
#define FRAMEWORK_GLOBALFUNCTIONS_DLEENCODER_H_
#include "../returnvalues/HasReturnvaluesIF.h"
#include <cstddef>
/**
* @brief This DLE Encoder (Data Link Encoder) can be used to encode and
* decode arbitrary data with ASCII control characters
* @details
* List of control codes:
* https://en.wikipedia.org/wiki/C0_and_C1_control_codes
*
* This encoder can be used to achieve a basic transport layer when using
* char based transmission systems.
* The passed source strean is converted into a encoded stream by adding
* a STX marker at the start of the stream and an ETX marker at the end of
* the stream. Any STX, ETX, DLE and CR occurrences in the source stream are
* escaped by a DLE character. The encoder also replaces escaped control chars
* by another char, so STX, ETX and CR should not appear anywhere in the actual
* encoded data stream.
*
* When using a strictly char based reception of packets encoded with DLE,
* STX can be used to notify a reader that actual data will start to arrive
* while ETX can be used to notify the reader that the data has ended.
*/
class DleEncoder: public HasReturnvaluesIF {
private:
DleEncoder();
virtual ~DleEncoder();
public:
static constexpr uint8_t INTERFACE_ID = CLASS_ID::DLE_ENCODER;
static constexpr ReturnValue_t STREAM_TOO_SHORT = MAKE_RETURN_CODE(0x01);
static constexpr ReturnValue_t DECODING_ERROR = MAKE_RETURN_CODE(0x02);
//! Start Of Text character. First character is encoded stream
static constexpr uint8_t STX_CHAR = 0x02;
//! End Of Text character. Last character in encoded stream
static constexpr uint8_t ETX_CHAR = 0x03;
//! Data Link Escape character. Used to escape STX, ETX and DLE occurrences
//! in the source stream.
static constexpr uint8_t DLE_CHAR = 0x10;
static constexpr uint8_t CARRIAGE_RETURN = 0x0D;
/**
* Encodes the give data stream by preceding it with the STX marker
* and ending it with an ETX marker. STX, ETX and DLE characters inside
* the stream are escaped by DLE characters and also replaced by adding
* 0x40 (which is reverted in the decoding process).
* @param sourceStream
* @param sourceLen
* @param destStream
* @param maxDestLen
* @param encodedLen
* @param addStxEtx
* Adding STX and ETX can be omitted, if they are added manually.
* @return
*/
static ReturnValue_t encode(const uint8_t *sourceStream, size_t sourceLen,
uint8_t *destStream, size_t maxDestLen, size_t *encodedLen,
bool addStxEtx = true);
/**
* Converts an encoded stream back.
* @param sourceStream
* @param sourceStreamLen
* @param readLen
* @param destStream
* @param maxDestStreamlen
* @param decodedLen
* @return
*/
static ReturnValue_t decode(const uint8_t *sourceStream,
size_t sourceStreamLen, size_t *readLen, uint8_t *destStream,
size_t maxDestStreamlen, size_t *decodedLen);
};
#endif /* FRAMEWORK_GLOBALFUNCTIONS_DLEENCODER_H_ */

41
hal/CMakeLists.txt Normal file
View File

@ -0,0 +1,41 @@
cmake_minimum_required(VERSION 3.13)
# Can also be changed by upper CMakeLists.txt file
find_library(LIB_FSFW_NAME fsfw REQUIRED)
option(FSFW_HAL_ADD_LINUX "Add the Linux HAL to the sources. Required gpiod library" OFF)
option(FSFW_HAL_ADD_RASPBERRY_PI "Add Raspberry Pi specific code to the sources" OFF)
option(FSFW_HAL_ADD_STM32H7 "Add the STM32H7 HAL to the sources" OFF)
option(FSFW_HAL_WARNING_SHADOW_LOCAL_GCC "Enable -Wshadow=local warning in GCC" ON)
set(LINUX_HAL_PATH_NAME linux)
set(STM32H7_PATH_NAME stm32h7)
add_subdirectory(src)
foreach(INCLUDE_PATH ${FSFW_HAL_ADDITIONAL_INC_PATHS})
if(IS_ABSOLUTE ${INCLUDE_PATH})
set(CURR_ABS_INC_PATH "${INCLUDE_PATH}")
else()
get_filename_component(CURR_ABS_INC_PATH
${INCLUDE_PATH} REALPATH BASE_DIR ${CMAKE_SOURCE_DIR})
endif()
if(CMAKE_VERBOSE)
message(STATUS "FSFW include path: ${CURR_ABS_INC_PATH}")
endif()
list(APPEND FSFW_HAL_ADD_INC_PATHS_ABS ${CURR_ABS_INC_PATH})
endforeach()
target_include_directories(${LIB_FSFW_NAME} PRIVATE
${FSFW_HAL_ADD_INC_PATHS_ABS}
)
target_compile_definitions(${LIB_FSFW_NAME} PRIVATE
${FSFW_HAL_DEFINES}
)
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
${FSFW_HAL_LINK_LIBS}
)

9
hal/src/CMakeLists.txt Normal file
View File

@ -0,0 +1,9 @@
target_include_directories(${LIB_FSFW_NAME} PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
)
target_include_directories(${LIB_FSFW_NAME} INTERFACE
${CMAKE_CURRENT_SOURCE_DIR}
)
add_subdirectory(fsfw_hal)

View File

@ -0,0 +1,10 @@
add_subdirectory(devicehandlers)
add_subdirectory(common)
if(FSFW_HAL_ADD_LINUX)
add_subdirectory(linux)
endif()
if(FSFW_HAL_ADD_STM32H7)
add_subdirectory(stm32h7)
endif()

View File

@ -0,0 +1 @@
add_subdirectory(gpio)

View File

@ -0,0 +1,3 @@
target_sources(${LIB_FSFW_NAME} PRIVATE
GpioCookie.cpp
)

View File

@ -0,0 +1,50 @@
#include "fsfw_hal/common/gpio/GpioCookie.h"
#include "fsfw/serviceinterface/ServiceInterface.h"
GpioCookie::GpioCookie() {
}
ReturnValue_t GpioCookie::addGpio(gpioId_t gpioId, GpioBase* gpioConfig) {
if (gpioConfig == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "GpioCookie::addGpio: gpioConfig is nullpointer" << std::endl;
#else
sif::printWarning("GpioCookie::addGpio: gpioConfig is nullpointer\n");
#endif
return HasReturnvaluesIF::RETURN_FAILED;
}
auto gpioMapIter = gpioMap.find(gpioId);
if(gpioMapIter == gpioMap.end()) {
auto statusPair = gpioMap.emplace(gpioId, gpioConfig);
if (statusPair.second == false) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "GpioCookie::addGpio: Failed to add GPIO " << gpioId <<
" to GPIO map" << std::endl;
#else
sif::printWarning("GpioCookie::addGpio: Failed to add GPIO %d to GPIO map\n", gpioId);
#endif
#endif
return HasReturnvaluesIF::RETURN_FAILED;
}
return HasReturnvaluesIF::RETURN_OK;
}
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "GpioCookie::addGpio: GPIO already exists in GPIO map " << std::endl;
#else
sif::printWarning("GpioCookie::addGpio: GPIO already exists in GPIO map\n");
#endif
#endif
return HasReturnvaluesIF::RETURN_FAILED;
}
GpioMap GpioCookie::getGpioMap() const {
return gpioMap;
}
GpioCookie::~GpioCookie() {
for(auto& config: gpioMap) {
delete(config.second);
}
}

View File

@ -0,0 +1,41 @@
#ifndef COMMON_GPIO_GPIOCOOKIE_H_
#define COMMON_GPIO_GPIOCOOKIE_H_
#include "GpioIF.h"
#include "gpioDefinitions.h"
#include <fsfw/devicehandlers/CookieIF.h>
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
/**
* @brief Cookie for the GpioIF. Allows the GpioIF to determine which
* GPIOs to initialize and whether they should be configured as in- or
* output.
* @details One GpioCookie can hold multiple GPIO configurations. To add a new
* GPIO configuration to a GpioCookie use the GpioCookie::addGpio
* function.
*
* @author J. Meier
*/
class GpioCookie: public CookieIF {
public:
GpioCookie();
virtual ~GpioCookie();
ReturnValue_t addGpio(gpioId_t gpioId, GpioBase* gpioConfig);
/**
* @brief Get map with registered GPIOs.
*/
GpioMap getGpioMap() const;
private:
/**
* Returns a copy of the internal GPIO map.
*/
GpioMap gpioMap;
};
#endif /* COMMON_GPIO_GPIOCOOKIE_H_ */

View File

@ -0,0 +1,54 @@
#ifndef COMMON_GPIO_GPIOIF_H_
#define COMMON_GPIO_GPIOIF_H_
#include "gpioDefinitions.h"
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
#include <fsfw/devicehandlers/CookieIF.h>
class GpioCookie;
/**
* @brief This class defines the interface for objects requiring the control
* over GPIOs.
* @author J. Meier
*/
class GpioIF : public HasReturnvaluesIF {
public:
virtual ~GpioIF() {};
/**
* @brief Called by the GPIO using object.
* @param cookie Cookie specifying informations of the GPIOs required
* by a object.
*/
virtual ReturnValue_t addGpios(GpioCookie* cookie) = 0;
/**
* @brief By implementing this function a child must provide the
* functionality to pull a certain GPIO to high logic level.
*
* @param gpioId A unique number which specifies the GPIO to drive.
* @return Returns RETURN_OK for success. This should never return RETURN_FAILED.
*/
virtual ReturnValue_t pullHigh(gpioId_t gpioId) = 0;
/**
* @brief By implementing this function a child must provide the
* functionality to pull a certain GPIO to low logic level.
*
* @param gpioId A unique number which specifies the GPIO to drive.
*/
virtual ReturnValue_t pullLow(gpioId_t gpioId) = 0;
/**
* @brief This function requires a child to implement the functionality to read the state of
* an ouput or input gpio.
*
* @param gpioId A unique number which specifies the GPIO to read.
* @param gpioState State of GPIO will be written to this pointer.
*/
virtual ReturnValue_t readGpio(gpioId_t gpioId, int* gpioState) = 0;
};
#endif /* COMMON_GPIO_GPIOIF_H_ */

View File

@ -0,0 +1,140 @@
#ifndef COMMON_GPIO_GPIODEFINITIONS_H_
#define COMMON_GPIO_GPIODEFINITIONS_H_
#include <string>
#include <unordered_map>
#include <map>
using gpioId_t = uint16_t;
namespace gpio {
enum Levels {
LOW = 0,
HIGH = 1
};
enum Direction {
IN = 0,
OUT = 1
};
enum GpioOperation {
READ,
WRITE
};
enum GpioTypes {
NONE,
GPIO_REGULAR_BY_CHIP,
GPIO_REGULAR_BY_LABEL,
CALLBACK
};
static constexpr gpioId_t NO_GPIO = -1;
using gpio_cb_t = void (*) (gpioId_t gpioId, gpio::GpioOperation gpioOp, int value, void* args);
}
/**
* @brief Struct containing information about the GPIO to use. This is
* required by the libgpiod to access and drive a GPIO.
* @param chipname String of the chipname specifying the group which contains the GPIO to
* access. E.g. gpiochip0. To detect names of GPIO groups run gpiodetect on
* the linux command line.
* @param lineNum The offset of the GPIO within the GPIO group.
* @param consumer Name of the consumer. Simply a description of the GPIO configuration.
* @param direction Specifies whether the GPIO should be used as in- or output.
* @param initValue Defines the initial state of the GPIO when configured as output.
* Only required for output GPIOs.
* @param lineHandle The handle returned by gpiod_chip_get_line will be later written to this
* pointer.
*/
class GpioBase {
public:
GpioBase() = default;
GpioBase(gpio::GpioTypes gpioType, std::string consumer, gpio::Direction direction,
int initValue):
gpioType(gpioType), consumer(consumer),direction(direction), initValue(initValue) {}
virtual~ GpioBase() {};
// Can be used to cast GpioBase to a concrete child implementation
gpio::GpioTypes gpioType = gpio::GpioTypes::NONE;
std::string consumer;
gpio::Direction direction = gpio::Direction::IN;
int initValue = 0;
};
class GpiodRegularBase: public GpioBase {
public:
GpiodRegularBase(gpio::GpioTypes gpioType, std::string consumer, gpio::Direction direction,
int initValue, int lineNum): GpioBase(gpioType, consumer, direction, initValue),
lineNum(lineNum) {
}
int lineNum = 0;
struct gpiod_line* lineHandle = nullptr;
};
class GpiodRegularByChip: public GpiodRegularBase {
public:
GpiodRegularByChip() :
GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_CHIP,
std::string(), gpio::Direction::IN, gpio::LOW, 0) {
}
GpiodRegularByChip(std::string chipname_, int lineNum_, std::string consumer_,
gpio::Direction direction_, int initValue_) :
GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_CHIP,
consumer_, direction_, initValue_, lineNum_),
chipname(chipname_){
}
GpiodRegularByChip(std::string chipname_, int lineNum_, std::string consumer_) :
GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_CHIP, consumer_,
gpio::Direction::IN, gpio::LOW, lineNum_),
chipname(chipname_) {
}
std::string chipname;
};
class GpiodRegularByLabel: public GpiodRegularBase {
public:
GpiodRegularByLabel(std::string label_, int lineNum_, std::string consumer_,
gpio::Direction direction_, int initValue_) :
GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_LABEL, consumer_,
direction_, initValue_, lineNum_),
label(label_) {
}
GpiodRegularByLabel(std::string label_, int lineNum_, std::string consumer_) :
GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_LABEL, consumer_,
gpio::Direction::IN, gpio::LOW, lineNum_),
label(label_) {
}
std::string label;
};
class GpioCallback: public GpioBase {
public:
GpioCallback(std::string consumer, gpio::Direction direction_, int initValue_,
gpio::gpio_cb_t callback, void* callbackArgs):
GpioBase(gpio::GpioTypes::CALLBACK, consumer, direction_, initValue_),
callback(callback), callbackArgs(callbackArgs) {}
gpio::gpio_cb_t callback = nullptr;
void* callbackArgs = nullptr;
};
using GpioMap = std::map<gpioId_t, GpioBase*>;
using GpioUnorderedMap = std::unordered_map<gpioId_t, GpioBase*>;
using GpioMapIter = GpioMap::iterator;
using GpioUnorderedMapIter = GpioUnorderedMap::iterator;
#endif /* LINUX_GPIO_GPIODEFINITIONS_H_ */

View File

@ -0,0 +1,17 @@
#ifndef FSFW_HAL_COMMON_SPI_SPICOMMON_H_
#define FSFW_HAL_COMMON_SPI_SPICOMMON_H_
#include <cstdint>
namespace spi {
enum SpiModes: uint8_t {
MODE_0,
MODE_1,
MODE_2,
MODE_3
};
}
#endif /* FSFW_HAL_COMMON_SPI_SPICOMMON_H_ */

View File

@ -0,0 +1,5 @@
target_sources(${LIB_FSFW_NAME} PRIVATE
GyroL3GD20Handler.cpp
MgmRM3100Handler.cpp
MgmLIS3MDLHandler.cpp
)

View File

@ -0,0 +1,287 @@
#include "GyroL3GD20Handler.h"
#include "fsfw/datapool/PoolReadGuard.h"
#include <cmath>
GyroHandlerL3GD20H::GyroHandlerL3GD20H(object_id_t objectId, object_id_t deviceCommunication,
CookieIF *comCookie, uint32_t transitionDelayMs):
DeviceHandlerBase(objectId, deviceCommunication, comCookie),
transitionDelayMs(transitionDelayMs), dataset(this) {
#if FSFW_HAL_L3GD20_GYRO_DEBUG == 1
debugDivider = new PeriodicOperationDivider(3);
#endif
}
GyroHandlerL3GD20H::~GyroHandlerL3GD20H() {}
void GyroHandlerL3GD20H::doStartUp() {
if(internalState == InternalState::NONE) {
internalState = InternalState::CONFIGURE;
}
if(internalState == InternalState::CONFIGURE) {
if(commandExecuted) {
internalState = InternalState::CHECK_REGS;
commandExecuted = false;
}
}
if(internalState == InternalState::CHECK_REGS) {
if(commandExecuted) {
internalState = InternalState::NORMAL;
if(goNormalModeImmediately) {
setMode(MODE_NORMAL);
}
else {
setMode(_MODE_TO_ON);
}
commandExecuted = false;
}
}
}
void GyroHandlerL3GD20H::doShutDown() {
setMode(_MODE_POWER_DOWN);
}
ReturnValue_t GyroHandlerL3GD20H::buildTransitionDeviceCommand(DeviceCommandId_t *id) {
switch(internalState) {
case(InternalState::NONE):
case(InternalState::NORMAL): {
return NOTHING_TO_SEND;
}
case(InternalState::CONFIGURE): {
*id = L3GD20H::CONFIGURE_CTRL_REGS;
uint8_t command [5];
command[0] = L3GD20H::CTRL_REG_1_VAL;
command[1] = L3GD20H::CTRL_REG_2_VAL;
command[2] = L3GD20H::CTRL_REG_3_VAL;
command[3] = L3GD20H::CTRL_REG_4_VAL;
command[4] = L3GD20H::CTRL_REG_5_VAL;
return buildCommandFromCommand(*id, command, 5);
}
case(InternalState::CHECK_REGS): {
*id = L3GD20H::READ_REGS;
return buildCommandFromCommand(*id, nullptr, 0);
}
default:
#if FSFW_CPP_OSTREAM_ENABLED == 1
/* Might be a configuration error. */
sif::warning << "GyroL3GD20Handler::buildTransitionDeviceCommand: "
"Unknown internal state!" << std::endl;
#else
sif::printDebug("GyroL3GD20Handler::buildTransitionDeviceCommand: "
"Unknown internal state!\n");
#endif
return HasReturnvaluesIF::RETURN_OK;
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t GyroHandlerL3GD20H::buildNormalDeviceCommand(DeviceCommandId_t *id) {
*id = L3GD20H::READ_REGS;
return buildCommandFromCommand(*id, nullptr, 0);
}
ReturnValue_t GyroHandlerL3GD20H::buildCommandFromCommand(
DeviceCommandId_t deviceCommand, const uint8_t *commandData,
size_t commandDataLen) {
switch(deviceCommand) {
case(L3GD20H::READ_REGS): {
commandBuffer[0] = L3GD20H::READ_START | L3GD20H::AUTO_INCREMENT_MASK | L3GD20H::READ_MASK;
std::memset(commandBuffer + 1, 0, L3GD20H::READ_LEN);
rawPacket = commandBuffer;
rawPacketLen = L3GD20H::READ_LEN + 1;
break;
}
case(L3GD20H::CONFIGURE_CTRL_REGS): {
commandBuffer[0] = L3GD20H::CTRL_REG_1 | L3GD20H::AUTO_INCREMENT_MASK;
if(commandData == nullptr or commandDataLen != 5) {
return DeviceHandlerIF::INVALID_COMMAND_PARAMETER;
}
ctrlReg1Value = commandData[0];
ctrlReg2Value = commandData[1];
ctrlReg3Value = commandData[2];
ctrlReg4Value = commandData[3];
ctrlReg5Value = commandData[4];
bool fsH = ctrlReg4Value & L3GD20H::SET_FS_1;
bool fsL = ctrlReg4Value & L3GD20H::SET_FS_0;
if(not fsH and not fsL) {
sensitivity = L3GD20H::SENSITIVITY_00;
}
else if(not fsH and fsL) {
sensitivity = L3GD20H::SENSITIVITY_01;
}
else {
sensitivity = L3GD20H::SENSITIVITY_11;
}
commandBuffer[1] = ctrlReg1Value;
commandBuffer[2] = ctrlReg2Value;
commandBuffer[3] = ctrlReg3Value;
commandBuffer[4] = ctrlReg4Value;
commandBuffer[5] = ctrlReg5Value;
rawPacket = commandBuffer;
rawPacketLen = 6;
break;
}
case(L3GD20H::READ_CTRL_REGS): {
commandBuffer[0] = L3GD20H::READ_START | L3GD20H::AUTO_INCREMENT_MASK |
L3GD20H::READ_MASK;
std::memset(commandBuffer + 1, 0, 5);
rawPacket = commandBuffer;
rawPacketLen = 6;
break;
}
default:
return DeviceHandlerIF::COMMAND_NOT_IMPLEMENTED;
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t GyroHandlerL3GD20H::scanForReply(const uint8_t *start, size_t len,
DeviceCommandId_t *foundId, size_t *foundLen) {
// For SPI, the ID will always be the one of the last sent command
*foundId = this->getPendingCommand();
*foundLen = this->rawPacketLen;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t GyroHandlerL3GD20H::interpretDeviceReply(DeviceCommandId_t id,
const uint8_t *packet) {
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
switch(id) {
case(L3GD20H::CONFIGURE_CTRL_REGS): {
commandExecuted = true;
break;
}
case(L3GD20H::READ_CTRL_REGS): {
if(packet[1] == ctrlReg1Value and packet[2] == ctrlReg2Value and
packet[3] == ctrlReg3Value and packet[4] == ctrlReg4Value and
packet[5] == ctrlReg5Value) {
commandExecuted = true;
}
else {
// Attempt reconfiguration
internalState = InternalState::CONFIGURE;
return DeviceHandlerIF::DEVICE_REPLY_INVALID;
}
break;
}
case(L3GD20H::READ_REGS): {
if(packet[1] != ctrlReg1Value and packet[2] != ctrlReg2Value and
packet[3] != ctrlReg3Value and packet[4] != ctrlReg4Value and
packet[5] != ctrlReg5Value) {
return DeviceHandlerIF::DEVICE_REPLY_INVALID;
}
else {
if(internalState == InternalState::CHECK_REGS) {
commandExecuted = true;
}
}
statusReg = packet[L3GD20H::STATUS_IDX];
int16_t angVelocXRaw = packet[L3GD20H::OUT_X_H] << 8 | packet[L3GD20H::OUT_X_L];
int16_t angVelocYRaw = packet[L3GD20H::OUT_Y_H] << 8 | packet[L3GD20H::OUT_Y_L];
int16_t angVelocZRaw = packet[L3GD20H::OUT_Z_H] << 8 | packet[L3GD20H::OUT_Z_L];
float angVelocX = angVelocXRaw * sensitivity;
float angVelocY = angVelocYRaw * sensitivity;
float angVelocZ = angVelocZRaw * sensitivity;
int8_t temperaturOffset = (-1) * packet[L3GD20H::TEMPERATURE_IDX];
float temperature = 25.0 + temperaturOffset;
#if FSFW_HAL_L3GD20_GYRO_DEBUG == 1
if(debugDivider->checkAndIncrement()) {
/* Set terminal to utf-8 if there is an issue with micro printout. */
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "GyroHandlerL3GD20H: Angular velocities (deg/s):" << std::endl;
sif::info << "X: " << angVelocX << std::endl;
sif::info << "Y: " << angVelocY << std::endl;
sif::info << "Z: " << angVelocZ << std::endl;
#else
sif::printInfo("GyroHandlerL3GD20H: Angular velocities (deg/s):\n");
sif::printInfo("X: %f\n", angVelocX);
sif::printInfo("Y: %f\n", angVelocY);
sif::printInfo("Z: %f\n", angVelocZ);
#endif
}
#endif
PoolReadGuard readSet(&dataset);
if(readSet.getReadResult() == HasReturnvaluesIF::RETURN_OK) {
if(std::abs(angVelocX) < this->absLimitX) {
dataset.angVelocX = angVelocX;
dataset.angVelocX.setValid(true);
}
else {
dataset.angVelocX.setValid(false);
}
if(std::abs(angVelocY) < this->absLimitY) {
dataset.angVelocY = angVelocY;
dataset.angVelocY.setValid(true);
}
else {
dataset.angVelocY.setValid(false);
}
if(std::abs(angVelocZ) < this->absLimitZ) {
dataset.angVelocZ = angVelocZ;
dataset.angVelocZ.setValid(true);
}
else {
dataset.angVelocZ.setValid(false);
}
dataset.temperature = temperature;
dataset.temperature.setValid(true);
}
break;
}
default:
return DeviceHandlerIF::COMMAND_NOT_IMPLEMENTED;
}
return result;
}
uint32_t GyroHandlerL3GD20H::getTransitionDelayMs(Mode_t from, Mode_t to) {
return this->transitionDelayMs;
}
void GyroHandlerL3GD20H::setToGoToNormalMode(bool enable) {
this->goNormalModeImmediately = true;
}
ReturnValue_t GyroHandlerL3GD20H::initializeLocalDataPool(
localpool::DataPool &localDataPoolMap, LocalDataPoolManager &poolManager) {
localDataPoolMap.emplace(L3GD20H::ANG_VELOC_X, new PoolEntry<float>({0.0}));
localDataPoolMap.emplace(L3GD20H::ANG_VELOC_Y, new PoolEntry<float>({0.0}));
localDataPoolMap.emplace(L3GD20H::ANG_VELOC_Z, new PoolEntry<float>({0.0}));
localDataPoolMap.emplace(L3GD20H::TEMPERATURE, new PoolEntry<float>({0.0}));
return HasReturnvaluesIF::RETURN_OK;
}
void GyroHandlerL3GD20H::fillCommandAndReplyMap() {
insertInCommandAndReplyMap(L3GD20H::READ_REGS, 1, &dataset);
insertInCommandAndReplyMap(L3GD20H::CONFIGURE_CTRL_REGS, 1);
insertInCommandAndReplyMap(L3GD20H::READ_CTRL_REGS, 1);
}
void GyroHandlerL3GD20H::modeChanged() {
internalState = InternalState::NONE;
}
void GyroHandlerL3GD20H::setAbsoluteLimits(float limitX, float limitY, float limitZ) {
this->absLimitX = limitX;
this->absLimitY = limitY;
this->absLimitZ = limitZ;
}

View File

@ -0,0 +1,99 @@
#ifndef MISSION_DEVICES_GYROL3GD20HANDLER_H_
#define MISSION_DEVICES_GYROL3GD20HANDLER_H_
#include "fsfw/FSFW.h"
#include "devicedefinitions/GyroL3GD20Definitions.h"
#include <fsfw/devicehandlers/DeviceHandlerBase.h>
#include <fsfw/globalfunctions/PeriodicOperationDivider.h>
/**
* @brief Device Handler for the L3GD20H gyroscope sensor
* (https://www.st.com/en/mems-and-sensors/l3gd20h.html)
* @details
* Advanced documentation:
* https://egit.irs.uni-stuttgart.de/redmine/projects/eive-flight-manual/wiki/L3GD20H_Gyro
*
* Data is read big endian with the smallest possible range of 245 degrees per second.
*/
class GyroHandlerL3GD20H: public DeviceHandlerBase {
public:
GyroHandlerL3GD20H(object_id_t objectId, object_id_t deviceCommunication,
CookieIF* comCookie, uint32_t transitionDelayMs);
virtual ~GyroHandlerL3GD20H();
/**
* Set the absolute limit for the values on the axis in degrees per second.
* The dataset values will be marked as invalid if that limit is exceeded
* @param xLimit
* @param yLimit
* @param zLimit
*/
void setAbsoluteLimits(float limitX, float limitY, float limitZ);
/**
* @brief Configure device handler to go to normal mode immediately
*/