Arduino PulseWire Transceiver Library
Loading...
Searching...
No Matches
PulseWidthCodec.h
1#pragma once
2
3#include <stddef.h>
4#include <stdint.h>
5
6#include "Codec.h"
7#include "pulse/tools/Vector.h"
8
9namespace pulsewire {
10
23class PulseWidthCodec : public Codec {
24 public:
25 PulseWidthCodec() = default;
26
28
29 // Used by IRTransceiver to initialize codec with protocol-specific parameters
30 virtual void init(Preamble& detector, uint32_t shortPulseUs,
31 uint32_t longPulseUs, uint32_t toleranceUs) {
33 _shortPulseUs = shortPulseUs;
34 _longPulseUs = longPulseUs;
35 _toleranceUs = toleranceUs;
36 }
37
38 bool begin(uint32_t bitFrequencyHz) override {
40 if (_shortPulseUs == 0) _shortPulseUs = 1000000UL / (bitFrequencyHz * 2);
41 if (_longPulseUs == 0) _longPulseUs = 1000000UL / (bitFrequencyHz / 2);
42 if (_toleranceUs == 0) _toleranceUs = _bitPeriodUs * 0.3;
43
44 _inFrame = false;
45
46 return true;
47 }
48
49 CodecEnum getCodecType() const override { return CodecEnum::PulseWidth; }
50
51 int getEndOfFrameDelayUs() override { return 2 * _longPulseUs; }
52
53 size_t getEdgeCount() const override { return 16; }
54
55 size_t encode(uint8_t byte, Vector<OutputEdge>& output) override {
57 bits.reserve(8);
58 encodeByte(byte, bits);
59 size_t total = 0;
60 for (int i = 0; i < 8; ++i) {
61 total += encodeBit(bits[i], output);
62 }
63 return total;
64 }
65
66 bool decodeEdge(uint32_t durationUs, bool level, uint8_t& result) override {
67 // ensure that edges are allocated
68 assert(_decodeEdgeStream.capacity() > 0);
69
70 // Filter idle gaps
71 if (level == getIdleLevel() && durationUs > getEndOfFrameDelayUs()) {
72 Logger::debug("Idle gap detected: %d us, resetting decoder", durationUs);
73 reset();
74 return false;
75 }
76
78 assert(_preamble != nullptr);
79 if (!_inFrame) {
80 if (_preamble->preambleLength() == 0) {
81 // no preamble, the edge is valid playload
82 _decodeEdgeStream.clear();
83 _decodeEdgeStream.push_back(newEdge);
84 _inFrame = true;
85 Logger::debug("No preamble, starting new frame");
86 } else if (_preamble->detect(newEdge)) {
87 // Detected preamble, start new frame
88 _inFrame = true;
89 _decodeEdgeStream.clear();
90 Logger::debug("Preamble detected, starting new frame");
91 }
92 } else {
93 _decodeEdgeStream.push_back(newEdge);
94 }
95
96 // Try to decode bytes if enough edges collected
97 if (_decodeEdgeStream.size() == getEdgeCount()) {
98 bool rc = decodeByte(_decodeEdgeStream, result);
99 Logger::debug("Decoded byte: 0x%x", result);
100 _decodeEdgeStream.clear();
101 return rc;
102 }
103 return false;
104 }
105
106 protected:
107 uint32_t _shortPulseUs = 0;
108 uint32_t _longPulseUs = 0;
109 uint32_t _toleranceUs = 0;
110
111 bool bitMatch(uint32_t duration, bool bit) const {
112 uint32_t expected = bit ? _longPulseUs : _shortPulseUs;
113 return (duration >= expected - _toleranceUs &&
114 duration <= expected + _toleranceUs);
115 }
116
125 size_t encodeBit(bool bit, Vector<OutputEdge>& output) {
127 pulse.level = true; // HIGH
128 pulse.pulseUs = bit ? _longPulseUs : _shortPulseUs;
129 space.level = false; // LOW
130 space.pulseUs = _shortPulseUs; // Fixed space duration for both bits
131 output.push_back(pulse);
132 output.push_back(space);
133 return 2;
134 }
135 bool decodeByte(Vector<OutputEdge>& edges, uint8_t& result) {
136 if (edges.size() < 16) {
137 Logger::error("Not enough edges to decode byte: %d", edges.size());
138 return false;
139 }
140 uint8_t byte = 0;
141 int bit = 0;
142 for (auto& edge : edges) {
143 // only consider high
144 if (edge.level) {
145 if (bitMatch(edge.pulseUs, true)) {
146 byte |= (1 << (7 - bit));
147 } else if (bitMatch(edge.pulseUs, false)) {
148 // bit is 0
149 } else {
150 Logger::error("Invalid pulse duration for bit %d: %d us", bit,
151 edge.pulseUs);
152 }
153 bit++;
154 }
155 }
156 result = byte;
157 return true;
158 }
159};
160
161} // namespace pulsewire
Abstract base class for IR protocol encoding and decoding.
Definition Codec.h:53
void setPreamble(Preamble &preamble)
Set the Preamble Detector object.
Definition Codec.h:94
virtual bool getIdleLevel() const
Provides the initial ldle state (low or hith)
Definition Codec.h:127
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:204
virtual bool begin(uint32_t bitFrequencyHz)
initialization method for codecs that require setup before use (e.g., loading PIO programs,...
Definition Codec.h:70
virtual void reset()
Reset the internal state of the codec.
Definition Codec.h:84
static void debug(const char *format,...)
Log a debug message with formatting.
Definition Logger.h:82
static void error(const char *format,...)
Log an error message with formatting.
Definition Logger.h:37
Abstract base class for preamble detection and generation.
Definition Preamble.h:40
virtual bool detect(const OutputEdge &edge)
Detects if the incoming edge matches the expected preamble pattern.
Definition Preamble.h:52
Pulse-width encoding/decoding utility class for IR communication.
CodecEnum getCodecType() const override
size_t encodeBit(bool bit, Vector< OutputEdge > &output)
Fill output vector with PulseWidth OutputSpec(s) for a bit.
size_t getEdgeCount() const override
Get the number of protocol symbols (bits, pulses, etc.) per encoded byte.
size_t encode(uint8_t byte, Vector< OutputEdge > &output) override
Fill output vector with protocol-specific OutputSpec(s) for a byte.
bool begin(uint32_t bitFrequencyHz) override
initialization method for codecs that require setup before use (e.g., loading PIO programs,...
int getEndOfFrameDelayUs() override
virtual void init(Preamble &detector, uint32_t shortPulseUs, uint32_t longPulseUs, uint32_t toleranceUs)
bool decodeEdge(uint32_t durationUs, bool level, uint8_t &result) override
Edge-based decoding for protocol-agnostic RX drivers.
Small, header-only vector replacement for non-STL environments.
Definition Vector.h:29
size_t capacity() const
Current allocated capacity.
Definition Vector.h:167
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
void reserve(size_t cap)
Reserve space for at least cap elements.
Definition Vector.h:157
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