FANET (Flying Ad-hoc Network) is a lightweight, embedded networking well tested library designed for aerial vehicles and ground stations. It provides a robust protocol for communication between flying objects and ground stations.
This library is a c++ implementation header only no malloc version designed to handle the full FANET protocol for embedded systems.
The protocol was taking from https://github.com/3s1d/fanet-stm32 and a library was created without the radio integration, this makes it easer to pull this into your codebase.
R. van Twisk [email protected]
To run the tests you can use ./build.sh However, since this is a header only library you can just include them in your project (use PlatformIO!)
#include "fanet/fanet.hpp"
// Create a connector implementation
class MyConnector : public FANET::Connector {
private:
FANET::Protocol protocol;
Radio &myRadio; // Some form of implementation of your radio
/**
* @brief return a number of ms. Does not matter if it's from epoch, as long as it's monotonic.
*/
uint32_t fanet_getTick() const override
{
return millis();
}
/**
* @brief send a frame to the network
* @param codingRate the coding rate to use
* @param data the data to send
* @return true if the frame was sent successfully
*/
bool fanet_sendFrame(uint8_t codingRate, etl::span<const uint8_t> data) override
{
(void)data;
auto sendOk = myRadio.sendData(codingRate, data)
return sendOk;
}
/**
* @brief called when an ack is received of any frames you send directory to an destination
* excluding tracking packets like Ground and Tracking. They are handled special.
* @param id the id of the ack
*/
void fanet_ackReceived(uint16_t id) override
{
printf("fanet_ackReceived %d\n", id);
}
public:
MyConnector(Radio myRadio_) : protocol(this), myRadio(myRadio)
{
protocol.ownAddress(FANET::Address(0x01, 0x1234));
}
};
// Initialize the protocol
// aRadio is some form of implementation of a radio system.
MyConnector connector(aRadio);
## Core Components
### Protocol (`protocol.hpp`)
The main protocol handler that manages packet transmission and reception. It handles:
- Packet forwarding
- Acknowledgments
- Neighbor discovery
- Transmission scheduling
```cpp
// Example: Sending a tracking packet
FANET::TrackingPayload payload;
payload.latitude(ownshipPosition.lat)
.longitude(ownshipPosition.lon)
.altitude(ownshipPosition.heightEgm96)
.speed(ownshipPosition.groundSpeed * MS_TO_KPH)
.groundTrack(ownshipPosition.course)
.climbRate(ownshipPosition.verticalSpeed)
.tracking(true)
.turnRate(ownshipPosition.hTurnRate)
.aircraftType(mapAircraftCategory(openAceConfiguration.category));
auto packet = FANET::Packet<1>() // Package size set to 1, not repoevant for TrackingPayload (this is on my TODO to improve)
.payload(payload)
.forward(true);
protocol.sendPacket(packet, 0);
FANET::NamePayload<20> namePayload;
namePayload.name("OpenAce");
auto packet = FANET::Packet<20>() // 20 bytes is fine to store OpenAce.
.payload(namePayload)
.destination(FANET::Address{0x08158C})
.singleHop()
.forward(true);
protocol.sendPacket(packet, 12); // When received by 0x08158C and ack is send back, fanet_ackReceived will be called with the id of 12
[!NOTE] You are responsible for the timings of when to send packages. The connector will handle the scheduling and will keep track of airtime, eg if you are allowed to send the package.
Represents a FANET device address consisting of:
- Manufacturer ID (8 bits)
- Unique Device ID (16 bits)
// Example
auto address = FANET::Address addr(0x01, 0x1234); // Mfg: 0x01, Device: 0x1234Used for real-time position reporting of aircraft:
- Position (lat/lon)
- Altitude
- Speed
- Aircraft type
- Climb rate
- Ground track
- Turn rate
Note
altitude is in meters EGM96, check your GPS what it's sending you!
// Example
FANET::TrackingPayload tracking;
tracking.latitude(47.123)
.longitude(8.456)
.altitude(1000)
.speed(30.5)
.aircraftType(FANET::TrackingPayload::AircraftType::PARAGLIDER);Used for ground-based objects:
- Position
- Type (walking, vehicle, bike, etc.)
- Support status (need help, technical support, etc.)
// Example
FANET::GroundTrackingPayload ground;
ground.latitude(47.123)
.longitude(8.456)
.groundType(FANET::GroundTrackingPayload::TrackingType::WALKING);General-purpose message transmission:
- Text messages
- Custom data payloads
- Configurable size
FANET::MessagePayload<100> msg; // 100-byte message capacity
etl::vector<uint8_t, 100> message;
// Fill message
msg.message(message);Device identification payload:
- Device name/identifier
- Configurable size
FANET::NamePayload<20> name; // 20-char name capacity
name.name("OpenACE");Maintains a list of nearby FANET devices:
- Address tracking
- Last seen timestamps
- Automatic cleanup
Manages regional settings:
- Frequency bands
- Power limits
- Geographic boundaries
FANET::Zone zone;
auto region = zone.findZone(47.123, 8.456); // Get region settings for coordinatesMemory management for packet transmission:
- Fixed-size memory pool
- Efficient allocation/deallocation
- Prevents fragmentation
Used internally
FANET supports multi-hop packet forwarding:
auto packet = FANET::Packet<1>()
.source(myAddress)
.destination(targetAddress)
.payload(payload)
.forward(true) // Enable forwarding
.twoHop(); // Request 2-hop acknowledgmentThree acknowledgment modes:
- None: No acknowledgment
- Single-hop: Direct acknowledgment
- Two-hop: Forwarded acknowledgment
[!NOTE] Acknowledgments only happen for messages that are not tracking
To use FANET, implement the Connector interface:
class MyConnector : public FANET::Connector {
public:
uint32_t fanet_getTick() const override {
return /* your timestamp implementation */;
}
bool fanet_sendFrame(uint8_t codingRate, etl::span<const uint8_t> data) override {
return /* your radio transmission implementation */;
}
void fanet_ackReceived(uint16_t id) override {
/* handle received acknowledgments */
}
};- ETL (Embedded Template Library)
- C++17 or later
- All memory allocations are static, no malloc
- Designed for embedded systems
- Uses template metaprogramming for compile-time optimizations
- Supports various payload sizes through templates
- Always check regional compliance using the Zone system
- Implement proper error handling in your Connector
- Monitor neighbor table size in dense networks
- Use appropriate acknowledgment modes based on reliability needs
- Consider airtime restrictions when sending frequent updates