Sniffing SPI data from my Current Cost EnviR

I've successfully sniffed SPI data from my Current Cost EnviR (firmware v 1.29) using a Bus Pirate.

Here's the back of the EnviR PCB. I soldered some wires onto the RFM01 module to make it a little easier to sniff data from the device:




The Bus Pirate is wonderfully easy to use. Just connect it up to the EnviR. Once the Bus Pirate is connected to a laptop, you can start talking to it using screen /dev/ttyUSB0 115200. Put the Bus Pirate into SPI mode and then start sniffing by typing (1). Easy peasy. Below are the results from some SPI bus sniffing...

RFM01 configuration commands

Here are the commands the EnviR sends to its RFM01 module when it first starts:

 1 [892D
 2  E196
 3  CC0E
 4  C69F
 5  C46A
 6  C88A
 7  C080]
 
 8 [CE8B
 9  C081
10  C200
11  A618
12  CE89
13  CE8B]

This sequence of commands is very similar (but not identical) to the command sequence observed by gangliontwitch. My CC unit probably has a different firmware.

And here's my attempt to interpret those commands using the RFM01 programming manual:

From RFM01 command #1 0x892D (gangliontwitch observed 0x892C)
eb=0 (disable low batt detection)
et=0 (disable wake-up timer)
ex=1 (enable crystal oscillator)
baseband bandwidth = 67kHz
dc=1 (disable signal output of CLK pin)
 
RFM01 command #2 E196 (5. wake-up timer command)
 
RFM01 command #3 CC0E (6. low duty-cycle command)
en = 0: disable low duty cycle mode
 
From RFM01 command #4 C69F (8. AFC Command)
a1 a0 rl1 rl0 st fi oe en
 1  0   0   1  1  1  1  1
a  = AFC auto-mode: keep offset when VDI hi
rl = range limit: +15/-16 (433band: 2.5kHz)
st=1 st goes hi will store offset into output register
fi=1 Enable AFC hi accuracy mode
oe=1 Enable AFC output register
en=1 Enable AFC function
 
From RFM01 command #5 C46A (9. data filter command)
al ml 1 s1 s0 f2 f1 f0
 0  1 1  0  1  0  1  0
al=0: disable clock recovery auto-lock
ml=1: enable clock recovery fast mode
s: data filter=digital filter
f: DQD threshold = 2
 
From RFM command #6 C88A
3918.5 bps
 
From RFM01 command #7 C080 (4. receiver setting command)
d1 d0 g1 g0 r2 r1 r0 en
 1  0  0  0  0  0  0  0
d: VDI source = clock recovery lock output
g: LNA gain = 0 dBm
r: DRSSI threshold = -103 dBm
en=0: disable receiver
 
GanglionTwitch has command CE88 here, my CC doesn't (11. output and FIFO mode)
 
From RFM01 command #8 CE8B (11. output and FIFO mode)
f3 f2 f1 f0 s1 s0 ff fe
 1  0  0  0  1  0  1  1
f: FIFO interrupt level = 8
s: FIFO fill start condition = reserved
ff=1: enable FIFO fill
fe=1: enable FIFO function
 
From RFM01 command #9 C081 (4. receiver setting command)
d1 d0 g1 g0 r2 r1 r0 en
 1  0  0  0  0  0  0  1
d: VDI source = clock recovery lock output
g: LNA gain = 0 dBm
r: DRSSI threshold = -103 dBm
en=1: enable receiver <--- only diff from command #7
 
From RFM01 command #10 C200 (7. Low Batt Detector & MCU Clock Div)
d2 d1 d0 t4 t3 t2 t1 t0
 0  0  0  0  0  0  0  0
d: frequency of CLK pin = 1MHz
t: low batt detection theshold = 2.2+0 V
 
From RFM01 command #11 A618 (3. frequency setting command)
Fc = 433.9MHz
 
From RFM01 command #12 CE89 (11. output and FIFO mode) (gangliontwitch has CE88)
f3 f2 f1 f0 s1 s0 ff fe
 1  0  0  0  1  0  0  1
f: FIFO interrupt level = 8
s: FIFO fill start condition = reserved
ff=0: disable FIFO fill
fe=1: enable FIFO function
 
From RFM01 command #14 CE8B (11. output and FIFO mode)
f3 f2 f1 f0 s1 s0 ff fe
 1  0  0  0  1  0  1  1
f: FIFO interrupt level = 8
s: FIFO fill start condition = reserved
ff=1: enable FIFO fill
fe=1: enable FIFO function

Data from Current Cost sensors

This is raw data from the SPI bus; it hasn't been demanchesterised. My tinkering is consistent with gangliontwitch's description of what each byte is used for.

16 bytes from IAM (180W, ID=3455):
 0 55 <--- button pressed indicator?
 1 A6 <--\
 2 6A <---}-- radio ID?
 3 AA <--/
 4 95
 5 55
 6 9A <--- watts MSB?
 7 65 <--- watts LSB?
 8 55
 9 55
10 55
11 55
12 55
13 55
14 55
15 55
 
16 bytes from IAM (0 watts, ID=3455):
 0 55
 1 A6
 2 6A
 3 AA
 4 95
 5 55
 6 55
 7 55
 8 55
 9 55
10 55
11 55
12 55
13 55
14 55
15 55
 
 
16 bytes from a different IAM (0 watts, ID=3913):
 0 55
 1 AA <--\
 2 65 <--+-- ID?
 3 96 <--/
 4 95
 5 55
 6 55
 7 55
 8 55
 9 55
10 55
11 55
12 55
13 55
14 55
15 55
 
From IAM after button has been pressed:
 0 95 <-- button pressed indicator?
 1 96
 2 6A
 3 96
 4 95
 5 55
 6 55
 7 55
 8 55
 9 55
10 55
11 55
12 55
13 55
14 55
15 55
 
From CT clamp (0 watts, ID=77)
 0 55
 1 55
 2 65
 3 A6
 4 95
 5 55
 6 55
 7 55 
 8 55
 9 55 
10 55
11 55
12 55
13 55
14 55
15 55

Comments

Not quite - the raw data from the sensor is manchester encoded, as you note. That means that each pair of bytes you've got represent one byte of gangliontwitch's description. Hence the first IAM you list has an address of 0D 7F and seems to be showing a wattage of "80B4" or about 180Watts, as the high bit seems to indicate something. gangliontwitch indicates that it indicates a current clamp, but the optical and dev boards also set the high bit of the wattage. Overall the message you received is "0D 7F 80 B4 00 00 00 00".

Incidentally, I found that the SPI data appears to be inverted - I'm guessing that the manchester data is inverted at transmission. I'm also not sure why they transmit manchester data, given that RF modules are self clocking, and hence there's no need to separate the clock signal from the data at the receiver.

While I remember, if anyone else is wanting to do the same thing to sniff SPI, you can just grab the signals from the pads on RX1 (next to the SMD RF module). They're just connected through, so I guess Current Cost were keeping their options open with SMD, DIP and populating the components on the board. U11 would have probably been a RXC101. Assuming you're numbering from right to left, with odd numbers on the lower row (towards the bottom of the board) , then the pins ppl are interested in would be:
3 - SDI
4 - SCK
5 - nSEL
6 -SDO
8 - GND
Ground can also be pulled from the VSS pin the ICSP header just below the RX1 DIP module location.

Hi Graham,

Thanks loads for the very useful comments. I haven't started trying to decode the Current Cost packet data yet but I will do soon; I think I'm close to having a working receiver using a Nanode and an RFM01.

I agree: it is odd that the data appears to be "manchesterised". I recently took apart the transmitter for a Current Cost CT clamp and it looks like TX data is arriving at the RFM02 over the RFM02's "FSK data input" pin. I need to do a bit of proper sniffing of the CT clamp to figure out what's going on. I hit a bit of a delay when I blew up my Bus Pirate and laptop by trying to sniff data from an IAM. I think the IAM and the Bus Pirate / Laptop violently disagreed about whether data ground should be connected to earth or not. I think the IAM was of the opinion that data ground should be allowed to hover at some horribly high voltage above earth. Big bang and the laptop needs a new motherboard :/. Here's a blog post about it!

Owch, sorry to hear that. I'm guessing your laptop was probably connected to the power supply at the time!
Looking at the development modules (I have a digital one), and you're correct, the TX data arrives at the FSK pin. Capturing that data is actually more difficult than I'd expected, and it seems easier to capture it at the receiver end. Having said that, I tried to send through some data using my own code on the dev module, but it's not turning up at the RX side for some reason. If I sniff the RF side, I can see it go out...

Wonder what I've got wrong there.

One of the many things that confuses me about the Current Cost EnviR RFM01 initialisation settings is command CE8B where the "FIFO fill start condition" is set to "reserved" which I assume means an undocumented synchron pattern. My assumption is that the RFM01 requires two things at the start of each packet: first a sequence of 101010... to give the RX time to lock onto the signal and then a one or two-byte "synchron" pattern. The RFM01 trims off this synchron pattern before squirting data over SPI so the only way to discover this synchron pattern is to sniff the TX data going into the RFM02 on a Current Cost transmitter (which is what I was trying to do when I blew up my laptop!). If you aren't exactly mimicking this synchron pattern then your TX data won't be recognised as a valid packet by the RX. At least, I think that's how it works! Do correct me if I'm wrong.

I may get round to sniffing the FSK data over the next couple of days. But my first EDF EcoManager Wireless Transmitter Plug has literally just been delivered so my focus is going to be on that.

I looked at the datasheet for the RXC101, which seems to be the RF receiver used in the RFM01, and the CE8B command indicates that the FIFO fill start condition is set to "Valid Data and Sync Word". It also indicates the packet structure should be a preamble of 0xAA (or 0x55) followed by 0x2DD4 as the sync word. The preamble in this case looks to be a single byte as the fast CR lock bit is set. So, yes, you're entirely correct.

I've done that, but haven't checked exactly what was received (suffice to say, the Envir hasn't displayed it as valid data). I'm going to pick up an RFM01 so I don't end up breaking the Envir, given that I'm logging from it's serial output.

The EcoManager looks to be a better bet for what you're trying to do, given it actually polls!

Great work finding the datasheet for the actual chip used on the RFM01 module; that's a massive help!

Yesterday I went through the commands issued by the EDF EcoManager to its RF module (as described by Paul). That also seems to use a sync word of 0x2DD40xCED4 explicitly sets the second byte of the sync word to the default D4 and the "FIFO and Reset Mode Command" 0xCA81 instructs the RF module to use a two-byte sync word and sets the FIFO start condition to "sync word".

I too am trying to send data to my EDF Wiresless Transmitter Plug but it's not listening.

By the way, are you padding the tail of your RF packets with anything? When I tried sending data from my RFM12b to my RFM01 I noticed that the last two bytes were being dropped during transmission so I added two bytes of 0x00 to the tail of my packets and now my RFM01 can receive the packets correctly. The RFM12b manual talks about padding the end of the packet with a CRC pattern but I haven't yet figured out if the Current Cost kit bothers with a CRC pattern (I suspect it doesn't).

Hi again!

I seem to be able to successfully transmit RF data to my EnviR from an RFM12b.

The full TX data packet I'm sending is:

00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20
55 2D D4 55 55 65 A6 95 55 55 55 55 55 55 55 55 55 55 55 40 00

  • Byte 0 is the preamble
  • Bytes 1-2 are the sync word
  • Bytes 3-18 are the payload. This is a CT clamp, RF ID=77, watts=0.
  • Bytes 19-20 are a tail which seems to be necessary to get successful transmission.

My code's on github. The function I'm using to mimick a CC CT clamp is Rfm12b::mimick_cc_ct().

Thanks,
Jack

Nice work! I found the source of my problem after breaking out a logic analyser - the PICC compiler I was using was emitting badly optimised code. Basically, instead of breaking my code down into 4 instructions, it seemed to take 12, of which 9 were gotos (2 instruction penalty each on PIC). The upshot was that my code missed some of the start of bit times (the indicator is only 1.6uS long).

Using the Current Cost digital dev board, I ended up transmitted a header of <AA><2D><D4> and then manchester encoded the message <0F><FF><80><01><00><00><00><00>. I didn't find I needed any trailing data

Playing around with the data format it seems that bit 15 of the sensor data indicates if there's data present or not - that way a three phase transmitter can indicate it's got three phases.
The first byte of address data only seems to use the lower 4 bits for address. The upper 4bits may be used for something else, but I don't know what. Setting bit 7 indicates the transmitter is in pairing mode, but setting bits 7 and 6 prevents the device from pairing. Bits 4 and 5 don't appear to have any effect.

very nice work! by the way, just out of interest, what are you working on? sound interesting!

With all this shared knowledge (mostly yours, actually!) , i wonder if we should start a "current cost rf" wiki of some sort? maybe on GitHub or something.

To be honest, I just want to know the temperature outside... and gas consumption... and water consumption... and... and... anything else I can think of really.

It would be worth having a central place for this kind of information. The fact that you've got some RFM12 code is interesting too, although I don't have any Ardunio stuff. Makes me wonder if it's worth having RFM12 code that checks the channel is clear before transmitting to try to reduce the level of lost packets. Still waiting on my RFM01 receiver!

The digital dev boards are cheap enough - around £5 each if you buy 3 of them, hence it's good to be able to run your own code on them, rather than being stuck with 0/500watts dependant on the input. I'd have preferred a transceiver, but hey, it's cheap enough and talks with what I already have.

I dropped some content onto the wiki, and created a new page for the CurrentCost protocol

brilliant! Thank you! I've been thinking that perhaps I should change the name of the GitHub project to something that includes current cost and EcoManager.

I put some example code for the digital dev board up - it can be found here. It's written for MPLABX and uses the XC8 compiler. Hopefully this will help someone!

Add new comment