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 confiured RFCOMM channels */
72 for (uint8_t i
= 0; i
< RFCOMM_MAX_OPEN_CHANNELS
; i
++)
73 RFCOMM_Channels
[i
].State
= RFCOMM_Channel_Closed
;
76 void RFCOMM_ProcessPacket(void* Data
, Bluetooth_Channel_t
* const Channel
)
78 const RFCOMM_Header_t
* FrameHeader
= (const RFCOMM_Header_t
*)Data
;
79 const uint8_t* FrameData
= (const uint8_t*)Data
+ sizeof(RFCOMM_Header_t
);
80 uint16_t FrameDataLen
= RFCOMM_GetVariableFieldValue(&FrameData
);
82 /* Decode the RFCOMM frame type from the header */
83 switch (FrameHeader
->Control
& ~FRAME_POLL_FINAL
)
86 RFCOMM_ProcessDM(&FrameHeader
->Address
, Channel
);
88 case RFCOMM_Frame_DISC
:
89 RFCOMM_ProcessDISC(&FrameHeader
->Address
, Channel
);
91 case RFCOMM_Frame_SABM
:
92 RFCOMM_ProcessSABM(&FrameHeader
->Address
, Channel
);
95 RFCOMM_ProcessUA(&FrameHeader
->Address
, Channel
);
97 case RFCOMM_Frame_UIH
:
98 RFCOMM_ProcessUIH(&FrameHeader
->Address
, FrameDataLen
, FrameData
, Channel
);
101 BT_RFCOMM_DEBUG(1, "<< Unknown Frame Received");
106 RFCOMM_Channel_t
* RFCOMM_GetChannelData(const uint8_t DLCI
)
108 /* Search through the RFCOMM channel list, looking for the specified channel */
109 for (uint8_t i
= 0; i
< RFCOMM_MAX_OPEN_CHANNELS
; i
++)
111 RFCOMM_Channel_t
* CurrRFCOMMChannel
= &RFCOMM_Channels
[i
];
113 /* If the current non-closed channel's DLCI matches the search DLCI, return it to the caller */
114 if ((CurrRFCOMMChannel
->DLCI
== DLCI
) && (CurrRFCOMMChannel
->State
!= RFCOMM_Channel_Closed
))
115 return CurrRFCOMMChannel
;
118 /* Channel not found in the channel state table, return failure */
122 uint16_t RFCOMM_GetVariableFieldValue(const uint8_t** BufferPos
)
125 uint8_t SecondOctet
= 0;
127 FirstOctet
= **BufferPos
;
130 /* If the field size is more than a single byte, fetch the next byte in the variable length field */
131 if (!(FirstOctet
& 0x01))
133 SecondOctet
= **BufferPos
;
136 /* Discard any remaining bytes in the variable length field that won't fit in the return value */
137 while (!(**BufferPos
& 0x01))
141 /* Bitshift the bytes that comprise the variable length field so that they form a single integer */
142 return (((uint16_t)SecondOctet
<< 7) | FirstOctet
>> 1);
145 void RFCOMM_SendFrame(const uint8_t DLCI
, const bool CommandResponse
, const uint8_t Control
, const uint16_t DataLen
,
146 const void* Data
, Bluetooth_Channel_t
* const Channel
)
150 RFCOMM_Header_t FrameHeader
;
151 uint8_t Size
[(DataLen
< 128) ?
1 : 2];
152 uint8_t Data
[DataLen
];
156 /* Set the frame header values to the specified address and frame type */
157 ResponsePacket
.FrameHeader
.Control
= Control
;
158 ResponsePacket
.FrameHeader
.Address
= (RFCOMM_Address_t
)
161 .CR
= CommandResponse
,
165 /* Set the lower 7 bits of the packet length */
166 ResponsePacket
.Size
[0] = (DataLen
<< 1);
168 /* Terminate the size field if size is 7 bits or lower, otherwise set the upper 8 bits of the length */
170 ResponsePacket
.Size
[0] |= 0x01;
172 ResponsePacket
.Size
[1] = (DataLen
>> 7);
174 /* Copy over the packet data from the source buffer to the response packet buffer */
175 memcpy(ResponsePacket
.Data
, Data
, DataLen
);
177 /* Determine the length of the frame which is to be used to calculate the CRC value */
178 uint8_t CRCLength
= sizeof(ResponsePacket
.FrameHeader
);
180 /* UIH frames do not have the CRC calculated on the Size field in the response, all other frames do */
181 if ((Control
& ~FRAME_POLL_FINAL
) != RFCOMM_Frame_UIH
)
182 CRCLength
+= sizeof(ResponsePacket
.Size
);
184 /* Calculate the frame checksum from the appropriate fields */
185 ResponsePacket
.FCS
= RFCOMM_GetFCSValue(&ResponsePacket
, CRCLength
);
187 /* Send the completed response packet to the sender */
188 Bluetooth_SendPacket(&ResponsePacket
, sizeof(ResponsePacket
), Channel
);
191 static uint8_t RFCOMM_GetFCSValue(const void* FrameStart
, uint8_t Length
)
195 for (uint8_t i
= 0; i
< Length
; i
++)
196 FCS
= pgm_read_byte(&CRC8_Table
[FCS
^ ((uint8_t*)FrameStart
)[i
]]);
201 static void RFCOMM_ProcessDM(const RFCOMM_Address_t
* const FrameAddress
, Bluetooth_Channel_t
* const Channel
)
203 BT_RFCOMM_DEBUG(1, "<< DM Received");
204 BT_RFCOMM_DEBUG(2, "-- DLCI 0x%02X", FrameAddress
->DLCI
);
207 static void RFCOMM_ProcessDISC(const RFCOMM_Address_t
* const FrameAddress
, Bluetooth_Channel_t
* const Channel
)
209 BT_RFCOMM_DEBUG(1, "<< DISC Received");
210 BT_RFCOMM_DEBUG(2, "-- DLCI 0x%02X", FrameAddress
->DLCI
);
212 RFCOMM_Channel_t
* RFCOMMChannel
= RFCOMM_GetChannelData(FrameAddress
->DLCI
);
214 /* If the requested channel is currently open, destroy it */
215 if (RFCOMMChannel
!= NULL
)
216 RFCOMMChannel
->DLCI
= 0x00;
218 BT_RFCOMM_DEBUG(1, ">> UA Sent");
219 RFCOMM_SendFrame(FrameAddress
->DLCI
, true, (RFCOMM_Frame_UA
| FRAME_POLL_FINAL
), 0, NULL
, Channel
);
222 static void RFCOMM_ProcessSABM(const RFCOMM_Address_t
* const FrameAddress
, Bluetooth_Channel_t
* const Channel
)
224 BT_RFCOMM_DEBUG(1, "<< SABM Received");
225 BT_RFCOMM_DEBUG(2, "-- DLCI 0x%02X", FrameAddress
->DLCI
);
227 /* Find a free entry in the RFCOMM channel multiplexer state array */
228 for (uint8_t i
= 0; i
< RFCOMM_MAX_OPEN_CHANNELS
; i
++)
230 RFCOMM_Channel_t
* CurrRFCOMMChannel
= &RFCOMM_Channels
[i
];
232 /* If the channel's DLCI is zero, the channel state entry is free */
233 if (!(CurrRFCOMMChannel
->DLCI
))
235 CurrRFCOMMChannel
->DLCI
= FrameAddress
->DLCI
;
236 CurrRFCOMMChannel
->State
= RFCOMM_Channel_Open
;
237 CurrRFCOMMChannel
->Priority
= 7 + (CurrRFCOMMChannel
->DLCI
>> 3) + ((CurrRFCOMMChannel
->DLCI
>> 3) * 7);
238 CurrRFCOMMChannel
->UseUIFrames
= false;
239 CurrRFCOMMChannel
->MTU
= 0xFFFF;
240 CurrRFCOMMChannel
->Signals
= 0;
241 CurrRFCOMMChannel
->BreakSignals
= 0;
243 BT_RFCOMM_DEBUG(1, ">> UA Sent");
244 RFCOMM_SendFrame(FrameAddress
->DLCI
, true, (RFCOMM_Frame_UA
| FRAME_POLL_FINAL
), 0, NULL
, Channel
);
249 BT_RFCOMM_DEBUG(1, ">> DM Sent");
251 /* No free channel in the multiplexer - decline the SABM by sending a DM frame */
252 RFCOMM_SendFrame(FrameAddress
->DLCI
, true, (RFCOMM_Frame_DM
| FRAME_POLL_FINAL
), 0, NULL
, Channel
);
255 static void RFCOMM_ProcessUA(const RFCOMM_Address_t
* const FrameAddress
, Bluetooth_Channel_t
* const Channel
)
257 BT_RFCOMM_DEBUG(1, "<< UA Received");
258 BT_RFCOMM_DEBUG(2, "-- DLCI 0x%02X", FrameAddress
->DLCI
);
261 static void RFCOMM_ProcessUIH(const RFCOMM_Address_t
* const FrameAddress
, const uint16_t FrameLength
,
262 const uint8_t* FrameData
, Bluetooth_Channel_t
* const Channel
)
264 if (FrameAddress
->DLCI
== RFCOMM_CONTROL_DLCI
)
266 RFCOMM_ProcessControlCommand(FrameData
, Channel
);
270 BT_RFCOMM_DEBUG(1, "<< UIH Received");
271 BT_RFCOMM_DEBUG(2, "-- DLCI 0x%02X", FrameAddress
->DLCI
);
272 BT_RFCOMM_DEBUG(2, "-- Length 0x%02X", FrameLength
);
274 puts("RFCOMM Data: ");
276 for (uint8_t i
= 0; i
< FrameLength
; i
++)
277 printf("0x%02X (%c) ", FrameData
[i
], FrameData
[i
]);