diff --git a/CMakeLists.txt b/CMakeLists.txt index b5abe9ab..5b1b94f8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,6 +52,7 @@ set(LIB_FSFW_HAL_NAME fsfw_hal) set(LIB_LWGPS_NAME lwgps) set(LIB_ARCSEC wire) set(THIRD_PARTY_FOLDER thirdparty) +set(LIB_CXX_FS -lstdc++fs) # Set path names set(FSFW_PATH fsfw) @@ -168,6 +169,7 @@ if(NOT Q7S_SIMPLE_MODE) ${LIB_LWGPS_NAME} ${LIB_FSFW_HAL_NAME} ${LIB_ARCSEC} + ${LIB_CXX_FS} ) endif() diff --git a/README.md b/README.md index 787d40f2..68a5df30 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,26 @@ -# EIVE On-Board Software + EIVE On-Board Software +====== -## General information +# General information Target systems: * OBC with Linux OS - * Xiphos Q7S - * Based on Zynq-7020 SoC (xc7z020clg484-2) - * Dual-core ARM Cortex-A9 - * 766 MHz - * 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 - * 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 built with Yocto 2.5 - * Linux Kernel https://github.com/XiphosSystemsCorp/linux-xlnx.git + * Xiphos Q7S + * Based on Zynq-7020 SoC (xc7z020clg484-2) + * Dual-core ARM Cortex-A9 + * 766 MHz + * 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 + * Also a lot of information about the Q7S can be found on + the [Xiphos Traq Platform](https://trac2.xiphos.ca/eive-q7). Press on index to find all + relevant pages. + * Linux OS built with Yocto 2.5 + * Linux Kernel https://github.com/XiphosSystemsCorp/linux-xlnx.git . EIVE version can be found + [here](https://github.com/spacefisch/linux-xlnx) . Pre-compiled files can be + found [here](https://eive-cloud.irs.uni-stuttgart.de/index.php/apps/files/?dir=/EIVE_IRS/Software/q7s-linux-components&fileid=777299). + * Q7S base project can be found [here](https://egit.irs.uni-stuttgart.de/eive/q7s-base) + * Minimal base project files can be found [here](https://eive-cloud.irs.uni-stuttgart.de/index.php/apps/files/?dir=/EIVE_IRS/Software/xiphos-q7s-sdk&fileid=510908) * Host System * Generic software components which are not dependant on hardware can also be run on a host system. All host code is contained in the `bsp_hosted` folder @@ -28,30 +35,56 @@ The CMake build system can be used to generate build systems as well (see helper - 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 +## Installing Vivado the the Xilinx development tools It's also possible to perform debugging with a normal Eclipse installation by installing -the TCF plugin and downloading the cross-compiler as specified in the section below. +the TCF plugin and downloading the cross-compiler as specified in the section below. However, +if you want to generate the `*.xdi` files necessary to update the firmware, you need to +installed Vivado with the SDK core tools. * 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 → Zynq-7000:
-
+
-
+
-
+
-* 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 permanent environment variables (`.profile` file in Linux): +* For supported OS refer to https://www.xilinx.com/support/documentation/sw_manuals/xilinx2018_2/ug973-vivado-release-notes-install-license.pdf . + Installation was tested on Windows and Ubuntu 21.04. +* Add path of linux cross-compiler to permanent environment variables (`.bashrc` file in Linux): `\SDK\2018.2\gnu\aarch32\nt\gcc-arm-linux-gnueabi\bin` or set up path each time before debugging. -### Installing toolchain without Vivado +### Installing on Linux - Device List Issue + +When installing on Ubuntu, the installer might get stuck at the `Generating installed device list` +step. When this happens, you can kill the installation process (might be necessara to kill a process +twice) and generate this list manually with the following commands, according to +[this forum entry](https://forums.xilinx.com/t5/Installation-and-Licensing/Vivado-2018-3-Final-Processing-hangs-at-Generating-installed/m-p/972114#M25861). + +1. Install the following library + ```sh + sudo apt install libncurses5 + ``` + +2. ```sh + sudo /Vivado/2018.2/bin/vivado -nolog -nojournal -mode batch -source + /.xinstall/Vivado_2018.2/scripts/xlpartinfo.tcl -tclargs + /Vivado/2018.2/data/parts/installed_devices.txt + ``` + +For Linux, you can also download a more recent version of the +[Linaro 8.3.0 cross-compiler](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-a/downloads) +from [here](https://developer.arm.com/-/media/Files/downloads/gnu-a/8.3-2019.03/binrel/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf.tar.xz?revision=e09a1c45-0ed3-4a8e-b06b-db3978fd8d56&la=en&hash=93ED4444B8B3A812B893373B490B90BBB28FD2E3) + +## Installing toolchain without Vivado You can download the toolchains for Windows and Linux [from the EIVE cloud](https://eive-cloud.irs.uni-stuttgart.de/index.php/apps/files?dir=/EIVE_IRS/Software/tools&fileid=831898). @@ -69,7 +102,7 @@ or the following command for Linux (could be useful for CI/CD) wget https://eive-cloud.irs.uni-stuttgart.de/index.php/s/2Fp2ag6NGnbtAsK/download/gcc-arm-linux-gnueabi.tar.gz ``` -### Installing CMake and MSYS2 on Windows +## Installing CMake and MSYS2 on Windows 1. Install [MSYS2](https://www.msys2.org/) and [CMake](https://cmake.org/download/) first. @@ -94,7 +127,7 @@ wget https://eive-cloud.irs.uni-stuttgart.de/index.php/s/2Fp2ag6NGnbtAsK/downloa 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 +## Installing CMake on Linux 1. Run the following command @@ -117,7 +150,7 @@ wget https://eive-cloud.irs.uni-stuttgart.de/index.php/s/agnJGYeRf6fw2ci/downloa Then, create a new environmental variables `Q7S_SYSROOT` and set it to the local system root path. -## Building the software with CMake +# Building the software with CMake When using Windows, run theses steps in MSYS2. @@ -153,7 +186,7 @@ When using Windows, run theses steps in MSYS2. ```sh cd cmake/scripts/Q7S - ./create_cmake_debug.sh + ./make_debug_cfg.sh cd ../../.. ``` @@ -230,7 +263,7 @@ IP address and path settings differ from machine to machine. You can run it manually there. To perform auto-start on boot, have a look at the start-up application section. -## Debugging the software via Flatsat PC +# Debugging the software via Flatsat PC Open SSH connection to flatsat PC: @@ -269,7 +302,8 @@ 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 @@ -289,12 +323,14 @@ To launch application from Xilinx SDK setup port fowarding on the development ma 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 of the Q7S. +Note: When now setting up a debug session in the Xilinx SDK or Eclipse, the host must be set +to localhost instead of the IP address of the Q7S. -## Transfering files via SCP +# Transfering files via SCP To transfer files from the local machine to the Q7S, use port forwarding @@ -318,11 +354,11 @@ From a windows machine files can be copied with putty tools (note: use IPv4 addr pscp -scp -P 22 eive@192.168.199.227:/example-file ```` -## Launching an application at start-up +# Launching an application at start-up -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 currently loaded root partition, e.g. creating directories. To do this, -the parition needs to be mounted. +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 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 @@ -340,11 +376,13 @@ the parition needs to be mounted. 3. Copy the executable to `/usr/bin` 4. Make sure the permissions to execute the application are set + ```sh chmod +x application ``` 5. Create systemd service in /lib/systemd/system. The following shows an example service. + ```sh cat > example.service [Unit] @@ -361,8 +399,8 @@ the parition needs to be mounted. [Install] WantedBy=multi-user.target ``` -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. +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. ```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' ``` @@ -380,37 +418,14 @@ the parition needs to be mounted. ```sh systemctl status example ``` + More detailed information about the used q7s commands can be found in the Q7S user manual. -### Bringing up CAN - - ```sh - ip link set can0 down - 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) -```` -cansend can0 -i99 99 88 77 11 33 11 22 99 -```` -For Q7S use this: -```` -cansend can0 5A1#11.22.33.44.55.66.77.88 -```` -Turn loopback mode on: -```` -ip link set can0 type can bitrate 1000000 loopback on -```` -Reading data from CAN: -```` -candump can0 -```` - ## Setting up UNIX environment for real-time functionalities + Please note that on most UNIX environments (e.g. Ubuntu), the real time functionalities -used by the UNIX pthread module are restricted, which will lead to permission errors when creating these tasks -and configuring real-time properites like scheduling priorities. +used by the UNIX pthread module are restricted, which will lead to permission errors when creating +these tasks and configuring real-time properites like scheduling priorities. To solve this issues, try following steps: @@ -435,58 +450,27 @@ required for some framework components. The recommended values for the new messa length is 130. 2. Edit the /etc/sysctl.conf file -```sh -sudo nano /etc/sysctl.conf -``` -Append at end: -```sh -fs/mqueue/msg_max = -``` -Apply changes with: -```sh -sudo sysctl -p -``` -A possible solution which only persists for the current session is -```sh -echo | sudo tee /proc/sys/fs/mqueue/msg_max -``` -or running the `unlockRealtime` script. + ```sh + sudo nano /etc/sysctl.conf + ``` -3. Run the shell script inside the linux folder -```sh -./unlockRealtime -``` -This script executes the `sudo setcap 'cap_sys_nice=eip' \` -command on the binaries, increases the soft real time limit of the current -session and increases the maximum number of message queues by setting -`/proc/sys/fs/mqueue/msg_max`. -All changes are only applied for the current session (read 2. and 3. for -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, -the hard real-time limit of the system might not be high enough (see step 1). + Append at end: + ```sh + fs/mqueue/msg_max = + ``` + + Apply changes with: + ```sh + sudo sysctl -p + ``` -## Flight Software Framework (FSFW) + A possible solution which only persists for the current session is + ```sh + echo | sudo tee /proc/sys/fs/mqueue/msg_max + ``` -An EIVE fork of the FSFW is submodules into this repository. -To add the master upstream branch and merge changes and updates from it -into the fork, run the following command in the fsfw folder first: - -```sh -git remote add upstream https://egit.irs.uni-stuttgart.de/fsfw/fsfw.git -git remote update --prune -``` - -After that, an update can be merged by running - -```sh -git merge upstream/master -``` - -Alternatively, changes from other upstreams (forks) and branches can be merged like that in -the same way. - -## PCDU +# PCDU Connect to serial console of P60 Dock ```` @@ -511,10 +495,11 @@ p60-dock # param get out_en[0] GET out_en[0] = 1 ```` -## Debugging the software (when workstation is directly conncected to Q7S) +# 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) + * Open serial console of Q7S (Accessible via the micro-USB of the PIM, see also Q7S user + manual chapter 10.3) * Baudrate 115200 * Login to Q7S: * user: root @@ -562,10 +547,10 @@ GET out_en[0] = 1 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 + * Local File Path: Path to eiveobsw-linux.elf (in `_bin\linux\devel`) + * Remote File Path: `/tmp/eive_obsw.elf` -## Running cppcheck on the Software +# Running cppcheck on the Software Static code analysis can be useful to find bugs. `cppcheck` can be used for this purpose. On Windows you can use MinGW64 to do this. @@ -597,6 +582,47 @@ Finally, you can convert the generated `.xml` file to HTML with the following co cppcheck-htmlreport --file=report.xml --report-dir=cppcheck --source-dir=.. ``` +# Special notes on Eclipse + +When using Eclipse, there are two special build variables in the project properties +→ C/C++ Build → 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. + +# Q7S Utilities and Troubleshooting + +## pa3tool Host Tool + +The `pa3tool` is a host tool to interface with the ProASIC3 on the Q7S board. It was +installed on the clean room PC but it can also be found +[on the Traq platform](https://trac2.xiphos.ca/manual/attachment/wiki/WikiStart/libpa3-1.3.4.tar.gz). + +For more information, see Q7S datasheet. + +## Creating files with cat and echo + +The only folder which can be written in the root filesystem is the `tmp` folder. + +You can create a simple file with initial content with `echo` + +```sh +echo "Hallo Welt" > /tmp/test.txt +cat /tmp/test.txt +``` + +For more useful combinations, see this [link](https://www.freecodecamp.org/news/the-cat-command-in-linux-how-to-create-a-text-file-with-cat-or-touch/). + +## Using `system` when debugging + +Please note that when using a `system` call in C++/C code and debugging, a new thread will be +spawned which will appear on the left in Eclipse or Xilinx SDK as a `sh` program. +The debugger might attach to this child process automatically, depending on debugger configuration, +and the process needs to be selected and continued/started manually. You can enable or disable +this behaviour by selecting or deselecting the `Attach Process Children` option in the Remote +Application Configuration for the TCF plugin like shown in the following picture + +
+ ## Libgpiod Detect all gpio device files: @@ -626,10 +652,84 @@ gpioget Example to get state: gpioget gpiochip7 14 -Both the MIOs and EMIOs can be accessed via the zynq_gpio instance which comprises 118 pins -(54 MIOs and 64 EMIOs). +Both the MIOs and EMIOs can be accessed via the zynq_gpio instance which +comprises 118 pins (54 MIOs and 64 EMIOs). -## Running the EIVE OBSW on a Raspberry Pi +## Xilinx UARTLIE + +Get info about ttyUL* devices +```` +cat /proc/tty/driver +```` + +## I2C + +Getting information about I2C device +```` +ls /sys/class/i2c-dev/i2c-0/device/device/driver +```` +This shows the memory mapping of /dev/i2c-0 + +## CAN + +```sh +ip link set can0 down +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) +```` +cansend can0 -i99 99 88 77 11 33 11 22 99 +```` +For Q7S use this: +```` +cansend can0 5A1#11.22.33.44.55.66.77.88 +```` +Turn loopback mode on: +```` +ip link set can0 type can bitrate 1000000 loopback on +```` +Reading data from CAN: +```` +candump can0 +```` + +## Useful Q7S Linux Commands + +Display currently running image: + +```sh +xsc_boot_copy +``` + +Rebooting currently running image: + +```sh +xsc_boot_copy -r +``` + +## Preparation of a fresh rootfs and SD card + +This section summarizes important changes between a fresh rootfs and the current +EIVE implementation + +### rootfs + +- Mount point `/mnt/sd0` created for SD card 0. Created with `mkdir` +- Mount point `/mnt/sd1` created for SD card 1. Created with `mkdir` +- Folder `scripts` in `/home/root` folder. +- `scripts` folder currently contains `update_main_components.sh` script + +### SD Cards + +- Folder `bin` for binaries, for example the OBSW +- Folder `misc` for miscellaneous files +- Folder `tc` for telecommands +- Folder `tm` for telemetry +- Folder `xdi` for XDI components (e.g. for firmware or device tree updates) + +# 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. @@ -645,26 +745,20 @@ sudo apt-get install gpiod libgpiod-dev to install the required GPIO libraries before cloning the system root folder. -## Special notes on Eclipse +# Flight Software Framework (FSFW) -When using Eclipse, there are two special build variables in the project properties -→ C/C++ Build → 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. +An EIVE fork of the FSFW is submodules into this repository. +To add the master upstream branch and merge changes and updates from it +into the fork, run the following command in the fsfw folder first: -## Xilinx UARTLIE -Get info about ttyUL* devices -```` -cat /proc/tty/driver -```` +```sh +git remote add upstream https://egit.irs.uni-stuttgart.de/fsfw/fsfw.git +git remote update --prune +``` -## I2C -Getting information about I2C device -```` -ls /sys/class/i2c-dev/i2c-0/device/device/driver -```` -This shows the memory mapping of /dev/i2c-0 +After that, an update can be merged by running +<<<<<<< HEAD ## Useful Q7S Linux Commands Rebooting currently running image: ```` @@ -688,4 +782,11 @@ hwclock -w Reading the real time clock ```` hwclock --show -```` \ No newline at end of file +```` +======= +```sh +git merge upstream/master +``` + +Alternatively, changes from other upstreams (forks) and branches can be merged like that in the same way. +>>>>>>> develop diff --git a/bsp_q7s/CMakeLists.txt b/bsp_q7s/CMakeLists.txt index abf785e6..3bc9aa4e 100644 --- a/bsp_q7s/CMakeLists.txt +++ b/bsp_q7s/CMakeLists.txt @@ -2,13 +2,15 @@ target_sources(${TARGET_NAME} PUBLIC main.cpp ) +add_subdirectory(boardtest) + if(Q7S_SIMPLE_MODE) add_subdirectory(simple) else() add_subdirectory(boardconfig) add_subdirectory(comIF) - add_subdirectory(boardtest) add_subdirectory(gpio) add_subdirectory(core) - add_subdirectory(spiCallbacks) + add_subdirectory(memory) + add_subdirectory(spiCallbacks) endif() diff --git a/bsp_q7s/boardconfig/q7sConfig.h.in b/bsp_q7s/boardconfig/q7sConfig.h.in index 6ee84821..11dec25c 100644 --- a/bsp_q7s/boardconfig/q7sConfig.h.in +++ b/bsp_q7s/boardconfig/q7sConfig.h.in @@ -1,7 +1,20 @@ #ifndef BSP_Q7S_BOARDCONFIG_Q7S_CONFIG_H_ #define BSP_Q7S_BOARDCONFIG_Q7S_CONFIG_H_ +#include + #cmakedefine01 Q7S_SIMPLE_MODE + +#define Q7S_SD_NONE 0 +#define Q7S_SD_COLD_REDUNDANT 1 +#define Q7S_SD_HOT_REDUNDANT 2 +// The OBSW will perform different actions to set up the SD cards depending on the flag set here +// Set to Q7S_SD_NONE: Don't do anything +// Set to Q7S_COLD_REDUNDANT: On startup, get the prefered SD card, turn it on and mount it, and +// turn off the second SD card if it is on +// Set to Q7S_HOT_REDUNDANT: On startup, turn on both SD cards and mount them +#define Q7S_SD_CARD_CONFIG Q7S_SD_COLD_REDUNDANT + #define Q7S_ADD_RTD_DEVICES 0 /* Only one of those 2 should be enabled! */ @@ -11,4 +24,12 @@ #define Q7S_ADD_SPI_TEST 0 #endif +#define Q7S_SIMPLE_ADD_FILE_SYSTEM_TEST 0 + +namespace config { + +static const uint32_t SD_CARD_ACCESS_MUTEX_TIMEOUT = 50; + +} + #endif /* BSP_Q7S_BOARDCONFIG_Q7S_CONFIG_H_ */ diff --git a/bsp_q7s/boardtest/CMakeLists.txt b/bsp_q7s/boardtest/CMakeLists.txt index 0599b73f..1cda38ca 100644 --- a/bsp_q7s/boardtest/CMakeLists.txt +++ b/bsp_q7s/boardtest/CMakeLists.txt @@ -1,4 +1,6 @@ target_sources(${TARGET_NAME} PRIVATE + FileSystemTest.cpp + Q7STestTask.cpp ) diff --git a/bsp_q7s/boardtest/FileSystemTest.cpp b/bsp_q7s/boardtest/FileSystemTest.cpp new file mode 100644 index 00000000..1de5bb7a --- /dev/null +++ b/bsp_q7s/boardtest/FileSystemTest.cpp @@ -0,0 +1,21 @@ +#include "FileSystemTest.h" +#include "fsfw/timemanager/Stopwatch.h" + +#include +#include + +FileSystemTest::FileSystemTest() { + using namespace std; + SdCard sdCard = SdCard::SDC0; + cout << "SD Card Test for SD card " << static_cast(sdCard) << std::endl; + //Stopwatch stopwatch; + std::system("q7hw sd info all > /tmp/sd_status.txt"); + //stopwatch.stop(true); + std::system("q7hw sd set 0 on > /tmp/sd_set.txt"); + //stopwatch.stop(true); + std::system("q7hw sd set 0 off > /tmp/sd_set.txt"); + //stopwatch.stop(true); +} + +FileSystemTest::~FileSystemTest() { +} diff --git a/bsp_q7s/boardtest/FileSystemTest.h b/bsp_q7s/boardtest/FileSystemTest.h new file mode 100644 index 00000000..907c86ca --- /dev/null +++ b/bsp_q7s/boardtest/FileSystemTest.h @@ -0,0 +1,18 @@ +#ifndef BSP_Q7S_BOARDTEST_FILESYSTEMTEST_H_ +#define BSP_Q7S_BOARDTEST_FILESYSTEMTEST_H_ + +enum SdCard { + SDC0, + SDC1 +}; + +class FileSystemTest { +public: + FileSystemTest(); + virtual~ FileSystemTest(); +private: +}; + + + +#endif /* BSP_Q7S_BOARDTEST_FILESYSTEMTEST_H_ */ diff --git a/bsp_q7s/boardtest/Q7STestTask.cpp b/bsp_q7s/boardtest/Q7STestTask.cpp new file mode 100644 index 00000000..a1470b79 --- /dev/null +++ b/bsp_q7s/boardtest/Q7STestTask.cpp @@ -0,0 +1,67 @@ +#include "Q7STestTask.h" + +#include "fsfw/timemanager/Stopwatch.h" +#include "fsfw/tasks/TaskFactory.h" + +#include "bsp_q7s/memory/scratchApi.h" + +#include +#include +#include + +Q7STestTask::Q7STestTask(object_id_t objectId): TestTask(objectId) { +} + +ReturnValue_t Q7STestTask::performOneShotAction() { + //sdCardTests(); + testScratchApi(); + return TestTask::performOneShotAction(); +} + +void Q7STestTask::sdCardTests() { + using namespace std; + Stopwatch stopwatch; + int result = std::system("q7hw sd info all > /tmp/sd_status.txt"); + if(result != 0) { + sif::debug << "system call failed with " << result << endl; + } + ifstream sdStatus("/tmp/sd_status.txt"); + string line; + uint8_t idx = 0; + while (std::getline(sdStatus, line)) { + std::istringstream iss(line); + string word; + while(iss >> word) { + if(word == "on") { + sif::info << "SD card " << static_cast(idx) << " is on" << endl; + } + else if(word == "off") { + sif::info << "SD card " << static_cast(idx) << " is off" << endl; + } + } + idx++; + } + std::remove("/tmp/sd_status.txt"); +} + +void Q7STestTask::fileTests() { + using namespace std; + ofstream testFile("/tmp/test.txt"); + testFile << "Hallo Welt" << endl; + testFile.close(); + + system("echo \"Hallo Welt\" > /tmp/test2.txt"); + system("echo \"Hallo Welt\""); +} + +void Q7STestTask::testScratchApi() { + ReturnValue_t result = scratch::writeNumber("TEST", 1); + if(result != HasReturnvaluesIF::RETURN_OK) { + sif::debug << "Q7STestTask::scratchApiTest: Writing number failed" << std::endl; + } + int number = 0; + result = scratch::readNumber("TEST", number); + if(result != HasReturnvaluesIF::RETURN_OK) { + sif::debug << "Q7STestTask::scratchApiTest: Reading number failed" << std::endl; + } +} diff --git a/bsp_q7s/boardtest/Q7STestTask.h b/bsp_q7s/boardtest/Q7STestTask.h new file mode 100644 index 00000000..664a8fa2 --- /dev/null +++ b/bsp_q7s/boardtest/Q7STestTask.h @@ -0,0 +1,20 @@ +#ifndef BSP_Q7S_BOARDTEST_Q7STESTTASK_H_ +#define BSP_Q7S_BOARDTEST_Q7STESTTASK_H_ + +#include "test/testtasks/TestTask.h" + +class Q7STestTask: public TestTask { +public: + Q7STestTask(object_id_t objectId); +private: + ReturnValue_t performOneShotAction() override; + + void sdCardTests(); + void fileTests(); + + void testScratchApi(); + +}; + + +#endif /* BSP_Q7S_BOARDTEST_Q7STESTTASK_H_ */ diff --git a/bsp_q7s/core/CoreController.cpp b/bsp_q7s/core/CoreController.cpp index 253efd91..c4863260 100644 --- a/bsp_q7s/core/CoreController.cpp +++ b/bsp_q7s/core/CoreController.cpp @@ -1,4 +1,7 @@ #include "CoreController.h" +#include "q7sConfig.h" + +#include "../memory/SdCardManager.h" CoreController::CoreController(object_id_t objectId): ExtendedControllerBase(objectId, objects::NO_OBJECT, 5) { @@ -20,7 +23,126 @@ LocalPoolDataSetBase* CoreController::getDataSetHandle(sid_t sid) { return nullptr; } +ReturnValue_t CoreController::initialize() { + return sdCardInit(); +} + ReturnValue_t CoreController::checkModeCommand(Mode_t mode, Submode_t submode, uint32_t *msToReachTheMode) { return HasReturnvaluesIF::RETURN_OK; } + +ReturnValue_t CoreController::sdCardInit() { +#if Q7S_SD_CARD_CONFIG == Q7S_SD_NONE + sif::info << "No SD card initialization will be performed" << std::endl; + return HasReturnvaluesIF::RETURN_OK; +#else + SdCardManager* sdcMan = SdCardManager::instance(); + + // Create update status file + ReturnValue_t result = sdcMan->updateSdCardStateFile(); + if(result != HasReturnvaluesIF::RETURN_OK) { + sif::warning << "CoreController::initialize: Updating SD card state file failed" + << std::endl; + } + + auto sdStatus = std::pair(sd::SdStatus::OFF, sd::SdStatus::OFF); + result = sdcMan->getSdCardActiveStatus(sdStatus); + if(result != HasReturnvaluesIF::RETURN_OK) { + sif::warning << "Getting SD card activity status failed" << std::endl; + } + + // Use a lambda to avoid duplicate code + auto setUpSdCard = [&](sd::SdCard sdCard, sd::SdStatus status, std::string sdString) { + std::string mountString; + if(sdCard == sd::SdCard::SLOT_0) { + mountString = SdCardManager::SD_0_MOUNT_POINT; + } + else { + mountString = SdCardManager::SD_1_MOUNT_POINT; + } + + if(status == sd::SdStatus::OFF) { + sif::info << "Switching on and mounting SD card " << sdString << " at " << + mountString << std::endl; + return sdcMan->switchOnSdCard(sdCard, true, &sdStatus); + } + else if(status == sd::SdStatus::ON) { + sif::info << "Mounting SD card " << sdString << " at " << mountString << std::endl; + return sdcMan->mountSdCard(sdCard); + } + else { + sif::info << "SD card " << sdString << " already on and mounted at " << + mountString << std::endl; + return SdCardManager::ALREADY_MOUNTED; + } + }; + +#if Q7S_SD_CARD_CONFIG == Q7S_SD_COLD_REDUNDANT + sd::SdCard preferredSdCard = sd::SdCard::SLOT_0; + result = sdcMan->getPreferredSdCard(preferredSdCard); + if(result != HasReturnvaluesIF::RETURN_OK) { + sif::warning << "Could not get preferred SD card information from the scratch buffer" + << std::endl; + } + std::string preferredString; + sd::SdStatus preferredStatus = sd::SdStatus::OFF; + + sd::SdStatus otherStatus = sd::SdStatus::OFF; + std::string otherString; + sd::SdCard otherSdc = sd::SdCard::SLOT_0; + + if(preferredSdCard == sd::SdCard::SLOT_0) { + preferredStatus = sdStatus.first; + preferredString = "0"; + otherSdc = sd::SdCard::SLOT_1; + otherStatus = sdStatus.second; + otherString = "1"; + } + else { + preferredString = "1"; + preferredStatus = sdStatus.second; + otherStatus = sdStatus.first; + otherSdc = sd::SdCard::SLOT_0; + otherString = "0"; + } + + sif::info << "Cold redundant SD card configuration, preferred SD card " << + preferredString << std::endl; + + result = setUpSdCard(preferredSdCard, preferredStatus, preferredString); + if(result != SdCardManager::ALREADY_MOUNTED and result != HasReturnvaluesIF::RETURN_OK) { + sif::warning << "Setting up preferred card " << otherString << + " in cold redundant mode failed" << std::endl; + // Try other SD card and mark set up operation as failed + setUpSdCard(otherSdc, otherStatus, otherString); + result = HasReturnvaluesIF::RETURN_FAILED; + } + + if(result != HasReturnvaluesIF::RETURN_FAILED and otherStatus != sd::SdStatus::OFF) { + sif::info << "Switching off secondary SD card " << otherString << std::endl; + // Switch off other SD card in cold redundant mode if setting up preferred one walked + // without issues + result = sdcMan->switchOffSdCard(otherSdc, otherStatus, &sdStatus); + if(result != HasReturnvaluesIF::RETURN_OK and result != SdCardManager::ALREADY_OFF) { + sif::warning << "Switching off secondary SD card " << otherString << + " in cold redundant mode failed" << std::endl; + } + } + + // Update status file + sdcMan->updateSdCardStateFile(); + return HasReturnvaluesIF::RETURN_OK; +#elif Q7S_SD_CARD_CONFIG == Q7S_SD_HOT_REDUNDANT + sif::info << "Hot redundant SD card configuration" << std::endl; + + setUpSdCard(sd::SdCard::SLOT_0, sdStatus.first, "0"); + setUpSdCard(sd::SdCard::SLOT_1, sdStatus.second, "1"); + // Update status file + sdcMan->updateSdCardStateFile(); + return HasReturnvaluesIF::RETURN_OK; +#endif + +#endif /* Q7S_SD_CARD_CONFIG != Q7S_SD_NONE */ + +} diff --git a/bsp_q7s/core/CoreController.h b/bsp_q7s/core/CoreController.h index bc8a1581..940a9097 100644 --- a/bsp_q7s/core/CoreController.h +++ b/bsp_q7s/core/CoreController.h @@ -7,6 +7,8 @@ class CoreController: public ExtendedControllerBase { public: CoreController(object_id_t objectId); + ReturnValue_t initialize() override; + ReturnValue_t handleCommandMessage(CommandMessage *message) override; void performControlOperation() override; private: @@ -15,6 +17,8 @@ private: LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override; ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, uint32_t *msToReachTheMode); + + ReturnValue_t sdCardInit(); }; diff --git a/bsp_q7s/core/InitMission.cpp b/bsp_q7s/core/InitMission.cpp index 3e655255..2bc334b9 100644 --- a/bsp_q7s/core/InitMission.cpp +++ b/bsp_q7s/core/InitMission.cpp @@ -44,6 +44,7 @@ void initmission::initMission() { void initmission::initTasks() { TaskFactory* factory = TaskFactory::instance(); + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; if(factory == nullptr) { /* Should never happen ! */ return; @@ -54,11 +55,18 @@ void initmission::initTasks() { void (*missedDeadlineFunc) (void) = nullptr; #endif + PeriodicTaskIF* coreController = factory->createPeriodicTask( + "CORE_CTRL", 60, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.4, missedDeadlineFunc); + result = coreController->addComponent(objects::CORE_CONTROLLER); + if(result != HasReturnvaluesIF::RETURN_OK) { + initmission::printAddObjectError("CORE_CTRL", objects::CORE_CONTROLLER); + + } + /* TMTC Distribution */ PeriodicTaskIF* tmTcDistributor = factory->createPeriodicTask( "DIST", 40, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.2, missedDeadlineFunc); - ReturnValue_t result = tmTcDistributor->addComponent( - objects::CCSDS_PACKET_DISTRIBUTOR); + result = tmTcDistributor->addComponent(objects::CCSDS_PACKET_DISTRIBUTOR); if(result != HasReturnvaluesIF::RETURN_OK) { initmission::printAddObjectError("CCSDS_DISTRIB", objects::CCSDS_PACKET_DISTRIBUTOR); } @@ -229,6 +237,7 @@ void initmission::initTasks() { tmTcDistributor->startTask(); udpBridgeTask->startTask(); udpPollingTask->startTask(); + coreController->startTask(); #if TE0720 == 0 uartPst->startTask(); diff --git a/bsp_q7s/core/ObjectFactory.cpp b/bsp_q7s/core/ObjectFactory.cpp index 91a26d8a..7389d5ff 100644 --- a/bsp_q7s/core/ObjectFactory.cpp +++ b/bsp_q7s/core/ObjectFactory.cpp @@ -1,3 +1,4 @@ +#include #include "ObjectFactory.h" #include "OBSWConfig.h" #include "tmtc/apid.h" @@ -643,6 +644,11 @@ void ObjectFactory::produce(void* args){ new UdpTmTcBridge(objects::UDP_BRIDGE, objects::CCSDS_PACKET_DISTRIBUTOR); new UdpTcPollingTask(objects::UDP_POLLING_TASK, objects::UDP_BRIDGE); + /* Test Task */ +#if OBSW_ADD_TEST_CODE == 1 + new Q7STestTask(objects::TEST_TASK); +#endif + #if TE0720 == 1 && TEST_LIBGPIOD == 1 /* Configure MIO0 as input */ GpiodRegular gpioConfigMio0(std::string("gpiochip0"), 0, @@ -728,4 +734,5 @@ void ObjectFactory::produce(void* args){ #if Q7S_ADD_SPI_TEST == 1 new SpiTestClass(objects::SPI_TEST, gpioComIF); #endif + } diff --git a/bsp_q7s/main.cpp b/bsp_q7s/main.cpp index 93968b76..9ce0dca2 100644 --- a/bsp_q7s/main.cpp +++ b/bsp_q7s/main.cpp @@ -6,12 +6,15 @@ #include "simple/simple.h" #endif +#include + /** * @brief This is the main program for the target hardware. * @return */ int main(void) { + using namespace std; #if Q7S_SIMPLE_MODE == 0 return obsw::obsw(); #else diff --git a/bsp_q7s/memory/CMakeLists.txt b/bsp_q7s/memory/CMakeLists.txt index 2ccdc7e2..6c7d0a94 100644 --- a/bsp_q7s/memory/CMakeLists.txt +++ b/bsp_q7s/memory/CMakeLists.txt @@ -1,4 +1,5 @@ target_sources(${TARGET_NAME} PRIVATE - FileSystemManager.cpp - SdCardAccess.cpp + FileSystemHandler.cpp + SdCardManager.cpp + scratchApi.cpp ) \ No newline at end of file diff --git a/bsp_q7s/memory/FileSystemHandler.cpp b/bsp_q7s/memory/FileSystemHandler.cpp new file mode 100644 index 00000000..1519b92b --- /dev/null +++ b/bsp_q7s/memory/FileSystemHandler.cpp @@ -0,0 +1,184 @@ +#include "FileSystemHandler.h" + +#include "fsfw/tasks/TaskFactory.h" +#include "fsfw/memory/GenericFileSystemMessage.h" +#include "fsfw/ipc/QueueFactory.h" + +#include + +FileSystemHandler::FileSystemHandler(object_id_t fileSystemHandler): + SystemObject(fileSystemHandler) { + mq = QueueFactory::instance()->createMessageQueue(FS_MAX_QUEUE_SIZE); +} + +FileSystemHandler::~FileSystemHandler() { + QueueFactory::instance()->deleteMessageQueue(mq); +} + +ReturnValue_t FileSystemHandler::performOperation(uint8_t unsignedChar) { + while(true) { + try { + fileSystemHandlerLoop(); + } + catch(std::bad_alloc& e) { + // Restart OBSW, hints at a memory leak + sif::error << "Allocation error in FileSystemHandler::performOperation" + << e.what() << std::endl; + // TODO: If we trigger an event, it might not get sent because were restarting + // Set up an error file or a special flag in the scratch buffer. + // TODO: CoreController: Implement function to restart OBC + } + } +} + + +void FileSystemHandler::fileSystemHandlerLoop() { + CommandMessage filemsg; + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + while(true) { + if(opCounter % 5 == 0) { + fileSystemCheckup(); + } + result = mq->receiveMessage(&filemsg); + if(result == MessageQueueIF::EMPTY) { + break; + } + else if(result != HasReturnvaluesIF::RETURN_FAILED) { + sif::warning << "FileSystemHandler::performOperation: Message reception failed!" + << std::endl; + break; + } + Command_t command = filemsg.getCommand(); + switch(command) { + case(GenericFileSystemMessage::CMD_CREATE_DIRECTORY): { + break; + } + case(GenericFileSystemMessage::CMD_CREATE_FILE): { + break; + } + } + opCounter++; + } + + // This task will have a low priority and will run permanently in the background + // so we will just run in a permanent loop here and check file system + // messages permanently + TaskFactory::instance()->delayTask(1000); +} + +void FileSystemHandler::fileSystemCheckup() { + SdCardManager::SdStatusPair statusPair; + sdcMan->getSdCardActiveStatus(statusPair); + sd::SdCard preferredSdCard; + sdcMan->getPreferredSdCard(preferredSdCard); + if((preferredSdCard == sd::SdCard::SLOT_0) and + (statusPair.first == sd::SdStatus::MOUNTED)) { + currentMountPrefix = SdCardManager::SD_0_MOUNT_POINT; + } + if((preferredSdCard == sd::SdCard::SLOT_1) and + (statusPair.second == sd::SdStatus::MOUNTED)) { + currentMountPrefix = SdCardManager::SD_1_MOUNT_POINT; + } + else { + std::string sdString; + if(preferredSdCard == sd::SdCard::SLOT_0) { + sdString = "0"; + } + else { + sdString = "1"; + } + sif::warning << "FileSystemHandler::performOperation: Inconsistent" << + " state detected. Preferred SD card is " << sdString << + " but does not appear to be mounted. Attempting fix.." << std::endl; + // This function will appear to fix the inconsistent state + ReturnValue_t result = sdcMan->sanitizeState(&preferredSdCard, &statusPair); + if(result != HasReturnvaluesIF::RETURN_OK) { + // Oh no. + // TODO: Trigger medium severity event + sif::error << "Fix failed" << std::endl; + } + } +} + +MessageQueueId_t FileSystemHandler::getCommandQueue() const { + return mq->getId(); +} + +ReturnValue_t FileSystemHandler::initialize() { + sdcMan = SdCardManager::instance(); + sd::SdCard preferredSdCard; + ReturnValue_t result = sdcMan->getPreferredSdCard(preferredSdCard); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if(preferredSdCard == sd::SdCard::SLOT_0) { + currentMountPrefix = SdCardManager::SD_0_MOUNT_POINT; + } + else if(preferredSdCard == sd::SdCard::SLOT_1) { + currentMountPrefix = SdCardManager::SD_1_MOUNT_POINT; + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t FileSystemHandler::appendToFile(const char *repositoryPath, const char *filename, + const uint8_t *data, size_t size, uint16_t packetNumber, void *args) { + // A double slash between repo and filename should not be an issue, so add it in any case + std::string fullPath = currentMountPrefix + std::string(repositoryPath) + "/" + + std::string(filename); + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t FileSystemHandler::createFile(const char *repositoryPath, const char *filename, + const uint8_t *data, size_t size, void *args) { + // A double slash between repo and filename should not be an issue, so add it in any case + std::string fullPath = currentMountPrefix + std::string(repositoryPath) + "/" + + std::string(filename); + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t FileSystemHandler::deleteFile(const char *repositoryPath, const char *filename, + void *args) { + // A double slash between repo and filename should not be an issue, so add it in any case + std::string fullPath = currentMountPrefix + std::string(repositoryPath) + "/" + + std::string(filename); + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t FileSystemHandler::createDirectory(const char *repositoryPath, void *args) { + std::string fullPath = currentMountPrefix + std::string(repositoryPath); + if(std::filesystem::exists(fullPath)) { + return DIRECTORY_ALREADY_EXISTS; + } + if(std::filesystem::create_directory(fullPath)) { + return HasReturnvaluesIF::RETURN_OK; + } + sif::warning << "Creating directory " << fullPath << " failed" << std::endl; + return GENERIC_FILE_ERROR; +} + +ReturnValue_t FileSystemHandler::removeDirectory(const char *repositoryPath, + bool deleteRecurively, void *args) { + std::string fullPath = currentMountPrefix + std::string(repositoryPath); + if(not std::filesystem::exists(fullPath)) { + return DIRECTORY_DOES_NOT_EXIST; + } + std::error_code err; + if(not deleteRecurively) { + if(std::filesystem::remove(fullPath, err)) { + return HasReturnvaluesIF::RETURN_OK; + } + else { + // Check error code. Most probably denied permissions because folder is not empty + } + } + else { + if(std::filesystem::remove_all(fullPath, err)) { + return HasReturnvaluesIF::RETURN_OK; + } + else { + // Check error code + } + } + + return HasReturnvaluesIF::RETURN_OK; +} diff --git a/bsp_q7s/memory/FileSystemHandler.h b/bsp_q7s/memory/FileSystemHandler.h new file mode 100644 index 00000000..886fa574 --- /dev/null +++ b/bsp_q7s/memory/FileSystemHandler.h @@ -0,0 +1,56 @@ +#ifndef BSP_Q7S_MEMORY_FILESYSTEMHANDLER_H_ +#define BSP_Q7S_MEMORY_FILESYSTEMHANDLER_H_ + +#include "SdCardManager.h" +#include "OBSWConfig.h" + +#include "fsfw/ipc/MessageQueueIF.h" +#include "fsfw/tasks/ExecutableObjectIF.h" +#include "fsfw/objectmanager/SystemObject.h" +#include "fsfw/memory/HasFileSystemIF.h" + +#include + +class FileSystemHandler: public SystemObject, + public ExecutableObjectIF, + public HasFileSystemIF { +public: + FileSystemHandler(object_id_t fileSystemHandler); + virtual~ FileSystemHandler(); + + ReturnValue_t performOperation(uint8_t) override; + + ReturnValue_t initialize() override; + + /** + * Function to get the MessageQueueId_t of the implementing object + * @return MessageQueueId_t of the object + */ + MessageQueueId_t getCommandQueue() const override; + +private: + MessageQueueIF* mq = nullptr; + std::string currentMountPrefix = SdCardManager::SD_0_MOUNT_POINT; + static constexpr uint32_t FS_MAX_QUEUE_SIZE = config::OBSW_FILESYSTEM_HANDLER_QUEUE_SIZE; + SdCardManager* sdcMan = nullptr; + uint8_t opCounter = 0; + + void fileSystemHandlerLoop(); + void fileSystemCheckup(); + + ReturnValue_t appendToFile(const char* repositoryPath, + const char* filename, const uint8_t* data, size_t size, + uint16_t packetNumber, void* args = nullptr) override; + ReturnValue_t createFile(const char* repositoryPath, + const char* filename, const uint8_t* data = nullptr, + size_t size = 0, void* args = nullptr) override; + ReturnValue_t deleteFile(const char* repositoryPath, + const char* filename, void* args = nullptr) override; + ReturnValue_t createDirectory(const char* repositoryPath, void* args = nullptr) override; + ReturnValue_t removeDirectory(const char* repositoryPath, bool deleteRecurively = false, + void* args = nullptr) override; +}; + + + +#endif /* BSP_Q7S_MEMORY_FILESYSTEMMANAGER_H_ */ diff --git a/bsp_q7s/memory/FileSystemManager.cpp b/bsp_q7s/memory/FileSystemManager.cpp deleted file mode 100644 index 40c8e58a..00000000 --- a/bsp_q7s/memory/FileSystemManager.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "FileSystemManager.h" - -class FileSystemManager { -public: - -private: -}; diff --git a/bsp_q7s/memory/FileSystemManager.h b/bsp_q7s/memory/FileSystemManager.h deleted file mode 100644 index 4fc8dc52..00000000 --- a/bsp_q7s/memory/FileSystemManager.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef BSP_Q7S_MEMORY_FILESYSTEMMANAGER_H_ -#define BSP_Q7S_MEMORY_FILESYSTEMMANAGER_H_ - - - - - -#endif /* BSP_Q7S_MEMORY_FILESYSTEMMANAGER_H_ */ diff --git a/bsp_q7s/memory/SdCardAccess.cpp b/bsp_q7s/memory/SdCardAccess.cpp deleted file mode 100644 index 3d5f12b9..00000000 --- a/bsp_q7s/memory/SdCardAccess.cpp +++ /dev/null @@ -1,4 +0,0 @@ -#include "SdCardAccess.h" - -SdCardAccess::SdCardAccess() { -} diff --git a/bsp_q7s/memory/SdCardAccess.h b/bsp_q7s/memory/SdCardAccess.h deleted file mode 100644 index ba273d09..00000000 --- a/bsp_q7s/memory/SdCardAccess.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef BSP_Q7S_MEMORY_SDCARDACCESS_H_ -#define BSP_Q7S_MEMORY_SDCARDACCESS_H_ - -class SdCardAccess { -public: - SdCardAccess(); -private: -}; - - -#endif /* BSP_Q7S_MEMORY_SDCARDACCESS_H_ */ diff --git a/bsp_q7s/memory/SdCardManager.cpp b/bsp_q7s/memory/SdCardManager.cpp new file mode 100644 index 00000000..5a50665b --- /dev/null +++ b/bsp_q7s/memory/SdCardManager.cpp @@ -0,0 +1,333 @@ +#include "SdCardManager.h" +#include "scratchApi.h" + +#include "linux/utility/utility.h" + +#include "fsfw/ipc/MutexFactory.h" +#include "fsfw/serviceinterface/ServiceInterface.h" + +#include +#include +#include + +SdCardManager* SdCardManager::factoryInstance = nullptr; + +SdCardManager::SdCardManager() { +} + +SdCardManager::~SdCardManager() { +} + +void SdCardManager::create() { + if(factoryInstance == nullptr) { + factoryInstance = new SdCardManager(); + } +} + +SdCardManager* SdCardManager::instance() { + SdCardManager::create(); + return SdCardManager::factoryInstance; +} + +ReturnValue_t SdCardManager::switchOnSdCard(sd::SdCard sdCard, bool doMountSdCard, + SdStatusPair* statusPair) { + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + if(statusPair == nullptr) { + statusPair = std::make_unique().get(); + result = getSdCardActiveStatus(*statusPair); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + } + + // Not allowed, this function turns on one SD card + if(sdCard == sd::SdCard::BOTH) { + sif::warning << "SdCardManager::switchOffSdCard: API does not allow sd::SdStatus::BOTH" + << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + + sd::SdStatus targetStatus; + if(sdCard == sd::SdCard::SLOT_0) { + targetStatus = statusPair->first; + } + else if(sdCard == sd::SdCard::SLOT_1) { + targetStatus = statusPair->second; + } + + auto switchCall = [&]() { + if(targetStatus == sd::SdStatus::ON) { + if(not doMountSdCard) { + return ALREADY_ON; + } + else { + return mountSdCard(sdCard); + } + } + else if(targetStatus == sd::SdStatus::MOUNTED) { + return ALREADY_MOUNTED; + } + else if(targetStatus == sd::SdStatus::OFF) { + return setSdCardState(sdCard, true); + } + else { + return HasReturnvaluesIF::RETURN_FAILED; + } + }; + + result = switchCall(); + + if(result != HasReturnvaluesIF::RETURN_OK or not doMountSdCard) { + return result; + } + + return mountSdCard(sdCard); +} + +ReturnValue_t SdCardManager::switchOffSdCard(sd::SdCard sdCard, bool doUnmountSdCard, + SdStatusPair* statusPair) { + std::pair active; + ReturnValue_t result = getSdCardActiveStatus(active); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + // Not allowed, this function turns off one SD card + if(sdCard == sd::SdCard::BOTH) { + sif::warning << "SdCardManager::switchOffSdCard: API does not allow sd::SdStatus::BOTH" + << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + if(sdCard == sd::SdCard::SLOT_0) { + if(active.first == sd::SdStatus::OFF) { + return ALREADY_OFF; + } + } + else if(sdCard == sd::SdCard::SLOT_1) { + if(active.second == sd::SdStatus::OFF) { + return ALREADY_OFF; + } + } + + if(doUnmountSdCard) { + result = unmountSdCard(sdCard); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + } + + return setSdCardState(sdCard, false); +} + +ReturnValue_t SdCardManager::setSdCardState(sd::SdCard sdCard, bool on) { + using namespace std; + string sdstring = ""; + string statestring = ""; + if(sdCard == sd::SdCard::SLOT_0) { + sdstring = "0"; + } + else if(sdCard == sd::SdCard::SLOT_1) { + sdstring = "1"; + } + if(on) { + statestring = "on"; + } + else { + statestring = "off"; + } + ostringstream command; + command << "q7hw sd set " << sdstring << " " << statestring; + int result = system(command.str().c_str()); + if(result == 0) { + return HasReturnvaluesIF::RETURN_OK; + } + sif::warning << "SdCardManager::setSdCardState: system call failed with code " << + result << std::endl; + return SYSTEM_CALL_ERROR; +} + +ReturnValue_t SdCardManager::getSdCardActiveStatus(SdStatusPair& active) { + using namespace std; + if(not filesystem::exists(SD_STATE_FILE)) { + return STATUS_FILE_NEXISTS; + } + + // Now the file should exist in any case. Still check whether it exists. + fstream sdStatus(SD_STATE_FILE); + if (not sdStatus.good()) { + return STATUS_FILE_NEXISTS; + } + string line; + uint8_t idx = 0; + sd::SdCard currentSd = sd::SdCard::SLOT_0; + // Process status file line by line + while (std::getline(sdStatus, line)) { + processSdStatusLine(active, line, idx, currentSd); + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t SdCardManager::mountSdCard(sd::SdCard sdCard) { + using namespace std; + if(sdCard == sd::SdCard::BOTH) { + sif::warning << "SdCardManager::mountSdCard: API does not allow sd::SdStatus::BOTH" + << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + string mountDev; + string mountPoint; + if(sdCard == sd::SdCard::SLOT_0) { + mountDev = SD_0_DEV_NAME; + mountPoint = SD_0_MOUNT_POINT; + } + else if(sdCard == sd::SdCard::SLOT_1) { + mountDev = SD_1_DEV_NAME; + mountPoint = SD_1_MOUNT_POINT; + } + if(not filesystem::exists(mountDev)) { + sif::warning << "SdCardManager::mountSdCard: Device file does not exists. Make sure to" + " turn on the SD card" << std::endl; + return MOUNT_ERROR; + } + + string sdMountCommand = "mount " + mountDev + " " + mountPoint; + int result = system(sdMountCommand.c_str()); + if (result != 0) { + utility::handleSystemError(result, "SdCardManager::mountSdCard"); + return SYSTEM_CALL_ERROR; + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t SdCardManager::unmountSdCard(sd::SdCard sdCard) { + using namespace std; + if(sdCard == sd::SdCard::BOTH) { + sif::warning << "SdCardManager::unmountSdCard: API does not allow sd::SdStatus::BOTH" + << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + string mountPoint; + if(sdCard == sd::SdCard::SLOT_0) { + mountPoint = SD_0_MOUNT_POINT; + } + else if(sdCard == sd::SdCard::SLOT_1) { + mountPoint = SD_1_MOUNT_POINT; + } + if(filesystem::is_empty(mountPoint)) { + // The mount point will always exist, but if it is empty, that is strong hint that + // the SD card was not mounted properly. Still proceed with operation. + sif::warning << "SdCardManager::unmountSdCard: Mount point is empty!" << std::endl; + } + string sdUnmountCommand = "umount " + mountPoint; + int result = system(sdUnmountCommand.c_str()); + if (result != 0) { + utility::handleSystemError(result, "SdCardManager::unmountSdCard"); + return SYSTEM_CALL_ERROR; + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t SdCardManager::sanitizeState(sd::SdCard* prefSdCard, SdStatusPair* statusPair) { + if(prefSdCard == nullptr) { + prefSdCard = std::make_unique(sd::SdCard::SLOT_0).get(); + getPreferredSdCard(*prefSdCard); + } + if(statusPair == nullptr) { + statusPair = std::make_unique().get(); + getSdCardActiveStatus(*statusPair); + } + + auto sanitizerFunc = [&](sd::SdCard prefSdCard) { + if(statusPair->first == sd::SdStatus::ON) { + return mountSdCard(prefSdCard); + } + else { + return switchOnSdCard(prefSdCard, true, statusPair); + } + }; + + return sanitizerFunc(*prefSdCard); +} + +void SdCardManager::processSdStatusLine(std::pair &active, + std::string& line, uint8_t& idx, sd::SdCard& currentSd) { + using namespace std; + istringstream iss(line); + string word; + bool slotLine = false; + bool mountLine = false; + while(iss >> word) { + if (word == "Slot") { + slotLine = true; + } + if(word == "Mounted") { + mountLine = true; + } + + if(slotLine) { + if (word == "1:") { + currentSd = sd::SdCard::SLOT_1; + } + + if(word == "on") { + if(currentSd == sd::SdCard::SLOT_0) { + active.first = sd::SdStatus::ON; + } + else { + active.second = sd::SdStatus::ON; + } + } + else if (word == "off") { + if(currentSd == sd::SdCard::SLOT_0) { + active.first = sd::SdStatus::OFF; + } + else { + active.second = sd::SdStatus::OFF; + } + } + } + + if(mountLine) { + if(currentSd == sd::SdCard::SLOT_0) { + active.first = sd::SdStatus::MOUNTED; + } + else { + active.second = sd::SdStatus::MOUNTED; + } + } + + if(idx > 5) { + sif::warning << "SdCardManager::sdCardActive: /tmp/sd_status.txt has more than 6 " + "lines and might be invalid!" << std::endl; + } + } + idx++; +} + +ReturnValue_t SdCardManager::getPreferredSdCard(sd::SdCard& sdCard) const { + uint8_t prefSdCard = 0; + ReturnValue_t result = scratch::readNumber(scratch::PREFERED_SDC_KEY, prefSdCard); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + sdCard = static_cast(prefSdCard); + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t SdCardManager::setPreferredSdCard(sd::SdCard sdCard) { + if(sdCard == sd::SdCard::BOTH) { + return HasReturnvaluesIF::RETURN_FAILED; + } + return scratch::writeNumber(scratch::PREFERED_SDC_KEY, static_cast(sdCard)); +} + +ReturnValue_t SdCardManager::updateSdCardStateFile() { + // Use q7hw utility and pipe the command output into the state file + std::string updateCmd = "q7hw sd info all > " + std::string(SD_STATE_FILE); + int result = std::system(updateCmd.c_str()); + if(result == 0) { + return HasReturnvaluesIF::RETURN_OK; + } + sif::warning << "SdCardManager::updateSdCardStateFile: system call failed with code " << + result << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; +} diff --git a/bsp_q7s/memory/SdCardManager.h b/bsp_q7s/memory/SdCardManager.h new file mode 100644 index 00000000..966e6e2a --- /dev/null +++ b/bsp_q7s/memory/SdCardManager.h @@ -0,0 +1,159 @@ +#ifndef BSP_Q7S_MEMORY_SDCARDACCESSMANAGER_H_ +#define BSP_Q7S_MEMORY_SDCARDACCESSMANAGER_H_ + +#include "definitions.h" +#include "returnvalues/classIds.h" + +#include "fsfw/returnvalues/HasReturnvaluesIF.h" + +#include +#include +#include + +class MutexIF; + +/** + * @brief Manages handling of SD cards like switching them on or off or getting the current + * state + */ +class SdCardManager { + friend class SdCardAccess; +public: + using SdStatusPair = std::pair; + + static constexpr uint8_t INTERFACE_ID = CLASS_ID::SD_CARD_MANAGER; + + static constexpr ReturnValue_t ALREADY_ON = + HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 0); + static constexpr ReturnValue_t ALREADY_MOUNTED = + HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 1); + static constexpr ReturnValue_t ALREADY_OFF = + HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 2); + static constexpr ReturnValue_t STATUS_FILE_NEXISTS = + HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 10); + static constexpr ReturnValue_t STATUS_FILE_FORMAT_INVALID = + HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 11); + static constexpr ReturnValue_t MOUNT_ERROR = + HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 12); + static constexpr ReturnValue_t UNMOUNT_ERROR = + HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 13); + static constexpr ReturnValue_t SYSTEM_CALL_ERROR = + HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 14); + + // C++17 does not support constexpr std::string yet + static constexpr char SD_0_DEV_NAME[] = "/dev/mmcblk0p1"; + static constexpr char SD_1_DEV_NAME[] = "/dev/mmcblk1p1"; + static constexpr char SD_0_MOUNT_POINT[] = "/mnt/sd0"; + static constexpr char SD_1_MOUNT_POINT[] = "/mnt/sd1"; + static constexpr char SD_STATE_FILE[] = "/tmp/sd_status.txt"; + + virtual ~SdCardManager(); + + static void create(); + + /** + * Returns the single instance of the SD card manager. + */ + static SdCardManager* instance(); + + /** + * Set the preferred SD card which will determine which SD card will be used as the primary + * SD card in hot redundant and cold redundant mode. This function will not switch the + * SD cards which are currently on and mounted, this needs to be implemented by + * an upper layer by using #switchOffSdCard , #switchOnSdCard and #updateSdCardStateFile + * @param sdCard + * @return + */ + ReturnValue_t setPreferredSdCard(sd::SdCard sdCard); + + /** + * Get the currently configured preferred SD card + * @param sdCard + * @return + */ + ReturnValue_t getPreferredSdCard(sd::SdCard& sdCard) const; + + /** + * Switch on the specified SD card. + * @param sdCard + * @param doMountSdCard Mount the SD card after switching it on, which is necessary + * to use it + * @param statusPair If the status pair is already available, it can be passed here + * @return - RETURN_OK on success, ALREADY_ON if it is already on, + * SYSTEM_CALL_ERROR on system error + */ + ReturnValue_t switchOnSdCard(sd::SdCard sdCard, bool doMountSdCard = true, + SdStatusPair* statusPair = nullptr); + + /** + * Switch off the specified SD card. + * @param sdCard + * @param doUnmountSdCard Unmount the SD card before switching the card off, which makes + * the operation safer + * @param statusPair If the status pair is already available, it can be passed here + * @return - RETURN_OK on success, ALREADY_ON if it is already on, + * SYSTEM_CALL_ERROR on system error + */ + ReturnValue_t switchOffSdCard(sd::SdCard sdCard, bool doUnmountSdCard = true, + SdStatusPair* statusPair = nullptr); + + /** + * Update the state file or creates one if it does not exist. You need to call this + * function before calling #sdCardActive + * @return - RETURN_OK if the state file was updated successfully + * - SYSTEM_CALL_ERROR if the call to create the status file failed + */ + ReturnValue_t updateSdCardStateFile(); + + /** + * Get the state of the SD cards. If the state file does not exist, this function will + * take care of updating it. If it does not, the function will use the state file to get + * the status of the SD cards and set the field of the provided boolean pair. + * @param active Pair of booleans, where the first entry is the state of the first SD card + * and the second one the state of the second SD card + * @return - RETURN_OK if the state was read successfully + * - STATUS_FILE_FORMAT_INVALID if there was an issue with the state file. The user + * should call #updateSdCardStateFile again in that case + * - STATUS_FILE_NEXISTS if the status file does not exist + */ + ReturnValue_t getSdCardActiveStatus(SdStatusPair& active); + + /** + * Mount the specified SD card. This is necessary to use it. + * @param sdCard + * @return + */ + ReturnValue_t mountSdCard(sd::SdCard sdCard); + /** + * Unmount the specified SD card. This is recommended before switching it off. The SD card + * can't be used after it has been unmounted. + * @param sdCard + * @return + */ + ReturnValue_t unmountSdCard(sd::SdCard sdCard); + + /** + * In case that there is a discrepancy between the preferred SD card and the currently + * mounted one, this function will sanitize the state by attempting to mount the + * currently preferred SD card. If the caller already has state information, it can be + * passed into the function. + * @param prefSdCard Preferred SD card captured with #getPreferredSdCard + * @param statusPair Current SD card status capture with #getSdCardActiveStatus + * @throws std::bad_alloc if one of the two arguments was a nullptr and an allocation failed + * @return + */ + ReturnValue_t sanitizeState(sd::SdCard* prefSdCard = nullptr, + SdStatusPair* statusPair = nullptr); + +private: + SdCardManager(); + + ReturnValue_t setSdCardState(sd::SdCard sdCard, bool on); + + void processSdStatusLine(SdStatusPair& active, std::string& line, uint8_t& idx, + sd::SdCard& currentSd); + + static SdCardManager* factoryInstance; +}; + +#endif /* BSP_Q7S_MEMORY_SDCARDACCESSMANAGER_H_ */ diff --git a/bsp_q7s/memory/definitions.h b/bsp_q7s/memory/definitions.h new file mode 100644 index 00000000..546a6585 --- /dev/null +++ b/bsp_q7s/memory/definitions.h @@ -0,0 +1,25 @@ +#ifndef BSP_Q7S_MEMORY_DEFINITIONS_H_ +#define BSP_Q7S_MEMORY_DEFINITIONS_H_ + +#include + +namespace sd { + +enum SdStatus: uint8_t { + OFF = 0, + ON = 1, + // A mounted SD card is on as well + MOUNTED = 2 +}; + +enum SdCard: uint8_t { + SLOT_0, + SLOT_1, + BOTH +}; + +} + + + +#endif /* BSP_Q7S_MEMORY_DEFINITIONS_H_ */ diff --git a/bsp_q7s/memory/scratchApi.cpp b/bsp_q7s/memory/scratchApi.cpp new file mode 100644 index 00000000..0b159775 --- /dev/null +++ b/bsp_q7s/memory/scratchApi.cpp @@ -0,0 +1,12 @@ +#include "scratchApi.h" + +ReturnValue_t scratch::writeString(std::string name, std::string string) { + std::ostringstream oss; + oss << "xsc_scratch write " << name << " \"" << string << "\""; + int result = std::system(oss.str().c_str()); + if(result != 0) { + utility::handleSystemError(result, "scratch::String"); + return HasReturnvaluesIF::RETURN_FAILED; + } + return HasReturnvaluesIF::RETURN_OK; +} diff --git a/bsp_q7s/memory/scratchApi.h b/bsp_q7s/memory/scratchApi.h new file mode 100644 index 00000000..eceda11a --- /dev/null +++ b/bsp_q7s/memory/scratchApi.h @@ -0,0 +1,72 @@ +#ifndef BSP_Q7S_MEMORY_SCRATCHAPI_H_ +#define BSP_Q7S_MEMORY_SCRATCHAPI_H_ + +#include "fsfw/returnvalues/HasReturnvaluesIF.h" +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "linux/utility/utility.h" + +#include +#include +#include +#include +#include + +/** + * @brief API for the scratch buffer + */ +namespace scratch { + +static constexpr char PREFERED_SDC_KEY[] = "PREFSD"; + +namespace { +static uint8_t counter = 0; +} + +template::value>::type> +inline ReturnValue_t writeNumber(std::string name, T num) noexcept { + std::ostringstream oss; + oss << "xsc_scratch write " << name << " " << num; + int result = std::system(oss.str().c_str()); + if(result != 0) { + utility::handleSystemError(result, "scratch::writeNumber"); + return HasReturnvaluesIF::RETURN_FAILED; + } + return HasReturnvaluesIF::RETURN_OK; +} + +template::value>::type> +inline ReturnValue_t readNumber(std::string name, T& num) noexcept { + using namespace std; + string filename = "/tmp/sro" + std::to_string(counter++); + ostringstream oss; + oss << "xsc_scratch read " << name << " > " << filename; + + int result = std::system(oss.str().c_str()); + if(result != 0) { + utility::handleSystemError(result, "scratch::writeNumber"); + return HasReturnvaluesIF::RETURN_FAILED; + } + ifstream file(filename); + string line; + if (not std::getline(file, line)) { + return HasReturnvaluesIF::RETURN_FAILED; + } + + size_t pos = line.find("="); + std::string valueAsString = line.substr(pos + 1); + try { + num = std::stoi(valueAsString); + } + catch(std::invalid_argument& e) { + sif::warning << "scratch::readNumber: stoi call failed with " << e.what() << std::endl; + } + + std::remove(filename.c_str()); + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t writeString(std::string name, std::string string); + +} + +#endif /* BSP_Q7S_MEMORY_SCRATCHAPI_H_ */ diff --git a/bsp_q7s/simple/simple.cpp b/bsp_q7s/simple/simple.cpp index 6261bfe3..a6bb9fdf 100644 --- a/bsp_q7s/simple/simple.cpp +++ b/bsp_q7s/simple/simple.cpp @@ -1,5 +1,17 @@ #include "simple.h" +#include "q7sConfig.h" + +#if Q7S_SIMPLE_ADD_FILE_SYSTEM_TEST == 1 +#include "../boardtest/FileSystemTest.h" +#endif int simple::simple() { + cout << "-- Q7S Simple Application --" << endl; +#if Q7S_SIMPLE_ADD_FILE_SYSTEM_TEST == 1 + { + FileSystemTest fileSystemTest; + } +#endif return 0; } + diff --git a/cmake/scripts/Linux/create_cmake_debug_cfg.sh b/cmake/scripts/Linux/make_debug_cfg.sh similarity index 99% rename from cmake/scripts/Linux/create_cmake_debug_cfg.sh rename to cmake/scripts/Linux/make_debug_cfg.sh index 8c626bf4..dc21896d 100755 --- a/cmake/scripts/Linux/create_cmake_debug_cfg.sh +++ b/cmake/scripts/Linux/make_debug_cfg.sh @@ -29,3 +29,4 @@ set -x # Print command ${python} 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 + diff --git a/cmake/scripts/Linux/create_cmake_release_cfg.sh b/cmake/scripts/Linux/make_release_cfg.sh similarity index 100% rename from cmake/scripts/Linux/create_cmake_release_cfg.sh rename to cmake/scripts/Linux/make_release_cfg.sh diff --git a/cmake/scripts/Linux/ninja_debug_cfg.sh b/cmake/scripts/Linux/ninja_debug_cfg.sh new file mode 100755 index 00000000..9627ccf6 --- /dev/null +++ b/cmake/scripts/Linux/ninja_debug_cfg.sh @@ -0,0 +1,32 @@ +#!/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="Ninja" +os_fsfw="linux" +builddir="build-Debug-Host" +if [ "${OS}" = "Windows_NT" ]; then + python="py" +# Could be other OS but this works for now. +else + python="python3" +fi + +echo "Running command (without the leading +):" +set -x # Print command +${python} 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 + diff --git a/cmake/scripts/Q7S/simple/simple_make_debug_cfg.sh b/cmake/scripts/Q7S/simple/simple_make_debug_cfg.sh index b692184a..8a6c7b3f 100755 --- a/cmake/scripts/Q7S/simple/simple_make_debug_cfg.sh +++ b/cmake/scripts/Q7S/simple/simple_make_debug_cfg.sh @@ -31,5 +31,5 @@ fi echo "Running command (without the leading +):" set -x # Print command ${python} cmake_build_config.py -o "${os_fsfw}" -g "${build_generator}" -b "debug" -t "${tgt_bsp}" \ - -l"${build_dir}" -d "${definitions}" + -l "${build_dir}" -d "${definitions}" # set +x diff --git a/cmake/scripts/Q7S/simple/simple_ninja_debug_cfg.sh b/cmake/scripts/Q7S/simple/simple_ninja_debug_cfg.sh index a3a55521..965aae45 100755 --- a/cmake/scripts/Q7S/simple/simple_ninja_debug_cfg.sh +++ b/cmake/scripts/Q7S/simple/simple_ninja_debug_cfg.sh @@ -29,6 +29,6 @@ fi echo "Running command (without the leading +):" set -x # Print command ${python} cmake_build_config.py -o "${os_fsfw}" -g "${build_generator}" -b "debug" -t "${tgt_bsp}" \ - -l"${build_dir}" -d "${definitions}" + -l "${build_dir}" -d "${definitions}" # set +x diff --git a/cmake/scripts/cmake_build_config.py b/cmake/scripts/cmake_build_config.py old mode 100644 new mode 100755 diff --git a/common/config/OBSWVersion.h b/common/config/OBSWVersion.h index 7ac812e6..b796f146 100644 --- a/common/config/OBSWVersion.h +++ b/common/config/OBSWVersion.h @@ -4,7 +4,7 @@ const char* const SW_NAME = "eive"; #define SW_VERSION 1 -#define SW_SUBVERSION 2 +#define SW_SUBVERSION 3 #define SW_SUBSUBVERSION 0 #endif /* COMMON_CONFIG_OBSWVERSION_H_ */ diff --git a/doc/img/ProcessSettings.png b/doc/img/ProcessSettings.png new file mode 100644 index 00000000..5a8c3c99 Binary files /dev/null and b/doc/img/ProcessSettings.png differ diff --git a/fsfw b/fsfw index 38f2f69c..da8a4470 160000 --- a/fsfw +++ b/fsfw @@ -1 +1 @@ -Subproject commit 38f2f69c784c74cd87a10dce6c968325cf1cb472 +Subproject commit da8a4470734808bed4d872e47c192af694382c41 diff --git a/linux/csp/CspComIF.cpp b/linux/csp/CspComIF.cpp index a8f13963..07fe63d3 100644 --- a/linux/csp/CspComIF.cpp +++ b/linux/csp/CspComIF.cpp @@ -24,6 +24,8 @@ ReturnValue_t CspComIF::initializeInterface(CookieIF *cookie) { /* Perform CAN and CSP initialization only once */ if(cspDeviceMap.empty()){ + sif::info << "Performing " << canInterface << " initialization.." << std::endl; + /* Define the memory to allocate for the CSP stack */ int buf_count = 10; int buf_size = 300; @@ -57,6 +59,7 @@ ReturnValue_t CspComIF::initializeInterface(CookieIF *cookie) { sif::error << "Failed to start csp route task" << std::endl; return HasReturnvaluesIF::RETURN_FAILED; } + sif::info << canInterface << " initialized successfully" << std::endl; } uint8_t cspAddress = cspCookie->getCspAddress(); diff --git a/linux/fsfwconfig/OBSWConfig.h.in b/linux/fsfwconfig/OBSWConfig.h.in index 657b4025..294f1d91 100644 --- a/linux/fsfwconfig/OBSWConfig.h.in +++ b/linux/fsfwconfig/OBSWConfig.h.in @@ -70,6 +70,7 @@ namespace config { #endif /* Add mission configuration flags here */ +static constexpr uint32_t OBSW_FILESYSTEM_HANDLER_QUEUE_SIZE = 50; #ifdef __cplusplus } diff --git a/linux/fsfwconfig/pollingsequence/pollingSequenceFactory.cpp b/linux/fsfwconfig/pollingsequence/pollingSequenceFactory.cpp index 3771c784..3c5f570c 100644 --- a/linux/fsfwconfig/pollingsequence/pollingSequenceFactory.cpp +++ b/linux/fsfwconfig/pollingsequence/pollingSequenceFactory.cpp @@ -477,7 +477,7 @@ ReturnValue_t pst::pstUart(FixedTimeslotTaskIF *thisSequence) { thisSequence->addSlot(objects::SYRLINKS_HK_HANDLER, length * 0, DeviceHandlerIF::PERFORM_OPERATION); -#if OBSW_ADD_GPS == 1 +#if OBSW_ADD_ACS_BOARD == 1 thisSequence->addSlot(objects::GPS0_HANDLER, length * 0, DeviceHandlerIF::PERFORM_OPERATION); thisSequence->addSlot(objects::GPS1_HANDLER, length * 0, @@ -486,7 +486,7 @@ ReturnValue_t pst::pstUart(FixedTimeslotTaskIF *thisSequence) { thisSequence->addSlot(objects::SYRLINKS_HK_HANDLER, length * 0.2, DeviceHandlerIF::SEND_WRITE); -#if OBSW_ADD_GPS == 1 +#if OBSW_ADD_ACS_BOARD == 1 thisSequence->addSlot(objects::GPS0_HANDLER, length * 0.2, DeviceHandlerIF::SEND_WRITE); thisSequence->addSlot(objects::GPS1_HANDLER, length * 0.2, @@ -495,7 +495,7 @@ ReturnValue_t pst::pstUart(FixedTimeslotTaskIF *thisSequence) { thisSequence->addSlot(objects::SYRLINKS_HK_HANDLER, length * 0.4, DeviceHandlerIF::GET_WRITE); -#if OBSW_ADD_GPS == 1 +#if OBSW_ADD_ACS_BOARD == 1 thisSequence->addSlot(objects::GPS0_HANDLER, length * 0.4, DeviceHandlerIF::GET_WRITE); thisSequence->addSlot(objects::GPS1_HANDLER, length * 0.4, @@ -504,7 +504,7 @@ ReturnValue_t pst::pstUart(FixedTimeslotTaskIF *thisSequence) { thisSequence->addSlot(objects::SYRLINKS_HK_HANDLER, length * 0.6, DeviceHandlerIF::SEND_READ); -#if OBSW_ADD_GPS == 1 +#if OBSW_ADD_ACS_BOARD == 1 thisSequence->addSlot(objects::GPS0_HANDLER, length * 0.6, DeviceHandlerIF::SEND_READ); thisSequence->addSlot(objects::GPS1_HANDLER, length * 0.6, @@ -513,7 +513,7 @@ ReturnValue_t pst::pstUart(FixedTimeslotTaskIF *thisSequence) { thisSequence->addSlot(objects::SYRLINKS_HK_HANDLER, length * 0.8, DeviceHandlerIF::GET_READ); -#if OBSW_ADD_GPS == 1 +#if OBSW_ADD_ACS_BOARD == 1 thisSequence->addSlot(objects::GPS0_HANDLER, length * 0.8, DeviceHandlerIF::GET_READ); thisSequence->addSlot(objects::GPS1_HANDLER, length * 0.8, diff --git a/linux/fsfwconfig/returnvalues/classIds.h b/linux/fsfwconfig/returnvalues/classIds.h index d1bfe7e2..79f1a175 100644 --- a/linux/fsfwconfig/returnvalues/classIds.h +++ b/linux/fsfwconfig/returnvalues/classIds.h @@ -13,6 +13,7 @@ namespace CLASS_ID { enum { CLASS_ID_START = COMMON_CLASS_ID_END, SA_DEPL_HANDLER, //SADPL + SD_CARD_MANAGER, //SDMA CLASS_ID_END // [EXPORT] : [END] }; } diff --git a/linux/utility/CMakeLists.txt b/linux/utility/CMakeLists.txt index 45a7edcc..a3387531 100644 --- a/linux/utility/CMakeLists.txt +++ b/linux/utility/CMakeLists.txt @@ -1,4 +1,5 @@ target_sources(${TARGET_NAME} PUBLIC + utility.cpp ) diff --git a/linux/utility/utility.cpp b/linux/utility/utility.cpp new file mode 100644 index 00000000..69a3d08f --- /dev/null +++ b/linux/utility/utility.cpp @@ -0,0 +1,11 @@ +#include "OBSWConfig.h" +#include "FSFWConfig.h" +#include "utility.h" + +#include "fsfw/serviceinterface/ServiceInterface.h" + +void utility::handleSystemError(int retcode, std::string function) { +#if OBSW_VERBOSE_LEVEL >= 1 + sif::warning << function << ": System call failed with code " << retcode; +#endif +} diff --git a/linux/utility/utility.h b/linux/utility/utility.h new file mode 100644 index 00000000..3eb17a9b --- /dev/null +++ b/linux/utility/utility.h @@ -0,0 +1,13 @@ +#ifndef LINUX_UTILITY_UTILITY_H_ +#define LINUX_UTILITY_UTILITY_H_ + +#include "fsfw/returnvalues/HasReturnvaluesIF.h" +#include + +namespace utility { + +void handleSystemError(int retcode, std::string function); + +} + +#endif /* LINUX_UTILITY_UTILITY_H_ */ diff --git a/misc/eclipse/.cproject b/misc/eclipse/.cproject index a562e7b2..16bd992b 100644 --- a/misc/eclipse/.cproject +++ b/misc/eclipse/.cproject @@ -19,25 +19,25 @@ - + - @@ -77,19 +77,23 @@ - @@ -127,7 +131,7 @@ - +