RF decode logic (not Manchester encoded) – Arduino

arduinoprogrammingRF

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()

Best 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.