3 Copyright (C) Dean Camera, 2010.
5 dean [at] fourwalledcubicle [dot] com
6 www.fourwalledcubicle.com
10 Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com)
12 Permission to use, copy, modify, distribute, and sell this
13 software and its documentation for any purpose is hereby granted
14 without fee, provided that the above copyright notice appear in
15 all copies and that both that the copyright notice and this
16 permission notice and warranty disclaimer appear in supporting
17 documentation, and that the name of the author not be used in
18 advertising or publicity pertaining to distribution of the
19 software without specific, written prior permission.
21 The author disclaim all warranties with regard to this
22 software, including all implied warranties of merchantability
23 and fitness. In no event shall the author be liable for any
24 special, indirect or consequential damages or any damages
25 whatsoever resulting from loss of use, data or profits, whether
26 in an action of contract, negligence or other tortious action,
27 arising out of or in connection with the use or performance of
33 * RFCOMM layer module. This module manages the RFCOMM layer of the
34 * stack, providing virtual serial port channels on top of the lower
38 #define INCLUDE_FROM_RFCOMM_C
41 /** 8-Bit CRC table used by the FCS field of each RFCOMM encoded frame, sourced from the ETSI TS 101 369 V7.2.0
42 * specification document, upon which the RFCOMM specification is based.
44 const uint8_t CRC8_Table
[256] PROGMEM
=
46 0x00, 0x91, 0xE3, 0x72, 0x07, 0x96, 0xE4, 0x75, 0x0E, 0x9F, 0xED, 0x7C, 0x09, 0x98, 0xEA, 0x7B,
47 0x1C, 0x8D, 0xFF, 0x6E, 0x1B, 0x8A, 0xF8, 0x69, 0x12, 0x83, 0xF1, 0x60, 0x15, 0x84, 0xF6, 0x67,
48 0x38, 0xA9, 0xDB, 0x4A, 0x3F, 0xAE, 0xDC, 0x4D, 0x36, 0xA7, 0xD5, 0x44, 0x31, 0xA0, 0xD2, 0x43,
49 0x24, 0xB5, 0xC7, 0x56, 0x23, 0xB2, 0xC0, 0x51, 0x2A, 0xBB, 0xC9, 0x58, 0x2D, 0xBC, 0xCE, 0x5F,
50 0x70, 0xE1, 0x93, 0x02, 0x77, 0xE6, 0x94, 0x05, 0x7E, 0xEF, 0x9D, 0x0C, 0x79, 0xE8, 0x9A, 0x0B,
51 0x6C, 0xFD, 0x8F, 0x1E, 0x6B, 0xFA, 0x88, 0x19, 0x62, 0xF3, 0x81, 0x10, 0x65, 0xF4, 0x86, 0x17,
52 0x48, 0xD9, 0xAB, 0x3A, 0x4F, 0xDE, 0xAC, 0x3D, 0x46, 0xD7, 0xA5, 0x34, 0x41, 0xD0, 0xA2, 0x33,
53 0x54, 0xC5, 0xB7, 0x26, 0x53, 0xC2, 0xB0, 0x21, 0x5A, 0xCB, 0xB9, 0x28, 0x5D, 0xCC, 0xBE, 0x2F,
54 0xE0, 0x71, 0x03, 0x92, 0xE7, 0x76, 0x04, 0x95, 0xEE, 0x7F, 0x0D, 0x9C, 0xE9, 0x78, 0x0A, 0x9B,
55 0xFC, 0x6D, 0x1F, 0x8E, 0xFB, 0x6A, 0x18, 0x89, 0xF2, 0x63, 0x11, 0x80, 0xF5, 0x64, 0x16, 0x87,
56 0xD8, 0x49, 0x3B, 0xAA, 0xDF, 0x4E, 0x3C, 0xAD, 0xD6, 0x47, 0x35, 0xA4, 0xD1, 0x40, 0x32, 0xA3,
57 0xC4, 0x55, 0x27, 0xB6, 0xC3, 0x52, 0x20, 0xB1, 0xCA, 0x5B, 0x29, 0xB8, 0xCD, 0x5C, 0x2E, 0xBF,
58 0x90, 0x01, 0x73, 0xE2, 0x97, 0x06, 0x74, 0xE5, 0x9E, 0x0F, 0x7D, 0xEC, 0x99, 0x08, 0x7A, 0xEB,
59 0x8C, 0x1D, 0x6F, 0xFE, 0x8B, 0x1A, 0x68, 0xF9, 0x82, 0x13, 0x61, 0xF0, 0x85, 0x14, 0x66, 0xF7,
60 0xA8, 0x39, 0x4B, 0xDA, 0xAF, 0x3E, 0x4C, 0xDD, 0xA6, 0x37, 0x45, 0xD4, 0xA1, 0x30, 0x42, 0xD3,
61 0xB4, 0x25, 0x57, 0xC6, 0xB3, 0x22, 0x50, 0xC1, 0xBA, 0x2B, 0x59, 0xC8, 0xBD, 0x2C, 0x5E, 0xCF
64 /** RFCOMM channel state structure, to retain information about each open channel in the RFCOMM multiplexer. */
65 RFCOMM_Channel_t RFCOMM_Channels
[RFCOMM_MAX_OPEN_CHANNELS
];
68 /** Initializes the RFCOMM service, ready for new connections from a SDP client. */
69 void RFCOMM_Initialize(void)
71 /* Reset the RFCOMM channel structures, to invalidate any configured RFCOMM channels */
72 for (uint8_t i
= 0; i
< RFCOMM_MAX_OPEN_CHANNELS
; i
++)
73 RFCOMM_Channels
[i
].State
= RFCOMM_Channel_Closed
;
76 /** Services all the logical RFCOMM channels on the given ACL channel, sending any RFCOMM control requests to
77 * the remote device as needed to establish new logical RFCOMM channels. This function should be called repeatedly
78 * in the main program loop when an ACL channel with an RFCOMM PSM has been established between the local and remote
81 * \param[in] ACLChannel ACL channel which has been previously opened to handle RFCOMM traffic between devices
83 void RFCOMM_ServiceChannels(Bluetooth_Channel_t
* const ACLChannel
)
85 /* Abort if the RFCOMM ACL channel is not currently open */
86 if ((ACLChannel
== NULL
) || (ACLChannel
->State
!= BT_Channel_Open
))
89 /* Loop through each of the RFCOMM channels, send any required RFCOMM control commands */
90 for (uint8_t i
= 0; i
< RFCOMM_MAX_OPEN_CHANNELS
; i
++)
92 RFCOMM_Channel_t
* RFCOMMChannel
= &RFCOMM_Channels
[i
];
94 if (RFCOMMChannel
->State
== RFCOMM_Channel_Configure
)
96 /* Check if the local signals have not yet been sent on the current channel */
97 if (!(RFCOMMChannel
->ConfigFlags
& RFCOMM_CONFIG_LOCALSIGNALSSENT
))
99 /* Indicate that the local signals have been sent, transmit them to the remote device */
100 RFCOMMChannel
->ConfigFlags
|= RFCOMM_CONFIG_LOCALSIGNALSSENT
;
101 RFCOMM_SendChannelSignals(RFCOMMChannel
, ACLChannel
);
104 /* If signals have been configured in both directions, progress to the open state */
105 if ((RFCOMMChannel
->ConfigFlags
& (RFCOMM_CONFIG_REMOTESIGNALS
| RFCOMM_CONFIG_LOCALSIGNALS
)) ==
106 (RFCOMM_CONFIG_REMOTESIGNALS
| RFCOMM_CONFIG_LOCALSIGNALS
))
108 RFCOMMChannel
->State
= RFCOMM_Channel_Open
;
109 RFCOMM_ChannelOpened(RFCOMMChannel
);
115 /** Processes an incoming RFCOMM packet on an ACL channel which has been previously opened between the local and
116 * a remote device to handle RFCOMM traffic.
118 * \param[in] Data Incoming packet data containing the RFCOMM packet
119 * \param[in] ACLChannel ACL channel the request was issued to by the remote device
121 void RFCOMM_ProcessPacket(void* Data
, Bluetooth_Channel_t
* const ACLChannel
)
123 const RFCOMM_Header_t
* FrameHeader
= (const RFCOMM_Header_t
*)Data
;
124 const uint8_t* FrameData
= (const uint8_t*)Data
+ sizeof(RFCOMM_Header_t
);
125 uint16_t FrameDataLen
= RFCOMM_GetVariableFieldValue(&FrameData
);
127 /* Decode the RFCOMM frame type from the header */
128 switch (FrameHeader
->Control
& ~FRAME_POLL_FINAL
)
130 case RFCOMM_Frame_DM
:
131 RFCOMM_ProcessDM(&FrameHeader
->Address
, ACLChannel
);
133 case RFCOMM_Frame_DISC
:
134 RFCOMM_ProcessDISC(&FrameHeader
->Address
, ACLChannel
);
136 case RFCOMM_Frame_SABM
:
137 RFCOMM_ProcessSABM(&FrameHeader
->Address
, ACLChannel
);
139 case RFCOMM_Frame_UA
:
140 RFCOMM_ProcessUA(&FrameHeader
->Address
, ACLChannel
);
142 case RFCOMM_Frame_UIH
:
143 RFCOMM_ProcessUIH(&FrameHeader
->Address
, FrameDataLen
, FrameData
, ACLChannel
);
146 BT_RFCOMM_DEBUG(1, "<< Unknown Frame Received");
151 /** Sends an RFCOMM notification to the remote device that the local terminal control signals (located in the
152 * "Local" structure of the RFCOMM channel) have changed, pushing the new signals to the remote device.
154 * \param[in] RFCOMMChannel RFCOMM logical channel whose local terminal signals have changed
155 * \param[in] ACLChannel ACL channel which has been opened to carry RFCOMM traffic between devices
157 void RFCOMM_SendChannelSignals(const RFCOMM_Channel_t
* const RFCOMMChannel
, Bluetooth_Channel_t
* const ACLChannel
)
159 BT_RFCOMM_DEBUG(1, ">> MSC Command");
160 BT_RFCOMM_DEBUG(2, "-- DLCI 0x%02X", RFCOMMChannel
->DLCI
);
164 RFCOMM_Command_t CommandHeader
;
166 RFCOMM_MSC_Parameters_t Params
;
169 MSCommand
.CommandHeader
= (RFCOMM_Command_t
){.Command
= RFCOMM_Control_ModemStatus
, .EA
= true, .CR
= true};
170 MSCommand
.Length
= (sizeof(MSCommand
.Params
) << 1) | 0x01;
171 MSCommand
.Params
.Channel
= (RFCOMM_Address_t
){.DLCI
= RFCOMMChannel
->DLCI
, .EA
= true, .CR
= true};
172 MSCommand
.Params
.Signals
= RFCOMMChannel
->Local
.Signals
;
173 MSCommand
.Params
.BreakSignal
= RFCOMMChannel
->Local
.BreakSignal
;
175 /* Send the MSC command to the remote device */
176 RFCOMM_SendFrame(RFCOMM_CONTROL_DLCI
, true, RFCOMM_Frame_UIH
, sizeof(MSCommand
), &MSCommand
, ACLChannel
);
179 /** Sends new data through an open logical RFCOMM channel. This should be used to transmit data through a
180 * RFCOMM channel once it has been opened.
182 * \param[in] DataLen Length of the RFCOMM data to send, in bytes
183 * \param[in] Data Pointer to a buffer where the data to send is located
184 * \param[in] RFCOMMChannel RFCOMM logical channel which is to be transmitted to
185 * \param[in] ACLChannel ACL channel which has been opened to carry RFCOMM traffic between devices
187 void RFCOMM_SendData(const uint16_t DataLen
, const uint8_t* Data
, const RFCOMM_Channel_t
* const RFCOMMChannel
,
188 Bluetooth_Channel_t
* const ACLChannel
)
190 if (RFCOMMChannel
->State
!= RFCOMM_Channel_Open
)
193 BT_RFCOMM_DEBUG(1, ">> UIH Frame");
194 BT_RFCOMM_DEBUG(2, "-- DLCI 0x%02X", RFCOMMChannel
->DLCI
);
196 /* Send the MSC command to the remote device */
197 RFCOMM_SendFrame(RFCOMMChannel
->DLCI
, false, RFCOMM_Frame_UIH
, DataLen
, Data
, ACLChannel
);
200 RFCOMM_Channel_t
* RFCOMM_GetFreeChannelEntry(const uint8_t DLCI
)
202 /* Find a free entry in the RFCOMM channel multiplexer state array */
203 for (uint8_t i
= 0; i
< RFCOMM_MAX_OPEN_CHANNELS
; i
++)
205 RFCOMM_Channel_t
* RFCOMMChannel
= &RFCOMM_Channels
[i
];
207 /* If the channel's state is closed, the channel state entry is free */
208 if (RFCOMMChannel
->State
== RFCOMM_Channel_Closed
)
210 RFCOMMChannel
->DLCI
= DLCI
;
211 RFCOMMChannel
->State
= RFCOMM_Channel_Configure
;
212 RFCOMMChannel
->Priority
= 7 + (RFCOMMChannel
->DLCI
& 0xF8);
213 RFCOMMChannel
->MTU
= 0xFFFF;
214 RFCOMMChannel
->Remote
.Signals
= 0 | (1 << 0);
215 RFCOMMChannel
->Remote
.BreakSignal
= 0 | (1 << 0);
216 RFCOMMChannel
->Local
.Signals
= RFCOMM_SIGNAL_RTC
| RFCOMM_SIGNAL_RTR
| RFCOMM_SIGNAL_DV
| (1 << 0);
217 RFCOMMChannel
->Local
.BreakSignal
= 0 | (1 << 0);
218 RFCOMMChannel
->ConfigFlags
= 0;
220 return RFCOMMChannel
;
227 RFCOMM_Channel_t
* RFCOMM_GetChannelData(const uint8_t DLCI
)
229 /* Search through the RFCOMM channel list, looking for the specified channel */
230 for (uint8_t i
= 0; i
< RFCOMM_MAX_OPEN_CHANNELS
; i
++)
232 RFCOMM_Channel_t
* CurrRFCOMMChannel
= &RFCOMM_Channels
[i
];
234 /* If the current non-closed channel's DLCI matches the search DLCI, return it to the caller */
235 if ((CurrRFCOMMChannel
->State
!= RFCOMM_Channel_Closed
) && (CurrRFCOMMChannel
->DLCI
== DLCI
))
236 return CurrRFCOMMChannel
;
239 /* Channel not found in the channel state table, return failure */
243 uint16_t RFCOMM_GetVariableFieldValue(const uint8_t** BufferPos
)
246 uint8_t SecondOctet
= 0;
248 FirstOctet
= **BufferPos
;
251 /* If the field size is more than a single byte, fetch the next byte in the variable length field */
252 if (!(FirstOctet
& 0x01))
254 SecondOctet
= **BufferPos
;
257 /* Discard any remaining bytes in the variable length field that won't fit in the return value */
258 while (!(**BufferPos
& 0x01))
262 /* Bitshift the bytes that comprise the variable length field so that they form a single integer */
263 return (((uint16_t)SecondOctet
<< 7) | FirstOctet
>> 1);
266 void RFCOMM_SendFrame(const uint8_t DLCI
, const bool CommandResponse
, const uint8_t Control
, const uint16_t DataLen
,
267 const void* Data
, Bluetooth_Channel_t
* const ACLChannel
)
271 RFCOMM_Header_t FrameHeader
;
272 uint8_t Size
[(DataLen
< 128) ?
1 : 2];
273 uint8_t Data
[DataLen
];
277 /* Set the frame header values to the specified address and frame type */
278 ResponsePacket
.FrameHeader
.Control
= Control
;
279 ResponsePacket
.FrameHeader
.Address
= (RFCOMM_Address_t
){.DLCI
= DLCI
, .EA
= true, .CR
= CommandResponse
};
281 /* Set the lower 7 bits of the packet length */
282 ResponsePacket
.Size
[0] = (DataLen
<< 1);
284 /* Terminate the size field if size is 7 bits or lower, otherwise set the upper 8 bits of the length */
286 ResponsePacket
.Size
[0] |= 0x01;
288 ResponsePacket
.Size
[1] = (DataLen
>> 7);
290 /* Copy over the packet data from the source buffer to the response packet buffer */
291 memcpy(ResponsePacket
.Data
, Data
, DataLen
);
293 /* Determine the length of the frame which is to be used to calculate the CRC value */
294 uint8_t CRCLength
= sizeof(ResponsePacket
.FrameHeader
);
296 /* UIH frames do not have the CRC calculated on the Size field in the response, all other frames do */
297 if ((Control
& ~FRAME_POLL_FINAL
) != RFCOMM_Frame_UIH
)
298 CRCLength
+= sizeof(ResponsePacket
.Size
);
300 /* Calculate the frame checksum from the appropriate fields */
301 ResponsePacket
.FCS
= RFCOMM_GetFCSValue(&ResponsePacket
, CRCLength
);
303 /* Send the completed response packet to the sender */
304 Bluetooth_SendPacket(&ResponsePacket
, sizeof(ResponsePacket
), ACLChannel
);
307 static uint8_t RFCOMM_GetFCSValue(const void* FrameStart
, uint8_t Length
)
311 /* Calculate new Frame CRC value via the given data bytes and the CRC table */
312 for (uint8_t i
= 0; i
< Length
; i
++)
313 FCS
= pgm_read_byte(&CRC8_Table
[FCS
^ ((const uint8_t*)FrameStart
)[i
]]);
318 static void RFCOMM_ProcessDM(const RFCOMM_Address_t
* const FrameAddress
, Bluetooth_Channel_t
* const ACLChannel
)
320 BT_RFCOMM_DEBUG(1, "<< DM Received");
321 BT_RFCOMM_DEBUG(2, "-- DLCI 0x%02X", FrameAddress
->DLCI
);
324 static void RFCOMM_ProcessDISC(const RFCOMM_Address_t
* const FrameAddress
, Bluetooth_Channel_t
* const ACLChannel
)
326 BT_RFCOMM_DEBUG(1, "<< DISC Received");
327 BT_RFCOMM_DEBUG(2, "-- DLCI 0x%02X", FrameAddress
->DLCI
);
329 RFCOMM_Channel_t
* RFCOMMChannel
= RFCOMM_GetChannelData(FrameAddress
->DLCI
);
331 /* If the requested channel is currently open, destroy it */
332 if (RFCOMMChannel
!= NULL
)
333 RFCOMMChannel
->State
= RFCOMM_Channel_Closed
;
335 BT_RFCOMM_DEBUG(1, ">> UA Sent");
336 RFCOMM_SendFrame(FrameAddress
->DLCI
, true, (RFCOMM_Frame_UA
| FRAME_POLL_FINAL
), 0, NULL
, ACLChannel
);
339 static void RFCOMM_ProcessSABM(const RFCOMM_Address_t
* const FrameAddress
, Bluetooth_Channel_t
* const ACLChannel
)
341 BT_RFCOMM_DEBUG(1, "<< SABM Received");
342 BT_RFCOMM_DEBUG(2, "-- DLCI 0x%02X", FrameAddress
->DLCI
);
344 if (FrameAddress
->DLCI
== RFCOMM_CONTROL_DLCI
)
346 BT_RFCOMM_DEBUG(1, ">> UA Sent");
348 /* Free channel found, or request was to the control channel - accept SABM by sending a UA frame */
349 RFCOMM_SendFrame(FrameAddress
->DLCI
, true, (RFCOMM_Frame_UA
| FRAME_POLL_FINAL
), 0, NULL
, ACLChannel
);
354 /* Find the existing channel's entry in the channel table */
355 RFCOMM_Channel_t
* RFCOMMChannel
= RFCOMM_GetChannelData(FrameAddress
->DLCI
);
357 /* Existing entry not found, create a new entry for the channel */
358 if (RFCOMMChannel
== NULL
)
359 RFCOMMChannel
= RFCOMM_GetFreeChannelEntry(FrameAddress
->DLCI
);
361 /* If space was found in the channel table for the new channel, ACK the request */
362 if (RFCOMMChannel
!= NULL
)
364 BT_RFCOMM_DEBUG(1, ">> UA Sent");
366 /* Free channel found, or request was to the control channel - accept SABM by sending a UA frame */
367 RFCOMM_SendFrame(FrameAddress
->DLCI
, true, (RFCOMM_Frame_UA
| FRAME_POLL_FINAL
), 0, NULL
, ACLChannel
);
371 BT_RFCOMM_DEBUG(1, ">> DM Sent");
373 /* No free channel in the multiplexer - decline the SABM by sending a DM frame */
374 RFCOMM_SendFrame(FrameAddress
->DLCI
, true, (RFCOMM_Frame_DM
| FRAME_POLL_FINAL
), 0, NULL
, ACLChannel
);
378 static void RFCOMM_ProcessUA(const RFCOMM_Address_t
* const FrameAddress
, Bluetooth_Channel_t
* const ACLChannel
)
380 BT_RFCOMM_DEBUG(1, "<< UA Received");
381 BT_RFCOMM_DEBUG(2, "-- DLCI 0x%02X", FrameAddress
->DLCI
);
384 static void RFCOMM_ProcessUIH(const RFCOMM_Address_t
* const FrameAddress
, const uint16_t FrameLength
,
385 const uint8_t* FrameData
, Bluetooth_Channel_t
* const ACLChannel
)
387 if (FrameAddress
->DLCI
== RFCOMM_CONTROL_DLCI
)
389 RFCOMM_ProcessControlCommand(FrameData
, ACLChannel
);
393 BT_RFCOMM_DEBUG(1, "<< UIH Received");
394 BT_RFCOMM_DEBUG(2, "-- DLCI 0x%02X", FrameAddress
->DLCI
);
395 BT_RFCOMM_DEBUG(2, "-- Length 0x%02X", FrameLength
);
397 RFCOMM_Channel_t
* RFCOMMChannel
= RFCOMM_GetChannelData(FrameAddress
->DLCI
);
399 if (RFCOMMChannel
!= NULL
)
400 RFCOMM_DataReceived(RFCOMMChannel
, FrameLength
, FrameData
);