Forj Link is a complete overlanding convoy communication system consisting of two main components:
- Mobile App (
mobile/) - React Native application for iOS/Android - ESP32 Firmware (
link/) - Bluetooth radio dongle firmware (this project)
The ESP32 firmware acts as a bridge between the mobile application and GMRS radio hardware, enabling convoy communication in off-grid environments. This document provides comprehensive guidance for developing the ESP32 firmware based on the mobile app architecture.
- ESP32-WROOM-32 development board (prototyping)
- GMRS Radio Interface (RJ45 breakout board for direct radio connection)
- Midland MXT275/MXT575 or compatible GMRS radios
- GPS Module (I2C interface)
- Real-time Clock (I2C interface)
- Status LEDs (convoy, emergency, transmission)
- Push Button (emergency activation)
- External Flash (4MB+ for data storage)
- Power Conditioning (LDO/Buck converter for radio power vampiring)
- Bluetooth Low Energy - Mobile app communication
- RJ45 Interface - Direct GMRS radio connection (audio, PTT, power, control)
- ESP32 ADC/DAC - Audio signal processing and sub-audible data transmission
- I2C - GPS and sensor communication
- GPIO - Status indicators and emergency button
The ESP32 connects directly to GMRS radios (Midland MXT275/MXT575) via RJ45 interface using a breakout board for signal access and monitoring.
// RJ45 breakout board connections
#define RJ45_PIN_1 GPIO_NUM_32 // ADC1_CH4 - Power/Ground
#define RJ45_PIN_2 GPIO_NUM_33 // ADC1_CH5 - Audio Input (Microphone)
#define RJ45_PIN_3 GPIO_NUM_34 // ADC1_CH6 - Audio Output (Speaker)
#define RJ45_PIN_4 GPIO_NUM_35 // ADC1_CH7 - PTT (Push-to-Talk)
#define RJ45_PIN_5 GPIO_NUM_36 // ADC1_CH0 - Channel Control
#define RJ45_PIN_6 GPIO_NUM_39 // ADC1_CH3 - Volume Control
#define RJ45_PIN_7 GPIO_NUM_25 // DAC1 - Data Transmission
#define RJ45_PIN_8 GPIO_NUM_26 // DAC2 - Control SignalsThe system can be powered directly from the radio's RJ45 interface:
- Voltage Range: 5V or 12V (auto-detected)
- Current Capacity: 200-500mA (sufficient for ESP32 + peripherals)
- Power Conditioning: LDO regulator (5V→3.3V) or buck converter (12V→3.3V)
- Current Limiting: Fuse protection and soft-start circuitry
Digital packets are transmitted using frequencies inaudible to users:
#define FORJ_DATA_TONE_LOW_HZ 67 // Sub-audible low tone (like CTCSS)
#define FORJ_DATA_TONE_HIGH_HZ 203 // Sub-audible high tone
#define FORJ_DATA_CARRIER_HZ 4500 // Ultrasonic carrier (above voice)
#define FORJ_VOICE_THRESHOLD_HZ 300 // Voice activity cutoff- Sub-Audible Mode: Use tones below 300Hz (filtered out by radio speakers)
- Ultrasonic Mode: Use frequencies above 3kHz (above voice bandwidth)
- Burst Mode: Inject brief data packets (10-50ms) during voice silence
- Mixed Mode: Low-level continuous data mixed with voice audio
- ADC: 12-bit resolution, 0-3.3V range, 100kHz sampling (sufficient for voice audio)
- DAC: 8-bit resolution, 0-3.3V output (adequate for tone generation)
- Processing: Real-time audio analysis, voice activity detection, tone generation
- Quality: Suitable for GMRS radio audio quality (300Hz-3kHz bandwidth)
The firmware includes comprehensive monitoring utilities:
- 8-Channel Monitoring: Real-time voltage monitoring on all RJ45 pins
- Signal Classification: Automatic detection of power, audio, and digital signals
- Change Detection: Logs only when pin states change
- Audio Analysis: Detailed sampling and frequency analysis
- Power Analysis: Voltage and current measurement for power vampiring
=== RJ45 Pin Readings ===
*RJ45_PIN_1: 5000mV (raw:4095) [HIGH] <- Power pin detected
RJ45_PIN_2: 0mV (raw:0) [LOW] <- Ground
*RJ45_PIN_3: 1650mV (raw:2048) [AUDIO] <- Audio signal varying
RJ45_PIN_4: 0mV (raw:0) [LOW] <- PTT inactive
RJ45_PIN_5: 3300mV (raw:4095) [HIGH] <- Channel control
#define FORJ_MAGIC_BYTES {0x46, 0x4F, 0x52, 0x4A} // "FORJ"
#define FORJ_PROTOCOL_VERSION 1
#define FORJ_MAX_PACKET_SIZE 1024
#define FORJ_MAX_PAYLOAD_SIZE 950
#define FORJ_HEADER_SIZE 24
#define FORJ_GMRS_CHANNELS 22
#define FORJ_DEFAULT_CHANNEL 15typedef struct __attribute__((packed)) {
uint8_t magic[4]; // "FORJ" magic bytes
uint8_t version; // Protocol version (1)
uint8_t type; // Packet type (0-9)
uint8_t priority; // Priority level (0-3)
uint8_t flags; // Protocol flags
uint8_t sender_id[4]; // Sender UUID hash
uint8_t convoy_id[4]; // Convoy UUID hash
uint16_t sequence_number; // Sequence number (big-endian)
uint8_t total_packets; // Total packets in message
uint8_t packet_index; // Current packet index
uint16_t payload_length; // Payload length (big-endian)
uint16_t checksum; // CRC16 checksum (big-endian)
} forj_packet_header_t;typedef enum {
FORJ_PACKET_HEARTBEAT = 0, // Regular status/location updates
FORJ_PACKET_MESSAGE = 1, // Text messages
FORJ_PACKET_EMERGENCY = 2, // Emergency alerts
FORJ_PACKET_LOCATION = 3, // Location updates
FORJ_PACKET_STATUS = 4, // Member status changes
FORJ_PACKET_CONVOY_INFO = 5, // Convoy metadata
FORJ_PACKET_RELAY = 6, // Store-and-forward relay
FORJ_PACKET_ACK = 7, // Acknowledgment packets
FORJ_PACKET_DISCOVERY = 8, // Network discovery
FORJ_PACKET_SYSTEM = 9 // System control messages
} forj_packet_type_t;typedef enum {
FORJ_PRIORITY_LOW = 0,
FORJ_PRIORITY_NORMAL = 1,
FORJ_PRIORITY_HIGH = 2,
FORJ_PRIORITY_EMERGENCY = 3
} forj_priority_t;#define FORJ_FLAG_ENCRYPTED 0x01 // Payload is encrypted
#define FORJ_FLAG_COMPRESSED 0x02 // Payload is compressed
#define FORJ_FLAG_FRAGMENTED 0x04 // Multi-packet message
#define FORJ_FLAG_RELAY_ALLOWED 0x08 // Can be relayed
#define FORJ_FLAG_ACK_REQUESTED 0x10 // Acknowledgment requested
#define FORJ_FLAG_PRIORITY_HIGH 0x20 // High priority transmission
#define FORJ_FLAG_BROADCAST 0x40 // Broadcast to all members
#define FORJ_FLAG_EXPERIMENTAL 0x80 // Experimental/testingtypedef struct __attribute__((packed)) {
int32_t lat; // Latitude * 1e7 (1.1m precision)
int32_t lon; // Longitude * 1e7
int16_t alt; // Altitude in meters
uint8_t speed; // Speed in km/h (0-255)
uint8_t heading; // Heading compressed (0-255 = 0-359°)
uint8_t accuracy_hdop; // Accuracy (4 bits) + HDOP (4 bits)
uint16_t timestamp; // Timestamp offset (seconds)
uint8_t reserved; // Reserved for future use
} forj_compressed_location_t;typedef struct __attribute__((packed)) {
forj_compressed_location_t location; // 16 bytes
uint8_t battery_level; // Battery level (0-100%)
uint8_t signal_strength; // Signal strength (0-100%)
uint8_t status; // Status flags
uint8_t radio_channel; // Current GMRS channel
uint8_t member_count; // Visible convoy members
uint8_t capabilities; // Capability flags
uint8_t reserved[6]; // Reserved for expansion
} forj_heartbeat_payload_t;typedef struct __attribute__((packed)) {
uint8_t emergency_type; // Emergency type (0-5)
uint8_t severity; // Severity level (0-3)
forj_compressed_location_t location; // 16 bytes
char description[]; // UTF-8 description
} forj_emergency_payload_t;
// Emergency types
#define FORJ_EMERGENCY_SOS 0
#define FORJ_EMERGENCY_MEDICAL 1
#define FORJ_EMERGENCY_MECHANICAL 2
#define FORJ_EMERGENCY_WEATHER 3
#define FORJ_EMERGENCY_ACCIDENT 4
#define FORJ_EMERGENCY_LOST 5typedef struct {
uint8_t channel;
float frequency;
bool simplex;
char* name;
} gmrs_channel_t;
static const gmrs_channel_t gmrs_channels[] = {
{1, 462.5625, true, "GMRS 1"},
{2, 462.5875, true, "GMRS 2"},
{3, 462.6125, true, "GMRS 3"},
{4, 462.6375, true, "GMRS 4"},
{5, 462.6625, true, "GMRS 5"},
{6, 462.6875, true, "GMRS 6"},
{7, 462.7125, true, "GMRS 7"},
// Channels 8-14 are repeater inputs (excluded)
{15, 462.5500, true, "GMRS 15"},
{16, 462.5750, true, "GMRS 16"},
{17, 462.6000, true, "GMRS 17"},
{18, 462.6250, true, "GMRS 18"},
{19, 462.6500, true, "GMRS 19"},
{20, 462.6750, true, "GMRS 20"},
{21, 462.7000, true, "GMRS 21"},
{22, 462.7250, true, "GMRS 22"}
};typedef struct {
uint8_t channel;
float frequency;
uint8_t power_level; // 1-5 watts
uint8_t squelch_level; // 0-9
uint16_t ctcss_code; // CTCSS tone (0 = off)
uint8_t dcs_code; // DCS code (0 = off)
bool encryption_enabled;
} radio_config_t;// Service and characteristic UUIDs (replace with actual values)
#define FORJ_SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"
#define FORJ_CONFIG_CHAR_UUID "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define FORJ_STATUS_CHAR_UUID "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
#define FORJ_MESSAGE_CHAR_UUID "6E400004-B5A3-F393-E0A9-E50E24DCCA9E"
#define FORJ_LOCATION_CHAR_UUID "6E400005-B5A3-F393-E0A9-E50E24DCCA9E"
#define FORJ_EMERGENCY_CHAR_UUID "6E400006-B5A3-F393-E0A9-E50E24DCCA9E"- Configuration (Write): Radio settings, convoy configuration
- Status (Read/Notify): Radio status, statistics, health
- Message (Write/Notify): Send/receive message packets
- Location (Read/Notify): Location updates and tracking
- Emergency (Write/Notify): Emergency alerts and SOS
typedef struct {
char device_name[32]; // "Forj-Link-XXXX"
uint8_t battery_level; // 0-100%
uint8_t signal_strength; // 0-100%
uint8_t radio_status; // Radio status flags
uint8_t convoy_members; // Number of visible members
} ble_advertisement_t;// Core system initialization
void forj_system_init(void);
void forj_radio_init(void);
void forj_ble_init(void);
void forj_gps_init(void);
void forj_storage_init(void);
// Main application loop
void forj_main_loop(void);typedef struct {
forj_packet_header_t header;
uint8_t payload[FORJ_MAX_PAYLOAD_SIZE];
uint32_t timestamp;
uint8_t retry_count;
uint8_t max_retries;
} forj_message_t;
// Message queue operations
bool forj_queue_push(forj_message_t* msg, forj_priority_t priority);
bool forj_queue_pop(forj_message_t* msg);
size_t forj_queue_size(forj_priority_t priority);
void forj_queue_clear(void);// Packet encoding/decoding
size_t forj_encode_packet(const forj_packet_header_t* header,
const uint8_t* payload, uint8_t* buffer);
bool forj_decode_packet(const uint8_t* buffer, size_t length,
forj_packet_header_t* header, uint8_t* payload);
bool forj_validate_packet(const forj_packet_header_t* header,
const uint8_t* payload);
uint16_t forj_calculate_crc16(const uint8_t* data, size_t length);// Radio control functions
bool forj_radio_set_channel(uint8_t channel);
bool forj_radio_set_power(uint8_t power_level);
bool forj_radio_set_squelch(uint8_t squelch_level);
bool forj_radio_transmit(const uint8_t* data, size_t length);
bool forj_radio_receive(uint8_t* data, size_t* length);
bool forj_radio_carrier_detect(void);// GPS data structure
typedef struct {
double latitude;
double longitude;
float altitude;
float speed;
float heading;
float accuracy;
uint32_t timestamp;
bool valid;
} forj_gps_data_t;
// GPS functions
bool forj_gps_read(forj_gps_data_t* gps_data);
forj_compressed_location_t forj_compress_location(const forj_gps_data_t* gps);
forj_gps_data_t forj_decompress_location(const forj_compressed_location_t* compressed);// Configuration storage
bool forj_storage_save_config(const radio_config_t* config);
bool forj_storage_load_config(radio_config_t* config);
bool forj_storage_save_convoy(const char* convoy_id, const char* convoy_name);
bool forj_storage_load_convoy(char* convoy_id, char* convoy_name);
// Message caching for offline support
bool forj_storage_cache_message(const forj_message_t* msg);
bool forj_storage_retrieve_cached_messages(forj_message_t* msgs, size_t max_count);- esp32 (ESP32 hardware abstraction)
- driver (GPIO, UART, SPI, I2C)
- nvs_flash (non-volatile storage)
- bt (Bluetooth Low Energy)
- freertos (real-time OS)
- lwip (TCP/IP stack)
- mbedtls (cryptography)
- json (JSON parsing)
- esp_timer (high-resolution timers)
- esp_log (logging system)
- TinyGPS++ - GPS NMEA parsing
- ArduinoJson - JSON configuration parsing
- CRC16 - Checksum calculation
- Base64 - BLE data encoding
- AES - Encryption/decryption
# Install ESP-IDF
mkdir -p ~/esp
cd ~/esp
git clone --recursive https://github.com/espressif/esp-idf.git
cd esp-idf
./install.sh esp32
. ./export.sh
# Create project
mkdir forj-link
cd forj-link
idf.py create-project link
cd linklink/
├── main/
│ ├── main.c # Main application entry
│ ├── forj_protocol.c # Radio protocol implementation
│ ├── forj_radio.c # Radio hardware interface
│ ├── forj_ble.c # Bluetooth Low Energy
│ ├── forj_gps.c # GPS location services
│ ├── forj_storage.c # Data storage and persistence
│ ├── forj_crypto.c # Cryptography and security
│ ├── forj_queue.c # Message queue system
│ └── forj_config.h # Configuration constants
├── components/
│ ├── radio_driver/ # Radio module driver
│ ├── gps_driver/ # GPS module driver
│ └── crypto_utils/ # Cryptography utilities
├── test/
│ ├── test_protocol.c # Protocol unit tests
│ ├── test_radio.c # Radio interface tests
│ └── test_integration.c # Integration tests
├── docs/
│ ├── hardware_design.md # Hardware specifications
│ ├── protocol_spec.md # Protocol documentation
│ └── api_reference.md # API documentation
├── CMakeLists.txt # Build configuration
├── sdkconfig # ESP-IDF configuration
└── README.md # Project documentation
{
"radio": {
"channel": 15,
"frequency": 462.575,
"power_level": 5,
"squelch_level": 5,
"ctcss_code": 0,
"dcs_code": 0,
"encryption": true
},
"convoy": {
"id": "convoy-uuid-here",
"name": "Moab Adventure",
"member_id": "member-uuid-here",
"member_name": "Trail Rider 1"
},
"location": {
"update_interval": 30,
"accuracy_threshold": 10,
"enable_breadcrumbs": true
},
"emergency": {
"auto_broadcast": true,
"broadcast_interval": 30,
"emergency_channel": 1
}
}{
"type": "RADIO_CONFIG",
"channel": 15,
"frequency": 462.575,
"power_level": 5,
"squelch_level": 5,
"ctcss_code": null,
"encryption": true
}// Emergency button interrupt handler
void IRAM_ATTR emergency_button_isr(void* arg);
// Emergency system functions
void forj_emergency_activate(uint8_t emergency_type, const char* description);
void forj_emergency_cancel(void);
bool forj_emergency_is_active(void);
void forj_emergency_broadcast_loop(void);- Immediate transmission on current channel
- Automatic retransmission every 30 seconds
- Highest priority in transmission queue
- Multi-channel emergency broadcast
- GPS location included in all emergency packets
typedef struct {
uint8_t channel;
uint8_t activity_level; // 0-100%
int8_t signal_strength; // -120 to 0 dBm
uint8_t air_time_utilization; // 0-100%
uint8_t interference_level; // 0-100%
uint8_t conversation_count; // Number of active conversations
uint8_t quality_score; // 0-100%
} channel_health_t;// Congestion avoidance functions
uint32_t forj_calculate_backoff_delay(uint8_t retry_count);
bool forj_channel_is_clear(void);
void forj_update_channel_health(channel_health_t* health);
uint8_t forj_recommend_channel(void);// Encryption functions
bool forj_encrypt_payload(const uint8_t* plaintext, size_t length,
uint8_t* ciphertext, const uint8_t* key);
bool forj_decrypt_payload(const uint8_t* ciphertext, size_t length,
uint8_t* plaintext, const uint8_t* key);
void forj_generate_convoy_key(const char* convoy_id, uint8_t* key);// HMAC message authentication
bool forj_sign_message(const uint8_t* message, size_t length,
uint8_t* signature, const uint8_t* key);
bool forj_verify_signature(const uint8_t* message, size_t length,
const uint8_t* signature, const uint8_t* key);// Test framework
#define FORJ_TEST_ASSERT(condition) \
if (!(condition)) { \
printf("FAIL: %s:%d - %s\n", __FILE__, __LINE__, #condition); \
return false; \
}
// Test functions
bool test_packet_encoding(void);
bool test_location_compression(void);
bool test_radio_interface(void);
bool test_congestion_management(void);
bool test_emergency_system(void);- Mobile App Integration: Test BLE communication with actual mobile app
- Radio Hardware: Test with actual GMRS radios
- Multi-Device: Test convoy scenarios with multiple devices
- Range Testing: Test communication range and reliability
- Emergency Scenarios: Test emergency activation and broadcasting
- Single Device: GPS, radio transmission, BLE connectivity
- Two Device: Point-to-point communication, message relay
- Multi-Device: Convoy simulation with 3+ devices
- Emergency: Emergency activation and multi-device response
- Range Test: Communication range in various terrain
- Endurance: Long-term operation and battery life
- Core Protocol Implementation: Packet encoding/decoding, CRC validation, all packet types
- Radio Interface Monitoring: 8-channel ADC monitoring, signal classification, change detection
- Audio Analysis: Voice activity detection, frequency analysis, power measurement
- System Architecture: FreeRTOS task management, logging, configuration structures
- Development Environment: ESP-IDF build system, flashing, monitoring
- RJ45 Pinout Discovery: Using monitoring utility to map Midland MXT275/MXT575 pinouts
- Power Vampiring: Measuring available power from radio interface
- Sub-Audible Data Transmission: Tone generation and detection implementation
- GPS Integration: I2C location services and compressed location format
- BLE Interface: Mobile app communication and command processing
- Message Queue System: Priority-based packet handling and transmission
- Emergency System: Button activation and automatic emergency broadcasting
- Persistent Storage: Configuration and message caching in flash memory
# Set up ESP-IDF environment
source ~/esp/esp-idf/export.sh
# Configure project (first time only)
idf.py menuconfig
# Build firmware
idf.py build
# Flash to device
idf.py flash -p /dev/cu.usbserial-1430
# Monitor serial output and radio interface
idf.py monitor -p /dev/cu.usbserial-1430Using a Generic RJ45 Breakout Board (B0D3J6PB4S or similar):
- Two female RJ45 ports for pass-through connection
- 16 middle pins for signal access (8 pairs mirrored from each port)
- 8 pins near each port for direct pin access
- Pass-through Mode: Connect middle pins together for normal radio operation
- Monitoring Mode: Connect ESP32 to middle pins for signal monitoring
- Man-in-the-Middle: ESP32 can monitor and inject signals simultaneously
ESP32 GPIO32 -> RJ45 Breakout Middle Pin 1 (Power detection)
ESP32 GPIO33 -> RJ45 Breakout Middle Pin 2 (Audio input monitoring)
ESP32 GPIO34 -> RJ45 Breakout Middle Pin 3 (Audio output monitoring)
ESP32 GPIO35 -> RJ45 Breakout Middle Pin 4 (PTT monitoring)
ESP32 GPIO36 -> RJ45 Breakout Middle Pin 5 (Control signal monitoring)
ESP32 GPIO39 -> RJ45 Breakout Middle Pin 6 (Volume/additional control)
ESP32 GPIO25 -> RJ45 Breakout Middle Pin 7 (Data injection - DAC1)
ESP32 GPIO26 -> RJ45 Breakout Middle Pin 8 (Control injection - DAC2)
ESP32 GND -> Common ground
- Protocol Testing: Heartbeat and emergency packet creation, encoding/decoding validation
- Radio Monitoring: Real-time voltage monitoring on all RJ45 pins
- Audio Analysis: Frequency analysis and signal classification
- Power Analysis: Voltage/current measurement for power vampiring feasibility
- Pinout Discovery: Using monitoring utility to identify Midland MXT275/MXT575 pin functions
// Over-the-air update support
bool forj_ota_check_update(void);
bool forj_ota_download_update(const char* url);
bool forj_ota_apply_update(void);
void forj_ota_rollback(void);- Static allocation for packet buffers
- Ring buffers for message queues
- Efficient data structures for convoy member tracking
- Flash storage for configuration and message caching
// Power management functions
void forj_enter_sleep_mode(uint32_t sleep_duration_ms);
void forj_wake_from_sleep(void);
void forj_adjust_tx_power(int8_t rssi);
void forj_optimize_gps_power(void);- Adaptive transmission timing based on channel conditions
- Message aggregation to reduce air time
- Efficient routing for multi-hop communication
- Congestion detection and avoidance
// Debug levels
#define FORJ_LOG_ERROR 0
#define FORJ_LOG_WARN 1
#define FORJ_LOG_INFO 2
#define FORJ_LOG_DEBUG 3
#define FORJ_LOG_VERBOSE 4
// Logging macros
#define FORJ_LOGE(tag, format, ...) ESP_LOGE(tag, format, ##__VA_ARGS__)
#define FORJ_LOGW(tag, format, ...) ESP_LOGW(tag, format, ##__VA_ARGS__)
#define FORJ_LOGI(tag, format, ...) ESP_LOGI(tag, format, ##__VA_ARGS__)
#define FORJ_LOGD(tag, format, ...) ESP_LOGD(tag, format, ##__VA_ARGS__)
#define FORJ_LOGV(tag, format, ...) ESP_LOGV(tag, format, ##__VA_ARGS__)- BLE Connection Issues: Check service UUIDs and characteristic properties
- Radio Transmission Failures: Verify UART configuration and radio module
- GPS Accuracy Problems: Check antenna placement and satellite visibility
- Power Management: Monitor current consumption and sleep modes
- Memory Leaks: Use static allocation and proper cleanup
- Mesh Networking: Multi-hop message relay
- Voice Integration: Voice message transmission
- Weather Integration: Weather data sharing
- Advanced Encryption: Perfect forward secrecy
- Machine Learning: Predictive congestion management
- LoRa Integration: Long-range communication
- Satellite Connectivity: Emergency satellite backup
- Advanced GPS: RTK GPS for centimeter accuracy
- Environmental Sensors: Temperature, humidity, pressure
- Install ESP-IDF framework
- Set up toolchain and build system
- Configure VS Code or preferred IDE
- Install required libraries and components
- Obtain ESP32-WROOM-32 development board
- Connect GMRS radio module (UART/SPI)
- Connect GPS module (I2C)
- Add status LEDs and emergency button
- Set up power management circuit
- Implement basic packet encoding/decoding
- Create BLE service for mobile app communication
- Implement GPS location reading
- Add radio transmission and reception
- Create message queue system
- Unit tests for protocol functions
- Integration tests with mobile app
- Hardware-in-the-loop testing
- Field testing with multiple devices
- Emergency scenario testing
- Optimize for power consumption
- Implement security features
- Add OTA update capability
- Create manufacturing test suite
- Document installation and usage
This comprehensive guide provides everything needed to develop the Forj Link ESP32 firmware that seamlessly integrates with the existing mobile application architecture. The firmware will enable reliable convoy communication in off-grid environments while maintaining compatibility with the established protocol and data structures.