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.
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. 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 button | 133 1 5 11 |
middle button | 133 1 4 10 |
right button | 133 1 3 9 |
upper button | 133 1 1 7 |
lower button | 133 1 2 8 |
being alive | 133 1 0 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:
decimal | ASCII |
---|---|
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:
decimal | ASCII |
---|---|
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):
decimal | ASCII |
---|---|
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:
decimal | ASCII |
---|---|
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.