4#include "TransceiverConfig.h"
5#include "pulse/RxDriver.h"
6#include "pulse/codecs/Codec.h"
7#include "pulse/codecs/ManchesterCodec.h"
8#include "pulse/tools/Logger.h"
9#include "pulse/tools/RingBuffer.h"
10#include "pulse/tools/Vector.h"
25 virtual void handleInterrupt() = 0;
28#if !defined(HAS_INTERRUPT_ARG)
38 for (
int i = 0;
i < 10;
i++) {
39 if (!_isrData[
i].active || _isrData[
i].pin == pin) {
40 _isrData[
i].instance = instance;
41 _isrData[
i].active =
true;
42 _isrData[
i].pin = pin;
50 static bool isAttached(
uint8_t pin) {
51 for (
int i = 0;
i < 10;
i++) {
52 if (_isrData[
i].active && _isrData[
i].pin == pin) {
59 static void detach(
uint8_t pin) {
60 for (
int i = 0;
i < 10;
i++) {
61 if (_isrData[
i].active && _isrData[
i].pin == pin) {
63 _isrData[
i].instance =
nullptr;
64 _isrData[
i].active =
false;
79 static InstanceData _isrData[10];
81 static void isr0() { dispatch(0); }
82 static void isr1() { dispatch(1); }
83 static void isr2() { dispatch(2); }
84 static void isr3() { dispatch(3); }
85 static void isr4() { dispatch(4); }
86 static void isr5() { dispatch(5); }
87 static void isr6() { dispatch(6); }
88 static void isr7() { dispatch(7); }
89 static void isr8() { dispatch(8); }
90 static void isr9() { dispatch(9); }
92 static void initISR() {
96 isr5, isr6, isr7, isr8, isr9};
97 for (
int i = 0;
i < 10; ++
i) {
98 _isrData[
i].instance =
nullptr;
100 _isrData[
i].pin = -1;
101 _isrData[
i].active =
false;
107 static void dispatch(
int index) {
109 _isrData[
index].instance->handleInterrupt();
173 ~RxDriverArduino() {
end(); }
179 _rxBuffer.resize(size * 2);
194 _bitPeriodUs = 1000000UL / _freqHz;
195 _minUs = _bitPeriodUs / 2;
196 _maxUs = _bitPeriodUs * 2;
198 "RXDriveer: Bit frequency: %d Hz, Bit period: %d us, Timing window: "
200 _freqHz, _bitPeriodUs, _minUs, _maxUs);
202 if (_timeoutUs == 0) {
205 Logger::info(
"RXDriver: Timeout set to %d us", _timeoutUs);
218#ifdef HAS_INTERRUPT_ARG
221 if (!ISRManager::attach(_pin,
this)) {
228 Logger::info(
"RX driver started on pin %d with codec %s with frame size %d",
229 _pin, _codec.
name(), _frameSize);
238 if (_rxBuffer.available() <
length) {
242 if (_rxBuffer.size() == 0) {
253 int result = _rxBuffer.available();
261#ifdef HAS_INTERRUPT_ARG
264 ISRManager::detach(_pin);
272 volatile bool _lastLevel;
275 uint16_t _frameSize = DEFAULT_FRAME_SIZE;
283 bool _useChecksum =
false;
285 volatile bool _is_active =
false;
286 volatile bool _is_open =
false;
288#ifdef HAS_INTERRUPT_ARG
294 void IRAM_ATTR handleInterrupt()
override {
295 bool newLevel = digitalRead(_pin);
296 uint32_t now = micros();
297 uint32_t duration = now - _lastEdge;
301 OutputEdge edge{_lastLevel, duration};
302 _edgeBuffer.write(edge);
303 _lastLevel = newLevel;
307 void processEdges() {
311 while (!_rxBuffer.isFull() && ok) {
313 ok = _edgeBuffer.read(edge);
317 uint8_t byte_data = 0;
318 Logger::debug(
"RX Processing edge: level=%d, duration=%d us",
319 edge.level, edge.pulseUs);
320 if (_codec.
decodeEdge(edge.pulseUs, edge.level, byte_data)) {
321 _rxBuffer.write(byte_data);
333 void checkTimeout() {
335 uint32_t now = micros();
336 uint32_t duration = now - _lastEdge;
337 uint8_t byte_data = 0;
340 if (_is_open && duration > _timeoutUs) {
341 Logger::debug(
"Processing final edge after timeout: duration %d us",
343 bool has_data = _codec.
decodeEdge(_bitPeriodUs, _lastLevel, byte_data);
345 _rxBuffer.write(byte_data);
352 _lastEdge = micros();
Abstract base class for IR protocol encoding and decoding.
virtual int getEndOfFrameDelayUs()=0
virtual bool decodeEdge(uint32_t durationUs, bool level, uint8_t &result)=0
Edge-based decoding for protocol-agnostic RX drivers.
const char * name() const
Get the name of the codec type as a string (e.g., "PulseDistance", "Manchester").
virtual bool getIdleLevel() const
Provides the initial ldle state (low or hith)
virtual size_t getEdgeCount() const =0
Get the number of protocol symbols (bits, pulses, etc.) per encoded byte.
virtual bool begin(uint32_t bitFrequencyHz)
initialization method for codecs that require setup before use (e.g., loading PIO programs,...
void setFrameSize(uint16_t size)
Set the Frame Size.
virtual void reset()
Reset the internal state of the codec.
Manager for handling multiple ISR instances on platforms without attachInterruptArg.
static void debug(const char *format,...)
Log a debug message with formatting.
static void info(const char *format,...)
Log an informational message with formatting.
int readArray(T *dest, size_t len)
Read up to len elements into dest, returns number of elements read.
Interrupt-driven Arduino RX driver for pulse-based protocols.
void end()
Stop the receiver.
void setRxBufferSize(size_t size)
Set the size of the internal RX buffer.
bool begin(uint32_t bitFrequencyHz=DEFAULT_BIT_FREQ_HZ) override
Start the receiver.
int available() override
Get the number of bytes available in the internal buffer.
size_t readBytes(uint8_t *buffer, size_t length) override
RxDriverArduino(Codec &codec, uint8_t pin, uint32_t freqHz=DEFAULT_BIT_FREQ_HZ, bool useChecksum=false, uint32_t timeoutUs=0)
void setFrameSize(uint16_t size) override
Set the expected frame size for dynamic data reception.
Interrupt-capable IR RX driver interface for platforms without attachInterruptArg.
Abstract base class for IR receivers.
Small, header-only vector replacement for non-STL environments.
void resize(size_t n)
Resize vector to n elements.