Hamburger Hamburger

Hacking a Serial Bus, RS232/RS485

Conecting the ventilation Paul Thermos 200 to the RaspberryPi I had to determine how the communication between control and pannel works. Looking at the PCB of the control I figured out that the connection should be RS232. So I bought the MAX3232, cut the bus cable in the middle and connected RX, TX and Gnd to my RaspberryPI. Now I was confronted with the task how to understand an unknown serial bus. First trivial finding was, if connection to pannel is interrupted, the control will shut off the ventilation, therefore there must be continouing communication on the bus.

Using the minicom tool I easily could listen to the RX (line from control to pannel) and saw that part of the transfered information is the content of the pannel. :-) Likewise I could connect the TX (line from pannel to control) to the RX of MAX3232 and see the stream of bytes but I did not know how to synchronize with RX.

Next step was to borrow a Picoscope and to figure out that there is (e.g. if menu is displayed) some ping pong like: control says 133 1 6 and the panel replies 133 1 0 6.

Picoscope_MenuTrace.png

From the oscilloscope you can tell the length of one bit, the width of the smallest peak, to be 0.1 ms and its inverse gives you roughly 9.6 kBaud.
Converting the bytes to decimal one gets some values > 127, which could indicate the usage of a parity bit, but I found it was neither "odd" nor "even" parity. Comparing the numbers to the output of minicom (which was luckily set to 7 data bits, odd parity, LSB) I knew that the least significant bit is transferred first.
From other snapshots of the Picoscope I could tell that there are data packages transferred, but the device is not capable to log and decode longer sequences of the bus.

To get such traces I enganged Gordons wiringPI and did bus traces of RX and TX of different panel states and transitions.

To investigate this stream of bytes my first attempt was to filter for the ping-pong sequences I knew from the oscilloscope to have one such message per line to make the stream more readable. Doing this I figured out that the suspicious values > 127 seem to indicate the type of message such that doing a line break before each such value helps a lot.

<?php
$file="";
main($file);

function main($file){
  if(empty($file)){
    echo "enter file name: n";
    $line=fread(STDIN, 1024);
    $file=trim($line);
  }
  $path="./";
  $allVals = readTrace($file,$path);
  $data = filterMessages($allVals);
  saveStream($data,$file);
}

function filterMessages($allVals){
  $m=-1;
  for($n=0;$n<count($allVals);$n++){
    $word=$allVals[$n];
    /* for this bus each message starts with identifier > 127 */
    if(1.0*trim($word)>127){
      $m++;
      $data[$m]=$word;
    }else{
      $data[$m].=" ".$word;
    }
  } #n
  return $data;
}


function readTrace($fname,$path){
  /* read output from wiringPi serial trace */
  $fname=sprintf("%s%s", $path, $fname);
  if (file_exists($fname)) {
    $fid = fopen($fname, "r");
    echo "reading ".$fname."n";
    $line = fgets( $fid, 2048 ); #headerline
    $line = fgets( $fid, 2048 ); #headerline
    $line = fgets( $fid, 2048 ); #headerline
    $line = fgets( $fid, 2048 ); #headerline
    $line = fgets( $fid, 2048 ); #headerline
    $line = fgets( $fid, 2048 );
    $n=-1;
    while(!feof($fid)){
      $n++;
      $value=substr($line,3);
      $allVals[$n]=trim($value);
      $line = fgets( $fid, 2048 );
    } #n
    fclose($fid);
  }else{
    printf("FILE ".$fname." DOES NOT EXIST!N");
  }
  return $allVals;
}


function saveStream($data,$file){
  $file=substr($file,0,strpos($file,".")).".parse";
  echo "saving: ".$file."n";
  $fid=fopen($file,"w");
  for($n=0;$n<count($data);$n++){
    $string=$data[$n]."n";
    fputs($fid,$string);
  } #n
  fclose($fid);
}

These reconfigured data stream of RX, TX may easily be synchronized using meld. meld_AutoMin.jpg Since the communication for menu display is trivial I could press one of the panel buttons after the other and compare each such trace to the stationary bus communication. This way I figured out the corresponding TX:

left button133 1 5 11
middle button133 1 4 10
right button133 1 3 9
upper button133 1 1 7
lower button133 1 2 8
being alive 133 1 0 6
The difference of last two messages is 6.

If one navigates within the menue the above switching event is followed by 7 138 RX messages which are aswered by a 138 1 11 TX message each. Afterwards the usual 133 1 6 continues indipended of the menu step you are in. The 7 RX messages look as follows:

decimalASCII
138 1 0 0 0 12 69 105 110 115 116 101 108 108 117 110 103 101 110 32 56 11 87 SOH NUL line0 NUL FF E i n s t e l l u n g e n SP 8 VT W
138 1 122 2 0 127 11 17 SOH z STX NUL DEL VT DC1
138 1 0 3 0 32 78 97 99 104 116 97 98 115 101 110 107 117 110 103 32 11 5 SOH NUL line3 NUL SP N a c h t a b s e n k u n g SP VT ENQ
138 1 0 4 0 62 73 110 102 111 32 32 32 32 32 32 32 32 32 32 60 11 96 SOH NUL line4 NUL > I n f o SP SP SP SP SP SP SP SP SP SP < VT `
138 1 0 5 0 32 83 121 115 116 101 109 115 101 116 117 112 32 32 32 32 11 113 SOH NUL line5 NUL SP S y s t e m s e t u p SP SP SP SP VT q
138 1 110 5 0 111 107 126 11 97 SOH n ENQ NUL o k ~ VT a
138 1 24 7 0 22 32 32 32 32 32 21 11 0 SOH CAN BEL NUL SYN SP SP SP SP SP NAK VT NUL

Or switching from menu back to start screen the 7 RX messages say:

decimalASCII
138 1 98 2 0 12 77 101 110 20 126 11 56 138 1 b 2 0 12 M e n 20 ~ 11 8
138 1 0 2 0 80 114 111 103 114 97 109 109 58 11 23 138 1 0 2 0 P r o g r a m m : 11 23
138 1 0 3 0 76 20 102 116 117 110 103 32 58 11 119 138 1 0 3 0 L 20 f t u n g SP : 11 w
138 1 0 4 0 83 116 117 102 101 32 32 32 58 11 59 138 1 0 4 0 S t u f e SP SP SP : 11 ;
138 1 0 6 0 76 20 102 116 117 110 103 32 97 117 102 58 11 54 138 1 0 6 0 L 20 f t u n g SP a u f : 11 6
138 1 12 7 0 109 105 110 32 32 32 110 111 114 109 97 108 32 32 109 97 120 11 92 138 1 12 7 0 m i n SP SP SP n o r m a l SP SP m a x 11
138 1 0 0 1 14 83 111 32 50 53 46 48 49 46 49 53 32 32 50 51 58 50 48 32 11 114 138 1 0 0 1 14 S o SP 2 5 . 0 1 . 1 5 SP SP 2 3 : 2 0 SP 11 r

Switching to Info screen between two 133 1 6 messages five 138 messages are send containing the temperatures (T_Erdwaerme, T_Zuluft, T_Abluft):

decimalASCII
138 1 72 0 1 32 48 56 44 53 16 67 32 11 59 138 1 H 0 1 SP 0 8 , 5 16 C SP 11 ;
138 1 72 1 1 32 49 54 44 53 16 67 32 11 59 138 1 H 1 1 SP 1 6 , 5 16 C SP 11 ;
138 1 72 2 1 45 45 120 45 45 11 13 138 1 H 2 1 - - x - - 11 13
138 1 72 3 1 32 49 56 44 48 16 67 32 11 58 138 1 H 3 1 SP 1 8 , 0 16 C SP 11 :
138 1 72 4 1 45 45 120 45 45 11 15 138 1 H 4 1 - - x - - 11 15

And the standard display contains besides the 133 1 6 and 142 1 15 there are 4 different 138 messages:

decimalASCII
138 1 0 0 1 15 83 111 32 50 53 46 48 49 46 49 53 32 32 50 51 58 49 57 32 11 123 138 1 0 0 1 15 S o SP 2 5 . 0 1 . 1 5 SP SP 2 3 : 1 9 SP 11 {
138 1 54 2 0 49 11 127 138 1 6 2 0 1 11 DEL
138 1 54 4 0 109 105 110 32 32 32 11 116 138 1 6 4 0 m i n SP SP SP 11 t
138 1 54 3 0 65 117 116 111 32 32 32 11 72 138 1 6 3 0 A u t o SP SP SP 11 H

Converting the bytes to ASCII this data package looks pretty much like the modified display content.