Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions FprimeZephyrReference/Components/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Include project-wide components here

add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Drv/")
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/ComDelay/")
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/FatalHandler")
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/ImuManager/")
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/NullPrmDb/")
Expand Down
36 changes: 36 additions & 0 deletions FprimeZephyrReference/Components/ComDelay/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
####
# F Prime CMakeLists.txt:
#
# SOURCES: list of source files (to be compiled)
# AUTOCODER_INPUTS: list of files to be passed to the autocoders
# DEPENDS: list of libraries that this module depends on
#
# More information in the F´ CMake API documentation:
# https://fprime.jpl.nasa.gov/latest/docs/reference/api/cmake/API/
#
####

# Module names are derived from the path from the nearest project/library/framework
# root when not specifically overridden by the developer. i.e. The module defined by
# `Ref/SignalGen/CMakeLists.txt` will be named `Ref_SignalGen`.

register_fprime_library(
AUTOCODER_INPUTS
"${CMAKE_CURRENT_LIST_DIR}/ComDelay.fpp"
SOURCES
"${CMAKE_CURRENT_LIST_DIR}/ComDelay.cpp"
# DEPENDS
# MyPackage_MyOtherModule
)

### Unit Tests ###
# register_fprime_ut(
# AUTOCODER_INPUTS
# "${CMAKE_CURRENT_LIST_DIR}/ComDelay.fpp"
# SOURCES
# "${CMAKE_CURRENT_LIST_DIR}/test/ut/ComDelayTestMain.cpp"
# "${CMAKE_CURRENT_LIST_DIR}/test/ut/ComDelayTester.cpp"
# DEPENDS
# STest # For rules-based testing
# UT_AUTO_HELPERS
# )
71 changes: 71 additions & 0 deletions FprimeZephyrReference/Components/ComDelay/ComDelay.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// ======================================================================
// \title ComDelay.cpp
// \author starchmd
// \brief cpp file for ComDelay component implementation class
// ======================================================================

#include "FprimeZephyrReference/Components/ComDelay/ComDelay.hpp"
#include "FprimeZephyrReference/Components/ComDelay/FppConstantsAc.hpp"

namespace Components {

// ----------------------------------------------------------------------
// Component construction and destruction
// ----------------------------------------------------------------------

ComDelay ::ComDelay(const char* const compName)
: ComDelayComponentBase(compName), m_last_status_valid(false), m_last_status(Fw::Success::FAILURE) {}

ComDelay ::~ComDelay() {}

void ComDelay ::parameterUpdated(FwPrmIdType id) {
switch (id) {
case ComDelay::PARAMID_DIVIDER: {
Fw::ParamValid is_valid;
U8 new_divider = this->paramGet_DIVIDER(is_valid);
if ((is_valid != Fw::ParamValid::INVALID) && (is_valid != Fw::ParamValid::UNINIT)) {
this->log_ACTIVITY_HI_DividerSet(new_divider);
}
} break;
default:
FW_ASSERT(0);
break; // Fallthrough from assert (static analysis)
}
}

// ----------------------------------------------------------------------
// Handler implementations for typed input ports
// ----------------------------------------------------------------------

void ComDelay ::comStatusIn_handler(FwIndexType portNum, Fw::Success& condition) {
this->m_last_status = condition;
this->m_last_status_valid = true;
}

void ComDelay ::run_handler(FwIndexType portNum, U32 context) {
// On the cycle after the tick count is reset, attempt to output any current com status
if (this->m_tick_count == 0) {
bool expected = true;
// Receive the current "last status" validity flag and atomically exchange it with false. This effectively
// "consumes" a valid status. When valid, the last status is sent out.
bool valid = this->m_last_status_valid.compare_exchange_strong(expected, false);
if (valid) {
this->comStatusOut_out(0, this->m_last_status);
this->timeout_out(0, 0);
}
}

// Unless there is corruption, the parameter should always be valid via its default value; however, in the interest
// of failing-safe and continuing some sort of communication we default the current_divisor to the default value.
Fw::ParamValid is_valid;
U8 current_divisor = this->paramGet_DIVIDER(is_valid);

// Increment and module the tick count by the divisor
if ((is_valid == Fw::ParamValid::INVALID) || (is_valid == Fw::ParamValid::UNINIT)) {
current_divisor = Components::DEFAULT_DIVIDER;
}
// Count this new tick, resetting whenever the current count is at or higher than the current divider.
this->m_tick_count = (this->m_tick_count >= current_divisor) ? 0 : this->m_tick_count + 1;
}

} // namespace Components
51 changes: 51 additions & 0 deletions FprimeZephyrReference/Components/ComDelay/ComDelay.fpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
module Components {
constant DEFAULT_DIVIDER = 30
@ A component to delay com status until some further point
passive component ComDelay {
@ Rate schedule port used to trigger radio transmission
sync input port run: Svc.Sched

@ Rate schedule port used to trigger aggregation timeout
output port timeout: Svc.Sched

@ Input comStatus from radio component
sync input port comStatusIn: Fw.SuccessCondition

@ Output comStatus to be called on rate group
output port comStatusOut: Fw.SuccessCondition

@ Divider of the incoming rate tick
param DIVIDER: U8 default DEFAULT_DIVIDER # Start slow i.e. on a 1S tick, transmit every 30S

@ Divider set event
event DividerSet(divider: U8) severity activity high \
format "Set divider to: {}"

###############################################################################
# Standard AC Ports: Required for Channels, Events, Commands, and Parameters #
###############################################################################
@ Port for requesting the current time
time get port timeCaller

@ Port for sending command registrations
command reg port cmdRegOut

@ Port for receiving commands
command recv port cmdIn

@ Port for sending command responses
command resp port cmdResponseOut

@ Port for sending textual representation of events
text event port logTextOut

@ Port for sending events to downlink
event port logOut

@ Port to return the value of a parameter
param get port prmGetOut

@Port to set the value of a parameter
param set port prmSetOut
}
}
61 changes: 61 additions & 0 deletions FprimeZephyrReference/Components/ComDelay/ComDelay.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// ======================================================================
// \title ComDelay.hpp
// \author starchmd
// \brief hpp file for ComDelay component implementation class
// ======================================================================

#ifndef Components_ComDelay_HPP
#define Components_ComDelay_HPP

#include <atomic>
#include "FprimeZephyrReference/Components/ComDelay/ComDelayComponentAc.hpp"

namespace Components {

class ComDelay final : public ComDelayComponentBase {
public:
// ----------------------------------------------------------------------
// Component construction and destruction
// ----------------------------------------------------------------------

//! Construct ComDelay object
ComDelay(const char* const compName //!< The component name
);

//! Destroy ComDelay object
~ComDelay();

private:
void parameterUpdated(FwPrmIdType id //!< The parameter ID
) override;

// ----------------------------------------------------------------------
// Handler implementations for typed input ports
// ----------------------------------------------------------------------

//! Handler implementation for comStatusIn
//!
//! Input comStatus from radio component
void comStatusIn_handler(FwIndexType portNum, //!< The port number
Fw::Success& condition //!< Condition success/failure
) override;

//! Handler implementation for run
//!
//! Rate schedule port used to trigger radio transmission
void run_handler(FwIndexType portNum, //!< The port number
U32 context //!< The call order
) override;

private:
//! Count of incoming run ticks
U8 m_tick_count;
//! Stores if the last status is currently valid
std::atomic<bool> m_last_status_valid;
//! Stores the last status
Fw::Success m_last_status;
};

} // namespace Components

#endif
17 changes: 17 additions & 0 deletions FprimeZephyrReference/Components/ComDelay/docs/sdd.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Components::ComDelay

`Components::ComDelay` is a parameterized rate group schedule divider. On the initial run invocation and on each multiple of the divider thereafter any received com status is sent out. This effectively delays the com status until the next (divided) run call.

# 1 Requirements

| Requirement ID | Description | Validation |
|----------------|----------------------------------------------------------------------|------------|
| COM_DELAY_001 | The `Svc::ComDelay` component shall accept com status in. | Unit-Test |
| COM_DELAY_002 | The `Svc::ComDelay` component shall emit com status once for each DIVIDER number of rate group ticks. | Unit-Test |
| COM_DELAY_003 | The `Svc::ComDelay` component shall set the DIVIDER via a parameter. | Unit-Test |

# 2 Parameters

| Name | Description |
|---------|-----------------------------------------------------------|
| DIVIDER | Number of rate group ticks received before sending status |
2 changes: 2 additions & 0 deletions FprimeZephyrReference/ReferenceDeployment/Top/instances.fpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,6 @@ module ReferenceDeployment {
instance gpioBurnwire1: Zephyr.ZephyrGpioDriver base id 0x10023000

instance prmDb: Components.NullPrmDb base id 0x10024000

instance comDelay: Components.ComDelay base id 0x10025000
}
4 changes: 3 additions & 1 deletion FprimeZephyrReference/ReferenceDeployment/Top/topology.fpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ module ReferenceDeployment {
instance lis2mdlManager
instance lsm6dsoManager
instance bootloaderTrigger
instance comDelay
instance burnwire

# ----------------------------------------------------------------------
Expand Down Expand Up @@ -100,7 +101,8 @@ module ReferenceDeployment {
rateGroup1Hz.RateGroupMemberOut[3] -> CdhCore.tlmSend.Run
rateGroup1Hz.RateGroupMemberOut[4] -> watchdog.run
rateGroup1Hz.RateGroupMemberOut[5] -> imuManager.run
rateGroup1Hz.RateGroupMemberOut[6] -> burnwire.schedIn
rateGroup1Hz.RateGroupMemberOut[6] -> comDelay.run
rateGroup1Hz.RateGroupMemberOut[7] -> burnwire.schedIn

}

Expand Down
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ fprime-venv: ## Create a virtual environment
@$(MAKE) uv
@echo "Creating virtual environment..."
@$(UV) venv fprime-venv
@$(UV) pip install --requirement requirements.txt
@$(UV) pip install --prerelease=allow --requirement requirements.txt

patch-gps-package:
cp custom_space_data_link.py fprime-venv/lib/python3.13/site-packages/fprime_gds/common/communication/ccsds/space_data_link.py

.PHONY: zephyr-setup
zephyr-setup: fprime-venv ## Set up Zephyr environment
Expand Down
3 changes: 3 additions & 0 deletions circuit-python-lora-passthrough/boot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import usb_cdc

usb_cdc.enable(console=True, data=True)
41 changes: 41 additions & 0 deletions circuit-python-lora-passthrough/code.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"""
CircuitPython Feather RP2350 LoRa Radio forwarder

This code will forward any received LoRa packets to the serial console (sys.stdout). It cycles through neo pixel colors
to indicate packet reception.
"""

import time

import adafruit_rfm9x
import board
import digitalio
import usb_cdc

# Radio constants
RADIO_FREQ_MHZ = 437.4
CS = digitalio.DigitalInOut(board.SPI0_CS0)
RESET = digitalio.DigitalInOut(board.RF1_RST)

rfm95 = adafruit_rfm9x.RFM9x(board.SPI(), CS, RESET, RADIO_FREQ_MHZ)
rfm95.spreading_factor = 8
rfm95.signal_bandwidth = 125000
rfm95.coding_rate = 5
rfm95.preamble_length = 8
time_start = time.time()
packet_count = 0
print("[INFO] LoRa Receiver receiving packets")
while True:
# Look for a new packet - wait up to 2 seconds:
packet = rfm95.receive(timeout=2.0)
# If no packet was received during the timeout then None is returned.
if packet is not None:
usb_cdc.data.write(packet)
packet_count += 1
time_delta = time.time() - time_start
if time_delta > 10:
print(f"[INFO] Packets received: {packet_count}")
time_start = time.time()
data = usb_cdc.data.read(usb_cdc.data.in_waiting)
if len(data) > 0:
rfm95.send(data)
Loading