Reverse engineering remote Itho CVE ECO RFT – Part 5

Two steps forward and one step back (almost like the song). That’s what my progress with reverse engineering the Itho RFT remote feels like. I’ve made some good progress in sending out the RF signal, but the ventilation box isn’t responding. The signal is more complex than I expected.

The first big step forward, since my last blog post was made because I (finally) received the CC1150 board I ordered on eBay. This is almost a drop-in replacement for the CC1101 board I blew up by applying to much voltage to it’s pins, and is actually the same chipset as the Itho remote uses. So the traces I recorded using the logical analyzer should be replay-able bit-by-bit.

CC1150

 

First I connected the board to my Arduino Pro Mini (clone) running at 3.3 volt (I’m not taking any changes with this board). Then I modified (slimmed down) the code I used during my previous test, so I could just read some default values from the CC1150-registers. I used the Arduino SPI library (not my own bit-banging code) and it worked the first time around! I could read the PARTNUM (default value 2), VERSION (default value 4) and FREQuency (default values 0x1E 0xC4 0xEC). Hurray! Now we are getting somewhere. (my code is on my GitHub repository, in the ReadRegisters example for the Itho-library I’m creating)

The next logical step was to set all recorded registers and sent the parallel data to see if the Ihto would change it’s speed. Adding the code to set the registers was easy, but the code that sends the parallel data proved to be more difficult. This code has to listen to a clock signal that the CC1150 is generating, and on each rising edge of that signal another pin should be set high or low to clock out the (parallel) data. This sounds pretty easy, but is actually harder than I expected, especially when you have to do it at pretty high speeds and with precision timing. I ended up writing 4 versions of the same code, where only one actually worked.

Version 1 used an Arduino library named PinchangeInt to listen to the falling edge of the clock-signal (on the Miso-pin) and then set the GDO1-pin in the right state. This version of the code is the cleanest solution and leaves the reading of the clock-signal to the hardware interrupt handler of the Arduino (actually the ATMEGA chip to be more precise). The problem with this code was that the Interrupt Service Routine was called again, before the previous call had finished setting the GDO1-pin. In the logical analyzer I could see that this resulted in incorrect data being transmitted to the CC1150 and thus to the Itho ventilation box.

void ISR_MISO() {
  // check if there is any more data to send
  if (dataIndexBits < dataLengthBits) { 

    byte bufferValue = dataBuffer[bufferIndex];

    if (bufferValue & mask) {
      digitalWrite(GDO0, HIGH);
    }
    else {
      digitalWrite(GDO0, LOW);
    }

    // bitmask trick came from: http://arduino.cc/en/Tutorial/BitMask
    mask >>= 1;

    if (mask == 0)
    {
      mask = 10000000; //reset mask
      bufferIndex++; //goto next byte in the data-array
    }

    dataIndexBits++; //increase bits send
  }
}

void enableMisoInterrupt() {
  pinMode(GDO0, OUTPUT); // sets the digital pin as output

  //queue the first bit, because the code below waits
  //for the first RISING edge to queue the next
  ISR_MISO(); 

  PCintPort::attachInterrupt(SPI_MISO, &ISR_MISO, FALLING);
}

Version 2 of the code did not rely on hardware interrupts but instead tried to clock out the signal at the exact time the CC1150 was expecting it (this is called Asynchronous transparent mode in the CC1150 datasheet). This meant that I would have to clock out data at exactly 38.46kHz, or one bit every 26 microseconds. For this the Arduino/ATMEGA has a feature called a timer. This is a hardware feature that you can configure to generate a signal every specified time. I used the clean Arduino library TimerOne from Paul Stoffregen to configure the timer. The timer fired, but not at the speed I configured, the fastest time it fired was every 90 microseconds. I think this isn’t a problem with the library but rather a limitation of the Arduino Pro Mini (running at 8 MHz) and not processing the timer-interrupts fast enough.

void enableMisoInterrupt() {
  pinMode(GDO0, OUTPUT); // sets the digital pin as output

  timerOne.initialize(26); //26 us = 38.46 kHz
  timerOne.attachInterrupt(ISR_MISO);
}

Version 3 of the code used the Synchronous Serial Operation mode of the CC1150 (just like version 1) but instead of using an interrupt to listen to the clock-signal I used an endless loop to read the value of the clock. This way I can detect the clock signal switching from low to high, which means the rising edge has taken place. After each rising edge (at which the CC1150 reads the data), I could change the output pin to the next value and wait for the next rising edge to pass. With this code I came a lot closer to the maximum of 26 microseconds that I had, but still not close enough (it was still over 50 microseconds).

void enableMisoInterrupt() {
  pinMode(GDO0, OUTPUT); // sets the digital pin as output

  generateFakeInterrupts();
}

void generateFakeInterrupts() {
  int previousMiso = -1;
  int currentMiso = -1;

  noInterrupts();

  //queue the first bit, because the code below waits
  //for the first RISING edge to queue the next
  ISR_MISO(); 

  do
  {
    currentMiso = digitalRead(SPI_MISO);

    if (currentMiso != previousMiso)
    {
      //wait for Miso to be high, then the RISING edge has taken place
      //and we can clock in new data
      if (currentMiso == HIGH)
      {
        ISR_MISO();
      }
      previousMiso = currentMiso;
    }
  }
  while(dataIndexBits < dataLengthBits);

  // wait for the last clock to become high
  // so the last queued bit is also sent
  while(digitalRead(SPI_MISO) == LOW);

  interrupts();
}

In version 4 the only thing I changed where the calls for digitalRead and digitalWrite. I switch them for calls to digitalReadFast and digitalWriteFast in the DigitalWriteFast-library. This sped up the code considerably, and I was actually able to respond within the required 26 microseconds.

void generateFakeInterrupts() {
  int previousMiso = -1;
  int currentMiso = -1;

  noInterrupts();

  //queue the first bit, because the code below waits
  //for the first RISING edge to queue the next
  ISR_MISO();

  do
  {
    currentMiso = digitalReadFast2(SPI_MISO);

    if (currentMiso != previousMiso)
    {
      //wait for Miso to be high, then the RISING edge has taken place
      //and we can clock in new data
      if (currentMiso == HIGH)
      {
        ISR_MISO();
      }
      previousMiso = currentMiso;
    }
  }
  while(dataIndexBits < dataLengthBits);

  // wait for the last clock to become high
  // so the last queued bit is also sent
  while(digitalReadFast2(SPI_MISO) == LOW);

  interrupts();
}

Using version 4 of the code (and some extra tweaks here and there), the logical analyzer finally showed the exact same commands being send to the CC1150 as I recorded previously from the remote control. But still the Itho ventilation box did not change it’s speed…
While I was looking at my code I left the Arduino running and transmitting a full-button-press every 5 seconds. After about 15 minutes all of the sudden I could hear the Itho ventilation box changing to full speed! Hurray! I must be on the right track, the code does actually do something, only transmitting the same signal over 300 times (20 times a minute for 15 minutes) to change the speed once isn’t exactly ‘working as expected’.

I started analyzing my previous recorded traces again and spotted a few bits that differ between trace v1 and trace v2 of the same button press (full speed). So this is the challenge I’m currently facing. I hooked up the logical analyzer to the remote control again and have recorded 8 new traces of the same button press (full speed). This shows that for the first serial transmission (part 1) only the last 2 bytes change of the 20 bytes sent (see Excel compare sheet).

v1 v2
170 170
170 170
170 170
173 173
51 51
83 83
74 74
203 203
76 76
205 205
84 84
213 213
85 85
51 51
82 82
180 180
170 170
171 171
85 77
75 77

And for the second serial transmission (still the same button press), a total of 5 bytes change (of the 50 bytes sent):

v1 v2
170 170
170 170
170 170
170 170
170 170
170 170
170 170
171 171
254 254
0 0
179 179
42 42
171 171
42 42
149 149
154 154
102 102
89 89
154 154
165 165
169 169
169 169
154 154
86 86
149 89
165 169
166 102
89 89
150 150
170 170
165 165
101 101
90 90
150 150
85 85
149 149
101 101
89 89
102 102
85 85
150 150
106 105
170 170
106 150
172 172
170 170
170 170
170 170
170 170
170 170

My first thought went out to a checksum, but the other bytes aren’t changing, so a checksum should not change either. Since the CC1150 is only a transmitter it can’t be responding to messages from the ventilation box. The only possibility that I see is that the remote stores a follow-up number in it’s EEPROM and increments this. I would have expected the numbers to change every button press, but this is where it starts to get weird. The first 8 button presses I recorded (v5 – v12) contain the same values, but the last 2 buttons presses show a different number (for part 1). It isn’t a simple 1 or 10 increment, so what logic is the remote using for these bytes?

v5 v6 v7 v8 v9 v10 v11 v12 v13 v14
170 170 170 170 170 170 170 170 170 170
170 170 170 170 170 170 170 170 170 170
170 170 170 170 170 170 170 170 170 170
173 173 173 173 173 173 173 173 173 173
51 51 51 51 51 51 51 51 51 51
83 83 83 83 83 83 83 83 83 83
74 74 74 74 74 74 74 74 74 74
203 203 203 203 203 203 203 203 203 203
76 76 76 76 76 76 76 76 76 76
205 205 205 205 205 205 205 205 205 205
84 84 84 84 84 84 84 84 84 84
213 213 213 213 213 213 213 213 213 213
85 85 85 85 85 85 85 85 85 85
51 51 51 51 51 51 51 75 75 51
82 82 82 82 82 82 82 76 76 82
180 180 180 180 180 180 180 180 180 180
170 170 170 170 170 170 170 170 170 170
171 171 171 171 171 171 171 171 171 171
85 85 85 85 85 85 85 85 85 85
53 53 53 53 53 53 53 53 75 75

 

I am going to analyze a bigger set of traces that I recorded for the same button press (full speed). Maybe with more data I can see the logic behind the few bytes that are changing.

Lessons learned:

  1. Interrupts can come too fast for a library/microcontroller to handle
  2. Direct port bit changes are faster than using Arduino’s DigitalWrite function
  3. Exact timing (microsecond precision) is hard (if not impossible on a Arduino)
  4. Serial communication is nice for debugging, but can screw up your timing when added in the wrong places
  5. Chinese probes aren’t that bendable (wire broke off at solder joint; fixed with my soldering iron)
  6. Cleaning up 4 versions of code (for commiting to GitHub) takes more time than creating them!

Other posts in this serie: Part 1Part 2, Part 3, Part 4, Part 6

Reverse engineering remote Itho CVE ECO RFT – Part 4

Reading back my previous blogpost I noticed that it has been a month since my last post! This doesn’t mean the project has stopped or that I’ve lost interest, it just means there is a lot happening in my life and it’s hard for me to find some spare time to do the work needed to advance this project.

I ended my previous post (part 3) with “let’s write some code”. What it should have read was “let’s connect the CC1101 to my Arduino”. This sound relatively easy, but it’s a step I really underestimated.

ArduinoNanoThe plan was to connect a CC1101 board I had bought on eBay and connect it to an Arduino Nano (also bought on eBay). I choose the Arduino Nano because it has an USB-connector on the board and that makes it easier to connect it to my pc and to my future IoT-hub (more on that in future posts).

CC1101-boardThe CC1101 board I ordered has 8 pins:

  1. GND
  2. VCC
  3. GDO0
  4. CSN
  5. SCK
  6. MOSI
  7. MISO/GDO1
  8. GDO2

The datasheet on eBay said the board supports a VCC voltage ranging from 1.8 to 3.6VDC. Since the Arduino Nano has a 3V3 output that connection was a no-brainer. The GND is also directly available on the Arduino Nano, no problem. Next were the SPI pins: CSN, SCK, MOSI and MISO. Turns out the Nano has dedicated pins for SPI: SS (CSN) on pin 10, SCK on pin 13, MOSI on pin 11, MISO on pin 12. Sounds simple, right? The only pins that are left to connect are GDO0 and GDO2. I choose pin 2 and pin 9, because that’s what the panStamp library seems to be using, and it’s almost the same combination I’m using (Arduino 328p with CC1101).

This is when I made my first and most crucial mistake, I got so excited that I found the panStamp library and that I had decoded enough data in my previous blogposts, that I had to try out the panStamp code. In my enthusiasm I forgot to double check everything and went ahead and turned on the Arduino Nano (connected to the CC1101) and programmed the code. After a few tweaks, the code that I wrote using the library ran, but I didn’t see the values I was expecting on my logical analyzer. That was the point where I should have realized there was something wrong, but instead I assumed that I had made a mistake in the code and started debugging. I first made the code smaller (fewer statements) so that I could focus on a few commands between the Arduino Nano and the CC1101. Every command send to the CC1101 should be acknowledged by the CC1101 and there are also commands to read back register settings from the CC1101. I thought that I would start by reading back the default values from the registers of the CC1101 after a hard reset, because then I could verify that my code was working. No matter what I tried the CC1101 didn’t return the values I was expecting. So I started using other libraries (the RFbee library is very nice and very well documented). When this library also failed to read the values I was expecting, I created a SPI library (set of methods) from scratch, even skipping the SPI functions the standard Arduino library provides. I bit-banged out the appropriate commands and still the CC1101 refused to return the defaults values.

I think at this point I had spent about 5 evenings & nights writing code and switching between different Arduino’s, when I started suspecting the CC1101 was the problem. I opened up the datasheet for the CC1101 and started reading it from the top. When I got to chapter 1 “Absolute Maximum Ratings” (page 8 of the PDF) I noticed something: “Voltage on any digital pin” “max” “3.9”. I know that I have connected the VCC of the CC1101 to the 3.3v connection of the Arduino, but how much voltage do the other pins of the Arduino Nano supply? From the Arduino website: “Each of the 14 digital pins on the Nano can be used as an input or output, using pinMode(), digitalWrite(), and digitalRead() functions. They operate at 5 volts.” Ouch! That means I have blown my CC1101 on the first power-up and just spend 5 evenings & nights searching for a bug in the code that wasn’t there.

There was nothing more I could do at this moment, but order another CC1101 chipset on eBay and wait. The next day I told this story to a colleague of mine and he pointed out another mistake I made. I bought a CC1101 board, but did not check what the other components on the board did. Turns out the components used on the board made an passive filter between the antenna and the CC1101, limiting/optimizing the signal to a frequency off 433MHz. Since I need 868 MHz, this board (and the one I just ordered) would probably have never worked on the Itho ventilation box.

I started searching for another CC1101 of CC1150 board which does support 868MHz. This is very hard/impossible to find on eBay. All manufacturers seem to optimize their boards for 433MHz. My colleague suggested I try out the Hope RF69 chips. These are very popular chips, since Moteino and JeeLabs both are using this (and similar chips). So I ordered a few (4) chips from a Dutch supplier and I am now waiting for the 2mm pin headers from China to solder wires to these chips.

Lessons learned from all this:

  1. Read the datasheet before you connect anything! Not all chips can handle more than 3.3V on their input.
  2. Carefully select the RF transmitter you need. Each board is usually optimized for a specific frequency.
  3. Not all RF transmitters use the same commands/registers, not even the ones from the same manufacturer. Again, read the datasheet!
  4. Order at least 1 component more than you need, so you can check/swap them if one is broken/blown.

Ps. Several people have asked me to share the traces from the logical analyzer I captured. I have put all files on my GitHub repository: https://github.com/xs4free/Itho-library/tree/master/Logical-Analyzer-traces
The *.logicdata files can be opened with the free Salaea Logic software. The *.csv files contain extracts of the *.logicdata files. The *.xlsx files combine all extracts and add references to the datasheet. Not all commands contain xlsx-files yet, I’m currently focusing on the ‘full’-command. Please let me know if you find these files usefull and/or want to automate the Itho yourself!

Other posts in this serie: part 1, part 2, part 3, part 5, Part 6