Files
pyxis/lib/sx1262_interface/SX1262Interface.h
torlando-tech d03f0b308f Add shared SPI bus mutex for SD card, display, and LoRa coexistence
The T-Deck Plus shares HSPI across the display (CS=12), LoRa (CS=9),
and SD card (CS=39). Previously SD logging was disabled because
SD.begin() reconfigured the SPI bus and blanked the display.

This introduces a FreeRTOS mutex created in main.cpp and injected into
Display, SX1262Interface, and a new SDAccess class so all three
peripherals serialize their SPI transactions safely.

- Add SDAccess class wrapping SD.begin() and file ops with mutex
- Add set_spi_mutex() to Display and SX1262Interface
- Wrap Display flush, fill, draw, and power ops in mutex
- Refactor SDLogger to use SDAccess mutex instead of owning SD.begin()
- Wire up mutex creation and injection order in setup()

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 00:19:10 -05:00

113 lines
3.2 KiB
C++

// Copyright (c) 2024 microReticulum contributors
// SPDX-License-Identifier: MIT
#pragma once
#include "Interface.h"
#include "Bytes.h"
#include "Type.h"
#include "Cryptography/Random.h"
#ifdef ARDUINO
#include <RadioLib.h>
#include <freertos/FreeRTOS.h>
#include <freertos/semphr.h>
#endif
/**
* SX1262 LoRa Interface for T-Deck Plus
*
* Air-compatible with RNode devices using same modulation and packet framing.
* Uses RadioLib for SX1262 support with DIO1+BUSY pin model.
*/
// T-Deck Plus SX1262 pins (from Hardware::TDeck::Radio)
namespace SX1262Pins {
constexpr uint8_t CS = 9;
constexpr uint8_t BUSY = 13;
constexpr uint8_t RST = 17;
constexpr uint8_t DIO1 = 45;
constexpr uint8_t SPI_MISO = 38;
// Shared with display: MOSI=41, SCK=40
}
/**
* LoRa configuration parameters.
* Defaults match RNode for interoperability.
*/
struct SX1262Config {
float frequency = 927.25f; // MHz
float bandwidth = 62.5f; // kHz (valid: 7.8, 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250, 500)
uint8_t spreading_factor = 7; // SF7-SF12
uint8_t coding_rate = 5; // 5=4/5, 6=4/6, 7=4/7, 8=4/8
int8_t tx_power = 17; // dBm (2-22)
uint8_t sync_word = 0x12; // Standard LoRa sync word
uint16_t preamble_length = 20; // symbols
};
class SX1262Interface : public RNS::InterfaceImpl {
public:
SX1262Interface(const char* name = "LoRa");
virtual ~SX1262Interface();
/**
* Set the shared SPI bus mutex. Call before start().
* If set, the interface uses this mutex instead of creating its own.
*/
static void set_spi_mutex(SemaphoreHandle_t mutex);
/**
* Set configuration before calling start().
* Changes take effect on next start().
*/
void set_config(const SX1262Config& config);
const SX1262Config& get_config() const { return _config; }
// InterfaceImpl interface
virtual bool start() override;
virtual void stop() override;
virtual void loop() override;
// Status getters (override virtual from InterfaceImpl)
float get_rssi() const override { return _last_rssi; }
float get_snr() const override { return _last_snr; }
bool is_transmitting() const { return _transmitting; }
virtual std::string toString() const override;
protected:
virtual void send_outgoing(const RNS::Bytes& data) override;
private:
void on_incoming(const RNS::Bytes& data);
void start_receive();
#ifdef ARDUINO
// RadioLib objects
SX1262* _radio = nullptr;
Module* _module = nullptr;
// SPI for LoRa (shared HSPI bus with display, but with MISO enabled)
SPIClass* _lora_spi = nullptr;
// SPI mutex for shared bus with display
static SemaphoreHandle_t _spi_mutex;
static bool _mutex_initialized;
#endif
// Configuration
SX1262Config _config;
// State
bool _transmitting = false;
float _last_rssi = 0.0f;
float _last_snr = 0.0f;
// Receive buffer
RNS::Bytes _rx_buffer;
// Hardware MTU: SX1262 max packet size is 255 bytes
// (RNode uses 508 because it fragments over serial HDLC, but we drive the radio directly)
static constexpr uint16_t HW_MTU = 255;
};