XPost: alt.os.linux
Hi,
I needed to connect the PC-60NW oximeter from Creative Medical
to an embedded Linux system. Unfortunately the manufacturer
does not document the Bluetooth protocol, and delivers software
only for Windows.
However in the original CD there was a documentation for
an USB-UART bridge, and that was a pointer that their oximeters
may use serial port protocol.
Indeed, after I pared th oximeter with my PC, using the sdptool
I have found, that it offers the SPP service.
I could binf rfcomm to it, but I was not able to receive any
response.
I have installed the original software on a Windows machine
and started wireshark. Unfortunately, wireshark on Windows is not
able to sniff BT communication.
I switched off the built-in BT adapter, and connected an USB BT
dongle. Then I have started recording of the USB traffic in
the Wireshark.
Indeed, in the recorded packets, I couls easily find the BT
packets with SPP protocol, and I could identify the transmitted
and received frames (S - transmitted, R - received)
The following transmitted frames were found:
S1: "\xaa\x55\x0f\x02\x83\x77"
S1b: "\xaa\x55\xf0\x02\x83\xa5"
S2: "\xaa\x55\xf0\x02\x81\x19"
S3: "\xaa\x55\x0f\x03\x84\x01\xe0"
S4: "\xaa\x55\x0f\x03\x85\x01\x24"
S5: "\xaa\x55\x0f\x03\x80\x02\x39"
There was a lot of different received frames, so I list only
a few examples:
R3: '\xaaU\x0f\x0b\x03 \x10PC-60NW\x9e' - in Python notation
it is the name and the version? of the device
byte: 1 2 3 4 5 6 7 8 9 10 11 12
R1a: "\xaa\x55\x0f\x08\x01\x60\x3f\x00\x2d\x00\x38\x8c"
R1b: "\xaa\x55\x0f\x08\x01\x5f\x47\x00\x81\x00\x18\x78"
It looks, like the above frames transmit the parameters
calculated by the device. The 6th byte transmits the saturation.
The 7th byte transmits the heart rate. At the moment
I don't know what is the meaning of the 9th byte.
The 12th byte seems to transmit the battery voltage multiplied
by 10 (0x18 - 24 - 2.4V), but the bit 0x20 seems to encode
the state of the pletysmographic curve transmission
(0x18 - battery 2.4V no transmission, 0x38 - battery 2.4V
transmission is on).
The frames below transmit the pletysmographic curve:
byte: 1 2 3 4 5 6 7 8 9 10 11
R2a: "\xaa\x55\x0f\x07\x02\x28\x26\x24\x23\x22\x96"
R2b: "\xaa\x55\x0f\x07\x02\x23\x27\x2e\x38\x44\x74"
R2c: "\xaa\x55\x0f\x07\x02\x4f\x57\x5b\x5c\x5b\x8b"
R2d: "\xaa\x55\x0f\x07\x02\x58\x54\x50\x4b\x48\x12"
Each frame:
1. begins with bytes 0xaa 0x55
2. The 3rd byte is either 0x0f or 0xf0. It seems, that the PC
sends alternately frames with 0x0f and 0xf0. I don't know
what is the real meaning of that byte.
3. The 4th byte defines the length of the frame (number of bytes
after that byte including CRC)
4. The 5th byte defines the type of the frame.
In the received frames:
0x01 - parameters and status
0x02 - pletysmographic curve
0x03 - name and version of device
The transmitted frames use both 5th and 6th byte
0x02 0x83 - sending this frame asks the device to transmit
status and parameters?
0x02 0x81 - meaning unclear
0x03 0x80 - followed by 0x02 unclear (is sent every 2 seconds
by the original Windows software)
0x03 0x84 - when followed by 0x01, switches on transmission
of parameters?
0x03 0x85 - when followed by 0x01, switches on transmission
of pletismographic curve?
The last byte is the CRC. The list of popular 8-bit CRCs may
be found at
https://users.ece.cmu.edu/~koopman/crc/crc8.html
I have created a simple Python script to test them all with one
frame:
import crcmod
for p in [0x1cf, 0x14d, 0x11d, 0x163, 0x17f, 0x107, \
0x12f, 0x131, 0x19b, 0x137, 0x1d5, 0x11b, 0x139, \
0x1d7, 0x101]:
for iv in [ -1L, 0L ]:
for rev in [ True, False]:
a=crcmod.mkCrcFun(p,iv,rev)
if a("\xaa\x55\xf0\x02\x81")==0x19:
print "full:"+hex(p)+" iv="+str(iv)+" rev="+str(rev)
if a("\xf0\x02\x81")==0x19:
print "no header:"+hex(p)+" iv="+str(iv)+" rev="+str(rev)
And I have got the following result:
full:0x131 iv=0 rev=True
So the CRC used is the DOWCRC
Finally I have prepared the simple script, that allows to connect
to PC-60NW and dump the received data.
Before using the script, you should bind the adapter (you will need
to change the MAC):
rfcomm bind 0 88:1B:96:11:4A:73 6
import serial
import time
p=serial.Serial('/dev/rfcomm0')
p.timeout=1
cm1="\xaa\x55\x0f\x02\x83\x77" # Transmit name
cm1b="\xaa\x55\xf0\x02\x83\xa5" # Transmit name
cm2="\xaa\x55\xf0\x02\x81\x19" # ???
cm3="\xaa\x55\x0f\x03\x84\x01\xe0" # Switch on params? cm4="\xaa\x55\x0f\x03\x85\x01\x24" # Switch on wave? cm6="\xaa\x55\x0f\x03\x80\x02\x39" # ? is send every 2 secs by PC soft
# Try to connect to the oximeter
while True:
p.write(cm1+cm2)
s=p.read(100)
if len(s)>0:
break
# It has responded,so switch on the wave transmission
p.write(cm3)
p.write(cm4)
p.write(cm2)
p.timeout=0.1
tlast = time.time()
frame=""
state=0 # Wait for \xaa
while True:
#Wait for the beginning of the frame
tnew=time.time()
if tnew > tlast+1:
p.write(cm1+cm6)
tlast=tnew
s=p.read()
if len(s) > 0:
#Process the character
if state==0: # wait for \xaa
if s=='\xaa':
frame += s
state=1 #Wait for \x55
else:
frame=""
state=0
elif state==1: #Wait for \x55
if s=='\x55':
frame += s
state=2 #Wait for 0xf0 or 0x0f
else:
frame=""
state=0
elif state==2: #Wait for \f0 or 0f
if (s=='\x0f') or (s=='\xf0'):
frame += s
state=3 #Wait for length
else:
frame=""
state=0
elif state==3: #Wait for length
frame += s
length=ord(s)
state=4 #Wait for data
elif state==4: #Wait for length
frame += s
length-=1
if length==0:
#Complete frame received
#We should check the CRC, but now we only dump the data
l=""
for i in frame:
l+="%2.2x:" % ord(i)
print l
frame=""
state=0 #Wait for data
Of course I do not understand all the details of the protocol.
If you manage to find more details, please publish a correction.
Good luck!
W
--- SoupGate-Win32 v1.05
* Origin: fsxNet Usenet Gateway (21:1/5)