Bluetooth for Dummies: Domesticating RFComm

Knowing RFComm port number to connect to we are fully set for our final step – to establish RFComm communication channel. Before we can send RFComm specific commands we need to establish L2CAP connection to RFComm the same way as it has been already described in ‘Establishing connection to SDP’. The only difference is that this time we need to use RFComm PSM (0x03) rather than SDP PSM. Let’s not focus our attention on L2CAP as it is now a technicality of no interest and shift our attention to RFComm specifics.

Make the same preparations and run two consoles with logging hcpdump applications and it was described in this post. Let’s analyze packet exchange immediately after establishing connection to RFComm. Here is what the first console would typically report:

< ACL data: handle 43 flags 0x02 dlen 8
L2CAP(d): cid 0x0041 len 4 [psm 3]
RFCOMM(s): SABM: cr 1 dlci 0 pf 1 ilen 0 fcs 0x1c //1-st SABM command
> ACL data: handle 43 flags 0x02 dlen 8
L2CAP(d): cid 0x0041 len 4 [psm 3]
RFCOMM(s): UA: cr 1 dlci 0 pf 1 ilen 0 fcs 0xd7 //UA response

< ACL data: handle 43 flags 0x02 dlen 18
L2CAP(d): cid 0x0041 len 14 [psm 3]
RFCOMM(s): PN CMD: cr 1 dlci 0 pf 0 ilen 10 fcs 0x70 mcc_len 8 //PM (paramater negotiation) request
dlci 32 frame_type 0 credit_flow 15 pri 7 ack_timer 0
frame_size 55 max_retrans 0 credits 7
> ACL data: handle 43 flags 0x02 dlen 18
L2CAP(d): cid 0x0041 len 14 [psm 3]
RFCOMM(s): PN RSP: cr 0 dlci 0 pf 0 ilen 10 fcs 0xaa mcc_len 8 //PM (parameter negotiation) response
dlci 32 frame_type 0 credit_flow 14 pri 0 ack_timer 0
frame_size 55 max_retrans 0 credits 7

< ACL data: handle 43 flags 0x02 dlen 8
L2CAP(d): cid 0x0041 len 4 [psm 3]
RFCOMM(s): SABM: cr 1 dlci 32 pf 1 ilen 0 fcs 0xca //2-nd SAMB command
> ACL data: handle 43 flags 0x02 dlen 8
L2CAP(d): cid 0x0041 len 4 [psm 3]
RFCOMM(s): UA: cr 1 dlci 32 pf 1 ilen 0 fcs 0x1 //UA response

< ACL data: handle 43 flags 0x02 dlen 12
L2CAP(d): cid 0x0041 len 8 [psm 3]
RFCOMM(s): MSC CMD: cr 1 dlci 0 pf 0 ilen 4 fcs 0x70 mcc_len 2 //MSC (modem status) command
dlci 32 fc 0 rtc 1 rtr 1 ic 0 dv 1 b1 1 b2 1 b3 0 len 0
> ACL data: handle 43 flags 0x02 dlen 12
L2CAP(d): cid 0x0041 len 8 [psm 3]
RFCOMM(s): MSC CMD: cr 0 dlci 0 pf 0 ilen 4 fcs 0xaa mcc_len 2 //MSC (modem status) command
dlci 32 fc 0 rtc 1 rtr 1 ic 0 dv 1 b1 1 b2 1 b3 0 len 0

< ACL data: handle 43 flags 0x02 dlen 12
L2CAP(d): cid 0x0041 len 8 [psm 3]
RFCOMM(s): MSC RSP: cr 1 dlci 0 pf 0 ilen 4 fcs 0x70 mcc_len 2 //MSC (modem status) response
dlci 32 fc 0 rtc 1 rtr 1 ic 0 dv 1 b1 1 b2 1 b3 0 len 0
> ACL data: handle 43 flags 0x02 dlen 12
L2CAP(d): cid 0x0041 len 8 [psm 3]
RFCOMM(s): MSC RSP: cr 0 dlci 0 pf 0 ilen 4 fcs 0xaa mcc_len 2 //MSC (mode status) response
dlci 32 fc 0 rtc 1 rtr 1 ic 0 dv 1 b1 1 b2 1 b3 0 len 0

< ACL data: handle 43 flags 0x02 dlen 9
L2CAP(d): cid 0x0041 len 5 [psm 3]
RFCOMM(d): UIH: cr 1 dlci 32 pf 1 ilen 0 fcs 0xc4 credits 33 //Command with credit

Let’s have a look at the same exchange in raw representation logged by the second console and try to decode it:

< 0000: 02 2a 20 08 00 04 00 41  00 03 3f 01 1c           .* ....A..?.. //1-st SABM on channel 0 (byte @ 0x9 == 0x3)
> 0000: 02 2a 20 08 00 04 00 41  00 03 73 01 d7           .* ....A..s.. //UA response

< 0000: 02 2a 20 12 00 0e 00 41  00 03 ef 15 83 11 20 f0  .* ....A...... . //PM (paramater negotiation) request
0010: 07 00 37 00 00 07 70                              ..7...p
> 0000: 02 2a 20 12 00 0e 00 41  00 01 ef 15 81 11 20 e0  .* ....A...... . //PM (parameter negotiation) response
0010: 00 00 37 00 00 07 aa                              ..7....

< 0000: 02 2a 20 08 00 04 00 41  00 83 3f 01 ca           .* ....A..?.. //2-nd SABM  on channel 0x10 (byte @ 0x9 == 0x83, channel number << 3 = 0x80)
> 0000: 02 2a 20 08 00 04 00 41  00 83 73 01 01           .* ....A..s.. //UA response

< 0000: 02 2a 20 0c 00 08 00 41  00 03 ef 09 e3 05 83 8d  .* ....A........ //MSC (modem status) command
0010: 70                                                p
> 0000: 02 2a 20 0c 00 08 00 41  00 01 ef 09 e3 05 83 8d  .* ....A........ //MSC (modem status) command
0010: aa                                                .
< 0000: 02 2a 20 0c 00 08 00 41  00 03 ef 09 e1 05 83 8d  .* ....A........ //MSC (modem status) response
0010: 70                                                p
> 0000: 02 2a 20 0c 00 08 00 41  00 01 ef 09 e1 05 83 8d  .* ....A........ //MSC (modem status) response
0010: aa                                                .

< 0000: 02 2a 20 09 00 05 00 41  00 83 ff 01 21 c4        .* ....A....!. //Command with credit on channel 0x10

...and... rock'n'roll!

Time to put everything together. Get source code from Download section below, update your installation of USB Host 2.0 library on your machine, run the provided sketch making sure that ELM327 is powered and within range of your Luminardo board. You should see something similar to the output provided below. Note, that very last reply >LM327 v1.5 is transmitted by ELM327 which means that we have established SPP communication channel! The only remaining part now is to put logic which communicates with ELM327 and renders received values on VFD panel.

Luminardo USB Host Bluetooth SPP Test
SPP Bluetooth Library Started
Enabling VBus... enabled
Bluetooth Dongle Initialized
HCI Reset complete
Write class of device
Local Bluetooth Address: 00:19:0E:12:65:6A
The name is set to: Luminardo
Pairing to 'Other' device with predefined address
Device: 40:22:11:00:69:58 has been found
Connecting to 'Other' device...
Connected to 'Other' device
Received Key Request
Bluetooth pin is set too: 1234
Pairing successful with 'Other' device
SDP Connection Request Sent
L2CAP Connection Response
SDP Connection Response
SDP Configuration Request Received
SDP Configuration Response Sent
SDP Configuration Request Sent
SDP Configuration Response Received
SDP Successfully Configured
SDP Service Search Attribute Request 1 Sent
Channel will be in the next packet
SDP Service Search Attribute Request 2 Sent
Channel found in second packet: 16
RFComm Connection Request Sent
L2CAP Connection Response
RFComm Connection Response
RFComm Configuration Request Received
RFComm Configuration Response Sent
RFComm Configuration Request Sent
RFComm Configuration Response Received
RFComm Successfully Configured
RFComm SABM Sent
Received UA RFComm Packet on channel: 00
Sent UAH RFComm Cmd BT_RFCOMM_PN_CMD (Parameter Negotiation Request) on channel: 00
Received UIH RFComm Packet on channel: 00 - BT_RFCOMM_PN_RSP (Parameter Negotiation Response)
RFComm 2-nd SABM Sent
Received UA RFComm Packet on channel: 10
Send UIH RFComm Cmd BT_RFCOMM_MSC_CMD (Modem Status Command)
Received UIH RFComm Packet on channel: 00 - BT_RFCOMM_MSC_CMD (Modem Status Cmd)
Send UIH RFComm Cmd BT_RFCOMM_MSC_RSP (Modem Status Response)
Received UIH RFComm Packet on channel: 00 - BT_RFCOMM_MSC_RSP (Modem Status Response)
RFComm Cmd with Credit Sent
Serial Bluetooth connected

>LM327 v1.5

Now the implemented functionality allows to establish SPP communication between two Arduino boards equipped with USB Host shields. It is also quite remarkable that this particular Bluetooth dongle is not functional under WinXP because it comes with Win8 driver only yet our hardware happily communicates with the dongle!

Downloads:

1. USB Host 2.0 For Arduino – Bluetooth SPPi addon;

2. UPDATE 2014.09.28: Full snapshot of USB Host 2.0 For Arduino with Bluetooth SPPi addon;