Merge pull request 'Update to v1.1.0' (#29) from develop into master

Reviewed-on: eive/eive_obsw#29
This commit is contained in:
Robin Müller 2021-04-25 12:43:23 +02:00
commit 95eebb54ce
381 changed files with 32965 additions and 1776 deletions

13
.gitignore vendored
View File

@ -2,8 +2,21 @@ _obj
_bin _bin
_dep _dep
Debug
Debug*
Release
Release*
MinSizeRel
MinSizeRel*
RelWithDebInfo
RelWithDebInfo*
.settings .settings
.metadata .metadata
.project .project
.cproject .cproject
__pycache__ __pycache__
!misc/eclipse/**/.cproject
!misc/eclipse/**/.project
/eive_obsw cmake debug/

17
.gitmodules vendored
View File

@ -1,12 +1,21 @@
[submodule "etl"] [submodule "etl"]
path = etl path = thirdparty/etl
url = https://github.com/ETLCPP/etl.git url = https://github.com/ETLCPP/etl.git
[submodule "tmtc"]
path = tmtc
url = https://git.ksat-stuttgart.de/Robin.Mueller/tmtc.git
[submodule "arduino"] [submodule "arduino"]
path = arduino path = arduino
url = https://egit.irs.uni-stuttgart.de/eive/eive_arduino_interface.git url = https://egit.irs.uni-stuttgart.de/eive/eive_arduino_interface.git
[submodule "fsfw"] [submodule "fsfw"]
path = fsfw path = fsfw
url = https://egit.irs.uni-stuttgart.de/eive/fsfw.git url = https://egit.irs.uni-stuttgart.de/eive/fsfw.git
[submodule "tmtc"]
path = tmtc
url = https://egit.irs.uni-stuttgart.de/eive/eive_tmtc.git
[submodule "thirdparty/lwgps"]
path = thirdparty/lwgps
url = https://github.com/rmspacefish/lwgps.git
[submodule "fsfw_hal"]
path = fsfw_hal
url = https://egit.irs.uni-stuttgart.de/fsfw/fsfw_hal.git
[submodule "generators/modgen"]
path = generators/modgen
url = https://git.ksat-stuttgart.de/source/modgen.git

228
CMakeLists.txt Normal file
View File

@ -0,0 +1,228 @@
################################################################################
# CMake support for the EIVE OBSW
#
# Developed in an effort to replace Make with a modern build system.
#
# Author: R. Mueller
################################################################################
################################################################################
# Pre-Project preparation
################################################################################
cmake_minimum_required(VERSION 3.13)
# set(CMAKE_VERBOSE TRUE)
set(CMAKE_SCRIPT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
option(ADD_ETL_LIB "Add ETL library" ON)
if(NOT OS_FSFW)
set(OS_FSFW host CACHE STRING "OS for the FSFW.")
endif()
# Perform steps like loading toolchain files where applicable.
include(${CMAKE_SCRIPT_PATH}/PreProjectConfig.cmake)
pre_project_config()
# Project Name
project(eive_obsw ASM C CXX)
################################################################################
# Pre-Sources preparation
################################################################################
# Specify the C++ standard
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
# Set names and variables
set(TARGET_NAME ${CMAKE_PROJECT_NAME})
set(LIB_FSFW_NAME fsfw)
set(LIB_ETL_NAME etl)
set(LIB_CSP_NAME libcsp)
set(LIB_FSFW_HAL_NAME fsfw_hal)
set(LIB_LWGPS_NAME lwgps)
set(THIRD_PARTY_FOLDER thirdparty)
# Set path names
set(FSFW_PATH fsfw)
set(MISSION_PATH mission)
set(TEST_PATH test/testtasks)
set(LINUX_PATH linux)
set(COMMON_PATH common)
set(FSFW_HAL_LIB_PATH fsfw_hal)
set(CSP_LIB_PATH ${THIRD_PARTY_FOLDER}/libcsp)
set(ETL_LIB_PATH ${THIRD_PARTY_FOLDER}/etl)
set(LWGPS_LIB_PATH ${THIRD_PARTY_FOLDER}/lwgps)
set(FSFW_WARNING_SHADOW_LOCAL_GCC OFF)
set(ADD_LINUX_FILES TRUE)
# Analyse different OS and architecture/target options, determine BSP_PATH,
# display information about compiler etc.
include (${CMAKE_SCRIPT_PATH}/HardwareOsPreConfig.cmake)
pre_source_hw_os_config()
if(TGT_BSP)
if(${TGT_BSP} MATCHES "arm/q7s" OR ${TGT_BSP} MATCHES "arm/raspberrypi")
set(ROOT_CONFIG_FOLDER TRUE)
set(FSFW_CONFIG_PATH "fsfwconfig")
set(ADD_LINUX_FILES TRUE)
set(ADD_CSP_LIB TRUE)
set(FSFW_HAL_ADD_LINUX ON)
endif()
if(${TGT_BSP} MATCHES "arm/raspberrypi")
add_definitions(-DRASPBERRY_PI)
set(FSFW_HAL_ADD_RASPBERRY_PI ON)
endif()
if(${TGT_BSP} MATCHES "arm/q7s")
add_definitions(-DXIPHOS_Q7S)
endif()
else()
# Required by FSFW library
set(FSFW_CONFIG_PATH "${BSP_PATH}/fsfwconfig")
endif()
# Set for lwgps library
set(LWGPS_CONFIG_PATH "${COMMON_PATH}/config")
################################################################################
# Executable and Sources
################################################################################
# Add executable
add_executable(${TARGET_NAME})
# Add subdirectories
if(ROOT_CONFIG_FOLDER)
add_subdirectory(${FSFW_CONFIG_PATH})
endif()
if(ADD_CSP_LIB)
add_subdirectory(${CSP_LIB_PATH})
endif()
if(ADD_ETL_LIB)
add_subdirectory(${ETL_LIB_PATH})
endif()
if(ADD_LINUX_FILES)
add_subdirectory(${LINUX_PATH})
endif()
add_subdirectory(${LWGPS_LIB_PATH})
add_subdirectory(${BSP_PATH})
add_subdirectory(${FSFW_PATH})
add_subdirectory(${MISSION_PATH})
add_subdirectory(${TEST_PATH})
add_subdirectory(${FSFW_HAL_LIB_PATH})
add_subdirectory(${COMMON_PATH})
################################################################################
# Post-Sources preparation
################################################################################
set_property(CACHE OS_FSFW PROPERTY STRINGS host linux)
# Add libraries for all sources.
target_link_libraries(${TARGET_NAME} PRIVATE
${LIB_FSFW_NAME}
${LIB_OS_NAME}
${LIB_LWGPS_NAME}
${LIB_FSFW_HAL_NAME}
)
if(ADD_ETL_LIB)
target_link_libraries(${TARGET_NAME} PRIVATE
${LIB_ETL_NAME}
)
endif()
if(ADD_CSP_LIB)
target_link_libraries(${TARGET_NAME} PRIVATE
${LIB_CSP_NAME}
)
endif()
# Add include paths for all sources.
target_include_directories(${TARGET_NAME} PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${FSFW_CONFIG_PATH}
)
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set(WARNING_FLAGS
-Wall
-Wextra
-Wimplicit-fallthrough=1
-Wno-unused-parameter
-Wno-psabi
)
# Remove unused sections.
target_compile_options(${TARGET_NAME} PRIVATE
"-ffunction-sections"
"-fdata-sections"
)
# Removed unused sections.
target_link_options(${TARGET_NAME} PRIVATE
"-Wl,--gc-sections"
)
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
set(COMPILER_FLAGS "/permissive-")
endif()
if(CMAKE_VERBOSE)
message(STATUS "Warning flags: ${WARNING_FLAGS}")
endif()
# Compile options for all sources.
target_compile_options(${TARGET_NAME} PRIVATE
${WARNING_FLAGS}
)
if(${CMAKE_CROSSCOMPILING})
include (${CMAKE_SCRIPT_PATH}/HardwareOsPostConfig.cmake)
post_source_hw_os_config()
endif()
if(NOT CMAKE_SIZE)
set(CMAKE_SIZE size)
if(WIN32)
set(FILE_SUFFIX ".exe")
endif()
endif()
if(TGT_BSP)
set(TARGET_STRING "Target BSP: ${TGT_BSP}")
else()
set(TARGET_STRING "Target BSP: Hosted")
endif()
string(CONCAT POST_BUILD_COMMENT
"Build directory: ${CMAKE_BINARY_DIR}\n"
"Target OSAL: ${OS_FSFW}\n"
"Target Build Type: ${CMAKE_BUILD_TYPE}\n"
"${TARGET_STRING}"
)
add_custom_command(
TARGET ${TARGET_NAME}
POST_BUILD
COMMAND ${CMAKE_SIZE} ${TARGET_NAME}${FILE_SUFFIX}
COMMENT ${POST_BUILD_COMMENT}
)
include (${CMAKE_SCRIPT_PATH}/BuildType.cmake)
set_build_type()

View File

@ -13,7 +13,7 @@ SHELL = /bin/sh
# Chip & board used for compilation # Chip & board used for compilation
# (can be overriden by adding CHIP=chip and BOARD=board to the command-line) # (can be overriden by adding CHIP=chip and BOARD=board to the command-line)
BOARD_FILE_ROOT = bsp_linux BOARD_FILE_ROOT = bsp_q7s
BOARD = linux BOARD = linux
OS_FSFW = linux OS_FSFW = linux
CUSTOM_DEFINES += -D$(OS_FSFW) CUSTOM_DEFINES += -D$(OS_FSFW)
@ -25,6 +25,7 @@ MISSION_PATH = mission
CONFIG_PATH = fsfwconfig CONFIG_PATH = fsfwconfig
TEST_PATH = test TEST_PATH = test
UNITTEST_PATH = unittest UNITTEST_PATH = unittest
LIBCSP_PATH = libcsp
# Board specific paths # Board specific paths
BSP_PATH = $(BOARD_FILE_ROOT) BSP_PATH = $(BOARD_FILE_ROOT)
@ -113,7 +114,7 @@ INCLUDES :=
# Directories where $(directoryname).mk files should be included from # Directories where $(directoryname).mk files should be included from
SUBDIRS := $(FRAMEWORK_PATH) $(TEST_PATH) $(BSP_PATH) $(UNITTEST_PATH)\ SUBDIRS := $(FRAMEWORK_PATH) $(TEST_PATH) $(BSP_PATH) $(UNITTEST_PATH)\
$(CONFIG_PATH) $(MISSION_PATH) $(CONFIG_PATH) $(MISSION_PATH) $(LIBCSP_PATH)
# INCLUDES += framework/test/catch2 # INCLUDES += framework/test/catch2
# ETL library include. # ETL library include.
@ -278,7 +279,7 @@ cleanbin:
-rm -rf $(BUILDPATH)/$(OUTPUT_FOLDER) -rm -rf $(BUILDPATH)/$(OUTPUT_FOLDER)
# Build target configuration # Build target configuration
release: OPTIMIZATION = -Os $(PROTOTYPE_OPTIMIZATION) $(LINK_TIME_OPTIMIZATION) release: OPTIMIZATION = -O2 $(PROTOTYPE_OPTIMIZATION) $(LINK_TIME_OPTIMIZATION)
release: LINK_TIME_OPTIMIZATION = -flto release: LINK_TIME_OPTIMIZATION = -flto
release: TARGET = Release release: TARGET = Release
release: OPTIMIZATION_MESSAGE = On with Link Time Optimization release: OPTIMIZATION_MESSAGE = On with Link Time Optimization

View File

@ -15,14 +15,14 @@ CUSTOM_DEFINES :=
# Chip & board used for compilation # Chip & board used for compilation
# (can be overriden by adding CHIP=chip and BOARD=board to the command-line) # (can be overriden by adding CHIP=chip and BOARD=board to the command-line)
BOARD_FILE_ROOT = hosted BOARD_FILE_ROOT = bsp_hosted
BOARD = host BOARD = host
OS_FSFW = host
CUSTOM_DEFINES += -D$(OS_FSFW)
DETECTED_OS :=
# Copied from stackoverflow, can be used to differentiate between Windows # Copied from stackoverflow, can be used to differentiate between Windows
# and Linux # and Linux
ifeq ($(OS),Windows_NT) ifeq ($(OS),Windows_NT)
DETECTED_OS = WINDOWS
CUSTOM_DEFINES += -DWIN32 CUSTOM_DEFINES += -DWIN32
ifeq ($(PROCESSOR_ARCHITEW6432),AMD64) ifeq ($(PROCESSOR_ARCHITEW6432),AMD64)
CUSTOM_DEFINES += -DAMD64 CUSTOM_DEFINES += -DAMD64
@ -55,6 +55,14 @@ else
endif endif
endif endif
ifeq (${DETECTED_OS}, WINDOWS)
OS_FSFW = host
else
OS_FSFW = linux
endif
CUSTOM_DEFINES += -D$(OS_FSFW)
# General folder paths # General folder paths
FRAMEWORK_PATH = fsfw FRAMEWORK_PATH = fsfw
MISSION_PATH = mission MISSION_PATH = mission
@ -179,10 +187,10 @@ $(foreach S,$(SUBDIRS),$(eval $(INCLUDE_FILE)))
# VPATH += mission/pus/ # VPATH += mission/pus/
ifeq ($(DETECTED_OS), LINUX) #ifeq ($(DETECTED_OS), LINUX)
CXXSRC += $(FRAMEWORK_PATH)/osal/linux/TcUnixUdpPollingTask.cpp #CXXSRC += $(FRAMEWORK_PATH)/osal/linux/TcUnixUdpPollingTask.cpp
CXXSRC += $(FRAMEWORK_PATH)/osal/linux/TmTcUnixUdpBridge.cpp #CXXSRC += $(FRAMEWORK_PATH)/osal/linux/TmTcUnixUdpBridge.cpp
endif #endif
# All C Sources included by .mk files are assigned here # All C Sources included by .mk files are assigned here
# Add the objects to sources so dependency handling works # Add the objects to sources so dependency handling works
@ -227,7 +235,6 @@ DEAD_CODE_REMOVAL = -Wl,--gc-sections
# Link time is larger and size of object files can not be retrieved # Link time is larger and size of object files can not be retrieved
# but resulting binary is smaller. Could be used in mission/deployment build # but resulting binary is smaller. Could be used in mission/deployment build
# Requires -ffunction-section in linker call # Requires -ffunction-section in linker call
LINK_TIME_OPTIMIZATION = -flto
OPTIMIZATION += $(PROTOTYPE_OPTIMIZATION) OPTIMIZATION += $(PROTOTYPE_OPTIMIZATION)
endif endif
@ -261,12 +268,12 @@ ASFLAGS = -Wall -g $(OPTIMIZATION) $(I_INCLUDES) -D__ASSEMBLY__
# LINK_INCLUDES specify the path to used libraries and the linker script # LINK_INCLUDES specify the path to used libraries and the linker script
# LINK_LIBRARIES link HCC and HAL library and enable float support # LINK_LIBRARIES link HCC and HAL library and enable float support
LDFLAGS := -g3 -pthread $(DEAD_CODE_REMOVAL) $(OPTIMIZATION) LDFLAGS := -g3 -pthread $(DEAD_CODE_REMOVAL) $(OPTIMIZATION)
LINK_INCLUDES :=
LINK_LIBRARIES := LINK_LIBRARIES :=
ifeq ($(OS),Windows_NT) ifeq ($(OS),Windows_NT)
LINK_LIBRARIES += -lwsock32 -lws2_32 LINK_LIBRARIES += -lwsock32 -lws2_32
else
LINK_LIBRARIES += -lrt
endif endif
# Gnu Coverage Tools Flags # Gnu Coverage Tools Flags
@ -309,7 +316,10 @@ all: executable
# Build target configuration # Build target configuration
release: OPTIMIZATION = -Os $(PROTOTYPE_OPTIMIZATION) $(LINK_TIME_OPTIMIZATION) release: OPTIMIZATION = -Os $(PROTOTYPE_OPTIMIZATION) $(LINK_TIME_OPTIMIZATION)
# Problematic on MinGW
ifneq ($(OS),Windows_NT)
release: LINK_TIME_OPTIMIZATION = -flto release: LINK_TIME_OPTIMIZATION = -flto
endif
release: TARGET = Release release: TARGET = Release
release: OPTIMIZATION_MESSAGE = On with Link Time Optimization release: OPTIMIZATION_MESSAGE = On with Link Time Optimization
release: DEBUG_LEVEL = -g0 release: DEBUG_LEVEL = -g0

549
README.md
View File

@ -4,7 +4,7 @@
Target systems: Target systems:
* OBC * OBC with Linux OS
* Xiphos Q7S * Xiphos Q7S
* Based on Zynq-7020 SoC (xc7z020clg484-2) * Based on Zynq-7020 SoC (xc7z020clg484-2)
* Dual-core ARM Cortex-A9 * Dual-core ARM Cortex-A9
@ -12,56 +12,157 @@ Target systems:
* Artix-7 FPGA (85K pogrammable logic cells) * Artix-7 FPGA (85K pogrammable logic cells)
* Datasheet at https://eive-cloud.irs.uni-stuttgart.de/index.php/apps/files/?dir=/EIVE_IRS/Arbeitsdaten/08_Used%20Components/Q7S&fileid=340648 * Datasheet at https://eive-cloud.irs.uni-stuttgart.de/index.php/apps/files/?dir=/EIVE_IRS/Arbeitsdaten/08_Used%20Components/Q7S&fileid=340648
* Also a lot of informatin about the Q7S can be found on the xiphos trac platform: https://trac.xiphos.com/trac/eive-q7/wiki/Q7RevB * Also a lot of informatin about the Q7S can be found on the xiphos trac platform: https://trac.xiphos.com/trac/eive-q7/wiki/Q7RevB
* Linux OS * Linux OS built with Yocto 2.5
* Built with Yocto 2.5
* Linux Kernel https://github.com/XiphosSystemsCorp/linux-xlnx.git * Linux Kernel https://github.com/XiphosSystemsCorp/linux-xlnx.git
* Host System * Host System
* Generic software components which are not dependant on hardware can also * Generic software components which are not dependant on hardware can also
be run. All host code is contained in the hosted folder be run on a host system. All host code is contained in the `bsp_hosted` folder
* Tested for Linux (Ubuntu 20.04) and Windows 10 * Tested for Linux (Ubuntu 20.04) and Windows 10
* Raspberry Pi
* EIVE OBC can be built for Raspberry Pi as well (either directly on Raspberry Pi or by installing a cross compiler)
The steps in the primary README are related to the main OBC target Q7S.
The CMake build system can be used to generate build systems as well (see helper scripts in `cmake/scripts`:
- Linux (Raspberry Pi): See special section below.
- Linux Host: Uses the `bsp_hosted` BSP folder and the CMake Unix Makefiles generator.
- Windows Host: Uses the `bsp_hosted` BSP folder, the CMake MinGW Makefiles generator and MSYS2.
## Setting up development environment ## Setting up development environment
### Installing Vivado the the Xilinx development tools
It's also possible to perform debugging with a normal Eclipse installation by installing
the TCF plugin. Still, it is necessary to install Vivado to get the toolchain for generating
C++ applications. Alternatively you can download the toolchain
[from the cloud](https://eive-cloud.irs.uni-stuttgart.de/index.php/apps/files/?dir=/EIVE_IRS/Arbeitsdaten/08_Used%20Components/Q7S/Toolchain&fileid=422486).
* Install Vivado 2018.2 and Xilinx SDK from https://www.xilinx.com/support/download/index.html/content/xilinx/en/downloadNav/vivado-design-tools/archive.html. * Install Vivado 2018.2 and Xilinx SDK from https://www.xilinx.com/support/download/index.html/content/xilinx/en/downloadNav/vivado-design-tools/archive.html.
Install the Vivado Design Suite - HLx Editions - 2018.2 Full Product Installation instead of the updates. It is recommended to use the installer Install the Vivado Design Suite - HLx Editions - 2018.2 Full Product Installation instead of the updates. It is recommended to use the installer.
* Install settings. In the Devices selection, it is sufficient to pick SoC &rarr; Zynq-7000: <br> * Install settings. In the Devices selection, it is sufficient to pick SoC &rarr; Zynq-7000: <br>
<img src="./doc/img/xilinx-install.PNG" width="50%"> <br>
<img src="./doc/img/vivado-edition.png" width="50%"> <br>
<img src="./doc/img/vivado-hl-design.png" width="50%"> <br>
<img src="./doc/img/xilinx-install.PNG" width="50%"> <br>
* For supported OS refer to https://www.xilinx.com/support/documentation/sw_manuals/xilinx2018_2/ug973-vivado-release-notes-install-license.pdf * For supported OS refer to https://www.xilinx.com/support/documentation/sw_manuals/xilinx2018_2/ug973-vivado-release-notes-install-license.pdf
* Add path of linux cross-compiler to environment variables SDK\2018.2\gnu\aarch32\nt\gcc-arm-linux-gnueabi\bin * Add path of linux cross-compiler to permanent environment variables (`.profile` file in Linux):
* Install make (only on windows, SDK on Linux can use the make installed with the SDK) `<XilinxInstallation>\SDK\2018.2\gnu\aarch32\nt\gcc-arm-linux-gnueabi\bin`
or set up path each time before debugging.
### Installing make on Windows ### Installing CMake and MSYS2 on Windows
1. Install NodeJS LTS
2. Install xpm
```sh 1. Install [MSYS2](https://www.msys2.org/) and [CMake](https://cmake.org/download/) first.
npm install --global xpm
```
3. Install Windows build tools (after installation also linux commands like mkdir can be used from windows) 2. Open the MinGW64 console. It is recommended to set up aliases in `.bashrc` to navigate to the
software repository quickly
```sh 3. Run the following commands in MinGW64
xpm install --global @xpack-dev-tools/windows-build-tools@latest
```
## Building the software ```sh
pacman -Syuuu
```
It is recommended to install the full base development toolchain
```sh
pacman -S base-devel
```
It is also possible to only install required packages
```sh
pacman -S mingw-w64-x86_64-cmake mingw-w64-x86_64-make mingw-w64-x86_64-gcc mingw-w64-x86_64-gdb python3
```
### Installing CMake on Linux
1. Run the following command
```sh
sudo apt-get install cmake
````
## Getting the Q7S system root
It is necessary to copy the Q7S system root to your local development machine for libraries
like `libgpio`. You can find the system root [here](https://eive-cloud.irs.uni-stuttgart.de/index.php/apps/files/?dir=/EIVE_IRS/Arbeitsdaten/08_Used%20Components/Q7S/Toolchain&fileid=422486). Download it and unzip it somewhere in the Xilinx installation folder.
Then, create a new environmental variables `Q7S_SYSROOT` and set it to the local system root path.
## Building the software with CMake
When using Windows, run theses steps in MSYS2.
1. Clone the repository with 1. Clone the repository with
```sh
git clone https://egit.irs.uni-stuttgart.de/eive/eive_obsw.git ```sh
``` git clone https://egit.irs.uni-stuttgart.de/eive/eive_obsw.git
```
2. Update all the submodules 2. Update all the submodules
```sh
git submodule init
git submodule sync
git submodule update
```
3. Open Xilinx SDK 2018.2 ```sh
4. Import project git submodule init
git submodule sync
git submodule update
```
3. Ensure that the cross-compiler is working with `arm-linux-gnueabihf-gcc --version`.
It is recommended to run the shell script `win_path_helper_xilinx_tools.sh` in `cmake/scripts/Q7S`
or to set up the [PATH and the CROSS_COMPILE variable permanently](https://unix.stackexchange.com/questions/26047/how-to-correctly-add-a-path-to-path)
in the `.profile` file.
4. Run the CMake configuration to create the build system in a `Debug` folder.
Navigate into the `eive_obsw` folder first.
```sh
cd cmake/scripts/Q7S
./create_cmake_debug.sh
cd ../../..
```
This will invoke a Python script which in turn invokes CMake with the correct
arguments to configure CMake for Q7S cross-compilation.
5. Build the software with
```sh
cd Debug
cmake --build . -j
```
## Setting up default Eclipse for Q7S projects - TCF agent
The [TCF agent](https://wiki.eclipse.org/TCF) can be used to perform remote debugging on the Q7S.
1. Install the TCF agent plugin in Eclipse from the [releases](https://www.eclipse.org/tcf/downloads.php). Go to Help &rarr; Install New Software and use the download page, for example https://download.eclipse.org/tools/tcf/releases/1.6/1.6.2/ to search for the plugin and install it.
2. Go to Window &rarr; Perspective &rarr; Open Perspective and open the **Target Explorer Perspective**.
Here, the Q7S should show up if the local port forwarding was set up as explained previously. Please note that you have to connect to `localhost` and port `1534` with port forwaring set up.
3. A launch configuration was provided, but it might be necessary to adapt it for your own needs. Alternatively:
- Create a new **TCF Remote Application** by pressing the cogs button at the top or going to Run &rarr; Debug Configurations &rarr; Remote Application and creating a new one there.
- Set up the correct image in the main tab (it might be necessary to send the image to the Q7S manually once) and file transfer properties
- It is also recommended to link the correct Eclipse project.
After that, comfortable remote debugging should be possible with the Debug button.
A build configuration and a shell helper script has been provided to set up the path variables and
build the Q7S binary on Windows, but a launch configuration needs to be newly created because the
IP address and path settings differ from machine to machine.
## Building in Xilinx SDK 2018.2
1. Open Xilinx SDK 2018.2
2. Import project
* File &rarr; Import &rarr; C/C++ &rarr; Existing Code as Makefile Project * File &rarr; Import &rarr; C/C++ &rarr; Existing Code as Makefile Project
5. Set build command. Replace \<target\> with either debug or release. 3. Set build command. Replace \<target\> with either debug or release.
* When on Linux right click project &rarr; Properties &rarr; C/C++ Build &rarr; Set build command to `make <target> -j` * When on Linux right click project &rarr; Properties &rarr; C/C++ Build &rarr; Set build command to `make <target> -j`
* -j causes the compiler to use all available cores * -j causes the compiler to use all available cores
* The target is used to either compile the debug or the optimized release build. * The target is used to either compile the debug or the optimized release build.
@ -70,153 +171,189 @@ git submodule update
* Target name: all * Target name: all
* Uncheck "Same as the target name" * Uncheck "Same as the target name"
* Uncheck "Use builder settings" * Uncheck "Use builder settings"
* As build command type: `make -j <target> WINDOWS=1` * As build command type: `cmake --build .`
6. Run build command by double clicking the created target or by right clicking * In the Behaviour tab, you can enable build acceleration
4. Run build command by double clicking the created target or by right clicking
the project folder and selecting Build Project. the project folder and selecting Build Project.
## Debugging the software (when workstation is directly conncected to Q7S) ## TCF-Agent
1. Assign static IP address to Q7S
* Open serial console of Q7S (Accessible via the micro-USB of the PIM, see also Q7S user maunal chapter 10.3) 1. On reboot, some steps have to be taken on the Q7S. Set static IP address and netmask
* Baudrate 115200
* Login to Q7S:
* user: root
* pw: root
* Set IP address and netmask with
```sh ```sh
ifconfig eth0 192.168.133.10 ifconfig eth0 192.168.133.10
ifconfig eth0 netmask 255.255.255.0 ifconfig eth0 netmask 255.255.255.0
``` ```
2. Connect Q7S to workstation via ethernet 2. `tcfagent` application should run automatically but this can be checked with
3. Make sure the netmask of the ehternet interface of the workstation matches the netmask of the Q7S
* When IP address is set to 192.168.133.10 and the netmask is 255.255.255.0, an example IP address for the workstation
is 192.168.133.2
4. Run tcf-agent on Q7S
* Tcf-agent is not yet integrated in the rootfs of the Q7S. Therefore build tcf-agent manually
```sh ```sh
git clone git://git.eclipse.org/gitroot/tcf/org.eclipse.tcf.agent.git systemctl status tcfagent
cd org.eclipse.tcf.agent/agent
make CC=arm-linux-gnueabihf-gcc LD=arm-linux-gnueabihf-ld MACHINE=arm NO_SSL=1 NO_UUID=1
``` ```
* Transfer executable agent from org.eclipse.tcf.agent/agent/obj/GNU/Linux/arm/Debug to /tmp of Q7S 3. If the agent is not running, check whether `agent` is located inside `usr/bin`.
You can run it manually there. To perform auto-start on boot, have a look at the start-up
```sh application section.
cd obj/GNU/Linux/arm/Debug
scp agent root@192.168.133.10:/tmp
```
* On Q7S
```sh
cd /tmp
chmod +x agent
```
* Run agent
```sh
./agent
```
5. In Xilinx SDK 2018.2 right click on project &rarr; Debug As &rarr; Debug Configurations
6. Right click Xilinx C/C++ applicaton (System Debugger) &rarr; New &rarr;
7. Set Debug Type to Linux Application Debug and Connectin to Linux Agent
8. Click New
9. Give connection a name
10. Set Host to static IP address of Q7S. e.g. 192.168.133.10
11. Test connection (This ensures the TCF Agent is running on the Q7S)
12. Select Application tab
* Project Name: eive_obsw
* Local File Path: Path to eiveobsw-linux.elf (in _bin\linux\devel)
* Remote File Path: /tmp/eive_obsw.elf
## Debugging the software via Flatsat PC ## Debugging the software via Flatsat PC
Open SSH connection to flatsat PC: Open SSH connection to flatsat PC:
````
```sh
ssh eive@flatsat.eive.absatvirt.lw
```
or
```sh
ssh eive@2001:7c0:2018:1099:babe:0:e1fe:f1a5 ssh eive@2001:7c0:2018:1099:babe:0:e1fe:f1a5
```` ```
To access the console of the Q7S run the following:
or
```sh
ssh eive@192.168.199.227
```
If the static IP address of the Q7S has already been set,
you can access it with ssh
```sh
ssh root@192.168.133.10
```
If this has not been done yet, you can access the serial
console of the Q7S like this to set it
```sh ```sh
picocom -b 115200 /dev/ttyUSB0 picocom -b 115200 /dev/ttyUSB0
``` ```
If the serial port is blocked for some reason, you can kill
the process using it with `q7s_kill`.
You can use `AltGr` + `X` to exit the picocom session.
To debug an application, first make sure a static IP address is assigned to the Q7S. Run ifconfig on the Q7S serial console. To debug an application, first make sure a static IP address is assigned to the Q7S. Run ifconfig on the Q7S serial console.
````
```sh
ifconfig ifconfig
```` ```
Set IP address and netmask with Set IP address and netmask with
````
```sh
ifconfig eth0 192.168.133.10 ifconfig eth0 192.168.133.10
ifconfig eth0 netmask 255.255.255.0 ifconfig eth0 netmask 255.255.255.0
```` ```
To launch application from Xilinx SDK setup port fowarding on the localhost.
```` To launch application from Xilinx SDK setup port fowarding on the development machine
ssh -L 1534:192.168.133.10:1534 eive@2001:7c0:2018:1099:babe:0:e1fe:f1a5 (not on the flatsat!)
````
```sh
ssh -L 1534:192.168.133.10:1534 eive@2001:7c0:2018:1099:babe:0:e1fe:f1a5 -t bash
```
This forwards any requests to localhost:1534 to the port 1534 of the Q7S with the IP address 192.168.133.10. This forwards any requests to localhost:1534 to the port 1534 of the Q7S with the IP address 192.168.133.10.
This needs to be done every time, so it is recommended to create an alias to do this quickly.
Note: When now setting up a debug session in the Xilinx SDK, the host must be set to localhost instead of the IP address Note: When now setting up a debug session in the Xilinx SDK, the host must be set to localhost instead of the IP address of the Q7S.
of the Q7S.
## Transfering files via SCP
To transfer files from the local machine to the Q7S, use port forwarding
```sh
ssh -L 1535:192.168.133.10:22 eive@2001:7c0:2018:1099:babe:0:e1fe:f1a5
```
Then you can copy an `example` file like this
```sh
scp -P 1535 example root@localhost:/tmp
```
Copying a file from Q7S to flatsat PC
````
scp -P 22 root@192.168.133.10:/tmp/kernel-config /tmp
````
From a windows machine files can be copied with putty tools
````
pscp -scp -P 22 eive@192.168.199.227:</directory-to-example-file/>/example-file </windows-machine-path/>
````
## Launching an application at start-up
## Launching an application after boot
Load the root partiton from the flash memory (there are to nor-flash memories and each flash holds two xdi images). Load the root partiton from the flash memory (there are to nor-flash memories and each flash holds two xdi images).
Note: It is not possible to modify the current loaded root partition. Note: It is not possible to modify the currently loaded root partition, e.g. creating directories. To do this,
the parition needs to be mounted.
1. Disable write protection of the desired root partition 1. Disable write protection of the desired root partition
````
writeprotect 0 0 0 # unlocks nominal image on nor-flash 0 ```sh
```` writeprotect 0 0 0 # unlocks nominal image on nor-flash 0
```
2. Mount the root partition 2. Mount the root partition
````
xsc_mount_copy 0 0 # Mounts the nominal image from nor-flash 0 ```sh
```` xsc_mount_copy 0 0 # Mounts the nominal image from nor-flash 0
3. Copy the executable to /bin/usr ```
The mounted partition will be located inside the `/tmp` folder
3. Copy the executable to `/usr/bin`
4. Make sure the permissions to execute the application are set 4. Make sure the permissions to execute the application are set
```` ```sh
chmod +x application chmod +x application
```` ```
5. Create systemd service in /lib/systemd/system. The following shows an example service. 5. Create systemd service in /lib/systemd/system. The following shows an example service.
```` ```sh
cat > example.service cat > example.service
[Unit] [Unit]
Description=Example Service Description=Example Service
StartLimitIntervalSec=0 StartLimitIntervalSec=0
[Service] [Service]
Type=simple Type=simple
Restart=always Restart=always
RestartSec=1 RestartSec=1
User=root User=root
ExecStart=/usr/bin/application ExecStart=/usr/bin/application
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target
```` ```
6. Enable the service. This is normally done with systemctl enable. However, this is not possible when the service is 6. Enable the service. This is normally done with systemctl enable. However, this is not possible when the service is
created for a mounted root partition. Therefore create a symlink as follows. created for a mounted root partition. Therefore create a symlink as follows.
```` ```sh
ln -s '/tmp/the-mounted-xdi-image/lib/systemd/system/example.service' '/tmp/the-mounted-xdi-image/etc/systemd/system/multi-user.target.wants/example.service' ln -s '/tmp/the-mounted-xdi-image/lib/systemd/system/example.service' '/tmp/the-mounted-xdi-image/etc/systemd/system/multi-user.target.wants/example.service'
```` ```
7. The modified root partition is written back when the partion is locked again. 7. The modified root partition is written back when the partion is locked again.
```` ```sh
writeprotect 0 0 1 writeprotect 0 0 1
```` ```
8. Now verify the application start by booting from the modified image 8. Now verify the application start by booting from the modified image
```` ```sh
xsc_boot_copy 0 0 xsc_boot_copy 0 0
```` ````
9. After booting verify if the service is running 9. After booting verify if the service is running
```` ```sh
systemctl status example systemctl status example
```` ```
More detailed information about the used q7s commands can be found in the Q7S user manual. More detailed information about the used q7s commands can be found in the Q7S user manual.
### Bringing up CAN ### Bringing up CAN
````
ip link set can0 down ```sh
ip link set can0 type can loopback off ip link set can0 down
ip link set can0 up type can bitrate 1000000 ip link set can0 type can loopback off
```` ip link set can0 up type can bitrate 1000000
```
Following command sends 8 bytes to device with id 99 (for petalinux) Following command sends 8 bytes to device with id 99 (for petalinux)
```` ````
cansend can0 -i99 99 88 77 11 33 11 22 99 cansend can0 -i99 99 88 77 11 33 11 22 99
@ -293,17 +430,6 @@ a permanent solution). If running the script before executing the binary does
not help or an warning is issue that the soft real time value is invalid, not help or an warning is issue that the soft real time value is invalid,
the hard real-time limit of the system might not be high enough (see step 1). the hard real-time limit of the system might not be high enough (see step 1).
## Building and running the software on a host system
The host build can be built with following command
```sh
make -f Makefile-Hosted all -j
```
If compiling on Windows, it is recommended to supply `WINDOWS=1` .
A release build can be built by using the `mission` target.
## Flight Software Framework (FSFW) ## Flight Software Framework (FSFW)
An EIVE fork of the FSFW is submodules into this repository. An EIVE fork of the FSFW is submodules into this repository.
@ -323,3 +449,134 @@ git merge upstream/master
Alternatively, changes from other upstreams (forks) and branches can be merged like that in Alternatively, changes from other upstreams (forks) and branches can be merged like that in
the same way. the same way.
## PCDU
Connect to serial console of P60 Dock
````
picocom -b 500000 /dev/ttyUSBx
````
General information
````
cmp ident
````
List parameter table:
x values: 1,2 or 4
````
param list x
````
Table 4 lists HK parameters
Changing parameters
First switch to table where parameter shall be changed (here table id is 1)
````
p60-dock # param mem 1
p60-dock # param set out_en[0] 1
p60-dock # param get out_en[0]
GET out_en[0] = 1
````
## Debugging the software (when workstation is directly conncected to Q7S)
1. Assign static IP address to Q7S
* Open serial console of Q7S (Accessible via the micro-USB of the PIM, see also Q7S user maunal chapter 10.3)
* Baudrate 115200
* Login to Q7S:
* user: root
* pw: root
2. Connect Q7S to workstation via ethernet
3. Make sure the netmask of the ehternet interface of the workstation matches the netmask of the Q7S
* When IP address is set to 192.168.133.10 and the netmask is 255.255.255.0, an example IP address for the workstation
is 192.168.133.2
4. Run tcf-agent on Q7S
* Tcf-agent is not yet integrated in the rootfs of the Q7S. Therefore build tcf-agent manually
```sh
git clone git://git.eclipse.org/gitroot/tcf/org.eclipse.tcf.agent.git
cd org.eclipse.tcf.agent/agent
make CC=arm-linux-gnueabihf-gcc LD=arm-linux-gnueabihf-ld MACHINE=arm NO_SSL=1 NO_UUID=1
```
* Transfer executable agent from org.eclipse.tcf.agent/agent/obj/GNU/Linux/arm/Debug to /tmp of Q7S
```sh
cd obj/GNU/Linux/arm/Debug
scp agent root@192.168.133.10:/tmp
```
* On Q7S
```sh
cd /tmp
chmod +x agent
```
* Run agent
```sh
./agent
```
5. In Xilinx SDK 2018.2 right click on project &rarr; Debug As &rarr; Debug Configurations
6. Right click Xilinx C/C++ applicaton (System Debugger) &rarr; New &rarr;
7. Set Debug Type to Linux Application Debug and Connectin to Linux Agent
8. Click New
9. Give connection a name
10. Set Host to static IP address of Q7S. e.g. 192.168.133.10
11. Test connection (This ensures the TCF Agent is running on the Q7S)
12. Select Application tab
* Project Name: eive_obsw
* Local File Path: Path to eiveobsw-linux.elf (in _bin\linux\devel)
* Remote File Path: /tmp/eive_obsw.elf
## Libgpiod
Detect all gpio device files:
````
gpiodetect
````
Get info about a specific gpio group:
````
gpioinfo <name of gpio group>
````
The following sets the gpio 18 from gpio group gpiochip7 to high level.
````
gpioset gpiochip7 18=1
````
Setting the gpio to low.
````
gpioset gpiochip7 18=0
````
Show options for setting gpios.
````
gpioset -h
````
To get the state of a gpio:
````
gpioget <gpiogroup> <offset>
````
Example to get state:
gpioget gpiochip7 14
## Running the EIVE OBSW on a Raspberry Pi
Special section for running the EIVE OBSW on the Raspberry Pi.
The Raspberry Pi build uses the `bsp_rpi` BSP folder, and a very similar cross-compiler.
For running the software on a Raspberry Pi, it is recommended to follow the steps specified in
[the fsfw example](https://egit.irs.uni-stuttgart.de/fsfw/fsfw_example/src/branch/mueller/master/doc/README-rpi.md#top)
and using the TCF agent to have a similar set-up process also required for the Q7S.
You should run the following command first on your Raspberry Pi
```sh
sudo apt-get install gpiod libgpiod-dev
```
to install the required GPIO libraries before cloning the system root folder.
## Special notes on Eclipse
When using Eclipse, there are two special build variables in the project properties
&rarr; C/C++ Build &rarr; Build Variables called `Q7S_SYSROOT` or `RPI_SYSROOT`. You can set
the sysroot path in those variables to get any additional includes like `gpiod.h` in the
Eclipse indexer.

10
bsp_hosted/CMakeLists.txt Normal file
View File

@ -0,0 +1,10 @@
target_sources(${TARGET_NAME} PUBLIC
InitMission.cpp
main.cpp
ObjectFactory.cpp
)
add_subdirectory(fsfwconfig)
add_subdirectory(boardconfig)

159
bsp_hosted/InitMission.cpp Normal file
View File

@ -0,0 +1,159 @@
#include "InitMission.h"
#include "ObjectFactory.h"
#include <OBSWConfig.h>
#include <fsfw/objectmanager/ObjectManagerIF.h>
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
#include <fsfw/serviceinterface/ServiceInterfaceStream.h>
#include <fsfw/objectmanager/ObjectManager.h>
#include <fsfw/tasks/FixedTimeslotTaskIF.h>
#include <fsfw/tasks/PeriodicTaskIF.h>
#include <fsfw/tasks/TaskFactory.h>
#include <mission/utility/InitMission.h>
#include <iostream>
#ifdef LINUX
ServiceInterfaceStream sif::debug("DEBUG");
ServiceInterfaceStream sif::info("INFO");
ServiceInterfaceStream sif::warning("WARNING");
ServiceInterfaceStream sif::error("ERROR", false, false, true);
#else
ServiceInterfaceStream sif::debug("DEBUG", true);
ServiceInterfaceStream sif::info("INFO", true);
ServiceInterfaceStream sif::warning("WARNING", true);
ServiceInterfaceStream sif::error("ERROR", true, false, true);
#endif
ObjectManagerIF *objectManager = nullptr;
void initmission::initMission() {
sif::info << "Building global objects.." << std::endl;
/* Instantiate global object manager and also create all objects */
objectManager = new ObjectManager(ObjectFactory::produce);
sif::info << "Initializing all objects.." << std::endl;
objectManager->initialize();
/* This function creates and starts all tasks */
initTasks();
}
void initmission::initTasks() {
TaskFactory* factory = TaskFactory::instance();
if(factory == nullptr) {
/* Should never happen ! */
return;
}
#if OBSW_PRINT_MISSED_DEADLINES == 1
void (*missedDeadlineFunc) (void) = TaskFactory::printMissedDeadline;
#else
void (*missedDeadlineFunc) (void) = nullptr;
#endif
/* TMTC Distribution */
PeriodicTaskIF* tmTcDistributor = factory->createPeriodicTask(
"DIST", 40, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.2, missedDeadlineFunc);
ReturnValue_t result = tmTcDistributor->addComponent(
objects::CCSDS_PACKET_DISTRIBUTOR);
if(result != HasReturnvaluesIF::RETURN_OK){
sif::error << "Object add component failed" << std::endl;
}
result = tmTcDistributor->addComponent(objects::PUS_PACKET_DISTRIBUTOR);
if(result != HasReturnvaluesIF::RETURN_OK){
sif::error << "Object add component failed" << std::endl;
}
result = tmTcDistributor->addComponent(objects::TM_FUNNEL);
if(result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "Object add component failed" << std::endl;
}
/* UDP bridge */
PeriodicTaskIF* udpBridgeTask = factory->createPeriodicTask(
"UDP_UNIX_BRIDGE", 50, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.2, missedDeadlineFunc);
result = udpBridgeTask->addComponent(objects::UDP_BRIDGE);
if(result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "Add component UDP Unix Bridge failed" << std::endl;
}
PeriodicTaskIF* udpPollingTask = factory->createPeriodicTask(
"UDP_POLLING", 80, PeriodicTaskIF::MINIMUM_STACK_SIZE, 2.0, missedDeadlineFunc);
result = udpPollingTask->addComponent(objects::UDP_POLLING_TASK);
if(result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "Add component UDP Polling failed" << std::endl;
}
/* PUS Services */
PeriodicTaskIF* pusVerification = factory->createPeriodicTask(
"PUS_VERIF", 40, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.200, missedDeadlineFunc);
result = pusVerification->addComponent(objects::PUS_SERVICE_1_VERIFICATION);
if(result != HasReturnvaluesIF::RETURN_OK){
sif::error << "Object add component failed" << std::endl;
}
PeriodicTaskIF* pusEvents = factory->createPeriodicTask(
"PUS_EVENTS", 60, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.200, missedDeadlineFunc);
result = pusVerification->addComponent(objects::PUS_SERVICE_5_EVENT_REPORTING);
if(result != HasReturnvaluesIF::RETURN_OK){
initmission::printAddObjectError("PUS5", objects::PUS_SERVICE_5_EVENT_REPORTING);
}
PeriodicTaskIF* pusHighPrio = factory->createPeriodicTask(
"PUS_HIGH_PRIO", 50, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.200, missedDeadlineFunc);
result = pusHighPrio->addComponent(objects::PUS_SERVICE_2_DEVICE_ACCESS);
if(result != HasReturnvaluesIF::RETURN_OK) {
initmission::printAddObjectError("PUS2", objects::PUS_SERVICE_2_DEVICE_ACCESS);
}
result = pusHighPrio->addComponent(objects::PUS_SERVICE_9_TIME_MGMT);
if(result != HasReturnvaluesIF::RETURN_OK) {
initmission::printAddObjectError("PUS9", objects::PUS_SERVICE_9_TIME_MGMT);
}
PeriodicTaskIF* pusMedPrio = factory->createPeriodicTask(
"PUS_MED_PRIO", 40, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.8, missedDeadlineFunc);
result = pusMedPrio->addComponent(objects::PUS_SERVICE_8_FUNCTION_MGMT);
if(result != HasReturnvaluesIF::RETURN_OK) {
initmission::printAddObjectError("PUS8", objects::PUS_SERVICE_8_FUNCTION_MGMT);
}
result = pusMedPrio->addComponent(objects::PUS_SERVICE_200_MODE_MGMT);
if(result != HasReturnvaluesIF::RETURN_OK) {
initmission::printAddObjectError("PUS200", objects::PUS_SERVICE_200_MODE_MGMT);
}
result = pusMedPrio->addComponent(objects::PUS_SERVICE_20_PARAMETERS);
if(result != HasReturnvaluesIF::RETURN_OK) {
initmission::printAddObjectError("PUS20", objects::PUS_SERVICE_20_PARAMETERS);
}
PeriodicTaskIF* pusLowPrio = factory->createPeriodicTask(
"PUS_LOW_PRIO", 30, PeriodicTaskIF::MINIMUM_STACK_SIZE, 1.6, missedDeadlineFunc);
result = pusLowPrio->addComponent(objects::PUS_SERVICE_17_TEST);
if(result != HasReturnvaluesIF::RETURN_OK) {
initmission::printAddObjectError("PUS17", objects::PUS_SERVICE_17_TEST);
}
PeriodicTaskIF* testTask = factory->createPeriodicTask(
"TEST_TASK", 40, PeriodicTaskIF::MINIMUM_STACK_SIZE, 2.0, missedDeadlineFunc);
#if OBSW_ADD_TEST_CODE == 1
result = testTask->addComponent(objects::TEST_TASK);
if(result != HasReturnvaluesIF::RETURN_OK) {
initmission::printAddObjectError("TEST_TASK", objects::TEST_TASK);
}
#endif /* OBSW_ADD_TEST_CODE == 1 */
sif::info << "Starting tasks.." << std::endl;
tmTcDistributor->startTask();
udpBridgeTask->startTask();
udpPollingTask->startTask();
pusVerification->startTask();
pusEvents->startTask();
pusHighPrio->startTask();
pusMedPrio->startTask();
pusLowPrio->startTask();
#if OBSW_ADD_TEST_CODE == 1
testTask->startTask();
#endif /* OBSW_ADD_TEST_CODE == 1 */
sif::info << "Tasks started.." << std::endl;
}

View File

@ -1,7 +1,7 @@
#ifndef BSP_LINUX_INITMISSION_H_ #ifndef BSP_LINUX_INITMISSION_H_
#define BSP_LINUX_INITMISSION_H_ #define BSP_LINUX_INITMISSION_H_
namespace InitMission { namespace initmission {
void initMission(); void initMission();
void initTasks(); void initTasks();
}; };

View File

@ -1,20 +1,27 @@
#include "ObjectFactory.h" #include "ObjectFactory.h"
#include <objects/systemObjectList.h>
#include <OBSWConfig.h> #include <OBSWConfig.h>
#include <objects/systemObjectList.h>
#include <tmtc/apid.h> #include <tmtc/apid.h>
#include <tmtc/pusIds.h> #include <tmtc/pusIds.h>
#include <fsfw/tmtcservices/CommandingServiceBase.h> #include <fsfw/tmtcservices/CommandingServiceBase.h>
#include <fsfw/tmtcservices/PusServiceBase.h> #include <fsfw/tmtcservices/PusServiceBase.h>
#include <fsfw/osal/linux/TmTcUnixUdpBridge.h>
#include <fsfw/tmtcpacket/pus/TmPacketStored.h>
#include <fsfw/osal/linux/TcUnixUdpPollingTask.h>
#include <mission/core/GenericFactory.h> #include <mission/core/GenericFactory.h>
#include <mission/utility/TmFunnel.h> #include <mission/utility/TmFunnel.h>
void Factory::setStaticFrameworkObjectIds() { #include <fsfw/osal/common/UdpTcPollingTask.h>
#include <fsfw/osal/common/UdpTmTcBridge.h>
#include <fsfw/tmtcpacket/pus/TmPacketStored.h>
#if OBSW_ADD_TEST_CODE == 1
#include <test/testtasks/TestTask.h>
#endif
void Factory::setStaticFrameworkObjectIds(){
PusServiceBase::packetSource = objects::PUS_PACKET_DISTRIBUTOR; PusServiceBase::packetSource = objects::PUS_PACKET_DISTRIBUTOR;
PusServiceBase::packetDestination = objects::TM_FUNNEL; PusServiceBase::packetDestination = objects::TM_FUNNEL;
@ -29,14 +36,13 @@ void Factory::setStaticFrameworkObjectIds() {
TmPacketStored::timeStamperId = objects::TIME_STAMPER; TmPacketStored::timeStamperId = objects::TIME_STAMPER;
} }
void ObjectFactory::produce(){ void ObjectFactory::produce(){
Factory::setStaticFrameworkObjectIds(); Factory::setStaticFrameworkObjectIds();
ObjectFactory::produceGenericObjects(); ObjectFactory::produceGenericObjects();
new TmTcUnixUdpBridge(objects::UDP_BRIDGE, new UdpTmTcBridge(objects::UDP_BRIDGE,
objects::CCSDS_PACKET_DISTRIBUTOR, objects::CCSDS_PACKET_DISTRIBUTOR,
objects::TM_STORE, objects::TC_STORE); objects::TM_STORE, objects::TC_STORE);
new TcUnixUdpPollingTask(objects::UDP_POLLING_TASK, objects::UDP_BRIDGE); new UdpTcPollingTask(objects::UDP_POLLING_TASK, objects::UDP_BRIDGE);
} }

View File

@ -0,0 +1,10 @@
target_sources(${TARGET_NAME} PRIVATE
print.c
)
target_include_directories(${TARGET_NAME} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
)

View File

@ -1,4 +1,5 @@
#include "print.h" #include "print.h"
#include <stdio.h> #include <stdio.h>
void printChar(const char* character, bool errStream) { void printChar(const char* character, bool errStream) {

View File

@ -0,0 +1,8 @@
#ifndef BSP_HOSTED_BOARDCONFIG_PRINT_H_
#define BSP_HOSTED_BOARDCONFIG_PRINT_H_
#include <stdbool.h>
void printChar(const char* character, bool errStream);
#endif /* BSP_HOSTED_BOARDCONFIG_PRINT_H_ */

View File

@ -8,3 +8,4 @@ CXXSRC += $(wildcard $(CURRENTPATH)/comIF/*.cpp)
CSRC += $(wildcard $(CURRENTPATH)/comIF/*.c) CSRC += $(wildcard $(CURRENTPATH)/comIF/*.c)
INCLUDES += $(CURRENTPATH)/boardconfig INCLUDES += $(CURRENTPATH)/boardconfig
INCLUDES += $(CURRENTPATH)/fsfwconfig

View File

@ -8,6 +8,8 @@
// This only works on Linux // This only works on Linux
#ifdef LINUX #ifdef LINUX
#include <termios.h> #include <termios.h>
#include <fcntl.h>
#include <unistd.h>
#elif WIN32 #elif WIN32
#include <windows.h> #include <windows.h>
#include <strsafe.h> #include <strsafe.h>
@ -255,7 +257,7 @@ ReturnValue_t ArduinoComIF::sendMessage(uint8_t command,
encodedLen = sizeof(sendBuffer) - remainingLen; encodedLen = sizeof(sendBuffer) - remainingLen;
#ifdef LINUX #ifdef LINUX
ssize_t writtenlen = write(serialPort, sendBuffer, encodedLen); ssize_t writtenlen = ::write(serialPort, sendBuffer, encodedLen);
if (writtenlen < 0) { if (writtenlen < 0) {
//we could try to find out what happened... //we could try to find out what happened...
return RETURN_FAILED; return RETURN_FAILED;
@ -286,7 +288,7 @@ void ArduinoComIF::handleSerialPortRx() {
rxBuffer.writeData(dataFromSerial, bytesRead); rxBuffer.writeData(dataFromSerial, bytesRead);
uint8_t dataReceivedSoFar[rxBuffer.maxSize()]; uint8_t dataReceivedSoFar[rxBuffer.getMaxSize()];
uint32_t dataLenReceivedSoFar = 0; uint32_t dataLenReceivedSoFar = 0;
@ -296,11 +298,11 @@ void ArduinoComIF::handleSerialPortRx() {
//look for STX //look for STX
size_t firstSTXinRawData = 0; size_t firstSTXinRawData = 0;
while ((firstSTXinRawData < dataLenReceivedSoFar) while ((firstSTXinRawData < dataLenReceivedSoFar)
&& (dataReceivedSoFar[firstSTXinRawData] != DleEncoder::STX)) { && (dataReceivedSoFar[firstSTXinRawData] != DleEncoder::STX_CHAR)) {
firstSTXinRawData++; firstSTXinRawData++;
} }
if (dataReceivedSoFar[firstSTXinRawData] != DleEncoder::STX) { if (dataReceivedSoFar[firstSTXinRawData] != DleEncoder::STX_CHAR) {
//there is no STX in our data, throw it away... //there is no STX in our data, throw it away...
rxBuffer.deleteData(dataLenReceivedSoFar); rxBuffer.deleteData(dataLenReceivedSoFar);
return; return;

View File

@ -1,4 +1,4 @@
#include "ArduinoCookie.h" #include <bsp_hosted/comIF/ArduinoCookie.h>
ArduinoCookie::ArduinoCookie(Protocol_t protocol, uint8_t address, ArduinoCookie::ArduinoCookie(Protocol_t protocol, uint8_t address,
const size_t maxReplySize) : const size_t maxReplySize) :

View File

@ -0,0 +1,8 @@
target_sources(${TARGET_NAME} PUBLIC
ArduinoComIF.cpp
ArduinoCookie.cpp
)

View File

@ -0,0 +1,10 @@
target_sources(${TARGET_NAME} PRIVATE
ipc/MissionMessageTypes.cpp
)
target_include_directories(${TARGET_NAME} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
)

View File

@ -1,25 +1,27 @@
#ifndef CONFIG_FSFWCONFIG_H_ #ifndef CONFIG_FSFWCONFIG_H_
#define CONFIG_FSFWCONFIG_H_ #define CONFIG_FSFWCONFIG_H_
#include <FSFWVersion.h>
#include <cstddef> #include <cstddef>
#include <cstdint>
//! Used to determine whether C++ ostreams are used //! Used to determine whether C++ ostreams are used which can increase
//! Those can lead to code bloat. //! the binary size significantly. If this is disabled,
//! the C stdio functions can be used alternatively
#define FSFW_CPP_OSTREAM_ENABLED 1 #define FSFW_CPP_OSTREAM_ENABLED 1
//! Reduced printout to further decrese code size //! More FSFW related printouts depending on level. Useful for development.
//! Be careful, this also turns off most diagnostic prinouts! #define FSFW_VERBOSE_LEVEL 1
#define FSFW_REDUCED_PRINTOUT 0
//! Can be used to enable debugging printouts for developing the FSFW //! Can be used to completely disable printouts, even the C stdio ones.
#define FSFW_DEBUGGING 0 #if FSFW_CPP_OSTREAM_ENABLED == 0 && FSFW_VERBOSE_LEVEL == 0
#define FSFW_DISABLE_PRINTOUT 0
#endif
//! Defines the FIFO depth of each commanding service base which //! Can be used to disable the ANSI color sequences for C stdio.
//! also determines how many commands a CSB service can handle in one cycle #define FSFW_COLORED_OUTPUT 1
//! simulataneously. This will increase the required RAM for
//! each CSB service ! //! Can be used to disable the ANSI color sequences for C stdio.
#define FSFW_CSB_FIFO_DEPTH 6 #define FSFW_COLORED_OUTPUT 1
//! If FSFW_OBJ_EVENT_TRANSLATION is set to one, //! If FSFW_OBJ_EVENT_TRANSLATION is set to one,
//! additional output which requires the translation files translateObjects //! additional output which requires the translation files translateObjects
@ -27,19 +29,20 @@
#define FSFW_OBJ_EVENT_TRANSLATION 0 #define FSFW_OBJ_EVENT_TRANSLATION 0
#if FSFW_OBJ_EVENT_TRANSLATION == 1 #if FSFW_OBJ_EVENT_TRANSLATION == 1
#define FSFW_DEBUG_OUTPUT 1
//! Specify whether info events are printed too. //! Specify whether info events are printed too.
#define FSFW_DEBUG_INFO 1 #define FSFW_DEBUG_INFO 1
#include <translateObjects.h> #include "objects/translateObjects.h"
#include <translateEvents.h> #include "events/translateEvents.h"
#else #else
#define FSFW_DEBUG_OUTPUT 0
#endif #endif
//! When using the newlib nano library, C99 support for stdio facilities //! When using the newlib nano library, C99 support for stdio facilities
//! will not be provided. This define should be set to 1 if this is the case. //! will not be provided. This define should be set to 1 if this is the case.
#define FSFW_NO_C99_IO 1 #define FSFW_NO_C99_IO 1
//! Specify whether a special mode store is used for Subsystem components.
#define FSFW_USE_MODESTORE 0
namespace fsfwconfig { namespace fsfwconfig {
//! Default timestamp size. The default timestamp will be an eight byte CDC //! Default timestamp size. The default timestamp will be an eight byte CDC
//! short timestamp. //! short timestamp.
@ -49,6 +52,14 @@ static constexpr uint8_t FSFW_MISSION_TIMESTAMP_SIZE = 8;
static constexpr size_t FSFW_EVENTMGMR_MATCHTREE_NODES = 240; static constexpr size_t FSFW_EVENTMGMR_MATCHTREE_NODES = 240;
static constexpr size_t FSFW_EVENTMGMT_EVENTIDMATCHERS = 120; static constexpr size_t FSFW_EVENTMGMT_EVENTIDMATCHERS = 120;
static constexpr size_t FSFW_EVENTMGMR_RANGEMATCHERS = 120; static constexpr size_t FSFW_EVENTMGMR_RANGEMATCHERS = 120;
//! Defines the FIFO depth of each commanding service base which
//! also determines how many commands a CSB service can handle in one cycle
//! simulataneously. This will increase the required RAM for
//! each CSB service !
static constexpr uint8_t FSFW_CSB_FIFO_DEPTH = 6;
static constexpr size_t FSFW_PRINT_BUFFER_SIZE = 124;
} }
#endif /* CONFIG_FSFWCONFIG_H_ */ #endif /* CONFIG_FSFWCONFIG_H_ */

View File

@ -0,0 +1,32 @@
/**
* @brief This file can be used to add preprocessor define for conditional
* code inclusion exclusion or various other project constants and
* properties in one place.
*/
#ifndef CONFIG_OBSWCONFIG_H_
#define CONFIG_OBSWCONFIG_H_
#include "commonConfig.h"
#define OBSW_ADD_TEST_CODE 1
/* These defines should be disabled for mission code but are useful for
debugging. */
#define OBSW_VEBOSE_LEVEL 1
#ifdef __cplusplus
#include "objects/systemObjectList.h"
#include "events/subsystemIdRanges.h"
#include "returnvalues/classIds.h"
namespace config {
#endif
/* Add mission configuration flags here */
#ifdef __cplusplus
}
#endif
#endif /* CONFIG_OBSWCONFIG_H_ */

View File

@ -3,8 +3,8 @@
const char* const SW_NAME = "eive"; const char* const SW_NAME = "eive";
#define SW_VERSION 0 #define SW_VERSION 1
#define SW_SUBVERSION 2 #define SW_SUBVERSION 0
#define SW_SUBSUBVERSION 0 #define SW_SUBSUBVERSION 0

View File

@ -0,0 +1,59 @@
#ifndef FSFWCONFIG_DEVICES_GPIOIDS_H_
#define FSFWCONFIG_DEVICES_GPIOIDS_H_
#include <linux/gpio/GpioIF.h>
namespace gpioIds {
enum gpioId_t {
HEATER_0,
HEATER_1,
HEATER_2,
HEATER_3,
HEATER_4,
HEATER_5,
HEATER_6,
HEATER_7,
DEPLSA1,
DEPLSA2,
MGM_0_LIS3_CS,
MGM_1_RM3100_CS,
GYRO_0_ADIS_CS,
GYRO_1_L3G_CS,
GYRO_2_L3G_CS,
MGM_2_LIS3_CS,
MGM_3_RM3100_CS,
TEST_ID_0,
TEST_ID_1,
RTD_IC3,
RTD_IC4,
RTD_IC5,
RTD_IC6,
RTD_IC7,
RTD_IC8,
RTD_IC9,
RTD_IC10,
RTD_IC11,
RTD_IC12,
RTD_IC13,
RTD_IC14,
RTD_IC15,
RTD_IC16,
RTD_IC17,
RTD_IC18,
SPI_MUX_BIT_1,
SPI_MUX_BIT_2,
SPI_MUX_BIT_3,
SPI_MUX_BIT_4,
SPI_MUX_BIT_5,
SPI_MUX_BIT_6
};
}
#endif /* FSFWCONFIG_DEVICES_GPIOIDS_H_ */

View File

@ -0,0 +1,58 @@
#ifndef FSFWCONFIG_DEVICES_POWERSWITCHERLIST_H_
#define FSFWCONFIG_DEVICES_POWERSWITCHERLIST_H_
#include <OBSWConfig.h>
namespace pcduSwitches {
/* Switches are uint8_t datatype and go from 0 to 255 */
enum switcherList {
Q7S,
PAYLOAD_PCDU_CH1,
RW,
TCS_BOARD_8V_HEATER_IN,
SUS_REDUNDANT,
DEPLOYMENT_MECHANISM,
PAYLOAD_PCDU_CH6,
ACS_BOARD_SIDE_B,
PAYLOAD_CAMERA,
TCS_BOARD_3V3,
SYRLINKS,
STAR_TRACKER,
MGT,
SUS_NOMINAL,
SOLAR_CELL_EXP,
PLOC,
ACS_BORAD_SIDE_A,
NUMBER_OF_SWITCHES
};
static const uint8_t ON = 1;
static const uint8_t OFF = 0;
/* Output states after reboot of the PDUs */
static const uint8_t INIT_STATE_Q7S = ON;
static const uint8_t INIT_STATE_PAYLOAD_PCDU_CH1 = OFF;
static const uint8_t INIT_STATE_RW = OFF;
#if TE0720 == 1
/* Because the TE0720 is not connected to the PCDU, this switch is always on */
static const uint8_t INIT_STATE_TCS_BOARD_8V_HEATER_IN = ON;
#else
static const uint8_t INIT_STATE_TCS_BOARD_8V_HEATER_IN = OFF;
#endif
static const uint8_t INIT_STATE_SUS_REDUNDANT = OFF;
static const uint8_t INIT_STATE_DEPLOYMENT_MECHANISM = OFF;
static const uint8_t INIT_STATE_PAYLOAD_PCDU_CH6 = OFF;
static const uint8_t INIT_STATE_ACS_BOARD_SIDE_B = OFF;
static const uint8_t INIT_STATE_PAYLOAD_CAMERA = OFF;
static const uint8_t INIT_STATE_TCS_BOARD_3V3 = OFF;
static const uint8_t INIT_STATE_SYRLINKS = OFF;
static const uint8_t INIT_STATE_STAR_TRACKER = OFF;
static const uint8_t INIT_STATE_MGT = OFF;
static const uint8_t INIT_STATE_SUS_NOMINAL = OFF;
static const uint8_t INIT_STATE_SOLAR_CELL_EXP = OFF;
static const uint8_t INIT_STATE_PLOC = OFF;
static const uint8_t INIT_STATE_ACS_BOARD_SIDE_A = OFF;
}
#endif /* FSFWCONFIG_DEVICES_POWERSWITCHERLIST_H_ */

View File

@ -10,7 +10,7 @@
*/ */
namespace SUBSYSTEM_ID { namespace SUBSYSTEM_ID {
enum: uint8_t { enum: uint8_t {
SUBSYSTE_ID_START = FW_SUBSYSTEM_ID_RANGE, SUBSYSTEM_ID_START = FW_SUBSYSTEM_ID_RANGE,
PUS_SERVICE_2, PUS_SERVICE_2,
PUS_SERVICE_3, PUS_SERVICE_3,
PUS_SERVICE_5, PUS_SERVICE_5,
@ -18,6 +18,7 @@ enum: uint8_t {
PUS_SERVICE_8, PUS_SERVICE_8,
PUS_SERVICE_23, PUS_SERVICE_23,
MGM_LIS3MDL, MGM_LIS3MDL,
MGM_RM3100,
DUMMY_DEVICE, DUMMY_DEVICE,
}; };

View File

@ -0,0 +1,7 @@
CXXSRC += $(wildcard $(CURRENTPATH)/cdatapool/*.cpp)
CXXSRC += $(wildcard $(CURRENTPATH)/ipc/*.cpp)
CXXSRC += $(wildcard $(CURRENTPATH)/objects/*.cpp)
CXXSRC += $(wildcard $(CURRENTPATH)/pollingsequence/*.cpp)
CXXSRC += $(wildcard $(CURRENTPATH)/events/*.cpp)
INCLUDES += $(CURRENTPATH)

View File

@ -1,5 +1,5 @@
#include "MissionMessageTypes.h"
#include <fsfw/ipc/CommandMessage.h> #include <fsfw/ipc/CommandMessage.h>
#include <hosted/fsfwconfig/ipc/MissionMessageTypes.h>
void messagetypes::clearMissionMessage(CommandMessage* message) { void messagetypes::clearMissionMessage(CommandMessage* message) {
switch(message->getMessageType()) { switch(message->getMessageType()) {

View File

@ -11,7 +11,7 @@ class CommandMessage;
* <fsfw/ipc/FwMessageTypes.h> * <fsfw/ipc/FwMessageTypes.h>
* @param message Generic Command Message * @param message Generic Command Message
*/ */
namespace messagetypes{ namespace messagetypes {
enum MESSAGE_TYPE { enum MESSAGE_TYPE {
MISSION_MESSAGE_TYPE_START = FW_MESSAGES_COUNT, MISSION_MESSAGE_TYPE_START = FW_MESSAGES_COUNT,
}; };

View File

@ -0,0 +1,50 @@
#ifndef HOSTED_CONFIG_OBJECTS_SYSTEMOBJECTLIST_H_
#define HOSTED_CONFIG_OBJECTS_SYSTEMOBJECTLIST_H_
#include <cstdint>
// The objects will be instantiated in the ID order
namespace objects {
enum sourceObjects: uint32_t {
/* First Byte 0x50-0x52 reserved for PUS Services **/
CCSDS_PACKET_DISTRIBUTOR = 0x50000100,
PUS_PACKET_DISTRIBUTOR = 0x50000200,
UDP_BRIDGE = 0x50000300,
UDP_POLLING_TASK = 0x50000400,
PUS_SERVICE_3 = 0x51000300,
PUS_SERVICE_5 = 0x51000400,
PUS_SERVICE_6 = 0x51000500,
PUS_SERVICE_8 = 0x51000800,
PUS_SERVICE_23 = 0x51002300,
PUS_SERVICE_201 = 0x51020100,
TM_FUNNEL = 0x52000002,
/* Test Task */
TEST_TASK = 0x42694269,
DUMMY_INTERFACE = 0xCAFECAFE,
DUMMY_HANDLER = 0x4400AFFE,
/* 0x44 ('D') for device handlers */
P60DOCK_HANDLER = 0x44000001,
PDU1_HANDLER = 0x44000002,
PDU2_HANDLER = 0x44000003,
ACU_HANDLER = 0x44000004,
TMP1075_HANDLER_1 = 0x44000005,
TMP1075_HANDLER_2 = 0x44000006,
MGM_0_LIS3_HANDLER = 0x4400007,
MGM_1_RM3100_HANDLER = 0x44000008,
MGM_2_LIS3_HANDLER = 0x44000009,
MGM_3_RM3100_HANDLER = 0x44000010,
GYRO_0_ADIS_HANDLER = 0x44000011,
GYRO_1_L3G_HANDLER = 0x44000012,
GYRO_2_L3G_HANDLER = 0x44000013,
/* 0x49 ('I') for Communication Interfaces **/
ARDUINO_COM_IF = 0x49000001
};
}
#endif /* BSP_CONFIG_OBJECTS_SYSTEMOBJECTLIST_H_ */

View File

@ -11,7 +11,8 @@
namespace CLASS_ID { namespace CLASS_ID {
enum { enum {
MISSION_CLASS_ID_START = FW_CLASS_ID_COUNT, MISSION_CLASS_ID_START = FW_CLASS_ID_COUNT,
MGM_LIS3MDL MGM_LIS3MDL,
MGM_RM3100
}; };
} }

View File

@ -0,0 +1,19 @@
#ifndef FSFWCONFIG_TMTC_APID_H_
#define FSFWCONFIG_TMTC_APID_H_
#include <stdint.h>
/**
* Application Process Definition: entity, uniquely identified by an
* application process ID (APID), capable of generating telemetry source
* packets and receiving telecommand packets
*
* SOURCE APID: 0x73 / 115 / s
* APID is a 11 bit number
*/
namespace apid {
static const uint16_t EIVE_OBSW = 0x65;
}
#endif /* FSFWCONFIG_TMTC_APID_H_ */

View File

@ -0,0 +1,23 @@
#ifndef CONFIG_TMTC_PUSIDS_HPP_
#define CONFIG_TMTC_PUSIDS_HPP_
namespace pus {
enum Ids{
PUS_SERVICE_1 = 1,
PUS_SERVICE_2 = 2,
PUS_SERVICE_3 = 3,
PUS_SERVICE_3_PSB = 3,
PUS_SERVICE_5 = 5,
PUS_SERVICE_6 = 6,
PUS_SERVICE_8 = 8,
PUS_SERVICE_9 = 9,
PUS_SERVICE_17 = 17,
PUS_SERVICE_19 = 19,
PUS_SERVICE_20 = 20,
PUS_SERVICE_23 = 23,
PUS_SERVICE_200 = 200,
PUS_SERVICE_201 = 201,
};
};
#endif /* CONFIG_TMTC_PUSIDS_HPP_ */

View File

@ -1,7 +1,7 @@
#include <bsp_linux/InitMission.h> #include "InitMission.h"
#include <fsfw/tasks/TaskFactory.h>
#include <hosted/fsfwconfig/OBSWVersion.h>
#include <OBSWVersion.h>
#include <fsfw/tasks/TaskFactory.h>
#include <iostream> #include <iostream>
#ifdef WIN32 #ifdef WIN32
@ -24,7 +24,7 @@ int main(void)
<< SW_SUBVERSION << "." << SW_SUBSUBVERSION << " -- " << std::endl; << SW_SUBVERSION << "." << SW_SUBSUBVERSION << " -- " << std::endl;
std::cout << "-- " << __DATE__ << " " << __TIME__ << " --" << std::endl; std::cout << "-- " << __DATE__ << " " << __TIME__ << " --" << std::endl;
InitMission::initMission(); initmission::initMission();
for(;;) { for(;;) {
// suspend main thread by sleeping it. // suspend main thread by sleeping it.

View File

@ -1,159 +0,0 @@
#include <bsp_linux/InitMission.h>
#include <bsp_linux/ObjectFactory.h>
#include <fsfw/objectmanager/ObjectManagerIF.h>
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
#include <fsfw/serviceinterface/ServiceInterfaceStream.h>
#include <fsfw/datapool/DataPool.h>
#include <fsfw/objectmanager/ObjectManager.h>
#include <fsfw/tasks/FixedTimeslotTaskIF.h>
#include <fsfw/tasks/PeriodicTaskIF.h>
#include <fsfw/tasks/TaskFactory.h>
#include <fsfwconfig/objects/systemObjectList.h>
#include <fsfwconfig/OBSWConfig.h>
#include <iostream>
// This is configured for linux without \cr
#ifdef LINUX
ServiceInterfaceStream sif::debug("DEBUG");
ServiceInterfaceStream sif::info("INFO");
ServiceInterfaceStream sif::warning("WARNING");
ServiceInterfaceStream sif::error("ERROR", false, false, true);
#else
ServiceInterfaceStream sif::debug("DEBUG", true);
ServiceInterfaceStream sif::info("INFO", true);
ServiceInterfaceStream sif::warning("WARNING", true);
ServiceInterfaceStream sif::error("ERROR", true, false, true);
#endif
ObjectManagerIF *objectManager = nullptr;
//Initialize Data Pool
DataPool dataPool(nullptr);
void InitMission::initMission() {
sif::info << "Building global objects.." << std::endl;
/* Instantiate global object manager and also create all objects */
objectManager = new ObjectManager(ObjectFactory::produce);
sif::info << "Initializing all objects.." << std::endl;
objectManager->initialize();
/* This function creates and starts all tasks */
initTasks();
}
void InitMission::initTasks(){
/* TMTC Distribution */
PeriodicTaskIF* TmTcDistributor = TaskFactory::instance()->
createPeriodicTask("DIST", 40, PeriodicTaskIF::MINIMUM_STACK_SIZE,
0.100, nullptr);
ReturnValue_t result = TmTcDistributor->addComponent(
objects::CCSDS_PACKET_DISTRIBUTOR);
if(result!=HasReturnvaluesIF::RETURN_OK){
sif::error << "Object add component failed" << std::endl;
}
result = TmTcDistributor->addComponent(objects::PUS_PACKET_DISTRIBUTOR);
if(result!=HasReturnvaluesIF::RETURN_OK){
sif::error << "Object add component failed" << std::endl;
}
result = TmTcDistributor->addComponent(objects::TM_FUNNEL);
if(result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "Object add component failed" << std::endl;
}
/* UDP bridge */
PeriodicTaskIF* UdpBridgeTask = TaskFactory::instance()->createPeriodicTask(
"UDP_UNIX_BRIDGE", 50, PeriodicTaskIF::MINIMUM_STACK_SIZE,
0.2, nullptr);
result = UdpBridgeTask->addComponent(objects::UDP_BRIDGE);
if(result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "Add component UDP Unix Bridge failed" << std::endl;
}
PeriodicTaskIF* UdpPollingTask = TaskFactory::instance()->
createPeriodicTask("UDP_POLLING", 80,
PeriodicTaskIF::MINIMUM_STACK_SIZE, 2.0, nullptr);
result = UdpPollingTask->addComponent(objects::UDP_POLLING_TASK);
if(result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "Add component UDP Polling failed" << std::endl;
}
/* PUS Services */
PeriodicTaskIF* PusVerification = TaskFactory::instance()->
createPeriodicTask("PUS_VERIF_1", 40,
PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.200, nullptr);
result = PusVerification->addComponent(objects::PUS_SERVICE_1_VERIFICATION);
if(result != HasReturnvaluesIF::RETURN_OK){
sif::error << "Object add component failed" << std::endl;
}
PeriodicTaskIF* PusEvents = TaskFactory::instance()->
createPeriodicTask("PUS_VERIF_1", 60,
PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.200, nullptr);
result = PusVerification->addComponent(objects::PUS_SERVICE_5_EVENT_REPORTING);
if(result != HasReturnvaluesIF::RETURN_OK){
sif::error << "Object add component failed" << std::endl;
}
PeriodicTaskIF* PusHighPrio = TaskFactory::instance()->
createPeriodicTask("PUS_HIGH_PRIO", 50,
PeriodicTaskIF::MINIMUM_STACK_SIZE,
0.200, nullptr);
result = PusHighPrio->addComponent(objects::PUS_SERVICE_2_DEVICE_ACCESS);
if(result!=HasReturnvaluesIF::RETURN_OK){
sif::error << "Object add component failed" << std::endl;
}
result = PusHighPrio->addComponent(objects::PUS_SERVICE_9_TIME_MGMT);
if(result!=HasReturnvaluesIF::RETURN_OK){
sif::error << "Object add component failed" << std::endl;
}
PeriodicTaskIF* PusMedPrio = TaskFactory::instance()->
createPeriodicTask("PUS_HIGH_PRIO", 40,
PeriodicTaskIF::MINIMUM_STACK_SIZE,
0.8, nullptr);
result = PusMedPrio->addComponent(objects::PUS_SERVICE_8_FUNCTION_MGMT);
if(result!=HasReturnvaluesIF::RETURN_OK){
sif::error << "Object add component failed" << std::endl;
}
result = PusMedPrio->addComponent(objects::PUS_SERVICE_200_MODE_MGMT);
if(result!=HasReturnvaluesIF::RETURN_OK){
sif::error << "Object add component failed" << std::endl;
}
PeriodicTaskIF* PusLowPrio = TaskFactory::instance()->
createPeriodicTask("PUSB", 30, PeriodicTaskIF::MINIMUM_STACK_SIZE,
1.6, nullptr);
result = PusLowPrio->addComponent(objects::PUS_SERVICE_17_TEST);
if(result!=HasReturnvaluesIF::RETURN_OK){
sif::error << "Object add component failed" << std::endl;
}
#if ADD_TEST_CODE == 1
FixedTimeslotTaskIF* TestTimeslotTask = TaskFactory::instance()->
createFixedTimeslotTask("PST_TEST_TASK", 10,
PeriodicTaskIF::MINIMUM_STACK_SIZE, 1.0, nullptr);
result = pst::pollingSequenceTestFunction(TestTimeslotTask);
if(result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "InitMission::createTasks: Test PST initialization "
<< "failed!" << std::endl;
}
#endif
//Main thread sleep
sif::info << "Starting tasks.." << std::endl;
TmTcDistributor->startTask();
UdpBridgeTask->startTask();
UdpPollingTask->startTask();
PusVerification->startTask();
PusEvents->startTask();
PusHighPrio->startTask();
PusMedPrio->startTask();
PusLowPrio->startTask();
#if ADD_TEST_CODE == 1
TestTimeslotTask->startTask();
#endif
sif::info << "Tasks started.." << std::endl;
}

View File

@ -1,4 +0,0 @@
CXXSRC += $(wildcard $(CURRENTPATH)/*.cpp)
CSRC += $(wildcard $(CURRENTPATH)/*.c)
CSRC += $(wildcard $(CURRENTPATH)/boardconfig/*.c)

View File

@ -1,324 +0,0 @@
#include "ArduinoCookie.h"
#include "ArduinoComIF.h"
#include <fsfw/globalfunctions/DleEncoder.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <fsfw/globalfunctions/CRC.h>
#include <termios.h>
ArduinoCommInterface::ArduinoCommInterface(object_id_t setObjectId,
const char *serialDevice) :
spiMap(MAX_NUMBER_OF_SPI_DEVICES), rxBuffer(
MAX_PACKET_SIZE * MAX_NUMBER_OF_SPI_DEVICES*10, true), SystemObject(setObjectId) {
initialized = false;
serialPort = ::open("/dev/ttyUSB0", O_RDWR);
if (serialPort < 0) {
//configuration error
printf("Error %i from open: %s\n", errno, strerror(errno));
return;
}
struct termios tty;
memset(&tty, 0, sizeof tty);
// Read in existing settings, and handle any error
if (tcgetattr(serialPort, &tty) != 0) {
printf("Error %i from tcgetattr: %s\n", errno, strerror(errno));
return;
}
tty.c_cflag &= ~PARENB; // Clear parity bit, disabling parity
tty.c_cflag &= ~CSTOPB; // Clear stop field, only one stop bit used in communication
tty.c_cflag |= CS8; // 8 bits per byte
tty.c_cflag &= ~CRTSCTS; // Disable RTS/CTS hardware flow control
tty.c_lflag &= ~ICANON; //Disable Canonical Mode
tty.c_oflag &= ~OPOST; // Prevent special interpretation of output bytes (e.g. newline chars)
tty.c_oflag &= ~ONLCR; // Prevent conversion of newline to carriage return/line feed
tty.c_cc[VTIME] = 0; // Non Blocking
tty.c_cc[VMIN] = 0;
cfsetispeed(&tty, B9600); //Baudrate
if (tcsetattr(serialPort, TCSANOW, &tty) != 0) {
//printf("Error %i from tcsetattr: %s\n", errno, strerror(errno));
return;
}
initialized = true;
}
ArduinoCommInterface::~ArduinoCommInterface() {
::close(serialPort);
}
ReturnValue_t ArduinoCommInterface::open(Cookie **cookie, uint32_t address,
uint32_t maxReplyLen) {
//This is a hack, will be gone with https://egit.irs.uni-stuttgart.de/fsfw/fsfw/issues/19
switch ((address >> 8) & 0xff) {
case 0:
*cookie = new ArduinoCookie(ArduinoCookie::SPI, address, maxReplyLen);
spiMap.insert(address, (ArduinoCookie*) *cookie); //Yes, I *do* know that it is an ArduinoSpiCookie, I just new'd it
break;
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t ArduinoCommInterface::reOpen(Cookie *cookie, uint32_t address,
uint32_t maxReplyLen) {
//too lazy right now will be irrelevant with https://egit.irs.uni-stuttgart.de/fsfw/fsfw/issues/19
return HasReturnvaluesIF::RETURN_FAILED;
}
void ArduinoCommInterface::close(Cookie *cookie) {
//too lazy as well, find the correct Map, delete it there, then the cookie...
}
ReturnValue_t ArduinoCommInterface::sendMessage(Cookie *cookie, uint8_t *data,
uint32_t len) {
ArduinoCookie *arduinoCookie = dynamic_cast<ArduinoCookie*>(cookie);
if (arduinoCookie == NULL) {
return INVALID_COOKIE_TYPE;
}
return sendMessage(arduinoCookie->command, arduinoCookie->address, data,
len);
}
ReturnValue_t ArduinoCommInterface::getSendSuccess(Cookie *cookie) {
return RETURN_OK;
}
ReturnValue_t ArduinoCommInterface::requestReceiveMessage(Cookie *cookie) {
return RETURN_OK;
}
ReturnValue_t ArduinoCommInterface::readReceivedMessage(Cookie *cookie,
uint8_t **buffer, uint32_t *size) {
handleSerialPortRx();
ArduinoCookie *arduinoCookie = dynamic_cast<ArduinoCookie*>(cookie);
if (arduinoCookie == NULL) {
return INVALID_COOKIE_TYPE;
}
*buffer = arduinoCookie->replyBuffer;
*size = arduinoCookie->receivedDataLen;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t ArduinoCommInterface::setAddress(Cookie *cookie,
uint32_t address) {
//not implemented
return RETURN_FAILED;
}
uint32_t ArduinoCommInterface::getAddress(Cookie *cookie) {
//not implemented
return 0;
}
ReturnValue_t ArduinoCommInterface::setParameter(Cookie *cookie,
uint32_t parameter) {
//not implemented
return RETURN_FAILED;
}
uint32_t ArduinoCommInterface::getParameter(Cookie *cookie) {
//not implemented
return 0;
}
ReturnValue_t ArduinoCommInterface::sendMessage(uint8_t command,
uint8_t address, const uint8_t *data, size_t dataLen) {
if (dataLen > UINT16_MAX) {
return TOO_MUCH_DATA;
}
//being conservative here
uint8_t sendBuffer[(dataLen + 6) * 2 + 2];
sendBuffer[0] = DleEncoder::STX;
uint8_t *currentPosition = sendBuffer + 1;
size_t remainingLen = sizeof(sendBuffer) - 1;
uint32_t encodedLen;
ReturnValue_t result = DleEncoder::encode(&command, 1, currentPosition,
remainingLen, &encodedLen, false);
if (result != RETURN_OK) {
return result;
}
currentPosition += encodedLen;
remainingLen -= encodedLen; //DleEncoder will never return encodedLen > remainingLen
result = DleEncoder::encode(&address, 1, currentPosition, remainingLen,
&encodedLen, false);
if (result != RETURN_OK) {
return result;
}
currentPosition += encodedLen;
remainingLen -= encodedLen; //DleEncoder will never return encodedLen > remainingLen
uint8_t temporaryBuffer[2];
//note to Lukas: yes we _could_ use Serialize here, but for 16 bit it is a bit too much...
temporaryBuffer[0] = dataLen >> 8; //we checked dataLen above
temporaryBuffer[1] = dataLen;
result = DleEncoder::encode(temporaryBuffer, 2, currentPosition,
remainingLen, &encodedLen, false);
if (result != RETURN_OK) {
return result;
}
currentPosition += encodedLen;
remainingLen -= encodedLen; //DleEncoder will never return encodedLen > remainingLen
//encoding the actual data
result = DleEncoder::encode(data, dataLen, currentPosition, remainingLen,
&encodedLen, false);
if (result != RETURN_OK) {
return result;
}
currentPosition += encodedLen;
remainingLen -= encodedLen; //DleEncoder will never return encodedLen > remainingLen
uint16_t crc = CRC::crc16ccitt(&command, 1);
crc = CRC::crc16ccitt(&address, 1, crc);
//fortunately the length is still there
crc = CRC::crc16ccitt(temporaryBuffer, 2, crc);
crc = CRC::crc16ccitt(data, dataLen, crc);
temporaryBuffer[0] = crc >> 8;
temporaryBuffer[1] = crc;
result = DleEncoder::encode(temporaryBuffer, 2, currentPosition,
remainingLen, &encodedLen, false);
if (result != RETURN_OK) {
return result;
}
currentPosition += encodedLen;
remainingLen -= encodedLen; //DleEncoder will never return encodedLen > remainingLen
if (remainingLen > 0) {
*currentPosition = DleEncoder::ETX;
}
remainingLen -= 1;
encodedLen = sizeof(sendBuffer) - remainingLen;
ssize_t writtenlen = write(serialPort, sendBuffer, encodedLen);
if (writtenlen < 0) {
//we could try to find out what happened...
return RETURN_FAILED;
}
if (writtenlen != encodedLen) {
//the OS failed us, we do not try to block until everything is written, as
//we can not block the whole system here
return RETURN_FAILED;
}
return RETURN_OK;
}
void ArduinoCommInterface::handleSerialPortRx() {
uint32_t availableSpace = rxBuffer.availableWriteSpace();
uint8_t dataFromSerial[availableSpace];
ssize_t bytesRead = read(serialPort, dataFromSerial,
sizeof(dataFromSerial));
if (bytesRead < 0) {
return;
}
rxBuffer.writeData(dataFromSerial, bytesRead);
uint8_t dataReceivedSoFar[rxBuffer.maxSize()];
uint32_t dataLenReceivedSoFar = 0;
rxBuffer.readData(dataReceivedSoFar, sizeof(dataReceivedSoFar), true,
&dataLenReceivedSoFar);
//look for STX
size_t firstSTXinRawData = 0;
while ((firstSTXinRawData < dataLenReceivedSoFar)
&& (dataReceivedSoFar[firstSTXinRawData] != DleEncoder::STX)) {
firstSTXinRawData++;
}
if (dataReceivedSoFar[firstSTXinRawData] != DleEncoder::STX) {
//there is no STX in our data, throw it away...
rxBuffer.deleteData(dataLenReceivedSoFar);
return;
}
uint8_t packet[MAX_PACKET_SIZE];
uint32_t packetLen;
uint32_t readSize;
ReturnValue_t result = DleEncoder::decode(
dataReceivedSoFar + firstSTXinRawData,
dataLenReceivedSoFar - firstSTXinRawData, &readSize, packet,
sizeof(packet), &packetLen);
size_t toDelete = firstSTXinRawData;
if (result == HasReturnvaluesIF::RETURN_OK) {
handlePacket(packet, packetLen);
//after handling the packet, we can delete it from the raw stream, it has been copied to packet
toDelete += readSize;
}
//remove Data which was processed
rxBuffer.deleteData(toDelete);
}
void ArduinoCommInterface::handlePacket(uint8_t *packet, size_t packetLen) {
uint16_t crc = CRC::crc16ccitt(packet, packetLen);
if (crc != 0) {
//CRC error
return;
}
uint8_t command = packet[0];
uint8_t address = packet[1];
uint16_t size = (packet[2] << 8) + packet[3];
if (size != packetLen - 6) {
//Invalid Length
return;
}
switch (command) {
case ArduinoCookie::SPI: {
ArduinoCookie **itsComplicated;
ReturnValue_t result = spiMap.find(address, &itsComplicated);
if (result != RETURN_OK) {
//we do no know this address
return;
}
ArduinoCookie *theActualCookie = *itsComplicated;
if (packetLen > theActualCookie->maxReplySize + 6) {
packetLen = theActualCookie->maxReplySize + 6;
}
memcpy(theActualCookie->replyBuffer, packet + 4, packetLen - 6);
theActualCookie->receivedDataLen = packetLen - 6;
}
break;
default:
return;
}
}

View File

@ -1,73 +0,0 @@
//#ifndef MISSION_ARDUINOCOMMINTERFACE_H_
//#define MISSION_ARDUINOCOMMINTERFACE_H_
//
//#include <bits/stdint-uintn.h>
//#include <framework/container/FixedMap.h>
//#include <framework/container/SimpleRingBuffer.h>
//#include <framework/devicehandlers/DeviceCommunicationIF.h>
//#include <framework/returnvalues/HasReturnvaluesIF.h>
//#include <stddef.h>
//
//#include "../../framework/objectmanager/SystemObject.h"
//#include "ArduinoCookie.h"
//
////Forward declaration, so users don't peek
//class ArduinoCookie;
//
//class ArduinoComIF: public SystemObject,
// public DeviceCommunicationIF {
//public:
// static const uint8_t MAX_NUMBER_OF_SPI_DEVICES = 8;
// static const uint8_t MAX_PACKET_SIZE = 64;
//
// static const uint8_t COMMAND_INVALID = -1;
// static const uint8_t COMMAND_SPI = 1;
//
// ArduinoComIF(object_id_t setObjectId, const char *serialDevice);
// virtual ~ArduinoComIF();
//
// virtual ReturnValue_t open(Cookie **cookie, uint32_t address,
// uint32_t maxReplyLen);
//
// virtual ReturnValue_t reOpen(Cookie *cookie, uint32_t address,
// uint32_t maxReplyLen);
//
// virtual void close(Cookie *cookie);
//
// //SHOULDDO can data be const?
// virtual ReturnValue_t sendMessage(Cookie *cookie, uint8_t *data,
// uint32_t len);
//
// virtual ReturnValue_t getSendSuccess(Cookie *cookie);
//
// virtual ReturnValue_t requestReceiveMessage(Cookie *cookie);
//
// virtual ReturnValue_t readReceivedMessage(Cookie *cookie, uint8_t **buffer,
// uint32_t *size);
//
// virtual ReturnValue_t setAddress(Cookie *cookie, uint32_t address);
//
// virtual uint32_t getAddress(Cookie *cookie);
//
// virtual ReturnValue_t setParameter(Cookie *cookie, uint32_t parameter);
//
// virtual uint32_t getParameter(Cookie *cookie);
//private:
// //remembering if the initialization in the ctor worked
// //if not, all calls are disabled
// bool initialized;
// int serialPort;
// //used to know where to put the data if a reply is received
// FixedMap<uint8_t, ArduinoCookie*> spiMap;
//
// SimpleRingBuffer rxBuffer;
//
// ReturnValue_t sendMessage(uint8_t command, uint8_t address,
// const uint8_t *data, size_t dataLen);
//
// void handleSerialPortRx();
//
// void handlePacket(uint8_t *packet, size_t packetLen);
//};
//
//#endif /* MISSION_ARDUINOCOMMINTERFACE_H_ */

View File

@ -1,12 +0,0 @@
//#include <mission/Arduino/ArduinoCookie.h>
//
//ArduinoCookie::ArduinoCookie(Protocol_t protocol, uint8_t address,
// size_t maxReplySize) :
// command(protocol), address(address), receivedDataLen(0), maxReplySize(
// maxReplySize) {
// replyBuffer = new uint8_t[maxReplySize];
//}
//
//ArduinoCookie::~ArduinoCookie() {
// delete[] replyBuffer;
//}

View File

@ -1,25 +0,0 @@
//#ifndef MISSION_ARDUINO_ARDUINOCOOKIE_H_
//#define MISSION_ARDUINO_ARDUINOCOOKIE_H_
//
//#include <framework/devicehandlers/Cookie.h>
//
//#include <stdint.h>
//#include <stdlib.h>
//
//class ArduinoCookie: public Cookie {
//public:
// enum Protocol_t {
// INVALID = 0, SPI = 1
// };
// ArduinoCookie(Protocol_t protocol, uint8_t address, size_t maxReplySize);
// virtual ~ArduinoCookie();
//
// uint8_t command;
// uint8_t address;
// uint8_t *replyBuffer;
// size_t receivedDataLen;
// size_t maxReplySize;
//
//};
//
//#endif /* MISSION_ARDUINO_ARDUINOCOOKIE_H_ */

14
bsp_q7s/CMakeLists.txt Normal file
View File

@ -0,0 +1,14 @@
target_sources(${TARGET_NAME} PUBLIC
InitMission.cpp
main.cpp
ObjectFactory.cpp
)
add_subdirectory(boardconfig)
add_subdirectory(comIF)
add_subdirectory(devices)
add_subdirectory(boardtest)
add_subdirectory(gpio)

205
bsp_q7s/InitMission.cpp Normal file
View File

@ -0,0 +1,205 @@
#include "InitMission.h"
#include "ObjectFactory.h"
#include <OBSWConfig.h>
#include <mission/utility/InitMission.h>
#include <fsfw/objectmanager/ObjectManagerIF.h>
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
#include <fsfw/serviceinterface/ServiceInterfaceStream.h>
#include <fsfw/objectmanager/ObjectManager.h>
#include <fsfw/tasks/FixedTimeslotTaskIF.h>
#include <fsfw/tasks/PeriodicTaskIF.h>
#include <fsfw/tasks/TaskFactory.h>
#include <fsfwconfig/pollingsequence/pollingSequenceFactory.h>
#include <iostream>
/* This is configured for linux without CR */
#ifdef LINUX
ServiceInterfaceStream sif::debug("DEBUG");
ServiceInterfaceStream sif::info("INFO");
ServiceInterfaceStream sif::warning("WARNING");
ServiceInterfaceStream sif::error("ERROR", false, false, true);
#else
ServiceInterfaceStream sif::debug("DEBUG", true);
ServiceInterfaceStream sif::info("INFO", true);
ServiceInterfaceStream sif::warning("WARNING", true);
ServiceInterfaceStream sif::error("ERROR", true, false, true);
#endif
ObjectManagerIF *objectManager = nullptr;
void initmission::initMission() {
sif::info << "Building global objects.." << std::endl;
/* Instantiate global object manager and also create all objects */
objectManager = new ObjectManager(ObjectFactory::produce);
sif::info << "Initializing all objects.." << std::endl;
objectManager->initialize();
/* This function creates and starts all tasks */
initTasks();
}
void initmission::initTasks() {
TaskFactory* factory = TaskFactory::instance();
if(factory == nullptr) {
/* Should never happen ! */
return;
}
#if OBSW_PRINT_MISSED_DEADLINES == 1
void (*missedDeadlineFunc) (void) = TaskFactory::printMissedDeadline;
#else
void (*missedDeadlineFunc) (void) = nullptr;
#endif
/* TMTC Distribution */
PeriodicTaskIF* tmTcDistributor = factory->createPeriodicTask(
"DIST", 40, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.2, missedDeadlineFunc);
ReturnValue_t result = tmTcDistributor->addComponent(
objects::CCSDS_PACKET_DISTRIBUTOR);
if(result != HasReturnvaluesIF::RETURN_OK) {
initmission::printAddObjectError("CCSDS_DISTRIB", objects::CCSDS_PACKET_DISTRIBUTOR);
}
result = tmTcDistributor->addComponent(objects::PUS_PACKET_DISTRIBUTOR);
if(result != HasReturnvaluesIF::RETURN_OK) {
initmission::printAddObjectError("PUS_PACKET_DISTRIB", objects::PUS_PACKET_DISTRIBUTOR);
}
result = tmTcDistributor->addComponent(objects::TM_FUNNEL);
if(result != HasReturnvaluesIF::RETURN_OK) {
initmission::printAddObjectError("TM_FUNNEL", objects::TM_FUNNEL);
}
/* UDP bridge */
PeriodicTaskIF* udpBridgeTask = factory->createPeriodicTask(
"UDP_UNIX_BRIDGE", 50, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.2, missedDeadlineFunc);
result = udpBridgeTask->addComponent(objects::UDP_BRIDGE);
if(result != HasReturnvaluesIF::RETURN_OK) {
initmission::printAddObjectError("UDP_BRIDGE", objects::UDP_BRIDGE);
}
PeriodicTaskIF* udpPollingTask = factory->createPeriodicTask(
"UDP_POLLING", 80, PeriodicTaskIF::MINIMUM_STACK_SIZE, 2.0, missedDeadlineFunc);
result = udpPollingTask->addComponent(objects::UDP_POLLING_TASK);
if(result != HasReturnvaluesIF::RETURN_OK) {
initmission::printAddObjectError("UDP_POLLING", objects::UDP_POLLING_TASK);
}
/* PUS Services */
PeriodicTaskIF* pusVerification = factory->createPeriodicTask(
"PUS_VERIF", 40, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.200, missedDeadlineFunc);
result = pusVerification->addComponent(objects::PUS_SERVICE_1_VERIFICATION);
if(result != HasReturnvaluesIF::RETURN_OK) {
initmission::printAddObjectError("PUS_VERIF", objects::PUS_SERVICE_1_VERIFICATION);
}
PeriodicTaskIF* pusEvents = factory->createPeriodicTask(
"PUS_EVENTS", 60, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.200, missedDeadlineFunc);
result = pusVerification->addComponent(objects::PUS_SERVICE_5_EVENT_REPORTING);
if(result != HasReturnvaluesIF::RETURN_OK) {
initmission::printAddObjectError("PUS_EVENTS", objects::PUS_SERVICE_5_EVENT_REPORTING);
}
PeriodicTaskIF* pusHighPrio = factory->createPeriodicTask(
"PUS_HIGH_PRIO", 50, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.200, missedDeadlineFunc);
result = pusHighPrio->addComponent(objects::PUS_SERVICE_2_DEVICE_ACCESS);
if(result != HasReturnvaluesIF::RETURN_OK) {
initmission::printAddObjectError("PUS_2", objects::PUS_SERVICE_2_DEVICE_ACCESS);
}
result = pusHighPrio->addComponent(objects::PUS_SERVICE_9_TIME_MGMT);
if(result != HasReturnvaluesIF::RETURN_OK) {
initmission::printAddObjectError("PUS_9", objects::PUS_SERVICE_9_TIME_MGMT);
}
PeriodicTaskIF* pusMedPrio = factory->createPeriodicTask(
"PUS_MED_PRIO", 40, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.8, missedDeadlineFunc);
result = pusMedPrio->addComponent(objects::PUS_SERVICE_8_FUNCTION_MGMT);
if(result != HasReturnvaluesIF::RETURN_OK) {
initmission::printAddObjectError("PUS_8", objects::PUS_SERVICE_8_FUNCTION_MGMT);
}
result = pusMedPrio->addComponent(objects::PUS_SERVICE_3_HOUSEKEEPING);
if(result!=HasReturnvaluesIF::RETURN_OK){
sif::error << "Object add component failed" << std::endl;
}
result = pusMedPrio->addComponent(objects::PUS_SERVICE_200_MODE_MGMT);
if(result != HasReturnvaluesIF::RETURN_OK) {
initmission::printAddObjectError("PUS_200", objects::PUS_SERVICE_200_MODE_MGMT);
}
result = pusMedPrio->addComponent(objects::PUS_SERVICE_20_PARAMETERS);
if(result != HasReturnvaluesIF::RETURN_OK) {
initmission::printAddObjectError("PUS_20", objects::PUS_SERVICE_20_PARAMETERS);
}
PeriodicTaskIF* pusLowPrio = factory->createPeriodicTask(
"PUS_LOW_PRIO", 30, PeriodicTaskIF::MINIMUM_STACK_SIZE, 1.6, missedDeadlineFunc);
result = pusLowPrio->addComponent(objects::PUS_SERVICE_17_TEST);
if(result != HasReturnvaluesIF::RETURN_OK) {
initmission::printAddObjectError("PUS_17", objects::PUS_SERVICE_17_TEST);
}
//TODO: Add handling of missed deadlines
/* Polling Sequence Table Default */
#if Q7S_ADD_SPI_TEST == 0
FixedTimeslotTaskIF * pollingSequenceTableTaskDefault = factory->createFixedTimeslotTask(
"PST_TASK_DEFAULT", 50, PeriodicTaskIF::MINIMUM_STACK_SIZE * 4, 3.0,
missedDeadlineFunc);
result = pst::pollingSequenceInitDefault(pollingSequenceTableTaskDefault);
if (result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "InitMission::initTasks: Creating PST failed!" << std::endl;
}
#endif
#if TE0720 == 0
FixedTimeslotTaskIF* gomSpacePstTask = factory->
createFixedTimeslotTask("GS_PST_TASK", 50,
PeriodicTaskIF::MINIMUM_STACK_SIZE*8, 3.0, missedDeadlineFunc);
result = pst::gomspacePstInit(gomSpacePstTask);
if(result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "InitMission::initTasks: GomSpace PST initialization failed!" << std::endl;
}
#endif
#if OBSW_ADD_TEST_CODE == 1
PeriodicTaskIF* testTask = factory->createPeriodicTask(
"TEST_TASK", 60, PeriodicTaskIF::MINIMUM_STACK_SIZE, 1, missedDeadlineFunc);
result = testTask->addComponent(objects::TEST_TASK);
if(result != HasReturnvaluesIF::RETURN_OK) {
initmission::printAddObjectError("TEST_TASK", objects::TEST_TASK);
}
#if Q7S_ADD_SPI_TEST == 1
result = testTask->addComponent(objects::SPI_TEST);
if(result != HasReturnvaluesIF::RETURN_OK) {
initmission::printAddObjectError("SPI_TEST", objects::SPI_TEST);
}
#endif
#endif /* OBSW_ADD_TEST_CODE == 1 */
#if TE0720 == 1 && TEST_LIBGPIOD == 1
result = testTask->addComponent(objects::LIBGPIOD_TEST);
if(result != HasReturnvaluesIF::RETURN_OK) {
initmission::printAddObjectError("GPIOD_TEST", objects::LIBGPIOD_TEST);
}
#endif /* TE0720 == 1 && TEST_LIBGPIOD == 1 */
sif::info << "Starting tasks.." << std::endl;
tmTcDistributor->startTask();
udpBridgeTask->startTask();
udpPollingTask->startTask();
#if TE0720 == 0
gomSpacePstTask->startTask();
#endif
#if Q7S_ADD_SPI_TEST == 0
pollingSequenceTableTaskDefault->startTask();
#endif
pusVerification->startTask();
pusEvents->startTask();
pusHighPrio->startTask();
pusMedPrio->startTask();
pusLowPrio->startTask();
#if OBSW_ADD_TEST_CODE == 1
testTask->startTask();
#endif
sif::info << "Tasks started.." << std::endl;
}

9
bsp_q7s/InitMission.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef BSP_Q7S_INITMISSION_H_
#define BSP_Q7S_INITMISSION_H_
namespace initmission {
void initMission();
void initTasks();
};
#endif /* BSP_Q7S_INITMISSION_H_ */

439
bsp_q7s/ObjectFactory.cpp Normal file
View File

@ -0,0 +1,439 @@
#include "ObjectFactory.h"
#include <OBSWConfig.h>
#include <tmtc/apid.h>
#include <devices/addresses.h>
#include <devices/gpioIds.h>
#include <tmtc/pusIds.h>
#include <devices/powerSwitcherList.h>
#include <devices/spi.h>
#include <bsp_q7s/devices/HeaterHandler.h>
#include <bsp_q7s/devices/SolarArrayDeploymentHandler.h>
#include <bsp_q7s/gpio/gpioCallbacks.h>
#include <mission/core/GenericFactory.h>
#include <mission/devices/PDU1Handler.h>
#include <mission/devices/PDU2Handler.h>
#include <mission/devices/ACUHandler.h>
#include <mission/devices/PCDUHandler.h>
#include <mission/devices/P60DockHandler.h>
#include <mission/devices/Tmp1075Handler.h>
#include <mission/devices/Max31865PT1000Handler.h>
#include <mission/devices/IMTQHandler.h>
#include <mission/devices/devicedefinitions/Max31865Definitions.h>
#include <mission/devices/SyrlinksHkHandler.h>
#include <mission/devices/MGMHandlerLIS3MDL.h>
#include <mission/devices/MGMHandlerRM3100.h>
#include <mission/devices/GyroL3GD20Handler.h>
#include <mission/devices/devicedefinitions/GomspaceDefinitions.h>
#include <mission/devices/devicedefinitions/SyrlinksDefinitions.h>
#include <mission/utility/TmFunnel.h>
#include <linux/csp/CspCookie.h>
#include <linux/csp/CspComIF.h>
#include <linux/uart/UartComIF.h>
#include <linux/uart/UartCookie.h>
#include <fsfw_hal/linux/i2c/I2cCookie.h>
#include <fsfw_hal/linux/i2c/I2cComIF.h>
#include <fsfw_hal/linux/spi/SpiCookie.h>
#include <fsfw_hal/linux/spi/SpiComIF.h>
#include <fsfw_hal/linux/gpio/LinuxLibgpioIF.h>
#include <fsfw_hal/common/gpio/GpioCookie.h>
#include <fsfw/datapoollocal/LocalDataPoolManager.h>
#include <fsfw/tmtcservices/CommandingServiceBase.h>
#include <fsfw/tmtcservices/PusServiceBase.h>
#include <fsfw/tmtcpacket/pus/TmPacketStored.h>
/* UDP server includes */
#include <fsfw/osal/common/UdpTmTcBridge.h>
#include <fsfw/osal/common/UdpTcPollingTask.h>
#include <linux/boardtest/SpiTestClass.h>
#if TEST_LIBGPIOD == 1
#include <linux/boardtest/LibgpiodTest.h>
#endif
void Factory::setStaticFrameworkObjectIds() {
PusServiceBase::packetSource = objects::PUS_PACKET_DISTRIBUTOR;
PusServiceBase::packetDestination = objects::TM_FUNNEL;
CommandingServiceBase::defaultPacketSource = objects::PUS_PACKET_DISTRIBUTOR;
CommandingServiceBase::defaultPacketDestination = objects::TM_FUNNEL;
TmFunnel::downlinkDestination = objects::UDP_BRIDGE;
// No storage object for now.
TmFunnel::storageDestination = objects::NO_OBJECT;
LocalDataPoolManager::defaultHkDestination = objects::PUS_SERVICE_3_HOUSEKEEPING;
VerificationReporter::messageReceiver = objects::PUS_SERVICE_1_VERIFICATION;
TmPacketBase::timeStamperId = objects::TIME_STAMPER;
}
void ObjectFactory::produce(){
Factory::setStaticFrameworkObjectIds();
ObjectFactory::produceGenericObjects();
#if TE0720 == 1
I2cCookie* i2cCookieTmp1075tcs1 = new I2cCookie(addresses::TMP1075_TCS_1,
TMP1075::MAX_REPLY_LENGTH, std::string("/dev/i2c-0"));
I2cCookie* i2cCookieTmp1075tcs2 = new I2cCookie(addresses::TMP1075_TCS_2,
TMP1075::MAX_REPLY_LENGTH, std::string("/dev/i2c-0"));
#else
I2cCookie* i2cCookieTmp1075tcs1 = new I2cCookie(addresses::TMP1075_TCS_1,
TMP1075::MAX_REPLY_LENGTH, std::string("/dev/i2c-1"));
I2cCookie* i2cCookieTmp1075tcs2 = new I2cCookie(addresses::TMP1075_TCS_2,
TMP1075::MAX_REPLY_LENGTH, std::string("/dev/i2c-1"));
#endif
LinuxLibgpioIF* gpioComIF = new LinuxLibgpioIF(objects::GPIO_IF);
/* Communication interfaces */
new CspComIF(objects::CSP_COM_IF);
new I2cComIF(objects::I2C_COM_IF);
new UartComIF(objects::UART_COM_IF);
#if Q7S_ADD_SPI_TEST == 0
new SpiComIF(objects::SPI_COM_IF, gpioComIF);
#endif
/* Temperature sensors */
Tmp1075Handler* tmp1075Handler_1 = new Tmp1075Handler(
objects::TMP1075_HANDLER_1, objects::I2C_COM_IF,
i2cCookieTmp1075tcs1);
tmp1075Handler_1->setStartUpImmediately();
Tmp1075Handler* tmp1075Handler_2 = new Tmp1075Handler(
objects::TMP1075_HANDLER_2, objects::I2C_COM_IF,
i2cCookieTmp1075tcs2);
tmp1075Handler_2->setStartUpImmediately();
GpioCookie* heaterGpiosCookie = new GpioCookie;
#if TE0720 == 0
CspCookie* p60DockCspCookie = new CspCookie(P60Dock::MAX_REPLY_LENGTH,
addresses::P60DOCK);
CspCookie* pdu1CspCookie = new CspCookie(PDU::MAX_REPLY_LENGTH,
addresses::PDU1);
CspCookie* pdu2CspCookie = new CspCookie(PDU::MAX_REPLY_LENGTH,
addresses::PDU2);
CspCookie* acuCspCookie = new CspCookie(ACU::MAX_REPLY_LENGTH,
addresses::ACU);
/* Device Handler */
P60DockHandler* p60dockhandler = new P60DockHandler(objects::P60DOCK_HANDLER,
objects::CSP_COM_IF, p60DockCspCookie);
PDU1Handler* pdu1handler = new PDU1Handler(objects::PDU1_HANDLER,
objects::CSP_COM_IF, pdu1CspCookie);
PDU2Handler* pdu2handler = new PDU2Handler(objects::PDU2_HANDLER,
objects::CSP_COM_IF, pdu2CspCookie);
ACUHandler* acuhandler = new ACUHandler(objects::ACU_HANDLER,
objects::CSP_COM_IF, acuCspCookie);
new PCDUHandler(objects::PCDU_HANDLER, 50);
/**
* Setting PCDU devices to mode normal immediately after start up because PCDU is always
* running.
*/
/** For now this needs to be commented out because there is no PCDU connected to the OBC */
// p60dockhandler->setModeNormal();
// pdu1handler->setModeNormal();
// pdu2handler->setModeNormal();
// acuhandler->setModeNormal();
(void) p60dockhandler;
(void) pdu1handler;
(void) pdu2handler;
(void) acuhandler;
#if OBSW_ADD_ACS_BOARD == 1
GpioCookie* gpioCookieAcsBoard = new GpioCookie();
GpiodRegular* gpio = nullptr;
gpio = new GpiodRegular(std::string("gpiochip5"), 1, std::string("CS_GYRO_1_ADIS"),
gpio::OUT, gpio::HIGH);
gpioCookieAcsBoard->addGpio(gpioIds::GYRO_0_ADIS_CS, gpio);
gpio = new GpiodRegular(std::string("gpiochip5"), 7, std::string("CS_GYRO_2_L3G"),
gpio::OUT, gpio::HIGH);
gpioCookieAcsBoard->addGpio(gpioIds::GYRO_1_L3G_CS, gpio);
gpio = new GpiodRegular(std::string("gpiochip5"), 3, std::string("CS_GYRO_3_L3G"),
gpio::OUT, gpio::HIGH);
gpioCookieAcsBoard->addGpio(gpioIds::GYRO_2_L3G_CS, gpio);
gpio = new GpiodRegular(std::string("gpiochip5"), 5, std::string("CS_MGM_0_LIS3_A"),
gpio::OUT, gpio::HIGH);
gpioCookieAcsBoard->addGpio(gpioIds::MGM_0_LIS3_CS, gpio);
gpio = new GpiodRegular(std::string("gpiochip5"), 17, std::string("CS_MGM_1_RM3100_A"),
gpio::OUT, gpio::HIGH);
gpioCookieAcsBoard->addGpio(gpioIds::MGM_1_RM3100_CS, gpio);
gpio = new GpiodRegular(std::string("gpiochip6"), 0, std::string("CS_MGM_2_LIS3_B"),
gpio::OUT, gpio::HIGH);
gpioCookieAcsBoard->addGpio(gpioIds::MGM_2_LIS3_CS, gpio);
gpio = new GpiodRegular(std::string("gpiochip5"), 10, std::string("CS_MGM_3_RM3100_B"),
gpio::OUT, gpio::HIGH);
gpioCookieAcsBoard->addGpio(gpioIds::MGM_3_RM3100_CS, gpio);
gpioComIF->addGpios(gpioCookieAcsBoard);
std::string spiDev = "/dev/spidev2.0";
SpiCookie* spiCookie = new SpiCookie(addresses::MGM_0_LIS3, gpioIds::MGM_0_LIS3_CS, spiDev,
MGMLIS3MDL::MAX_BUFFER_SIZE, spi::DEFAULT_LIS3_MODE, spi::DEFAULT_LIS3_SPEED);
auto mgmLis3Handler = new MGMHandlerLIS3MDL(objects::MGM_0_LIS3_HANDLER,
objects::SPI_COM_IF, spiCookie);
mgmLis3Handler->setStartUpImmediately();
spiCookie = new SpiCookie(addresses::MGM_2_LIS3, gpioIds::MGM_2_LIS3_CS, spiDev,
MGMLIS3MDL::MAX_BUFFER_SIZE, spi::DEFAULT_LIS3_MODE, spi::DEFAULT_LIS3_SPEED);
auto mgmLis3Handler2 = new MGMHandlerLIS3MDL(objects::MGM_2_LIS3_HANDLER,
objects::SPI_COM_IF, spiCookie);
mgmLis3Handler2->setStartUpImmediately();
spiCookie = new SpiCookie(addresses::MGM_1_RM3100, gpioIds::MGM_1_RM3100_CS, spiDev,
RM3100::MAX_BUFFER_SIZE, spi::DEFAULT_RM3100_MODE, spi::DEFAULT_RM3100_SPEED);
auto mgmRm3100Handler = new MGMHandlerRM3100(objects::MGM_1_RM3100_HANDLER,
objects::SPI_COM_IF, spiCookie);
mgmRm3100Handler->setStartUpImmediately();
spiCookie = new SpiCookie(addresses::GYRO_1_L3G, gpioIds::GYRO_1_L3G_CS, spiDev,
L3GD20H::MAX_BUFFER_SIZE, spi::DEFAULT_L3G_MODE, spi::DEFAULT_L3G_SPEED);
auto gyroL3gHandler = new GyroHandlerL3GD20H(objects::GYRO_1_L3G_HANDLER, objects::SPI_COM_IF,
spiCookie);
gyroL3gHandler->setStartUpImmediately();
#endif
/* Pin H2-11 on stack connector */
GpiodRegular* gpioConfigHeater0 = new GpiodRegular(std::string("gpiochip7"), 6,
std::string("Heater0"), gpio::OUT, 0);
heaterGpiosCookie->addGpio(gpioIds::HEATER_0, gpioConfigHeater0);
/* Pin H2-12 on stack connector */
GpiodRegular* gpioConfigHeater1 = new GpiodRegular(std::string("gpiochip7"), 12,
std::string("Heater1"), gpio::OUT, 0);
heaterGpiosCookie->addGpio(gpioIds::HEATER_1, gpioConfigHeater1);
/* Pin H2-13 on stack connector */
GpiodRegular* gpioConfigHeater2 = new GpiodRegular(std::string("gpiochip7"), 7,
std::string("Heater2"), gpio::OUT, 0);
heaterGpiosCookie->addGpio(gpioIds::HEATER_2, gpioConfigHeater2);
GpiodRegular* gpioConfigHeater3 = new GpiodRegular(std::string("gpiochip7"), 5,
std::string("Heater3"), gpio::OUT, 0);
heaterGpiosCookie->addGpio(gpioIds::HEATER_3, gpioConfigHeater3);
GpiodRegular* gpioConfigHeater4 = new GpiodRegular(std::string("gpiochip7"), 3,
std::string("Heater4"), gpio::OUT, 0);
heaterGpiosCookie->addGpio(gpioIds::HEATER_4, gpioConfigHeater4);
GpiodRegular* gpioConfigHeater5 = new GpiodRegular(std::string("gpiochip7"), 0,
std::string("Heater5"), gpio::OUT, 0);
heaterGpiosCookie->addGpio(gpioIds::HEATER_5, gpioConfigHeater5);
GpiodRegular* gpioConfigHeater6 = new GpiodRegular(std::string("gpiochip7"), 1,
std::string("Heater6"), gpio::OUT, 0);
heaterGpiosCookie->addGpio(gpioIds::HEATER_6, gpioConfigHeater6);
GpiodRegular* gpioConfigHeater7 = new GpiodRegular(std::string("gpiochip7"), 11,
std::string("Heater7"), gpio::OUT, 0);
heaterGpiosCookie->addGpio(gpioIds::HEATER_7, gpioConfigHeater7);
new HeaterHandler(objects::HEATER_HANDLER, objects::GPIO_IF, heaterGpiosCookie,
objects::PCDU_HANDLER, pcduSwitches::TCS_BOARD_8V_HEATER_IN);
GpioCookie* solarArrayDeplCookie = new GpioCookie;
GpiodRegular* gpioConfigDeplSA0 = new GpiodRegular(std::string("gpiochip7"), 4,
std::string("DeplSA1"), gpio::OUT, 0);
solarArrayDeplCookie->addGpio(gpioIds::DEPLSA1, gpioConfigDeplSA0);
GpiodRegular* gpioConfigDeplSA1 = new GpiodRegular(std::string("gpiochip7"), 2,
std::string("DeplSA2"), gpio::OUT, 0);
solarArrayDeplCookie->addGpio(gpioIds::DEPLSA2, gpioConfigDeplSA1);
//TODO: Find out burn time. For now set to 1000 ms.
new SolarArrayDeploymentHandler(objects::SOLAR_ARRAY_DEPL_HANDLER, objects::GPIO_IF,
solarArrayDeplCookie, objects::PCDU_HANDLER, pcduSwitches::DEPLOYMENT_MECHANISM,
gpioIds::DEPLSA1, gpioIds::DEPLSA2, 1000);
UartCookie* syrlinksUartCookie = new UartCookie(
std::string("/dev/ttyUL0"), 38400, SYRLINKS::MAX_REPLY_SIZE);
syrlinksUartCookie->setParityEven();
SyrlinksHkHandler* syrlinksHkHandler = new SyrlinksHkHandler(objects::SYRLINKS_HK_HANDLER,
objects::UART_COM_IF, syrlinksUartCookie);
syrlinksHkHandler->setModeNormal();
#if Q7S_ADD_RTD_DEVICES == 1
GpioCookie* rtdGpioCookie = new GpioCookie;
gpioCallbacks::initTcsBoardDecoder(gpioComIF);
GpioCallback* gpioRtdIc3 = new GpioCallback(std::string("Chip select RTD IC3"), gpio::OUT, 1,
&gpioCallbacks::tcsBoardDecoderCallback, gpioComIF);
rtdGpioCookie->addGpio(gpioIds::RTD_IC3, gpioRtdIc3);
GpioCallback* gpioRtdIc4 = new GpioCallback(std::string("Chip select RTD IC4"), gpio::OUT, 1,
&gpioCallbacks::tcsBoardDecoderCallback, gpioComIF);
rtdGpioCookie->addGpio(gpioIds::RTD_IC4, gpioRtdIc4);
GpioCallback* gpioRtdIc5 = new GpioCallback(std::string("Chip select RTD IC5"), gpio::OUT, 1,
&gpioCallbacks::tcsBoardDecoderCallback, gpioComIF);
rtdGpioCookie->addGpio(gpioIds::RTD_IC5, gpioRtdIc5);
GpioCallback* gpioRtdIc6 = new GpioCallback(std::string("Chip select RTD IC6"), gpio::OUT, 1,
&gpioCallbacks::tcsBoardDecoderCallback, gpioComIF);
rtdGpioCookie->addGpio(gpioIds::RTD_IC6, gpioRtdIc6);
GpioCallback* gpioRtdIc7 = new GpioCallback(std::string("Chip select RTD IC7"), gpio::OUT, 1,
&gpioCallbacks::tcsBoardDecoderCallback, gpioComIF);
rtdGpioCookie->addGpio(gpioIds::RTD_IC7, gpioRtdIc7);
GpioCallback* gpioRtdIc8 = new GpioCallback(std::string("Chip select RTD IC8"), gpio::OUT, 1,
&gpioCallbacks::tcsBoardDecoderCallback, gpioComIF);
rtdGpioCookie->addGpio(gpioIds::RTD_IC8, gpioRtdIc8);
GpioCallback* gpioRtdIc9 = new GpioCallback(std::string("Chip select RTD IC9"), gpio::OUT, 1,
&gpioCallbacks::tcsBoardDecoderCallback, gpioComIF);
rtdGpioCookie->addGpio(gpioIds::RTD_IC9, gpioRtdIc9);
GpioCallback* gpioRtdIc10 = new GpioCallback(std::string("Chip select RTD IC10"), gpio::OUT, 1,
&gpioCallbacks::tcsBoardDecoderCallback, gpioComIF);
rtdGpioCookie->addGpio(gpioIds::RTD_IC10, gpioRtdIc10);
GpioCallback* gpioRtdIc11 = new GpioCallback(std::string("Chip select RTD IC11"), gpio::OUT, 1,
&gpioCallbacks::tcsBoardDecoderCallback, gpioComIF);
rtdGpioCookie->addGpio(gpioIds::RTD_IC11, gpioRtdIc11);
GpioCallback* gpioRtdIc12 = new GpioCallback(std::string("Chip select RTD IC12"), gpio::OUT, 1,
&gpioCallbacks::tcsBoardDecoderCallback, gpioComIF);
rtdGpioCookie->addGpio(gpioIds::RTD_IC12, gpioRtdIc12);
GpioCallback* gpioRtdIc13 = new GpioCallback(std::string("Chip select RTD IC13"), gpio::OUT, 1,
&gpioCallbacks::tcsBoardDecoderCallback, gpioComIF);
rtdGpioCookie->addGpio(gpioIds::RTD_IC13, gpioRtdIc13);
GpioCallback* gpioRtdIc14 = new GpioCallback(std::string("Chip select RTD IC14"), gpio::OUT, 1,
&gpioCallbacks::tcsBoardDecoderCallback, gpioComIF);
rtdGpioCookie->addGpio(gpioIds::RTD_IC14, gpioRtdIc14);
GpioCallback* gpioRtdIc15 = new GpioCallback(std::string("Chip select RTD IC15"), gpio::OUT, 1,
&gpioCallbacks::tcsBoardDecoderCallback, gpioComIF);
rtdGpioCookie->addGpio(gpioIds::RTD_IC15, gpioRtdIc15);
GpioCallback* gpioRtdIc16 = new GpioCallback(std::string("Chip select RTD IC16"), gpio::OUT, 1,
&gpioCallbacks::tcsBoardDecoderCallback, gpioComIF);
rtdGpioCookie->addGpio(gpioIds::RTD_IC16, gpioRtdIc16);
GpioCallback* gpioRtdIc17 = new GpioCallback(std::string("Chip select RTD IC17"), gpio::OUT, 1,
&gpioCallbacks::tcsBoardDecoderCallback, gpioComIF);
rtdGpioCookie->addGpio(gpioIds::RTD_IC17, gpioRtdIc17);
GpioCallback* gpioRtdIc18 = new GpioCallback(std::string("Chip select RTD IC18"), gpio::OUT, 1,
&gpioCallbacks::tcsBoardDecoderCallback, gpioComIF);
rtdGpioCookie->addGpio(gpioIds::RTD_IC18, gpioRtdIc18);
gpioComIF->addGpios(rtdGpioCookie);
SpiCookie* spiRtdIc3 = new SpiCookie(addresses::RTD_IC3, gpioIds::RTD_IC3,
std::string("/dev/spidev2.0"), Max31865Definitions::MAX_REPLY_SIZE,
spi::SpiModes::MODE_1, 2000000);
SpiCookie* spiRtdIc4 = new SpiCookie(addresses::RTD_IC4, gpioIds::RTD_IC4,
std::string("/dev/spidev2.0"), Max31865Definitions::MAX_REPLY_SIZE,
spi::SpiModes::MODE_1, 2000000);
SpiCookie* spiRtdIc5 = new SpiCookie(addresses::RTD_IC5, gpioIds::RTD_IC5,
std::string("/dev/spidev2.0"), Max31865Definitions::MAX_REPLY_SIZE,
spi::SpiModes::MODE_1, 2000000);
SpiCookie* spiRtdIc6 = new SpiCookie(addresses::RTD_IC6, gpioIds::RTD_IC6,
std::string("/dev/spidev2.0"), Max31865Definitions::MAX_REPLY_SIZE,
spi::SpiModes::MODE_1, 2000000);
SpiCookie* spiRtdIc7 = new SpiCookie(addresses::RTD_IC7, gpioIds::RTD_IC7,
std::string("/dev/spidev2.0"), Max31865Definitions::MAX_REPLY_SIZE,
spi::SpiModes::MODE_1, 2000000);
SpiCookie* spiRtdIc8 = new SpiCookie(addresses::RTD_IC8, gpioIds::RTD_IC8,
std::string("/dev/spidev2.0"), Max31865Definitions::MAX_REPLY_SIZE,
spi::SpiModes::MODE_1, 2000000);
SpiCookie* spiRtdIc9 = new SpiCookie(addresses::RTD_IC9, gpioIds::RTD_IC9,
std::string("/dev/spidev2.0"), Max31865Definitions::MAX_REPLY_SIZE,
spi::SpiModes::MODE_1, 2000000);
SpiCookie* spiRtdIc10 = new SpiCookie(addresses::RTD_IC10, gpioIds::RTD_IC10,
std::string("/dev/spidev2.0"), Max31865Definitions::MAX_REPLY_SIZE,
spi::SpiModes::MODE_1, 2000000);
SpiCookie* spiRtdIc11 = new SpiCookie(addresses::RTD_IC11, gpioIds::RTD_IC11,
std::string("/dev/spidev2.0"), Max31865Definitions::MAX_REPLY_SIZE,
spi::SpiModes::MODE_1, 2000000);
SpiCookie* spiRtdIc12 = new SpiCookie(addresses::RTD_IC12, gpioIds::RTD_IC12,
std::string("/dev/spidev2.0"), Max31865Definitions::MAX_REPLY_SIZE,
spi::SpiModes::MODE_1, 2000000);
SpiCookie* spiRtdIc13 = new SpiCookie(addresses::RTD_IC13, gpioIds::RTD_IC13,
std::string("/dev/spidev2.0"), Max31865Definitions::MAX_REPLY_SIZE,
spi::SpiModes::MODE_1, 2000000);
SpiCookie* spiRtdIc14 = new SpiCookie(addresses::RTD_IC14, gpioIds::RTD_IC14,
std::string("/dev/spidev2.0"), Max31865Definitions::MAX_REPLY_SIZE,
spi::SpiModes::MODE_1, 2000000);
SpiCookie* spiRtdIc15 = new SpiCookie(addresses::RTD_IC15, gpioIds::RTD_IC15,
std::string("/dev/spidev2.0"), Max31865Definitions::MAX_REPLY_SIZE,
spi::SpiModes::MODE_1, 2000000);
SpiCookie* spiRtdIc16 = new SpiCookie(addresses::RTD_IC16, gpioIds::RTD_IC16,
std::string("/dev/spidev2.0"), Max31865Definitions::MAX_REPLY_SIZE,
spi::SpiModes::MODE_1, 2000000);
SpiCookie* spiRtdIc17 = new SpiCookie(addresses::RTD_IC17, gpioIds::RTD_IC17,
std::string("/dev/spidev2.0"), Max31865Definitions::MAX_REPLY_SIZE,
spi::SpiModes::MODE_1, 2000000);
SpiCookie* spiRtdIc18 = new SpiCookie(addresses::RTD_IC18, gpioIds::RTD_IC18,
std::string("/dev/spidev2.0"), Max31865Definitions::MAX_REPLY_SIZE,
spi::SpiModes::MODE_1, 2000000);
Max31865PT1000Handler* rtdIc3 = new Max31865PT1000Handler(objects::RTD_IC3, objects::SPI_COM_IF, spiRtdIc3, 0); // 0 is switchId
Max31865PT1000Handler* rtdIc4 = new Max31865PT1000Handler(objects::RTD_IC4, objects::SPI_COM_IF, spiRtdIc4, 0);
Max31865PT1000Handler* rtdIc5 = new Max31865PT1000Handler(objects::RTD_IC5, objects::SPI_COM_IF, spiRtdIc5, 0);
Max31865PT1000Handler* rtdIc6 = new Max31865PT1000Handler(objects::RTD_IC6, objects::SPI_COM_IF, spiRtdIc6, 0);
Max31865PT1000Handler* rtdIc7 = new Max31865PT1000Handler(objects::RTD_IC7, objects::SPI_COM_IF, spiRtdIc7, 0);
Max31865PT1000Handler* rtdIc8 = new Max31865PT1000Handler(objects::RTD_IC8, objects::SPI_COM_IF, spiRtdIc8, 0);
Max31865PT1000Handler* rtdIc9 = new Max31865PT1000Handler(objects::RTD_IC9, objects::SPI_COM_IF, spiRtdIc9, 0);
Max31865PT1000Handler* rtdIc10 = new Max31865PT1000Handler(objects::RTD_IC10, objects::SPI_COM_IF, spiRtdIc10, 0);
Max31865PT1000Handler* rtdIc11 = new Max31865PT1000Handler(objects::RTD_IC11, objects::SPI_COM_IF, spiRtdIc11, 0);
Max31865PT1000Handler* rtdIc12 = new Max31865PT1000Handler(objects::RTD_IC12, objects::SPI_COM_IF, spiRtdIc12, 0);
Max31865PT1000Handler* rtdIc13 = new Max31865PT1000Handler(objects::RTD_IC13, objects::SPI_COM_IF, spiRtdIc13, 0);
Max31865PT1000Handler* rtdIc14 = new Max31865PT1000Handler(objects::RTD_IC14, objects::SPI_COM_IF, spiRtdIc14, 0);
Max31865PT1000Handler* rtdIc15 = new Max31865PT1000Handler(objects::RTD_IC15, objects::SPI_COM_IF, spiRtdIc15, 0);
Max31865PT1000Handler* rtdIc16 = new Max31865PT1000Handler(objects::RTD_IC16, objects::SPI_COM_IF, spiRtdIc16, 0);
Max31865PT1000Handler* rtdIc17 = new Max31865PT1000Handler(objects::RTD_IC17, objects::SPI_COM_IF, spiRtdIc17, 0);
Max31865PT1000Handler* rtdIc18 = new Max31865PT1000Handler(objects::RTD_IC18, objects::SPI_COM_IF, spiRtdIc18, 0);
// rtdIc10->setStartUpImmediately();
// rtdIc4->setStartUpImmediately();
(void) rtdIc3;
(void) rtdIc4;
(void) rtdIc5;
(void) rtdIc6;
(void) rtdIc7;
(void) rtdIc8;
(void) rtdIc9;
(void) rtdIc10;
(void) rtdIc11;
(void) rtdIc12;
(void) rtdIc13;
(void) rtdIc14;
(void) rtdIc15;
(void) rtdIc16;
(void) rtdIc17;
(void) rtdIc18;
#endif /* Q7S_ADD_RTD_DEVICES == 1 */
#endif /* TE0720 == 0 */
new UdpTmTcBridge(objects::UDP_BRIDGE, objects::CCSDS_PACKET_DISTRIBUTOR, objects::TM_STORE,
objects::TC_STORE);
new UdpTcPollingTask(objects::UDP_POLLING_TASK, objects::UDP_BRIDGE);
I2cCookie* imtqI2cCookie = new I2cCookie(addresses::IMTQ, IMTQ::MAX_REPLY_SIZE,
std::string("/dev/i2c-0"));
IMTQHandler* imtqHandler = new IMTQHandler(objects::IMTQ_HANDLER, objects::I2C_COM_IF, imtqI2cCookie);
imtqHandler->setStartUpImmediately();
#if TE0720 == 1 && TEST_LIBGPIOD == 1
/* Configure MIO0 as input */
GpiodRegular gpioConfigMio0(std::string("gpiochip0"), 0,
std::string("MIO0"), gpio::IN, 0);
GpioCookie* gpioCookie = new GpioCookie;
gpioCookie->addGpio(gpioIds::TEST_ID_0, gpioConfigMio0);
new LibgpiodTest(objects::LIBGPIOD_TEST, objects::GPIO_IF, gpioCookie);
#elif TE0720 == 1
/* Configuration for MIO0 on TE0720-03-1CFA */
GpiodRegular gpioConfigForDummyHeater(std::string("gpiochip0"), 0,
std::string("Heater0"), gpio::OUT, 0);
heaterGpiosCookie->addGpio(gpioIds::HEATER_0, gpioConfigForDummyHeater);
new HeaterHandler(objects::HEATER_HANDLER, objects::GPIO_IF, heaterGpiosCookie,
objects::PCDU_HANDLER, pcduSwitches::TCS_BOARD_8V_HEATER_IN);
#endif
#if Q7S_ADD_SPI_TEST == 1
new SpiTestClass(objects::SPI_TEST, gpioComIF);
#endif
}

9
bsp_q7s/ObjectFactory.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef BSP_Q7S_OBJECTFACTORY_H_
#define BSP_Q7S_OBJECTFACTORY_H_
namespace ObjectFactory {
void setStatics();
void produce();
};
#endif /* BSP_Q7S_OBJECTFACTORY_H_ */

View File

@ -0,0 +1,10 @@
target_sources(${TARGET_NAME} PRIVATE
print.c
)
target_include_directories(${TARGET_NAME} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
)

View File

@ -1,4 +1,4 @@
#include "print.h" #include <bsp_q7s/boardconfig/print.h>
#include <stdio.h> #include <stdio.h>
void printChar(const char* character, bool errStream) { void printChar(const char* character, bool errStream) {

View File

@ -0,0 +1,13 @@
#ifndef BSP_Q7S_BOARDCONFIG_Q7S_CONFIG_H_
#define BSP_Q7S_BOARDCONFIG_Q7S_CONFIG_H_
#define Q7S_ADD_RTD_DEVICES 0
/* Only one of those 2 should be enabled! */
/* Add code for ACS board */
#define OBSW_ADD_ACS_BOARD 0
#define Q7S_ADD_SPI_TEST 0
#endif /* BSP_Q7S_BOARDCONFIG_Q7S_CONFIG_H_ */

View File

@ -0,0 +1,6 @@
target_sources(${TARGET_NAME} PRIVATE
)

6
bsp_q7s/bsp_q7s.mk Normal file
View File

@ -0,0 +1,6 @@
CXXSRC += $(wildcard $(CURRENTPATH)/*.cpp)
CXXSRC += $(wildcard $(CURRENTPATH)/comIF/cookies/*.cpp)
CXXSRC += $(wildcard $(CURRENTPATH)/comIF/*.cpp)
CSRC += $(wildcard $(CURRENTPATH)/*.c)
CSRC += $(wildcard $(CURRENTPATH)/boardconfig/*.c)

View File

@ -0,0 +1,6 @@
target_sources(${TARGET_NAME} PRIVATE
)

View File

@ -0,0 +1,4 @@
target_sources(${TARGET_NAME} PRIVATE
HeaterHandler.cpp
SolarArrayDeploymentHandler.cpp
)

View File

@ -0,0 +1,370 @@
#include "HeaterHandler.h"
#include <fsfwconfig/devices/powerSwitcherList.h>
#include <fsfw/ipc/QueueFactory.h>
#include <devices/gpioIds.h>
#include <fsfw_hal/common/gpio/GpioCookie.h>
HeaterHandler::HeaterHandler(object_id_t setObjectId_, object_id_t gpioDriverId_,
CookieIF * gpioCookie_, object_id_t mainLineSwitcherObjectId_, uint8_t mainLineSwitch_) :
SystemObject(setObjectId_), gpioDriverId(gpioDriverId_), gpioCookie(gpioCookie_),
mainLineSwitcherObjectId(mainLineSwitcherObjectId_), mainLineSwitch(mainLineSwitch_),
actionHelper(this, nullptr) {
commandQueue = QueueFactory::instance()->createMessageQueue(cmdQueueSize,
MessageQueueMessage::MAX_MESSAGE_SIZE);
}
HeaterHandler::~HeaterHandler() {
}
ReturnValue_t HeaterHandler::performOperation(uint8_t operationCode) {
if (operationCode == DeviceHandlerIF::PERFORM_OPERATION) {
readCommandQueue();
handleActiveCommands();
return RETURN_OK;
}
return RETURN_OK;
}
ReturnValue_t HeaterHandler::initialize() {
ReturnValue_t result = SystemObject::initialize();
if (result != RETURN_OK) {
return ObjectManagerIF::CHILD_INIT_FAILED;
}
result = initializeHeaterMap();
if (result != RETURN_OK) {
return ObjectManagerIF::CHILD_INIT_FAILED;
}
gpioInterface = objectManager->get<GpioIF>(gpioDriverId);
if (gpioInterface == nullptr) {
sif::error << "HeaterHandler::initialize: Invalid Gpio interface." << std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
}
result = gpioInterface->addGpios(dynamic_cast<GpioCookie*>(gpioCookie));
if (result != RETURN_OK) {
sif::error << "HeaterHandler::initialize: Failed to initialize Gpio interface" << std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
}
IPCStore = objectManager->get<StorageManagerIF>(objects::IPC_STORE);
if (IPCStore == nullptr) {
sif::error << "HeaterHandler::initialize: IPC store not set up in factory." << std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
}
if(mainLineSwitcherObjectId != objects::NO_OBJECT) {
mainLineSwitcher = objectManager->get<PowerSwitchIF>(mainLineSwitcherObjectId);
if (mainLineSwitcher == nullptr) {
sif::error << "HeaterHandler::initialize: Main line switcher failed to fetch object"
<< "from object ID." << std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
}
}
result = actionHelper.initialize(commandQueue);
if (result != RETURN_OK) {
return ObjectManagerIF::CHILD_INIT_FAILED;
}
return RETURN_OK;
}
ReturnValue_t HeaterHandler::initializeHeaterMap(){
HeaterCommandInfo_t heaterCommandInfo;
for(switchNr_t switchNr = 0; switchNr < heaterSwitches::NUMBER_OF_SWITCHES; switchNr++) {
std::pair status = heaterMap.emplace(switchNr, heaterCommandInfo);
if (status.second == false) {
sif::error << "HeaterHandler::initializeHeaterMap: Failed to initialize heater map"
<< std::endl;
return RETURN_FAILED;
}
}
return RETURN_OK;
}
void HeaterHandler::setInitialSwitchStates() {
for (switchNr_t switchNr = 0; switchNr < heaterSwitches::NUMBER_OF_SWITCHES; switchNr++) {
switchStates[switchNr] = OFF;
}
}
void HeaterHandler::readCommandQueue() {
CommandMessage command;
ReturnValue_t result = commandQueue->receiveMessage(&command);
if (result != RETURN_OK) {
return;
}
result = actionHelper.handleActionMessage(&command);
if (result == RETURN_OK) {
return;
}
}
ReturnValue_t HeaterHandler::executeAction(ActionId_t actionId,
MessageQueueId_t commandedBy, const uint8_t* data, size_t size) {
ReturnValue_t result;
if (actionId != SWITCH_HEATER) {
result = COMMAND_NOT_SUPPORTED;
} else {
switchNr_t switchNr = *data;
HeaterMapIter heaterMapIter = heaterMap.find(switchNr);
if (heaterMapIter != heaterMap.end()) {
if (heaterMapIter->second.active) {
return COMMAND_ALREADY_WAITING;
}
heaterMapIter->second.action = *(data + 1);
heaterMapIter->second.active = true;
heaterMapIter->second.replyQueue = commandedBy;
}
else {
sif::error << "HeaterHandler::executeAction: Invalid switchNr" << std::endl;
return INVALID_SWITCH_NR;
}
result = RETURN_OK;
}
return result;
}
void HeaterHandler::sendSwitchCommand(uint8_t switchNr,
ReturnValue_t onOff) const {
ReturnValue_t result;
store_address_t storeAddress;
uint8_t commandData[2];
switch(onOff) {
case PowerSwitchIF::SWITCH_ON:
commandData[0] = switchNr;
commandData[1] = SET_SWITCH_ON;
break;
case PowerSwitchIF::SWITCH_OFF:
commandData[0] = switchNr;
commandData[1] = SET_SWITCH_OFF;
break;
default:
sif::error << "HeaterHandler::sendSwitchCommand: Invalid switch request"
<< std::endl;
break;
}
result = IPCStore->addData(&storeAddress, commandData, sizeof(commandData));
if (result == RETURN_OK) {
CommandMessage message;
ActionMessage::setCommand(&message, SWITCH_HEATER, storeAddress);
/* Send heater command to own command queue */
result = commandQueue->sendMessage(commandQueue->getId(), &message, 0);
if (result != RETURN_OK) {
sif::debug << "HeaterHandler::sendSwitchCommand: Failed to send switch"
<< "message" << std::endl;
}
}
}
void HeaterHandler::handleActiveCommands(){
HeaterMapIter heaterMapIter = heaterMap.begin();
for (; heaterMapIter != heaterMap.end(); heaterMapIter++) {
if (heaterMapIter->second.active) {
switch(heaterMapIter->second.action) {
case SET_SWITCH_ON:
handleSwitchOnCommand(heaterMapIter);
break;
case SET_SWITCH_OFF:
handleSwitchOffCommand(heaterMapIter);
break;
default:
sif::error << "HeaterHandler::handleActiveCommands: Invalid action commanded"
<< std::endl;
break;
}
}
}
}
void HeaterHandler::handleSwitchOnCommand(HeaterMapIter heaterMapIter) {
ReturnValue_t result = RETURN_OK;
switchNr_t switchNr;
/* Check if command waits for main switch being set on and whether the timeout has expired */
if (heaterMapIter->second.waitMainSwitchOn
&& heaterMapIter->second.mainSwitchCountdown.hasTimedOut()) {
//TODO - This requires the initiation of an FDIR procedure
triggerEvent(MAIN_SWITCH_TIMEOUT);
sif::error << "HeaterHandler::handleSwitchOnCommand: Main switch setting on timeout"
<< std::endl;
heaterMapIter->second.active = false;
heaterMapIter->second.waitMainSwitchOn = false;
if (heaterMapIter->second.replyQueue != commandQueue->getId()) {
actionHelper.finish(false, heaterMapIter->second.replyQueue,
heaterMapIter->second.action, MAIN_SWITCH_SET_TIMEOUT );
}
return;
}
switchNr = heaterMapIter->first;
/* Check state of main line switch */
ReturnValue_t mainSwitchState = mainLineSwitcher->getSwitchState(mainLineSwitch);
if (mainSwitchState == PowerSwitchIF::SWITCH_ON) {
if (!checkSwitchState(switchNr)) {
gpioId_t gpioId = getGpioIdFromSwitchNr(switchNr);
result = gpioInterface->pullHigh(gpioId);
if (result != RETURN_OK) {
sif::error << "HeaterHandler::handleSwitchOnCommand: Failed to pull gpio with id "
<< gpioId << " high" << std::endl;
triggerEvent(GPIO_PULL_HIGH_FAILED, result);
}
else {
switchStates[switchNr] = ON;
}
}
else {
triggerEvent(SWITCH_ALREADY_ON, switchNr);
}
/* There is no need to send action finish replies if the sender was the
* HeaterHandler itself. */
if (heaterMapIter->second.replyQueue != commandQueue->getId()) {
if(result == RETURN_OK) {
actionHelper.finish(true, heaterMapIter->second.replyQueue,
heaterMapIter->second.action, result);
}
else {
actionHelper.finish(false, heaterMapIter->second.replyQueue,
heaterMapIter->second.action, result);
}
}
heaterMapIter->second.active = false;
heaterMapIter->second.waitMainSwitchOn = false;
}
else if (mainSwitchState == PowerSwitchIF::SWITCH_OFF
&& heaterMapIter->second.waitMainSwitchOn) {
/* Just waiting for the main switch being set on */
return;
}
else if (mainSwitchState == PowerSwitchIF::SWITCH_OFF) {
mainLineSwitcher->sendSwitchCommand(mainLineSwitch,
PowerSwitchIF::SWITCH_ON);
heaterMapIter->second.mainSwitchCountdown.setTimeout(mainLineSwitcher->getSwitchDelayMs());
heaterMapIter->second.waitMainSwitchOn = true;
}
else {
sif::debug << "HeaterHandler::handleActiveCommands: Failed to get state of"
<< " main line switch" << std::endl;
if (heaterMapIter->second.replyQueue != commandQueue->getId()) {
actionHelper.finish(false, heaterMapIter->second.replyQueue,
heaterMapIter->second.action, mainSwitchState);
}
heaterMapIter->second.active = false;
}
}
void HeaterHandler::handleSwitchOffCommand(HeaterMapIter heaterMapIter) {
ReturnValue_t result = RETURN_OK;
switchNr_t switchNr = heaterMapIter->first;
/* Check whether switch is already off */
if (checkSwitchState(switchNr)) {
gpioId_t gpioId = getGpioIdFromSwitchNr(switchNr);
result = gpioInterface->pullLow(gpioId);
if (result != RETURN_OK) {
sif::error << "HeaterHandler::handleSwitchOffCommand: Failed to pull gpio with id"
<< gpioId << " low" << std::endl;
triggerEvent(GPIO_PULL_LOW_FAILED, result);
}
else {
switchStates[switchNr] = OFF;
/* When all switches are off, also main line switch will be turned off */
if (allSwitchesOff()) {
mainLineSwitcher->sendSwitchCommand(mainLineSwitch, PowerSwitchIF::SWITCH_OFF);
}
}
}
else {
sif::info << "HeaterHandler::handleSwitchOffCommand: Switch already off" << std::endl;
triggerEvent(SWITCH_ALREADY_OFF, switchNr);
}
if (heaterMapIter->second.replyQueue != NO_COMMANDER) {
/* Report back switch command reply if necessary */
if(result == HasReturnvaluesIF::RETURN_OK) {
actionHelper.finish(true, heaterMapIter->second.replyQueue,
heaterMapIter->second.action, result);
}
else {
actionHelper.finish(false, heaterMapIter->second.replyQueue,
heaterMapIter->second.action, result);
}
}
heaterMapIter->second.active = false;
}
bool HeaterHandler::checkSwitchState(int switchNr) {
return switchStates[switchNr];
}
bool HeaterHandler::allSwitchesOff() {
bool allSwitchesOrd = false;
/* Or all switches. As soon one switch is on, allSwitchesOrd will be true */
for (switchNr_t switchNr = 0; switchNr < heaterSwitches::NUMBER_OF_SWITCHES; switchNr++) {
allSwitchesOrd = allSwitchesOrd || switchStates[switchNr];
}
return !allSwitchesOrd;
}
gpioId_t HeaterHandler::getGpioIdFromSwitchNr(int switchNr) {
gpioId_t gpioId = 0xFFFF;
switch(switchNr) {
case heaterSwitches::HEATER_0:
gpioId = gpioIds::HEATER_0;
break;
case heaterSwitches::HEATER_1:
gpioId = gpioIds::HEATER_1;
break;
case heaterSwitches::HEATER_2:
gpioId = gpioIds::HEATER_2;
break;
case heaterSwitches::HEATER_3:
gpioId = gpioIds::HEATER_3;
break;
case heaterSwitches::HEATER_4:
gpioId = gpioIds::HEATER_4;
break;
case heaterSwitches::HEATER_5:
gpioId = gpioIds::HEATER_5;
break;
case heaterSwitches::HEATER_6:
gpioId = gpioIds::HEATER_6;
break;
case heaterSwitches::HEATER_7:
gpioId = gpioIds::HEATER_7;
break;
default:
sif::error << "HeaterHandler::getGpioIdFromSwitchNr: Unknown heater switch number"
<< std::endl;
break;
}
return gpioId;
}
MessageQueueId_t HeaterHandler::getCommandQueue() const {
return commandQueue->getId();
}
void HeaterHandler::sendFuseOnCommand(uint8_t fuseNr) const {
}
ReturnValue_t HeaterHandler::getSwitchState( uint8_t switchNr ) const {
return 0;
}
ReturnValue_t HeaterHandler::getFuseState( uint8_t fuseNr ) const {
return 0;
}
uint32_t HeaterHandler::getSwitchDelayMs(void) const {
return 0;
}

View File

@ -0,0 +1,177 @@
#ifndef MISSION_DEVICES_HEATERHANDLER_H_
#define MISSION_DEVICES_HEATERHANDLER_H_
#include <fsfw/objectmanager/SystemObject.h>
#include <fsfw/tasks/ExecutableObjectIF.h>
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
#include <fsfw/action/HasActionsIF.h>
#include <fsfw/power/PowerSwitchIF.h>
#include <fsfwconfig/devices/heaterSwitcherList.h>
#include <fsfw/devicehandlers/DeviceHandlerIF.h>
#include <fsfw/devicehandlers/CookieIF.h>
#include <fsfw/timemanager/Countdown.h>
#include <fsfw_hal/common/gpio/GpioIF.h>
#include <unordered_map>
/**
* @brief This class intends the control of heaters.
*
* @author J. Meier
*/
class HeaterHandler: public ExecutableObjectIF,
public PowerSwitchIF,
public SystemObject,
public HasActionsIF {
public:
/** Device command IDs */
static const DeviceCommandId_t SWITCH_HEATER = 0x0;
HeaterHandler(object_id_t setObjectId, object_id_t gpioDriverId, CookieIF * gpioCookie,
object_id_t mainLineSwitcherObjectId, uint8_t mainLineSwitch);
virtual ~HeaterHandler();
virtual ReturnValue_t performOperation(uint8_t operationCode = 0) override;
virtual void sendSwitchCommand(uint8_t switchNr, ReturnValue_t onOff) const override;
virtual void sendFuseOnCommand(uint8_t fuseNr) const override;
/**
* @brief This function will be called from the Heater object to check
* the current switch state.
*/
virtual ReturnValue_t getSwitchState( uint8_t switchNr ) const override;
virtual ReturnValue_t getFuseState( uint8_t fuseNr ) const override;
virtual uint32_t getSwitchDelayMs(void) const override;
virtual MessageQueueId_t getCommandQueue() const override;
virtual ReturnValue_t executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
const uint8_t* data, size_t size) override;
virtual ReturnValue_t initialize() override;
private:
static const uint8_t INTERFACE_ID = CLASS_ID::HEATER_HANDLER;
static const ReturnValue_t COMMAND_NOT_SUPPORTED = MAKE_RETURN_CODE(0xA1);
static const ReturnValue_t INIT_FAILED = MAKE_RETURN_CODE(0xA2);
static const ReturnValue_t INVALID_SWITCH_NR = MAKE_RETURN_CODE(0xA3);
static const ReturnValue_t MAIN_SWITCH_SET_TIMEOUT = MAKE_RETURN_CODE(0xA4);
static const ReturnValue_t COMMAND_ALREADY_WAITING = MAKE_RETURN_CODE(0xA5);
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::HEATER_HANDLER;
static const Event GPIO_PULL_HIGH_FAILED = MAKE_EVENT(0, severity::LOW);
static const Event GPIO_PULL_LOW_FAILED = MAKE_EVENT(1, severity::LOW);
static const Event SWITCH_ALREADY_ON = MAKE_EVENT(2, severity::LOW);
static const Event SWITCH_ALREADY_OFF = MAKE_EVENT(3, severity::LOW);
static const Event MAIN_SWITCH_TIMEOUT = MAKE_EVENT(4, severity::LOW);
static const MessageQueueId_t NO_COMMANDER = 0;
enum SwitchState : bool {
ON = true,
OFF = false
};
/**
* @brief Struct holding information about a heater command to execute.
*
* @param action The action to perform.
* @param replyQueue The queue of the commander to which status replies
* will be sent.
* @param active True if command is waiting for execution, otherwise false.
* @param waitSwitchOn True if the command is waiting for the main switch being set on.
* @param mainSwitchCountdown Sets timeout to wait for main switch being set on.
*/
typedef struct HeaterCommandInfo {
uint8_t action;
MessageQueueId_t replyQueue;
bool active = false;
bool waitMainSwitchOn = false;
Countdown mainSwitchCountdown;
} HeaterCommandInfo_t;
enum SwitchAction {
SET_SWITCH_OFF,
SET_SWITCH_ON
};
using switchNr_t = uint8_t;
using HeaterMap = std::unordered_map<switchNr_t, HeaterCommandInfo_t>;
using HeaterMapIter = HeaterMap::iterator;
HeaterMap heaterMap;
bool switchStates[heaterSwitches::NUMBER_OF_SWITCHES];
/** Size of command queue */
size_t cmdQueueSize = 20;
/**
* The object ID of the GPIO driver which enables and disables the
* heaters.
*/
object_id_t gpioDriverId;
CookieIF * gpioCookie;
GpioIF* gpioInterface = nullptr;
/** Queue to receive messages from other objects. */
MessageQueueIF* commandQueue = nullptr;
object_id_t mainLineSwitcherObjectId;
/** Switch number of the heater power supply switch */
uint8_t mainLineSwitch;
/**
* Power switcher object which controls the 8V main line of the heater
* logic on the TCS board.
*/
PowerSwitchIF *mainLineSwitcher = nullptr;
ActionHelper actionHelper;
StorageManagerIF *IPCStore = nullptr;
void readCommandQueue();
/**
* @brief Returns the state of a switch (ON - true, or OFF - false).
* @param switchNr The number of the switch to check.
*/
bool checkSwitchState(int switchNr);
/**
* @brief Returns the ID of the GPIO related to a heater identified by the switch number
* which is defined in the heaterSwitches list.
*/
gpioId_t getGpioIdFromSwitchNr(int switchNr);
/**
* @brief This function runs commands waiting for execution.
*/
void handleActiveCommands();
ReturnValue_t initializeHeaterMap();
/**
* @brief Sets all switches to OFF.
*/
void setInitialSwitchStates();
void handleSwitchOnCommand(HeaterMapIter heaterMapIter);
void handleSwitchOffCommand(HeaterMapIter heaterMapIter);
/**
* @brief Checks if all switches are off.
* @return True if all switches are off, otherwise false.
*/
bool allSwitchesOff();
};
#endif /* MISSION_DEVICES_HEATERHANDLER_H_ */

View File

@ -0,0 +1,201 @@
#include "SolarArrayDeploymentHandler.h"
#include <devices/powerSwitcherList.h>
#include <devices/gpioIds.h>
#include <fsfw_hal/common/gpio/GpioCookie.h>
#include <fsfw/ipc/QueueFactory.h>
SolarArrayDeploymentHandler::SolarArrayDeploymentHandler(object_id_t setObjectId_,
object_id_t gpioDriverId_, CookieIF * gpioCookie_, object_id_t mainLineSwitcherObjectId_,
uint8_t mainLineSwitch_, gpioId_t deplSA1, gpioId_t deplSA2, uint32_t burnTimeMs) :
SystemObject(setObjectId_), gpioDriverId(gpioDriverId_), gpioCookie(gpioCookie_),
mainLineSwitcherObjectId(mainLineSwitcherObjectId_), mainLineSwitch(mainLineSwitch_),
deplSA1(deplSA1), deplSA2(deplSA2), burnTimeMs(burnTimeMs), actionHelper(this, nullptr) {
commandQueue = QueueFactory::instance()->createMessageQueue(cmdQueueSize,
MessageQueueMessage::MAX_MESSAGE_SIZE);
}
SolarArrayDeploymentHandler::~SolarArrayDeploymentHandler() {
}
ReturnValue_t SolarArrayDeploymentHandler::performOperation(uint8_t operationCode) {
if (operationCode == DeviceHandlerIF::PERFORM_OPERATION) {
handleStateMachine();
return RETURN_OK;
}
return RETURN_OK;
}
ReturnValue_t SolarArrayDeploymentHandler::initialize() {
ReturnValue_t result = SystemObject::initialize();
if (result != RETURN_OK) {
return ObjectManagerIF::CHILD_INIT_FAILED;
}
gpioInterface = objectManager->get<GpioIF>(gpioDriverId);
if (gpioInterface == nullptr) {
sif::error << "SolarArrayDeploymentHandler::initialize: Invalid Gpio interface."
<< std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
}
result = gpioInterface->addGpios(dynamic_cast<GpioCookie*>(gpioCookie));
if (result != RETURN_OK) {
sif::error << "SolarArrayDeploymentHandler::initialize: Failed to initialize Gpio interface"
<< std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
}
if (mainLineSwitcherObjectId != objects::NO_OBJECT) {
mainLineSwitcher = objectManager->get<PowerSwitchIF>(mainLineSwitcherObjectId);
if (mainLineSwitcher == nullptr) {
sif::error
<< "SolarArrayDeploymentHandler::initialize: Main line switcher failed to fetch object"
<< "from object ID." << std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
}
}
result = actionHelper.initialize(commandQueue);
if (result != RETURN_OK) {
return ObjectManagerIF::CHILD_INIT_FAILED;
}
return RETURN_OK;
}
void SolarArrayDeploymentHandler::handleStateMachine() {
switch (stateMachine) {
case WAIT_ON_DELOYMENT_COMMAND:
readCommandQueue();
break;
case SWITCH_8V_ON:
mainLineSwitcher->sendSwitchCommand(mainLineSwitch, PowerSwitchIF::SWITCH_ON);
mainSwitchCountdown.setTimeout(mainLineSwitcher->getSwitchDelayMs());
stateMachine = WAIT_ON_8V_SWITCH;
break;
case WAIT_ON_8V_SWITCH:
performWaitOn8VActions();
break;
case SWITCH_DEPL_GPIOS:
switchDeploymentTransistors();
break;
case WAIT_ON_DEPLOYMENT_FINISH:
handleDeploymentFinish();
break;
case WAIT_FOR_MAIN_SWITCH_OFF:
if (mainLineSwitcher->getSwitchState(mainLineSwitch) == PowerSwitchIF::SWITCH_OFF) {
stateMachine = WAIT_ON_DELOYMENT_COMMAND;
} else if (mainSwitchCountdown.hasTimedOut()) {
triggerEvent(MAIN_SWITCH_OFF_TIMEOUT);
sif::error << "SolarArrayDeploymentHandler::handleStateMachine: Failed to switch main"
<< " switch off" << std::endl;
stateMachine = WAIT_ON_DELOYMENT_COMMAND;
}
break;
default:
sif::debug << "SolarArrayDeploymentHandler::handleStateMachine: Invalid state" << std::endl;
break;
}
}
void SolarArrayDeploymentHandler::performWaitOn8VActions() {
if (mainLineSwitcher->getSwitchState(mainLineSwitch) == PowerSwitchIF::SWITCH_ON) {
stateMachine = SWITCH_DEPL_GPIOS;
} else {
if (mainSwitchCountdown.hasTimedOut()) {
triggerEvent(MAIN_SWITCH_ON_TIMEOUT);
actionHelper.finish(false, rememberCommanderId, DEPLOY_SOLAR_ARRAYS,
MAIN_SWITCH_TIMEOUT_FAILURE);
stateMachine = WAIT_ON_DELOYMENT_COMMAND;
}
}
}
void SolarArrayDeploymentHandler::switchDeploymentTransistors() {
ReturnValue_t result = RETURN_OK;
result = gpioInterface->pullHigh(deplSA1);
if (result != RETURN_OK) {
sif::debug << "SolarArrayDeploymentHandler::handleStateMachine: Failed to pull solar"
" array deployment switch 1 high " << std::endl;
/* If gpio switch high failed, state machine is reset to wait for a command reinitiating
* the deployment sequence. */
stateMachine = WAIT_ON_DELOYMENT_COMMAND;
triggerEvent(DEPL_SA1_GPIO_SWTICH_ON_FAILED);
actionHelper.finish(false, rememberCommanderId, DEPLOY_SOLAR_ARRAYS,
SWITCHING_DEPL_SA2_FAILED);
mainLineSwitcher->sendSwitchCommand(mainLineSwitch, PowerSwitchIF::SWITCH_OFF);
}
result = gpioInterface->pullHigh(deplSA2);
if (result != RETURN_OK) {
sif::debug << "SolarArrayDeploymentHandler::handleStateMachine: Failed to pull solar"
" array deployment switch 2 high " << std::endl;
stateMachine = WAIT_ON_DELOYMENT_COMMAND;
triggerEvent(DEPL_SA2_GPIO_SWTICH_ON_FAILED);
actionHelper.finish(false, rememberCommanderId, DEPLOY_SOLAR_ARRAYS,
SWITCHING_DEPL_SA2_FAILED);
mainLineSwitcher->sendSwitchCommand(mainLineSwitch, PowerSwitchIF::SWITCH_OFF);
}
deploymentCountdown.setTimeout(burnTimeMs);
stateMachine = WAIT_ON_DEPLOYMENT_FINISH;
}
void SolarArrayDeploymentHandler::handleDeploymentFinish() {
ReturnValue_t result = RETURN_OK;
if (deploymentCountdown.hasTimedOut()) {
actionHelper.finish(true, rememberCommanderId, DEPLOY_SOLAR_ARRAYS, RETURN_OK);
result = gpioInterface->pullLow(deplSA1);
if (result != RETURN_OK) {
sif::debug << "SolarArrayDeploymentHandler::handleStateMachine: Failed to pull solar"
" array deployment switch 1 low " << std::endl;
}
result = gpioInterface->pullLow(deplSA2);
if (result != RETURN_OK) {
sif::debug << "SolarArrayDeploymentHandler::handleStateMachine: Failed to pull solar"
" array deployment switch 2 low " << std::endl;
}
mainLineSwitcher->sendSwitchCommand(mainLineSwitch, PowerSwitchIF::SWITCH_OFF);
mainSwitchCountdown.setTimeout(mainLineSwitcher->getSwitchDelayMs());
stateMachine = WAIT_FOR_MAIN_SWITCH_OFF;
}
}
void SolarArrayDeploymentHandler::readCommandQueue() {
CommandMessage command;
ReturnValue_t result = commandQueue->receiveMessage(&command);
if (result != RETURN_OK) {
return;
}
result = actionHelper.handleActionMessage(&command);
if (result == RETURN_OK) {
return;
}
}
ReturnValue_t SolarArrayDeploymentHandler::executeAction(ActionId_t actionId,
MessageQueueId_t commandedBy, const uint8_t* data, size_t size) {
ReturnValue_t result;
if (stateMachine != WAIT_ON_DELOYMENT_COMMAND) {
sif::error << "SolarArrayDeploymentHandler::executeAction: Received command while not in"
<< "waiting-on-command-state" << std::endl;
return DEPLOYMENT_ALREADY_EXECUTING;
}
if (actionId != DEPLOY_SOLAR_ARRAYS) {
sif::error << "SolarArrayDeploymentHandler::executeAction: Received invalid command"
<< std::endl;
result = COMMAND_NOT_SUPPORTED;
} else {
stateMachine = SWITCH_8V_ON;
rememberCommanderId = commandedBy;
result = RETURN_OK;
}
return result;
}
MessageQueueId_t SolarArrayDeploymentHandler::getCommandQueue() const {
return commandQueue->getId();
}

View File

@ -0,0 +1,158 @@
#ifndef MISSION_DEVICES_SOLARARRAYDEPLOYMENT_H_
#define MISSION_DEVICES_SOLARARRAYDEPLOYMENT_H_
#include <fsfw/objectmanager/SystemObject.h>
#include <fsfw/tasks/ExecutableObjectIF.h>
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
#include <fsfw/action/HasActionsIF.h>
#include <fsfw/power/PowerSwitchIF.h>
#include <fsfw/devicehandlers/CookieIF.h>
#include <fsfw/devicehandlers/DeviceHandlerIF.h>
#include <fsfw/timemanager/Countdown.h>
#include <fsfw_hal/common/gpio/GpioIF.h>
#include <unordered_map>
/**
* @brief This class is used to control the solar array deployment.
*
* @author J. Meier
*/
class SolarArrayDeploymentHandler: public ExecutableObjectIF,
public SystemObject,
public HasReturnvaluesIF,
public HasActionsIF {
public:
static const DeviceCommandId_t DEPLOY_SOLAR_ARRAYS = 0x5;
/**
* @brief constructor
*
* @param setObjectId The object id of the SolarArrayDeploymentHandler.
* @param gpioDriverId The id of the gpio com if.
* @param gpioCookie GpioCookie holding information about the gpios used to switch the
* transistors.
* @param mainLineSwitcherObjectId The object id of the object responsible for switching
* the 8V power source. This is normally the PCDU.
* @param mainLineSwitch The id of the main line switch. This is defined in
* powerSwitcherList.h.
* @param deplSA1 gpioId of the GPIO controlling the deployment 1 transistor.
* @param deplSA2 gpioId of the GPIO controlling the deployment 2 transistor.
* @param burnTimeMs Time duration the power will be applied to the burn wires.
*/
SolarArrayDeploymentHandler(object_id_t setObjectId, object_id_t gpioDriverId,
CookieIF * gpioCookie, object_id_t mainLineSwitcherObjectId, uint8_t mainLineSwitch,
gpioId_t deplSA1, gpioId_t deplSA2, uint32_t burnTimeMs);
virtual ~SolarArrayDeploymentHandler();
virtual ReturnValue_t performOperation(uint8_t operationCode = 0) override;
virtual MessageQueueId_t getCommandQueue() const override;
virtual ReturnValue_t executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
const uint8_t* data, size_t size) override;
virtual ReturnValue_t initialize() override;
private:
static const uint8_t INTERFACE_ID = CLASS_ID::SA_DEPL_HANDLER;
static const ReturnValue_t COMMAND_NOT_SUPPORTED = MAKE_RETURN_CODE(0xA0);
static const ReturnValue_t DEPLOYMENT_ALREADY_EXECUTING = MAKE_RETURN_CODE(0xA1);
static const ReturnValue_t MAIN_SWITCH_TIMEOUT_FAILURE = MAKE_RETURN_CODE(0xA2);
static const ReturnValue_t SWITCHING_DEPL_SA1_FAILED = MAKE_RETURN_CODE(0xA3);
static const ReturnValue_t SWITCHING_DEPL_SA2_FAILED = MAKE_RETURN_CODE(0xA4);
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::SA_DEPL_HANDLER;
static const Event MAIN_SWITCH_ON_TIMEOUT = MAKE_EVENT(0, severity::LOW);
static const Event MAIN_SWITCH_OFF_TIMEOUT = MAKE_EVENT(1, severity::LOW);
static const Event DEPLOYMENT_FAILED = MAKE_EVENT(2, severity::HIGH);
static const Event DEPL_SA1_GPIO_SWTICH_ON_FAILED = MAKE_EVENT(3, severity::HIGH);
static const Event DEPL_SA2_GPIO_SWTICH_ON_FAILED = MAKE_EVENT(4, severity::HIGH);
enum StateMachine {
WAIT_ON_DELOYMENT_COMMAND,
SWITCH_8V_ON,
WAIT_ON_8V_SWITCH,
SWITCH_DEPL_GPIOS,
WAIT_ON_DEPLOYMENT_FINISH,
WAIT_FOR_MAIN_SWITCH_OFF
};
StateMachine stateMachine = WAIT_ON_DELOYMENT_COMMAND;
/**
* This countdown is used to check if the PCDU sets the 8V line on in the intended time.
*/
Countdown mainSwitchCountdown;
/**
* This countdown is used to wait for the burn wire being successful cut.
*/
Countdown deploymentCountdown;
/**
* The message queue id of the component commanding an action will be stored in this variable.
* This is necessary to send later the action finish replies.
*/
MessageQueueId_t rememberCommanderId = 0;
/** Size of command queue */
size_t cmdQueueSize = 20;
/** The object ID of the GPIO driver which switches the deployment transistors */
object_id_t gpioDriverId;
CookieIF * gpioCookie;
/** Object id of the object responsible to switch the 8V power input. Typically the PCDU. */
object_id_t mainLineSwitcherObjectId;
/** Switch number of the 8V power switch */
uint8_t mainLineSwitch;
gpioId_t deplSA1;
gpioId_t deplSA2;
GpioIF* gpioInterface = nullptr;
/** Time duration switches are active to cut the burn wire */
uint32_t burnTimeMs;
/** Queue to receive messages from other objects. */
MessageQueueIF* commandQueue = nullptr;
/**
* After initialization this pointer will hold the reference to the main line switcher object.
*/
PowerSwitchIF *mainLineSwitcher = nullptr;
ActionHelper actionHelper;
void readCommandQueue();
/**
* @brief This function performs actions dependent on the current state.
*/
void handleStateMachine();
/**
* @brief This function polls the 8V switch state and changes the state machine when the
* switch has been enabled.
*/
void performWaitOn8VActions();
/**
* @brief This functions handles the switching of the solar array deployment transistors.
*/
void switchDeploymentTransistors();
/**
* @brief This function performs actions to finish the deployment. Essentially switches
* are turned of after the burn time has expired.
*/
void handleDeploymentFinish();
};
#endif /* MISSION_DEVICES_SOLARARRAYDEPLOYMENT_H_ */

View File

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

View File

@ -0,0 +1,221 @@
#include "gpioCallbacks.h"
#include <devices/gpioIds.h>
#include <fsfw_hal/linux/gpio/LinuxLibgpioIF.h>
#include <fsfw_hal/common/gpio/GpioCookie.h>
#include <fsfw/serviceinterface/ServiceInterface.h>
namespace gpioCallbacks {
GpioIF* gpioComInterface;
void initTcsBoardDecoder(GpioIF* gpioComIF) {
ReturnValue_t result;
if (gpioComIF == nullptr) {
sif::debug << "initTcsBoardDecoder: Invalid gpioComIF" << std::endl;
return;
}
gpioComInterface = gpioComIF;
GpioCookie* spiMuxGpios = new GpioCookie;
/**
* Initial values of the spi mux gpios can all be set to an arbitrary value expect for spi mux
* bit 1. Setting spi mux bit 1 to high will pull all decoder outputs to high voltage level.
*/
GpiodRegular* spiMuxBit1 = new GpiodRegular(std::string("gpiochip7"), 13,
std::string("SPI Mux Bit 1"), gpio::OUT, 1);
spiMuxGpios->addGpio(gpioIds::SPI_MUX_BIT_1, spiMuxBit1);
GpiodRegular* spiMuxBit2 = new GpiodRegular(std::string("gpiochip7"), 14,
std::string("SPI Mux Bit 2"), gpio::OUT, 0);
spiMuxGpios->addGpio(gpioIds::SPI_MUX_BIT_2, spiMuxBit2);
GpiodRegular* spiMuxBit3 = new GpiodRegular(std::string("gpiochip7"), 15,
std::string("SPI Mux Bit 3"), gpio::OUT, 0);
spiMuxGpios->addGpio(gpioIds::SPI_MUX_BIT_3, spiMuxBit3);
GpiodRegular* spiMuxBit4 = new GpiodRegular(std::string("gpiochip7"), 16,
std::string("SPI Mux Bit 4"), gpio::OUT, 0);
spiMuxGpios->addGpio(gpioIds::SPI_MUX_BIT_4, spiMuxBit4);
GpiodRegular* spiMuxBit5 = new GpiodRegular(std::string("gpiochip7"), 17,
std::string("SPI Mux Bit 5"), gpio::OUT, 0);
spiMuxGpios->addGpio(gpioIds::SPI_MUX_BIT_5, spiMuxBit5);
GpiodRegular* spiMuxBit6 = new GpiodRegular(std::string("gpiochip7"), 18,
std::string("SPI Mux Bit 6"), gpio::OUT, 0);
spiMuxGpios->addGpio(gpioIds::SPI_MUX_BIT_6, spiMuxBit6);
result = gpioComInterface->addGpios(spiMuxGpios);
if (result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "initTcsBoardDecoder: Failed to add mux bit gpios to gpioComIF"
<< std::endl;
return;
}
}
void tcsBoardDecoderCallback(gpioId_t gpioId, gpio::GpioOperation gpioOp, int value,
void* args) {
if (gpioComInterface == nullptr) {
sif::debug << "tcsBoardDecoderCallback: No gpioComIF specified. Call initTcsBoardDecoder "
<< "to specify gpioComIF" << std::endl;
return;
}
/* Read is not supported by the callback function */
if (gpioOp == gpio::GpioOperation::READ) {
return;
}
if (value == 1) {
/* This will pull all 16 decoder outputs to high */
gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_1);
}
else if (value == 0) {
switch (gpioId) {
case(gpioIds::RTD_IC3): {
gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_1);
gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_2);
gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_3);
gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_4);
gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_5);
gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_6);
break;
}
case(gpioIds::RTD_IC4): {
gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_1);
gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_2);
gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_3);
gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_4);
gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_5);
gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_6);
break;
}
case(gpioIds::RTD_IC5): {
gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_1);
gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_2);
gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_3);
gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_4);
gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_5);
gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_6);
break;
}
case(gpioIds::RTD_IC6): {
gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_1);
gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_2);
gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_3);
gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_4);
gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_5);
gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_6);
break;
}
case(gpioIds::RTD_IC7): {
gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_1);
gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_2);
gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_3);
gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_4);
gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_5);
gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_6);
break;
}
case(gpioIds::RTD_IC8): {
gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_1);
gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_2);
gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_3);
gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_4);
gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_5);
gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_6);
break;
}
case(gpioIds::RTD_IC9): {
gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_1);
gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_2);
gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_3);
gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_4);
gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_5);
gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_6);
break;
}
case(gpioIds::RTD_IC10): {
gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_1);
gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_2);
gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_3);
gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_4);
gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_5);
gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_6);
break;
}
case(gpioIds::RTD_IC11): {
gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_1);
gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_3);
gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_4);
gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_5);
gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_6);
break;
}
case(gpioIds::RTD_IC12): {
gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_1);
gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_3);
gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_4);
gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_5);
gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_6);
break;
}
case(gpioIds::RTD_IC13): {
gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_1);
gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_3);
gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_4);
gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_5);
gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_6);
break;
}
case(gpioIds::RTD_IC14): {
gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_1);
gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_3);
gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_4);
gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_5);
gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_6);
break;
}
case(gpioIds::RTD_IC15): {
gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_1);
gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_3);
gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_4);
gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_5);
gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_6);
break;
}
case(gpioIds::RTD_IC16): {
gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_1);
gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_3);
gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_4);
gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_5);
gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_6);
break;
}
case(gpioIds::RTD_IC17): {
gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_1);
gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_3);
gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_4);
gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_5);
gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_6);
break;
}
case(gpioIds::RTD_IC18): {
gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_1);
gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_3);
gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_4);
gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_5);
gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_6);
break;
}
default:
sif::debug << "tcsBoardDecoderCallback: Invalid gpioid " << gpioId << std::endl;
}
}
else {
sif::debug << "tcsBoardDecoderCallback: Invalid value. Must be 0 or 1" << std::endl;
}
}
}

View File

@ -0,0 +1,23 @@
#ifndef LINUX_GPIO_GPIOCALLBACKS_H_
#define LINUX_GPIO_GPIOCALLBACKS_H_
#include <fsfw_hal/common/gpio/gpioDefinitions.h>
#include <fsfw_hal/common/gpio/GpioIF.h>
namespace gpioCallbacks {
/**
* @brief This function initializes the GPIOs used to control the SN74LVC138APWR decoders on
* the TCS Board.
*/
void initTcsBoardDecoder(GpioIF* gpioComIF);
/**
* @brief This function implements the decoding to multiply gpios by using the two decoder
* chips SN74LVC138APWR on the TCS board.
*/
void tcsBoardDecoderCallback(gpioId_t gpioId, gpio::GpioOperation gpioOp, int value, void* args);
}
#endif /* LINUX_GPIO_GPIOCALLBACKS_H_ */

View File

@ -1,5 +1,4 @@
#include "InitMission.h" #include "InitMission.h"
#include <OBSWVersion.h> #include <OBSWVersion.h>
#include <fsfw/tasks/TaskFactory.h> #include <fsfw/tasks/TaskFactory.h>
@ -14,15 +13,15 @@
int main(void) int main(void)
{ {
std::cout << "-- EIVE OBSW --" << std::endl; std::cout << "-- EIVE OBSW --" << std::endl;
std::cout << "-- Compiled for Linux " << " --" << std::endl; std::cout << "-- Compiled for Linux (Xiphos Q7S) --" << std::endl;
std::cout << "-- Software version " << SW_NAME << " v" << SW_VERSION << "." std::cout << "-- Software version " << SW_NAME << " v" << SW_VERSION << "."
<< SW_SUBVERSION << "." << SW_SUBSUBVERSION << " -- " << std::endl; << SW_SUBVERSION << "." << SW_SUBSUBVERSION << " -- " << std::endl;
std::cout << "-- " << __DATE__ << " " << __TIME__ << " --" << std::endl; std::cout << "-- " << __DATE__ << " " << __TIME__ << " --" << std::endl;
InitMission::initMission(); initmission::initMission();
for(;;) { for(;;) {
// suspend main thread by sleeping it. /* Suspend main thread by sleeping it. */
TaskFactory::delayTask(5000); TaskFactory::delayTask(5000);
} }
} }

14
bsp_rpi/CMakeLists.txt Normal file
View File

@ -0,0 +1,14 @@
target_sources(${TARGET_NAME} PUBLIC
InitMission.cpp
main.cpp
ObjectFactory.cpp
)
add_subdirectory(boardconfig)
add_subdirectory(boardtest)
add_subdirectory(gpio)

177
bsp_rpi/InitMission.cpp Normal file
View File

@ -0,0 +1,177 @@
#include "InitMission.h"
#include "ObjectFactory.h"
#include <fsfwconfig/objects/systemObjectList.h>
#include <fsfwconfig/OBSWConfig.h>
#include <fsfwconfig/pollingsequence/pollingSequenceFactory.h>
#include <mission/utility/InitMission.h>
#include <fsfw/objectmanager/ObjectManagerIF.h>
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
#include <fsfw/serviceinterface/ServiceInterface.h>
#include <fsfw/objectmanager/ObjectManager.h>
#include <fsfw/tasks/FixedTimeslotTaskIF.h>
#include <fsfw/tasks/PeriodicTaskIF.h>
#include <fsfw/tasks/TaskFactory.h>
#include <iostream>
ServiceInterfaceStream sif::debug("DEBUG");
ServiceInterfaceStream sif::info("INFO");
ServiceInterfaceStream sif::warning("WARNING");
ServiceInterfaceStream sif::error("ERROR");
ObjectManagerIF *objectManager = nullptr;
void initmission::initMission() {
sif::info << "Building global objects.." << std::endl;
/* Instantiate global object manager and also create all objects */
objectManager = new ObjectManager(ObjectFactory::produce);
sif::info << "Initializing all objects.." << std::endl;
objectManager->initialize();
/* This function creates and starts all tasks */
initTasks();
}
void initmission::initTasks() {
TaskFactory* factory = TaskFactory::instance();
if(factory == nullptr) {
/* Should never happen ! */
return;
}
#if OBSW_PRINT_MISSED_DEADLINES == 1
void (*missedDeadlineFunc) (void) = TaskFactory::printMissedDeadline;
#else
void (*missedDeadlineFunc) (void) = nullptr;
#endif
/* TMTC Distribution */
PeriodicTaskIF* tmTcDistributor = factory->createPeriodicTask(
"DIST", 40, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.2, missedDeadlineFunc);
ReturnValue_t result = tmTcDistributor->addComponent(
objects::CCSDS_PACKET_DISTRIBUTOR);
if(result != HasReturnvaluesIF::RETURN_OK){
sif::error << "Object add component failed" << std::endl;
}
result = tmTcDistributor->addComponent(objects::PUS_PACKET_DISTRIBUTOR);
if(result != HasReturnvaluesIF::RETURN_OK){
sif::error << "Object add component failed" << std::endl;
}
result = tmTcDistributor->addComponent(objects::TM_FUNNEL);
if(result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "Object add component failed" << std::endl;
}
/* UDP bridge */
PeriodicTaskIF* udpBridgeTask = factory->createPeriodicTask(
"UDP_UNIX_BRIDGE", 50, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.2, missedDeadlineFunc);
result = udpBridgeTask->addComponent(objects::UDP_BRIDGE);
if(result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "Add component UDP Unix Bridge failed" << std::endl;
}
PeriodicTaskIF* udpPollingTask = factory->createPeriodicTask(
"UDP_POLLING", 80, PeriodicTaskIF::MINIMUM_STACK_SIZE, 2.0, missedDeadlineFunc);
result = udpPollingTask->addComponent(objects::UDP_POLLING_TASK);
if(result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "Add component UDP Polling failed" << std::endl;
}
/* PUS Services */
PeriodicTaskIF* pusVerification = factory->createPeriodicTask(
"PUS_VERIF", 40, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.200, missedDeadlineFunc);
result = pusVerification->addComponent(objects::PUS_SERVICE_1_VERIFICATION);
if(result != HasReturnvaluesIF::RETURN_OK){
sif::error << "Object add component failed" << std::endl;
}
PeriodicTaskIF* pusEvents = factory->createPeriodicTask(
"PUS_EVENTS", 60, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.200, missedDeadlineFunc);
result = pusVerification->addComponent(objects::PUS_SERVICE_5_EVENT_REPORTING);
if(result != HasReturnvaluesIF::RETURN_OK){
initmission::printAddObjectError("PUS5", objects::PUS_SERVICE_5_EVENT_REPORTING);
}
PeriodicTaskIF* pusHighPrio = factory->createPeriodicTask(
"PUS_HIGH_PRIO", 50, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.200, missedDeadlineFunc);
result = pusHighPrio->addComponent(objects::PUS_SERVICE_2_DEVICE_ACCESS);
if(result != HasReturnvaluesIF::RETURN_OK) {
initmission::printAddObjectError("PUS2", objects::PUS_SERVICE_2_DEVICE_ACCESS);
}
result = pusHighPrio->addComponent(objects::PUS_SERVICE_9_TIME_MGMT);
if(result != HasReturnvaluesIF::RETURN_OK) {
initmission::printAddObjectError("PUS9", objects::PUS_SERVICE_9_TIME_MGMT);
}
PeriodicTaskIF* pusMedPrio = factory->createPeriodicTask(
"PUS_MED_PRIO", 40, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.8, missedDeadlineFunc);
result = pusMedPrio->addComponent(objects::PUS_SERVICE_8_FUNCTION_MGMT);
if(result != HasReturnvaluesIF::RETURN_OK) {
initmission::printAddObjectError("PUS8", objects::PUS_SERVICE_8_FUNCTION_MGMT);
}
result = pusMedPrio->addComponent(objects::PUS_SERVICE_200_MODE_MGMT);
if(result != HasReturnvaluesIF::RETURN_OK) {
initmission::printAddObjectError("PUS200", objects::PUS_SERVICE_200_MODE_MGMT);
}
result = pusMedPrio->addComponent(objects::PUS_SERVICE_20_PARAMETERS);
if(result != HasReturnvaluesIF::RETURN_OK) {
initmission::printAddObjectError("PUS20", objects::PUS_SERVICE_20_PARAMETERS);
}
PeriodicTaskIF* pusLowPrio = factory->createPeriodicTask(
"PUS_LOW_PRIO", 30, PeriodicTaskIF::MINIMUM_STACK_SIZE, 1.6, missedDeadlineFunc);
result = pusLowPrio->addComponent(objects::PUS_SERVICE_17_TEST);
if(result != HasReturnvaluesIF::RETURN_OK) {
initmission::printAddObjectError("PUS17", objects::PUS_SERVICE_17_TEST);
}
#if RPI_TEST_ACS_BOARD == 1
FixedTimeslotTaskIF* acsTask = factory->createFixedTimeslotTask(
"ACS_PST", 50, PeriodicTaskIF::MINIMUM_STACK_SIZE * 2, 2.0, missedDeadlineFunc);
result = pst::pollingSequenceAcsTest(acsTask);
if(result != HasReturnvaluesIF::RETURN_OK) {
sif::warning << "initmission::initTasks: ACS PST initialization failed!" << std::endl;
}
#endif /* RPI_TEST_ACS_BOARD == 1 */
PeriodicTaskIF* testTask = factory->createPeriodicTask(
"TEST_TASK", 40, PeriodicTaskIF::MINIMUM_STACK_SIZE, 2.0, missedDeadlineFunc);
#if OBSW_ADD_TEST_CODE == 1
result = testTask->addComponent(objects::TEST_TASK);
if(result != HasReturnvaluesIF::RETURN_OK) {
initmission::printAddObjectError("TEST_TASK", objects::TEST_TASK);
}
#endif /* OBSW_ADD_TEST_CODE == 1 */
#if RPI_ADD_SPI_TEST == 1
result = testTask->addComponent(objects::SPI_TEST);
if(result != HasReturnvaluesIF::RETURN_OK) {
initmission::printAddObjectError("SPI_TEST", objects::SPI_TEST);
}
#endif /* RPI_ADD_SPI_TEST == 1 */
#if RPI_ADD_GPIO_TEST == 1
result = testTask->addComponent(objects::LIBGPIOD_TEST);
if(result != HasReturnvaluesIF::RETURN_OK) {
initmission::printAddObjectError("GPIOD_TEST", objects::LIBGPIOD_TEST);
}
#endif /* RPI_ADD_GPIO_TEST == 1 */
sif::info << "Starting tasks.." << std::endl;
tmTcDistributor->startTask();
udpBridgeTask->startTask();
udpPollingTask->startTask();
pusVerification->startTask();
pusEvents->startTask();
pusHighPrio->startTask();
pusMedPrio->startTask();
pusLowPrio->startTask();
#if OBSW_ADD_TEST_CODE == 1
testTask->startTask();
#endif /* OBSW_ADD_TEST_CODE == 1 */
#if RPI_TEST_ACS_BOARD == 1
acsTask->startTask();
#endif /* RPI_TEST_ACS_BOARD == 1 */
sif::info << "Tasks started.." << std::endl;
}

View File

@ -1,7 +1,7 @@
#ifndef BSP_LINUX_INITMISSION_H_ #ifndef BSP_LINUX_INITMISSION_H_
#define BSP_LINUX_INITMISSION_H_ #define BSP_LINUX_INITMISSION_H_
namespace InitMission { namespace initmission {
void initMission(); void initMission();
void initTasks(); void initTasks();
}; };

125
bsp_rpi/ObjectFactory.cpp Normal file
View File

@ -0,0 +1,125 @@
#include "ObjectFactory.h"
#include <fsfwconfig/objects/systemObjectList.h>
#include <fsfwconfig/devices/addresses.h>
#include <fsfwconfig/devices/gpioIds.h>
#include <fsfwconfig/OBSWConfig.h>
#include <fsfwconfig/tmtc/apid.h>
#include <fsfwconfig/tmtc/pusIds.h>
#include <fsfwconfig/devices/spi.h>
#include <linux/boardtest/LibgpiodTest.h>
#include <linux/boardtest/SpiTestClass.h>
#include <mission/devices/GyroL3GD20Handler.h>
#include <mission/core/GenericFactory.h>
#include <mission/utility/TmFunnel.h>
#include <mission/devices/MGMHandlerLIS3MDL.h>
#include <mission/devices/MGMHandlerRM3100.h>
#include <fsfw/datapoollocal/LocalDataPoolManager.h>
#include <fsfw/tmtcservices/CommandingServiceBase.h>
#include <fsfw/tmtcservices/PusServiceBase.h>
#include <fsfw/tmtcpacket/pus/TmPacketStored.h>
#include <fsfw/tasks/TaskFactory.h>
/* UDP server includes */
#include <fsfw/osal/common/UdpTmTcBridge.h>
#include <fsfw/osal/common/UdpTcPollingTask.h>
#include <fsfw_hal/linux/gpio/LinuxLibgpioIF.h>
#include <fsfw_hal/linux/rpi/GpioRPi.h>
#include <fsfw_hal/common/gpio/GpioCookie.h>
#include <fsfw_hal/linux/spi/SpiCookie.h>
#include <fsfw_hal/linux/spi/SpiComIF.h>
void Factory::setStaticFrameworkObjectIds() {
PusServiceBase::packetSource = objects::PUS_PACKET_DISTRIBUTOR;
PusServiceBase::packetDestination = objects::TM_FUNNEL;
CommandingServiceBase::defaultPacketSource = objects::PUS_PACKET_DISTRIBUTOR;
CommandingServiceBase::defaultPacketDestination = objects::TM_FUNNEL;
TmFunnel::downlinkDestination = objects::UDP_BRIDGE;
// No storage object for now.
TmFunnel::storageDestination = objects::NO_OBJECT;
LocalDataPoolManager::defaultHkDestination = objects::NO_OBJECT;
VerificationReporter::messageReceiver = objects::PUS_SERVICE_1_VERIFICATION;
TmPacketStored::timeStamperId = objects::TIME_STAMPER;
}
void ObjectFactory::produce(){
Factory::setStaticFrameworkObjectIds();
ObjectFactory::produceGenericObjects();
new UdpTmTcBridge(objects::UDP_BRIDGE,
objects::CCSDS_PACKET_DISTRIBUTOR,
objects::TM_STORE, objects::TC_STORE);
new UdpTcPollingTask(objects::UDP_POLLING_TASK, objects::UDP_BRIDGE);
GpioIF* gpioIF = new LinuxLibgpioIF(objects::GPIO_IF);
#if RPI_ADD_SPI_TEST == 1
new SpiTestClass(objects::SPI_TEST, gpioIF);
#endif
#if RPI_LOOPBACK_TEST_GPIO == 1
GpioCookie* gpioCookieLoopback = new GpioCookie();
/* Loopback pins. Adapt according to setup */
gpioId_t gpioIdSender = gpioIds::TEST_ID_0;
int bcmPinSender = 26;
gpioId_t gpioIdReader = gpioIds::TEST_ID_1;
int bcmPinReader = 16;
gpio::createRpiGpioConfig(gpioCookieLoopback, gpioIdSender, bcmPinSender, "GPIO_LB_SENDER",
gpio::Direction::OUT, 0);
gpio::createRpiGpioConfig(gpioCookieLoopback, gpioIdReader, bcmPinReader, "GPIO_LB_READER",
gpio::Direction::IN, 0);
new LibgpiodTest(objects::LIBGPIOD_TEST, objects::GPIO_IF, gpioCookieLoopback);
#endif /* RPI_LOOPBACK_TEST_GPIO == 1 */
new SpiComIF(objects::SPI_COM_IF, gpioIF);
#if RPI_TEST_ACS_BOARD == 1
GpioCookie* gpioCookieAcsBoard = new GpioCookie();
gpio::createRpiGpioConfig(gpioCookieAcsBoard, gpioIds::MGM_0_LIS3_CS, gpio::MGM_0_BCM_PIN,
"MGM_0_LIS3", gpio::Direction::OUT, 1);
gpio::createRpiGpioConfig(gpioCookieAcsBoard, gpioIds::MGM_1_RM3100_CS, gpio::MGM_1_BCM_PIN,
"MGM_1_RM3100", gpio::Direction::OUT, 1);
gpio::createRpiGpioConfig(gpioCookieAcsBoard, gpioIds::MGM_2_LIS3_CS, gpio::MGM_2_BCM_PIN,
"MGM_2_LIS3", gpio::Direction::OUT, 1);
gpio::createRpiGpioConfig(gpioCookieAcsBoard, gpioIds::MGM_3_RM3100_CS, gpio::MGM_3_BCM_PIN,
"MGM_3_RM3100", gpio::Direction::OUT, 1);
gpio::createRpiGpioConfig(gpioCookieAcsBoard, gpioIds::GYRO_0_ADIS_CS, gpio::GYRO_0_BCM_PIN,
"GYRO_0_ADIS", gpio::Direction::OUT, 1);
gpio::createRpiGpioConfig(gpioCookieAcsBoard, gpioIds::GYRO_1_L3G_CS, gpio::GYRO_1_BCM_PIN,
"GYRO_1_L3G", gpio::Direction::OUT, 1);
gpio::createRpiGpioConfig(gpioCookieAcsBoard, gpioIds::GYRO_2_L3G_CS, gpio::GYRO_2_BCM_PIN,
"GYRO_2_L3G", gpio::Direction::OUT, 1);
gpioIF->addGpios(gpioCookieAcsBoard);
std::string spiDev = "/dev/spidev0.0";
SpiCookie* spiCookie = new SpiCookie(addresses::MGM_0_LIS3, gpioIds::MGM_0_LIS3_CS, spiDev,
MGMLIS3MDL::MAX_BUFFER_SIZE, spi::DEFAULT_LIS3_MODE, spi::DEFAULT_LIS3_SPEED);
auto mgmLis3Handler = new MGMHandlerLIS3MDL(objects::MGM_0_LIS3_HANDLER,
objects::SPI_COM_IF, spiCookie);
mgmLis3Handler->setStartUpImmediately();
spiCookie = new SpiCookie(addresses::MGM_1_RM3100, gpioIds::MGM_1_RM3100_CS, spiDev,
RM3100::MAX_BUFFER_SIZE, spi::DEFAULT_RM3100_MODE, spi::DEFAULT_RM3100_SPEED);
auto mgmRm3100Handler = new MGMHandlerRM3100(objects::MGM_1_RM3100_HANDLER,
objects::SPI_COM_IF, spiCookie);
mgmRm3100Handler->setStartUpImmediately();
spiCookie = new SpiCookie(addresses::GYRO_1_L3G, gpioIds::GYRO_1_L3G_CS, spiDev,
L3GD20H::MAX_BUFFER_SIZE, spi::DEFAULT_L3G_MODE, spi::DEFAULT_L3G_SPEED);
auto gyroL3gHandler = new GyroHandlerL3GD20H(objects::GYRO_1_L3G_HANDLER, objects::SPI_COM_IF,
spiCookie);
gyroL3gHandler->setStartUpImmediately();
#endif /* RPI_TEST_ACS_BOARD == 1 */
}

View File

@ -0,0 +1,10 @@
target_sources(${TARGET_NAME} PRIVATE
print.c
)
target_include_directories(${TARGET_NAME} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
)

View File

@ -0,0 +1,38 @@
///\file
/******************************************************************************
The MIT License(MIT)
Embedded Template Library.
https://github.com/ETLCPP/etl
https://www.etlcpp.com
Copyright(c) 2019 jwellbelove
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files(the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions :
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#ifndef __ETL_PROFILE_H__
#define __ETL_PROFILE_H__
#define ETL_CHECK_PUSH_POP
#define ETL_CPP11_SUPPORTED 1
#define ETL_NO_NULLPTR_SUPPORT 0
#endif

View File

@ -0,0 +1,14 @@
#ifndef LINUX_GCOV_H_
#define LINUX_GCOV_H_
#include <fsfw/serviceinterface/ServiceInterfaceStream.h>
#ifdef GCOV
extern "C" void __gcov_flush();
#else
void __gcov_flush() {
sif::info << "GCC GCOV: Please supply GCOV=1 in Makefile if "
"coverage information is desired.\n" << std::flush;
}
#endif
#endif /* LINUX_GCOV_H_ */

View File

@ -0,0 +1,14 @@
#include <bsp_q7s/boardconfig/print.h>
#include <stdio.h>
void printChar(const char* character, bool errStream) {
if(errStream) {
putc(*character, stderr);
return;
}
putc(*character, stdout);
}

View File

@ -0,0 +1,24 @@
#ifndef BSP_RPI_BOARDCONFIG_RPI_CONFIG_H_
#define BSP_RPI_BOARDCONFIG_RPI_CONFIG_H_
#include <cstdint>
#define RPI_ADD_GPIO_TEST 0
#define RPI_LOOPBACK_TEST_GPIO 0
/* Only one of those 2 should be enabled! */
#define RPI_ADD_SPI_TEST 0
#define RPI_TEST_ACS_BOARD 0
/* Adapt these values accordingly */
namespace gpio {
static constexpr uint8_t MGM_0_BCM_PIN = 0;
static constexpr uint8_t MGM_1_BCM_PIN = 1;
static constexpr uint8_t MGM_2_BCM_PIN = 17;
static constexpr uint8_t MGM_3_BCM_PIN = 27;
static constexpr uint8_t GYRO_0_BCM_PIN = 5;
static constexpr uint8_t GYRO_1_BCM_PIN = 6;
static constexpr uint8_t GYRO_2_BCM_PIN = 4;
}
#endif /* BSP_RPI_BOARDCONFIG_RPI_CONFIG_H_ */

View File

@ -0,0 +1,6 @@
target_sources(${TARGET_NAME} PRIVATE
)

View File

@ -0,0 +1,8 @@
target_sources(${TARGET_NAME} PUBLIC
)

28
bsp_rpi/main.cpp Normal file
View File

@ -0,0 +1,28 @@
#include "InitMission.h"
#include <OBSWVersion.h>
#include <fsfw/tasks/TaskFactory.h>
#include <iostream>
/**
* @brief This is the main program and entry point for the Raspberry Pi.
* @return
*/
int main(void)
{
std::cout << "-- EIVE OBSW --" << std::endl;
std::cout << "-- Compiled for Linux (Raspberry Pi) --" << std::endl;
std::cout << "-- Software version " << SW_NAME << " v" << SW_VERSION << "."
<< SW_SUBVERSION << "." << SW_SUBSUBVERSION << " -- " << std::endl;
std::cout << "-- " << __DATE__ << " " << __TIME__ << " --" << std::endl;
initmission::initMission();
for(;;) {
/* Suspend main thread by sleeping it. */
TaskFactory::delayTask(5000);
}
}

45
cmake/BuildType.cmake Normal file
View File

@ -0,0 +1,45 @@
function(set_build_type)
message(STATUS "Used build generator: ${CMAKE_GENERATOR}")
# Set a default build type if none was specified
set(DEFAULT_BUILD_TYPE "RelWithDebInfo")
if(EXISTS "${CMAKE_SOURCE_DIR}/.git")
set(DEFAULT_BUILD_TYPE "Debug")
endif()
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message(STATUS
"Setting build type to '${DEFAULT_BUILD_TYPE}' as none was specified."
)
set(CMAKE_BUILD_TYPE "${DEFAULT_BUILD_TYPE}" CACHE
STRING "Choose the type of build." FORCE
)
# Set the possible values of build type for cmake-gui
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
"Debug" "Release" "MinSizeRel" "RelWithDebInfo"
)
endif()
if(${CMAKE_BUILD_TYPE} MATCHES "Debug")
message(STATUS
"Building Debug application with flags: ${CMAKE_C_FLAGS_DEBUG}"
)
elseif(${CMAKE_BUILD_TYPE} MATCHES "RelWithDebInfo")
message(STATUS
"Building Release (Debug) application with "
"flags: ${CMAKE_C_FLAGS_RELWITHDEBINFO}"
)
elseif(${CMAKE_BUILD_TYPE} MATCHES "MinSizeRel")
message(STATUS
"Building Release (Size) application with "
"flags: ${CMAKE_C_FLAGS_MINSIZEREL}"
)
else()
message(STATUS
"Building Release (Speed) application with "
"flags: ${CMAKE_C_FLAGS_RELEASE}"
)
endif()
endfunction()

View File

@ -0,0 +1,62 @@
function(post_source_hw_os_config)
if(LINK_LWIP)
message(STATUS "Linking against ${LIB_LWIP_NAME} lwIP library")
if(LIB_LWIP_NAME)
target_link_libraries(${TARGET_NAME} PUBLIC
${LIB_LWIP_NAME}
)
else()
message(WARNING "lwIP library name not set!")
endif()
endif()
if(LINK_HAL)
message(STATUS "Linking against ${LIB_HAL_NAME} HAL library")
if(LIB_HAL_NAME)
target_link_libraries(${TARGET_NAME} PUBLIC
${LIB_HAL_NAME}
)
else()
message(WARNING "HAL library name not set!")
endif()
endif()
if(LINKER_SCRIPT)
target_link_options(${TARGET_NAME} PRIVATE
-T${LINKER_SCRIPT}
)
endif()
set(C_FLAGS "" CACHE INTERNAL "C flags")
set(C_DEFS ""
CACHE INTERNAL
"C Defines"
)
set(CXX_FLAGS ${C_FLAGS})
set(CXX_DEFS ${C_DEFS})
if(CMAKE_VERBOSE)
message(STATUS "C Flags: ${C_FLAGS}")
message(STATUS "CXX Flags: ${CXX_FLAGS}")
message(STATUS "C Defs: ${C_DEFS}")
message(STATUS "CXX Defs: ${CXX_DEFS}")
endif()
# Generator expression. Can be used to set different C, CXX and ASM flags.
target_compile_options(${TARGET_NAME} PRIVATE
$<$<COMPILE_LANGUAGE:C>:${C_DEFS} ${C_FLAGS}>
$<$<COMPILE_LANGUAGE:CXX>:${CXX_DEFS} ${CXX_FLAGS}>
$<$<COMPILE_LANGUAGE:ASM>:${ASM_FLAGS}>
)
add_custom_command(
TARGET ${TARGET_NAME}
POST_BUILD
COMMAND ${CMAKE_OBJCOPY} -O binary ${TARGET_NAME} ${TARGET_NAME}.bin
COMMENT "Generating binary file ${CMAKE_PROJECT_NAME}.bin.."
)
endfunction()

View File

@ -0,0 +1,70 @@
function(pre_source_hw_os_config)
# FreeRTOS
if(${OS_FSFW} MATCHES freertos)
message(FATAL_ERROR "No FreeRTOS support implemented yet.")
# RTEMS
elseif(${OS_FSFW} STREQUAL rtems)
add_definitions(-DRTEMS)
message(FATAL_ERROR "No RTEMS support implemented yet.")
elseif(${OS_FSFW} STREQUAL linux)
add_definitions(-DUNIX -DLINUX)
find_package(Threads REQUIRED)
# Hosted
else()
set(BSP_PATH "bsp_hosted")
if(WIN32)
add_definitions(-DWIN32)
elseif(UNIX)
find_package(Threads REQUIRED)
add_definitions(-DUNIX -DLINUX)
endif()
endif()
# Cross-compile information
if(CMAKE_CROSSCOMPILING)
# set(CMAKE_VERBOSE TRUE)
message(STATUS "Cross-compiling for ${TGT_BSP} target")
message(STATUS "Cross-compile gcc: ${CMAKE_C_COMPILER}")
message(STATUS "Cross-compile g++: ${CMAKE_CXX_COMPILER}")
if(CMAKE_VERBOSE)
message(STATUS "Cross-compile linker: ${CMAKE_LINKER}")
message(STATUS "Cross-compile size utility: ${CMAKE_SIZE}")
message(STATUS "Cross-compile objcopy utility: ${CMAKE_OBJCOPY}")
message(STATUS "Cross-compile ranlib utility: ${CMAKE_RANLIB}")
message(STATUS "Cross-compile ar utility: ${CMAKE_AR}")
message(STATUS "Cross-compile nm utility: ${CMAKE_NM}")
message(STATUS "Cross-compile strip utility: ${CMAKE_STRIP}")
message(STATUS
"Cross-compile assembler: ${CMAKE_ASM_COMPILER} "
"-x assembler-with-cpp"
)
message(STATUS "ABI flags: ${ABI_FLAGS}")
message(STATUS "Custom linker script: ${LINKER_SCRIPT}")
endif()
set_property(CACHE TGT_BSP
PROPERTY STRINGS
"arm/q7s" "arm/raspberrypi"
)
endif()
if(TGT_BSP)
if (${TGT_BSP} MATCHES "arm/raspberrypi")
set(BSP_PATH "bsp_rpi")
elseif(${TGT_BSP} MATCHES "arm/q7s")
set(BSP_PATH "bsp_q7s")
else()
message(WARNING "CMake not configured for this target!")
message(FATAL_ERROR "Target: ${TGT_BSP}!")
endif()
else()
set(BSP_PATH "bsp_hosted")
endif()
set(BSP_PATH ${BSP_PATH} PARENT_SCOPE)
endfunction()

View File

@ -0,0 +1,59 @@
function(pre_project_config)
# Basic input sanitization
if(DEFINED TGT_BSP)
if(${TGT_BSP} MATCHES "arm/raspberrypi" AND NOT ${OS_FSFW} MATCHES linux)
message(STATUS "FSFW OSAL invalid for specified target BSP ${TGT_BSP}!")
message(STATUS "Setting valid OS_FSFW: linux")
set(OS_FSFW "linux")
endif()
endif()
# Disable compiler checks for cross-compiling.
if(${OS_FSFW} STREQUAL linux AND TGT_BSP)
if(${TGT_BSP} MATCHES "arm/q7s")
set(CMAKE_TOOLCHAIN_FILE
"${CMAKE_SCRIPT_PATH}/Q7SCrossCompileConfig.cmake"
PARENT_SCOPE
)
elseif (${TGT_BSP} MATCHES "arm/raspberrypi")
if(NOT DEFINED ENV{RASPBIAN_ROOTFS})
if(NOT DEFINED RASPBIAN_ROOTFS)
message(WARNING "No RASPBIAN_ROOTFS environmental or CMake variable set!")
set(ENV{RASPBIAN_ROOTFS} "$ENV{HOME}/raspberrypi/rootfs")
else()
set(ENV{RASPBIAN_ROOTFS} "${RASPBIAN_ROOTFS}")
endif()
else()
message(STATUS
"RASPBIAN_ROOTFS from environmental variables used: $ENV{RASPBIAN_ROOTFS}"
)
endif()
if(NOT DEFINED ENV{RASPBERRY_VERSION})
if(NOT RASPBERRY_VERSION)
message(STATUS "No RASPBERRY_VERSION specified, setting to 4")
set(RASPBERRY_VERSION "4" CACHE STRING "Raspberry Pi version")
else()
message(STATUS "Setting RASPBERRY_VERSION to ${RASPBERRY_VERSION}")
set(RASPBERRY_VERSION ${RASPBERRY_VERSION} CACHE STRING "Raspberry Pi version")
set(ENV{RASPBERRY_VERSION} ${RASPBERRY_VERSION})
endif()
else()
message(STATUS
"RASPBERRY_VERSION from environmental variables used: "
"$ENV{RASPBERRY_VERSION}"
)
endif()
set(CMAKE_TOOLCHAIN_FILE
"${CMAKE_SCRIPT_PATH}/RPiCrossCompileConfig.cmake"
PARENT_SCOPE
)
else()
message(WARNING "Target BSP (TGT_BSP) ${TGT_BSP} unknown!")
endif()
endif()
endfunction()

View File

@ -0,0 +1,88 @@
# CROSS_COMPILE also needs to be set accordingly or passed to the CMake command
if(NOT DEFINED ENV{Q7S_SYSROOT})
# message(FATAL_ERROR
# "Define the Q7S_ROOTFS variable to "
# "point to the raspbian rootfs."
# )
else()
set(SYSROOT_PATH "$ENV{Q7S_SYSROOT}")
endif()
if(NOT DEFINED ENV{CROSS_COMPILE})
set(CROSS_COMPILE "arm-linux-gnueabihf")
message(STATUS
"No CROSS_COMPILE environmental variable set, using default ARM linux "
"cross compiler name ${CROSS_COMPILE}"
)
else()
set(CROSS_COMPILE "$ENV{CROSS_COMPILE}")
message(STATUS
"Using environmental variable CROSS_COMPILE as cross-compiler: "
"$ENV{CROSS_COMPILE}"
)
endif()
message(STATUS "Using sysroot path: ${SYSROOT_PATH}")
set(CROSS_COMPILE_CC "${CROSS_COMPILE}-gcc")
set(CROSS_COMPILE_CXX "${CROSS_COMPILE}-g++")
set(CROSS_COMPILE_LD "${CROSS_COMPILE}-ld")
set(CROSS_COMPILE_AR "${CROSS_COMPILE}-ar")
set(CROSS_COMPILE_RANLIB "${CROSS_COMPILE}-ranlib")
set(CROSS_COMPILE_STRIP "${CROSS_COMPILE}-strip")
set(CROSS_COMPILE_NM "${CROSS_COMPILE}-nm")
set(CROSS_COMPILE_OBJCOPY "${CROSS_COMPILE}-objcopy")
set(CROSS_COMPILE_SIZE "${CROSS_COMPILE}-size")
# At the very least, cross compile gcc and g++ have to be set!
find_program (CROSS_COMPILE_CC_FOUND ${CROSS_COMPILE_CC} REQUIRED)
find_program (CROSS_COMPILE_CXX_FOUND ${CROSS_COMPILE_CXX} REQUIRED)
set(CMAKE_CROSSCOMPILING TRUE)
set(CMAKE_SYSROOT "${SYSROOT_PATH}")
# Define name of the target system
set(CMAKE_SYSTEM_NAME "Linux")
set(CMAKE_SYSTEM_PROCESSOR "armv7")
# Define the compiler
set(CMAKE_C_COMPILER ${CROSS_COMPILE_CC})
set(CMAKE_CXX_COMPILER ${CROSS_COMPILE_CXX})
# List of library dirs where LD has to look. Pass them directly through gcc.
set(LIB_DIRS
"${SYSROOT_PATH}/usr/include"
"${SYSROOT_PATH}/usr/include/linux"
"${SYSROOT_PATH}/usr/lib"
"${SYSROOT_PATH}/lib"
"${SYSROOT_PATH}"
"${SYSROOT_PATH}/usr/lib/arm-xiphos-linux-gnueabi"
)
# You can additionally check the linker paths if you add the
# flags ' -Xlinker --verbose'
set(COMMON_FLAGS "-I${SYSROOT_PATH}/usr/lib")
foreach(LIB ${LIB_DIRS})
set(COMMON_FLAGS "${COMMON_FLAGS} -L${LIB} -Wl,-rpath-link,${LIB}")
endforeach()
set(CMAKE_PREFIX_PATH
"${CMAKE_PREFIX_PATH}"
# "${SYSROOT_PATH}/usr/lib/${CROSS_COMPILE}"
)
set(CMAKE_C_FLAGS
"-mcpu=cortex-a9 -mfpu=neon-vfpv3 -mfloat-abi=hard ${COMMON_FLAGS} -lgpiod"
CACHE STRING "C flags for Q7S"
)
set(CMAKE_CXX_FLAGS
"${CMAKE_C_FLAGS}"
CACHE STRING "CPP flags for Q7S"
)
# search for programs in the build host directories
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# for libraries and headers in the target directories
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)

View File

@ -0,0 +1,146 @@
# Based on https://github.com/Pro/raspi-toolchain but rewritten completely.
# Adapted for the FSFW Example
if(NOT $ENV{RASPBERRY_VERSION})
message(STATUS "Raspberry Pi version not specified, setting version 4!")
set(RASPBERRY_VERSION 4)
else()
set(RASPBERRY_VERSION $ENV{RASPBERRY_VERSION})
endif()
# RASPBIAN_ROOTFS should point to the local directory which contains all the
# libraries and includes from the target raspi.
# The following command can be used to do this, replace <ip-address> and the
# local <rootfs-path> accordingly:
# rsync -vR --progress -rl --delete-after --safe-links pi@<ip-address>:/{lib,usr,opt/vc/lib} <rootfs-path>
# RASPBIAN_ROOTFS needs to be passed to the CMake command or defined in the
# application CMakeLists.txt before loading the toolchain file.
# CROSS_COMPILE also needs to be set accordingly or passed to the CMake command
if(NOT DEFINED ENV{RASPBIAN_ROOTFS})
message(FATAL_ERROR
"Define the RASPBIAN_ROOTFS variable to "
"point to the raspbian rootfs."
)
else()
set(SYSROOT_PATH "$ENV{RASPBIAN_ROOTFS}")
endif()
if(NOT DEFINED ENV{CROSS_COMPILE})
set(CROSS_COMPILE "arm-linux-gnueabihf")
message(STATUS
"No CROSS_COMPILE environmental variable set, using default ARM linux "
"cross compiler name ${CROSS_COMPILE}"
)
else()
set(CROSS_COMPILE "$ENV{CROSS_COMPILE}")
message(STATUS
"Using environmental variable CROSS_COMPILE as cross-compiler: "
"$ENV{CROSS_COMPILE}"
)
endif()
message(STATUS "Using sysroot path: ${SYSROOT_PATH}")
set(CROSS_COMPILE_CC "${CROSS_COMPILE}-gcc")
set(CROSS_COMPILE_CXX "${CROSS_COMPILE}-g++")
set(CROSS_COMPILE_LD "${CROSS_COMPILE}-ld")
set(CROSS_COMPILE_AR "${CROSS_COMPILE}-ar")
set(CROSS_COMPILE_RANLIB "${CROSS_COMPILE}-ranlib")
set(CROSS_COMPILE_STRIP "${CROSS_COMPILE}-strip")
set(CROSS_COMPILE_NM "${CROSS_COMPILE}-nm")
set(CROSS_COMPILE_OBJCOPY "${CROSS_COMPILE}-objcopy")
set(CROSS_COMPILE_SIZE "${CROSS_COMPILE}-size")
# At the very least, cross compile gcc and g++ have to be set!
find_program (CROSS_COMPILE_CC_FOUND ${CROSS_COMPILE_CC} REQUIRED)
find_program (CROSS_COMPILE_CXX_FOUND ${CROSS_COMPILE_CXX} REQUIRED)
set(CMAKE_CROSSCOMPILING TRUE)
set(CMAKE_SYSROOT "${SYSROOT_PATH}")
# Define name of the target system
set(CMAKE_SYSTEM_NAME "Linux")
if(RASPBERRY_VERSION VERSION_GREATER 1)
set(CMAKE_SYSTEM_PROCESSOR "armv7")
else()
set(CMAKE_SYSTEM_PROCESSOR "arm")
endif()
# Define the compiler
set(CMAKE_C_COMPILER ${CROSS_COMPILE_CC})
set(CMAKE_CXX_COMPILER ${CROSS_COMPILE_CXX})
# List of library dirs where LD has to look. Pass them directly through gcc.
# LD_LIBRARY_PATH is not evaluated by arm-*-ld
set(LIB_DIRS
"/opt/cross-pi-gcc/arm-linux-gnueabihf/lib"
"/opt/cross-pi-gcc/lib"
"${SYSROOT_PATH}/opt/vc/lib"
"${SYSROOT_PATH}/lib/${CROSS_COMPILE}"
"${SYSROOT_PATH}/usr/local/lib"
"${SYSROOT_PATH}/usr/lib/${CROSS_COMPILE}"
"${SYSROOT_PATH}/usr/lib"
"${SYSROOT_PATH}/usr/lib/${CROSS_COMPILE}/blas"
"${SYSROOT_PATH}/usr/lib/${CROSS_COMPILE}/lapack"
)
# You can additionally check the linker paths if you add the
# flags ' -Xlinker --verbose'
set(COMMON_FLAGS "-I${SYSROOT_PATH}/usr/include")
foreach(LIB ${LIB_DIRS})
set(COMMON_FLAGS "${COMMON_FLAGS} -L${LIB} -Wl,-rpath-link,${LIB}")
endforeach()
set(CMAKE_PREFIX_PATH
"${CMAKE_PREFIX_PATH}"
"${SYSROOT_PATH}/usr/lib/${CROSS_COMPILE}"
)
if(RASPBERRY_VERSION VERSION_GREATER 3)
set(CMAKE_C_FLAGS
"-mcpu=cortex-a72 -mfpu=neon-vfpv4 -mfloat-abi=hard ${COMMON_FLAGS}"
CACHE STRING "CPP flags for Raspberry PI 4"
)
set(CMAKE_CXX_FLAGS
"${CMAKE_C_FLAGS}"
CACHE STRING "C flags for Raspberry PI 4"
)
elseif(RASPBERRY_VERSION VERSION_GREATER 2)
set(CMAKE_C_FLAGS
"-mcpu=cortex-a53 -mfpu=neon-vfpv4 -mfloat-abi=hard ${COMMON_FLAGS}"
CACHE STRING "C flags for Raspberry PI 3"
)
set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS}"
CACHE STRING "CPP flags for Raspberry PI 3"
)
elseif(RASPBERRY_VERSION VERSION_GREATER 1)
set(CMAKE_C_FLAGS
"-mcpu=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard ${COMMON_FLAGS}"
CACHE STRING "C flags for Raspberry PI 2"
)
set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS}"
CACHE STRING "CPP flags for Raspberry PI 2"
)
else()
set(CMAKE_C_FLAGS
"-mcpu=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard ${COMMON_FLAGS}"
CACHE STRING "C flags for Raspberry PI 1 B+ Zero"
)
set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS}"
CACHE STRING "CPP flags for Raspberry PI 1 B+ Zero"
)
endif()
set(CMAKE_FIND_ROOT_PATH
"${CMAKE_INSTALL_PREFIX};${CMAKE_PREFIX_PATH};${CMAKE_SYSROOT}"
)
# search for programs in the build host directories
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# for libraries and headers in the target directories
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)

View File

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.9" project-jdk-type="Python SDK" />
</project>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/scripts.iml" filepath="$PROJECT_DIR$/.idea/scripts.iml" />
</modules>
</component>
</project>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/../../.." vcs="Git" />
</component>
</project>

View File

@ -0,0 +1,89 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ChangeListManager">
<list default="true" id="b7804b00-6384-4363-ae17-406610449420" name="Default Changelist" comment="" />
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$/../../.." />
</component>
<component name="ProjectId" id="1mFLMh77EFiQ6e8GGJM4DSy44LC" />
<component name="ProjectLevelVcsManager" settingsEditedManually="true" />
<component name="ProjectViewState">
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent">
<property name="RunOnceActivity.OpenProjectViewOnStart" value="true" />
<property name="RunOnceActivity.ShowReadmeOnStart" value="true" />
<property name="WebServerToolWindowFactoryState" value="false" />
<property name="last_opened_file_path" value="$PROJECT_DIR$" />
<property name="node.js.detected.package.eslint" value="true" />
<property name="node.js.detected.package.tslint" value="true" />
<property name="node.js.path.for.package.eslint" value="project" />
<property name="node.js.path.for.package.tslint" value="project" />
<property name="node.js.selected.package.eslint" value="(autodetect)" />
<property name="node.js.selected.package.tslint" value="(autodetect)" />
</component>
<component name="RunManager">
<configuration name="cmake_build_config" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
<module name="scripts" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
</envs>
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/cmake_build_config.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
<option name="MODULE_MODE" value="false" />
<option name="REDIRECT_INPUT" value="false" />
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
<recent_temporary>
<list>
<item itemvalue="Python.cmake_build_config" />
</list>
</recent_temporary>
</component>
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="b7804b00-6384-4363-ae17-406610449420" name="Default Changelist" comment="" />
<created>1609084345199</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1609084345199</updated>
<workItem from="1609084346343" duration="6791000" />
</task>
<servers />
</component>
<component name="TypeScriptGeneratedFilesManager">
<option name="version" value="3" />
</component>
<component name="Vcs.Log.Tabs.Properties">
<option name="TAB_STATES">
<map>
<entry key="MAIN">
<value>
<State />
</value>
</entry>
</map>
</option>
</component>
<component name="com.intellij.coverage.CoverageDataManagerImpl">
<SUITE FILE_PATH="coverage/scripts$cmake_build_config.coverage" NAME="cmake_build_config Coverage Results" MODIFIED="1609089450693" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
</component>
</project>

View File

@ -0,0 +1,27 @@
#!/bin/sh
counter=0
while [ ${counter} -lt 5 ]
do
cd ..
if [ -f "cmake_build_config.py" ];then
break
fi
counter=$((counter=counter + 1))
done
if [ "${counter}" -ge 5 ];then
echo "create_cmake_cfg.sh not found in upper directories!"
exit 1
fi
build_generator=""
build_dir="Debug-Host"
os_fsfw="host"
if [ "${OS}" = "Windows_NT" ]; then
build_generator="MinGW Makefiles"
# Could be other OS but this works for now.
else
build_generator="Unix Makefiles"
fi
python3 cmake_build_config.py -o "${os_fsfw}" -g "${build_generator}" -b "debug" -l"${build_dir}"

View File

@ -0,0 +1,27 @@
#!/bin/sh
counter=0
while [ ${counter} -lt 5 ]
do
cd ..
if [ -f "cmake_build_config.py" ];then
break
fi
counter=$((counter=counter + 1))
done
if [ "${counter}" -ge 5 ];then
echo "create_cmake_cfg.sh not found in upper directories!"
exit 1
fi
build_generator=""
os_fsfw="host"
build_dir="Release-Host"
if [ "${OS}" = "Windows_NT" ]; then
build_generator="MinGW Makefiles"
# Could be other OS but this works for now.
else
build_generator="Unix Makefiles"
fi
python3 cmake_build_config.py -o "${os_fsfw}" -g "${build_generator}" -b "release" -l"${build_dir}"

View File

@ -0,0 +1,26 @@
#!/bin/sh
counter=0
while [ ${counter} -lt 5 ]
do
cd ..
if [ -f "cmake_build_config.py" ];then
break
fi
counter=$((counter=counter + 1))
done
if [ "${counter}" -ge 5 ];then
echo "create_cmake_cfg.sh not found in upper directories!"
exit 1
fi
build_generator=""
os_fsfw="host"
if [ "${OS}" = "Windows_NT" ]; then
build_generator="MinGW Makefiles"
# Could be other OS but this works for now.
else
build_generator="Unix Makefiles"
fi
python3 cmake_build_config.py -o "${os_fsfw}" -g "${build_generator}" -b "reldeb"

View File

@ -0,0 +1,26 @@
#!/bin/sh
counter=0
while [ ${counter} -lt 5 ]
do
cd ..
if [ -f "cmake_build_config.py" ];then
break
fi
counter=$((counter=counter + 1))
done
if [ "${counter}" -ge 5 ];then
echo "create_cmake_cfg.sh not found in upper directories!"
exit 1
fi
build_generator=""
os_fsfw="host"
if [ "${OS}" = "Windows_NT" ]; then
build_generator="MinGW Makefiles"
# Could be other OS but this works for now.
else
build_generator="Unix Makefiles"
fi
python3 cmake_build_config.py -o "${os_fsfw}" -g "${build_generator}" -b "size"

View File

@ -0,0 +1,25 @@
#!/bin/sh
counter=0
while [ ${counter} -lt 5 ]
do
cd ..
if [ -f "cmake_build_config.py" ];then
break
fi
counter=$((counter=counter + 1))
done
if [ "${counter}" -ge 5 ];then
echo "create_cmake_cfg.sh not found in upper directories!"
exit 1
fi
build_generator="Unix Makefiles"
os_fsfw="linux"
builddir="Debug-Linux"
echo "Running command (without the leading +):"
set -x # Print command
python3 cmake_build_config.py -o "${os_fsfw}" -g "${build_generator}" -b "debug" -l "${builddir}"
# Use this if commands are added which should not be printed
# set +x

View File

@ -0,0 +1,25 @@
#!/bin/sh
counter=0
while [ ${counter} -lt 5 ]
do
cd ..
if [ -f "cmake_build_config.py" ];then
break
fi
counter=$((counter=counter + 1))
done
if [ "${counter}" -ge 5 ];then
echo "create_cmake_cfg.sh not found in upper directories!"
exit 1
fi
build_generator="Unix Makefiles"
os_fsfw="linux"
builddir="Release-Linux"
echo "Running command (without the leading +):"
set -x # Print command
python3 cmake_build_config.py -o "${os_fsfw}" -g "${build_generator}" -b "debug" -l "${builddir}"
# Use this if commands are added which should not be printed
# set +x

View File

@ -0,0 +1,25 @@
#!/bin/sh
counter=0
while [ ${counter} -lt 5 ]
do
cd ..
if [ -f "cmake_build_config.py" ];then
break
fi
counter=$((counter=counter + 1))
done
if [ "${counter}" -ge 5 ];then
echo "create_cmake_cfg.sh not found in upper directories!"
exit 1
fi
build_generator="Unix Makefiles"
os_fsfw="linux"
builddir="RelWithDeb-Linux"
echo "Running command (without the leading +):"
set -x # Print command
python3 cmake_build_config.py -o "${os_fsfw}" -g "${build_generator}" -b "debug" -l "${builddir}"
# Use this if commands are added which should not be printed
# set +x

View File

@ -0,0 +1,20 @@
#!/bin/sh
counter=0
while [ ${counter} -lt 5 ]
do
cd ..
if [ -f "cmake_build_config.py" ];then
break
fi
counter=$((counter=counter + 1))
done
if [ "${counter}" -ge 5 ];then
echo "create_cmake_cfg.sh not found in upper directories!"
exit 1
fi
build_generator="Unix Makefiles"
os_fsfw="linux"
python3 cmake_build_config.py -o "${os_fsfw}" -g "${build_generator}" -b "size"

Some files were not shown because too many files have changed in this diff Show More