From ec1f45392fd6c931dcb9fca060f9a768208544e1 Mon Sep 17 00:00:00 2001
From: Davide Mor <davide.mor@skywarder.eu>
Date: Sat, 18 Nov 2023 10:17:38 +0000
Subject: [PATCH] [gs] Added groundstation software
---
.vscode/c_cpp_properties.json | 46 +++++
.vscode/settings.json | 9 +-
CMakeLists.txt | 14 ++
cmake/dependencies.cmake | 19 ++
src/boards/Groundstation/Base/BoardStatus.cpp | 128 ++++++++++++++
src/boards/Groundstation/Base/BoardStatus.h | 123 +++++++++++++
src/boards/Groundstation/Base/Buses.h | 48 +++++
src/boards/Groundstation/Base/Hub.cpp | 75 ++++++++
src/boards/Groundstation/Base/Hub.h | 54 ++++++
.../Groundstation/Base/Ports/Ethernet.cpp | 61 +++++++
.../Groundstation/Base/Ports/Ethernet.h | 38 ++++
src/boards/Groundstation/Base/Radio/Radio.cpp | 150 ++++++++++++++++
src/boards/Groundstation/Base/Radio/Radio.h | 42 +++++
.../Common/Config/EthernetConfig.h | 40 +++++
.../Common/Config/GeneralConfig.h | 33 ++++
.../Groundstation/Common/Config/RadioConfig.h | 51 ++++++
src/boards/Groundstation/Common/HubBase.cpp | 36 ++++
src/boards/Groundstation/Common/HubBase.h | 58 ++++++
.../Common/Ports/EthernetBase.cpp | 124 +++++++++++++
.../Groundstation/Common/Ports/EthernetBase.h | 70 ++++++++
.../Groundstation/Common/Ports/Serial.cpp | 71 ++++++++
.../Groundstation/Common/Ports/Serial.h | 70 ++++++++
.../Groundstation/Common/Radio/RadioBase.cpp | 167 ++++++++++++++++++
.../Groundstation/Common/Radio/RadioBase.h | 128 ++++++++++++++
src/boards/Groundstation/Nokia/Buses.h | 42 +++++
src/boards/Groundstation/Nokia/Hub.cpp | 47 +++++
src/boards/Groundstation/Nokia/Hub.h | 54 ++++++
.../Groundstation/Nokia/Radio/Radio.cpp | 94 ++++++++++
src/boards/Groundstation/Nokia/Radio/Radio.h | 36 ++++
src/boards/common/Radio.h | 54 ++++++
.../base-groundstation-entry.cpp | 143 +++++++++++++++
.../nokia-groundstation-entry.cpp | 88 +++++++++
32 files changed, 2206 insertions(+), 7 deletions(-)
create mode 100644 src/boards/Groundstation/Base/BoardStatus.cpp
create mode 100644 src/boards/Groundstation/Base/BoardStatus.h
create mode 100644 src/boards/Groundstation/Base/Buses.h
create mode 100644 src/boards/Groundstation/Base/Hub.cpp
create mode 100644 src/boards/Groundstation/Base/Hub.h
create mode 100644 src/boards/Groundstation/Base/Ports/Ethernet.cpp
create mode 100644 src/boards/Groundstation/Base/Ports/Ethernet.h
create mode 100644 src/boards/Groundstation/Base/Radio/Radio.cpp
create mode 100644 src/boards/Groundstation/Base/Radio/Radio.h
create mode 100644 src/boards/Groundstation/Common/Config/EthernetConfig.h
create mode 100644 src/boards/Groundstation/Common/Config/GeneralConfig.h
create mode 100644 src/boards/Groundstation/Common/Config/RadioConfig.h
create mode 100644 src/boards/Groundstation/Common/HubBase.cpp
create mode 100644 src/boards/Groundstation/Common/HubBase.h
create mode 100644 src/boards/Groundstation/Common/Ports/EthernetBase.cpp
create mode 100644 src/boards/Groundstation/Common/Ports/EthernetBase.h
create mode 100644 src/boards/Groundstation/Common/Ports/Serial.cpp
create mode 100644 src/boards/Groundstation/Common/Ports/Serial.h
create mode 100644 src/boards/Groundstation/Common/Radio/RadioBase.cpp
create mode 100644 src/boards/Groundstation/Common/Radio/RadioBase.h
create mode 100644 src/boards/Groundstation/Nokia/Buses.h
create mode 100644 src/boards/Groundstation/Nokia/Hub.cpp
create mode 100644 src/boards/Groundstation/Nokia/Hub.h
create mode 100644 src/boards/Groundstation/Nokia/Radio/Radio.cpp
create mode 100644 src/boards/Groundstation/Nokia/Radio/Radio.h
create mode 100644 src/boards/common/Radio.h
create mode 100644 src/entrypoints/Groundstation/base-groundstation-entry.cpp
create mode 100644 src/entrypoints/Groundstation/nokia-groundstation-entry.cpp
diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json
index 94d0850d8..74b7c3142 100755
--- a/.vscode/c_cpp_properties.json
+++ b/.vscode/c_cpp_properties.json
@@ -763,6 +763,52 @@
"${workspaceFolder}/skyward-boardcore/libs/miosix-kernel/miosix/arch/cortexM7_stm32f7/stm32f769ni_discovery",
"${workspaceFolder}/skyward-boardcore/libs/miosix-kernel/miosix/config/arch/cortexM7_stm32f7/stm32f769ni_discovery"
]
+ },
+ {
+ "name": "stm32f767zi_gemini_gs",
+ "cStandard": "c11",
+ "cppStandard": "c++14",
+ "compilerPath": "/opt/arm-miosix-eabi/bin/arm-miosix-eabi-g++",
+ "defines": [
+ "{defaultDefines}",
+ "_MIOSIX_BOARDNAME=stm32f767zi_gemini_gs",
+ "_BOARD_STM32F767ZI_GEMINI_GS",
+ "_ARCH_CORTEXM7_STM32F7",
+ "STM32F769xx",
+ "HSE_VALUE=25000000",
+ "SYSCLK_FREQ_216MHz=216000000",
+ "__ENABLE_XRAM",
+ "V_DDA_VOLTAGE=3.3f"
+ ],
+ "includePath": [
+ "${defaultIncludePaths}",
+ "${workspaceFolder}/skyward-boardcore/libs/miosix-kernel/miosix/arch/cortexM7_stm32f7/common",
+ "${workspaceFolder}/skyward-boardcore/libs/miosix-kernel/miosix/arch/cortexM7_stm32f7/stm32f767zi_gemini_gs",
+ "${workspaceFolder}/skyward-boardcore/libs/miosix-kernel/miosix/config/arch/cortexM7_stm32f7/stm32f767zi_gemini_gs"
+ ]
+ },
+ {
+ "name": "stm32f429zi_skyward_groundstation_v2",
+ "cStandard": "c11",
+ "cppStandard": "c++14",
+ "compilerPath": "/opt/arm-miosix-eabi/bin/arm-miosix-eabi-g++",
+ "defines": [
+ "{defaultDefines}",
+ "_MIOSIX_BOARDNAME=stm32f429zi_skyward_groundstation_v2",
+ "_BOARD_STM32F429ZI_SKYWARD_GS_V2",
+ "_ARCH_CORTEXM4_STM32F4",
+ "STM32F429xx",
+ "HSE_VALUE=8000000",
+ "SYSCLK_FREQ_168MHz=168000000",
+ "__ENABLE_XRAM",
+ "V_DDA_VOLTAGE=3.0f"
+ ],
+ "includePath": [
+ "${defaultIncludePaths}",
+ "${workspaceFolder}/skyward-boardcore/libs/miosix-kernel/miosix/arch/cortexM4_stm32f4/common",
+ "${workspaceFolder}/skyward-boardcore/libs/miosix-kernel/miosix/arch/cortexM4_stm32f4/stm32f429zi_skyward_groundstation_v2",
+ "${workspaceFolder}/skyward-boardcore/libs/miosix-kernel/miosix/config/arch/cortexM4_stm32f4/stm32f429zi_skyward_groundstation_v2"
+ ]
}
],
"version": 4
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 6c2786aa3..a51e6cc18 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -118,13 +118,6 @@
"numbers": "cpp",
"semaphore": "cpp"
},
- "editor.formatOnSave": true,
- "[c]": {
- "editor.formatOnSave": false
- },
- "[cmake]": {
- "editor.formatOnSave": false
- },
"cSpell.words": [
"Aeroutils",
"AIRBRAKES",
@@ -152,6 +145,7 @@
"Duca",
"Eigen",
"EXTI",
+ "Gpio",
"GPIOF",
"KALM",
"kalman",
@@ -161,6 +155,7 @@
"MPXH",
"Nidasio",
"pitot",
+ "RSSI",
"SATS",
"setb",
"Setpoint",
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 65a2c2f39..bb34a759c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -73,3 +73,17 @@ sbs_target(rig-entry stm32f429zi_skyward_rig)
add_executable(con_rig-entry src/entrypoints/con_RIG/con_rig-entry.cpp ${CON_RIG_COMPUTER})
target_include_directories(con_rig-entry PRIVATE ${OBSW_INCLUDE_DIRS})
sbs_target(con_rig-entry stm32f429zi_stm32f4discovery)
+
+add_executable(base-groundstation-entry
+ src/entrypoints/Groundstation/base-groundstation-entry.cpp
+ ${GROUNDSTATION_COMMON} ${GROUNDSTATION_BASE}
+)
+target_include_directories(base-groundstation-entry PRIVATE ${OBSW_INCLUDE_DIRS})
+sbs_target(base-groundstation-entry stm32f767zi_gemini_gs)
+
+add_executable(nokia-groundstation-entry
+ src/entrypoints/Groundstation/nokia-groundstation-entry.cpp
+ ${GROUNDSTATION_COMMON} ${GROUNDSTATION_NOKIA}
+)
+target_include_directories(nokia-groundstation-entry PRIVATE ${OBSW_INCLUDE_DIRS})
+sbs_target(nokia-groundstation-entry stm32f429zi_skyward_groundstation_v2)
diff --git a/cmake/dependencies.cmake b/cmake/dependencies.cmake
index 65860823f..41e4ba501 100644
--- a/cmake/dependencies.cmake
+++ b/cmake/dependencies.cmake
@@ -95,3 +95,22 @@ set(PAYLOAD_COMPUTER
src/boards/Payload/Sensors/RotatedIMU/RotatedIMU.cpp
src/boards/Payload/WindEstimationScheme/WindEstimation.cpp
)
+
+set(GROUNDSTATION_BASE
+ src/boards/Groundstation/Base/Radio/Radio.cpp
+ src/boards/Groundstation/Base/Ports/Ethernet.cpp
+ src/boards/Groundstation/Base/BoardStatus.cpp
+ src/boards/Groundstation/Base/Hub.cpp
+)
+
+set(GROUNDSTATION_NOKIA
+ src/boards/Groundstation/Nokia/Radio/Radio.cpp
+ src/boards/Groundstation/Nokia/Hub.cpp
+)
+
+set(GROUNDSTATION_COMMON
+ src/boards/Groundstation/Common/Ports/Serial.cpp
+ src/boards/Groundstation/Common/Ports/EthernetBase.cpp
+ src/boards/Groundstation/Common/Radio/RadioBase.cpp
+ src/boards/Groundstation/Common/HubBase.cpp
+)
diff --git a/src/boards/Groundstation/Base/BoardStatus.cpp b/src/boards/Groundstation/Base/BoardStatus.cpp
new file mode 100644
index 000000000..a8fb81e1e
--- /dev/null
+++ b/src/boards/Groundstation/Base/BoardStatus.cpp
@@ -0,0 +1,128 @@
+/* Copyright (c) 2023 Skyward Experimental Rocketry
+ * Author: Davide Mor
+ *
+ * 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.
+ */
+
+#include "BoardStatus.h"
+
+#include <Groundstation/Base/Ports/Ethernet.h>
+#include <Groundstation/Base/Radio/Radio.h>
+#include <Groundstation/Common/Config/GeneralConfig.h>
+#include <Groundstation/Common/HubBase.h>
+#include <common/Mavlink.h>
+#include <drivers/timer/TimestampTimer.h>
+
+using namespace Boardcore;
+using namespace Groundstation;
+using namespace GroundstationBase;
+
+bool BoardStatus::isMainRadioPresent() { return main_radio_present; }
+bool BoardStatus::isPayloadRadioPresent() { return payload_radio_present; }
+bool BoardStatus::isEthernetPresent() { return ethernet_present; }
+
+bool BoardStatus::start()
+{
+ if (!ActiveObject::start())
+ {
+ return false;
+ }
+
+ return true;
+}
+
+void BoardStatus::setMainRadioPresent(bool present)
+{
+ main_radio_present = present;
+}
+
+void BoardStatus::setPayloadRadioPresent(bool present)
+{
+ payload_radio_present = present;
+}
+
+void BoardStatus::setEthernetPresent(bool present)
+{
+ ethernet_present = present;
+}
+
+void BoardStatus::run()
+{
+ while (!shouldStop())
+ {
+ miosix::Thread::sleep(RADIO_STATUS_PERIOD);
+
+ mavlink_receiver_tm_t tm = {0};
+ tm.timestamp = TimestampTimer::getTimestamp();
+ tm.battery_voltage = -420.0;
+
+ if (main_radio_present)
+ {
+ tm.main_radio_present = 1;
+
+ auto stats =
+ ModuleManager::getInstance().get<RadioMain>()->getStats();
+ tm.main_packet_tx_error_count = stats.send_errors;
+ tm.main_tx_bitrate = main_tx_bitrate.update(stats.bits_tx_count);
+ tm.main_packet_rx_success_count = stats.packet_rx_success_count;
+ tm.main_packet_rx_drop_count = stats.packet_rx_drop_count;
+ tm.main_rx_bitrate = main_rx_bitrate.update(stats.bits_rx_count);
+ tm.main_rx_rssi = stats.rx_rssi;
+ tm.main_rx_fei = stats.rx_fei;
+
+ last_main_stats = stats;
+ }
+
+ if (payload_radio_present)
+ {
+ tm.payload_radio_present = 1;
+
+ auto stats =
+ ModuleManager::getInstance().get<RadioPayload>()->getStats();
+ tm.payload_packet_tx_error_count = stats.send_errors;
+ tm.payload_tx_bitrate =
+ payload_tx_bitrate.update(stats.bits_tx_count);
+ tm.payload_packet_rx_success_count = stats.packet_rx_success_count;
+ tm.payload_packet_rx_drop_count = stats.packet_rx_drop_count;
+ tm.payload_rx_bitrate =
+ payload_rx_bitrate.update(stats.bits_rx_count);
+ tm.payload_rx_rssi = stats.rx_rssi;
+ tm.payload_rx_fei = stats.rx_fei;
+
+ last_payload_stats = stats;
+ }
+
+ if (ethernet_present)
+ {
+ auto stats =
+ ModuleManager::getInstance().get<Ethernet>()->getState();
+
+ tm.ethernet_present = 1;
+ tm.ethernet_status = (stats.link_up ? 1 : 0) |
+ (stats.full_duplex ? 2 : 0) |
+ (stats.based_100mbps ? 4 : 0);
+ }
+
+ mavlink_message_t msg;
+ mavlink_msg_receiver_tm_encode(GS_SYSTEM_ID, GS_COMPONENT_ID, &msg,
+ &tm);
+
+ ModuleManager::getInstance().get<HubBase>()->dispatchIncomingMsg(msg);
+ }
+}
\ No newline at end of file
diff --git a/src/boards/Groundstation/Base/BoardStatus.h b/src/boards/Groundstation/Base/BoardStatus.h
new file mode 100644
index 000000000..c684a3319
--- /dev/null
+++ b/src/boards/Groundstation/Base/BoardStatus.h
@@ -0,0 +1,123 @@
+/* Copyright (c) 2023 Skyward Experimental Rocketry
+ * Author: Davide Mor
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <ActiveObject.h>
+#include <Groundstation/Common/Config/RadioConfig.h>
+#include <Groundstation/Common/Radio/RadioBase.h>
+#include <utils/collections/CircularBuffer.h>
+
+#include <utils/ModuleManager/ModuleManager.hpp>
+
+namespace GroundstationBase
+{
+
+/**
+ * @brief Utility to calculate the bitrate
+ */
+template <unsigned int WINDOW_SIZE, unsigned int PERIOD>
+class BitrateCalculator
+{
+public:
+ BitrateCalculator() {}
+
+ /**
+ * @brief Update the calculator, should be called every PERIOD ms
+ */
+ uint16_t update(uint32_t sample)
+ {
+ if (window.isFull())
+ {
+ uint32_t last = window.pop();
+ window.put(sample);
+
+ uint16_t delta = sample - last;
+
+ // window size is in ms, we want the result in s
+ return delta * 1000 / WINDOW_SIZE;
+ }
+ else
+ {
+ window.put(sample);
+ return 0;
+ }
+ }
+
+private:
+ Boardcore::CircularBuffer<uint32_t, WINDOW_SIZE / PERIOD> window;
+};
+
+/**
+ * @brief Class responsible for keeping track of radio status and metrics.
+ */
+class BoardStatus : public Boardcore::Module, private Boardcore::ActiveObject
+{
+public:
+ BoardStatus() {}
+
+ bool start();
+
+ /**
+ * @brief Check wether the main radio was found during boot.
+ */
+ bool isMainRadioPresent();
+
+ /**
+ * @brief Check wether the payload radio was found during boot.
+ */
+ bool isPayloadRadioPresent();
+
+ /**
+ * @brief Check wether the ethernet was found during boot.
+ */
+ bool isEthernetPresent();
+
+ void setMainRadioPresent(bool present);
+ void setPayloadRadioPresent(bool present);
+ void setEthernetPresent(bool present);
+
+private:
+ void run() override;
+
+ Groundstation::RadioStats last_main_stats = {0};
+ Groundstation::RadioStats last_payload_stats = {0};
+
+ BitrateCalculator<Groundstation::RADIO_BITRATE_WINDOW_SIZE,
+ Groundstation::RADIO_STATUS_PERIOD>
+ main_tx_bitrate;
+ BitrateCalculator<Groundstation::RADIO_BITRATE_WINDOW_SIZE,
+ Groundstation::RADIO_STATUS_PERIOD>
+ main_rx_bitrate;
+ BitrateCalculator<Groundstation::RADIO_BITRATE_WINDOW_SIZE,
+ Groundstation::RADIO_STATUS_PERIOD>
+ payload_tx_bitrate;
+ BitrateCalculator<Groundstation::RADIO_BITRATE_WINDOW_SIZE,
+ Groundstation::RADIO_STATUS_PERIOD>
+ payload_rx_bitrate;
+
+ bool main_radio_present = false;
+ bool payload_radio_present = false;
+ bool ethernet_present = false;
+};
+
+} // namespace GroundstationBase
\ No newline at end of file
diff --git a/src/boards/Groundstation/Base/Buses.h b/src/boards/Groundstation/Base/Buses.h
new file mode 100644
index 000000000..e77614811
--- /dev/null
+++ b/src/boards/Groundstation/Base/Buses.h
@@ -0,0 +1,48 @@
+/* Copyright (c) 2023 Skyward Experimental Rocketry
+ * Author: Davide Mor
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <drivers/spi/SPIBus.h>
+
+#include <utils/ModuleManager/ModuleManager.hpp>
+
+#include "interfaces-impl/hwmapping.h"
+
+namespace GroundstationBase
+{
+
+class Buses : public Boardcore::Module
+{
+public:
+ Boardcore::SPIBus radio1_bus;
+ Boardcore::SPIBus radio2_bus;
+ Boardcore::SPIBus ethernet_bus;
+
+ Buses()
+ : radio1_bus(MIOSIX_RADIO1_SPI), radio2_bus(MIOSIX_RADIO2_SPI),
+ ethernet_bus(MIOSIX_ETHERNET_SPI)
+ {
+ }
+};
+
+} // namespace GroundstationBase
\ No newline at end of file
diff --git a/src/boards/Groundstation/Base/Hub.cpp b/src/boards/Groundstation/Base/Hub.cpp
new file mode 100644
index 000000000..af0b0608d
--- /dev/null
+++ b/src/boards/Groundstation/Base/Hub.cpp
@@ -0,0 +1,75 @@
+/* Copyright (c) 2023 Skyward Experimental Rocketry
+ * Author: Davide Mor
+ *
+ * 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.
+ */
+
+#include "Hub.h"
+
+#include <Groundstation/Base/BoardStatus.h>
+#include <Groundstation/Base/Ports/Ethernet.h>
+#include <Groundstation/Base/Radio/Radio.h>
+#include <Groundstation/Common/Config/GeneralConfig.h>
+#include <Groundstation/Common/Ports/Serial.h>
+
+using namespace Groundstation;
+using namespace GroundstationBase;
+using namespace Boardcore;
+
+void Hub::dispatchOutgoingMsg(const mavlink_message_t& msg)
+{
+ BoardStatus* status = ModuleManager::getInstance().get<BoardStatus>();
+
+ bool send_ok = false;
+
+ if (status->isMainRadioPresent() && msg.sysid == MAV_SYSID_MAIN)
+ {
+ RadioMain* radio = ModuleManager::getInstance().get<RadioMain>();
+ send_ok |= radio->sendMsg(msg);
+ }
+
+ if (status->isPayloadRadioPresent() && msg.sysid == MAV_SYSID_PAYLOAD)
+ {
+ RadioPayload* radio = ModuleManager::getInstance().get<RadioPayload>();
+ send_ok |= radio->sendMsg(msg);
+ }
+
+ (void)send_ok;
+
+ // If both of the sends went wrong, just send a nack
+ // This doesn't work well with multiple GS on the same ethernet network
+ // if (!send_ok)
+ // {
+ // sendNack(msg);
+ // }
+}
+
+void Hub::dispatchIncomingMsg(const mavlink_message_t& msg)
+{
+ BoardStatus* status = ModuleManager::getInstance().get<BoardStatus>();
+
+ Serial* serial = ModuleManager::getInstance().get<Serial>();
+ serial->sendMsg(msg);
+
+ if (status->isEthernetPresent())
+ {
+ Ethernet* ethernet = ModuleManager::getInstance().get<Ethernet>();
+ ethernet->sendMsg(msg);
+ }
+}
\ No newline at end of file
diff --git a/src/boards/Groundstation/Base/Hub.h b/src/boards/Groundstation/Base/Hub.h
new file mode 100644
index 000000000..c22a7339f
--- /dev/null
+++ b/src/boards/Groundstation/Base/Hub.h
@@ -0,0 +1,54 @@
+/* Copyright (c) 2023 Skyward Experimental Rocketry
+ * Author: Davide Mor
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <Groundstation/Common/HubBase.h>
+#include <common/Mavlink.h>
+
+#include <utils/ModuleManager/ModuleManager.hpp>
+
+namespace GroundstationBase
+{
+
+/**
+ * @brief Central hub connecting all outgoing and ingoing modules.
+ */
+class Hub : public Groundstation::HubBase
+{
+public:
+ Hub() {}
+
+ /**
+ * @brief Dispatch to the correct interface and outgoing packet (gs ->
+ * rocket).
+ */
+ void dispatchOutgoingMsg(const mavlink_message_t& msg) override;
+
+ /**
+ * @brief Dispatch to the correct interface and incoming packet (rocket ->
+ * gs).
+ */
+ void dispatchIncomingMsg(const mavlink_message_t& msg) override;
+};
+
+} // namespace GroundstationBase
\ No newline at end of file
diff --git a/src/boards/Groundstation/Base/Ports/Ethernet.cpp b/src/boards/Groundstation/Base/Ports/Ethernet.cpp
new file mode 100644
index 000000000..875c083cf
--- /dev/null
+++ b/src/boards/Groundstation/Base/Ports/Ethernet.cpp
@@ -0,0 +1,61 @@
+/* Copyright (c) 2023 Skyward Experimental Rocketry
+ * Author: Davide Mor
+ *
+ * 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.
+ */
+
+#include "Ethernet.h"
+
+#include <Groundstation/Base/BoardStatus.h>
+#include <Groundstation/Base/Buses.h>
+#include <interfaces-impl/hwmapping.h>
+
+using namespace Groundstation;
+using namespace GroundstationBase;
+using namespace Boardcore;
+using namespace miosix;
+
+void __attribute__((used)) MIOSIX_ETHERNET_IRQ()
+{
+ ModuleManager::getInstance().get<Ethernet>()->handleINTn();
+}
+
+bool Ethernet::start()
+{
+ std::unique_ptr<Wiz5500> wiz5500 = std::make_unique<Wiz5500>(
+ ModuleManager::getInstance().get<Buses>()->ethernet_bus,
+ ethernet::cs::getPin(), ethernet::intr::getPin(),
+ SPI::ClockDivider::DIV_64);
+
+ // First check if the device is even connected
+ bool present = wiz5500->checkVersion();
+
+ ModuleManager::getInstance().get<BoardStatus>()->setEthernetPresent(
+ present);
+
+ if (present)
+ {
+ if (!EthernetBase::start(std::move(wiz5500)))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
\ No newline at end of file
diff --git a/src/boards/Groundstation/Base/Ports/Ethernet.h b/src/boards/Groundstation/Base/Ports/Ethernet.h
new file mode 100644
index 000000000..4a8283b19
--- /dev/null
+++ b/src/boards/Groundstation/Base/Ports/Ethernet.h
@@ -0,0 +1,38 @@
+/* Copyright (c) 2023 Skyward Experimental Rocketry
+ * Author: Davide Mor
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <Groundstation/Common/Ports/EthernetBase.h>
+
+#include <utils/ModuleManager/ModuleManager.hpp>
+
+namespace GroundstationBase
+{
+
+class Ethernet : public Groundstation::EthernetBase, public Boardcore::Module
+{
+public:
+ [[nodiscard]] bool start();
+};
+
+} // namespace GroundstationBase
\ No newline at end of file
diff --git a/src/boards/Groundstation/Base/Radio/Radio.cpp b/src/boards/Groundstation/Base/Radio/Radio.cpp
new file mode 100644
index 000000000..a8bf2456f
--- /dev/null
+++ b/src/boards/Groundstation/Base/Radio/Radio.cpp
@@ -0,0 +1,150 @@
+/* Copyright (c) 2023 Skyward Experimental Rocketry
+ * Author: Davide Mor
+ *
+ * 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.
+ */
+
+#include "Radio.h"
+
+#include <Groundstation/Base/BoardStatus.h>
+#include <Groundstation/Base/Buses.h>
+#include <Groundstation/Base/Hub.h>
+#include <Groundstation/Common/Ports/Serial.h>
+#include <radio/SX1278/SX1278Frontends.h>
+
+using namespace Groundstation;
+using namespace GroundstationBase;
+using namespace Boardcore;
+using namespace miosix;
+
+void __attribute__((used)) MIOSIX_RADIO1_DIO0_IRQ()
+{
+ ModuleManager::getInstance().get<RadioMain>()->handleDioIRQ();
+}
+
+void __attribute__((used)) MIOSIX_RADIO1_DIO1_IRQ()
+{
+ ModuleManager::getInstance().get<RadioMain>()->handleDioIRQ();
+}
+
+void __attribute__((used)) MIOSIX_RADIO1_DIO3_IRQ()
+{
+ ModuleManager::getInstance().get<RadioMain>()->handleDioIRQ();
+}
+
+void __attribute__((used)) MIOSIX_RADIO2_DIO0_IRQ()
+{
+ ModuleManager::getInstance().get<RadioPayload>()->handleDioIRQ();
+}
+
+void __attribute__((used)) MIOSIX_RADIO2_DIO1_IRQ()
+{
+ ModuleManager::getInstance().get<RadioPayload>()->handleDioIRQ();
+}
+
+void __attribute__((used)) MIOSIX_RADIO2_DIO3_IRQ()
+{
+ ModuleManager::getInstance().get<RadioPayload>()->handleDioIRQ();
+}
+
+bool RadioMain::start()
+{
+#ifdef SKYWARD_GS_MAIN_USE_BACKUP_RF
+ std::unique_ptr<SX1278::ISX1278Frontend> frontend =
+ std::make_unique<EbyteFrontend>(radio1::txen::getPin(),
+ radio1::rxen::getPin());
+#else
+ std::unique_ptr<SX1278::ISX1278Frontend> frontend =
+ std::make_unique<Skyward433Frontend>();
+#endif
+
+ std::unique_ptr<Boardcore::SX1278Fsk> sx1278 =
+ std::make_unique<Boardcore::SX1278Fsk>(
+ ModuleManager::getInstance().get<Buses>()->radio1_bus,
+ radio1::cs::getPin(), radio1::dio0::getPin(),
+ radio1::dio1::getPin(), radio1::dio3::getPin(),
+ SPI::ClockDivider::DIV_64, std::move(frontend));
+
+ // First check if the device is even connected
+ bool present = sx1278->checkVersion();
+
+ ModuleManager::getInstance().get<BoardStatus>()->setMainRadioPresent(
+ present);
+
+ if (present)
+ {
+ // Configure the radio
+ if (sx1278->configure(Common::MAIN_RADIO_CONFIG) !=
+ SX1278Fsk::Error::NONE)
+ {
+ return false;
+ }
+
+ // Initialize if only if present
+ if (!RadioBase::start(std::move(sx1278)))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool RadioPayload::start()
+{
+#ifdef SKYWARD_GS_PAYLOAD_USE_BACKUP_RF
+ std::unique_ptr<SX1278::ISX1278Frontend> frontend =
+ std::make_unique<EbyteFrontend>(radio2::txen::getPin(),
+ radio2::rxen::getPin());
+#else
+ std::unique_ptr<SX1278::ISX1278Frontend> frontend =
+ std::make_unique<Skyward433Frontend>();
+#endif
+
+ std::unique_ptr<Boardcore::SX1278Fsk> sx1278 =
+ std::make_unique<Boardcore::SX1278Fsk>(
+ ModuleManager::getInstance().get<Buses>()->radio2_bus,
+ radio2::cs::getPin(), radio2::dio0::getPin(),
+ radio2::dio1::getPin(), radio2::dio3::getPin(),
+ SPI::ClockDivider::DIV_64, std::move(frontend));
+
+ // First check if the device is even connected
+ bool present = sx1278->checkVersion();
+
+ ModuleManager::getInstance().get<BoardStatus>()->setPayloadRadioPresent(
+ present);
+
+ if (present)
+ {
+ // Configure the radio
+ if (sx1278->configure(Common::PAYLOAD_RADIO_CONFIG) !=
+ SX1278Fsk::Error::NONE)
+ {
+ return false;
+ }
+
+ // Initialize if only if present
+ if (!RadioBase::start(std::move(sx1278)))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
\ No newline at end of file
diff --git a/src/boards/Groundstation/Base/Radio/Radio.h b/src/boards/Groundstation/Base/Radio/Radio.h
new file mode 100644
index 000000000..e09d207c9
--- /dev/null
+++ b/src/boards/Groundstation/Base/Radio/Radio.h
@@ -0,0 +1,42 @@
+/* Copyright (c) 2023 Skyward Experimental Rocketry
+ * Author: Davide Mor
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <Groundstation/Common/Radio/RadioBase.h>
+
+namespace GroundstationBase
+{
+
+class RadioMain : public Groundstation::RadioBase, public Boardcore::Module
+{
+public:
+ [[nodiscard]] bool start();
+};
+
+class RadioPayload : public Groundstation::RadioBase, public Boardcore::Module
+{
+public:
+ [[nodiscard]] bool start();
+};
+
+} // namespace GroundstationBase
\ No newline at end of file
diff --git a/src/boards/Groundstation/Common/Config/EthernetConfig.h b/src/boards/Groundstation/Common/Config/EthernetConfig.h
new file mode 100644
index 000000000..ddb9872a0
--- /dev/null
+++ b/src/boards/Groundstation/Common/Config/EthernetConfig.h
@@ -0,0 +1,40 @@
+/* Copyright (c) 2023 Skyward Experimental Rocketry
+ * Author: Davide Mor
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <drivers/WIZ5500/WIZ5500.h>
+
+#include <cstdint>
+
+namespace Groundstation
+{
+
+constexpr uint16_t RECV_PORT = 42070;
+constexpr uint16_t SEND_PORT = 42069;
+
+constexpr Boardcore::WizMac MAC_BASE = {0x69, 0x69, 0x69, 0x69, 0, 0};
+constexpr Boardcore::WizIp IP_BASE = {192, 168, 1, 0};
+constexpr Boardcore::WizIp GATEWAY = {192, 168, 1, 1};
+constexpr Boardcore::WizIp SUBNET = {0, 0, 0, 0};
+
+} // namespace Groundstation
\ No newline at end of file
diff --git a/src/boards/Groundstation/Common/Config/GeneralConfig.h b/src/boards/Groundstation/Common/Config/GeneralConfig.h
new file mode 100644
index 000000000..b7c8b8d3f
--- /dev/null
+++ b/src/boards/Groundstation/Common/Config/GeneralConfig.h
@@ -0,0 +1,33 @@
+/* Copyright (c) 2023 Skyward Experimental Rocketry
+ * Author: Davide Mor
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <cstdint>
+
+namespace Groundstation
+{
+
+constexpr uint8_t GS_COMPONENT_ID = 1;
+constexpr uint8_t GS_SYSTEM_ID = 1;
+
+} // namespace Groundstation
\ No newline at end of file
diff --git a/src/boards/Groundstation/Common/Config/RadioConfig.h b/src/boards/Groundstation/Common/Config/RadioConfig.h
new file mode 100644
index 000000000..c32abe0d5
--- /dev/null
+++ b/src/boards/Groundstation/Common/Config/RadioConfig.h
@@ -0,0 +1,51 @@
+/* Copyright (c) 2023 Skyward Experimental Rocketry
+ * Author: Davide Mor
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <cstddef>
+#include <cstdint>
+
+// Uncomment the following line to enable backup RF for main
+// #define SKYWARD_GS_MAIN_USE_BACKUP_RF
+// Uncomment the following line to enable backup RF for payload
+// #define SKYWARD_GS_PAYLOAD_USE_BACKUP_RF
+
+namespace Groundstation
+{
+
+constexpr size_t MAV_OUT_QUEUE_SIZE = 10;
+constexpr size_t MAV_PENDING_OUT_QUEUE_SIZE = 10;
+constexpr uint16_t MAV_SLEEP_AFTER_SEND = 5;
+constexpr size_t MAV_OUT_BUFFER_MAX_AGE = 10;
+
+/// @brief Every how many ms force the flush of the send queue.
+constexpr unsigned int AUTOMATIC_FLUSH_PERIOD = 250;
+/// @brief After how many ms stop waiting for the other side to send commands.
+constexpr long long AUTOMATIC_FLUSH_DELAY = 2000;
+
+/// @brief Period of the radio status telemetry.
+constexpr unsigned int RADIO_STATUS_PERIOD = 250;
+/// @brief Size in ms of the radio moving bitrate window size.
+constexpr size_t RADIO_BITRATE_WINDOW_SIZE = 1000;
+
+} // namespace Groundstation
diff --git a/src/boards/Groundstation/Common/HubBase.cpp b/src/boards/Groundstation/Common/HubBase.cpp
new file mode 100644
index 000000000..4b767dae7
--- /dev/null
+++ b/src/boards/Groundstation/Common/HubBase.cpp
@@ -0,0 +1,36 @@
+/* Copyright (c) 2023 Skyward Experimental Rocketry
+ * Author: Davide Mor
+ *
+ * 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.
+ */
+
+#include "HubBase.h"
+
+#include <Groundstation/Common/Config/GeneralConfig.h>
+
+using namespace Groundstation;
+
+void HubBase::sendNack(const mavlink_message_t& msg)
+{
+ mavlink_message_t nack_msg;
+ mavlink_msg_nack_tm_pack(GS_SYSTEM_ID, GS_COMPONENT_ID, &nack_msg,
+ msg.msgid, msg.seq);
+
+ dispatchIncomingMsg(nack_msg);
+}
\ No newline at end of file
diff --git a/src/boards/Groundstation/Common/HubBase.h b/src/boards/Groundstation/Common/HubBase.h
new file mode 100644
index 000000000..d7caa7ed0
--- /dev/null
+++ b/src/boards/Groundstation/Common/HubBase.h
@@ -0,0 +1,58 @@
+/* Copyright (c) 2023 Skyward Experimental Rocketry
+ * Author: Davide Mor
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <common/Mavlink.h>
+
+#include <utils/ModuleManager/ModuleManager.hpp>
+
+namespace Groundstation
+{
+
+/**
+ * @brief Central hub connecting all outgoing and ingoing modules.
+ */
+class HubBase : public Boardcore::Module
+{
+public:
+ /**
+ * @brief Dispatch to the correct interface and outgoing packet (gs ->
+ * rocket).
+ */
+ virtual void dispatchOutgoingMsg(const mavlink_message_t& msg) = 0;
+
+ /**
+ * @brief Dispatch to the correct interface and incoming packet (rocket ->
+ * gs).
+ */
+ virtual void dispatchIncomingMsg(const mavlink_message_t& msg) = 0;
+
+protected:
+ /**
+ * @brief Used internally to signal to the gs computer that something went
+ * wrong, and the packet could not be delivered.
+ */
+ void sendNack(const mavlink_message_t& msg);
+};
+
+} // namespace Groundstation
\ No newline at end of file
diff --git a/src/boards/Groundstation/Common/Ports/EthernetBase.cpp b/src/boards/Groundstation/Common/Ports/EthernetBase.cpp
new file mode 100644
index 000000000..f6c627b23
--- /dev/null
+++ b/src/boards/Groundstation/Common/Ports/EthernetBase.cpp
@@ -0,0 +1,124 @@
+/* Copyright (c) 2023 Skyward Experimental Rocketry
+ * Author: Davide Mor
+ *
+ * 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.
+ */
+
+#include "EthernetBase.h"
+
+#include <Groundstation/Common/Config/EthernetConfig.h>
+#include <Groundstation/Common/HubBase.h>
+
+#include <random>
+
+using namespace Groundstation;
+using namespace Boardcore;
+using namespace miosix;
+
+WizIp Groundstation::genNewRandomIp()
+{
+ WizIp ip = IP_BASE;
+ ip.d = (rand() % 253) + 1; // Generate in range 1-254
+
+ return ip;
+}
+
+WizMac Groundstation::genNewRandomMac()
+{
+ WizMac mac = MAC_BASE;
+ mac.e = (rand() % 253) + 1; // Generate in range 1-254
+ mac.f = (rand() % 253) + 1; // Generate in range 1-254
+
+ return mac;
+}
+
+void EthernetBase::handleINTn()
+{
+ if (wiz5500)
+ {
+ wiz5500->handleINTn();
+ }
+}
+
+void EthernetBase::sendMsg(const mavlink_message_t& msg)
+{
+ if (mav_driver && mav_driver->isStarted())
+ {
+ mav_driver->enqueueMsg(msg);
+ }
+}
+
+Boardcore::Wiz5500::PhyState EthernetBase::getState()
+{
+ return wiz5500->getPhyState();
+}
+
+bool EthernetBase::start(std::unique_ptr<Boardcore::Wiz5500> wiz5500)
+{
+ this->wiz5500 = std::move(wiz5500);
+
+ // Reset the device
+ this->wiz5500->reset();
+
+ // Setup ip and other stuff
+ this->wiz5500->setSubnetMask(SUBNET);
+ this->wiz5500->setGatewayIp(GATEWAY);
+ this->wiz5500->setSourceIp(genNewRandomIp());
+ this->wiz5500->setSourceMac(genNewRandomMac());
+
+ this->wiz5500->setOnIpConflict(
+ [this]() { this->wiz5500->setSourceIp(genNewRandomIp()); });
+
+ // Ok now open the UDP socket
+ if (!this->wiz5500->openUdp(0, RECV_PORT, {255, 255, 255, 255}, SEND_PORT,
+ 500))
+ {
+ return false;
+ }
+
+ auto mav_handler = [this](EthernetMavDriver* channel,
+ const mavlink_message_t& msg) { handleMsg(msg); };
+
+ mav_driver = std::make_unique<EthernetMavDriver>(this, mav_handler, 0, 10);
+
+ if (!mav_driver->start())
+ {
+ return false;
+ }
+
+ return true;
+}
+
+void EthernetBase::handleMsg(const mavlink_message_t& msg)
+{
+ // Dispatch the message through the hub.
+ ModuleManager::getInstance().get<HubBase>()->dispatchOutgoingMsg(msg);
+}
+
+ssize_t EthernetBase::receive(uint8_t* pkt, size_t max_len)
+{
+ WizIp dst_ip;
+ uint16_t dst_port;
+ return wiz5500->recvfrom(0, pkt, max_len, dst_ip, dst_port);
+}
+
+bool EthernetBase::send(uint8_t* pkt, size_t len)
+{
+ return wiz5500->send(0, pkt, len, 100);
+}
\ No newline at end of file
diff --git a/src/boards/Groundstation/Common/Ports/EthernetBase.h b/src/boards/Groundstation/Common/Ports/EthernetBase.h
new file mode 100644
index 000000000..cd377b574
--- /dev/null
+++ b/src/boards/Groundstation/Common/Ports/EthernetBase.h
@@ -0,0 +1,70 @@
+/* Copyright (c) 2023 Skyward Experimental Rocketry
+ * Author: Davide Mor
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <ActiveObject.h>
+#include <common/Mavlink.h>
+#include <drivers/WIZ5500/WIZ5500.h>
+#include <radio/MavlinkDriver/MavlinkDriver.h>
+
+#include <memory>
+
+namespace Groundstation
+{
+
+Boardcore::WizIp genNewRandomIp();
+Boardcore::WizMac genNewRandomMac();
+
+using EthernetMavDriver =
+ Boardcore::MavlinkDriver<1024, 10, MAVLINK_MAX_DIALECT_PAYLOAD_SIZE>;
+
+class EthernetBase : public Boardcore::Transceiver
+{
+public:
+ EthernetBase() {}
+
+ void handleINTn();
+
+ void sendMsg(const mavlink_message_t& msg);
+
+ Boardcore::Wiz5500::PhyState getState();
+
+protected:
+ bool start(std::unique_ptr<Boardcore::Wiz5500> wiz5500);
+
+private:
+ /**
+ * @brief Called internally when a message is received.
+ */
+ void handleMsg(const mavlink_message_t& msg);
+
+ ssize_t receive(uint8_t* pkt, size_t max_len) override;
+
+ bool send(uint8_t* pkt, size_t len) override;
+
+ bool started = false;
+ std::unique_ptr<Boardcore::Wiz5500> wiz5500;
+ std::unique_ptr<EthernetMavDriver> mav_driver;
+};
+
+} // namespace Groundstation
\ No newline at end of file
diff --git a/src/boards/Groundstation/Common/Ports/Serial.cpp b/src/boards/Groundstation/Common/Ports/Serial.cpp
new file mode 100644
index 000000000..45f4b7712
--- /dev/null
+++ b/src/boards/Groundstation/Common/Ports/Serial.cpp
@@ -0,0 +1,71 @@
+/* Copyright (c) 2023 Skyward Experimental Rocketry
+ * Author: Davide Mor
+ *
+ * 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.
+ */
+
+#include "Serial.h"
+
+#include <Groundstation/Common/HubBase.h>
+#include <filesystem/console/console_device.h>
+
+using namespace miosix;
+using namespace Groundstation;
+using namespace Boardcore;
+
+bool Serial::start()
+{
+ auto mav_handler = [this](SerialMavDriver* channel,
+ const mavlink_message_t& msg) { handleMsg(msg); };
+
+ mav_driver = std::make_unique<SerialMavDriver>(this, mav_handler, 0, 10);
+
+ if (!mav_driver->start())
+ {
+ return false;
+ }
+
+ return true;
+}
+
+void Serial::sendMsg(const mavlink_message_t& msg)
+{
+ if (mav_driver && mav_driver->isStarted())
+ {
+ mav_driver->enqueueMsg(msg);
+ }
+}
+
+void Serial::handleMsg(const mavlink_message_t& msg)
+{
+ // Dispatch the message through the hub.
+ ModuleManager::getInstance().get<HubBase>()->dispatchOutgoingMsg(msg);
+}
+
+ssize_t Serial::receive(uint8_t* pkt, size_t max_len)
+{
+ auto serial = miosix::DefaultConsole::instance().get();
+ return serial->readBlock(pkt, max_len, 0);
+}
+
+bool Serial::send(uint8_t* pkt, size_t len)
+{
+ auto serial = miosix::DefaultConsole::instance().get();
+ return serial->writeBlock(pkt, len, 0) != static_cast<ssize_t>(len);
+}
\ No newline at end of file
diff --git a/src/boards/Groundstation/Common/Ports/Serial.h b/src/boards/Groundstation/Common/Ports/Serial.h
new file mode 100644
index 000000000..ea39b6394
--- /dev/null
+++ b/src/boards/Groundstation/Common/Ports/Serial.h
@@ -0,0 +1,70 @@
+/* Copyright (c) 2023 Skyward Experimental Rocketry
+ * Author: Davide Mor
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <ActiveObject.h>
+#include <common/Mavlink.h>
+#include <radio/MavlinkDriver/MavlinkDriver.h>
+
+#include <memory>
+#include <utils/ModuleManager/ModuleManager.hpp>
+
+namespace Groundstation
+{
+
+using SerialMavDriver =
+ Boardcore::MavlinkDriver<1024, 10, MAVLINK_MAX_DIALECT_PAYLOAD_SIZE>;
+
+/**
+ * @brief Class responsible for UART communication.
+ */
+class Serial : public Boardcore::Module, public Boardcore::Transceiver
+{
+public:
+ Serial() {}
+
+ /**
+ * @brief Initialize the serial module.
+ */
+ [[nodiscard]] bool start();
+
+ /**
+ * @brief Send a mavlink message through this port.
+ */
+ void sendMsg(const mavlink_message_t& msg);
+
+private:
+ /**
+ * @brief Called internally when a message is received.
+ */
+ void handleMsg(const mavlink_message_t& msg);
+
+ ssize_t receive(uint8_t* pkt, size_t max_len) override;
+
+ bool send(uint8_t* pkt, size_t len) override;
+
+ miosix::FastMutex mutex;
+ std::unique_ptr<SerialMavDriver> mav_driver;
+};
+
+} // namespace Groundstation
\ No newline at end of file
diff --git a/src/boards/Groundstation/Common/Radio/RadioBase.cpp b/src/boards/Groundstation/Common/Radio/RadioBase.cpp
new file mode 100644
index 000000000..22be5ff3b
--- /dev/null
+++ b/src/boards/Groundstation/Common/Radio/RadioBase.cpp
@@ -0,0 +1,167 @@
+/* Copyright (c) 2023 Skyward Experimental Rocketry
+ * Author: Davide Mor
+ *
+ * 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.
+ */
+
+#include "RadioBase.h"
+
+#include <Groundstation/Common/HubBase.h>
+
+#include <memory>
+
+using namespace miosix;
+using namespace Groundstation;
+using namespace Boardcore;
+
+bool RadioBase::sendMsg(const mavlink_message_t& msg)
+{
+ Lock<FastMutex> l(pending_msgs_mutex);
+ if (pending_msgs_count >= MAV_PENDING_OUT_QUEUE_SIZE)
+ {
+ return false;
+ }
+ else
+ {
+ pending_msgs[pending_msgs_count] = msg;
+ pending_msgs_count += 1;
+
+ return true;
+ }
+}
+
+void RadioBase::handleDioIRQ()
+{
+ if (started)
+ {
+ sx1278->handleDioIRQ();
+ }
+}
+
+RadioStats RadioBase::getStats()
+{
+ if (started)
+ {
+ auto mav_stats = mav_driver->getStatus();
+
+ return {.send_errors = mav_stats.nSendErrors,
+ .packet_rx_success_count =
+ mav_stats.mavStats.packet_rx_success_count,
+ .packet_rx_drop_count = mav_stats.mavStats.packet_rx_drop_count,
+ .bits_rx_count = bits_rx_count,
+ .bits_tx_count = bits_tx_count,
+ .rx_rssi = sx1278->getLastRxRssi(),
+ .rx_fei = sx1278->getLastRxFei()};
+ }
+ else
+ {
+ return {0};
+ }
+}
+
+bool RadioBase::start(std::unique_ptr<SX1278Fsk> sx1278)
+{
+ this->sx1278 = std::move(sx1278);
+
+ auto mav_handler = [this](RadioMavDriver* channel,
+ const mavlink_message_t& msg) { handleMsg(msg); };
+
+ mav_driver = std::make_unique<RadioMavDriver>(
+ this, mav_handler, Groundstation::MAV_SLEEP_AFTER_SEND,
+ Groundstation::MAV_OUT_BUFFER_MAX_AGE);
+
+ if (!mav_driver->start())
+ {
+ return false;
+ }
+
+ if (!ActiveObject::start())
+ {
+ return false;
+ }
+
+ started = true;
+ return true;
+}
+
+void RadioBase::run()
+{
+
+ while (!shouldStop())
+ {
+ miosix::Thread::sleep(AUTOMATIC_FLUSH_PERIOD);
+
+ // If enough time has passed, automatically flush.
+ if (miosix::getTick() > last_eot_packet_ts + AUTOMATIC_FLUSH_DELAY)
+ {
+ flush();
+ }
+ }
+}
+
+ssize_t RadioBase::receive(uint8_t* pkt, size_t max_len)
+{
+ ssize_t ret = sx1278->receive(pkt, max_len);
+ if (ret > 0)
+ {
+ bits_rx_count += ret * 8;
+ }
+
+ return ret;
+}
+
+bool RadioBase::send(uint8_t* pkt, size_t len)
+{
+ bool ret = sx1278->send(pkt, len);
+ if (ret)
+ {
+ bits_tx_count += len * 8;
+ }
+
+ return ret;
+}
+
+void RadioBase::handleMsg(const mavlink_message_t& msg)
+{
+ // Dispatch the message through the hub.
+ ModuleManager::getInstance().get<HubBase>()->dispatchIncomingMsg(msg);
+
+ if (isEndOfTransmissionPacket(msg))
+ {
+ last_eot_packet_ts = miosix::getTick();
+ flush();
+ }
+}
+
+void RadioBase::flush()
+{
+ Lock<FastMutex> l(pending_msgs_mutex);
+ for (size_t i = 0; i < pending_msgs_count; i++)
+ {
+ mav_driver->enqueueMsg(pending_msgs[i]);
+ }
+
+ pending_msgs_count = 0;
+}
+
+bool RadioBase::isEndOfTransmissionPacket(const mavlink_message_t& msg)
+{
+ return msg.msgid == MAVLINK_MSG_ID_ROCKET_FLIGHT_TM ||
+ msg.msgid == MAVLINK_MSG_ID_PAYLOAD_FLIGHT_TM;
+}
\ No newline at end of file
diff --git a/src/boards/Groundstation/Common/Radio/RadioBase.h b/src/boards/Groundstation/Common/Radio/RadioBase.h
new file mode 100644
index 000000000..306791210
--- /dev/null
+++ b/src/boards/Groundstation/Common/Radio/RadioBase.h
@@ -0,0 +1,128 @@
+/* Copyright (c) 2023 Skyward Experimental Rocketry
+ * Author: Davide Mor
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <ActiveObject.h>
+#include <Groundstation/Common/Config/RadioConfig.h>
+#include <common/Mavlink.h>
+#include <common/Radio.h>
+#include <radio/MavlinkDriver/MavlinkDriver.h>
+#include <radio/SX1278/SX1278Fsk.h>
+
+#include <memory>
+#include <utils/ModuleManager/ModuleManager.hpp>
+
+namespace Groundstation
+{
+
+using RadioMavDriver =
+ Boardcore::MavlinkDriver<Boardcore::SX1278Fsk::MTU,
+ Groundstation::MAV_OUT_QUEUE_SIZE,
+ MAVLINK_MAX_DIALECT_PAYLOAD_SIZE>;
+
+/**
+ * @brief Statistics of the radio.
+ */
+struct RadioStats
+{
+ uint16_t send_errors; //< Number of failed sends.
+ uint16_t packet_rx_success_count; //< Number of received packets.
+ uint16_t packet_rx_drop_count; //< Number of packet drops.
+ uint32_t bits_rx_count; //< Number of bits received.
+ uint32_t bits_tx_count; //< Number of bits sent.
+ float rx_rssi; //< RSSI in dBm of last received packet.
+ float rx_fei; //< Frequency error index in Hz of last received packet.
+};
+
+/**
+ * @brief Base radio class, used to implement functionality independent of
+ * main/payload radios.
+ */
+class RadioBase : private Boardcore::ActiveObject, public Boardcore::Transceiver
+{
+public:
+ RadioBase() {}
+
+ /**
+ * @brief Send a mavlink message through this radio.
+ *
+ * @returns false when the queue is full.
+ */
+ bool sendMsg(const mavlink_message_t& msg);
+
+ /**
+ * @brief Handle generic DIO irq.
+ */
+ void handleDioIRQ();
+
+ /**
+ * @brief Retrieve current statistics metrics.
+ */
+ RadioStats getStats();
+
+protected:
+ /**
+ * @brief Initialize this radio module.
+ */
+ bool start(std::unique_ptr<Boardcore::SX1278Fsk> sx1278);
+
+private:
+ void run() override;
+
+ ssize_t receive(uint8_t* pkt, size_t max_len) override;
+
+ bool send(uint8_t* pkt, size_t len) override;
+
+ /**
+ * @brief Called internally when a message is received.
+ */
+ void handleMsg(const mavlink_message_t& msg);
+
+ /**
+ * @brief Flush all pending messages.
+ */
+ void flush();
+
+ /**
+ * @brief Check if a message signals an end of transmission
+ */
+ bool isEndOfTransmissionPacket(const mavlink_message_t& msg);
+
+ bool started = false;
+
+ miosix::FastMutex pending_msgs_mutex;
+ mavlink_message_t pending_msgs[Groundstation::MAV_PENDING_OUT_QUEUE_SIZE];
+ size_t pending_msgs_count = 0;
+
+ long long last_eot_packet_ts = 0;
+
+ uint32_t bits_rx_count = 0;
+ uint32_t bits_tx_count = 0;
+
+ // Objects are always destructed in reverse order, so keep them in this
+ // order
+ std::unique_ptr<Boardcore::SX1278Fsk> sx1278;
+ std::unique_ptr<RadioMavDriver> mav_driver;
+};
+
+} // namespace Groundstation
\ No newline at end of file
diff --git a/src/boards/Groundstation/Nokia/Buses.h b/src/boards/Groundstation/Nokia/Buses.h
new file mode 100644
index 000000000..8a3f17a18
--- /dev/null
+++ b/src/boards/Groundstation/Nokia/Buses.h
@@ -0,0 +1,42 @@
+/* Copyright (c) 2023 Skyward Experimental Rocketry
+ * Author: Davide Mor
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <drivers/spi/SPIBus.h>
+
+#include <utils/ModuleManager/ModuleManager.hpp>
+
+#include "interfaces-impl/hwmapping.h"
+
+namespace GroundstationNokia
+{
+
+class Buses : public Boardcore::Module
+{
+public:
+ Boardcore::SPIBus radio_bus;
+
+ Buses() : radio_bus(SPI4) {}
+};
+
+} // namespace GroundstationNokia
\ No newline at end of file
diff --git a/src/boards/Groundstation/Nokia/Hub.cpp b/src/boards/Groundstation/Nokia/Hub.cpp
new file mode 100644
index 000000000..ab06368e1
--- /dev/null
+++ b/src/boards/Groundstation/Nokia/Hub.cpp
@@ -0,0 +1,47 @@
+/* Copyright (c) 2023 Skyward Experimental Rocketry
+ * Author: Davide Mor
+ *
+ * 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.
+ */
+
+#include "Hub.h"
+
+#include <Groundstation/Common/Config/GeneralConfig.h>
+#include <Groundstation/Common/Ports/Serial.h>
+#include <Groundstation/Nokia/Radio/Radio.h>
+
+using namespace Groundstation;
+using namespace GroundstationNokia;
+using namespace Boardcore;
+
+void Hub::dispatchOutgoingMsg(const mavlink_message_t& msg)
+{
+ Radio* radio = ModuleManager::getInstance().get<Radio>();
+
+ if (!radio->sendMsg(msg))
+ {
+ sendNack(msg);
+ }
+}
+
+void Hub::dispatchIncomingMsg(const mavlink_message_t& msg)
+{
+ Serial* serial = ModuleManager::getInstance().get<Serial>();
+ serial->sendMsg(msg);
+}
\ No newline at end of file
diff --git a/src/boards/Groundstation/Nokia/Hub.h b/src/boards/Groundstation/Nokia/Hub.h
new file mode 100644
index 000000000..0351d7ab8
--- /dev/null
+++ b/src/boards/Groundstation/Nokia/Hub.h
@@ -0,0 +1,54 @@
+/* Copyright (c) 2023 Skyward Experimental Rocketry
+ * Author: Davide Mor
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <Groundstation/Common/HubBase.h>
+#include <common/Mavlink.h>
+
+#include <utils/ModuleManager/ModuleManager.hpp>
+
+namespace GroundstationNokia
+{
+
+/**
+ * @brief Central hub connecting all outgoing and ingoing modules.
+ */
+class Hub : public Groundstation::HubBase
+{
+public:
+ Hub() {}
+
+ /**
+ * @brief Dispatch to the correct interface and outgoing packet (gs ->
+ * rocket).
+ */
+ void dispatchOutgoingMsg(const mavlink_message_t& msg) override;
+
+ /**
+ * @brief Dispatch to the correct interface and incoming packet (rocket ->
+ * gs).
+ */
+ void dispatchIncomingMsg(const mavlink_message_t& msg) override;
+};
+
+} // namespace GroundstationNokia
\ No newline at end of file
diff --git a/src/boards/Groundstation/Nokia/Radio/Radio.cpp b/src/boards/Groundstation/Nokia/Radio/Radio.cpp
new file mode 100644
index 000000000..2e27dfac3
--- /dev/null
+++ b/src/boards/Groundstation/Nokia/Radio/Radio.cpp
@@ -0,0 +1,94 @@
+/* Copyright (c) 2023 Skyward Experimental Rocketry
+ * Author: Davide Mor
+ *
+ * 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.
+ */
+
+#include "Radio.h"
+
+#include <Groundstation/Common/Ports/Serial.h>
+#include <Groundstation/Nokia/Buses.h>
+#include <radio/SX1278/SX1278Frontends.h>
+
+#include "interfaces-impl/hwmapping.h"
+
+using namespace Groundstation;
+using namespace GroundstationNokia;
+using namespace Boardcore;
+using namespace miosix;
+
+#define SX1278_DIO0_IRQ EXTI6_IRQHandlerImpl
+#define SX1278_DIO1_IRQ EXTI4_IRQHandlerImpl
+#define SX1278_DIO3_IRQ EXTI11_IRQHandlerImpl
+
+void __attribute__((used)) SX1278_DIO0_IRQ()
+{
+ ModuleManager::getInstance().get<Radio>()->handleDioIRQ();
+}
+
+void __attribute__((used)) SX1278_DIO1_IRQ()
+{
+ ModuleManager::getInstance().get<Radio>()->handleDioIRQ();
+}
+
+void __attribute__((used)) SX1278_DIO3_IRQ()
+{
+ ModuleManager::getInstance().get<Radio>()->handleDioIRQ();
+}
+
+bool Radio::start()
+{
+#ifdef SKYWARD_GS_MAIN_USE_BACKUP_RF
+#error "Backup RF not supported on nokia"
+#else
+ std::unique_ptr<SX1278::ISX1278Frontend> frontend =
+ std::make_unique<RA01Frontend>();
+#endif
+
+ std::unique_ptr<Boardcore::SX1278Fsk> sx1278 =
+ std::make_unique<Boardcore::SX1278Fsk>(
+ ModuleManager::getInstance()
+ .get<GroundstationNokia::Buses>()
+ ->radio_bus,
+ peripherals::ra01::pc13::cs::getPin(),
+ peripherals::ra01::pc13::dio0::getPin(),
+ peripherals::ra01::pc13::dio1::getPin(),
+ peripherals::ra01::pc13::dio3::getPin(), SPI::ClockDivider::DIV_64,
+ std::move(frontend));
+
+ // First check if the device is even connected
+ if (!sx1278->checkVersion())
+ {
+ return false;
+ }
+
+ // Configure the radio
+ if (sx1278->configure(Common::MAIN_RADIO_CONFIG) != SX1278Fsk::Error::NONE)
+ {
+ return false;
+ }
+
+ // Initialize if only if present
+ if (!RadioBase::start(std::move(sx1278)))
+ {
+ return false;
+ }
+
+ return true;
+}
\ No newline at end of file
diff --git a/src/boards/Groundstation/Nokia/Radio/Radio.h b/src/boards/Groundstation/Nokia/Radio/Radio.h
new file mode 100644
index 000000000..950b8243a
--- /dev/null
+++ b/src/boards/Groundstation/Nokia/Radio/Radio.h
@@ -0,0 +1,36 @@
+/* Copyright (c) 2023 Skyward Experimental Rocketry
+ * Author: Davide Mor
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <Groundstation/Common/Radio/RadioBase.h>
+
+namespace GroundstationNokia
+{
+
+class Radio : public Groundstation::RadioBase, public Boardcore::Module
+{
+public:
+ [[nodiscard]] bool start();
+};
+
+} // namespace GroundstationNokia
\ No newline at end of file
diff --git a/src/boards/common/Radio.h b/src/boards/common/Radio.h
new file mode 100644
index 000000000..efdfa4b89
--- /dev/null
+++ b/src/boards/common/Radio.h
@@ -0,0 +1,54 @@
+/* Copyright (c) 2023 Skyward Experimental Rocketry
+ * Author: Davide Mor
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <radio/SX1278/SX1278Fsk.h>
+
+namespace Common
+{
+
+static const Boardcore::SX1278Fsk::Config MAIN_RADIO_CONFIG = {
+ .freq_rf = 419000000,
+ .freq_dev = 50000,
+ .bitrate = 48000,
+ .rx_bw = Boardcore::SX1278Fsk::Config::RxBw::HZ_125000,
+ .afc_bw = Boardcore::SX1278Fsk::Config::RxBw::HZ_125000,
+ .ocp = 120,
+ .power = 13,
+ .shaping = Boardcore::SX1278Fsk::Config::Shaping::GAUSSIAN_BT_1_0,
+ .dc_free = Boardcore::SX1278Fsk::Config::DcFree::WHITENING,
+ .enable_crc = false};
+
+static const Boardcore::SX1278Fsk::Config PAYLOAD_RADIO_CONFIG = {
+ .freq_rf = 868000000,
+ .freq_dev = 50000,
+ .bitrate = 48000,
+ .rx_bw = Boardcore::SX1278Fsk::Config::RxBw::HZ_125000,
+ .afc_bw = Boardcore::SX1278Fsk::Config::RxBw::HZ_125000,
+ .ocp = 120,
+ .power = 13,
+ .shaping = Boardcore::SX1278Fsk::Config::Shaping::GAUSSIAN_BT_1_0,
+ .dc_free = Boardcore::SX1278Fsk::Config::DcFree::WHITENING,
+ .enable_crc = false};
+
+} // namespace Common
\ No newline at end of file
diff --git a/src/entrypoints/Groundstation/base-groundstation-entry.cpp b/src/entrypoints/Groundstation/base-groundstation-entry.cpp
new file mode 100644
index 000000000..99b7374fc
--- /dev/null
+++ b/src/entrypoints/Groundstation/base-groundstation-entry.cpp
@@ -0,0 +1,143 @@
+/* Copyright (c) 2023 Skyward Experimental Rocketry
+ * Author: Davide Mor
+ *
+ * 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.
+ */
+
+#include <Groundstation/Base/BoardStatus.h>
+#include <Groundstation/Base/Buses.h>
+#include <Groundstation/Base/Hub.h>
+#include <Groundstation/Base/Ports/Ethernet.h>
+#include <Groundstation/Base/Radio/Radio.h>
+#include <Groundstation/Common/Ports/Serial.h>
+#include <miosix.h>
+
+using namespace Groundstation;
+using namespace GroundstationBase;
+using namespace Boardcore;
+using namespace miosix;
+
+void idleLoop()
+{
+ while (1)
+ {
+ Thread::wait();
+ }
+}
+
+void errorLoop()
+{
+ while (1)
+ {
+ led1On();
+ Thread::sleep(100);
+ led1Off();
+ Thread::sleep(100);
+ }
+}
+
+int main()
+{
+ ledOff();
+
+ Hub *hub = new Hub();
+ Buses *buses = new Buses();
+ Serial *serial = new Serial();
+ Ethernet *ethernet = new Ethernet();
+ RadioMain *radio_main = new RadioMain();
+ RadioPayload *radio_payload = new RadioPayload();
+ BoardStatus *board_status = new BoardStatus();
+
+ ModuleManager &modules = ModuleManager::getInstance();
+
+ bool ok = true;
+
+ ok &= modules.insert<HubBase>(hub);
+ ok &= modules.insert(buses);
+ ok &= modules.insert(serial);
+ ok &= modules.insert(ethernet);
+ ok &= modules.insert(radio_main);
+ ok &= modules.insert(radio_payload);
+ ok &= modules.insert(board_status);
+
+ // If insertion failed, stop right here
+ if (!ok)
+ {
+ printf("[error] Failed to insert all modules!\n");
+ errorLoop();
+ }
+
+ // Ok now start them
+
+ ok &= serial->start();
+ if (!ok)
+ {
+ printf("[error] Failed to start serial!\n");
+ }
+
+ ok &= ethernet->start();
+ if (!ok)
+ {
+ printf("[error] Failed to start ethernet!\n");
+ }
+
+ ok &= radio_main->start();
+ if (!ok)
+ {
+ printf("[error] Failed to start main radio!\n");
+ }
+
+ ok &= radio_payload->start();
+ if (!ok)
+ {
+ printf("[error] Failed to start payload radio!\n");
+ }
+
+ ok &= board_status->start();
+ if (!ok)
+ {
+ printf("[error] Failed to start board status!\n");
+ }
+
+ if (board_status->isMainRadioPresent())
+ {
+ printf("Main radio detected!\n");
+ led2On();
+ }
+
+ if (board_status->isPayloadRadioPresent())
+ {
+ printf("Payload radio detected!\n");
+ led3On();
+ }
+
+ if (board_status->isEthernetPresent())
+ {
+ printf("Ethernet detected!\n");
+ }
+
+ if (!ok)
+ {
+ errorLoop();
+ }
+
+ led1On();
+ idleLoop();
+ return 0;
+}
\ No newline at end of file
diff --git a/src/entrypoints/Groundstation/nokia-groundstation-entry.cpp b/src/entrypoints/Groundstation/nokia-groundstation-entry.cpp
new file mode 100644
index 000000000..da685704b
--- /dev/null
+++ b/src/entrypoints/Groundstation/nokia-groundstation-entry.cpp
@@ -0,0 +1,88 @@
+/* Copyright (c) 2023 Skyward Experimental Rocketry
+ * Author: Davide Mor
+ *
+ * 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.
+ */
+
+#include <Groundstation/Common/Ports/Serial.h>
+#include <Groundstation/Nokia/Buses.h>
+#include <Groundstation/Nokia/Hub.h>
+#include <Groundstation/Nokia/Radio/Radio.h>
+#include <miosix.h>
+
+using namespace Groundstation;
+using namespace GroundstationNokia;
+using namespace Boardcore;
+using namespace miosix;
+
+void idleLoop()
+{
+ while (1)
+ {
+ Thread::wait();
+ }
+}
+
+int main()
+{
+ ledOff();
+
+ Hub *hub = new Hub();
+ Buses *buses = new Buses();
+ Radio *radio = new Radio();
+ Serial *serial = new Serial();
+
+ ModuleManager &modules = ModuleManager::getInstance();
+
+ bool ok = true;
+
+ ok &= modules.insert<HubBase>(hub);
+ ok &= modules.insert(buses);
+ ok &= modules.insert(serial);
+ ok &= modules.insert(radio);
+
+ // If insertion failed, stop right here
+ if (!ok)
+ {
+ printf("[error] Failed to insert all modules!\n");
+ idleLoop();
+ }
+
+ // Ok now start them
+
+ ok &= serial->start();
+ if (!ok)
+ {
+ printf("[error] Failed to start serial!\n");
+ }
+
+ ok &= radio->start();
+ if (!ok)
+ {
+ printf("[error] Failed to start radio!\n");
+ }
+
+ if (ok)
+ {
+ printf("Init complete!\n");
+ }
+
+ idleLoop();
+ return 0;
+}
\ No newline at end of file
--
GitLab