Arduino PulseWire Transceiver Library
Loading...
Searching...
No Matches
IRProtocol.h
1#pragma once
2#include "codecs/PulseDistanceCodec.h"
3#include "codecs/PulseWidthCodec.h"
4#include "codecs/ManchesterCodec.h"
5#include "codecs/NRZCodec.h"
6#include "Preamble.h"
7#include "codecs/Codec.h"
8#include "tools/Vector.h"
9
10namespace pulsewire {
14enum class IRProtocolEnum {
15 Unknown,
16 Custom,
17 NEC,
18 NEC16,
19 NEC42,
20 Sony,
21 RC5,
22 RC6,
23 Denon,
24 JVC,
25 Sharp,
26 Kaseikyo,
27 Samsung,
28 Samsung48,
29 Whynter,
30 Manchester,
31 Apple,
32 Onkyo,
33 Matsushita,
34 Grundig,
35 SiemensGigaset,
36 Nokia,
37 Thomson,
38 Telefunken,
39 Technics
40};
41
43const char* toStr(IRProtocolEnum protocol) {
44 switch (protocol) {
45 case IRProtocolEnum::Custom:
46 return "Custom";
47 case IRProtocolEnum::NEC:
48 return "NEC";
49 case IRProtocolEnum::NEC16:
50 return "NEC16";
51 case IRProtocolEnum::NEC42:
52 return "NEC42";
53 case IRProtocolEnum::Sony:
54 return "Sony";
55 case IRProtocolEnum::RC5:
56 return "RC5";
57 case IRProtocolEnum::RC6:
58 return "RC6";
59 case IRProtocolEnum::Denon:
60 return "Denon";
61 case IRProtocolEnum::JVC:
62 return "JVC";
63 case IRProtocolEnum::Sharp:
64 return "Sharp";
65 case IRProtocolEnum::Kaseikyo:
66 return "Kaseikyo";
67 case IRProtocolEnum::Samsung:
68 return "Samsung";
69 case IRProtocolEnum::Samsung48:
70 return "Samsung48";
71 case IRProtocolEnum::Whynter:
72 return "Whynter";
73 case IRProtocolEnum::Apple:
74 return "Apple";
75 case IRProtocolEnum::Onkyo:
76 return "Onkyo";
77 case IRProtocolEnum::Matsushita:
78 return "Matsushita";
79 case IRProtocolEnum::Grundig:
80 return "Grundig";
81 case IRProtocolEnum::SiemensGigaset:
82 return "Siemens Gigaset";
83 case IRProtocolEnum::Nokia:
84 return "Nokia";
85 case IRProtocolEnum::Thomson:
86 return "Thomson";
87 case IRProtocolEnum::Telefunken:
88 return "Telefunken";
89 case IRProtocolEnum::Technics:
90 return "Technics";
91 case IRProtocolEnum::Manchester:
92 return "Manchester";
93 default:
94 return "Unknown";
95 }
96}
97
124class IRProtocol : public Preamble {
125 public:
126 IRProtocol() = default;
127 IRProtocol(IRProtocolEnum proto, CodecEnum codecType, uint32_t frequency,
128 size_t dataLength, uint32_t shortPulse, uint32_t longPulse,
129 uint32_t tolerance, Vector<OutputEdge> edges)
130 : _proto(proto),
131 _frequency(frequency),
132 _dataLength(dataLength),
133 _shortPulseUs(shortPulse),
134 _longPulseUs(longPulse),
135 _toleranceUs(tolerance),
136 _codecType(codecType),
137 _edges(edges) {}
138
139 // Destructor to clean up codec if allocated
140 ~IRProtocol() {
141 if (_codec != nullptr) {
142 delete _codec;
143 _codec = nullptr;
144 }
145 }
146
148 void begin(IRProtocolEnum proto, uint32_t frequency, size_t dataLength,
149 uint32_t shortPulse, uint32_t longPulse, uint32_t tolerance,
150 Vector<OutputEdge> edges,
151 CodecEnum codecType = CodecEnum::PulseDistance) {
152 _proto = proto;
153 _frequency = frequency;
154 _dataLength = dataLength;
155 _shortPulseUs = shortPulse;
156 _longPulseUs = longPulse;
157 _toleranceUs = tolerance;
158 _edges.clear();
159 for (const auto& edge : edges) {
160 _edges.push_back(edge);
161 }
162 }
163
165 void copyFrom(const IRProtocol& other) {
166 _proto = other._proto;
167 _frequency = other._frequency;
168 _dataLength = other._dataLength;
169 _shortPulseUs = other._shortPulseUs;
170 _longPulseUs = other._longPulseUs;
171 _toleranceUs = other._toleranceUs;
172 _codecType = other._codecType;
173 _edges.clear();
174 for (const auto& edge : other._edges) {
175 _edges.push_back(edge);
176 }
177 }
178
180 virtual IRProtocolEnum getProtocolID() const { return _proto; }
181
182 const char* name() const { return toStr(_proto); }
183
185 virtual int getEdges(Vector<OutputEdge>& output) const override {
186 output.clear();
187 for (auto& edge : _edges) {
188 output.push_back(edge);
189 }
190 return _edges.size();
191 }
193 virtual size_t preambleLength() const override { return _edges.size(); }
195 virtual uint32_t frequency() const { return _frequency; }
197 virtual size_t dataLength() const { return _dataLength; }
199 virtual uint32_t shortPulseUs() const { return _shortPulseUs; }
201 virtual uint32_t longPulseUs() const { return _longPulseUs; }
203 virtual uint32_t toleranceUs() const { return _toleranceUs; }
205 virtual Codec& codec() {
206 if (_codec == nullptr) {
207 switch (_codecType) {
208 case CodecEnum::PulseDistance:
209 _codec = new PulseDistanceCodec();
210 break;
211 case CodecEnum::PulseWidth:
212 _codec = new PulseWidthCodec();
213 break;
214 case CodecEnum::Manchester:
215 _codec = new ManchesterCodec();
216 break;
217 case CodecEnum::NRZ:
218 _codec = new NRZCodec();
219 break;
220 default:
221 _codec = new PulseWidthCodec();
222 break;
223 }
224 }
225 return *_codec;
226 }
227
228 private:
229 IRProtocolEnum _proto = IRProtocolEnum::Unknown;
230 Codec* _codec = nullptr;
231
232 uint32_t _frequency = 38000; // Default frequency in Hz
233 size_t _dataLength = 4;
234 // Add these fields for protocol-specific timings:
235 uint32_t _shortPulseUs = 560; // Duration of the short pulse in microseconds
236 uint32_t _longPulseUs = 1690; // Duration of the long pulse in microseconds
237 uint32_t _toleranceUs = 200; // Tolerance in microseconds
238 std::vector<OutputEdge> _edges;
239 CodecEnum _codecType;
240};
241
242static IRProtocol IRProtocolNEC(IRProtocolEnum::NEC, CodecEnum::PulseDistance,
243 38000, 32, 560, 1690, 200,
244 {{true, 9000}, {false, 4500}});
245static IRProtocol IRProtocolNEC16(IRProtocolEnum::NEC16, CodecEnum::PulseDistance,
246 38000, 16, 560, 1690, 200,
247 {{true, 9000}, {false, 2250}});
248static IRProtocol IRProtocolNEC42(IRProtocolEnum::NEC42, CodecEnum::PulseDistance,
249 38000, 42, 560, 1690, 200,
250 {{true, 9000}, {false, 4500}, {true, 562}, {false, 562}});
251static IRProtocol IRProtocolSony(IRProtocolEnum::Sony, CodecEnum::PulseWidth,
252 40000, 12, 600, 1200, 200,
253 {{true, 2400}});
254static IRProtocol IRProtocolSamsung(IRProtocolEnum::Samsung, CodecEnum::PulseDistance,
255 38000, 32, 560, 1690, 200,
256 {{true, 4500}, {false, 4500}});
257static IRProtocol IRProtocolSamsung48(IRProtocolEnum::Samsung48, CodecEnum::PulseDistance,
258 38000, 48, 560, 1690, 200,
259 {{true, 4800}, {false, 4800}});
260static IRProtocol IRProtocolWhynter(IRProtocolEnum::Whynter, CodecEnum::PulseDistance,
261 38000, 32, 560, 1690, 200,
262 {{true, 2850}, {false, 2850}});
263static IRProtocol IRProtocolApple(IRProtocolEnum::Apple, CodecEnum::PulseDistance,
264 38000, 32, 560, 1690, 200,
265 {{true, 9000}, {false, 4500}});
266static IRProtocol IRProtocolOnkyo(IRProtocolEnum::Onkyo, CodecEnum::PulseDistance,
267 38000, 32, 560, 1690, 200,
268 {{true, 9000}, {false, 4500}});
269static IRProtocol IRProtocolMatsushita(IRProtocolEnum::Matsushita, CodecEnum::PulseDistance,
270 37900, 48, 432, 1296, 200,
271 {{true, 3456}, {false, 1728}});
272static IRProtocol IRProtocolGrundig(IRProtocolEnum::Grundig, CodecEnum::Manchester,
273 38000, 24, 560, 1690, 200,
274 {{true, 2600}, {false, 600}});
275static IRProtocol IRProtocolSiemensGigaset(IRProtocolEnum::SiemensGigaset, CodecEnum::Manchester,
276 38000, 32, 560, 1690, 200,
277 {{true, 9000}, {false, 4500}});
278static IRProtocol IRProtocolNokia(IRProtocolEnum::Nokia, CodecEnum::Manchester,
279 38000, 32, 560, 1690, 200,
280 {{true, 4500}, {false, 4500}});
281static IRProtocol IRProtocolThomson(IRProtocolEnum::Thomson, CodecEnum::Manchester,
282 38000, 24, 560, 1690, 200,
283 {{true, 2600}, {false, 600}});
284static IRProtocol IRProtocolTelefunken(IRProtocolEnum::Telefunken, CodecEnum::Manchester,
285 38000, 24, 560, 1690, 200,
286 {{true, 2600}, {false, 600}});
287static IRProtocol IRProtocolTechnics(IRProtocolEnum::Technics, CodecEnum::Manchester,
288 37900, 48, 432, 1296, 200,
289 {{true, 3456}, {false, 1728}});
290static IRProtocol IRProtocolJVC(IRProtocolEnum::JVC, CodecEnum::PulseDistance,
291 38000, 32, 525, 1575, 200,
292 {{true, 8400}, {false, 4200}});
293static IRProtocol IRProtocolSharp(IRProtocolEnum::Sharp, CodecEnum::PulseDistance,
294 38000, 32, 320, 1600, 200,
295 {{true, 3200}, {false, 1600}});
296static IRProtocol IRProtocolKaseikyo(IRProtocolEnum::Kaseikyo, CodecEnum::PulseDistance,
297 37900, 48, 432, 1296, 200,
298 {{true, 3456}, {false, 1728}});
299static IRProtocol IRProtocolDenon(IRProtocolEnum::Denon, CodecEnum::PulseDistance,
300 38000, 24, 425, 1275, 200,
301 {{true, 2600}, {false, 500}});
302
317 public:
319 _preambles.push_back(&IRProtocolNEC);
320 _preambles.push_back(&IRProtocolNEC16);
321 _preambles.push_back(&IRProtocolNEC42);
322 _preambles.push_back(&IRProtocolSony);
323 _preambles.push_back(&IRProtocolSamsung);
324 _preambles.push_back(&IRProtocolSamsung48);
325 _preambles.push_back(&IRProtocolWhynter);
326 _preambles.push_back(&IRProtocolApple);
327 _preambles.push_back(&IRProtocolOnkyo);
328 _preambles.push_back(&IRProtocolMatsushita);
329 _preambles.push_back(&IRProtocolGrundig);
330 _preambles.push_back(&IRProtocolSiemensGigaset);
331 _preambles.push_back(&IRProtocolNokia);
332 _preambles.push_back(&IRProtocolThomson);
333 _preambles.push_back(&IRProtocolTelefunken);
334 _preambles.push_back(&IRProtocolTechnics);
335 _preambles.push_back(&IRProtocolJVC);
336 _preambles.push_back(&IRProtocolSharp);
337 _preambles.push_back(&IRProtocolKaseikyo);
338 _preambles.push_back(&IRProtocolDenon);
339 }
340 IRMultiProtocol(IRProtocol& defaultInfo) : IRMultiProtocol() {
341 setActualProtocol(defaultInfo);
342 }
343 IRProtocolEnum getProtocolID() const override {
344 return _refInfo->getProtocolID();
345 }
346 int getEdges(Vector<OutputEdge>& output) const override {
347 return _refInfo->getEdges(output);
348 }
349 size_t preambleLength() const override { return _refInfo->preambleLength(); }
350 uint32_t frequency() const { return _refInfo->frequency(); }
351 size_t dataLength() const { return _refInfo->dataLength(); }
352 uint32_t shortPulseUs() const { return _refInfo->shortPulseUs(); }
353 uint32_t longPulseUs() const { return _refInfo->longPulseUs(); }
354 uint32_t toleranceUs() const { return _refInfo->toleranceUs(); }
355
356 // Optionally, delegate copyFrom and setup if needed
357 void copyFrom(const IRProtocol& other) { _refInfo->copyFrom(other); }
358 void begin(IRProtocolEnum proto, uint32_t frequency, size_t dataLength,
359 uint32_t shortPulse, uint32_t longPulse, uint32_t tolerance,
360 Vector<OutputEdge> edges) {
361 _refInfo->begin(proto, frequency, dataLength, shortPulse, longPulse,
362 tolerance, edges);
363 }
364
365 bool detect(const OutputEdge& edge) override {
366 for (size_t i = 0; i < _preambles.size(); ++i) {
367 if (_preambles[i]->detect(edge)) {
368 IRProtocolEnum _proto = _preambles[i]->getProtocolID();
369 if (_callback) _callback(_proto, *_preambles[i], _ref);
370 return true;
371 }
372 }
373 return false;
374 }
375
378 void setCallback(void (*callback)(IRProtocolEnum, IRProtocol&, void* ref),
379 void* ref) {
380 _callback = callback;
381 _ref = ref;
382 }
383
385 IRProtocol& getProtocol() const { return *_refInfo; }
386
388 IRProtocol& getProtocolByID(IRProtocolEnum proto) const {
389 for (size_t i = 0; i < _preambles.size(); ++i) {
390 if (_preambles[i]->getProtocolID() == proto) {
391 return *_preambles[i];
392 }
393 }
394 static IRProtocol na;
395 return na; // Return default if not found
396 }
397
398 void addProtocol(IRProtocol& protocol) {
399 // Check if protocol with same ID already exists
400 for (size_t i = 0; i < _preambles.size(); ++i) {
401 if (_preambles[i]->getProtocolID() == protocol.getProtocolID()) {
402 _preambles[i] = &protocol; // Replace existing protocol
403 return;
404 }
405 }
406 _preambles.push_back(&protocol); // Add new protocol
407 }
408
409 void setActualProtocol(IRProtocol& proto) {
410 _refInfo = &proto;
411 if (_preambles[0] != &proto) {
412 _preambles.insert(_preambles.begin(), _refInfo);
413 }
414 }
415
416 protected:
417 IRProtocol* _refInfo = &IRProtocolNEC;
418 Vector<IRProtocol*> _preambles;
419 void (*_callback)(IRProtocolEnum, IRProtocol&, void* ref) = nullptr;
420 void* _ref = nullptr;
421};
422
423} // namespace pulsewire
Abstract base class for IR protocol encoding and decoding.
Definition Codec.h:41
IRMultiProtocol: Handles detection and delegation for multiple IR protocols.
Definition IRProtocol.h:316
IRProtocol & getProtocol() const
Provides the active protocol.
Definition IRProtocol.h:385
IRProtocol & getProtocolByID(IRProtocolEnum proto) const
Provides a protocol by its enum ID, or a default if not found.
Definition IRProtocol.h:388
uint32_t toleranceUs() const
Tolerance in microseconds for pulse duration matching during detection.
Definition IRProtocol.h:354
size_t preambleLength() const override
Returns the number of edges in the preamble.
Definition IRProtocol.h:349
void setCallback(void(*callback)(IRProtocolEnum, IRProtocol &, void *ref), void *ref)
Definition IRProtocol.h:378
uint32_t frequency() const
Returns the carrier frequency in Hz.
Definition IRProtocol.h:350
size_t dataLength() const
Returns the expected data length in bytes (not including preamble)
Definition IRProtocol.h:351
uint32_t shortPulseUs() const
Returns the duration of the short pulse in microseconds.
Definition IRProtocol.h:352
uint32_t longPulseUs() const
Returns the duration of the long pulse in microseconds.
Definition IRProtocol.h:353
int getEdges(Vector< OutputEdge > &output) const override
Returns the preamble edges for this protocol.
Definition IRProtocol.h:346
IRProtocolEnum getProtocolID() const override
Returns the protocol enum identifier for this IR protocol.
Definition IRProtocol.h:343
bool detect(const OutputEdge &edge) override
Detects if the incoming edge matches the expected preamble pattern.
Definition IRProtocol.h:365
IRProtocol: Represents a specific IR protocol with all its parameters.
Definition IRProtocol.h:124
virtual Codec & codec()
Provides the codec associated with this protocol.
Definition IRProtocol.h:205
virtual size_t preambleLength() const override
Returns the number of edges in the preamble.
Definition IRProtocol.h:193
void begin(IRProtocolEnum proto, uint32_t frequency, size_t dataLength, uint32_t shortPulse, uint32_t longPulse, uint32_t tolerance, Vector< OutputEdge > edges, CodecEnum codecType=CodecEnum::PulseDistance)
Set all fields for this IR protocol, including preamble edges.
Definition IRProtocol.h:148
void copyFrom(const IRProtocol &other)
Copy all fields from another IRProtocol instance.
Definition IRProtocol.h:165
virtual size_t dataLength() const
Returns the expected data length in bytes (not including preamble)
Definition IRProtocol.h:197
virtual uint32_t frequency() const
Returns the carrier frequency in Hz.
Definition IRProtocol.h:195
virtual int getEdges(Vector< OutputEdge > &output) const override
Returns the preamble edges for this protocol.
Definition IRProtocol.h:185
virtual IRProtocolEnum getProtocolID() const
Returns the protocol enum identifier for this IR protocol.
Definition IRProtocol.h:180
virtual uint32_t shortPulseUs() const
Returns the duration of the short pulse in microseconds.
Definition IRProtocol.h:199
virtual uint32_t toleranceUs() const
Tolerance in microseconds for pulse duration matching during detection.
Definition IRProtocol.h:203
virtual uint32_t longPulseUs() const
Returns the duration of the long pulse in microseconds.
Definition IRProtocol.h:201
Manchester encoding/decoding utility class for IR communication.
NRZ (Non-Return-to-Zero) codec for serial-like encoding/decoding with start/stop bit framing.
Definition NRZCodec.h:10
Abstract base class for preamble detection and generation.
Definition Preamble.h:40
Pulse-distance encoding/decoding utility class for IR communication.
Pulse-width encoding/decoding utility class for IR communication.
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
size_t size() const
Number of elements in vector.
Definition Vector.h:116
Specifies a single IR signal segment for protocol-agnostic transmission.
Definition Preamble.h:23