From 4f17dc7deb1234819827aee6a8727aa47c14c6e3 Mon Sep 17 00:00:00 2001 From: Federico Lolli <federico.lolli@skywarder.eu> Date: Wed, 13 Mar 2024 18:21:50 +0100 Subject: [PATCH] Completed sender entrypoint --- justfile | 12 +- on-device/CMakeLists.txt | 57 +--- on-device/cmake/dependencies.cmake | 2 +- on-device/src/config/Mavlink.h | 29 ++ on-device/src/config/RadioConfig.h | 29 +- .../src/entrypoints/arpist-device-sender.cpp | 301 ------------------ .../entrypoints/arpist_device_receiver.cpp | 86 +++++ .../arpist_device_sender.cpp} | 66 ++-- .../src/entrypoints/test_mavlink_parse.cpp | 11 +- on-device/src/shared/Radio.cpp | 81 ----- on-device/src/shared/mavlink/Utils.h | 73 +++++ on-device/src/shared/radio/Radio.cpp | 120 +++++++ on-device/src/shared/radio/Radio.h | 92 ++++++ 13 files changed, 476 insertions(+), 483 deletions(-) create mode 100644 on-device/src/config/Mavlink.h delete mode 100644 on-device/src/entrypoints/arpist-device-sender.cpp create mode 100644 on-device/src/entrypoints/arpist_device_receiver.cpp rename on-device/src/{shared/Radio.h => entrypoints/arpist_device_sender.cpp} (58%) delete mode 100644 on-device/src/shared/Radio.cpp create mode 100644 on-device/src/shared/mavlink/Utils.h create mode 100644 on-device/src/shared/radio/Radio.cpp create mode 100644 on-device/src/shared/radio/Radio.h diff --git a/justfile b/justfile index ce73400..07fe540 100644 --- a/justfile +++ b/justfile @@ -1,7 +1,8 @@ export RUST_LOG := "debug" -alias db := device-build alias hb := host-build +alias dbs := device-build-sender +alias dbr := device-build-receiver default: ./arpist gemini.csv @@ -12,7 +13,12 @@ host-build: cargo build --release cp target/release/arpist .. -device-build: +device-build-sender: #!/bin/bash cd on-device - ./sbs -df test-mavlink-parse + ./sbs -df arpist-device-sender + +device-build-receiver: + #!/bin/bash + cd on-device + ./sbs -df arpist-device-receiver diff --git a/on-device/CMakeLists.txt b/on-device/CMakeLists.txt index 390a8d6..e11574b 100644 --- a/on-device/CMakeLists.txt +++ b/on-device/CMakeLists.txt @@ -30,60 +30,17 @@ include(libs/boardcore/cmake/sbs.cmake) project(Arpist) #-----------------------------------------------------------------------------# -# Flight entrypoints # +# Arpist entrypoints # #-----------------------------------------------------------------------------# add_executable(test-mavlink-parse src/entrypoints/test_mavlink_parse.cpp ${RADIO}) target_include_directories(test-mavlink-parse PRIVATE ${ARPIST_INCLUDE_DIRS}) sbs_target(test-mavlink-parse stm32f429zi_skyward_groundstation_v2) -# add_executable(test-hil src/entrypoints/HIL/test-hil.cpp ${HIL}) -# target_include_directories(test-hil PRIVATE ${OBSW_INCLUDE_DIRS}) -# target_compile_definitions(test-hil PRIVATE HILTest) -# sbs_target(test-hil stm32f767zi_compute_unit) +add_executable(arpist-device-sender src/entrypoints/arpist_device_sender.cpp ${RADIO}) +target_include_directories(arpist-device-sender PRIVATE ${ARPIST_INCLUDE_DIRS}) +sbs_target(arpist-device-sender stm32f429zi_skyward_groundstation_v2) -# 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) - -# add_executable(automated-antennas-entry -# src/entrypoints/Groundstation/Automated/automated-antennas-entry.cpp -# ${ANTENNAS} ${GROUNDSTATION_COMMON} ${GROUNDSTATION_AUTOMATED} -# ) -# target_include_directories(automated-antennas-entry PRIVATE ${OBSW_INCLUDE_DIRS}) -# sbs_target(automated-antennas-entry stm32f767zi_automated_antennas) - -# add_executable(test-automated-radio -# src/entrypoints/Groundstation/Automated/test-automated-radio.cpp -# ${ANTENNAS} ${GROUNDSTATION_COMMON} ${GROUNDSTATION_AUTOMATED} -# ) -# target_include_directories(test-automated-radio PRIVATE ${OBSW_INCLUDE_DIRS}) -# # target_compile_definitions(test-automated-radio PRIVATE NO_SD_LOGGING) -# sbs_target(test-automated-radio stm32f767zi_automated_antennas) - -# add_executable(test-steps src/entrypoints/Groundstation/Automated/test-steps.cpp ${ANTENNAS}) -# target_include_directories(test-steps PRIVATE ${OBSW_INCLUDE_DIRS}) -# # target_compile_definitions(test-steps PRIVATE NO_SD_LOGGING) -# sbs_target(test-steps stm32f767zi_automated_antennas) - -# add_executable(test-actuators src/entrypoints/Groundstation/Automated/test-actuators.cpp -# ${ANTENNAS} ${GROUNDSTATION_COMMON} ${GROUNDSTATION_AUTOMATED} -# ) -# target_include_directories(test-actuators PRIVATE ${OBSW_INCLUDE_DIRS}) -# # target_compile_definitions(test-actuators PRIVATE NO_SD_LOGGING) -# sbs_target(test-actuators stm32f767zi_automated_antennas) - -# add_executable(test-smcontroller src/entrypoints/Groundstation/Automated/test-smcontroller.cpp ${GROUNDSTATION_COMMON}) -# target_include_directories(test-smcontroller PRIVATE ${OBSW_INCLUDE_DIRS}) -# # target_compile_definitions(test-smcontroller PRIVATE NO_SD_LOGGING) -# sbs_target(test-smcontroller stm32f767zi_nucleo) +add_executable(arpist-device-receiver src/entrypoints/arpist_device_receiver.cpp ${RADIO}) +target_include_directories(arpist-device-receiver PRIVATE ${ARPIST_INCLUDE_DIRS}) +sbs_target(arpist-device-receiver stm32f429zi_skyward_groundstation_v2) diff --git a/on-device/cmake/dependencies.cmake b/on-device/cmake/dependencies.cmake index 0c2fafe..9a187f6 100644 --- a/on-device/cmake/dependencies.cmake +++ b/on-device/cmake/dependencies.cmake @@ -25,5 +25,5 @@ set(ARPIST_INCLUDE_DIRS ) set(RADIO - src/shared/Radio.cpp + src/shared/radio/Radio.cpp ) diff --git a/on-device/src/config/Mavlink.h b/on-device/src/config/Mavlink.h new file mode 100644 index 0000000..4313049 --- /dev/null +++ b/on-device/src/config/Mavlink.h @@ -0,0 +1,29 @@ +/* Copyright (c) 2023 Skyward Experimental Rocketry + * Author: Matteo Pignataro + * + * 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. + */ + +// Ignore warnings as these are auto-generated headers made by a third party +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-align" +#pragma GCC diagnostic ignored "-Waddress-of-packed-member" +#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" +#include <mavlink_lib/lyra/mavlink.h> +#pragma GCC diagnostic pop diff --git a/on-device/src/config/RadioConfig.h b/on-device/src/config/RadioConfig.h index 0049142..7fba28f 100644 --- a/on-device/src/config/RadioConfig.h +++ b/on-device/src/config/RadioConfig.h @@ -24,15 +24,24 @@ #include <radio/SX1278/SX1278Fsk.h> +namespace Arpist +{ + +constexpr size_t MAV_OUT_QUEUE_SIZE = 10; +constexpr uint16_t MAV_SLEEP_AFTER_SEND = 0; +constexpr size_t MAV_OUT_BUFFER_MAX_AGE = 10; + // Radio configuration constexpr Boardcore::SX1278Fsk::Config RADIO_CONFIG = { - .freq_rf = 421000000, - .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 = true}; + .freq_rf = 434000000, + .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 Arpist diff --git a/on-device/src/entrypoints/arpist-device-sender.cpp b/on-device/src/entrypoints/arpist-device-sender.cpp deleted file mode 100644 index fbd0ef5..0000000 --- a/on-device/src/entrypoints/arpist-device-sender.cpp +++ /dev/null @@ -1,301 +0,0 @@ -/* Copyright (c) 2024 Skyward Experimental Rocketry - * Author: Federico Lolli - * - * 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 <drivers/interrupt/external_interrupts.h> -#include <filesystem/console/console_device.h> -#include <mavlink_lib/gemini/mavlink.h> -// SX1278 includes -#include <radio/SX1278/SX1278Frontends.h> -#include <radio/SX1278/SX1278Fsk.h> -#include <radio/SX1278/SX1278Lora.h> -#include <config/radio.h> - -#include <iostream> -#include <thread> - -using namespace miosix; - -#if defined _BOARD_STM32F429ZI_SKYWARD_GS_V2 -#include "interfaces-impl/hwmapping.h" - -using cs = peripherals::ra01::pc13::cs; -using dio0 = peripherals::ra01::pc13::dio0; -using dio1 = peripherals::ra01::pc13::dio1; -using dio3 = peripherals::ra01::pc13::dio3; - -using sck = interfaces::spi4::sck; -using miso = interfaces::spi4::miso; -using mosi = interfaces::spi4::mosi; - -#define SX1278_SPI SPI4 - -#define SX1278_IRQ_DIO0 EXTI6_IRQHandlerImpl -#define SX1278_IRQ_DIO1 EXTI4_IRQHandlerImpl -#define SX1278_IRQ_DIO3 EXTI11_IRQHandlerImpl -#else -#error "Target not supported" -#endif - -// === CONSTANTS === -static constexpr size_t SX1278_MTU = Boardcore::SX1278Fsk::MTU; -constexpr size_t PACKET_SIZE = MAVLINK_MSG_ID_PAYLOAD_FLIGHT_TM_LEN; - -/** @brief Number of packets to send */ -constexpr size_t MSG_NUM = 580; - -/** @brief End of transmission character */ -constexpr uint8_t ACK = 0x06; - -// === GLOBALS === -Boardcore::SX1278Fsk *sx1278 = nullptr; -Boardcore::SPIBus sx1278_bus(SX1278_SPI); - -volatile int dio0_cnt = 0; -volatile int dio1_cnt = 0; -volatile int dio3_cnt = 0; - -// === INTERRUPTS === -#ifdef SX1278_IRQ_DIO0 -void __attribute__((used)) SX1278_IRQ_DIO0() -{ - dio0_cnt++; - if (sx1278) - sx1278->handleDioIRQ(); -} -#endif - -#ifdef SX1278_IRQ_DIO1 -void __attribute__((used)) SX1278_IRQ_DIO1() -{ - dio1_cnt++; - if (sx1278) - sx1278->handleDioIRQ(); -} -#endif - -#ifdef SX1278_IRQ_DIO3 -void __attribute__((used)) SX1278_IRQ_DIO3() -{ - dio3_cnt++; - if (sx1278) - sx1278->handleDioIRQ(); -} -#endif - -// === DEFINITIONS === -void recvLoop(); -void sendLoop(); -mavlink_message_t readPacketFromSerial(); -void initBoard(); - -// === MAIN === -int main() -{ - initBoard(); - -#if defined SX1278_IS_SENDER - sendLoop(); -#elif defined SX1278_IS_RECEIVER - recvLoop(); -#else - // this may cause problems with stdin and stdout - // interfering with each other - - // Actually spawn threads - std::thread send([]() - { sendLoop(); }); - recvLoop(); -#endif - - return 0; -} - -// === IMPLEMENTATIONS === -void recvLoop() -{ - uint8_t msg[SX1278_MTU]; - while (1) - { - int len = sx1278->receive(msg, sizeof(msg)); - if (len == PACKET_SIZE) - { - mavlink_payload_flight_tm_t tm; - memcpy(&tm, msg, PACKET_SIZE); - - // auto serial = miosix::DefaultConsole::instance().get(); - // serial->writeBlock(msg, len, 0); - std::cout << "[sx1278] Received packet - time: " << tm.timestamp - << std::endl; - // std::cout << "[sx1278] tm.timestamp: " << tm.timestamp << - // std::endl; std::cout << "[sx1278] tm.pressure_digi: " << - // tm.pressure_digi - // << std::endl; - // std::cout << "[sx1278] tm.pressure_static: " << - // tm.pressure_static - // << std::endl; - // std::cout << "[sx1278] tm.airspeed_pitot: " << tm.airspeed_pitot - // << std::endl; - // std::cout << "[sx1278] tm.altitude_agl: " << tm.altitude_agl - // << std::endl; - // std::cout << "[sx1278] tm.acc_x: " << tm.acc_x << std::endl; - // std::cout << "[sx1278] tm.acc_y: " << tm.acc_y << std::endl; - // std::cout << "[sx1278] tm.acc_z: " << tm.acc_z << std::endl; - // std::cout << "[sx1278] tm.gyro_x: " << tm.gyro_x << std::endl; - // std::cout << "[sx1278] tm.gyro_y: " << tm.gyro_y << std::endl; - // std::cout << "[sx1278] tm.gyro_z: " << tm.gyro_z << std::endl; - // std::cout << "[sx1278] tm.mag_x: " << tm.mag_x << std::endl; - // std::cout << "[sx1278] tm.mag_y: " << tm.mag_y << std::endl; - // std::cout << "[sx1278] tm.mag_z: " << tm.mag_z << std::endl; - // std::cout << "[sx1278] tm.gps_lat: " << tm.gps_lat << std::endl; - // std::cout << "[sx1278] tm.gps_lon: " << tm.gps_lon << std::endl; - // std::cout << "[sx1278] tm.gps_alt: " << tm.gps_alt << std::endl; - // std::cout << "[sx1278] tm.left_servo_angle: " << - // tm.left_servo_angle - // << std::endl; - // std::cout << "[sx1278] tm.right_servo_angle: " - // << tm.right_servo_angle << std::endl; - // std::cout << "[sx1278] tm.nas_n: " << tm.nas_n << std::endl; - // std::cout << "[sx1278] tm.nas_e: " << tm.nas_e << std::endl; - // std::cout << "[sx1278] tm.nas_d: " << tm.nas_d << std::endl; - // std::cout << "[sx1278] tm.nas_vn: " << tm.nas_vn << std::endl; - // std::cout << "[sx1278] tm.nas_ve: " << tm.nas_ve << std::endl; - // std::cout << "[sx1278] tm.nas_vd: " << tm.nas_vd << std::endl; - // std::cout << "[sx1278] tm.nas_qx: " << tm.nas_qx << std::endl; - // std::cout << "[sx1278] tm.nas_qy: " << tm.nas_qy << std::endl; - // std::cout << "[sx1278] tm.nas_qz: " << tm.nas_qz << std::endl; - // std::cout << "[sx1278] tm.nas_qw: " << tm.nas_qw << std::endl; - // std::cout << "[sx1278] tm.nas_bias_x: " << tm.nas_bias_x - // << std::endl; - // std::cout << "[sx1278] tm.nas_bias_y: " << tm.nas_bias_y - // << std::endl; - // std::cout << "[sx1278] tm.nas_bias_z: " << tm.nas_bias_z - // << std::endl; - // std::cout << "[sx1278] tm.wes_n: " << tm.wes_n << std::endl; - // std::cout << "[sx1278] tm.wes_e: " << tm.wes_e << std::endl; - // std::cout << "[sx1278] tm.vbat: " << tm.vbat << std::endl; - // std::cout << "[sx1278] tm.vsupply_5v: " << tm.vsupply_5v - // << std::endl; - // std::cout << "[sx1278] tm.temperature: " << tm.temperature - // << std::endl; - // std::cout << "[sx1278] tm.fmm_state: " << tm.fmm_state << - // std::endl; std::cout << "[sx1278] tm.nas_state: " << tm.nas_state - // << std::endl; std::cout << "[sx1278] tm.wes_state: " << - // tm.wes_state << std::endl; std::cout << "[sx1278] tm.gps_fix: " - // << tm.gps_fix << std::endl; std::cout << "[sx1278] - // tm.pin_nosecone: " << tm.pin_nosecone - // << std::endl; - // std::cout << "[sx1278] tm.logger_error: " << tm.logger_error - // << std::endl; - } - } -} - -void sendLoop() -{ - uint8_t msg[SX1278_MTU]; - while (1) - { - mavlink_message_t tm = readPacketFromSerial(); - // std::cout << "[sx1278] Sending packet" << std::endl; - sx1278->send(&tm, PACKET_SIZE); - } -} - -/** - * @brief Read a packet from the serial port - * @warning This function will parse raw bytes coming from - * serial into the struct - * @return mavlink_payload_flight_tm_t - */ -mavlink_message_t readPacketFromSerial() -{ - mavlink_message_t msg; - bool stop_flag = false; - ssize_t rcv_size; - uint8_t serial_buffer[171]; - uint8_t parse_result = 0; - mavlink_status_t status; - - auto serial = DefaultConsole::instance().get(); - - while (!stop_flag) - { - // Check for a new message on the device - rcv_size = serial->readBlock(serial_buffer, 171, 0); - // printf("Received %d bytes\n", rcv_size); - - // If there's a new message ... - if (rcv_size > 0) - { - for (int i = 0; i < rcv_size; i++) - { - parse_result = 0; - // ... parse received bytes - parse_result = - mavlink_parse_char(MAVLINK_COMM_0, - serial_buffer[i], // byte to parse - &msg, // where to parse it - &status); // stats to update - - // When a valid message is found ... - if (parse_result == 1) - break; - } - } - - break; - } - - // printf("Received message with ID %d\n", msg.msgid); - - serial->writeBlock(&ACK, 1, 0); - - // this may be shrunk to the above statement (needs further testing) - // memcpy(ptr_to_tm, serial_buffer, PACKET_SIZE); - - return msg; -} - -void initBoard() -{ - printf("[sx1278] Configuring RA01 frontend...\n"); - std::unique_ptr<Boardcore::SX1278::ISX1278Frontend> frontend( - new Boardcore::RA01Frontend()); - - // Run default configuration - Boardcore::SX1278Fsk::Error err; - - sx1278 = new Boardcore::SX1278Fsk(sx1278_bus, cs::getPin(), dio0::getPin(), - dio1::getPin(), dio3::getPin(), - Boardcore::SPI::ClockDivider::DIV_256, - std::move(frontend)); - - printf("\n[sx1278] Configuring sx1278 fsk...\n"); - if ((err = sx1278->init(RADIO_CONFIG)) != Boardcore::SX1278Fsk::Error::NONE) - { - // FIXME: Why does clang-format put this line up here? - printf("[sx1278] sx1278->init error\n"); - return; - } - - printf("\n[sx1278] Initialization complete!\n"); -} diff --git a/on-device/src/entrypoints/arpist_device_receiver.cpp b/on-device/src/entrypoints/arpist_device_receiver.cpp new file mode 100644 index 0000000..569c98c --- /dev/null +++ b/on-device/src/entrypoints/arpist_device_receiver.cpp @@ -0,0 +1,86 @@ +/* Copyright (c) 2024 Skyward Experimental Rocketry + * Author: Federico Lolli + * + * 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 <filesystem/console/console_device.h> +#include <mavlink_lib/gemini/mavlink.h> +#include <radio/MavlinkDriver/MavlinkDriver.h> +#include <shared/mavlink/Utils.h> +#include <shared/radio/Radio.h> + +using namespace miosix; +using namespace Boardcore; +using namespace Arpist; + +// === CONSTANTS === +/** @brief End of transmission character */ +constexpr uint8_t ACK = 0x06; + +using MavDriver = MavlinkDriver<20, 10>; + +// === DEFINITIONS === +void onReceive(MavDriver *channel, mavlink_message_t msg); + +// === MAIN === +int main() +{ + mavlink_message_t msg; + mavlink_payload_flight_tm_t payload; + MavDriver *mavlink; + + // init radio + if (Radio::init()) + { + printf("Radio init success\n"); + } + else + { + printf("Radio init failed\n"); + return -1; + } + + // init mavlink + mavlink = new MavDriver(sx1278, onReceive, 256); + if (mavlink->start()) + { + printf("Mavlink init success\n"); + } + else + { + printf("Mavlink init failed\n"); + return -1; + } + + while (1) + { + } + + return 0; +} + +void onReceive(MavDriver *channel, mavlink_message_t msg) +{ + mavlink_payload_flight_tm_t payload; + + printf("Received message with ID %d\n", msg.msgid); + mavlink_msg_payload_flight_tm_decode(&msg, &payload); + printf("Received payload with timestamp %lld\n", payload.timestamp); +} diff --git a/on-device/src/shared/Radio.h b/on-device/src/entrypoints/arpist_device_sender.cpp similarity index 58% rename from on-device/src/shared/Radio.h rename to on-device/src/entrypoints/arpist_device_sender.cpp index 9eedcba..4bed47b 100644 --- a/on-device/src/shared/Radio.h +++ b/on-device/src/entrypoints/arpist_device_sender.cpp @@ -20,40 +20,42 @@ * THE SOFTWARE. */ -#pragma once - -#include <radio/SX1278/SX1278Frontends.h> -#include <radio/SX1278/SX1278Fsk.h> -#include <radio/SX1278/SX1278Lora.h> - -#if defined _BOARD_STM32F429ZI_SKYWARD_GS_V2 -#include "interfaces-impl/hwmapping.h" - -#define SX1278_SPI SPI4 -#define SX1278_IRQ_DIO0 EXTI6_IRQHandlerImpl -#define SX1278_IRQ_DIO1 EXTI4_IRQHandlerImpl -#define SX1278_IRQ_DIO3 EXTI11_IRQHandlerImpl -#else -#error "Target not supported" -#endif - -namespace Arpist +#include <filesystem/console/console_device.h> +#include <mavlink_lib/gemini/mavlink.h> +#include <radio/MavlinkDriver/MavlinkDriver.h> +#include <shared/mavlink/Utils.h> +#include <shared/radio/Radio.h> + +using namespace miosix; +using namespace Boardcore; +using namespace Arpist; + +// === CONSTANTS === +/** @brief End of transmission character */ +constexpr uint8_t ACK = 0x06; + +// === MAIN === +int main() { + mavlink_message_t msg; - static volatile int dio0_cnt = 0; - static volatile int dio1_cnt = 0; - static volatile int dio3_cnt = 0; - - static Boardcore::SX1278Fsk *sx1278 = nullptr; - static Boardcore::SPIBus sx1278_bus(SX1278_SPI); + // start radio + if (Radio::getInstance().start([](const mavlink_message_t&) {})) + { + printf("Radio start success\n"); + } + else + { + printf("Radio start failed\n"); + return -1; + } - /** - * @brief Radio class - */ - class Radio + while (true) { - public: - static bool init(); - }; + msg = readPacketFromSerial(); + DefaultConsole::instance().get()->writeBlock(&ACK, 1, 0); + Radio::getInstance().sendMsg(msg); + } -} // namespace Arpist + return 0; +} diff --git a/on-device/src/entrypoints/test_mavlink_parse.cpp b/on-device/src/entrypoints/test_mavlink_parse.cpp index f24bc95..2eae9dd 100644 --- a/on-device/src/entrypoints/test_mavlink_parse.cpp +++ b/on-device/src/entrypoints/test_mavlink_parse.cpp @@ -23,9 +23,9 @@ // #include <filesystem/console/console_device.h> #include <mavlink_lib/gemini/mavlink.h> // SX1278 includes -#include <radio/SerialTransceiver/SerialTransceiver.h> #include <radio/MavlinkDriver/MavlinkDriver.h> -#include <shared/Radio.h> +#include <radio/SerialTransceiver/SerialTransceiver.h> +#include <shared/radio/Radio.h> #include <iostream> #include <thread> @@ -62,6 +62,7 @@ int main() return 0; } + /** * @brief Read a packet from the serial port * @warning This function will parse raw bytes coming from @@ -94,9 +95,9 @@ mavlink_message_t readPacketFromSerial() // ... parse received bytes parse_result = mavlink_parse_char(MAVLINK_COMM_0, - serial_buffer[i], // byte to parse - &msg, // where to parse it - &status); // stats to update + serial_buffer[i], // byte to parse + &msg, // where to parse it + &status); // stats to update // When a valid message is found ... if (parse_result == 1) diff --git a/on-device/src/shared/Radio.cpp b/on-device/src/shared/Radio.cpp deleted file mode 100644 index f6f86aa..0000000 --- a/on-device/src/shared/Radio.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/* Copyright (c) 2024 Skyward Experimental Rocketry - * Author: Federico Lolli - * - * 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 <drivers/interrupt/external_interrupts.h> -#include <radio/SX1278/SX1278Frontends.h> -#include <radio/SX1278/SX1278Fsk.h> -#include <radio/SX1278/SX1278Lora.h> -#include <config/RadioConfig.h> - -#include "Radio.h" - -// === INTERRUPTS === -#ifdef SX1278_IRQ_DIO0 -void __attribute__((used)) SX1278_IRQ_DIO0() -{ - Arpist::dio0_cnt++; - if (Arpist::sx1278) - Arpist::sx1278->handleDioIRQ(); -} -#endif - -#ifdef SX1278_IRQ_DIO1 -void __attribute__((used)) SX1278_IRQ_DIO1() -{ - Arpist::dio1_cnt++; - if (Arpist::sx1278) - Arpist::sx1278->handleDioIRQ(); -} -#endif - -#ifdef SX1278_IRQ_DIO3 -void __attribute__((used)) SX1278_IRQ_DIO3() -{ - Arpist::dio3_cnt++; - if (Arpist::sx1278) - Arpist::sx1278->handleDioIRQ(); -} -#endif - -namespace Arpist -{ - - bool Radio::init() - { - using cs = miosix::peripherals::ra01::pc13::cs; - using dio0 = miosix::peripherals::ra01::pc13::dio0; - using dio1 = miosix::peripherals::ra01::pc13::dio1; - using dio3 = miosix::peripherals::ra01::pc13::dio3; - using sck = miosix::interfaces::spi4::sck; - using miso = miosix::interfaces::spi4::miso; - using mosi = miosix::interfaces::spi4::mosi; - - std::unique_ptr<Boardcore::SX1278::ISX1278Frontend> frontend( - new Boardcore::RA01Frontend()); - sx1278 = new Boardcore::SX1278Fsk( - sx1278_bus, cs::getPin(), dio0::getPin(), dio1::getPin(), - dio3::getPin(), Boardcore::SPI::ClockDivider::DIV_256, - std::move(frontend)); - return sx1278->init(RADIO_CONFIG) == Boardcore::SX1278Fsk::Error::NONE; - } - -} // namespace Arpist diff --git a/on-device/src/shared/mavlink/Utils.h b/on-device/src/shared/mavlink/Utils.h new file mode 100644 index 0000000..9db699c --- /dev/null +++ b/on-device/src/shared/mavlink/Utils.h @@ -0,0 +1,73 @@ +/* Copyright (c) 2024 Skyward Experimental Rocketry + * Author: Federico Lolli + * + * 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 <filesystem/console/console_device.h> +#include <mavlink_lib/gemini/mavlink.h> + +/** + * @brief Read a packet from the serial port + * @warning This function will parse raw bytes coming from + * serial into the struct + * @return mavlink_payload_flight_tm_t + */ +mavlink_message_t readPacketFromSerial() +{ + bool stop_flag = false; + ssize_t rcv_size; + uint8_t serial_buffer[128]; + uint8_t parse_result = 0; + mavlink_message_t msg; + mavlink_status_t status; + + auto serial = miosix::DefaultConsole::instance().get(); + + while (!stop_flag) + { + // Check for a new message on the device + rcv_size = serial->readBlock(serial_buffer, 128, 0); + // LOG_DEBUG("Received %d bytes\n", rcv_size); + + // If there's a new message ... + if (rcv_size > 0) + { + for (int i = 0; i < rcv_size; i++) + { + parse_result = 0; + // ... parse received bytes + parse_result = + mavlink_parse_char(MAVLINK_COMM_0, + serial_buffer[i], // byte to parse + &msg, // where to parse it + &status); // stats to update + + // When a valid message is found ... + if (parse_result == 1) + { + stop_flag = true; + break; + } + } + } + } + + return msg; +} diff --git a/on-device/src/shared/radio/Radio.cpp b/on-device/src/shared/radio/Radio.cpp new file mode 100644 index 0000000..5dc2f0a --- /dev/null +++ b/on-device/src/shared/radio/Radio.cpp @@ -0,0 +1,120 @@ +/* Copyright (c) 2024 Skyward Experimental Rocketry + * Author: Federico Lolli + * + * 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 <config/RadioConfig.h> +#include <radio/SX1278/SX1278Frontends.h> + +#include <memory> + +// === INTERRUPTS === +#ifdef SX1278_IRQ_DIO0 +void __attribute__((used)) SX1278_IRQ_DIO0() +{ + Arpist::Radio::getInstance().handleDioIRQ(); +} +#endif + +#ifdef SX1278_IRQ_DIO1 +void __attribute__((used)) SX1278_IRQ_DIO1() +{ + Arpist::Radio::getInstance().handleDioIRQ(); +} +#endif + +#ifdef SX1278_IRQ_DIO3 +void __attribute__((used)) SX1278_IRQ_DIO3() +{ + Arpist::Radio::getInstance().handleDioIRQ(); +} +#endif + +namespace Arpist +{ + +void Radio::handleDioIRQ() +{ + if (started) + { + sx1278->handleDioIRQ(); + } +} + +bool Radio::sendMsg(const mavlink_message_t &msg) +{ + if (!started) + { + return false; + } + + return mav_driver->enqueueMsg(msg); +} + +bool Radio::send(uint8_t *pkt, size_t len) { return sx1278->send(pkt, len); } + +ssize_t Radio::receive(uint8_t *pkt, size_t max_len) +{ + return sx1278->receive(pkt, max_len); +} + +bool Radio::start(std::function<void(const mavlink_message_t &)> onReceive) +{ + // initialize frontend + std::unique_ptr<Boardcore::SX1278::ISX1278Frontend> frontend = + std::make_unique<Boardcore::Skyward433Frontend>(); + + std::unique_ptr<Boardcore::SX1278Fsk> sx1278 = + std::make_unique<Boardcore::SX1278Fsk>( + sx1278_bus, radio_cs::getPin(), radio_dio0::getPin(), + radio_dio1::getPin(), radio_dio3::getPin(), + Boardcore::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(RADIO_CONFIG) != Boardcore::SX1278Fsk::Error::NONE) + return false; + + // Initialize + this->sx1278 = std::move(sx1278); + + auto mav_handler = + [onReceive](RadioMavDriver *channel, const mavlink_message_t &msg) + { onReceive(msg); }; + + mav_driver = std::make_unique<RadioMavDriver>( + this, mav_handler, Arpist::MAV_SLEEP_AFTER_SEND, + Arpist::MAV_OUT_BUFFER_MAX_AGE); + + if (!mav_driver->start()) + { + return false; + } + + started = true; + return true; +} + +} // namespace Arpist diff --git a/on-device/src/shared/radio/Radio.h b/on-device/src/shared/radio/Radio.h new file mode 100644 index 0000000..edd4b37 --- /dev/null +++ b/on-device/src/shared/radio/Radio.h @@ -0,0 +1,92 @@ +/* Copyright (c) 2024 Skyward Experimental Rocketry + * Author: Federico Lolli + * + * 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 <Singleton.h> +#include <config/Mavlink.h> +#include <config/RadioConfig.h> +#include <radio/MavlinkDriver/MavlinkDriver.h> +#include <radio/SX1278/SX1278Fsk.h> +#include <radio/SX1278/SX1278Lora.h> + +#if defined _BOARD_STM32F429ZI_SKYWARD_GS_V2 +#include "interfaces-impl/hwmapping.h" + +#define SX1278_SPI SPI4 +#define SX1278_IRQ_DIO0 EXTI6_IRQHandlerImpl +#define SX1278_IRQ_DIO1 EXTI4_IRQHandlerImpl +#define SX1278_IRQ_DIO3 EXTI11_IRQHandlerImpl + +#else +#error "Target not supported" +#endif + +namespace Arpist +{ + +#if defined _BOARD_STM32F429ZI_SKYWARD_GS_V2 +// pin mapping +using radio_cs = miosix::peripherals::ra01::pc13::cs; +using radio_dio0 = miosix::peripherals::ra01::pc13::dio0; +using radio_dio1 = miosix::peripherals::ra01::pc13::dio1; +using radio_dio3 = miosix::peripherals::ra01::pc13::dio3; +using radio_sck = miosix::interfaces::spi4::sck; +using radio_miso = miosix::interfaces::spi4::miso; +using radio_mosi = miosix::interfaces::spi4::mosi; +#endif + +using RadioMavDriver = + Boardcore::MavlinkDriver<Boardcore::SX1278Fsk::MTU, + Arpist::MAV_OUT_QUEUE_SIZE, + MAVLINK_MAX_DIALECT_PAYLOAD_SIZE>; + +// static volatile int dio0_cnt = 0; +// static volatile int dio1_cnt = 0; +// static volatile int dio3_cnt = 0; + +/** + * @brief Radio class + */ +class Radio : public Boardcore::Singleton<Radio>, public Boardcore::Transceiver +{ + friend class Boardcore::Singleton<Radio>; + +public: + void handleDioIRQ(); + + bool start(std::function<void(const mavlink_message_t&)> onReceive); + + bool sendMsg(const mavlink_message_t& msg); + +private: + ssize_t receive(uint8_t* pkt, size_t max_len) override; + + bool send(uint8_t* pkt, size_t len) override; + + bool started = false; + Boardcore::SPIBus sx1278_bus{SX1278_SPI}; + std::unique_ptr<Boardcore::SX1278Fsk> sx1278; + std::unique_ptr<RadioMavDriver> mav_driver; +}; + +} // namespace Arpist -- GitLab