Arduino PulseWire Transceiver Library
Loading...
Searching...
No Matches
ManchesterCodec.h
1#pragma once
2#include "assert.h"
3#include "pulse/SignalBase.h"
4#include "pulse/codecs/Codec.h"
5#include "pulse/tools/Vector.h"
6
7namespace pulsewire {
8
20class ManchesterCodec : public Codec {
21 public:
22 ManchesterCodec() = default;
23
25
26 CodecEnum getCodecType() const override { return CodecEnum::Manchester; }
27
28 bool begin(uint32_t bitFrequencyHz) override {
29 // Set up default preamble if still using the built-in one
30 if (_preamble == &_defaultPreamble) {
31 _defaultPreamble.clear();
32 uint32_t halfBit = (1000000UL / bitFrequencyHz) / 2;
33 _defaultPreamble.addEdge(true, halfBit); // single HIGH idle edge
34 }
36 }
37
43 int getEndOfFrameDelayUs() override { return 16 * _bitPeriodUs; }
44
48 size_t getEdgeCount() const override { return 16; }
49
62 bool decodeEdge(uint32_t durationUs, bool level, uint8_t& result) override {
63 int edgePeriod = 0.45f * _bitPeriodUs;
65 if (edgeCount < 1) edgeCount = 1;
66 if (edgeCount > 4) edgeCount = 4;
68
69 bool valid = false;
70 for (int i = 0; i < edgeCount; ++i) {
71 if (decodeEdgeInternal(avg_period, level, result)) {
72 valid = true;
73 }
74 }
75 return valid;
76 }
77
89 virtual size_t encode(uint8_t byte, Vector<OutputEdge>& output) {
91 bits.reserve(8);
92 encodeByte(byte, bits);
93 size_t total = 0;
94 for (int i = 0; i < 8; ++i) {
95 total += encodeBit(bits[i], output);
96 }
97 return total;
98 }
99
100 protected:
101 bool decodeEdgeInternal(uint32_t durationUs, bool level, uint8_t& result) {
102 // ensure that edges are allocated
103 assert(_decodeEdgeStream.capacity() > 0);
104
105 // Filter idle gaps
106 if (level == getIdleLevel() && durationUs > getEndOfFrameDelayUs()) {
107 Logger::debug("Idle gap detected: %d us, resetting decoder", durationUs);
108 reset();
109 return false;
110 }
111
112 OutputEdge newEdge{level, durationUs};
113 assert(_preamble != nullptr);
114 if (!_inFrame) {
115 if (_preamble->preambleLength() == 0) {
116 // no preamble, the edge is valid playload
117 _decodeEdgeStream.clear();
118 _decodeEdgeStream.push_back(newEdge);
119 _inFrame = true;
120 Logger::debug("No preamble, starting new frame");
121 } else if (_preamble->detect(newEdge)) {
122 // Detected preamble, start new frame
123 _inFrame = true;
124 _decodeEdgeStream.clear();
125 Logger::debug("Preamble detected, starting new frame");
126 }
127 } else {
128 _decodeEdgeStream.push_back(newEdge);
129 }
130
131 // Try to decode bytes if enough edges collected
132 if (_decodeEdgeStream.size() == getEdgeCount()) {
133 bool rc = decodeByte(_decodeEdgeStream, result);
134 Logger::debug("Decoded byte: 0x%x", result);
135 _decodeEdgeStream.clear();
136 return rc;
137 }
138 return false;
139 }
140
141 bool decodeByte(Vector<OutputEdge>& edges, uint8_t& result) {
142 assert(edges.size() == getEdgeCount());
143 bool valid = true;
144
145 uint8_t& byte = result;
146 byte = 0;
147
148 for (int i = 0; i < 8; ++i) {
149 bool b0 = edges[i * 2].level;
150 bool b1 = edges[i * 2 + 1].level;
151
152 if (b0 == 1 && b1 == 0) {
153 byte |= (1 << (7 - i)); // Set bit to 1
154 } else if (b0 == 0 && b1 == 1) {
155 // Bit is 0, do nothing
156 } else {
157 valid = false; // Invalid Manchester pair
158 Logger::error("Invalid Manchester pair at bit %d: b0=%d, b1=%d", i, b0,
159 b1);
160 break;
161 }
162 }
163
164 return valid;
165 }
166
175 size_t encodeBit(bool bit, Vector<OutputEdge>& output) {
176 // Manchester: each bit is two pulses
178 if (bit) {
179 first.level = true; // HIGH
180 first.pulseUs = _bitPeriodUs / 2;
181 second.level = false; // LOW
182 second.pulseUs = _bitPeriodUs / 2;
183 } else {
184 first.level = false; // LOW
185 first.pulseUs = _bitPeriodUs / 2;
186 second.level = true; // HIGH
187 second.pulseUs = _bitPeriodUs / 2;
188 }
189 output.push_back(first);
190 output.push_back(second);
191 return 2;
192 }
193};
194
195} // namespace pulsewire
Abstract base class for IR protocol encoding and decoding.
Definition Codec.h:53
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
Manchester encoding/decoding utility class for IR communication.
virtual size_t encode(uint8_t byte, Vector< OutputEdge > &output)
Fill output vector with protocol-specific OutputSpec(s) for a byte.
bool decodeEdge(uint32_t durationUs, bool level, uint8_t &result) override
Decode incoming edges to reconstruct bytes. Handles multiple edges per bit for noise tolerance by ave...
bool begin(uint32_t bitFrequencyHz) override
initialization method for codecs that require setup before use (e.g., loading PIO programs,...
int getEndOfFrameDelayUs() override
Get delay to mark End Of Frame in us.
CodecEnum getCodecType() const override
size_t getEdgeCount() const override
Get the number of edges used to encode a byte (16 for Manchester).
size_t encodeBit(bool bit, Vector< OutputEdge > &output)
Fill output vector with Manchester OutputSpec(s) for a bit.
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
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