# RF decode logic (not Manchester encoded) - Arduino

Continuing from my previous post, I am trying to decode the encoded RF data directly on Arduino. I've adopted the "sampling" approach, as against the "interrupt" based approach, reason being I believe the interrupt line will be used for some other purposes.

Having written it, and spending a good day trying to debug it (lack of real debugger is really telling, as serial-console println()'s are really limited due to their sluggishness.), but still can't seem to working.

Here I share the logic (pseudo-code), in the hope that someone can help point any obvious mistakes, or maybe a less obvious intricate timing issue (which I suspect to be more likely).

Firstly, how the data is encoded (which I am trying to decode) :-

bit-0: IIII ---- ---- ---- IIII ---- ---- ----
bit-1: IIII IIII IIII ---- IIII IIII IIII ----
bit-F: IIII ---- ---- ---- IIII IIII IIII ---- ('Floating', used only in Addr-part)
bit-S: IIII ---- ---- ---- ---- ---- ---- ---- (sync-bit)


Each I (High) or - (Low) is ~120 us (micro-sec) [actually ranges between 118-121 us].

So, I've decided to sample at 30us intervals, i.e. 4x the signal freq. On Arduino, I use delayMicroseconds(30) to get this effect, although the logic within the loop() is rather heavy, ~150 lines of code and upto 4 level of if-nesting (just to indicate complexity) of the state-machine, pattern-maching, level-transition logic. Compiled Arduino sketch is ~2KB in size, just to give an indication of the complexity.

Data transmission is a sequence of 'Codewords', where each codeword is --

[ Addr(8-bits: 0/1/F) | Data (4-bits: 0/1) | Sync-bit ]


And, a minimum of 2 codewords with same address are used for some rudimentary error checking.

Between 2 successive codewords, there is a time of all Low signal.

Also, prior-to/post valid transmission there is significant noise in the line, and my observation is that noise characteristics is such that there were no continuous high period in noise that was close to the representation of highs in encoded bit-1, but there were quite a few patterns in noise, whose continuous high period matched that of the high-period for bit-0 or first part of bit-F / bit-S, i.e. I we can (safely) assume that these patterns do not exist in noise...

---- ---- ----
IIII IIII IIII


but these do...

----
IIII


And, now my logic --

Decoding state-machine: INITIAL --> DEC_CW1 --> DONE_CW1 --> DEC_CW2 --> DONE_CW2 --> INITIAL

High-Level Pseudocode:

1) Detect RF-data pin state
2) Check if there is a transition
3) If no transition, then just increment count of samples in same state (say SampleCount)
4) If transition, then
4.1) Check, If SampleCount is in valid range to qualify towards an encoded bit
4.1.1) And, If CurrentState is INITIAL (i.e. before finding start of CW1)
4.1.1.1) Set CurrentState = DEC_CW1 (i.e. found start of CW1, potentially)
4.2.1) Or, If CurrentState is DONE_CW1 (i.e. before finding start of CW2)
4.1.1.1) Set CurrentState = DEC_CW2 (i.e. found start of CW2, potentially)
4.3.1) Or, If CurrentState is DEC_CW1 (i.e. already decoding CW1)
4.3.1.1) Is SamplePatternFor1Bit length enough to decode Bit
4.3.1.1.1) Yes, does it match 1BitPattern for 0 | 1 | F | S ?
4.3.1.1.1.1) Yes, then add it to CW1
4.3.1.1.1.2) No, then invalid pattern/error, discard all under-construction buffers, reset all counters and states & return from loop()
4.3.1.1.2) No, then continue loop()
4.4.1) Or, If CurrentState is DEC_CW2 (i.e. already decoding CW2)
4.4.1.1) Is SamplePatternFor1Bit length enough to decode Bit
4.4.1.1.1) Yes, does it match 1BitPattern for 0 | 1 | F | S ?
4.4.1.1.1.1) Yes, then add it to CW1
4.4.1.1.1.2) No, then invalid pattern/error, discard all under-construction buffers, reset all counters and states & return from loop()
4.4.1.1.2) No, then continue loop()
5) No transition,
5.1) Increment SampleCount (i.e. yet another sample in same state as before)
5.2) If SampleCount is 95-97 samples, all LOW then it indicates trailing end of S-bit pattern
5.2.1) Yes, If CurrentState is INITIAL (i.e. already decoding CW1)
5.2.1.1) Yes, means CW1 is complete, so Set CurrentState = DONE_CW1
5.2.1.2) Move under-construction CW, into saved CW1
5.2.2) Yes, If CurrentState is DEC_CW2 (i.e. already decoding CW2)
5.2.2.1) Yes, means CW1 is complete, so Set CurrentState = DONE_CW2
5.2.2.2) Move under-construction CW, into saved CW2
5.2.2.3) If CW1.Addr = CW2.Addr (same pattern) ?
5.2.2.3.1) Yes, then CW match, return CW2.data as the decoded Data from CW2.Addr as Addr
5.2.2.3.2) No, then discard all under-construction buffers, reset all counters and states & return from loop()

• In what way is it not working? – Majenko Nov 27 '11 at 16:09
• @Majenko, initially I had put prints on a Codeword find (duplicate matched), but then I inserted prints on even finding a partial pattern (within a single Codeword), e.g. IIII ---- , and even this isn't detected. I know for sure that the uC is receiving the RF pattern (I've a Logic Analyzer hooked on the pin). – icarus74 Nov 27 '11 at 16:33
• Wondering if my question is better suited for Stackoverflow, since it is a bit more programming intensive ! – icarus74 Nov 28 '11 at 6:52
• It's a tough one - while it's not off-topic for here, it's questionable whether the expertise exists here to give you a good answer. – Majenko Nov 28 '11 at 9:20
• Do you fancy trying to convert the pseudocode into a flowchart? It makes it easier to follow. – Majenko Nov 28 '11 at 9:21

## 1 Answer

While the Atmel app-note regarding Manchester encode/decode talks of 2 approaches - 1. Fast sampling 2. Using interrupts

My first attempt, as depicted by this question was using the Fast-sampling method, but not being able to make reasonable progress, and growing complexity of the sampling, decode, command-parsing logic, I switched over to the Interrupt method. If one follows the 'Linked Questions' one would find how I eventually solved it. In a nutshell, I found the interrupt method to be much simpler, and also, I think it is somewhat more reliable and robust against timing issues.

• Most sampling approachs assume a quite uniform sampling period, which delay() probably does not get you unless the delay period drastically overshadows any variable computation demands inlcuding other interrupts. To do sampling right, you likely need to use a timer, possibly a timer interrupt. So the real question becomes if you are triggered by abstract time, or by transitions of the input line. Anyway, glad you solved it. – Chris Stratton Jan 3 '12 at 17:59
• Ah, good point and glad you asked. The final solution is based on ISR handling transitions on input line. In a nut-shell, I measure signal duration, ignore high frequency noise, keeping acceptable signal. Since the encode logic has a sync signal, which is quite unique, the decoding is simplified by watching for it, and starting my decode window at that point. – icarus74 Jan 3 '12 at 18:08