Arduino PulseWire Transceiver Library
Loading...
Searching...
No Matches
RxDriverRP2040.h
1#pragma once
2#include <Arduino.h>
3
4#include "pulse/Codec.h"
5#include "pulse/RxDriver.h"
6#include "pulse/Vector.h"
7
8namespace pulsewire {
9
19class RxDriverRP2040 : public RxDriver {
20 public:
30 bool useChecksum = false, uint32_t timeoutUs = 1000000)
31 : _codec(codec),
32 _rxPin(pin),
33 _freqHz(freqHz),
34 _useChecksum(useChecksum),
35 _timeoutUs(timeoutUs) {
36 _lastEdgeTime = micros();
37 }
38
39 void setFrameSize(uint8_t size) override { _frameSize = size; }
40
41 bool begin(uint8_t frameSize) override {
42 setFrameSize(frameSize);
43 return begin();
44 }
45
46 bool begin() override {
47 _codec.begin();
48 // DMA setup
49 dmaChannel = dma_claim_unused_channel(true);
50 if (dmaChannel < 0) return false;
51 dma_channel_config cfg = dma_channel_get_default_config(dmaChannel);
52 channel_config_set_transfer_data_size(&cfg, DMA_SIZE_32);
53 channel_config_set_read_increment(&cfg, false);
54 channel_config_set_write_increment(&cfg, true);
55 bool dma_config_ok = dma_channel_configure(
56 dmaChannel, &cfg, dmaBuf, &pio0->rxfifo[0], DMA_BUF_SIZE, false);
57 if (!dma_config_ok) return false;
58 dma_channel_start(dmaChannel);
59 // Pin initialization
60 pinMode(_rxPin, INPUT);
61 // PIO setup
62 PIO pio = pio0;
63 uint sm = pio_claim_unused_sm(pio, true);
64 if (sm == (uint)-1) return false;
65 uint offset = pio_add_program(pio, (const pio_program_t*)&ir_rx_program);
66 if (offset == (uint)-1) return false;
67 pio_sm_config c = pio_get_default_sm_config();
68 sm_config_set_in_pins(&c, _rxPin);
69 sm_config_set_clkdiv(&c, 1.0f);
70 pio_sm_set_consecutive_pindirs(pio, sm, _rxPin, 1, false);
71 pio_sm_init(pio, sm, offset, &c);
72 pio_sm_set_enabled(pio, sm, true);
73 return true;
74 }
75
76 void pollPIO() {
77 // Poll DMA buffer for new edge timings
78 while (dmaBufHead < DMA_BUF_SIZE) {
79 uint32_t data = dmaBuf[dmaBufHead++];
80 uint32_t duration = data & 0xFFFFFF;
81 bool level = (data >> 24) & 0x01;
82 _edgeDurations.push_back(duration);
83 _edgeLevels.push_back(level);
84 _lastEdgeTime = micros();
85 }
86 // Reset head if buffer is full
87 if (dmaBufHead >= DMA_BUF_SIZE) dmaBufHead = 0;
88 }
89
90 void checkTimeout() {
91 uint32_t now = micros();
92 if (!_edgeDurations.empty() && (now - _lastEdgeTime > _timeoutUs)) {
93 // Try to decode with a zero-duration edge to flush the buffer
94 uint8_t buffer[32] = {0};
95 size_t frameLen = 0;
96 if (_codec.decodeEdge(0, 0, 0, 0, buffer, _frameSize, frameLen)) {
97 bool valid = true;
98 if (_useChecksum) {
99 if (frameLen < 2)
100 valid = false;
101 else {
102 uint8_t sum = 0;
103 for (size_t j = 0; j < frameLen - 1; ++j) sum += buffer[j];
104 valid = (sum == buffer[frameLen - 1]);
105 }
106 }
107 if (valid) {
108 for (size_t i = 0; i < frameLen; ++i)
109 _frameBuffer.push_back(buffer[i]);
110 }
111 }
112 _edgeDurations.clear();
113 _edgeLevels.clear();
114 _lastEdgeTime = now;
115 }
116 }
117
118 size_t readBytes(uint8_t* buffer, size_t length) override {
119 checkTimeout();
120 size_t totalRead = 0;
121 // Poll edge buffer and decode frames using codec
122 while (length > 0 && available() >= _frameSize) {
123 if (decodeFrame(buffer, _frameSize)) {
124 buffer += _frameSize;
125 length -= _frameSize;
126 totalRead += _frameSize;
127 } else {
128 break;
129 }
130 }
131 return totalRead;
132 }
133
134 int available() override {
135 checkTimeout();
136 // Return number of bytes available in decoded frame buffer
137 return _frameBuffer.size();
138 }
139
140 protected:
141 Codec& _codec;
142 uint8_t _rxPin;
143 uint32_t _freqHz;
144 uint16_t _frameSize = 20;
145 Vector<uint8_t> _frameBuffer;
146 Vector<uint32_t> _edgeDurations;
147 Vector<bool> _edgeLevels;
148 // DMA support
149 static constexpr size_t DMA_BUF_SIZE = 128;
150 uint32_t dmaBuf[DMA_BUF_SIZE];
151 volatile size_t dmaBufHead = 0;
152 int dmaChannel = -1;
153 bool _useChecksum = false;
154 uint32_t _timeoutUs = 1000000;
155 uint32_t _lastEdgeTime = 0;
156 // Simple PIO program to capture edges and timings
157 static const uint16_t ir_rx_program[4] = {
158 0x2020, // wait for pin high
159 0xa042, // in pins, 1
160 0x2021, // wait for pin low
161 0xa042, // in pins, 1
162 };
163
164 // Example decodeFrame implementation
165 bool decodeFrame(uint8_t* buffer, size_t frameSize) {
166 // Use edgeDurations and edgeLevels to call codec.decodeEdge
167 size_t frameLen = 0;
168 for (size_t i = 0; i < _edgeDurations.size(); ++i) {
169 if (_codec.decodeEdge(_edgeDurations[i], _edgeLevels[i], 0, 0, buffer,
170 frameSize, frameLen)) {
171 bool valid = true;
172 if (_useChecksum) {
173 if (frameLen < 2)
174 valid = false;
175 else {
176 uint8_t sum = 0;
177 for (size_t j = 0; j < frameLen - 1; ++j) sum += buffer[j];
178 valid = (sum == buffer[frameLen - 1]);
179 }
180 }
181 if (valid) {
182 // Remove used edges
183 _edgeDurations.erase(_edgeDurations.begin(),
184 _edgeDurations.begin() + i + 1);
185 _edgeLevels.erase(_edgeLevels.begin(), _edgeLevels.begin() + i + 1);
186 return true;
187 }
188 }
189 }
190 return false;
191 }
192};
193
194} // namespace pulsewire
Abstract base class for IR protocol encoding and decoding.
Definition Codec.h:41
virtual bool decodeEdge(uint32_t durationUs, bool level, uint8_t &result)
Edge-based decoding for protocol-agnostic RX drivers.
Definition Codec.h:106
virtual bool begin(uint32_t bitFrequencyHz)
initialization method for codecs that require setup before use (e.g., loading PIO programs,...
Definition Codec.h:56
High-performance RP2040 IR RX driver using PIO for edge capture.
int available() override
Get the number of bytes available in the internal buffer.
size_t readBytes(uint8_t *buffer, size_t length) override
RxDriverRP2040(Codec &codec, uint8_t pin, uint32_t freqHz=1000, bool useChecksum=false, uint32_t timeoutUs=1000000)
Abstract base class for IR receivers.
Definition RxDriver.h:10
Small, header-only vector replacement for non-STL environments.
Definition Vector.h:29
iterator begin()
Iterator to first element.
Definition Vector.h:97
void clear()
Remove all elements.
Definition Vector.h:120
void push_back(const T &value)
Add element to end of vector.
Definition Vector.h:92
bool empty() const
True if vector is empty.
Definition Vector.h:118
iterator erase(iterator pos)
Erase single element at iterator pos, return iterator to next element.
Definition Vector.h:128
size_t size() const
Number of elements in vector.
Definition Vector.h:116