Arduino PulseWire Transceiver Library
Loading...
Searching...
No Matches
Codec.h
1#pragma once
2#include <stddef.h>
3#include <stdint.h>
4#include <assert.h>
5
6#include "pulse/Preamble.h"
7#include "pulse/SignalBase.h"
8#include "pulse/tools/Vector.h"
9#include "pulse/tools/Logger.h"
10
11namespace pulsewire {
12
14enum class CodecEnum { PulseDistance, PulseWidth, Manchester, DifferentialManchester, NRZ };
15
16const char* toStr(CodecEnum codec) {
17 switch (codec) {
18 case CodecEnum::PulseDistance:
19 return "PulseDistance";
20 case CodecEnum::PulseWidth:
21 return "PulseWidth";
22 case CodecEnum::Manchester:
23 return "Manchester";
24 case CodecEnum::DifferentialManchester:
25 return "DifferentialManchester";
26 case CodecEnum::NRZ:
27 return "NRZ";
28 default:
29 return "Unknown";
30 }
31}
32
41class Codec {
42 public:
43 Codec() = default;
44
45 Codec(Preamble& preambleDetector) : _preamble(&preambleDetector) {}
46
49 virtual void init(Preamble& detector, uint32_t shortPulseUs = 600,
50 uint32_t longPulseUs = 1200, uint32_t toleranceUs = 200) {}
51
56 virtual bool begin(uint32_t bitFrequencyHz) {
57 TRACE();
58 assert(_preamble != nullptr);
59 _inFrame = false;
60 _bitFrequencyHz = bitFrequencyHz;
61 _bitPeriodUs = 1000000UL / bitFrequencyHz; // Bit period in microseconds
62 _preamble->begin(bitFrequencyHz);
63 _decodeEdgeStream.reserve(getEdgeCount());
64 return true;
65 }
66
67 virtual void reset() {
68 _decodeEdgeStream.clear(); // clear() keeps capacity, no realloc
69 _inFrame = false;
70 _preamble->reset();
71 }
72
77 Preamble& getPreamble() { return *_preamble; }
78
84 void setPreamble(Preamble& preamble) { _preamble = &preamble; }
90 virtual size_t getEdgeCount() const = 0;
91
106 virtual bool decodeEdge(uint32_t durationUs, bool level, uint8_t& result) {
107 // ensure that edges are allocated
108 assert(_decodeEdgeStream.capacity() > 0);
109
110 // Filter idle gaps
111 if (level == getIdleLevel() && durationUs > getEndOfFrameDelayUs()) {
112 Logger::debug("Idle gap detected: %d us, resetting decoder", durationUs);
113 reset();
114 return false;
115 }
116
117 OutputEdge newEdge{level, durationUs};
118 assert(_preamble != nullptr);
119 if (!_inFrame) {
120 if (_preamble->preambleLength() == 0) {
121 // no preamble, the edge is valid playload
122 _decodeEdgeStream.clear();
123 _decodeEdgeStream.push_back(newEdge);
124 _inFrame = true;
125 Logger::debug("No preamble, starting new frame");
126 } else if (_preamble->detect(newEdge)) {
127 // Detected preamble, start new frame
128 _inFrame = true;
129 _decodeEdgeStream.clear();
130 Logger::debug("Preamble detected, starting new frame");
131 }
132 } else {
133 _decodeEdgeStream.push_back(newEdge);
134 }
135
136 // Try to decode bytes if enough edges collected
137 if (_decodeEdgeStream.size() == getEdgeCount()) {
138 bool rc = decodeByte(_decodeEdgeStream, result);
139 Logger::debug("Decoded byte: 0x%x", result);
140 _decodeEdgeStream.clear();
141 return rc;
142 }
143 return false;
144 }
145
146 size_t encodePreamble(Vector<OutputEdge>& output) {
147 if (_preamble == nullptr) return 0;
148 return _preamble->getEdges(output);
149 }
150
162 virtual size_t encode(uint8_t byte, Vector<OutputEdge>& output) {
163 Vector<bool> bits;
164 bits.reserve(8);
165 encodeByte(byte, bits);
166 size_t total = 0;
167 for (int i = 0; i < 8; ++i) {
168 total += encodeBit(bits[i], output);
169 }
170 return total;
171 }
172
173 void setFrameSize(uint16_t size) {
174 _decodeEdgeStream.reserve(size * getEdgeCount());
175 }
176
184 virtual size_t encodeBit(bool bit, Vector<OutputEdge>& output) { return 0; };
185
194 virtual void encodeByte(uint8_t byte, std::vector<bool> &bits) const {
195 for (int i = 7; i >= 0; --i) {
196 bool bit = (byte >> i) & 0x01;
197 bits[7 - i] = bit ? 1 : 0;
198 }
199 }
200
202 virtual bool decodeByte(Vector<OutputEdge>& edges, uint8_t& result) = 0;
203
205 virtual int getEndOfFrameDelayUs() = 0;
206
208 virtual bool getIdleLevel() const {
209 return false;
210 }
211
214 virtual CodecEnum getCodecType() const = 0;
215
218 const char* name() const { return toStr(getCodecType()); }
219
220
221 protected:
222 CustomPreambleUs _defaultPreamble;
223 Preamble* _preamble = &_defaultPreamble;
224 uint16_t _bitFrequencyHz = 0;
225 uint32_t _bitPeriodUs = 0;
226 Vector<OutputEdge> _decodeEdgeStream;
227 volatile bool _inFrame = false;
228};
229
230} // namespace pulsewire
Abstract base class for IR protocol encoding and decoding.
Definition Codec.h:41
virtual size_t encode(uint8_t byte, Vector< OutputEdge > &output)
Fill output vector with protocol-specific OutputSpec(s) for a byte.
Definition Codec.h:162
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
virtual size_t encodeBit(bool bit, Vector< OutputEdge > &output)
Fill output vector with protocol-specific OutputSpec(s) for a bit.
Definition Codec.h:184
virtual int getEndOfFrameDelayUs()=0
Provide the end of frame delay in microseconds for this protocol, used by RX driver to.
virtual void init(Preamble &detector, uint32_t shortPulseUs=600, uint32_t longPulseUs=1200, uint32_t toleranceUs=200)
Definition Codec.h:49
void setPreamble(Preamble &preamble)
Set the Preamble Detector object.
Definition Codec.h:84
const char * name() const
Get the name of the codec type as a string (e.g., "PulseDistance", "Manchester").
Definition Codec.h:218
virtual bool getIdleLevel() const
Provides the initial ldle state (low or hith)
Definition Codec.h:208
virtual CodecEnum getCodecType() const =0
instance.
Preamble & getPreamble()
Get the preamble detector associated with this codec.
Definition Codec.h:77
virtual bool decodeByte(Vector< OutputEdge > &edges, uint8_t &result)=0
Decode edges into a byte.
virtual size_t getEdgeCount() const =0
Get the number of protocol symbols (bits, pulses, etc.) per encoded byte.
virtual void encodeByte(uint8_t byte, std::vector< bool > &bits) const
Encode a byte to protocol bitstream. Default implementation encodes to raw bits (MSB first),...
Definition Codec.h:194
CustomPreambleUs: Allows users to define their own preamble by setting expected edges....
Definition Preamble.h:127
static void debug(const char *format,...)
Log a debug message with formatting.
Definition Logger.h:82
Abstract base class for preamble detection and generation.
Definition Preamble.h:40
virtual int getEdges(pulsewire::Vector< pulsewire::OutputEdge > &output) const =0
Returns the expected preamble edges for this protocol.
virtual bool detect(const OutputEdge &edge)
Detects if the incoming edge matches the expected preamble pattern.
Definition Preamble.h:52
Small, header-only vector replacement for non-STL environments.
Definition Vector.h:29
void reserve(size_t cap)
Reserve space for at least cap elements.
Definition Vector.h:157
Specifies a single IR signal segment for protocol-agnostic transmission.
Definition Preamble.h:23