RS-232 Protocol decoding Puzzle - Page 1
Forum section: electronics / projects

author: sile
author_rank: Contributor
timestamp: October 19, 2012, 04:11:20 am
content: I've a digital scale i'm trying to read off of: MBSC Ultra U-2 from My Weigh. What is curious is that the output from the scale on the com port will be completely different from time to time but the actual weight is the same. I haven't been able to figure it out yet... Does anyone see what they are doing?There are 6 bytes in the middle that are all the same when it's at 0g. And then the right most digits start to go up as I add weight. But, I haven't been able to determine how to calculate it yet. For each weight I pressed the send button a bunch of times. So, each line is the bytes I would see come across for each measurement:0g02 99 B5 94 9F 9F 9F 9F 9F 9F 8F 06 2B 0302 03 2F 0E 05 05 05 05 05 05 15 00 73 0302 4C 60 41 4A 4A 4A 4A 4A 4A 5A 03 03 0302 AA 86 A7 AC AC AC AC AC AC BC 06 9B 0302 20 0C 2D 26 26 26 26 26 26 36 01 73 0302 89 A5 84 8F 8F 8F 8F 8F 8F 9F 05 AB 0302 FA D6 F7 FC FC FC FC FC FC EC 09 9B 0302 6F 43 62 69 69 69 69 69 69 79 04 03 0302 EA C6 E7 EC EC EC EC EC EC FC 09 1B 0302 4C 60 41 4A 4A 4A 4A 4A 4A 5A 03 03 0302 C6 EA CB C0 C0 C0 C0 C0 C0 D0 07 CB 0316g02 16 3A 1B 10 10 10 10 10 01 06 00 C2 0302 79 55 74 7F 7F 7F 7F 7F 6E 69 04 94 0302 D4 F8 D9 D2 D2 D2 D2 D2 C3 C4 08 46 0302 33 1F 3E 35 35 35 35 35 24 23 01 E0 0302 8C A0 81 8A 8A 8A 8A 8A 9B 9C 05 96 0302 11 3D 1C 17 17 17 17 17 06 01 00 E4 0302 90 BC 9D 96 96 96 96 96 87 80 05 DE 0302 06 2A 0B 00 00 00 00 00 11 16 00 62 0302 5D 71 50 5B 5B 5B 5B 5B 4A 4D 03 7C 0302 B7 9B BA B1 B1 B1 B1 B1 A0 A7 06 C8 0302 09 25 04 0F 0F 0F 0F 0F 1E 19 00 B4 0302 7A 56 77 7C 7C 7C 7C 7C 6D 6A 04 8A 0302 E7 CB EA E1 E1 E1 E1 E1 F0 F7 08 E8 03750g02 E3 CF EE E5 E5 E5 E5 F2 F0 F5 09 0B 0302 85 A9 88 83 83 83 83 94 96 93 05 7F 0302 2A 06 27 2C 2C 2C 2C 3B 39 3C 01 B7 0302 97 BB 9A 91 91 91 91 86 84 81 05 BB 0302 12 3E 1F 14 14 14 14 03 01 04 00 C7 0302 95 B9 98 93 93 93 93 84 86 83 05 BF 0302 EF C3 E2 E9 E9 E9 E9 FE FC F9 09 2B 0302 56 7A 5B 50 50 50 50 47 45 40 03 37 0302 A7 8B AA A1 A1 A1 A1 B6 B4 B1 06 7B 0302 FC D0 F1 FA FA FA FA ED EF EA 09 6B 0302 3D 11 30 3B 3B 3B 3B 2C 2E 2B 01 EF 0310,750g02 32 1E 3F 34 34 25 24 23 21 24 01 A8 0302 BF 93 B2 B9 B9 A8 A9 AE AC A9 06 CA 0302 2E 02 23 28 28 39 38 3F 3D 38 01 C8 0302 98 B4 95 9E 9E 8F 8E 89 8B 8E 05 DC 0302 FF D3 F2 F9 F9 E8 E9 EE EC E9 09 4A 0302 64 48 69 62 62 73 72 75 77 72 04 1C 0302 D1 FD DC D7 D7 C6 C7 C0 C2 C7 08 2E 0302 1E 32 13 18 18 09 08 0F 0D 08 00 C8 0302 70 5C 7D 76 76 67 66 61 63 66 04 2C 0302 BE 92 B3 B8 B8 A9 A8 AF AD A8 06 C8 0302 27 0B 2A 21 21 30 31 36 34 31 01 9A 0302 75 59 78 73 73 62 63 64 66 63 04 1E 0302 CB E7 C6 CD CD DC DD DA D8 DD 08 5A 0302 11 3D 1C 17 17 06 07 00 02 07 00 AE 0302 5B 77 56 5D 5D 4C 4D 4A 48 4D 03 5A 0310,020g:02 A5 89 A8 A3 A3 B2 B3 B3 B1 B3 06 98 0302 09 25 04 0F 0F 1E 1F 1F 1D 1F 00 E8 0302 6C 40 61 6A 6A 7B 7A 7A 78 7A 04 42 0302 D0 FC DD D6 D6 C7 C6 C6 C4 C6 08 32 0302 25 09 28 23 23 32 33 33 31 33 01 98 0302 81 AD 8C 87 87 96 97 97 95 97 05 B8 0302 E6 CA EB E0 E0 F1 F0 F0 F2 F0 09 0E 0302 3B 17 36 3D 3D 2C 2D 2D 2F 2D 01 E4 0302 8F A3 82 89 89 98 99 99 9B 99 05 C4 0302 E1 CD EC E7 E7 F6 F7 F7 F5 F7 09 38 0302 3B 17 36 3D 3D 2C 2D 2D 2F 2D 01 E4 03

author: Psi
author_rank: Super Contributor
timestamp: October 19, 2012, 05:13:13 am
content: That look suspiciously like the baud rate is wrong.Or maybe the serial data has been inverted (or hasn't been).UART <--> RS232 conversion involves inverting the signal. The max232 does that for you but if you try and level shift the signal yourself then you have to do it.

author: DRT
author_rank: Regular Contributor
timestamp: October 19, 2012, 09:02:50 am
content: I think the data is received correctly: The 16-bit sum of the 2nd to 11th bytes equals the 16-bit value in the 12th and 13th bytes.

author: firewalker
author_rank: Super Contributor
timestamp: October 19, 2012, 09:19:34 am
content: Does it use 7-segment display? It could send the values of the individual segments. As many DMM do.Alexander.

author: Psi
author_rank: Super Contributor
timestamp: October 19, 2012, 09:41:34 am
content: That wouldn't explain why the same weight value has so many different data payloads.

author: PA0PBZ
author_rank: Super Contributor
timestamp: October 19, 2012, 09:49:19 am
content: When I google "MBSC Ultra U-2" it has an USB port, where exactly are you taking this data from?

author: firewalker
author_rank: Super Contributor
timestamp: October 19, 2012, 09:52:23 am
content: It probably has a UART<->USB (e.g. FT232 chip) bridge.Alexander.

author: Psi
author_rank: Super Contributor
timestamp: October 19, 2012, 09:55:25 am
content: Can we get a picture of the display showing some value?The digit arrangement/grouping may give some clues.EDIT: Found this by googling, is this what it looks like?Also, have you tried different stop/start bit settings? If there are extra bits being treated as data it might do something like that.

author: HackedFridgeMagnet
author_rank: Super Contributor
timestamp: October 19, 2012, 10:13:58 am
content: Seems to have a stack of redundancy.Maybe you should post about 3 messages each from a few different weights.oops Sorry you already did that.

author: amyk
author_rank: Super Contributor
timestamp: October 19, 2012, 10:38:31 am
content: XOR the 2nd byte with the 3rd through 11th and you get...0g:Code:02 99 2c 0d 06 06 06 06 06 06 16 06 2b 0302 03 2c 0d 06 06 06 06 06 06 16 00 73 0302 4c 2c 0d 06 06 06 06 06 06 16 03 03 0302 aa 2c 0d 06 06 06 06 06 06 16 06 9b 0302 20 2c 0d 06 06 06 06 06 06 16 01 73 0302 89 2c 0d 06 06 06 06 06 06 16 05 ab 0302 fa 2c 0d 06 06 06 06 06 06 16 09 9b 0302 6f 2c 0d 06 06 06 06 06 06 16 04 03 0302 ea 2c 0d 06 06 06 06 06 06 16 09 1b 0302 4c 2c 0d 06 06 06 06 06 06 16 03 03 0302 c6 2c 0d 06 06 06 06 06 06 16 07 cb 0316g:Code:02 16 2c 0d 06 06 06 06 06 17 10 00 c2 0302 79 2c 0d 06 06 06 06 06 17 10 04 94 0302 d4 2c 0d 06 06 06 06 06 17 10 08 46 0302 33 2c 0d 06 06 06 06 06 17 10 01 e0 0302 8c 2c 0d 06 06 06 06 06 17 10 05 96 0302 11 2c 0d 06 06 06 06 06 17 10 00 e4 0302 90 2c 0d 06 06 06 06 06 17 10 05 de 0302 06 2c 0d 06 06 06 06 06 17 10 00 62 0302 5d 2c 0d 06 06 06 06 06 17 10 03 7c 0302 b7 2c 0d 06 06 06 06 06 17 10 06 c8 0302 09 2c 0d 06 06 06 06 06 17 10 00 b4 0302 7a 2c 0d 06 06 06 06 06 17 10 04 8a 0302 e7 2c 0d 06 06 06 06 06 17 10 08 e8 03750g:Code:02 e3 2c 0d 06 06 06 06 11 13 16 09 0b 0302 85 2c 0d 06 06 06 06 11 13 16 05 7f 0302 2a 2c 0d 06 06 06 06 11 13 16 01 b7 0302 97 2c 0d 06 06 06 06 11 13 16 05 bb 0302 12 2c 0d 06 06 06 06 11 13 16 00 c7 0302 95 2c 0d 06 06 06 06 11 13 16 05 bf 0302 ef 2c 0d 06 06 06 06 11 13 16 09 2b 0302 56 2c 0d 06 06 06 06 11 13 16 03 37 0302 a7 2c 0d 06 06 06 06 11 13 16 06 7b 0302 fc 2c 0d 06 06 06 06 11 13 16 09 6b 0302 3d 2c 0d 06 06 06 06 11 13 16 01 ef 0310750g:Code:02 32 2c 0d 06 06 17 16 11 13 16 01 a8 0302 bf 2c 0d 06 06 17 16 11 13 16 06 ca 0302 2e 2c 0d 06 06 17 16 11 13 16 01 c8 0302 98 2c 0d 06 06 17 16 11 13 16 05 dc 0302 ff 2c 0d 06 06 17 16 11 13 16 09 4a 0302 64 2c 0d 06 06 17 16 11 13 16 04 1c 0302 d1 2c 0d 06 06 17 16 11 13 16 08 2e 0302 1e 2c 0d 06 06 17 16 11 13 16 00 c8 0302 70 2c 0d 06 06 17 16 11 13 16 04 2c 0302 be 2c 0d 06 06 17 16 11 13 16 06 c8 0302 27 2c 0d 06 06 17 16 11 13 16 01 9a 0302 75 2c 0d 06 06 17 16 11 13 16 04 1e 0302 cb 2c 0d 06 06 17 16 11 13 16 08 5a 0302 11 2c 0d 06 06 17 16 11 13 16 00 ae 0302 5b 2c 0d 06 06 17 16 11 13 16 03 5a 0310,020g:Code:02 a5 2c 0d 06 06 17 16 16 14 16 06 98 0302 09 2c 0d 06 06 17 16 16 14 16 00 e8 0302 6c 2c 0d 06 06 17 16 16 14 16 04 42 0302 d0 2c 0d 06 06 17 16 16 14 16 08 32 0302 25 2c 0d 06 06 17 16 16 14 16 01 98 0302 81 2c 0d 06 06 17 16 16 14 16 05 b8 0302 e6 2c 0d 06 06 17 16 16 14 16 09 0e 0302 3b 2c 0d 06 06 17 16 16 14 16 01 e4 0302 8f 2c 0d 06 06 17 16 16 14 16 05 c4 0302 e1 2c 0d 06 06 17 16 16 14 16 09 38 0302 3b 2c 0d 06 06 17 16 16 14 16 01 e4 03Now we get:blank: 06 = 0000 01100: 16 = 0001 01101: 17 = 0001 01112: 14 = 0001 01005: 13 = 0001 00116: 10 = 0001 00007: 11 = 0001 0001Probably not encryption, but rather they're raw drive signals for the display. The 2nd byte seems to be the backplane and the rest are the segments (some might be inverted).

author: HackedFridgeMagnet
author_rank: Super Contributor
timestamp: October 19, 2012, 11:03:03 pm
content: Good work AmykAny idea why they would xor those bytes?Quotewhich byte is this?Also I dont think the rest of the output of your decoding are the segments whether they are inverted or not. as it there should be two bits difference between blank and one. It must be slightly more complicated mapping to the segments, I guess just done with a few gates.

author: amyk
author_rank: Super Contributor
timestamp: October 20, 2012, 05:31:21 am
content: LCDs need an AC drive signal to the crystal to prevent electrolysis. When there is a voltage difference between a segment and common electrode, the segment turns on. When there isn't, the segment is off. A xor makes the desired segments' drive signal 180 degrees out of phase with the common when it's on, and in phase when it's off.That still doesn't explain why the drive signals are being sent raw over RS-232; I had some thoughts that it might be some sort of scrambling of the data to reduce EMI but in that case it wouldn't be a simple xor like this.There might be a few more gates between the signal and the display, or I might just be xor'ing the wrong values together --- anything that's driven in phase with the common would've produced similar results. We need to see the values for the other few digits to figure that out. Also from the large picture above the display appears to contain 8 segments (middle bar is two segments?)

author: sile
author_rank: Contributor
timestamp: October 21, 2012, 02:25:59 am
content: Thanks everyone for your help!I did some more testing and I now have some code that can decode it reliably. Once I get it finished up i'll post it here as well. The plan is to get it running on a raspberry pi and upload the measurements to a web server. The interface is indeed USB, but the driver for the PL2303 USB device just creates a local COM port to use.As for the format, I still have not figured out what bytes 3 & 4 are for. They look like some kind of satus codes "2C 0D", but no matter what units I change on the scale or tare , hold, etc, those bytes stay the same. Also, as far as the individual digits I don't think it is just pulling the 7 segment bits. My main reason that in 7 bytes that are transmitted for digits, 08 is used to indicate a decimal. So, even though the decimal is a part of a single 7 segment display it takes up a whole character in the serial output. Grams is the only unit that won't ever have a decimal, so i can check and if there are no 0x08 i know it's in grams. Kind of a dumb way to do it. You would think if they are going to all the trouble to build this they would have thought to include the UNIT in that data stream... crazy. Even the dumb little application (not sure you can even call it an application), forces you to manually pick the unit.Also, the other thing I never found out was what bytes 12 & 13 are used for. They look like a checksum of some sort, but every checksum/CRC I tried never matched what they had. It's not really that import unless they contain the unit data... which I don't think they do.so, 0x06 0x06 0x06 0x11 0x08 0x12 0x13 = 7.45 on the displaylookup = {6,7,4,5,2,3,0,1,11,11,11,11,11,11,8,9};decimal = lookup[ byteVal & 0x0f];0x06 = blank0x08 = decimal0x10 = 60x11 = 70x12 = 40x13 = 50x14 = 20x15 = 30x16 = 00x17 = 10x1E = 80x1F = 9

author: sile
author_rank: Contributor
timestamp: December 15, 2012, 03:24:26 am
content: For those interested this is my full Python code running on the Raspberry Pi. Requires to "apt-get install python-serial" . This is my first Python program btw, so go easy on me. I originally wrote this in Java, but decided to re-do it and learn a new language.Code:import sys, os, serial, timedef dump_port_list():comports = []files = os.listdir("/dev/")for file in files:if file.startswith("ttyU"):comports.append("/dev/" + file)return comportsdef decodeData(data):output = []lookup = [6,7,4,5,2,3,0,1,11,11,11,11,11,11,8,9]#XOR and mask all the valuesfor x in range(4,11) :output.append( ( ord(data) ^ ord(data) ) & 0x0f )#use lookup to change to decimalvalue=0print "Converted: ",for x in range(7):digit = lookup[output]print hex(digit) + " ",value += digit * 10**(6-x)print ""return valuedef uploadData(value):url = "https://docs.google.com/spreadsheet/formResponse?formkey=dFJYcWVkWVJRZakf3JSajd0U09OYmN1UVE6MQ&ifq"url += "&backupCache=&pageNumber=0&submit=Submit&entry.1.single="url += str(value)import urllib2try:f=urllib2.urlopen(url)f.read(1000)f.close()except :print "Error! Could not upload value"def main():### Main Loopwhile True :allports = []#Loop until we find a USB Portwhile len(allports) == 0:allports = dump_port_list()time.sleep(1)print "USB Ports:" + str(allports)try:ser = serial.Serial()bad_data_timer = 0## Open serial portser.port = allportsser.baud = 9600print "Opening port: " + ser.portser.open()while ser.isOpen() and ser.readable :if ser.inWaiting() > 13 :serdata = ser.read(14)print "Serial data: " ,for x in serdata:print hex(ord(x)) ,print ""value = decodeData(serdata)print "Value: " + str(value)uploadData(value)bad_data_timer=0elif ser.inWaiting() > 0 :if bad_data_time == 0 :##Start timer for bad databad_data_timer = time.time()elif (time.time() - bad_data_timer) > 5:##It's been over 5 seconds lets dump our data stuck in the streamprint "Bad data dump: " + str(ser.read(ser.inWaiting()))bad_data_timier=0time.sleep(1)#while ser.isOpen() and ser.readableexcept:try:if ser.isOpen(): ser.close()except:print "Error closing stream"print "Error while reading "##try### End Main Loop## def main()