Skip to content

Commit

Permalink
Merge pull request #78 from KriSun95/additions2readme
Browse files Browse the repository at this point in the history
Added some thoughts on the main README.
  • Loading branch information
thanasipantazides authored Dec 4, 2024
2 parents 41fe379 + 67e551f commit da8fc73
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 50 deletions.
81 changes: 67 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ brew install googletest
I have used `boost` v1.83.0 and v1.80.0, and `nlohmann-hson` v3.11.3. I expect other `boost` versions 1.7x and up, and other 3.1x versions of `nlohmann-json` to also work, but have not tested.

### Building on the Raspberry Pi to run
### Building on the Raspberry Pi and/or your computer to run
The flight Raspberry Pi already has dependencies installed. If you are setting up a brand new Raspberry Pi, see [PISETUP.md](PISETUP.md). Otherwise, choose instructions for either
1. [setting up from](#set-up-from-a-release) a [tagged release](https://github.com/foxsi/foxsi-4matter/tags), or
2. [setting up from the latest version of the `main` branch available](#set-up-from-latest-main).
Expand Down Expand Up @@ -109,7 +109,7 @@ sudo systemctl stop formatter.service
The Formatter service will resume running after a reboot.

> [!NOTE]
> This will overwrite the existing `formatter` binary in the Formatter. If you want to save a copy of it first, do the following to save a copy of the binary in whatever directory you are currently in on your machine:
> The steps below will overwrite the existing `formatter` binary in the Formatter. If you want to save a copy of it first, do the following to save a copy of the binary in whatever directory you are currently in on your machine:
> ```bash
> scp [email protected]:foxsi-4matter/bin/formatter .
> ```
Expand All @@ -131,11 +131,45 @@ cmake --build . -j4
```
The Raspberry Pi build process takes a couple minutes. This will create several binaries in `foxsi-4matter/bin/` that you can run. The main program that runs in flight is `foxsi-4matter/bin/formatter`.
You should have stopped executing `formatter` via `systemctl` above. The new binary you just built will be run after a reboot. Or, if you want to see all the `cout` output as it happens, you can run it now like this:
## How to run
### Run a post-build test
If you just built a new binary (either on your computer or on the Formatter Raspberry Pi), you may want to check that it works. You can run the following code to validate:
```bash
./bin/test_buffers --config foxsi4-commands/systems.json
```
This will use dummy CdTe and CMOS data frames, packetize them to "transfer" them to the Formatter, reassemble them, then packetize them for "downlink," then reassemble the "downlinked" data as frames. The frame you get out at the very end is supposed to be identical to the frame that originally came out of CdTe or CMOS.
When you run this test you should see lots of printout, and a final line claiming
```
All tests passed successfully.
```
### Run the real deal
> I will assume you're doing this on a Raspberry Pi. For running the `foxsimile` emulator on your laptop instead, build the [full documentation](#documentation) and see the `foxsimile` guide there.
There are two ways to run the `formatter` binary in the flight system. You can rely on the `systemd`/`systemctl` utility to start it automatically on boot, or you can manually run it from the command line.
In either case, you should have stopped executing `formatter` via `systemctl` above before building the new software. The new binary you just built will be run after a reboot. If you want to run the new binary manually and see all the printout, do this:
```bash
./bin/formatter --verbose --config foxsi4-commands/systems.json
```
To have `systemd` run the new software you can either do
```bash
sudo systemctl start formatter.service
```
or reboot the Formatter with
```bash
sudo reboot
```
> [!NOTE]
> When you run the `formatter` binary yourself, you get to see everything that gets printed out. This can be useful for debugging, especially if the software is crashing right when it starts up.
>
> In either run case (`systemd` or you running manually at a terminal), the software logs output to the `foxsi-4matter/log` folder. The information logged here is different from the information printed via `cout` that is visible when running manually.
## How to use
Once the Formatter software starts running (either on boot, or because you have manually started running something) it will try to poll all the detector systems for housekeeping data. These systems may or may not be connected or powered on.
Expand All @@ -158,19 +192,31 @@ The DE identifies connected canisters (in the raw data recordings) on the SpaceW
| Timepix | --- | --- | `0x01` |
| SAAS | --- | --- | `0x02` |
### Starting the Formatter software
The Formatter will try to run the binary `/home/foxsi/foxsi4-matter/bin/formatter` after boot, and again every 10 seconds after that binary stops running. This is managed by [[`systemctl`](https://www.freedesktop.org/software/systemd/man/latest/systemctl.html)], which is a powerful Linux utility for running *services*. You can interact with the Formatter service using these commands:
### Interacting with the `formatter` service
The Formatter will try to run the binary `/home/foxsi/foxsi4-matter/bin/formatter` after boot, and again every 10 seconds after that binary stops running. This is managed by [`systemctl`](https://www.freedesktop.org/software/systemd/man/latest/systemctl.html), which is a powerful Linux utility for running *services*.
These `systemctl` commands will affect the `formatter` service during a session. If you `stop` the `formatter.service`, it will start again after reboot.
```bash
sudo systemctl stop formatter.service # stop running the Formatter service
sudo systemctl start formatter.service # start running the Formatter service
sudo systemctl disable formatter.service # disable the Formatter service from starting after boot
sudo systemctl enable formatter.service # enable the Formatter service to run after boot
sudo systemctl status formatter.service # report the current status of the Formatter service
# stop running the Formatter service
sudo systemctl stop formatter.service
# start running the Formatter service
sudo systemctl start formatter.service
# report the current status of the Formatter service
sudo systemctl status formatter.service
```
The last command, querying the `status` of the running Formatter service, will tell you if it is running still or has stopped. It will also print some of the Formatter's recent output. Note that while the Formatter service may still be running, the main loop may have effectively stopped due to subsystem disconnects. If you query the status multiple times and always see identical printout, the service may no longer be running correctly.
The following `systemctl` commands enable/disable the `formatter.service` from running **on boot**. If you `disable` the `formatter.service`, it will no longer run when the Pi is rebooted. You can always re`enable` it. For more, see the [PISETUP.md](PISETUP.md).
```bash
# disable the Formatter service from starting after boot
sudo systemctl disable formatter.service
# enable the Formatter service to run after boot
sudo systemctl enable formatter.service
```
When the service is running, if you need to debug you will need to find the correct `~/foxsi-4matter/log/` file to collect evidence. This can be inconvenient to track down since Unixtime changes with every reboot.
A helpful debugging workflow is to stop the Formatter service, then launch it manually so you can see the stdout output:
Expand Down Expand Up @@ -218,15 +264,22 @@ You can also log downlinked data using the [GSE software](https://github.com/fox
python3 FoGSE/listening.py foxsi4-commands/systems.json
```
On startup, this `Listener` application creates a set of log file at this location in the GSE directory: `logs/received/<date_time>/`. Within this folder, a file is created for each system and downlink datatype from the above table, with this format: `<system>_<data>.log`.
On startup, this `Listener` application creates a set of log files at this location in the GSE directory: `logs/received/<date_time>/`. Within this folder, a file is created for each system and downlink datatype from the above table, with this format: `<system>_<data>.log`.
Additionally, an ASCII-formatted file called `catch.log` is produced to log any received packets that can't be parsed into a system-specific file. Each entry in this file is newline-separated, and tagged at the start of the file with an offset timestamp from the creation time of the file.
## Common issues
1. In a typical lab or flight setup, physical connections, GSE computer network configuration, and `systems.json` mismatch cause far more problems than the code internals. If you're having issues, verify your connections with simple tests before you try anything else. Check if everything is plugged in, and your GSE machine shows Ethernets are "connected." Check if you can `ping` from the GSE to the Formatter. Check in Wireshark if you get packets from the Formatter to the right IP address.
3. If you run the formatter software, kill it, then try to run it immediately again, you will get an error containing `connect: Address already in use`. This is because the kernel retains control of TCP sockets for a while (~1 minute) after you close them to allow any messages still on the wire to come through. Just wait a moment and try running again. Of course, it is possible (depending on your configuration) that another process on the same machine actually is using the IP address you want as well.
4. Unix time resets to a similar value on every reboot. Do not trust any timestamps you get out of this software.
5. If you never clear the `~/foxsi-4matter/log/` folder, you can completely fill the disk and get a read-only filesystem. Then you will need to edit `fstab` manually and with a racing heart while the whole flare campaign waits for you. This happened at PFRR during the FOXSI-4 launch campaign.
- In the Wireshark top menu bar, use the filter `ip.dst==224.1.1.118 && udp && !icmp` to filter for packets that the Formatter sends to the GSE. If you see anything show up the data is coming in!
2. If you run the Formatter software, kill it, then try to run it immediately again, you will get an error containing `connect: Address already in use`. This is because the kernel retains control of TCP sockets for a while (~1 minute) after you close them to allow any messages still on the wire to come through. Just wait a moment and try running again. Of course, it is possible (depending on your configuration) that another process on the same machine actually is using the IP address you want as well.
- If you get an `Address already in use` error on the Formatter but it definitely *is not* because the Formatter software was just running, check that you are not launching the Formatter software manually while `systemd` is already running an instance of it.
- If you get an `Address already in use` error in the GSE, try `ps aux | grep FoGSE` and kill any process IDs that match. Sometimes in testing a background logging process from the GSE is not killed, so it lingers and retains control of the GSE IP address.
3. Unix time resets to a similar value on every reboot. Do not trust any timestamps you get out of this software.
4. If you never clear the `~/foxsi-4matter/log/` folder, you can completely fill the disk and get a read-only filesystem. Then you will need to manually repair `fstab`, which is stressful. To avoid this, just delete `foxsi-4matter/log/*` regularly, and clear the syslog and daemon log (while `ssh`'d in the Pi):
```bash
sudo truncate -s 0 /var/log/syslog
sudo truncate -s 0 /var/log/daemon.log
```
## Documentation
If you enjoyed this measly little README, you're going to *love* the rest of the documentation! You can view these docs in a web browser (they are HTML), and until they are hosted somewhere, you will need these instructions to build them:
Expand Down
6 changes: 3 additions & 3 deletions doc/breathe/source/conf.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
import sys
from pathlib import Path
# Configuration file for the Sphinx documentation builder.
#
# For the full list of built-in configuration values, see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html

# -- Project information -----------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
sys.path.append("/Users/thanasi/Documents/FOXSI/Data/formatter/foxsi-4matter/doc/breathe")

project = 'foxsi-4matter'
copyright = '2024, Thanasi Pantazides, Yixian Zhang, Kris Cooper'
author = 'Thanasi Pantazides, Yixian Zhang, Kris Cooper'
release = 'v1.2.0'
release = 'v1.2.2'

# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration

extensions = ["sphinx.ext.autodoc", "sphinx.ext.todo", "sphinx.ext.graphviz", "breathe"]
breathe_projects = {"foxsi-4matter": "/Users/thanasi/Documents/FOXSI/Data/formatter/foxsi-4matter/doc/xml"}
breathe_projects = {"foxsi-4matter": Path(__file__).parent.parent.parent.joinpath('xml/').resolve()}
breathe_default_project = "foxsi-4matter"

todo_include_todos = True
Expand Down
63 changes: 31 additions & 32 deletions test/test_buffers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -208,67 +208,61 @@ int main(int argc, char* argv[]) {
}
std::cout << "cmos FramePacketizer: " << fp_cmos.to_string() << "\n";

bool total_success = true;

// ---------------------------- SpaceWire reply data tests ----------------------- //

std::cout << "test SpaceWire reply data:\n";
std::vector<uint8_t> good_reply = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0xfe, 0x01, 0x0d, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x0e, 0x04, 0x22, 0x80, 0x3c, 0x42};
std::vector<uint8_t> bad_reply = {0x21, 0x12, 0x81, 0x6a, 0x32, 0x3a, 0x0b, 0x70, 0x4b, 0x33, 0x8b, 0x33, 0xab, 0xb3, 0x22, 0xbf, 0x2b, 0x33, 0x32, 0xba, 0xab, 0x23, 0x3a, 0x2a, 0x12, 0xb7, 0x9f, 0x72, 0x91};
std::cout << "\treading good data...\n";
std::vector<uint8_t> good_data = cdte1.spacewire->get_reply_data(good_reply);
std::vector<uint8_t> ref_good_data = {0x04, 0x22, 0x80, 0x3c};
std::cout << "\treading bad data...\n";
std::vector<uint8_t> bad_data = cdte1.spacewire->get_reply_data(bad_reply);
std::vector<uint8_t> ref_bad_data = {};

// check if source data is reconstructed correctly.
total_success = total_success && (false_downlink_cdte == false_data_cdte);
if (false_downlink_cdte == false_data_cdte) {
std::cout << "\nSUCCESS for cdte transfer.\n";
} else {
std::cout << "\ntry again cdte transfer :(\n";
std::cout << "FAILURE for cdte transfer:\n";
std::cout << "\treceived " << std::to_string(false_downlink_cdte.size()) << " bytes of data: \n";
for (size_t i = 0; i < false_downlink_cdte.size(); ++i) {
std::cout << " " << std::to_string(false_downlink_cdte[i]);
}
std::cout << "\n";
}
total_success = total_success && (false_downlink_cmos == false_data_cmos);
if (false_downlink_cmos == false_data_cmos) {
std::cout << "\nSUCCESS for cmos transfer.\n";
std::cout << "SUCCESS for cmos transfer.\n";
} else {
std::cout << "\ntry again cmos transfer :(\n";
std::cout << "FAILURE for cmos transfer:\n";
std::cout << "\treceived " << std::to_string(false_downlink_cmos.size()) << " bytes of data: \n";
for (size_t i = 0; i < false_downlink_cmos.size(); ++i) {
std::cout << " " << std::to_string(false_downlink_cmos[i]);
}
std::cout << "\n";
}
std::cout << "\n";

// ---------------------------- SpaceWire reply data tests ----------------------- //

std::cout << "test SpaceWire reply data:\n";
std::vector<uint8_t> good_reply = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0xfe, 0x01, 0x0d, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x0e, 0x04, 0x22, 0x80, 0x3c, 0x42};
std::vector<uint8_t> bad_reply = {0x21, 0x12, 0x81, 0x6a, 0x32, 0x3a, 0x0b, 0x70, 0x4b, 0x33, 0x8b, 0x33, 0xab, 0xb3, 0x22, 0xbf, 0x2b, 0x33, 0x32, 0xba, 0xab, 0x23, 0x3a, 0x2a, 0x12, 0xb7, 0x9f, 0x72, 0x91};
std::cout << "from good packet: \n";
std::vector<uint8_t> good_data = cdte1.spacewire->get_reply_data(good_reply);
std::vector<uint8_t> ref_good_data = {0x04, 0x22, 0x80, 0x3c};

utilities::hex_print(good_data);
std::cout << "from bad packet: \n";
std::vector<uint8_t> bad_data = cdte1.spacewire->get_reply_data(bad_reply);
utilities::hex_print(bad_data);
std::vector<uint8_t> ref_bad_data = {};

total_success = total_success && (good_data == ref_good_data);
if (good_data == ref_good_data) {
std::cout << "\nSUCCESS for good packet parsing.\n";
std::cout << "SUCCESS for good packet parsing.\n";
} else {
std::cout << "\ntry again parsing the good packet :(\n";
std::cout << "FAILURE for good packet parsing.\n";
std::cout << "\tgot ";
utilities::hex_print(good_data);
}

total_success = total_success && (bad_data == ref_bad_data);
if (bad_data == ref_bad_data) {
std::cout << "\nSUCCESS for bad packet parsing.\n";
std::cout << "SUCCESS for bad packet parsing.\n";
} else {
std::cout << "\ntry again parsing the bad packet :(\n";
std::cout << "FAILURE for bad packet parsing.\n";
std::cout << "\tgot ";
utilities::hex_print(bad_data);
}
std::cout << "\n";

std::vector<uint8_t> test = {0,1,2,3,4,5,6,7};

std::vector<uint8_t> other(test.begin() + 8, test.begin() + 8);
std::cout << "other: ";
utilities::hex_print(other);

// ---------------------------- SpaceWire print tests ---------------------------- //

std::cout << "test SpaceWire printing:\n";
Expand All @@ -285,6 +279,11 @@ int main(int argc, char* argv[]) {
utilities::spw_print(test_cdte_read_msg, cdte1.spacewire);
utilities::spw_print(test_cdte_reply_msg, nullptr);

std::cout << "end of main.\n";
if (total_success) {
std::cout << "\nAll tests passed successfully.\n";
} else {
std::cout << "\nSome tests failed.\n";
}

return 0;
}
3 changes: 2 additions & 1 deletion util/build_doc.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ cd doc/breathe
sphinx-build -M html source build
sphinx-build -M latexpdf source build
echo "opening docs..."
open doc/breathe/build/html/index.html
open build/html/index.html
cd ../..

0 comments on commit da8fc73

Please sign in to comment.