AppConfigHeaders: Remove outdated incomplete BluetoothHost demo - updated Bluetooth stack code is in the ExplorerBot project (http://www.fourwalledcubicle.com/ExplorerBot.php).
parent
5cba3ce3a4
commit
f9fb44b01c
@ -1,194 +0,0 @@
|
|||||||
/*
|
|
||||||
LUFA Library
|
|
||||||
Copyright (C) Dean Camera, 2012.
|
|
||||||
|
|
||||||
dean [at] fourwalledcubicle [dot] com
|
|
||||||
www.lufa-lib.org
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright 2012 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
|
||||||
|
|
||||||
Permission to use, copy, modify, distribute, and sell this
|
|
||||||
software and its documentation for any purpose is hereby granted
|
|
||||||
without fee, provided that the above copyright notice appear in
|
|
||||||
all copies and that both that the copyright notice and this
|
|
||||||
permission notice and warranty disclaimer appear in supporting
|
|
||||||
documentation, and that the name of the author not be used in
|
|
||||||
advertising or publicity pertaining to distribution of the
|
|
||||||
software without specific, written prior permission.
|
|
||||||
|
|
||||||
The author disclaim all warranties with regard to this
|
|
||||||
software, including all implied warranties of merchantability
|
|
||||||
and fitness. In no event shall the author be liable for any
|
|
||||||
special, indirect or consequential damages or any damages
|
|
||||||
whatsoever resulting from loss of use, data or profits, whether
|
|
||||||
in an action of contract, negligence or other tortious action,
|
|
||||||
arising out of or in connection with the use or performance of
|
|
||||||
this software.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** \file
|
|
||||||
*
|
|
||||||
* Bluetooth stack event callback handlers. This module handles the callback events that are
|
|
||||||
* thrown from the Bluetooth stack in response to changes in the connection and channel
|
|
||||||
* states.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "BluetoothEvents.h"
|
|
||||||
|
|
||||||
/** Pointer to the opened Bluetooth ACL channel structure for RFCOMM, used to send and receive data between the
|
|
||||||
* local and remote device once a RFCOMM channel has been opened.
|
|
||||||
*/
|
|
||||||
Bluetooth_Channel_t* SerialChannel_ACL = NULL;
|
|
||||||
|
|
||||||
/** Pointer to the opened RFCOMM logical channel between local and remote device, once a RFCOMM ACL channel has been
|
|
||||||
* negotiated and a logical RFCOMM channel requested.
|
|
||||||
*/
|
|
||||||
RFCOMM_Channel_t* SerialChannel_RFCOMM = NULL;
|
|
||||||
|
|
||||||
/** Bluetooth stack callback event for when the Bluetooth stack has fully initialized using the attached
|
|
||||||
* Bluetooth dongle.
|
|
||||||
*/
|
|
||||||
void Bluetooth_StackInitialized(void)
|
|
||||||
{
|
|
||||||
printf_P(PSTR("Stack initialized with local address %02X:%02X:%02X:%02X:%02X:%02X.\r\n"),
|
|
||||||
Bluetooth_State.LocalBDADDR[5], Bluetooth_State.LocalBDADDR[4], Bluetooth_State.LocalBDADDR[3],
|
|
||||||
Bluetooth_State.LocalBDADDR[2], Bluetooth_State.LocalBDADDR[1], Bluetooth_State.LocalBDADDR[0]);
|
|
||||||
|
|
||||||
/* Reinitialize the services placed on top of the Bluetooth stack ready for new connections */
|
|
||||||
RFCOMM_Initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Bluetooth stack callback event for a Bluetooth connection request. When this callback fires, the
|
|
||||||
* user application must indicate if the connection is to be allowed or rejected.
|
|
||||||
*
|
|
||||||
* \param[in] RemoteAddress Bluetooth address of the remote device attempting the connection
|
|
||||||
*
|
|
||||||
* \return Boolean true to accept the connection, false to reject it
|
|
||||||
*/
|
|
||||||
bool Bluetooth_ConnectionRequest(const uint8_t* RemoteAddress)
|
|
||||||
{
|
|
||||||
printf_P(PSTR("Connection Request from Device %02X:%02X:%02X:%02X:%02X:%02X.\r\n"),
|
|
||||||
RemoteAddress[5], RemoteAddress[4], RemoteAddress[3], RemoteAddress[2],
|
|
||||||
RemoteAddress[1], RemoteAddress[0]);
|
|
||||||
|
|
||||||
/* Always accept connections from remote devices */
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Bluetooth stack callback event for a completed Bluetooth connection. When this callback is made,
|
|
||||||
* the connection information can be accessed through the global \ref Bluetooth_Connection structure.
|
|
||||||
*/
|
|
||||||
void Bluetooth_ConnectionComplete(void)
|
|
||||||
{
|
|
||||||
printf_P(PSTR("Connection Complete to Device %02X:%02X:%02X:%02X:%02X:%02X.\r\n"),
|
|
||||||
Bluetooth_Connection.RemoteAddress[5], Bluetooth_Connection.RemoteAddress[4],
|
|
||||||
Bluetooth_Connection.RemoteAddress[3], Bluetooth_Connection.RemoteAddress[2],
|
|
||||||
Bluetooth_Connection.RemoteAddress[1], Bluetooth_Connection.RemoteAddress[0]);
|
|
||||||
|
|
||||||
LEDs_SetAllLEDs(LEDMASK_USB_BUSY);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Bluetooth stack callback event for a completed Bluetooth disconnection. When this callback is made,
|
|
||||||
* the connection information in the global \ref Bluetooth_Connection structure is invalidated with the
|
|
||||||
* exception of the RemoteAddress element, which can be used to determine the address of the device that
|
|
||||||
* was disconnected.
|
|
||||||
*/
|
|
||||||
void Bluetooth_DisconnectionComplete(void)
|
|
||||||
{
|
|
||||||
printf_P(PSTR("Disconnection Complete to Device %02X:%02X:%02X:%02X:%02X:%02X.\r\n"),
|
|
||||||
Bluetooth_Connection.RemoteAddress[5], Bluetooth_Connection.RemoteAddress[4],
|
|
||||||
Bluetooth_Connection.RemoteAddress[3], Bluetooth_Connection.RemoteAddress[2],
|
|
||||||
Bluetooth_Connection.RemoteAddress[1], Bluetooth_Connection.RemoteAddress[0]);
|
|
||||||
|
|
||||||
LEDs_SetAllLEDs(LEDMASK_USB_READY);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Bluetooth stack callback event for a Bluetooth ACL Channel connection request. When is callback fires,
|
|
||||||
* the user application must indicate if the channel connection should be rejected or not, based on the
|
|
||||||
* protocol (PSM) value of the requested channel.
|
|
||||||
*
|
|
||||||
* \param[in] PSM Protocol PSM value for the requested channel
|
|
||||||
*
|
|
||||||
* \return Boolean true to accept the channel connection request, false to reject it
|
|
||||||
*/
|
|
||||||
bool Bluetooth_ChannelConnectionRequest(const uint16_t PSM)
|
|
||||||
{
|
|
||||||
/* Only accept connections for channels that will be used for RFCOMM or SDP data */
|
|
||||||
return ((PSM == CHANNEL_PSM_RFCOMM) || (PSM == CHANNEL_PSM_SDP));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Bluetooth stack callback event for when a Bluetooth ACL channel has been fully created and configured,
|
|
||||||
* either at the request of the local device, or the remote device.
|
|
||||||
*
|
|
||||||
* \param[in] ACLChannel Bluetooth ACL data channel information structure for the channel that can now be used
|
|
||||||
*/
|
|
||||||
void Bluetooth_ChannelOpened(Bluetooth_Channel_t* const ACLChannel)
|
|
||||||
{
|
|
||||||
/* Save the RFCOMM channel for later use when we want to send RFCOMM data */
|
|
||||||
if (ACLChannel->PSM == CHANNEL_PSM_RFCOMM)
|
|
||||||
SerialChannel_ACL = ACLChannel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Bluetooth stack callback event for a non-signal ACL packet reception. This callback fires once a connection
|
|
||||||
* to a remote Bluetooth device has been made, and the remote device has sent a non-signaling ACL packet.
|
|
||||||
*
|
|
||||||
* \param[in] Data Pointer to a buffer where the received data is stored
|
|
||||||
* \param[in] DataLen Length of the packet data, in bytes
|
|
||||||
* \param[in] ACLChannel Bluetooth ACL data channel information structure for the packet's destination channel
|
|
||||||
*/
|
|
||||||
void Bluetooth_PacketReceived(void* Data, uint16_t DataLen, Bluetooth_Channel_t* const ACLChannel)
|
|
||||||
{
|
|
||||||
/* Run the correct packet handler based on the received packet's PSM, which indicates the service being carried */
|
|
||||||
switch (ACLChannel->PSM)
|
|
||||||
{
|
|
||||||
case CHANNEL_PSM_SDP:
|
|
||||||
/* Service Discovery Protocol packet */
|
|
||||||
SDP_ProcessPacket(Data, ACLChannel);
|
|
||||||
break;
|
|
||||||
case CHANNEL_PSM_RFCOMM:
|
|
||||||
/* RFCOMM (Serial Port) Protocol packet */
|
|
||||||
RFCOMM_ProcessPacket(Data, ACLChannel);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** RFCOMM layer callback for event for when a RFCOMM logical channel has been fully opened and configured between
|
|
||||||
* the local and remote device. Once open, this RFCOMM channel can be read from and written to freely until is it
|
|
||||||
* closed by either end.
|
|
||||||
*
|
|
||||||
* \param[in] RFCOMMChannel RFCOMM channel that was opened
|
|
||||||
*/
|
|
||||||
void RFCOMM_ChannelOpened(RFCOMM_Channel_t* const RFCOMMChannel)
|
|
||||||
{
|
|
||||||
/* Save the serial port RFCOMM logical channel for later use */
|
|
||||||
SerialChannel_RFCOMM = RFCOMMChannel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** RFCOMM layer callback event for when a packet is received on an open RFCOMM channel.
|
|
||||||
*
|
|
||||||
* \param[in] ACLChannel RFCOMM ACL channel that the data was directed to
|
|
||||||
* \param[in] DataLen Length of the received data, in bytes
|
|
||||||
* \param[in] Data Pointer to a buffer where the received data is stored
|
|
||||||
*/
|
|
||||||
void RFCOMM_DataReceived(RFCOMM_Channel_t* const ACLChannel, uint16_t DataLen, const uint8_t* Data)
|
|
||||||
{
|
|
||||||
/* Write the received bytes to the serial port */
|
|
||||||
for (uint8_t i = 0; i < DataLen; i++)
|
|
||||||
putchar(Data[i]);
|
|
||||||
|
|
||||||
/* Echo the data back to the sending device */
|
|
||||||
RFCOMM_SendData(DataLen, Data, SerialChannel_RFCOMM, SerialChannel_ACL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** RFCOMM layer callback event for when the remote device has updated the channel terminal control signals
|
|
||||||
* for a particular RFCOMM channel.
|
|
||||||
*
|
|
||||||
* \param[in] RFCOMMChannel RFCOMM logical channel whose signals were altered
|
|
||||||
*/
|
|
||||||
void RFCOMM_ChannelSignalsReceived(RFCOMM_Channel_t* const RFCOMMChannel)
|
|
||||||
{
|
|
||||||
// Currently do nothing in response to the remote device sending new terminal control signals
|
|
||||||
}
|
|
||||||
|
|
@ -1,72 +0,0 @@
|
|||||||
/*
|
|
||||||
LUFA Library
|
|
||||||
Copyright (C) Dean Camera, 2012.
|
|
||||||
|
|
||||||
dean [at] fourwalledcubicle [dot] com
|
|
||||||
www.lufa-lib.org
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright 2012 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
|
||||||
|
|
||||||
Permission to use, copy, modify, distribute, and sell this
|
|
||||||
software and its documentation for any purpose is hereby granted
|
|
||||||
without fee, provided that the above copyright notice appear in
|
|
||||||
all copies and that both that the copyright notice and this
|
|
||||||
permission notice and warranty disclaimer appear in supporting
|
|
||||||
documentation, and that the name of the author not be used in
|
|
||||||
advertising or publicity pertaining to distribution of the
|
|
||||||
software without specific, written prior permission.
|
|
||||||
|
|
||||||
The author disclaim all warranties with regard to this
|
|
||||||
software, including all implied warranties of merchantability
|
|
||||||
and fitness. In no event shall the author be liable for any
|
|
||||||
special, indirect or consequential damages or any damages
|
|
||||||
whatsoever resulting from loss of use, data or profits, whether
|
|
||||||
in an action of contract, negligence or other tortious action,
|
|
||||||
arising out of or in connection with the use or performance of
|
|
||||||
this software.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** \file
|
|
||||||
*
|
|
||||||
* Header file for BluetoothEvents.c.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _BLUETOOTH_EVENTS_H_
|
|
||||||
#define _BLUETOOTH_EVENTS_H_
|
|
||||||
|
|
||||||
/* Includes: */
|
|
||||||
#include <avr/io.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include "BluetoothHost.h"
|
|
||||||
#include "Lib/BluetoothStack.h"
|
|
||||||
#include "Lib/SDP.h"
|
|
||||||
#include "Lib/RFCOMM.h"
|
|
||||||
|
|
||||||
#include <LUFA/Drivers/Peripheral/Serial.h>
|
|
||||||
#include <LUFA/Drivers/Board/LEDs.h>
|
|
||||||
|
|
||||||
/* Macros: */
|
|
||||||
/** LED mask for the library LED driver, to indicate that the USB interface is not ready. */
|
|
||||||
#define LEDMASK_USB_NOTREADY LEDS_LED1
|
|
||||||
|
|
||||||
/** LED mask for the library LED driver, to indicate that the USB interface is enumerating. */
|
|
||||||
#define LEDMASK_USB_ENUMERATING (LEDS_LED2 | LEDS_LED3)
|
|
||||||
|
|
||||||
/** LED mask for the library LED driver, to indicate that the USB interface is ready. */
|
|
||||||
#define LEDMASK_USB_READY (LEDS_LED2 | LEDS_LED4)
|
|
||||||
|
|
||||||
/** LED mask for the library LED driver, to indicate that an error has occurred in the USB interface. */
|
|
||||||
#define LEDMASK_USB_ERROR (LEDS_LED1 | LEDS_LED3)
|
|
||||||
|
|
||||||
/** LED mask for the library LED driver, to indicate that the USB interface is busy. */
|
|
||||||
#define LEDMASK_USB_BUSY LEDS_LED2
|
|
||||||
|
|
||||||
/* External Variables: */
|
|
||||||
extern Bluetooth_Channel_t* SerialChannel_ACL;
|
|
||||||
extern RFCOMM_Channel_t* SerialChannel_RFCOMM;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,187 +0,0 @@
|
|||||||
/*
|
|
||||||
LUFA Library
|
|
||||||
Copyright (C) Dean Camera, 2012.
|
|
||||||
|
|
||||||
dean [at] fourwalledcubicle [dot] com
|
|
||||||
www.lufa-lib.org
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright 2012 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
|
||||||
|
|
||||||
Permission to use, copy, modify, distribute, and sell this
|
|
||||||
software and its documentation for any purpose is hereby granted
|
|
||||||
without fee, provided that the above copyright notice appear in
|
|
||||||
all copies and that both that the copyright notice and this
|
|
||||||
permission notice and warranty disclaimer appear in supporting
|
|
||||||
documentation, and that the name of the author not be used in
|
|
||||||
advertising or publicity pertaining to distribution of the
|
|
||||||
software without specific, written prior permission.
|
|
||||||
|
|
||||||
The author disclaim all warranties with regard to this
|
|
||||||
software, including all implied warranties of merchantability
|
|
||||||
and fitness. In no event shall the author be liable for any
|
|
||||||
special, indirect or consequential damages or any damages
|
|
||||||
whatsoever resulting from loss of use, data or profits, whether
|
|
||||||
in an action of contract, negligence or other tortious action,
|
|
||||||
arising out of or in connection with the use or performance of
|
|
||||||
this software.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** \file
|
|
||||||
*
|
|
||||||
* Main source file for the BluetoothHost demo. This file contains the main tasks of
|
|
||||||
* the demo and is responsible for the initial application hardware configuration.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "BluetoothHost.h"
|
|
||||||
|
|
||||||
/** Bluetooth configuration structure. This structure configures the Bluetooth stack's user alterable settings. */
|
|
||||||
Bluetooth_Device_t Bluetooth_DeviceConfiguration =
|
|
||||||
{
|
|
||||||
Class: (DEVICE_CLASS_SERVICE_CAPTURING | DEVICE_CLASS_MAJOR_COMPUTER | DEVICE_CLASS_MINOR_COMPUTER_PALM),
|
|
||||||
PINCode: "0000",
|
|
||||||
Name: "LUFA Bluetooth Demo"
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Main program entry point. This routine configures the hardware required by the application, then
|
|
||||||
* enters a loop to run the application tasks in sequence.
|
|
||||||
*/
|
|
||||||
int main(void)
|
|
||||||
{
|
|
||||||
SetupHardware();
|
|
||||||
|
|
||||||
puts_P(PSTR(ESC_FG_CYAN "Bluetooth Host Demo running.\r\n" ESC_FG_WHITE));
|
|
||||||
|
|
||||||
LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
|
|
||||||
sei();
|
|
||||||
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
RFCOMM_ServiceChannels(SerialChannel_ACL);
|
|
||||||
|
|
||||||
Bluetooth_Stack_USBTask();
|
|
||||||
USB_USBTask();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Configures the board hardware and chip peripherals for the demo's functionality. */
|
|
||||||
void SetupHardware(void)
|
|
||||||
{
|
|
||||||
/* Disable watchdog if enabled by bootloader/fuses */
|
|
||||||
MCUSR &= ~(1 << WDRF);
|
|
||||||
wdt_disable();
|
|
||||||
|
|
||||||
/* Disable clock division */
|
|
||||||
clock_prescale_set(clock_div_1);
|
|
||||||
|
|
||||||
/* Hardware Initialization */
|
|
||||||
Serial_Init(9600, false);
|
|
||||||
LEDs_Init();
|
|
||||||
USB_Init();
|
|
||||||
|
|
||||||
/* Create a stdio stream for the serial port for stdin and stdout */
|
|
||||||
Serial_CreateStream(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Event handler for the USB_DeviceAttached event. This indicates that a device has been attached to the host, and
|
|
||||||
* starts the library USB task to begin the enumeration and USB management process.
|
|
||||||
*/
|
|
||||||
void EVENT_USB_Host_DeviceAttached(void)
|
|
||||||
{
|
|
||||||
puts_P(PSTR(ESC_FG_GREEN "Device Attached.\r\n" ESC_FG_WHITE));
|
|
||||||
LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Event handler for the USB_DeviceUnattached event. This indicates that a device has been removed from the host, and
|
|
||||||
* stops the library USB task management process.
|
|
||||||
*/
|
|
||||||
void EVENT_USB_Host_DeviceUnattached(void)
|
|
||||||
{
|
|
||||||
puts_P(PSTR(ESC_FG_GREEN "\r\nDevice Unattached.\r\n" ESC_FG_WHITE));
|
|
||||||
LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Event handler for the USB_DeviceEnumerationComplete event. This indicates that a device has been successfully
|
|
||||||
* enumerated by the host and is now ready to be used by the application.
|
|
||||||
*/
|
|
||||||
void EVENT_USB_Host_DeviceEnumerationComplete(void)
|
|
||||||
{
|
|
||||||
puts_P(PSTR("Getting Device Data.\r\n"));
|
|
||||||
|
|
||||||
uint8_t ErrorCode;
|
|
||||||
|
|
||||||
/* Get and process the configuration descriptor data */
|
|
||||||
if ((ErrorCode = ProcessDeviceDescriptor()) != SuccessfulDeviceRead)
|
|
||||||
{
|
|
||||||
if (ErrorCode == DevControlError)
|
|
||||||
puts_P(PSTR(ESC_FG_RED "Control Error (Get Device).\r\n"));
|
|
||||||
else
|
|
||||||
puts_P(PSTR(ESC_FG_RED "Invalid Device.\r\n"));
|
|
||||||
|
|
||||||
printf_P(PSTR(" -- Error Code: %d\r\n" ESC_FG_WHITE), ErrorCode);
|
|
||||||
|
|
||||||
LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
puts_P(PSTR("Getting Config Data.\r\n"));
|
|
||||||
|
|
||||||
/* Get and process the configuration descriptor data */
|
|
||||||
if ((ErrorCode = ProcessConfigurationDescriptor()) != SuccessfulConfigRead)
|
|
||||||
{
|
|
||||||
if (ErrorCode == ControlError)
|
|
||||||
puts_P(PSTR(ESC_FG_RED "Control Error (Get Configuration).\r\n"));
|
|
||||||
else
|
|
||||||
puts_P(PSTR(ESC_FG_RED "Invalid Device.\r\n"));
|
|
||||||
|
|
||||||
printf_P(PSTR(" -- Error Code: %d\r\n" ESC_FG_WHITE), ErrorCode);
|
|
||||||
|
|
||||||
LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set the device configuration to the first configuration (rarely do devices use multiple configurations) */
|
|
||||||
if ((ErrorCode = USB_Host_SetDeviceConfiguration(1)) != HOST_SENDCONTROL_Successful)
|
|
||||||
{
|
|
||||||
printf_P(PSTR(ESC_FG_RED "Control Error (Set Configuration).\r\n"
|
|
||||||
" -- Error Code: %d\r\n" ESC_FG_WHITE), ErrorCode);
|
|
||||||
|
|
||||||
LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
puts_P(PSTR("Bluetooth Dongle Enumerated.\r\n"));
|
|
||||||
|
|
||||||
/* Initialize the Bluetooth stack */
|
|
||||||
Bluetooth_Stack_Init();
|
|
||||||
|
|
||||||
LEDs_SetAllLEDs(LEDMASK_USB_READY);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Event handler for the USB_HostError event. This indicates that a hardware error occurred while in host mode. */
|
|
||||||
void EVENT_USB_Host_HostError(const uint8_t ErrorCode)
|
|
||||||
{
|
|
||||||
USB_Disable();
|
|
||||||
|
|
||||||
printf_P(PSTR(ESC_FG_RED "Host Mode Error\r\n"
|
|
||||||
" -- Error Code %d\r\n" ESC_FG_WHITE), ErrorCode);
|
|
||||||
|
|
||||||
LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
|
|
||||||
for(;;);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Event handler for the USB_DeviceEnumerationFailed event. This indicates that a problem occurred while
|
|
||||||
* enumerating an attached USB device.
|
|
||||||
*/
|
|
||||||
void EVENT_USB_Host_DeviceEnumerationFailed(const uint8_t ErrorCode,
|
|
||||||
const uint8_t SubErrorCode)
|
|
||||||
{
|
|
||||||
printf_P(PSTR(ESC_FG_RED "Dev Enum Error\r\n"
|
|
||||||
" -- Error Code %d\r\n"
|
|
||||||
" -- Sub Error Code %d\r\n"
|
|
||||||
" -- In State %d\r\n" ESC_FG_WHITE), ErrorCode, SubErrorCode, USB_HostState);
|
|
||||||
|
|
||||||
LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
|
|
||||||
}
|
|
||||||
|
|
@ -1,86 +0,0 @@
|
|||||||
/*
|
|
||||||
LUFA Library
|
|
||||||
Copyright (C) Dean Camera, 2012.
|
|
||||||
|
|
||||||
dean [at] fourwalledcubicle [dot] com
|
|
||||||
www.lufa-lib.org
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright 2012 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
|
||||||
|
|
||||||
Permission to use, copy, modify, distribute, and sell this
|
|
||||||
software and its documentation for any purpose is hereby granted
|
|
||||||
without fee, provided that the above copyright notice appear in
|
|
||||||
all copies and that both that the copyright notice and this
|
|
||||||
permission notice and warranty disclaimer appear in supporting
|
|
||||||
documentation, and that the name of the author not be used in
|
|
||||||
advertising or publicity pertaining to distribution of the
|
|
||||||
software without specific, written prior permission.
|
|
||||||
|
|
||||||
The author disclaim all warranties with regard to this
|
|
||||||
software, including all implied warranties of merchantability
|
|
||||||
and fitness. In no event shall the author be liable for any
|
|
||||||
special, indirect or consequential damages or any damages
|
|
||||||
whatsoever resulting from loss of use, data or profits, whether
|
|
||||||
in an action of contract, negligence or other tortious action,
|
|
||||||
arising out of or in connection with the use or performance of
|
|
||||||
this software.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** \file
|
|
||||||
*
|
|
||||||
* Header file for BluetoothHost.c.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _BLUETOOTH_HOST_H_
|
|
||||||
#define _BLUETOOTH_HOST_H_
|
|
||||||
|
|
||||||
/* Includes: */
|
|
||||||
#include <avr/io.h>
|
|
||||||
#include <avr/wdt.h>
|
|
||||||
#include <avr/pgmspace.h>
|
|
||||||
#include <avr/power.h>
|
|
||||||
#include <avr/interrupt.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include "BluetoothEvents.h"
|
|
||||||
#include "DeviceDescriptor.h"
|
|
||||||
#include "ConfigDescriptor.h"
|
|
||||||
#include "Lib/BluetoothStack.h"
|
|
||||||
|
|
||||||
#include <LUFA/Version.h>
|
|
||||||
#include <LUFA/Drivers/Misc/TerminalCodes.h>
|
|
||||||
#include <LUFA/Drivers/USB/USB.h>
|
|
||||||
#include <LUFA/Drivers/Peripheral/Serial.h>
|
|
||||||
#include <LUFA/Drivers/Board/LEDs.h>
|
|
||||||
|
|
||||||
/* Macros: */
|
|
||||||
/** LED mask for the library LED driver, to indicate that the USB interface is not ready. */
|
|
||||||
#define LEDMASK_USB_NOTREADY LEDS_LED1
|
|
||||||
|
|
||||||
/** LED mask for the library LED driver, to indicate that the USB interface is enumerating. */
|
|
||||||
#define LEDMASK_USB_ENUMERATING (LEDS_LED2 | LEDS_LED3)
|
|
||||||
|
|
||||||
/** LED mask for the library LED driver, to indicate that the USB interface is ready. */
|
|
||||||
#define LEDMASK_USB_READY (LEDS_LED2 | LEDS_LED4)
|
|
||||||
|
|
||||||
/** LED mask for the library LED driver, to indicate that an error has occurred in the USB interface. */
|
|
||||||
#define LEDMASK_USB_ERROR (LEDS_LED1 | LEDS_LED3)
|
|
||||||
|
|
||||||
/** LED mask for the library LED driver, to indicate that the USB interface is busy. */
|
|
||||||
#define LEDMASK_USB_BUSY LEDS_LED2
|
|
||||||
|
|
||||||
/* Event Handlers: */
|
|
||||||
void EVENT_USB_Host_DeviceAttached(void);
|
|
||||||
void EVENT_USB_Host_DeviceUnattached(void);
|
|
||||||
void EVENT_USB_Host_DeviceEnumerationComplete(void);
|
|
||||||
void EVENT_USB_Host_HostError(const uint8_t ErrorCode);
|
|
||||||
void EVENT_USB_Host_DeviceEnumerationFailed(const uint8_t ErrorCode,
|
|
||||||
const uint8_t SubErrorCode);
|
|
||||||
|
|
||||||
/* Function Prototypes: */
|
|
||||||
void SetupHardware(void);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,142 +0,0 @@
|
|||||||
/*
|
|
||||||
LUFA Library
|
|
||||||
Copyright (C) Dean Camera, 2012.
|
|
||||||
|
|
||||||
dean [at] fourwalledcubicle [dot] com
|
|
||||||
www.lufa-lib.org
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright 2012 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
|
||||||
|
|
||||||
Permission to use, copy, modify, distribute, and sell this
|
|
||||||
software and its documentation for any purpose is hereby granted
|
|
||||||
without fee, provided that the above copyright notice appear in
|
|
||||||
all copies and that both that the copyright notice and this
|
|
||||||
permission notice and warranty disclaimer appear in supporting
|
|
||||||
documentation, and that the name of the author not be used in
|
|
||||||
advertising or publicity pertaining to distribution of the
|
|
||||||
software without specific, written prior permission.
|
|
||||||
|
|
||||||
The author disclaim all warranties with regard to this
|
|
||||||
software, including all implied warranties of merchantability
|
|
||||||
and fitness. In no event shall the author be liable for any
|
|
||||||
special, indirect or consequential damages or any damages
|
|
||||||
whatsoever resulting from loss of use, data or profits, whether
|
|
||||||
in an action of contract, negligence or other tortious action,
|
|
||||||
arising out of or in connection with the use or performance of
|
|
||||||
this software.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** \file
|
|
||||||
*
|
|
||||||
* USB Device Configuration Descriptor processing routines, to determine the correct pipe configurations
|
|
||||||
* needed to communication with an attached USB device. Descriptors are special computer-readable structures
|
|
||||||
* which the host requests upon device enumeration, to determine the device's capabilities and functions.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "ConfigDescriptor.h"
|
|
||||||
|
|
||||||
/** Reads and processes an attached device's descriptors, to determine compatibility and pipe configurations. This
|
|
||||||
* routine will read in the entire configuration descriptor, and configure the hosts pipes to correctly communicate
|
|
||||||
* with compatible devices.
|
|
||||||
*
|
|
||||||
* This routine searches for a BT interface descriptor containing bulk IN and OUT data endpoints.
|
|
||||||
*
|
|
||||||
* \return An error code from the \ref BluetoothHost_GetConfigDescriptorDataCodes_t enum.
|
|
||||||
*/
|
|
||||||
uint8_t ProcessConfigurationDescriptor(void)
|
|
||||||
{
|
|
||||||
uint8_t ConfigDescriptorData[512];
|
|
||||||
void* CurrConfigLocation = ConfigDescriptorData;
|
|
||||||
uint16_t CurrConfigBytesRem;
|
|
||||||
|
|
||||||
USB_Descriptor_Endpoint_t* DataINEndpoint = NULL;
|
|
||||||
USB_Descriptor_Endpoint_t* DataOUTEndpoint = NULL;
|
|
||||||
USB_Descriptor_Endpoint_t* EventsEndpoint = NULL;
|
|
||||||
|
|
||||||
/* Retrieve the entire configuration descriptor into the allocated buffer */
|
|
||||||
switch (USB_Host_GetDeviceConfigDescriptor(1, &CurrConfigBytesRem, ConfigDescriptorData, sizeof(ConfigDescriptorData)))
|
|
||||||
{
|
|
||||||
case HOST_GETCONFIG_Successful:
|
|
||||||
break;
|
|
||||||
case HOST_GETCONFIG_InvalidData:
|
|
||||||
return InvalidConfigDataReturned;
|
|
||||||
case HOST_GETCONFIG_BuffOverflow:
|
|
||||||
return DescriptorTooLarge;
|
|
||||||
default:
|
|
||||||
return DevControlError;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The Bluetooth USB transport addendum mandates that the data (not streaming voice) endpoints
|
|
||||||
be in the first interface descriptor (interface 0) */
|
|
||||||
USB_GetNextDescriptorOfType(&CurrConfigBytesRem, &CurrConfigLocation, DTYPE_Interface);
|
|
||||||
|
|
||||||
/* Ensure that an interface was found, and the end of the descriptor was not reached */
|
|
||||||
if (!(CurrConfigBytesRem))
|
|
||||||
return NoCompatibleInterfaceFound;
|
|
||||||
|
|
||||||
while (!(DataINEndpoint) || !(DataOUTEndpoint))
|
|
||||||
{
|
|
||||||
/* Get the next Bluetooth interface's data endpoint descriptor */
|
|
||||||
if (USB_GetNextDescriptorComp(&CurrConfigBytesRem, &CurrConfigLocation,
|
|
||||||
DComp_NextInterfaceBluetoothDataEndpoint) != DESCRIPTOR_SEARCH_COMP_Found)
|
|
||||||
{
|
|
||||||
/* Data endpoints not found within the first bluetooth device interface, error out */
|
|
||||||
return NoCompatibleInterfaceFound;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Retrieve the endpoint address from the endpoint descriptor */
|
|
||||||
USB_Descriptor_Endpoint_t* EndpointData = DESCRIPTOR_PCAST(CurrConfigLocation, USB_Descriptor_Endpoint_t);
|
|
||||||
|
|
||||||
/* If the endpoint is a IN type endpoint */
|
|
||||||
if ((EndpointData->EndpointAddress & ENDPOINT_DIR_MASK) == ENDPOINT_DIR_IN)
|
|
||||||
{
|
|
||||||
/* Check if the found endpoint is a interrupt or bulk type descriptor */
|
|
||||||
if ((EndpointData->Attributes & EP_TYPE_MASK) == EP_TYPE_INTERRUPT)
|
|
||||||
EventsEndpoint = EndpointData;
|
|
||||||
else
|
|
||||||
DataINEndpoint = EndpointData;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DataOUTEndpoint = EndpointData;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Configure the Bluetooth data IN pipe */
|
|
||||||
Pipe_ConfigurePipe(BLUETOOTH_DATA_IN_PIPE, EP_TYPE_BULK, DataINEndpoint->EndpointAddress, DataINEndpoint->EndpointSize, 1);
|
|
||||||
|
|
||||||
/* Configure the Bluetooth data OUT pipe */
|
|
||||||
Pipe_ConfigurePipe(BLUETOOTH_DATA_OUT_PIPE, EP_TYPE_BULK, DataOUTEndpoint->EndpointAddress, DataOUTEndpoint->EndpointSize, 1);
|
|
||||||
|
|
||||||
/* Configure the Bluetooth events pipe */
|
|
||||||
Pipe_ConfigurePipe(BLUETOOTH_EVENTS_PIPE, EP_TYPE_INTERRUPT, EventsEndpoint->EndpointAddress, EventsEndpoint->EndpointSize, 1);
|
|
||||||
Pipe_SetInterruptPeriod(EventsEndpoint->PollingIntervalMS);
|
|
||||||
|
|
||||||
/* Valid data found, return success */
|
|
||||||
return SuccessfulConfigRead;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Descriptor comparator function. This comparator function is can be called while processing an attached USB device's
|
|
||||||
* configuration descriptor, to search for a specific sub descriptor. It can also be used to abort the configuration
|
|
||||||
* descriptor processing if an incompatible descriptor configuration is found.
|
|
||||||
*
|
|
||||||
* This comparator searches for the next Endpoint descriptor inside the current interface descriptor, aborting the
|
|
||||||
* search if another interface descriptor is found before the required endpoint.
|
|
||||||
*
|
|
||||||
* \return A value from the DSEARCH_Return_ErrorCodes_t enum
|
|
||||||
*/
|
|
||||||
uint8_t DComp_NextInterfaceBluetoothDataEndpoint(void* CurrentDescriptor)
|
|
||||||
{
|
|
||||||
USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);
|
|
||||||
|
|
||||||
/* Determine the type of the current descriptor */
|
|
||||||
if (Header->Type == DTYPE_Endpoint)
|
|
||||||
return DESCRIPTOR_SEARCH_Found;
|
|
||||||
else if (Header->Type == DTYPE_Interface)
|
|
||||||
return DESCRIPTOR_SEARCH_Fail;
|
|
||||||
else
|
|
||||||
return DESCRIPTOR_SEARCH_NotFound;
|
|
||||||
}
|
|
||||||
|
|
@ -1,64 +0,0 @@
|
|||||||
/*
|
|
||||||
LUFA Library
|
|
||||||
Copyright (C) Dean Camera, 2012.
|
|
||||||
|
|
||||||
dean [at] fourwalledcubicle [dot] com
|
|
||||||
www.lufa-lib.org
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright 2012 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
|
||||||
|
|
||||||
Permission to use, copy, modify, distribute, and sell this
|
|
||||||
software and its documentation for any purpose is hereby granted
|
|
||||||
without fee, provided that the above copyright notice appear in
|
|
||||||
all copies and that both that the copyright notice and this
|
|
||||||
permission notice and warranty disclaimer appear in supporting
|
|
||||||
documentation, and that the name of the author not be used in
|
|
||||||
advertising or publicity pertaining to distribution of the
|
|
||||||
software without specific, written prior permission.
|
|
||||||
|
|
||||||
The author disclaim all warranties with regard to this
|
|
||||||
software, including all implied warranties of merchantability
|
|
||||||
and fitness. In no event shall the author be liable for any
|
|
||||||
special, indirect or consequential damages or any damages
|
|
||||||
whatsoever resulting from loss of use, data or profits, whether
|
|
||||||
in an action of contract, negligence or other tortious action,
|
|
||||||
arising out of or in connection with the use or performance of
|
|
||||||
this software.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** \file
|
|
||||||
*
|
|
||||||
* Header file for ConfigDescriptor.c.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _CONFIGDESCRIPTOR_H_
|
|
||||||
#define _CONFIGDESCRIPTOR_H_
|
|
||||||
|
|
||||||
/* Includes: */
|
|
||||||
#include <LUFA/Drivers/USB/USB.h>
|
|
||||||
|
|
||||||
/* Macros: */
|
|
||||||
#define BLUETOOTH_DATA_IN_PIPE (PIPE_DIR_IN | 1)
|
|
||||||
#define BLUETOOTH_DATA_OUT_PIPE (PIPE_DIR_OUT | 2)
|
|
||||||
#define BLUETOOTH_EVENTS_PIPE (PIPE_DIR_IN | 3)
|
|
||||||
|
|
||||||
/* Enums: */
|
|
||||||
/** Enum for the possible return codes of the \ref ProcessConfigurationDescriptor() function. */
|
|
||||||
enum BluetoothHost_GetConfigDescriptorDataCodes_t
|
|
||||||
{
|
|
||||||
SuccessfulConfigRead = 0, /**< Configuration Descriptor was processed successfully */
|
|
||||||
DevControlError = 1, /**< A control request to the device failed to complete successfully */
|
|
||||||
DescriptorTooLarge = 2, /**< The device's Configuration Descriptor is too large to process */
|
|
||||||
InvalidConfigDataReturned = 3, /**< The device returned an invalid Configuration Descriptor */
|
|
||||||
NoCompatibleInterfaceFound = 4, /**< A compatible interface with the required endpoints was not found */
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Function Prototypes: */
|
|
||||||
uint8_t ProcessConfigurationDescriptor(void);
|
|
||||||
|
|
||||||
uint8_t DComp_NextInterfaceBluetoothDataEndpoint(void* CurrentDescriptor);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,68 +0,0 @@
|
|||||||
/*
|
|
||||||
LUFA Library
|
|
||||||
Copyright (C) Dean Camera, 2012.
|
|
||||||
|
|
||||||
dean [at] fourwalledcubicle [dot] com
|
|
||||||
www.lufa-lib.org
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright 2012 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
|
||||||
|
|
||||||
Permission to use, copy, modify, distribute, and sell this
|
|
||||||
software and its documentation for any purpose is hereby granted
|
|
||||||
without fee, provided that the above copyright notice appear in
|
|
||||||
all copies and that both that the copyright notice and this
|
|
||||||
permission notice and warranty disclaimer appear in supporting
|
|
||||||
documentation, and that the name of the author not be used in
|
|
||||||
advertising or publicity pertaining to distribution of the
|
|
||||||
software without specific, written prior permission.
|
|
||||||
|
|
||||||
The author disclaim all warranties with regard to this
|
|
||||||
software, including all implied warranties of merchantability
|
|
||||||
and fitness. In no event shall the author be liable for any
|
|
||||||
special, indirect or consequential damages or any damages
|
|
||||||
whatsoever resulting from loss of use, data or profits, whether
|
|
||||||
in an action of contract, negligence or other tortious action,
|
|
||||||
arising out of or in connection with the use or performance of
|
|
||||||
this software.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** \file
|
|
||||||
*
|
|
||||||
* USB Device Descriptor processing routines, to determine the overall device parameters. Descriptors are special
|
|
||||||
* computer-readable structures which the host requests upon device enumeration, to determine information about
|
|
||||||
* the attached device.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "DeviceDescriptor.h"
|
|
||||||
|
|
||||||
/** Reads and processes an attached device's Device Descriptor, to determine compatibility
|
|
||||||
*
|
|
||||||
* This routine checks to ensure that the attached device's class codes match those for Bluetooth devices.
|
|
||||||
*
|
|
||||||
* \return An error code from the \ref BluetoothHost_GetDeviceDescriptorDataCodes_t enum.
|
|
||||||
*/
|
|
||||||
uint8_t ProcessDeviceDescriptor(void)
|
|
||||||
{
|
|
||||||
USB_Descriptor_Device_t DeviceDescriptor;
|
|
||||||
|
|
||||||
/* Send the request to retrieve the device descriptor */
|
|
||||||
if (USB_Host_GetDeviceDescriptor(&DeviceDescriptor) != HOST_SENDCONTROL_Successful)
|
|
||||||
return DevControlError;
|
|
||||||
|
|
||||||
/* Validate returned data - ensure the returned data is a device descriptor */
|
|
||||||
if (DeviceDescriptor.Header.Type != DTYPE_Device)
|
|
||||||
return InvalidDeviceDataReturned;
|
|
||||||
|
|
||||||
/* Validate returned device Class, SubClass and Protocol values against the Bluetooth spec values */
|
|
||||||
if ((DeviceDescriptor.Class != BLUETOOTH_DEVICE_CLASS) ||
|
|
||||||
(DeviceDescriptor.SubClass != BLUETOOTH_DEVICE_SUBCLASS) ||
|
|
||||||
(DeviceDescriptor.Protocol != BLUETOOTH_DEVICE_PROTOCOL))
|
|
||||||
{
|
|
||||||
return IncorrectBTDevice;
|
|
||||||
}
|
|
||||||
|
|
||||||
return SuccessfulDeviceRead;
|
|
||||||
}
|
|
||||||
|
|
@ -1,68 +0,0 @@
|
|||||||
/*
|
|
||||||
LUFA Library
|
|
||||||
Copyright (C) Dean Camera, 2012.
|
|
||||||
|
|
||||||
dean [at] fourwalledcubicle [dot] com
|
|
||||||
www.lufa-lib.org
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright 2012 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
|
||||||
|
|
||||||
Permission to use, copy, modify, distribute, and sell this
|
|
||||||
software and its documentation for any purpose is hereby granted
|
|
||||||
without fee, provided that the above copyright notice appear in
|
|
||||||
all copies and that both that the copyright notice and this
|
|
||||||
permission notice and warranty disclaimer appear in supporting
|
|
||||||
documentation, and that the name of the author not be used in
|
|
||||||
advertising or publicity pertaining to distribution of the
|
|
||||||
software without specific, written prior permission.
|
|
||||||
|
|
||||||
The author disclaim all warranties with regard to this
|
|
||||||
software, including all implied warranties of merchantability
|
|
||||||
and fitness. In no event shall the author be liable for any
|
|
||||||
special, indirect or consequential damages or any damages
|
|
||||||
whatsoever resulting from loss of use, data or profits, whether
|
|
||||||
in an action of contract, negligence or other tortious action,
|
|
||||||
arising out of or in connection with the use or performance of
|
|
||||||
this software.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** \file
|
|
||||||
*
|
|
||||||
* Header file for DeviceDescriptor.c.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _DEVICEDESCRIPTOR_H_
|
|
||||||
#define _DEVICEDESCRIPTOR_H_
|
|
||||||
|
|
||||||
/* Includes: */
|
|
||||||
#include <LUFA/Drivers/USB/USB.h>
|
|
||||||
|
|
||||||
#include "BluetoothHost.h"
|
|
||||||
|
|
||||||
/* Macros: */
|
|
||||||
/** Device Class value for the Bluetooth Device class. */
|
|
||||||
#define BLUETOOTH_DEVICE_CLASS 0xE0
|
|
||||||
|
|
||||||
/** Device Subclass value for the Bluetooth Device class. */
|
|
||||||
#define BLUETOOTH_DEVICE_SUBCLASS 0x01
|
|
||||||
|
|
||||||
/** Device Protocol value for the Bluetooth Device class. */
|
|
||||||
#define BLUETOOTH_DEVICE_PROTOCOL 0x01
|
|
||||||
|
|
||||||
/* Enums: */
|
|
||||||
/** Enum for the possible return codes of the \ref ProcessDeviceDescriptor() function. */
|
|
||||||
enum BluetoothHost_GetDeviceDescriptorDataCodes_t
|
|
||||||
{
|
|
||||||
SuccessfulDeviceRead = 0, /**< Device Descriptor was processed successfully */
|
|
||||||
ControlError = 1, /**< A control request to the device failed to complete successfully */
|
|
||||||
InvalidDeviceDataReturned = 2, /**< The device returned an invalid Device Descriptor */
|
|
||||||
IncorrectBTDevice = 3, /**< The attached device is not a Bluetooth class device */
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Function Prototypes: */
|
|
||||||
uint8_t ProcessDeviceDescriptor(void);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,1814 +0,0 @@
|
|||||||
# Doxyfile 1.8.0
|
|
||||||
|
|
||||||
# This file describes the settings to be used by the documentation system
|
|
||||||
# doxygen (www.doxygen.org) for a project.
|
|
||||||
#
|
|
||||||
# All text after a hash (#) is considered a comment and will be ignored.
|
|
||||||
# The format is:
|
|
||||||
# TAG = value [value, ...]
|
|
||||||
# For lists items can also be appended using:
|
|
||||||
# TAG += value [value, ...]
|
|
||||||
# Values that contain spaces should be placed between quotes (" ").
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------
|
|
||||||
# Project related configuration options
|
|
||||||
#---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
# This tag specifies the encoding used for all characters in the config file
|
|
||||||
# that follow. The default is UTF-8 which is also the encoding used for all
|
|
||||||
# text before the first occurrence of this tag. Doxygen uses libiconv (or the
|
|
||||||
# iconv built into libc) for the transcoding. See
|
|
||||||
# http://www.gnu.org/software/libiconv for the list of possible encodings.
|
|
||||||
|
|
||||||
DOXYFILE_ENCODING = UTF-8
|
|
||||||
|
|
||||||
# The PROJECT_NAME tag is a single word (or sequence of words) that should
|
|
||||||
# identify the project. Note that if you do not use Doxywizard you need
|
|
||||||
# to put quotes around the project name if it contains spaces.
|
|
||||||
|
|
||||||
PROJECT_NAME = "LUFA Library - Bluetooth Host Demo"
|
|
||||||
|
|
||||||
# The PROJECT_NUMBER tag can be used to enter a project or revision number.
|
|
||||||
# This could be handy for archiving the generated documentation or
|
|
||||||
# if some version control system is used.
|
|
||||||
|
|
||||||
PROJECT_NUMBER = 0.0.0
|
|
||||||
|
|
||||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
|
||||||
# for a project that appears at the top of each page and should give viewer
|
|
||||||
# a quick idea about the purpose of the project. Keep the description short.
|
|
||||||
|
|
||||||
PROJECT_BRIEF =
|
|
||||||
|
|
||||||
# With the PROJECT_LOGO tag one can specify an logo or icon that is
|
|
||||||
# included in the documentation. The maximum height of the logo should not
|
|
||||||
# exceed 55 pixels and the maximum width should not exceed 200 pixels.
|
|
||||||
# Doxygen will copy the logo to the output directory.
|
|
||||||
|
|
||||||
PROJECT_LOGO =
|
|
||||||
|
|
||||||
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
|
|
||||||
# base path where the generated documentation will be put.
|
|
||||||
# If a relative path is entered, it will be relative to the location
|
|
||||||
# where doxygen was started. If left blank the current directory will be used.
|
|
||||||
|
|
||||||
OUTPUT_DIRECTORY = ./Documentation/
|
|
||||||
|
|
||||||
# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
|
|
||||||
# 4096 sub-directories (in 2 levels) under the output directory of each output
|
|
||||||
# format and will distribute the generated files over these directories.
|
|
||||||
# Enabling this option can be useful when feeding doxygen a huge amount of
|
|
||||||
# source files, where putting all generated files in the same directory would
|
|
||||||
# otherwise cause performance problems for the file system.
|
|
||||||
|
|
||||||
CREATE_SUBDIRS = NO
|
|
||||||
|
|
||||||
# The OUTPUT_LANGUAGE tag is used to specify the language in which all
|
|
||||||
# documentation generated by doxygen is written. Doxygen will use this
|
|
||||||
# information to generate all constant output in the proper language.
|
|
||||||
# The default language is English, other supported languages are:
|
|
||||||
# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
|
|
||||||
# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
|
|
||||||
# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
|
|
||||||
# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
|
|
||||||
# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak,
|
|
||||||
# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
|
|
||||||
|
|
||||||
OUTPUT_LANGUAGE = English
|
|
||||||
|
|
||||||
# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
|
|
||||||
# include brief member descriptions after the members that are listed in
|
|
||||||
# the file and class documentation (similar to JavaDoc).
|
|
||||||
# Set to NO to disable this.
|
|
||||||
|
|
||||||
BRIEF_MEMBER_DESC = YES
|
|
||||||
|
|
||||||
# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
|
|
||||||
# the brief description of a member or function before the detailed description.
|
|
||||||
# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
|
|
||||||
# brief descriptions will be completely suppressed.
|
|
||||||
|
|
||||||
REPEAT_BRIEF = YES
|
|
||||||
|
|
||||||
# This tag implements a quasi-intelligent brief description abbreviator
|
|
||||||
# that is used to form the text in various listings. Each string
|
|
||||||
# in this list, if found as the leading text of the brief description, will be
|
|
||||||
# stripped from the text and the result after processing the whole list, is
|
|
||||||
# used as the annotated text. Otherwise, the brief description is used as-is.
|
|
||||||
# If left blank, the following values are used ("$name" is automatically
|
|
||||||
# replaced with the name of the entity): "The $name class" "The $name widget"
|
|
||||||
# "The $name file" "is" "provides" "specifies" "contains"
|
|
||||||
# "represents" "a" "an" "the"
|
|
||||||
|
|
||||||
ABBREVIATE_BRIEF = "The $name class" \
|
|
||||||
"The $name widget" \
|
|
||||||
"The $name file" \
|
|
||||||
is \
|
|
||||||
provides \
|
|
||||||
specifies \
|
|
||||||
contains \
|
|
||||||
represents \
|
|
||||||
a \
|
|
||||||
an \
|
|
||||||
the
|
|
||||||
|
|
||||||
# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
|
|
||||||
# Doxygen will generate a detailed section even if there is only a brief
|
|
||||||
# description.
|
|
||||||
|
|
||||||
ALWAYS_DETAILED_SEC = NO
|
|
||||||
|
|
||||||
# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
|
|
||||||
# inherited members of a class in the documentation of that class as if those
|
|
||||||
# members were ordinary class members. Constructors, destructors and assignment
|
|
||||||
# operators of the base classes will not be shown.
|
|
||||||
|
|
||||||
INLINE_INHERITED_MEMB = NO
|
|
||||||
|
|
||||||
# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
|
|
||||||
# path before files name in the file list and in the header files. If set
|
|
||||||
# to NO the shortest path that makes the file name unique will be used.
|
|
||||||
|
|
||||||
FULL_PATH_NAMES = YES
|
|
||||||
|
|
||||||
# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
|
|
||||||
# can be used to strip a user-defined part of the path. Stripping is
|
|
||||||
# only done if one of the specified strings matches the left-hand part of
|
|
||||||
# the path. The tag can be used to show relative paths in the file list.
|
|
||||||
# If left blank the directory from which doxygen is run is used as the
|
|
||||||
# path to strip.
|
|
||||||
|
|
||||||
STRIP_FROM_PATH =
|
|
||||||
|
|
||||||
# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
|
|
||||||
# the path mentioned in the documentation of a class, which tells
|
|
||||||
# the reader which header file to include in order to use a class.
|
|
||||||
# If left blank only the name of the header file containing the class
|
|
||||||
# definition is used. Otherwise one should specify the include paths that
|
|
||||||
# are normally passed to the compiler using the -I flag.
|
|
||||||
|
|
||||||
STRIP_FROM_INC_PATH =
|
|
||||||
|
|
||||||
# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
|
|
||||||
# (but less readable) file names. This can be useful if your file system
|
|
||||||
# doesn't support long names like on DOS, Mac, or CD-ROM.
|
|
||||||
|
|
||||||
SHORT_NAMES = YES
|
|
||||||
|
|
||||||
# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
|
|
||||||
# will interpret the first line (until the first dot) of a JavaDoc-style
|
|
||||||
# comment as the brief description. If set to NO, the JavaDoc
|
|
||||||
# comments will behave just like regular Qt-style comments
|
|
||||||
# (thus requiring an explicit @brief command for a brief description.)
|
|
||||||
|
|
||||||
JAVADOC_AUTOBRIEF = NO
|
|
||||||
|
|
||||||
# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
|
|
||||||
# interpret the first line (until the first dot) of a Qt-style
|
|
||||||
# comment as the brief description. If set to NO, the comments
|
|
||||||
# will behave just like regular Qt-style comments (thus requiring
|
|
||||||
# an explicit \brief command for a brief description.)
|
|
||||||
|
|
||||||
QT_AUTOBRIEF = NO
|
|
||||||
|
|
||||||
# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
|
|
||||||
# treat a multi-line C++ special comment block (i.e. a block of //! or ///
|
|
||||||
# comments) as a brief description. This used to be the default behaviour.
|
|
||||||
# The new default is to treat a multi-line C++ comment block as a detailed
|
|
||||||
# description. Set this tag to YES if you prefer the old behaviour instead.
|
|
||||||
|
|
||||||
MULTILINE_CPP_IS_BRIEF = NO
|
|
||||||
|
|
||||||
# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
|
|
||||||
# member inherits the documentation from any documented member that it
|
|
||||||
# re-implements.
|
|
||||||
|
|
||||||
INHERIT_DOCS = YES
|
|
||||||
|
|
||||||
# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
|
|
||||||
# a new page for each member. If set to NO, the documentation of a member will
|
|
||||||
# be part of the file/class/namespace that contains it.
|
|
||||||
|
|
||||||
SEPARATE_MEMBER_PAGES = NO
|
|
||||||
|
|
||||||
# The TAB_SIZE tag can be used to set the number of spaces in a tab.
|
|
||||||
# Doxygen uses this value to replace tabs by spaces in code fragments.
|
|
||||||
|
|
||||||
TAB_SIZE = 4
|
|
||||||
|
|
||||||
# This tag can be used to specify a number of aliases that acts
|
|
||||||
# as commands in the documentation. An alias has the form "name=value".
|
|
||||||
# For example adding "sideeffect=\par Side Effects:\n" will allow you to
|
|
||||||
# put the command \sideeffect (or @sideeffect) in the documentation, which
|
|
||||||
# will result in a user-defined paragraph with heading "Side Effects:".
|
|
||||||
# You can put \n's in the value part of an alias to insert newlines.
|
|
||||||
|
|
||||||
ALIASES =
|
|
||||||
|
|
||||||
# This tag can be used to specify a number of word-keyword mappings (TCL only).
|
|
||||||
# A mapping has the form "name=value". For example adding
|
|
||||||
# "class=itcl::class" will allow you to use the command class in the
|
|
||||||
# itcl::class meaning.
|
|
||||||
|
|
||||||
TCL_SUBST =
|
|
||||||
|
|
||||||
# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
|
|
||||||
# sources only. Doxygen will then generate output that is more tailored for C.
|
|
||||||
# For instance, some of the names that are used will be different. The list
|
|
||||||
# of all members will be omitted, etc.
|
|
||||||
|
|
||||||
OPTIMIZE_OUTPUT_FOR_C = YES
|
|
||||||
|
|
||||||
# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
|
|
||||||
# sources only. Doxygen will then generate output that is more tailored for
|
|
||||||
# Java. For instance, namespaces will be presented as packages, qualified
|
|
||||||
# scopes will look different, etc.
|
|
||||||
|
|
||||||
OPTIMIZE_OUTPUT_JAVA = NO
|
|
||||||
|
|
||||||
# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
|
|
||||||
# sources only. Doxygen will then generate output that is more tailored for
|
|
||||||
# Fortran.
|
|
||||||
|
|
||||||
OPTIMIZE_FOR_FORTRAN = NO
|
|
||||||
|
|
||||||
# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
|
|
||||||
# sources. Doxygen will then generate output that is tailored for
|
|
||||||
# VHDL.
|
|
||||||
|
|
||||||
OPTIMIZE_OUTPUT_VHDL = NO
|
|
||||||
|
|
||||||
# Doxygen selects the parser to use depending on the extension of the files it
|
|
||||||
# parses. With this tag you can assign which parser to use for a given extension.
|
|
||||||
# Doxygen has a built-in mapping, but you can override or extend it using this
|
|
||||||
# tag. The format is ext=language, where ext is a file extension, and language
|
|
||||||
# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C,
|
|
||||||
# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make
|
|
||||||
# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
|
|
||||||
# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions
|
|
||||||
# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
|
|
||||||
|
|
||||||
EXTENSION_MAPPING =
|
|
||||||
|
|
||||||
# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all
|
|
||||||
# comments according to the Markdown format, which allows for more readable
|
|
||||||
# documentation. See http://daringfireball.net/projects/markdown/ for details.
|
|
||||||
# The output of markdown processing is further processed by doxygen, so you
|
|
||||||
# can mix doxygen, HTML, and XML commands with Markdown formatting.
|
|
||||||
# Disable only in case of backward compatibilities issues.
|
|
||||||
|
|
||||||
MARKDOWN_SUPPORT = NO
|
|
||||||
|
|
||||||
# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
|
|
||||||
# to include (a tag file for) the STL sources as input, then you should
|
|
||||||
# set this tag to YES in order to let doxygen match functions declarations and
|
|
||||||
# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
|
|
||||||
# func(std::string) {}). This also makes the inheritance and collaboration
|
|
||||||
# diagrams that involve STL classes more complete and accurate.
|
|
||||||
|
|
||||||
BUILTIN_STL_SUPPORT = NO
|
|
||||||
|
|
||||||
# If you use Microsoft's C++/CLI language, you should set this option to YES to
|
|
||||||
# enable parsing support.
|
|
||||||
|
|
||||||
CPP_CLI_SUPPORT = NO
|
|
||||||
|
|
||||||
# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
|
|
||||||
# Doxygen will parse them like normal C++ but will assume all classes use public
|
|
||||||
# instead of private inheritance when no explicit protection keyword is present.
|
|
||||||
|
|
||||||
SIP_SUPPORT = NO
|
|
||||||
|
|
||||||
# For Microsoft's IDL there are propget and propput attributes to indicate getter
|
|
||||||
# and setter methods for a property. Setting this option to YES (the default)
|
|
||||||
# will make doxygen replace the get and set methods by a property in the
|
|
||||||
# documentation. This will only work if the methods are indeed getting or
|
|
||||||
# setting a simple type. If this is not the case, or you want to show the
|
|
||||||
# methods anyway, you should set this option to NO.
|
|
||||||
|
|
||||||
IDL_PROPERTY_SUPPORT = YES
|
|
||||||
|
|
||||||
# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
|
|
||||||
# tag is set to YES, then doxygen will reuse the documentation of the first
|
|
||||||
# member in the group (if any) for the other members of the group. By default
|
|
||||||
# all members of a group must be documented explicitly.
|
|
||||||
|
|
||||||
DISTRIBUTE_GROUP_DOC = NO
|
|
||||||
|
|
||||||
# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
|
|
||||||
# the same type (for instance a group of public functions) to be put as a
|
|
||||||
# subgroup of that type (e.g. under the Public Functions section). Set it to
|
|
||||||
# NO to prevent subgrouping. Alternatively, this can be done per class using
|
|
||||||
# the \nosubgrouping command.
|
|
||||||
|
|
||||||
SUBGROUPING = YES
|
|
||||||
|
|
||||||
# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and
|
|
||||||
# unions are shown inside the group in which they are included (e.g. using
|
|
||||||
# @ingroup) instead of on a separate page (for HTML and Man pages) or
|
|
||||||
# section (for LaTeX and RTF).
|
|
||||||
|
|
||||||
INLINE_GROUPED_CLASSES = NO
|
|
||||||
|
|
||||||
# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and
|
|
||||||
# unions with only public data fields will be shown inline in the documentation
|
|
||||||
# of the scope in which they are defined (i.e. file, namespace, or group
|
|
||||||
# documentation), provided this scope is documented. If set to NO (the default),
|
|
||||||
# structs, classes, and unions are shown on a separate page (for HTML and Man
|
|
||||||
# pages) or section (for LaTeX and RTF).
|
|
||||||
|
|
||||||
INLINE_SIMPLE_STRUCTS = NO
|
|
||||||
|
|
||||||
# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
|
|
||||||
# is documented as struct, union, or enum with the name of the typedef. So
|
|
||||||
# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
|
|
||||||
# with name TypeT. When disabled the typedef will appear as a member of a file,
|
|
||||||
# namespace, or class. And the struct will be named TypeS. This can typically
|
|
||||||
# be useful for C code in case the coding convention dictates that all compound
|
|
||||||
# types are typedef'ed and only the typedef is referenced, never the tag name.
|
|
||||||
|
|
||||||
TYPEDEF_HIDES_STRUCT = NO
|
|
||||||
|
|
||||||
# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
|
|
||||||
# determine which symbols to keep in memory and which to flush to disk.
|
|
||||||
# When the cache is full, less often used symbols will be written to disk.
|
|
||||||
# For small to medium size projects (<1000 input files) the default value is
|
|
||||||
# probably good enough. For larger projects a too small cache size can cause
|
|
||||||
# doxygen to be busy swapping symbols to and from disk most of the time
|
|
||||||
# causing a significant performance penalty.
|
|
||||||
# If the system has enough physical memory increasing the cache will improve the
|
|
||||||
# performance by keeping more symbols in memory. Note that the value works on
|
|
||||||
# a logarithmic scale so increasing the size by one will roughly double the
|
|
||||||
# memory usage. The cache size is given by this formula:
|
|
||||||
# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
|
|
||||||
# corresponding to a cache size of 2^16 = 65536 symbols.
|
|
||||||
|
|
||||||
SYMBOL_CACHE_SIZE = 0
|
|
||||||
|
|
||||||
# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be
|
|
||||||
# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given
|
|
||||||
# their name and scope. Since this can be an expensive process and often the
|
|
||||||
# same symbol appear multiple times in the code, doxygen keeps a cache of
|
|
||||||
# pre-resolved symbols. If the cache is too small doxygen will become slower.
|
|
||||||
# If the cache is too large, memory is wasted. The cache size is given by this
|
|
||||||
# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0,
|
|
||||||
# corresponding to a cache size of 2^16 = 65536 symbols.
|
|
||||||
|
|
||||||
LOOKUP_CACHE_SIZE = 0
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------
|
|
||||||
# Build related configuration options
|
|
||||||
#---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
|
|
||||||
# documentation are documented, even if no documentation was available.
|
|
||||||
# Private class members and static file members will be hidden unless
|
|
||||||
# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
|
|
||||||
|
|
||||||
EXTRACT_ALL = YES
|
|
||||||
|
|
||||||
# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
|
|
||||||
# will be included in the documentation.
|
|
||||||
|
|
||||||
EXTRACT_PRIVATE = YES
|
|
||||||
|
|
||||||
# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal scope will be included in the documentation.
|
|
||||||
|
|
||||||
EXTRACT_PACKAGE = NO
|
|
||||||
|
|
||||||
# If the EXTRACT_STATIC tag is set to YES all static members of a file
|
|
||||||
# will be included in the documentation.
|
|
||||||
|
|
||||||
EXTRACT_STATIC = YES
|
|
||||||
|
|
||||||
# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
|
|
||||||
# defined locally in source files will be included in the documentation.
|
|
||||||
# If set to NO only classes defined in header files are included.
|
|
||||||
|
|
||||||
EXTRACT_LOCAL_CLASSES = YES
|
|
||||||
|
|
||||||
# This flag is only useful for Objective-C code. When set to YES local
|
|
||||||
# methods, which are defined in the implementation section but not in
|
|
||||||
# the interface are included in the documentation.
|
|
||||||
# If set to NO (the default) only methods in the interface are included.
|
|
||||||
|
|
||||||
EXTRACT_LOCAL_METHODS = NO
|
|
||||||
|
|
||||||
# If this flag is set to YES, the members of anonymous namespaces will be
|
|
||||||
# extracted and appear in the documentation as a namespace called
|
|
||||||
# 'anonymous_namespace{file}', where file will be replaced with the base
|
|
||||||
# name of the file that contains the anonymous namespace. By default
|
|
||||||
# anonymous namespaces are hidden.
|
|
||||||
|
|
||||||
EXTRACT_ANON_NSPACES = NO
|
|
||||||
|
|
||||||
# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
|
|
||||||
# undocumented members of documented classes, files or namespaces.
|
|
||||||
# If set to NO (the default) these members will be included in the
|
|
||||||
# various overviews, but no documentation section is generated.
|
|
||||||
# This option has no effect if EXTRACT_ALL is enabled.
|
|
||||||
|
|
||||||
HIDE_UNDOC_MEMBERS = NO
|
|
||||||
|
|
||||||
# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
|
|
||||||
# undocumented classes that are normally visible in the class hierarchy.
|
|
||||||
# If set to NO (the default) these classes will be included in the various
|
|
||||||
# overviews. This option has no effect if EXTRACT_ALL is enabled.
|
|
||||||
|
|
||||||
HIDE_UNDOC_CLASSES = NO
|
|
||||||
|
|
||||||
# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
|
|
||||||
# friend (class|struct|union) declarations.
|
|
||||||
# If set to NO (the default) these declarations will be included in the
|
|
||||||
# documentation.
|
|
||||||
|
|
||||||
HIDE_FRIEND_COMPOUNDS = NO
|
|
||||||
|
|
||||||
# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
|
|
||||||
# documentation blocks found inside the body of a function.
|
|
||||||
# If set to NO (the default) these blocks will be appended to the
|
|
||||||
# function's detailed documentation block.
|
|
||||||
|
|
||||||
HIDE_IN_BODY_DOCS = NO
|
|
||||||
|
|
||||||
# The INTERNAL_DOCS tag determines if documentation
|
|
||||||
# that is typed after a \internal command is included. If the tag is set
|
|
||||||
# to NO (the default) then the documentation will be excluded.
|
|
||||||
# Set it to YES to include the internal documentation.
|
|
||||||
|
|
||||||
INTERNAL_DOCS = NO
|
|
||||||
|
|
||||||
# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
|
|
||||||
# file names in lower-case letters. If set to YES upper-case letters are also
|
|
||||||
# allowed. This is useful if you have classes or files whose names only differ
|
|
||||||
# in case and if your file system supports case sensitive file names. Windows
|
|
||||||
# and Mac users are advised to set this option to NO.
|
|
||||||
|
|
||||||
CASE_SENSE_NAMES = NO
|
|
||||||
|
|
||||||
# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
|
|
||||||
# will show members with their full class and namespace scopes in the
|
|
||||||
# documentation. If set to YES the scope will be hidden.
|
|
||||||
|
|
||||||
HIDE_SCOPE_NAMES = NO
|
|
||||||
|
|
||||||
# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
|
|
||||||
# will put a list of the files that are included by a file in the documentation
|
|
||||||
# of that file.
|
|
||||||
|
|
||||||
SHOW_INCLUDE_FILES = YES
|
|
||||||
|
|
||||||
# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
|
|
||||||
# will list include files with double quotes in the documentation
|
|
||||||
# rather than with sharp brackets.
|
|
||||||
|
|
||||||
FORCE_LOCAL_INCLUDES = NO
|
|
||||||
|
|
||||||
# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
|
|
||||||
# is inserted in the documentation for inline members.
|
|
||||||
|
|
||||||
INLINE_INFO = YES
|
|
||||||
|
|
||||||
# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
|
|
||||||
# will sort the (detailed) documentation of file and class members
|
|
||||||
# alphabetically by member name. If set to NO the members will appear in
|
|
||||||
# declaration order.
|
|
||||||
|
|
||||||
SORT_MEMBER_DOCS = YES
|
|
||||||
|
|
||||||
# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
|
|
||||||
# brief documentation of file, namespace and class members alphabetically
|
|
||||||
# by member name. If set to NO (the default) the members will appear in
|
|
||||||
# declaration order.
|
|
||||||
|
|
||||||
SORT_BRIEF_DOCS = NO
|
|
||||||
|
|
||||||
# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
|
|
||||||
# will sort the (brief and detailed) documentation of class members so that
|
|
||||||
# constructors and destructors are listed first. If set to NO (the default)
|
|
||||||
# the constructors will appear in the respective orders defined by
|
|
||||||
# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
|
|
||||||
# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
|
|
||||||
# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
|
|
||||||
|
|
||||||
SORT_MEMBERS_CTORS_1ST = NO
|
|
||||||
|
|
||||||
# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
|
|
||||||
# hierarchy of group names into alphabetical order. If set to NO (the default)
|
|
||||||
# the group names will appear in their defined order.
|
|
||||||
|
|
||||||
SORT_GROUP_NAMES = NO
|
|
||||||
|
|
||||||
# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
|
|
||||||
# sorted by fully-qualified names, including namespaces. If set to
|
|
||||||
# NO (the default), the class list will be sorted only by class name,
|
|
||||||
# not including the namespace part.
|
|
||||||
# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
|
|
||||||
# Note: This option applies only to the class list, not to the
|
|
||||||
# alphabetical list.
|
|
||||||
|
|
||||||
SORT_BY_SCOPE_NAME = NO
|
|
||||||
|
|
||||||
# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to
|
|
||||||
# do proper type resolution of all parameters of a function it will reject a
|
|
||||||
# match between the prototype and the implementation of a member function even
|
|
||||||
# if there is only one candidate or it is obvious which candidate to choose
|
|
||||||
# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen
|
|
||||||
# will still accept a match between prototype and implementation in such cases.
|
|
||||||
|
|
||||||
STRICT_PROTO_MATCHING = NO
|
|
||||||
|
|
||||||
# The GENERATE_TODOLIST tag can be used to enable (YES) or
|
|
||||||
# disable (NO) the todo list. This list is created by putting \todo
|
|
||||||
# commands in the documentation.
|
|
||||||
|
|
||||||
GENERATE_TODOLIST = NO
|
|
||||||
|
|
||||||
# The GENERATE_TESTLIST tag can be used to enable (YES) or
|
|
||||||
# disable (NO) the test list. This list is created by putting \test
|
|
||||||
# commands in the documentation.
|
|
||||||
|
|
||||||
GENERATE_TESTLIST = NO
|
|
||||||
|
|
||||||
# The GENERATE_BUGLIST tag can be used to enable (YES) or
|
|
||||||
# disable (NO) the bug list. This list is created by putting \bug
|
|
||||||
# commands in the documentation.
|
|
||||||
|
|
||||||
GENERATE_BUGLIST = NO
|
|
||||||
|
|
||||||
# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
|
|
||||||
# disable (NO) the deprecated list. This list is created by putting
|
|
||||||
# \deprecated commands in the documentation.
|
|
||||||
|
|
||||||
GENERATE_DEPRECATEDLIST= YES
|
|
||||||
|
|
||||||
# The ENABLED_SECTIONS tag can be used to enable conditional
|
|
||||||
# documentation sections, marked by \if sectionname ... \endif.
|
|
||||||
|
|
||||||
ENABLED_SECTIONS =
|
|
||||||
|
|
||||||
# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
|
|
||||||
# the initial value of a variable or macro consists of for it to appear in
|
|
||||||
# the documentation. If the initializer consists of more lines than specified
|
|
||||||
# here it will be hidden. Use a value of 0 to hide initializers completely.
|
|
||||||
# The appearance of the initializer of individual variables and macros in the
|
|
||||||
# documentation can be controlled using \showinitializer or \hideinitializer
|
|
||||||
# command in the documentation regardless of this setting.
|
|
||||||
|
|
||||||
MAX_INITIALIZER_LINES = 30
|
|
||||||
|
|
||||||
# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
|
|
||||||
# at the bottom of the documentation of classes and structs. If set to YES the
|
|
||||||
# list will mention the files that were used to generate the documentation.
|
|
||||||
|
|
||||||
SHOW_USED_FILES = YES
|
|
||||||
|
|
||||||
# If the sources in your project are distributed over multiple directories
|
|
||||||
# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
|
|
||||||
# in the documentation. The default is NO.
|
|
||||||
|
|
||||||
SHOW_DIRECTORIES = YES
|
|
||||||
|
|
||||||
# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
|
|
||||||
# This will remove the Files entry from the Quick Index and from the
|
|
||||||
# Folder Tree View (if specified). The default is YES.
|
|
||||||
|
|
||||||
SHOW_FILES = YES
|
|
||||||
|
|
||||||
# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
|
|
||||||
# Namespaces page.
|
|
||||||
# This will remove the Namespaces entry from the Quick Index
|
|
||||||
# and from the Folder Tree View (if specified). The default is YES.
|
|
||||||
|
|
||||||
SHOW_NAMESPACES = YES
|
|
||||||
|
|
||||||
# The FILE_VERSION_FILTER tag can be used to specify a program or script that
|
|
||||||
# doxygen should invoke to get the current version for each file (typically from
|
|
||||||
# the version control system). Doxygen will invoke the program by executing (via
|
|
||||||
# popen()) the command <command> <input-file>, where <command> is the value of
|
|
||||||
# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
|
|
||||||
# provided by doxygen. Whatever the program writes to standard output
|
|
||||||
# is used as the file version. See the manual for examples.
|
|
||||||
|
|
||||||
FILE_VERSION_FILTER =
|
|
||||||
|
|
||||||
# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
|
|
||||||
# by doxygen. The layout file controls the global structure of the generated
|
|
||||||
# output files in an output format independent way. The create the layout file
|
|
||||||
# that represents doxygen's defaults, run doxygen with the -l option.
|
|
||||||
# You can optionally specify a file name after the option, if omitted
|
|
||||||
# DoxygenLayout.xml will be used as the name of the layout file.
|
|
||||||
|
|
||||||
LAYOUT_FILE =
|
|
||||||
|
|
||||||
# The CITE_BIB_FILES tag can be used to specify one or more bib files
|
|
||||||
# containing the references data. This must be a list of .bib files. The
|
|
||||||
# .bib extension is automatically appended if omitted. Using this command
|
|
||||||
# requires the bibtex tool to be installed. See also
|
|
||||||
# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style
|
|
||||||
# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this
|
|
||||||
# feature you need bibtex and perl available in the search path.
|
|
||||||
|
|
||||||
CITE_BIB_FILES =
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------
|
|
||||||
# configuration options related to warning and progress messages
|
|
||||||
#---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
# The QUIET tag can be used to turn on/off the messages that are generated
|
|
||||||
# by doxygen. Possible values are YES and NO. If left blank NO is used.
|
|
||||||
|
|
||||||
QUIET = YES
|
|
||||||
|
|
||||||
# The WARNINGS tag can be used to turn on/off the warning messages that are
|
|
||||||
# generated by doxygen. Possible values are YES and NO. If left blank
|
|
||||||
# NO is used.
|
|
||||||
|
|
||||||
WARNINGS = YES
|
|
||||||
|
|
||||||
# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
|
|
||||||
# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
|
|
||||||
# automatically be disabled.
|
|
||||||
|
|
||||||
WARN_IF_UNDOCUMENTED = YES
|
|
||||||
|
|
||||||
# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
|
|
||||||
# potential errors in the documentation, such as not documenting some
|
|
||||||
# parameters in a documented function, or documenting parameters that
|
|
||||||
# don't exist or using markup commands wrongly.
|
|
||||||
|
|
||||||
WARN_IF_DOC_ERROR = YES
|
|
||||||
|
|
||||||
# The WARN_NO_PARAMDOC option can be enabled to get warnings for
|
|
||||||
# functions that are documented, but have no documentation for their parameters
|
|
||||||
# or return value. If set to NO (the default) doxygen will only warn about
|
|
||||||
# wrong or incomplete parameter documentation, but not about the absence of
|
|
||||||
# documentation.
|
|
||||||
|
|
||||||
WARN_NO_PARAMDOC = YES
|
|
||||||
|
|
||||||
# The WARN_FORMAT tag determines the format of the warning messages that
|
|
||||||
# doxygen can produce. The string should contain the $file, $line, and $text
|
|
||||||
# tags, which will be replaced by the file and line number from which the
|
|
||||||
# warning originated and the warning text. Optionally the format may contain
|
|
||||||
# $version, which will be replaced by the version of the file (if it could
|
|
||||||
# be obtained via FILE_VERSION_FILTER)
|
|
||||||
|
|
||||||
WARN_FORMAT = "$file:$line: $text"
|
|
||||||
|
|
||||||
# The WARN_LOGFILE tag can be used to specify a file to which warning
|
|
||||||
# and error messages should be written. If left blank the output is written
|
|
||||||
# to stderr.
|
|
||||||
|
|
||||||
WARN_LOGFILE =
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------
|
|
||||||
# configuration options related to the input files
|
|
||||||
#---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
# The INPUT tag can be used to specify the files and/or directories that contain
|
|
||||||
# documented source files. You may enter file names like "myfile.cpp" or
|
|
||||||
# directories like "/usr/src/myproject". Separate the files or directories
|
|
||||||
# with spaces.
|
|
||||||
|
|
||||||
INPUT = ./
|
|
||||||
|
|
||||||
# This tag can be used to specify the character encoding of the source files
|
|
||||||
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
|
|
||||||
# also the default input encoding. Doxygen uses libiconv (or the iconv built
|
|
||||||
# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
|
|
||||||
# the list of possible encodings.
|
|
||||||
|
|
||||||
INPUT_ENCODING = UTF-8
|
|
||||||
|
|
||||||
# If the value of the INPUT tag contains directories, you can use the
|
|
||||||
# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
|
|
||||||
# and *.h) to filter out the source-files in the directories. If left
|
|
||||||
# blank the following patterns are tested:
|
|
||||||
# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh
|
|
||||||
# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
|
|
||||||
# *.f90 *.f *.for *.vhd *.vhdl
|
|
||||||
|
|
||||||
FILE_PATTERNS = *.h \
|
|
||||||
*.c \
|
|
||||||
*.txt
|
|
||||||
|
|
||||||
# The RECURSIVE tag can be used to turn specify whether or not subdirectories
|
|
||||||
# should be searched for input files as well. Possible values are YES and NO.
|
|
||||||
# If left blank NO is used.
|
|
||||||
|
|
||||||
RECURSIVE = YES
|
|
||||||
|
|
||||||
# The EXCLUDE tag can be used to specify files and/or directories that should be
|
|
||||||
# excluded from the INPUT source files. This way you can easily exclude a
|
|
||||||
# subdirectory from a directory tree whose root is specified with the INPUT tag.
|
|
||||||
# Note that relative paths are relative to the directory from which doxygen is
|
|
||||||
# run.
|
|
||||||
|
|
||||||
EXCLUDE = Documentation/
|
|
||||||
|
|
||||||
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
|
|
||||||
# directories that are symbolic links (a Unix file system feature) are excluded
|
|
||||||
# from the input.
|
|
||||||
|
|
||||||
EXCLUDE_SYMLINKS = NO
|
|
||||||
|
|
||||||
# If the value of the INPUT tag contains directories, you can use the
|
|
||||||
# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
|
|
||||||
# certain files from those directories. Note that the wildcards are matched
|
|
||||||
# against the file with absolute path, so to exclude all test directories
|
|
||||||
# for example use the pattern */test/*
|
|
||||||
|
|
||||||
EXCLUDE_PATTERNS =
|
|
||||||
|
|
||||||
# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
|
|
||||||
# (namespaces, classes, functions, etc.) that should be excluded from the
|
|
||||||
# output. The symbol name can be a fully qualified name, a word, or if the
|
|
||||||
# wildcard * is used, a substring. Examples: ANamespace, AClass,
|
|
||||||
# AClass::ANamespace, ANamespace::*Test
|
|
||||||
|
|
||||||
EXCLUDE_SYMBOLS = __* \
|
|
||||||
INCLUDE_FROM_*
|
|
||||||
|
|
||||||
# The EXAMPLE_PATH tag can be used to specify one or more files or
|
|
||||||
# directories that contain example code fragments that are included (see
|
|
||||||
# the \include command).
|
|
||||||
|
|
||||||
EXAMPLE_PATH =
|
|
||||||
|
|
||||||
# If the value of the EXAMPLE_PATH tag contains directories, you can use the
|
|
||||||
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
|
|
||||||
# and *.h) to filter out the source-files in the directories. If left
|
|
||||||
# blank all files are included.
|
|
||||||
|
|
||||||
EXAMPLE_PATTERNS = *
|
|
||||||
|
|
||||||
# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
|
|
||||||
# searched for input files to be used with the \include or \dontinclude
|
|
||||||
# commands irrespective of the value of the RECURSIVE tag.
|
|
||||||
# Possible values are YES and NO. If left blank NO is used.
|
|
||||||
|
|
||||||
EXAMPLE_RECURSIVE = NO
|
|
||||||
|
|
||||||
# The IMAGE_PATH tag can be used to specify one or more files or
|
|
||||||
# directories that contain image that are included in the documentation (see
|
|
||||||
# the \image command).
|
|
||||||
|
|
||||||
IMAGE_PATH =
|
|
||||||
|
|
||||||
# The INPUT_FILTER tag can be used to specify a program that doxygen should
|
|
||||||
# invoke to filter for each input file. Doxygen will invoke the filter program
|
|
||||||
# by executing (via popen()) the command <filter> <input-file>, where <filter>
|
|
||||||
# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
|
|
||||||
# input file. Doxygen will then use the output that the filter program writes
|
|
||||||
# to standard output.
|
|
||||||
# If FILTER_PATTERNS is specified, this tag will be
|
|
||||||
# ignored.
|
|
||||||
|
|
||||||
INPUT_FILTER =
|
|
||||||
|
|
||||||
# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
|
|
||||||
# basis.
|
|
||||||
# Doxygen will compare the file name with each pattern and apply the
|
|
||||||
# filter if there is a match.
|
|
||||||
# The filters are a list of the form:
|
|
||||||
# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
|
|
||||||
# info on how filters are used. If FILTER_PATTERNS is empty or if
|
|
||||||
# non of the patterns match the file name, INPUT_FILTER is applied.
|
|
||||||
|
|
||||||
FILTER_PATTERNS =
|
|
||||||
|
|
||||||
# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
|
|
||||||
# INPUT_FILTER) will be used to filter the input files when producing source
|
|
||||||
# files to browse (i.e. when SOURCE_BROWSER is set to YES).
|
|
||||||
|
|
||||||
FILTER_SOURCE_FILES = NO
|
|
||||||
|
|
||||||
# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
|
|
||||||
# pattern. A pattern will override the setting for FILTER_PATTERN (if any)
|
|
||||||
# and it is also possible to disable source filtering for a specific pattern
|
|
||||||
# using *.ext= (so without naming a filter). This option only has effect when
|
|
||||||
# FILTER_SOURCE_FILES is enabled.
|
|
||||||
|
|
||||||
FILTER_SOURCE_PATTERNS =
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------
|
|
||||||
# configuration options related to source browsing
|
|
||||||
#---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
# If the SOURCE_BROWSER tag is set to YES then a list of source files will
|
|
||||||
# be generated. Documented entities will be cross-referenced with these sources.
|
|
||||||
# Note: To get rid of all source code in the generated output, make sure also
|
|
||||||
# VERBATIM_HEADERS is set to NO.
|
|
||||||
|
|
||||||
SOURCE_BROWSER = NO
|
|
||||||
|
|
||||||
# Setting the INLINE_SOURCES tag to YES will include the body
|
|
||||||
# of functions and classes directly in the documentation.
|
|
||||||
|
|
||||||
INLINE_SOURCES = NO
|
|
||||||
|
|
||||||
# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
|
|
||||||
# doxygen to hide any special comment blocks from generated source code
|
|
||||||
# fragments. Normal C and C++ comments will always remain visible.
|
|
||||||
|
|
||||||
STRIP_CODE_COMMENTS = YES
|
|
||||||
|
|
||||||
# If the REFERENCED_BY_RELATION tag is set to YES
|
|
||||||
# then for each documented function all documented
|
|
||||||
# functions referencing it will be listed.
|
|
||||||
|
|
||||||
REFERENCED_BY_RELATION = NO
|
|
||||||
|
|
||||||
# If the REFERENCES_RELATION tag is set to YES
|
|
||||||
# then for each documented function all documented entities
|
|
||||||
# called/used by that function will be listed.
|
|
||||||
|
|
||||||
REFERENCES_RELATION = NO
|
|
||||||
|
|
||||||
# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
|
|
||||||
# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
|
|
||||||
# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
|
|
||||||
# link to the source code.
|
|
||||||
# Otherwise they will link to the documentation.
|
|
||||||
|
|
||||||
REFERENCES_LINK_SOURCE = NO
|
|
||||||
|
|
||||||
# If the USE_HTAGS tag is set to YES then the references to source code
|
|
||||||
# will point to the HTML generated by the htags(1) tool instead of doxygen
|
|
||||||
# built-in source browser. The htags tool is part of GNU's global source
|
|
||||||
# tagging system (see http://www.gnu.org/software/global/global.html). You
|
|
||||||
# will need version 4.8.6 or higher.
|
|
||||||
|
|
||||||
USE_HTAGS = NO
|
|
||||||
|
|
||||||
# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
|
|
||||||
# will generate a verbatim copy of the header file for each class for
|
|
||||||
# which an include is specified. Set to NO to disable this.
|
|
||||||
|
|
||||||
VERBATIM_HEADERS = NO
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------
|
|
||||||
# configuration options related to the alphabetical class index
|
|
||||||
#---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
|
|
||||||
# of all compounds will be generated. Enable this if the project
|
|
||||||
# contains a lot of classes, structs, unions or interfaces.
|
|
||||||
|
|
||||||
ALPHABETICAL_INDEX = YES
|
|
||||||
|
|
||||||
# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
|
|
||||||
# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
|
|
||||||
# in which this list will be split (can be a number in the range [1..20])
|
|
||||||
|
|
||||||
COLS_IN_ALPHA_INDEX = 5
|
|
||||||
|
|
||||||
# In case all classes in a project start with a common prefix, all
|
|
||||||
# classes will be put under the same header in the alphabetical index.
|
|
||||||
# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
|
|
||||||
# should be ignored while generating the index headers.
|
|
||||||
|
|
||||||
IGNORE_PREFIX =
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------
|
|
||||||
# configuration options related to the HTML output
|
|
||||||
#---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
|
|
||||||
# generate HTML output.
|
|
||||||
|
|
||||||
GENERATE_HTML = YES
|
|
||||||
|
|
||||||
# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
|
|
||||||
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
|
|
||||||
# put in front of it. If left blank `html' will be used as the default path.
|
|
||||||
|
|
||||||
HTML_OUTPUT = html
|
|
||||||
|
|
||||||
# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
|
|
||||||
# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
|
|
||||||
# doxygen will generate files with .html extension.
|
|
||||||
|
|
||||||
HTML_FILE_EXTENSION = .html
|
|
||||||
|
|
||||||
# The HTML_HEADER tag can be used to specify a personal HTML header for
|
|
||||||
# each generated HTML page. If it is left blank doxygen will generate a
|
|
||||||
# standard header. Note that when using a custom header you are responsible
|
|
||||||
# for the proper inclusion of any scripts and style sheets that doxygen
|
|
||||||
# needs, which is dependent on the configuration options used.
|
|
||||||
# It is advised to generate a default header using "doxygen -w html
|
|
||||||
# header.html footer.html stylesheet.css YourConfigFile" and then modify
|
|
||||||
# that header. Note that the header is subject to change so you typically
|
|
||||||
# have to redo this when upgrading to a newer version of doxygen or when
|
|
||||||
# changing the value of configuration settings such as GENERATE_TREEVIEW!
|
|
||||||
|
|
||||||
HTML_HEADER =
|
|
||||||
|
|
||||||
# The HTML_FOOTER tag can be used to specify a personal HTML footer for
|
|
||||||
# each generated HTML page. If it is left blank doxygen will generate a
|
|
||||||
# standard footer.
|
|
||||||
|
|
||||||
HTML_FOOTER =
|
|
||||||
|
|
||||||
# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
|
|
||||||
# style sheet that is used by each HTML page. It can be used to
|
|
||||||
# fine-tune the look of the HTML output. If the tag is left blank doxygen
|
|
||||||
# will generate a default style sheet. Note that doxygen will try to copy
|
|
||||||
# the style sheet file to the HTML output directory, so don't put your own
|
|
||||||
# style sheet in the HTML output directory as well, or it will be erased!
|
|
||||||
|
|
||||||
HTML_STYLESHEET =
|
|
||||||
|
|
||||||
# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
|
|
||||||
# other source files which should be copied to the HTML output directory. Note
|
|
||||||
# that these files will be copied to the base HTML output directory. Use the
|
|
||||||
# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
|
|
||||||
# files. In the HTML_STYLESHEET file, use the file name only. Also note that
|
|
||||||
# the files will be copied as-is; there are no commands or markers available.
|
|
||||||
|
|
||||||
HTML_EXTRA_FILES =
|
|
||||||
|
|
||||||
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
|
|
||||||
# Doxygen will adjust the colors in the style sheet and background images
|
|
||||||
# according to this color. Hue is specified as an angle on a colorwheel,
|
|
||||||
# see http://en.wikipedia.org/wiki/Hue for more information.
|
|
||||||
# For instance the value 0 represents red, 60 is yellow, 120 is green,
|
|
||||||
# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
|
|
||||||
# The allowed range is 0 to 359.
|
|
||||||
|
|
||||||
HTML_COLORSTYLE_HUE = 220
|
|
||||||
|
|
||||||
# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
|
|
||||||
# the colors in the HTML output. For a value of 0 the output will use
|
|
||||||
# grayscales only. A value of 255 will produce the most vivid colors.
|
|
||||||
|
|
||||||
HTML_COLORSTYLE_SAT = 100
|
|
||||||
|
|
||||||
# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
|
|
||||||
# the luminance component of the colors in the HTML output. Values below
|
|
||||||
# 100 gradually make the output lighter, whereas values above 100 make
|
|
||||||
# the output darker. The value divided by 100 is the actual gamma applied,
|
|
||||||
# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
|
|
||||||
# and 100 does not change the gamma.
|
|
||||||
|
|
||||||
HTML_COLORSTYLE_GAMMA = 80
|
|
||||||
|
|
||||||
# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
|
|
||||||
# page will contain the date and time when the page was generated. Setting
|
|
||||||
# this to NO can help when comparing the output of multiple runs.
|
|
||||||
|
|
||||||
HTML_TIMESTAMP = NO
|
|
||||||
|
|
||||||
# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
|
|
||||||
# files or namespaces will be aligned in HTML using tables. If set to
|
|
||||||
# NO a bullet list will be used.
|
|
||||||
|
|
||||||
HTML_ALIGN_MEMBERS = YES
|
|
||||||
|
|
||||||
# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
|
|
||||||
# documentation will contain sections that can be hidden and shown after the
|
|
||||||
# page has loaded. For this to work a browser that supports
|
|
||||||
# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
|
|
||||||
# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
|
|
||||||
|
|
||||||
HTML_DYNAMIC_SECTIONS = YES
|
|
||||||
|
|
||||||
# If the GENERATE_DOCSET tag is set to YES, additional index files
|
|
||||||
# will be generated that can be used as input for Apple's Xcode 3
|
|
||||||
# integrated development environment, introduced with OSX 10.5 (Leopard).
|
|
||||||
# To create a documentation set, doxygen will generate a Makefile in the
|
|
||||||
# HTML output directory. Running make will produce the docset in that
|
|
||||||
# directory and running "make install" will install the docset in
|
|
||||||
# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
|
|
||||||
# it at startup.
|
|
||||||
# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
|
|
||||||
# for more information.
|
|
||||||
|
|
||||||
GENERATE_DOCSET = NO
|
|
||||||
|
|
||||||
# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
|
|
||||||
# feed. A documentation feed provides an umbrella under which multiple
|
|
||||||
# documentation sets from a single provider (such as a company or product suite)
|
|
||||||
# can be grouped.
|
|
||||||
|
|
||||||
DOCSET_FEEDNAME = "Doxygen generated docs"
|
|
||||||
|
|
||||||
# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
|
|
||||||
# should uniquely identify the documentation set bundle. This should be a
|
|
||||||
# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
|
|
||||||
# will append .docset to the name.
|
|
||||||
|
|
||||||
DOCSET_BUNDLE_ID = org.doxygen.Project
|
|
||||||
|
|
||||||
# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify
|
|
||||||
# the documentation publisher. This should be a reverse domain-name style
|
|
||||||
# string, e.g. com.mycompany.MyDocSet.documentation.
|
|
||||||
|
|
||||||
DOCSET_PUBLISHER_ID = org.doxygen.Publisher
|
|
||||||
|
|
||||||
# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
|
|
||||||
|
|
||||||
DOCSET_PUBLISHER_NAME = Publisher
|
|
||||||
|
|
||||||
# If the GENERATE_HTMLHELP tag is set to YES, additional index files
|
|
||||||
# will be generated that can be used as input for tools like the
|
|
||||||
# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
|
|
||||||
# of the generated HTML documentation.
|
|
||||||
|
|
||||||
GENERATE_HTMLHELP = NO
|
|
||||||
|
|
||||||
# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
|
|
||||||
# be used to specify the file name of the resulting .chm file. You
|
|
||||||
# can add a path in front of the file if the result should not be
|
|
||||||
# written to the html output directory.
|
|
||||||
|
|
||||||
CHM_FILE =
|
|
||||||
|
|
||||||
# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
|
|
||||||
# be used to specify the location (absolute path including file name) of
|
|
||||||
# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
|
|
||||||
# the HTML help compiler on the generated index.hhp.
|
|
||||||
|
|
||||||
HHC_LOCATION =
|
|
||||||
|
|
||||||
# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
|
|
||||||
# controls if a separate .chi index file is generated (YES) or that
|
|
||||||
# it should be included in the master .chm file (NO).
|
|
||||||
|
|
||||||
GENERATE_CHI = NO
|
|
||||||
|
|
||||||
# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
|
|
||||||
# is used to encode HtmlHelp index (hhk), content (hhc) and project file
|
|
||||||
# content.
|
|
||||||
|
|
||||||
CHM_INDEX_ENCODING =
|
|
||||||
|
|
||||||
# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
|
|
||||||
# controls whether a binary table of contents is generated (YES) or a
|
|
||||||
# normal table of contents (NO) in the .chm file.
|
|
||||||
|
|
||||||
BINARY_TOC = NO
|
|
||||||
|
|
||||||
# The TOC_EXPAND flag can be set to YES to add extra items for group members
|
|
||||||
# to the contents of the HTML help documentation and to the tree view.
|
|
||||||
|
|
||||||
TOC_EXPAND = YES
|
|
||||||
|
|
||||||
# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
|
|
||||||
# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
|
|
||||||
# that can be used as input for Qt's qhelpgenerator to generate a
|
|
||||||
# Qt Compressed Help (.qch) of the generated HTML documentation.
|
|
||||||
|
|
||||||
GENERATE_QHP = NO
|
|
||||||
|
|
||||||
# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
|
|
||||||
# be used to specify the file name of the resulting .qch file.
|
|
||||||
# The path specified is relative to the HTML output folder.
|
|
||||||
|
|
||||||
QCH_FILE =
|
|
||||||
|
|
||||||
# The QHP_NAMESPACE tag specifies the namespace to use when generating
|
|
||||||
# Qt Help Project output. For more information please see
|
|
||||||
# http://doc.trolltech.com/qthelpproject.html#namespace
|
|
||||||
|
|
||||||
QHP_NAMESPACE = org.doxygen.Project
|
|
||||||
|
|
||||||
# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
|
|
||||||
# Qt Help Project output. For more information please see
|
|
||||||
# http://doc.trolltech.com/qthelpproject.html#virtual-folders
|
|
||||||
|
|
||||||
QHP_VIRTUAL_FOLDER = doc
|
|
||||||
|
|
||||||
# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
|
|
||||||
# add. For more information please see
|
|
||||||
# http://doc.trolltech.com/qthelpproject.html#custom-filters
|
|
||||||
|
|
||||||
QHP_CUST_FILTER_NAME =
|
|
||||||
|
|
||||||
# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
|
|
||||||
# custom filter to add. For more information please see
|
|
||||||
# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
|
|
||||||
# Qt Help Project / Custom Filters</a>.
|
|
||||||
|
|
||||||
QHP_CUST_FILTER_ATTRS =
|
|
||||||
|
|
||||||
# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
|
|
||||||
# project's
|
|
||||||
# filter section matches.
|
|
||||||
# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
|
|
||||||
# Qt Help Project / Filter Attributes</a>.
|
|
||||||
|
|
||||||
QHP_SECT_FILTER_ATTRS =
|
|
||||||
|
|
||||||
# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
|
|
||||||
# be used to specify the location of Qt's qhelpgenerator.
|
|
||||||
# If non-empty doxygen will try to run qhelpgenerator on the generated
|
|
||||||
# .qhp file.
|
|
||||||
|
|
||||||
QHG_LOCATION =
|
|
||||||
|
|
||||||
# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
|
|
||||||
# will be generated, which together with the HTML files, form an Eclipse help
|
|
||||||
# plugin. To install this plugin and make it available under the help contents
|
|
||||||
# menu in Eclipse, the contents of the directory containing the HTML and XML
|
|
||||||
# files needs to be copied into the plugins directory of eclipse. The name of
|
|
||||||
# the directory within the plugins directory should be the same as
|
|
||||||
# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
|
|
||||||
# the help appears.
|
|
||||||
|
|
||||||
GENERATE_ECLIPSEHELP = NO
|
|
||||||
|
|
||||||
# A unique identifier for the eclipse help plugin. When installing the plugin
|
|
||||||
# the directory name containing the HTML and XML files should also have
|
|
||||||
# this name.
|
|
||||||
|
|
||||||
ECLIPSE_DOC_ID = org.doxygen.Project
|
|
||||||
|
|
||||||
# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs)
|
|
||||||
# at top of each HTML page. The value NO (the default) enables the index and
|
|
||||||
# the value YES disables it. Since the tabs have the same information as the
|
|
||||||
# navigation tree you can set this option to NO if you already set
|
|
||||||
# GENERATE_TREEVIEW to YES.
|
|
||||||
|
|
||||||
DISABLE_INDEX = NO
|
|
||||||
|
|
||||||
# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
|
|
||||||
# structure should be generated to display hierarchical information.
|
|
||||||
# If the tag value is set to YES, a side panel will be generated
|
|
||||||
# containing a tree-like index structure (just like the one that
|
|
||||||
# is generated for HTML Help). For this to work a browser that supports
|
|
||||||
# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
|
|
||||||
# Windows users are probably better off using the HTML help feature.
|
|
||||||
# Since the tree basically has the same information as the tab index you
|
|
||||||
# could consider to set DISABLE_INDEX to NO when enabling this option.
|
|
||||||
|
|
||||||
GENERATE_TREEVIEW = YES
|
|
||||||
|
|
||||||
# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values
|
|
||||||
# (range [0,1..20]) that doxygen will group on one line in the generated HTML
|
|
||||||
# documentation. Note that a value of 0 will completely suppress the enum
|
|
||||||
# values from appearing in the overview section.
|
|
||||||
|
|
||||||
ENUM_VALUES_PER_LINE = 1
|
|
||||||
|
|
||||||
# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
|
|
||||||
# and Class Hierarchy pages using a tree view instead of an ordered list.
|
|
||||||
|
|
||||||
USE_INLINE_TREES = NO
|
|
||||||
|
|
||||||
# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
|
|
||||||
# used to set the initial width (in pixels) of the frame in which the tree
|
|
||||||
# is shown.
|
|
||||||
|
|
||||||
TREEVIEW_WIDTH = 250
|
|
||||||
|
|
||||||
# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
|
|
||||||
# links to external symbols imported via tag files in a separate window.
|
|
||||||
|
|
||||||
EXT_LINKS_IN_WINDOW = NO
|
|
||||||
|
|
||||||
# Use this tag to change the font size of Latex formulas included
|
|
||||||
# as images in the HTML documentation. The default is 10. Note that
|
|
||||||
# when you change the font size after a successful doxygen run you need
|
|
||||||
# to manually remove any form_*.png images from the HTML output directory
|
|
||||||
# to force them to be regenerated.
|
|
||||||
|
|
||||||
FORMULA_FONTSIZE = 10
|
|
||||||
|
|
||||||
# Use the FORMULA_TRANPARENT tag to determine whether or not the images
|
|
||||||
# generated for formulas are transparent PNGs. Transparent PNGs are
|
|
||||||
# not supported properly for IE 6.0, but are supported on all modern browsers.
|
|
||||||
# Note that when changing this option you need to delete any form_*.png files
|
|
||||||
# in the HTML output before the changes have effect.
|
|
||||||
|
|
||||||
FORMULA_TRANSPARENT = YES
|
|
||||||
|
|
||||||
# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax
|
|
||||||
# (see http://www.mathjax.org) which uses client side Javascript for the
|
|
||||||
# rendering instead of using prerendered bitmaps. Use this if you do not
|
|
||||||
# have LaTeX installed or if you want to formulas look prettier in the HTML
|
|
||||||
# output. When enabled you may also need to install MathJax separately and
|
|
||||||
# configure the path to it using the MATHJAX_RELPATH option.
|
|
||||||
|
|
||||||
USE_MATHJAX = NO
|
|
||||||
|
|
||||||
# When MathJax is enabled you need to specify the location relative to the
|
|
||||||
# HTML output directory using the MATHJAX_RELPATH option. The destination
|
|
||||||
# directory should contain the MathJax.js script. For instance, if the mathjax
|
|
||||||
# directory is located at the same level as the HTML output directory, then
|
|
||||||
# MATHJAX_RELPATH should be ../mathjax. The default value points to
|
|
||||||
# the MathJax Content Delivery Network so you can quickly see the result without
|
|
||||||
# installing MathJax.
|
|
||||||
# However, it is strongly recommended to install a local
|
|
||||||
# copy of MathJax from http://www.mathjax.org before deployment.
|
|
||||||
|
|
||||||
MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
|
|
||||||
|
|
||||||
# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension
|
|
||||||
# names that should be enabled during MathJax rendering.
|
|
||||||
|
|
||||||
MATHJAX_EXTENSIONS =
|
|
||||||
|
|
||||||
# When the SEARCHENGINE tag is enabled doxygen will generate a search box
|
|
||||||
# for the HTML output. The underlying search engine uses javascript
|
|
||||||
# and DHTML and should work on any modern browser. Note that when using
|
|
||||||
# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
|
|
||||||
# (GENERATE_DOCSET) there is already a search function so this one should
|
|
||||||
# typically be disabled. For large projects the javascript based search engine
|
|
||||||
# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
|
|
||||||
|
|
||||||
SEARCHENGINE = NO
|
|
||||||
|
|
||||||
# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
|
|
||||||
# implemented using a PHP enabled web server instead of at the web client
|
|
||||||
# using Javascript. Doxygen will generate the search PHP script and index
|
|
||||||
# file to put on the web server. The advantage of the server
|
|
||||||
# based approach is that it scales better to large projects and allows
|
|
||||||
# full text search. The disadvantages are that it is more difficult to setup
|
|
||||||
# and does not have live searching capabilities.
|
|
||||||
|
|
||||||
SERVER_BASED_SEARCH = NO
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------
|
|
||||||
# configuration options related to the LaTeX output
|
|
||||||
#---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
|
|
||||||
# generate Latex output.
|
|
||||||
|
|
||||||
GENERATE_LATEX = NO
|
|
||||||
|
|
||||||
# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
|
|
||||||
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
|
|
||||||
# put in front of it. If left blank `latex' will be used as the default path.
|
|
||||||
|
|
||||||
LATEX_OUTPUT = latex
|
|
||||||
|
|
||||||
# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
|
|
||||||
# invoked. If left blank `latex' will be used as the default command name.
|
|
||||||
# Note that when enabling USE_PDFLATEX this option is only used for
|
|
||||||
# generating bitmaps for formulas in the HTML output, but not in the
|
|
||||||
# Makefile that is written to the output directory.
|
|
||||||
|
|
||||||
LATEX_CMD_NAME = latex
|
|
||||||
|
|
||||||
# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
|
|
||||||
# generate index for LaTeX. If left blank `makeindex' will be used as the
|
|
||||||
# default command name.
|
|
||||||
|
|
||||||
MAKEINDEX_CMD_NAME = makeindex
|
|
||||||
|
|
||||||
# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
|
|
||||||
# LaTeX documents. This may be useful for small projects and may help to
|
|
||||||
# save some trees in general.
|
|
||||||
|
|
||||||
COMPACT_LATEX = NO
|
|
||||||
|
|
||||||
# The PAPER_TYPE tag can be used to set the paper type that is used
|
|
||||||
# by the printer. Possible values are: a4, letter, legal and
|
|
||||||
# executive. If left blank a4wide will be used.
|
|
||||||
|
|
||||||
PAPER_TYPE = a4wide
|
|
||||||
|
|
||||||
# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
|
|
||||||
# packages that should be included in the LaTeX output.
|
|
||||||
|
|
||||||
EXTRA_PACKAGES =
|
|
||||||
|
|
||||||
# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
|
|
||||||
# the generated latex document. The header should contain everything until
|
|
||||||
# the first chapter. If it is left blank doxygen will generate a
|
|
||||||
# standard header. Notice: only use this tag if you know what you are doing!
|
|
||||||
|
|
||||||
LATEX_HEADER =
|
|
||||||
|
|
||||||
# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for
|
|
||||||
# the generated latex document. The footer should contain everything after
|
|
||||||
# the last chapter. If it is left blank doxygen will generate a
|
|
||||||
# standard footer. Notice: only use this tag if you know what you are doing!
|
|
||||||
|
|
||||||
LATEX_FOOTER =
|
|
||||||
|
|
||||||
# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
|
|
||||||
# is prepared for conversion to pdf (using ps2pdf). The pdf file will
|
|
||||||
# contain links (just like the HTML output) instead of page references
|
|
||||||
# This makes the output suitable for online browsing using a pdf viewer.
|
|
||||||
|
|
||||||
PDF_HYPERLINKS = YES
|
|
||||||
|
|
||||||
# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
|
|
||||||
# plain latex in the generated Makefile. Set this option to YES to get a
|
|
||||||
# higher quality PDF documentation.
|
|
||||||
|
|
||||||
USE_PDFLATEX = YES
|
|
||||||
|
|
||||||
# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
|
|
||||||
# command to the generated LaTeX files. This will instruct LaTeX to keep
|
|
||||||
# running if errors occur, instead of asking the user for help.
|
|
||||||
# This option is also used when generating formulas in HTML.
|
|
||||||
|
|
||||||
LATEX_BATCHMODE = NO
|
|
||||||
|
|
||||||
# If LATEX_HIDE_INDICES is set to YES then doxygen will not
|
|
||||||
# include the index chapters (such as File Index, Compound Index, etc.)
|
|
||||||
# in the output.
|
|
||||||
|
|
||||||
LATEX_HIDE_INDICES = NO
|
|
||||||
|
|
||||||
# If LATEX_SOURCE_CODE is set to YES then doxygen will include
|
|
||||||
# source code with syntax highlighting in the LaTeX output.
|
|
||||||
# Note that which sources are shown also depends on other settings
|
|
||||||
# such as SOURCE_BROWSER.
|
|
||||||
|
|
||||||
LATEX_SOURCE_CODE = NO
|
|
||||||
|
|
||||||
# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
|
|
||||||
# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See
|
|
||||||
# http://en.wikipedia.org/wiki/BibTeX for more info.
|
|
||||||
|
|
||||||
LATEX_BIB_STYLE = plain
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------
|
|
||||||
# configuration options related to the RTF output
|
|
||||||
#---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
|
|
||||||
# The RTF output is optimized for Word 97 and may not look very pretty with
|
|
||||||
# other RTF readers or editors.
|
|
||||||
|
|
||||||
GENERATE_RTF = NO
|
|
||||||
|
|
||||||
# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
|
|
||||||
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
|
|
||||||
# put in front of it. If left blank `rtf' will be used as the default path.
|
|
||||||
|
|
||||||
RTF_OUTPUT = rtf
|
|
||||||
|
|
||||||
# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
|
|
||||||
# RTF documents. This may be useful for small projects and may help to
|
|
||||||
# save some trees in general.
|
|
||||||
|
|
||||||
COMPACT_RTF = NO
|
|
||||||
|
|
||||||
# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
|
|
||||||
# will contain hyperlink fields. The RTF file will
|
|
||||||
# contain links (just like the HTML output) instead of page references.
|
|
||||||
# This makes the output suitable for online browsing using WORD or other
|
|
||||||
# programs which support those fields.
|
|
||||||
# Note: wordpad (write) and others do not support links.
|
|
||||||
|
|
||||||
RTF_HYPERLINKS = NO
|
|
||||||
|
|
||||||
# Load style sheet definitions from file. Syntax is similar to doxygen's
|
|
||||||
# config file, i.e. a series of assignments. You only have to provide
|
|
||||||
# replacements, missing definitions are set to their default value.
|
|
||||||
|
|
||||||
RTF_STYLESHEET_FILE =
|
|
||||||
|
|
||||||
# Set optional variables used in the generation of an rtf document.
|
|
||||||
# Syntax is similar to doxygen's config file.
|
|
||||||
|
|
||||||
RTF_EXTENSIONS_FILE =
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------
|
|
||||||
# configuration options related to the man page output
|
|
||||||
#---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
|
|
||||||
# generate man pages
|
|
||||||
|
|
||||||
GENERATE_MAN = NO
|
|
||||||
|
|
||||||
# The MAN_OUTPUT tag is used to specify where the man pages will be put.
|
|
||||||
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
|
|
||||||
# put in front of it. If left blank `man' will be used as the default path.
|
|
||||||
|
|
||||||
MAN_OUTPUT = man
|
|
||||||
|
|
||||||
# The MAN_EXTENSION tag determines the extension that is added to
|
|
||||||
# the generated man pages (default is the subroutine's section .3)
|
|
||||||
|
|
||||||
MAN_EXTENSION = .3
|
|
||||||
|
|
||||||
# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
|
|
||||||
# then it will generate one additional man file for each entity
|
|
||||||
# documented in the real man page(s). These additional files
|
|
||||||
# only source the real man page, but without them the man command
|
|
||||||
# would be unable to find the correct page. The default is NO.
|
|
||||||
|
|
||||||
MAN_LINKS = NO
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------
|
|
||||||
# configuration options related to the XML output
|
|
||||||
#---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
# If the GENERATE_XML tag is set to YES Doxygen will
|
|
||||||
# generate an XML file that captures the structure of
|
|
||||||
# the code including all documentation.
|
|
||||||
|
|
||||||
GENERATE_XML = NO
|
|
||||||
|
|
||||||
# The XML_OUTPUT tag is used to specify where the XML pages will be put.
|
|
||||||
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
|
|
||||||
# put in front of it. If left blank `xml' will be used as the default path.
|
|
||||||
|
|
||||||
XML_OUTPUT = xml
|
|
||||||
|
|
||||||
# The XML_SCHEMA tag can be used to specify an XML schema,
|
|
||||||
# which can be used by a validating XML parser to check the
|
|
||||||
# syntax of the XML files.
|
|
||||||
|
|
||||||
XML_SCHEMA =
|
|
||||||
|
|
||||||
# The XML_DTD tag can be used to specify an XML DTD,
|
|
||||||
# which can be used by a validating XML parser to check the
|
|
||||||
# syntax of the XML files.
|
|
||||||
|
|
||||||
XML_DTD =
|
|
||||||
|
|
||||||
# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
|
|
||||||
# dump the program listings (including syntax highlighting
|
|
||||||
# and cross-referencing information) to the XML output. Note that
|
|
||||||
# enabling this will significantly increase the size of the XML output.
|
|
||||||
|
|
||||||
XML_PROGRAMLISTING = YES
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------
|
|
||||||
# configuration options for the AutoGen Definitions output
|
|
||||||
#---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
|
|
||||||
# generate an AutoGen Definitions (see autogen.sf.net) file
|
|
||||||
# that captures the structure of the code including all
|
|
||||||
# documentation. Note that this feature is still experimental
|
|
||||||
# and incomplete at the moment.
|
|
||||||
|
|
||||||
GENERATE_AUTOGEN_DEF = NO
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------
|
|
||||||
# configuration options related to the Perl module output
|
|
||||||
#---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
# If the GENERATE_PERLMOD tag is set to YES Doxygen will
|
|
||||||
# generate a Perl module file that captures the structure of
|
|
||||||
# the code including all documentation. Note that this
|
|
||||||
# feature is still experimental and incomplete at the
|
|
||||||
# moment.
|
|
||||||
|
|
||||||
GENERATE_PERLMOD = NO
|
|
||||||
|
|
||||||
# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
|
|
||||||
# the necessary Makefile rules, Perl scripts and LaTeX code to be able
|
|
||||||
# to generate PDF and DVI output from the Perl module output.
|
|
||||||
|
|
||||||
PERLMOD_LATEX = NO
|
|
||||||
|
|
||||||
# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
|
|
||||||
# nicely formatted so it can be parsed by a human reader.
|
|
||||||
# This is useful
|
|
||||||
# if you want to understand what is going on.
|
|
||||||
# On the other hand, if this
|
|
||||||
# tag is set to NO the size of the Perl module output will be much smaller
|
|
||||||
# and Perl will parse it just the same.
|
|
||||||
|
|
||||||
PERLMOD_PRETTY = YES
|
|
||||||
|
|
||||||
# The names of the make variables in the generated doxyrules.make file
|
|
||||||
# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
|
|
||||||
# This is useful so different doxyrules.make files included by the same
|
|
||||||
# Makefile don't overwrite each other's variables.
|
|
||||||
|
|
||||||
PERLMOD_MAKEVAR_PREFIX =
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------
|
|
||||||
# Configuration options related to the preprocessor
|
|
||||||
#---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
|
|
||||||
# evaluate all C-preprocessor directives found in the sources and include
|
|
||||||
# files.
|
|
||||||
|
|
||||||
ENABLE_PREPROCESSING = YES
|
|
||||||
|
|
||||||
# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
|
|
||||||
# names in the source code. If set to NO (the default) only conditional
|
|
||||||
# compilation will be performed. Macro expansion can be done in a controlled
|
|
||||||
# way by setting EXPAND_ONLY_PREDEF to YES.
|
|
||||||
|
|
||||||
MACRO_EXPANSION = YES
|
|
||||||
|
|
||||||
# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
|
|
||||||
# then the macro expansion is limited to the macros specified with the
|
|
||||||
# PREDEFINED and EXPAND_AS_DEFINED tags.
|
|
||||||
|
|
||||||
EXPAND_ONLY_PREDEF = YES
|
|
||||||
|
|
||||||
# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
|
|
||||||
# pointed to by INCLUDE_PATH will be searched when a #include is found.
|
|
||||||
|
|
||||||
SEARCH_INCLUDES = YES
|
|
||||||
|
|
||||||
# The INCLUDE_PATH tag can be used to specify one or more directories that
|
|
||||||
# contain include files that are not input files but should be processed by
|
|
||||||
# the preprocessor.
|
|
||||||
|
|
||||||
INCLUDE_PATH =
|
|
||||||
|
|
||||||
# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
|
|
||||||
# patterns (like *.h and *.hpp) to filter out the header-files in the
|
|
||||||
# directories. If left blank, the patterns specified with FILE_PATTERNS will
|
|
||||||
# be used.
|
|
||||||
|
|
||||||
INCLUDE_FILE_PATTERNS =
|
|
||||||
|
|
||||||
# The PREDEFINED tag can be used to specify one or more macro names that
|
|
||||||
# are defined before the preprocessor is started (similar to the -D option of
|
|
||||||
# gcc). The argument of the tag is a list of macros of the form: name
|
|
||||||
# or name=definition (no spaces). If the definition and the = are
|
|
||||||
# omitted =1 is assumed. To prevent a macro definition from being
|
|
||||||
# undefined via #undef or recursively expanded use the := operator
|
|
||||||
# instead of the = operator.
|
|
||||||
|
|
||||||
PREDEFINED = __DOXYGEN__ \
|
|
||||||
PROGMEM
|
|
||||||
|
|
||||||
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
|
|
||||||
# this tag can be used to specify a list of macro names that should be expanded.
|
|
||||||
# The macro definition that is found in the sources will be used.
|
|
||||||
# Use the PREDEFINED tag if you want to use a different macro definition that
|
|
||||||
# overrules the definition found in the source code.
|
|
||||||
|
|
||||||
EXPAND_AS_DEFINED =
|
|
||||||
|
|
||||||
# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
|
|
||||||
# doxygen's preprocessor will remove all references to function-like macros
|
|
||||||
# that are alone on a line, have an all uppercase name, and do not end with a
|
|
||||||
# semicolon, because these will confuse the parser if not removed.
|
|
||||||
|
|
||||||
SKIP_FUNCTION_MACROS = YES
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------
|
|
||||||
# Configuration::additions related to external references
|
|
||||||
#---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
# The TAGFILES option can be used to specify one or more tagfiles. For each
|
|
||||||
# tag file the location of the external documentation should be added. The
|
|
||||||
# format of a tag file without this location is as follows:
|
|
||||||
#
|
|
||||||
# TAGFILES = file1 file2 ...
|
|
||||||
# Adding location for the tag files is done as follows:
|
|
||||||
#
|
|
||||||
# TAGFILES = file1=loc1 "file2 = loc2" ...
|
|
||||||
# where "loc1" and "loc2" can be relative or absolute paths
|
|
||||||
# or URLs. Note that each tag file must have a unique name (where the name does
|
|
||||||
# NOT include the path). If a tag file is not located in the directory in which
|
|
||||||
# doxygen is run, you must also specify the path to the tagfile here.
|
|
||||||
|
|
||||||
TAGFILES =
|
|
||||||
|
|
||||||
# When a file name is specified after GENERATE_TAGFILE, doxygen will create
|
|
||||||
# a tag file that is based on the input files it reads.
|
|
||||||
|
|
||||||
GENERATE_TAGFILE =
|
|
||||||
|
|
||||||
# If the ALLEXTERNALS tag is set to YES all external classes will be listed
|
|
||||||
# in the class index. If set to NO only the inherited external classes
|
|
||||||
# will be listed.
|
|
||||||
|
|
||||||
ALLEXTERNALS = NO
|
|
||||||
|
|
||||||
# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
|
|
||||||
# in the modules index. If set to NO, only the current project's groups will
|
|
||||||
# be listed.
|
|
||||||
|
|
||||||
EXTERNAL_GROUPS = YES
|
|
||||||
|
|
||||||
# The PERL_PATH should be the absolute path and name of the perl script
|
|
||||||
# interpreter (i.e. the result of `which perl').
|
|
||||||
|
|
||||||
PERL_PATH = /usr/bin/perl
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------
|
|
||||||
# Configuration options related to the dot tool
|
|
||||||
#---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
|
|
||||||
# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
|
|
||||||
# or super classes. Setting the tag to NO turns the diagrams off. Note that
|
|
||||||
# this option also works with HAVE_DOT disabled, but it is recommended to
|
|
||||||
# install and use dot, since it yields more powerful graphs.
|
|
||||||
|
|
||||||
CLASS_DIAGRAMS = NO
|
|
||||||
|
|
||||||
# You can define message sequence charts within doxygen comments using the \msc
|
|
||||||
# command. Doxygen will then run the mscgen tool (see
|
|
||||||
# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
|
|
||||||
# documentation. The MSCGEN_PATH tag allows you to specify the directory where
|
|
||||||
# the mscgen tool resides. If left empty the tool is assumed to be found in the
|
|
||||||
# default search path.
|
|
||||||
|
|
||||||
MSCGEN_PATH =
|
|
||||||
|
|
||||||
# If set to YES, the inheritance and collaboration graphs will hide
|
|
||||||
# inheritance and usage relations if the target is undocumented
|
|
||||||
# or is not a class.
|
|
||||||
|
|
||||||
HIDE_UNDOC_RELATIONS = YES
|
|
||||||
|
|
||||||
# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
|
|
||||||
# available from the path. This tool is part of Graphviz, a graph visualization
|
|
||||||
# toolkit from AT&T and Lucent Bell Labs. The other options in this section
|
|
||||||
# have no effect if this option is set to NO (the default)
|
|
||||||
|
|
||||||
HAVE_DOT = NO
|
|
||||||
|
|
||||||
# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
|
|
||||||
# allowed to run in parallel. When set to 0 (the default) doxygen will
|
|
||||||
# base this on the number of processors available in the system. You can set it
|
|
||||||
# explicitly to a value larger than 0 to get control over the balance
|
|
||||||
# between CPU load and processing speed.
|
|
||||||
|
|
||||||
DOT_NUM_THREADS = 0
|
|
||||||
|
|
||||||
# By default doxygen will use the Helvetica font for all dot files that
|
|
||||||
# doxygen generates. When you want a differently looking font you can specify
|
|
||||||
# the font name using DOT_FONTNAME. You need to make sure dot is able to find
|
|
||||||
# the font, which can be done by putting it in a standard location or by setting
|
|
||||||
# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
|
|
||||||
# directory containing the font.
|
|
||||||
|
|
||||||
DOT_FONTNAME = FreeSans
|
|
||||||
|
|
||||||
# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
|
|
||||||
# The default size is 10pt.
|
|
||||||
|
|
||||||
DOT_FONTSIZE = 10
|
|
||||||
|
|
||||||
# By default doxygen will tell dot to use the Helvetica font.
|
|
||||||
# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to
|
|
||||||
# set the path where dot can find it.
|
|
||||||
|
|
||||||
DOT_FONTPATH =
|
|
||||||
|
|
||||||
# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
|
|
||||||
# will generate a graph for each documented class showing the direct and
|
|
||||||
# indirect inheritance relations. Setting this tag to YES will force the
|
|
||||||
# CLASS_DIAGRAMS tag to NO.
|
|
||||||
|
|
||||||
CLASS_GRAPH = NO
|
|
||||||
|
|
||||||
# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
|
|
||||||
# will generate a graph for each documented class showing the direct and
|
|
||||||
# indirect implementation dependencies (inheritance, containment, and
|
|
||||||
# class references variables) of the class with other documented classes.
|
|
||||||
|
|
||||||
COLLABORATION_GRAPH = NO
|
|
||||||
|
|
||||||
# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
|
|
||||||
# will generate a graph for groups, showing the direct groups dependencies
|
|
||||||
|
|
||||||
GROUP_GRAPHS = NO
|
|
||||||
|
|
||||||
# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
|
|
||||||
# collaboration diagrams in a style similar to the OMG's Unified Modeling
|
|
||||||
# Language.
|
|
||||||
|
|
||||||
UML_LOOK = NO
|
|
||||||
|
|
||||||
# If the UML_LOOK tag is enabled, the fields and methods are shown inside
|
|
||||||
# the class node. If there are many fields or methods and many nodes the
|
|
||||||
# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS
|
|
||||||
# threshold limits the number of items for each type to make the size more
|
|
||||||
# managable. Set this to 0 for no limit. Note that the threshold may be
|
|
||||||
# exceeded by 50% before the limit is enforced.
|
|
||||||
|
|
||||||
UML_LIMIT_NUM_FIELDS = 10
|
|
||||||
|
|
||||||
# If set to YES, the inheritance and collaboration graphs will show the
|
|
||||||
# relations between templates and their instances.
|
|
||||||
|
|
||||||
TEMPLATE_RELATIONS = NO
|
|
||||||
|
|
||||||
# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
|
|
||||||
# tags are set to YES then doxygen will generate a graph for each documented
|
|
||||||
# file showing the direct and indirect include dependencies of the file with
|
|
||||||
# other documented files.
|
|
||||||
|
|
||||||
INCLUDE_GRAPH = NO
|
|
||||||
|
|
||||||
# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
|
|
||||||
# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
|
|
||||||
# documented header file showing the documented files that directly or
|
|
||||||
# indirectly include this file.
|
|
||||||
|
|
||||||
INCLUDED_BY_GRAPH = NO
|
|
||||||
|
|
||||||
# If the CALL_GRAPH and HAVE_DOT options are set to YES then
|
|
||||||
# doxygen will generate a call dependency graph for every global function
|
|
||||||
# or class method. Note that enabling this option will significantly increase
|
|
||||||
# the time of a run. So in most cases it will be better to enable call graphs
|
|
||||||
# for selected functions only using the \callgraph command.
|
|
||||||
|
|
||||||
CALL_GRAPH = NO
|
|
||||||
|
|
||||||
# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
|
|
||||||
# doxygen will generate a caller dependency graph for every global function
|
|
||||||
# or class method. Note that enabling this option will significantly increase
|
|
||||||
# the time of a run. So in most cases it will be better to enable caller
|
|
||||||
# graphs for selected functions only using the \callergraph command.
|
|
||||||
|
|
||||||
CALLER_GRAPH = NO
|
|
||||||
|
|
||||||
# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
|
|
||||||
# will generate a graphical hierarchy of all classes instead of a textual one.
|
|
||||||
|
|
||||||
GRAPHICAL_HIERARCHY = NO
|
|
||||||
|
|
||||||
# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
|
|
||||||
# then doxygen will show the dependencies a directory has on other directories
|
|
||||||
# in a graphical way. The dependency relations are determined by the #include
|
|
||||||
# relations between the files in the directories.
|
|
||||||
|
|
||||||
DIRECTORY_GRAPH = NO
|
|
||||||
|
|
||||||
# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
|
|
||||||
# generated by dot. Possible values are svg, png, jpg, or gif.
|
|
||||||
# If left blank png will be used. If you choose svg you need to set
|
|
||||||
# HTML_FILE_EXTENSION to xhtml in order to make the SVG files
|
|
||||||
# visible in IE 9+ (other browsers do not have this requirement).
|
|
||||||
|
|
||||||
DOT_IMAGE_FORMAT = png
|
|
||||||
|
|
||||||
# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
|
|
||||||
# enable generation of interactive SVG images that allow zooming and panning.
|
|
||||||
# Note that this requires a modern browser other than Internet Explorer.
|
|
||||||
# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you
|
|
||||||
# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files
|
|
||||||
# visible. Older versions of IE do not have SVG support.
|
|
||||||
|
|
||||||
INTERACTIVE_SVG = NO
|
|
||||||
|
|
||||||
# The tag DOT_PATH can be used to specify the path where the dot tool can be
|
|
||||||
# found. If left blank, it is assumed the dot tool can be found in the path.
|
|
||||||
|
|
||||||
DOT_PATH =
|
|
||||||
|
|
||||||
# The DOTFILE_DIRS tag can be used to specify one or more directories that
|
|
||||||
# contain dot files that are included in the documentation (see the
|
|
||||||
# \dotfile command).
|
|
||||||
|
|
||||||
DOTFILE_DIRS =
|
|
||||||
|
|
||||||
# The MSCFILE_DIRS tag can be used to specify one or more directories that
|
|
||||||
# contain msc files that are included in the documentation (see the
|
|
||||||
# \mscfile command).
|
|
||||||
|
|
||||||
MSCFILE_DIRS =
|
|
||||||
|
|
||||||
# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
|
|
||||||
# nodes that will be shown in the graph. If the number of nodes in a graph
|
|
||||||
# becomes larger than this value, doxygen will truncate the graph, which is
|
|
||||||
# visualized by representing a node as a red box. Note that doxygen if the
|
|
||||||
# number of direct children of the root node in a graph is already larger than
|
|
||||||
# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
|
|
||||||
# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
|
|
||||||
|
|
||||||
DOT_GRAPH_MAX_NODES = 15
|
|
||||||
|
|
||||||
# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
|
|
||||||
# graphs generated by dot. A depth value of 3 means that only nodes reachable
|
|
||||||
# from the root by following a path via at most 3 edges will be shown. Nodes
|
|
||||||
# that lay further from the root node will be omitted. Note that setting this
|
|
||||||
# option to 1 or 2 may greatly reduce the computation time needed for large
|
|
||||||
# code bases. Also note that the size of a graph can be further restricted by
|
|
||||||
# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
|
|
||||||
|
|
||||||
MAX_DOT_GRAPH_DEPTH = 2
|
|
||||||
|
|
||||||
# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
|
|
||||||
# background. This is disabled by default, because dot on Windows does not
|
|
||||||
# seem to support this out of the box. Warning: Depending on the platform used,
|
|
||||||
# enabling this option may lead to badly anti-aliased labels on the edges of
|
|
||||||
# a graph (i.e. they become hard to read).
|
|
||||||
|
|
||||||
DOT_TRANSPARENT = YES
|
|
||||||
|
|
||||||
# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
|
|
||||||
# files in one run (i.e. multiple -o and -T options on the command line). This
|
|
||||||
# makes dot run faster, but since only newer versions of dot (>1.8.10)
|
|
||||||
# support this, this feature is disabled by default.
|
|
||||||
|
|
||||||
DOT_MULTI_TARGETS = NO
|
|
||||||
|
|
||||||
# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
|
|
||||||
# generate a legend page explaining the meaning of the various boxes and
|
|
||||||
# arrows in the dot generated graphs.
|
|
||||||
|
|
||||||
GENERATE_LEGEND = YES
|
|
||||||
|
|
||||||
# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
|
|
||||||
# remove the intermediate dot files that are used to generate
|
|
||||||
# the various graphs.
|
|
||||||
|
|
||||||
DOT_CLEANUP = YES
|
|
@ -1,809 +0,0 @@
|
|||||||
/*
|
|
||||||
LUFA Library
|
|
||||||
Copyright (C) Dean Camera, 2012.
|
|
||||||
|
|
||||||
dean [at] fourwalledcubicle [dot] com
|
|
||||||
www.lufa-lib.org
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright 2012 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
|
||||||
|
|
||||||
Permission to use, copy, modify, distribute, and sell this
|
|
||||||
software and its documentation for any purpose is hereby granted
|
|
||||||
without fee, provided that the above copyright notice appear in
|
|
||||||
all copies and that both that the copyright notice and this
|
|
||||||
permission notice and warranty disclaimer appear in supporting
|
|
||||||
documentation, and that the name of the author not be used in
|
|
||||||
advertising or publicity pertaining to distribution of the
|
|
||||||
software without specific, written prior permission.
|
|
||||||
|
|
||||||
The author disclaim all warranties with regard to this
|
|
||||||
software, including all implied warranties of merchantability
|
|
||||||
and fitness. In no event shall the author be liable for any
|
|
||||||
special, indirect or consequential damages or any damages
|
|
||||||
whatsoever resulting from loss of use, data or profits, whether
|
|
||||||
in an action of contract, negligence or other tortious action,
|
|
||||||
arising out of or in connection with the use or performance of
|
|
||||||
this software.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** \file
|
|
||||||
*
|
|
||||||
* Bluetooth L2CAP layer management code. This module managed the creation,
|
|
||||||
* configuration and teardown of L2CAP channels, and manages packet reception
|
|
||||||
* and sending to and from other Bluetooth devices.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
TODO: Make SendPacket respect receiver's MTU
|
|
||||||
TODO: Make ReceivePacket stitch together MTU fragments (?)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define INCLUDE_FROM_BLUETOOTH_ACLPACKETS_C
|
|
||||||
#include "BluetoothACLPackets.h"
|
|
||||||
|
|
||||||
/** Bluetooth ACL processing task. This task should be called repeatedly the main Bluetooth
|
|
||||||
* stack task to manage the ACL processing state.
|
|
||||||
*/
|
|
||||||
void Bluetooth_ACLTask(void)
|
|
||||||
{
|
|
||||||
/* Process incoming ACL packets, if any */
|
|
||||||
Bluetooth_ProcessIncomingACLPackets();
|
|
||||||
|
|
||||||
/* Check for any half-open channels, send configuration details to the remote device if found */
|
|
||||||
for (uint8_t i = 0; i < BLUETOOTH_MAX_OPEN_CHANNELS; i++)
|
|
||||||
{
|
|
||||||
Bluetooth_Channel_t* ChannelData = &Bluetooth_Connection.Channels[i];
|
|
||||||
|
|
||||||
bool MustSendConfigReq = true;
|
|
||||||
|
|
||||||
/* Check if we are in a channel state which requires a configuration request to be sent */
|
|
||||||
switch (ChannelData->State)
|
|
||||||
{
|
|
||||||
case BT_Channel_Config_WaitConfig:
|
|
||||||
ChannelData->State = BT_Channel_Config_WaitReqResp;
|
|
||||||
break;
|
|
||||||
case BT_Channel_Config_WaitSendConfig:
|
|
||||||
ChannelData->State = BT_Channel_Config_WaitResp;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
MustSendConfigReq = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Only send a configuration request if it the channel was in a state which required it */
|
|
||||||
if (MustSendConfigReq)
|
|
||||||
{
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
BT_Signal_Header_t SignalCommandHeader;
|
|
||||||
BT_Signal_ConfigurationReq_t ConfigurationRequest;
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
BT_Config_Option_Header_t Header;
|
|
||||||
uint16_t Value;
|
|
||||||
} Option_LocalMTU;
|
|
||||||
} PacketData;
|
|
||||||
|
|
||||||
/* Fill out the Signal Command header in the response packet */
|
|
||||||
PacketData.SignalCommandHeader.Code = BT_SIGNAL_CONFIGURATION_REQUEST;
|
|
||||||
PacketData.SignalCommandHeader.Identifier = ++Bluetooth_Connection.SignalingIdentifier;
|
|
||||||
PacketData.SignalCommandHeader.Length = sizeof(PacketData.ConfigurationRequest) +
|
|
||||||
sizeof(PacketData.Option_LocalMTU);
|
|
||||||
|
|
||||||
/* Fill out the Configuration Request in the response packet, including local MTU information */
|
|
||||||
PacketData.ConfigurationRequest.DestinationChannel = ChannelData->RemoteNumber;
|
|
||||||
PacketData.ConfigurationRequest.Flags = 0;
|
|
||||||
PacketData.Option_LocalMTU.Header.Type = BT_CONFIG_OPTION_MTU;
|
|
||||||
PacketData.Option_LocalMTU.Header.Length = sizeof(PacketData.Option_LocalMTU.Value);
|
|
||||||
PacketData.Option_LocalMTU.Value = ChannelData->LocalMTU;
|
|
||||||
|
|
||||||
Bluetooth_SendPacket(&PacketData, sizeof(PacketData), NULL);
|
|
||||||
|
|
||||||
BT_ACL_DEBUG(1, ">> L2CAP Configuration Request");
|
|
||||||
BT_ACL_DEBUG(2, "-- Destination Channel: 0x%04X", PacketData.ConfigurationRequest.DestinationChannel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Incoming ACL packet processing task. This task is called by the main ACL processing task to read in and process
|
|
||||||
* any incoming ACL packets to the device, handling signal requests as they are received or passing along channel
|
|
||||||
* data to the user application.
|
|
||||||
*/
|
|
||||||
static void Bluetooth_ProcessIncomingACLPackets(void)
|
|
||||||
{
|
|
||||||
BT_ACL_Header_t ACLPacketHeader;
|
|
||||||
BT_DataPacket_Header_t DataHeader;
|
|
||||||
|
|
||||||
Pipe_SelectPipe(BLUETOOTH_DATA_IN_PIPE);
|
|
||||||
Pipe_Unfreeze();
|
|
||||||
|
|
||||||
if (!(Pipe_IsReadWriteAllowed()))
|
|
||||||
{
|
|
||||||
Pipe_Freeze();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read in the received ACL packet headers when it has been discovered that a packet has been received */
|
|
||||||
Pipe_Read_Stream_LE(&ACLPacketHeader, sizeof(ACLPacketHeader), NULL);
|
|
||||||
Pipe_Read_Stream_LE(&DataHeader, sizeof(DataHeader), NULL);
|
|
||||||
|
|
||||||
BT_ACL_DEBUG(2, "");
|
|
||||||
BT_ACL_DEBUG(2, "Packet Received");
|
|
||||||
BT_ACL_DEBUG(2, "-- Connection Handle: 0x%04X", (ACLPacketHeader.ConnectionHandle & 0x0FFF));
|
|
||||||
BT_ACL_DEBUG(2, "-- Data Length: 0x%04X", ACLPacketHeader.DataLength);
|
|
||||||
BT_ACL_DEBUG(2, "-- Destination Channel: 0x%04X", DataHeader.DestinationChannel);
|
|
||||||
BT_ACL_DEBUG(2, "-- Payload Length: 0x%04X", DataHeader.PayloadLength);
|
|
||||||
|
|
||||||
/* Check the packet's destination channel - signaling channel should be processed by the stack internally */
|
|
||||||
if (DataHeader.DestinationChannel == BT_CHANNEL_SIGNALING)
|
|
||||||
{
|
|
||||||
/* Read in the Signal Command header of the incoming packet */
|
|
||||||
BT_Signal_Header_t SignalCommandHeader;
|
|
||||||
Pipe_Read_Stream_LE(&SignalCommandHeader, sizeof(SignalCommandHeader), NULL);
|
|
||||||
|
|
||||||
/* Dispatch to the appropriate handler function based on the Signal message code */
|
|
||||||
switch (SignalCommandHeader.Code)
|
|
||||||
{
|
|
||||||
case BT_SIGNAL_CONNECTION_REQUEST:
|
|
||||||
Bluetooth_Signal_ConnectionReq(&SignalCommandHeader);
|
|
||||||
break;
|
|
||||||
case BT_SIGNAL_CONNECTION_RESPONSE:
|
|
||||||
Bluetooth_Signal_ConnectionResp(&SignalCommandHeader);
|
|
||||||
break;
|
|
||||||
case BT_SIGNAL_CONFIGURATION_REQUEST:
|
|
||||||
Bluetooth_Signal_ConfigurationReq(&SignalCommandHeader);
|
|
||||||
break;
|
|
||||||
case BT_SIGNAL_CONFIGURATION_RESPONSE:
|
|
||||||
Bluetooth_Signal_ConfigurationResp(&SignalCommandHeader);
|
|
||||||
break;
|
|
||||||
case BT_SIGNAL_DISCONNECTION_REQUEST:
|
|
||||||
Bluetooth_Signal_DisconnectionReq(&SignalCommandHeader);
|
|
||||||
break;
|
|
||||||
case BT_SIGNAL_DISCONNECTION_RESPONSE:
|
|
||||||
Bluetooth_Signal_DisconnectionResp(&SignalCommandHeader);
|
|
||||||
break;
|
|
||||||
case BT_SIGNAL_ECHO_REQUEST:
|
|
||||||
Bluetooth_Signal_EchoReq(&SignalCommandHeader);
|
|
||||||
break;
|
|
||||||
case BT_SIGNAL_INFORMATION_REQUEST:
|
|
||||||
Bluetooth_Signal_InformationReq(&SignalCommandHeader);
|
|
||||||
break;
|
|
||||||
case BT_SIGNAL_COMMAND_REJECT:
|
|
||||||
BT_ACL_DEBUG(1, "<< Command Reject");
|
|
||||||
|
|
||||||
uint16_t RejectReason;
|
|
||||||
Pipe_Read_Stream_LE(&RejectReason, sizeof(RejectReason), NULL);
|
|
||||||
Pipe_Discard_Stream(ACLPacketHeader.DataLength - sizeof(RejectReason), NULL);
|
|
||||||
Pipe_ClearIN();
|
|
||||||
Pipe_Freeze();
|
|
||||||
|
|
||||||
BT_ACL_DEBUG(2, "-- Reason: %d", RejectReason);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
BT_ACL_DEBUG(1, "<< Unknown Signaling Command 0x%02X", SignalCommandHeader.Code);
|
|
||||||
|
|
||||||
Pipe_Discard_Stream(ACLPacketHeader.DataLength, NULL);
|
|
||||||
Pipe_ClearIN();
|
|
||||||
Pipe_Freeze();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Non-signaling packet received, read in the packet contents and pass to the user application */
|
|
||||||
uint8_t PacketData[DataHeader.PayloadLength];
|
|
||||||
Pipe_Read_Stream_LE(PacketData, DataHeader.PayloadLength, NULL);
|
|
||||||
Pipe_ClearIN();
|
|
||||||
Pipe_Freeze();
|
|
||||||
|
|
||||||
Bluetooth_PacketReceived(PacketData, DataHeader.PayloadLength,
|
|
||||||
Bluetooth_GetChannelData(DataHeader.DestinationChannel, CHANNEL_SEARCH_LOCALNUMBER));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Retrieves the channel information structure with the given local or remote channel number from the channel list.
|
|
||||||
*
|
|
||||||
* \param[in] SearchValue Value to search for in the channel structure list
|
|
||||||
* \param[in] SearchKey Key to search within the channel structure, a \c CHANNEL_SEARCH_* mask
|
|
||||||
*
|
|
||||||
* \return Pointer to the matching channel information structure in the channel table if found, NULL otherwise
|
|
||||||
*/
|
|
||||||
Bluetooth_Channel_t* Bluetooth_GetChannelData(const uint16_t SearchValue,
|
|
||||||
const uint8_t SearchKey)
|
|
||||||
{
|
|
||||||
for (uint8_t i = 0; i < BLUETOOTH_MAX_OPEN_CHANNELS; i++)
|
|
||||||
{
|
|
||||||
Bluetooth_Channel_t* ChannelData = &Bluetooth_Connection.Channels[i];
|
|
||||||
|
|
||||||
/* Closed channels should be ignored as they are not considered valid data */
|
|
||||||
if (ChannelData->State == BT_Channel_Closed)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
bool FoundMatch = false;
|
|
||||||
|
|
||||||
/* Search the current channel for the search key to see if it matches */
|
|
||||||
switch (SearchKey)
|
|
||||||
{
|
|
||||||
case CHANNEL_SEARCH_LOCALNUMBER:
|
|
||||||
FoundMatch = (SearchValue == ChannelData->LocalNumber);
|
|
||||||
break;
|
|
||||||
case CHANNEL_SEARCH_REMOTENUMBER:
|
|
||||||
FoundMatch = (SearchValue == ChannelData->RemoteNumber);
|
|
||||||
break;
|
|
||||||
case CHANNEL_SEARCH_PSM:
|
|
||||||
FoundMatch = (SearchValue == ChannelData->PSM);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FoundMatch)
|
|
||||||
return ChannelData;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Sends a packet to the remote device on the specified channel.
|
|
||||||
*
|
|
||||||
* \param[in] Data Pointer to a buffer where the data is to be sourced from
|
|
||||||
* \param[in] DataLen Length of the data to send
|
|
||||||
* \param[in] ACLChannel ACL channel information structure containing the destination channel's information, NULL
|
|
||||||
* to send to the remote device's signaling channel
|
|
||||||
*
|
|
||||||
* \return A value from the \ref BT_SendPacket_ErrorCodes_t enum
|
|
||||||
*/
|
|
||||||
uint8_t Bluetooth_SendPacket(void* Data,
|
|
||||||
const uint16_t DataLen,
|
|
||||||
Bluetooth_Channel_t* const ACLChannel)
|
|
||||||
{
|
|
||||||
BT_ACL_Header_t ACLPacketHeader;
|
|
||||||
BT_DataPacket_Header_t DataHeader;
|
|
||||||
|
|
||||||
/* A remote device must be connected before a packet transmission is attempted */
|
|
||||||
if (!(Bluetooth_Connection.IsConnected))
|
|
||||||
return BT_SENDPACKET_NotConnected;
|
|
||||||
|
|
||||||
/* If the destination channel is not the signaling channel and it is not currently fully open, abort */
|
|
||||||
if ((ACLChannel != NULL) && (ACLChannel->State != BT_Channel_Open))
|
|
||||||
return BT_SENDPACKET_ChannelNotOpen;
|
|
||||||
|
|
||||||
/* Fill out the packet's header from the remote device connection information structure */
|
|
||||||
ACLPacketHeader.ConnectionHandle = (Bluetooth_Connection.ConnectionHandle | BT_ACL_FIRST_AUTOFLUSH);
|
|
||||||
ACLPacketHeader.DataLength = sizeof(DataHeader) + DataLen;
|
|
||||||
DataHeader.PayloadLength = DataLen;
|
|
||||||
DataHeader.DestinationChannel = (ACLChannel == NULL) ? BT_CHANNEL_SIGNALING : ACLChannel->RemoteNumber;
|
|
||||||
|
|
||||||
Pipe_SelectPipe(BLUETOOTH_DATA_OUT_PIPE);
|
|
||||||
|
|
||||||
Pipe_WaitUntilReady();
|
|
||||||
Pipe_Unfreeze();
|
|
||||||
|
|
||||||
/* Write the packet contents to the pipe so that it can be sent to the remote device */
|
|
||||||
Pipe_Write_Stream_LE(&ACLPacketHeader, sizeof(ACLPacketHeader), NULL);
|
|
||||||
Pipe_Write_Stream_LE(&DataHeader, sizeof(DataHeader), NULL);
|
|
||||||
Pipe_Write_Stream_LE(Data, DataLen, NULL);
|
|
||||||
Pipe_ClearOUT();
|
|
||||||
|
|
||||||
Pipe_Freeze();
|
|
||||||
|
|
||||||
BT_ACL_DEBUG(2, "");
|
|
||||||
BT_ACL_DEBUG(2, "Packet Sent");
|
|
||||||
BT_ACL_DEBUG(2, "-- Connection Handle: 0x%04X", (ACLPacketHeader.ConnectionHandle & 0x0FFF));
|
|
||||||
BT_ACL_DEBUG(2, "-- Data Length: 0x%04X", ACLPacketHeader.DataLength);
|
|
||||||
BT_ACL_DEBUG(2, "-- Destination Channel: 0x%04X", DataHeader.DestinationChannel);
|
|
||||||
BT_ACL_DEBUG(2, "-- Payload Length: 0x%04X", DataHeader.PayloadLength);
|
|
||||||
|
|
||||||
return BT_SENDPACKET_NoError;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Opens a Bluetooth channel to the currently connected remote device, so that data can be exchanged.
|
|
||||||
*
|
|
||||||
* \note The channel is not immediately opened when this function returns - it must undergo a two way
|
|
||||||
* connection and configuration process first as the main Bluetooth stack processing task is
|
|
||||||
* repeatedly called. The returned channel is unusable by the user application until its State
|
|
||||||
* element has progressed to the Open state.
|
|
||||||
*
|
|
||||||
* \param[in] PSM PSM of the service that the channel is to be opened for
|
|
||||||
*
|
|
||||||
* \return Pointer to the channel information structure of the opened channel, or NULL if no free channels
|
|
||||||
*/
|
|
||||||
Bluetooth_Channel_t* Bluetooth_OpenChannel(const uint16_t PSM)
|
|
||||||
{
|
|
||||||
Bluetooth_Channel_t* ChannelData = NULL;
|
|
||||||
|
|
||||||
/* Search through the channel information list for a free channel item */
|
|
||||||
for (uint8_t i = 0; i < BLUETOOTH_MAX_OPEN_CHANNELS; i++)
|
|
||||||
{
|
|
||||||
if (Bluetooth_Connection.Channels[i].State == BT_Channel_Closed)
|
|
||||||
{
|
|
||||||
ChannelData = &Bluetooth_Connection.Channels[i];
|
|
||||||
|
|
||||||
/* Set the new channel structure's local channel number to a unique value within the connection orientated
|
|
||||||
channel address space */
|
|
||||||
ChannelData->LocalNumber = (BT_CHANNELNUMBER_BASEOFFSET + i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If no free channel item was found in the list, all channels are occupied - abort */
|
|
||||||
if (ChannelData == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/* Reset and fill out the allocated channel's information structure with defaults */
|
|
||||||
ChannelData->RemoteNumber = 0;
|
|
||||||
ChannelData->PSM = PSM;
|
|
||||||
ChannelData->LocalMTU = MAXIMUM_CHANNEL_MTU;
|
|
||||||
ChannelData->State = BT_Channel_WaitConnectRsp;
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
BT_Signal_Header_t SignalCommandHeader;
|
|
||||||
BT_Signal_ConnectionReq_t ConnectionRequest;
|
|
||||||
} PacketData;
|
|
||||||
|
|
||||||
/* Fill out the Signal Command header in the response packet */
|
|
||||||
PacketData.SignalCommandHeader.Code = BT_SIGNAL_CONNECTION_REQUEST;
|
|
||||||
PacketData.SignalCommandHeader.Identifier = ++Bluetooth_Connection.SignalingIdentifier;
|
|
||||||
PacketData.SignalCommandHeader.Length = sizeof(PacketData.ConnectionRequest);
|
|
||||||
|
|
||||||
/* Fill out the Connection Request in the response packet */
|
|
||||||
PacketData.ConnectionRequest.PSM = PSM;
|
|
||||||
PacketData.ConnectionRequest.SourceChannel = ChannelData->LocalNumber;
|
|
||||||
|
|
||||||
Bluetooth_SendPacket(&PacketData, sizeof(PacketData), NULL);
|
|
||||||
|
|
||||||
BT_ACL_DEBUG(1, ">> L2CAP Connection Request");
|
|
||||||
BT_ACL_DEBUG(2, "-- PSM 0x%04X", PacketData.ConnectionRequest.PSM);
|
|
||||||
BT_ACL_DEBUG(2, "-- Source Channel: 0x%04X", PacketData.ConnectionRequest.SourceChannel);
|
|
||||||
|
|
||||||
return ChannelData;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Closes a Bluetooth channel that is open to the currently connected remote device, so that no further data
|
|
||||||
* can be exchanged.
|
|
||||||
*
|
|
||||||
* \note The channel is not immediately closed when this function returns - it must undergo an asynchronous
|
|
||||||
* disconnection process first as the main Bluetooth stack processing task is repeatedly called. The
|
|
||||||
* returned channel is unusable by the user application upon return however the channel is not completely
|
|
||||||
* closed until its State element has progressed to the Closed state.
|
|
||||||
*
|
|
||||||
* \param[in,out] ACLChannel ACL channel information structure of the channel to close
|
|
||||||
*/
|
|
||||||
void Bluetooth_CloseChannel(Bluetooth_Channel_t* const ACLChannel)
|
|
||||||
{
|
|
||||||
/* Don't try to close a non-existing or already closed channel */
|
|
||||||
if ((ACLChannel == NULL) || (ACLChannel->State == BT_Channel_Closed))
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* Set the channel's state to the start of the teardown process */
|
|
||||||
ACLChannel->State = BT_Channel_WaitDisconnect;
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
BT_Signal_Header_t SignalCommandHeader;
|
|
||||||
BT_Signal_DisconnectionReq_t DisconnectionRequest;
|
|
||||||
} PacketData;
|
|
||||||
|
|
||||||
/* Fill out the Signal Command header in the response packet */
|
|
||||||
PacketData.SignalCommandHeader.Code = BT_SIGNAL_DISCONNECTION_REQUEST;
|
|
||||||
PacketData.SignalCommandHeader.Identifier = ++Bluetooth_Connection.SignalingIdentifier;
|
|
||||||
PacketData.SignalCommandHeader.Length = sizeof(PacketData.DisconnectionRequest);
|
|
||||||
|
|
||||||
/* Fill out the Disconnection Request in the response packet */
|
|
||||||
PacketData.DisconnectionRequest.DestinationChannel = ACLChannel->RemoteNumber;
|
|
||||||
PacketData.DisconnectionRequest.SourceChannel = ACLChannel->LocalNumber;
|
|
||||||
|
|
||||||
Bluetooth_SendPacket(&PacketData, sizeof(PacketData), NULL);
|
|
||||||
|
|
||||||
BT_ACL_DEBUG(1, ">> L2CAP Disconnection Request");
|
|
||||||
BT_ACL_DEBUG(2, "-- Destination Channel: 0x%04X", PacketData.DisconnectionRequest.DestinationChannel);
|
|
||||||
BT_ACL_DEBUG(2, "-- Source Channel: 0x%04X", PacketData.DisconnectionRequest.SourceChannel);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Internal Bluetooth stack Signal Command processing routine for a Connection Request command.
|
|
||||||
*
|
|
||||||
* \param[in] SignalCommandHeader Pointer to the start of the received packet's Signal Command header
|
|
||||||
*/
|
|
||||||
static inline void Bluetooth_Signal_ConnectionReq(const BT_Signal_Header_t* const SignalCommandHeader)
|
|
||||||
{
|
|
||||||
BT_Signal_ConnectionReq_t ConnectionRequest;
|
|
||||||
|
|
||||||
Pipe_Read_Stream_LE(&ConnectionRequest, sizeof(ConnectionRequest), NULL);
|
|
||||||
|
|
||||||
Pipe_ClearIN();
|
|
||||||
Pipe_Freeze();
|
|
||||||
|
|
||||||
BT_ACL_DEBUG(1, "<< L2CAP Connection Request");
|
|
||||||
BT_ACL_DEBUG(2, "-- PSM: 0x%04X", ConnectionRequest.PSM);
|
|
||||||
BT_ACL_DEBUG(2, "-- Source Channel: 0x%04X", ConnectionRequest.SourceChannel);
|
|
||||||
|
|
||||||
/* Try to retrieve the existing channel's information structure if it exists */
|
|
||||||
Bluetooth_Channel_t* ChannelData = Bluetooth_GetChannelData(ConnectionRequest.SourceChannel, CHANNEL_SEARCH_REMOTENUMBER);
|
|
||||||
|
|
||||||
/* If an existing channel item with the correct remote channel number was not found, find a free channel entry */
|
|
||||||
if (ChannelData == NULL)
|
|
||||||
{
|
|
||||||
/* Look through the channel information list for a free entry */
|
|
||||||
for (uint8_t i = 0; i < BLUETOOTH_MAX_OPEN_CHANNELS; i++)
|
|
||||||
{
|
|
||||||
if (Bluetooth_Connection.Channels[i].State == BT_Channel_Closed)
|
|
||||||
{
|
|
||||||
ChannelData = &Bluetooth_Connection.Channels[i];
|
|
||||||
|
|
||||||
/* Set the new channel structure's local channel number to a unique value within the connection orientated
|
|
||||||
channel address space */
|
|
||||||
ChannelData->LocalNumber = (BT_CHANNELNUMBER_BASEOFFSET + i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t ChannelStatus = BT_CONNECTION_REFUSED_RESOURCES;
|
|
||||||
|
|
||||||
/* Reset the channel item contents only if a channel entry was found for it */
|
|
||||||
if (ChannelData != NULL)
|
|
||||||
{
|
|
||||||
/* Check if the user application will allow the connection based on its PSM */
|
|
||||||
if (Bluetooth_ChannelConnectionRequest(ConnectionRequest.PSM))
|
|
||||||
{
|
|
||||||
ChannelData->RemoteNumber = ConnectionRequest.SourceChannel;
|
|
||||||
ChannelData->PSM = ConnectionRequest.PSM;
|
|
||||||
ChannelData->LocalMTU = MAXIMUM_CHANNEL_MTU;
|
|
||||||
ChannelData->State = BT_Channel_Config_WaitConfig;
|
|
||||||
|
|
||||||
ChannelStatus = BT_CONNECTION_SUCCESSFUL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ChannelStatus = BT_CONNECTION_REFUSED_PSM;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
BT_Signal_Header_t SignalCommandHeader;
|
|
||||||
BT_Signal_ConnectionResp_t ConnectionResponse;
|
|
||||||
} ResponsePacket;
|
|
||||||
|
|
||||||
/* Fill out the Signal Command header in the response packet */
|
|
||||||
ResponsePacket.SignalCommandHeader.Code = BT_SIGNAL_CONNECTION_RESPONSE;
|
|
||||||
ResponsePacket.SignalCommandHeader.Identifier = SignalCommandHeader->Identifier;
|
|
||||||
ResponsePacket.SignalCommandHeader.Length = sizeof(ResponsePacket.ConnectionResponse);
|
|
||||||
|
|
||||||
/* Fill out the Connection Response in the response packet */
|
|
||||||
ResponsePacket.ConnectionResponse.DestinationChannel = (ChannelData != NULL) ? ChannelData->LocalNumber : 0;
|
|
||||||
ResponsePacket.ConnectionResponse.SourceChannel = (ChannelData != NULL) ? ChannelData->RemoteNumber : 0;
|
|
||||||
ResponsePacket.ConnectionResponse.Result = ChannelStatus;
|
|
||||||
ResponsePacket.ConnectionResponse.Status = 0x00;
|
|
||||||
|
|
||||||
Bluetooth_SendPacket(&ResponsePacket, sizeof(ResponsePacket), NULL);
|
|
||||||
|
|
||||||
BT_ACL_DEBUG(1, ">> L2CAP Connection Response");
|
|
||||||
BT_ACL_DEBUG(2, "-- Result: 0x%02X", ResponsePacket.ConnectionResponse.Result);
|
|
||||||
BT_ACL_DEBUG(2, "-- Destination Channel: 0x%04X", ResponsePacket.ConnectionResponse.DestinationChannel);
|
|
||||||
BT_ACL_DEBUG(2, "-- Source Channel: 0x%04X", ResponsePacket.ConnectionResponse.SourceChannel);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Internal Bluetooth stack Signal Command processing routine for a Connection Response command.
|
|
||||||
*
|
|
||||||
* \param[in] SignalCommandHeader Pointer to the start of the received packet's Signal Command header
|
|
||||||
*/
|
|
||||||
static inline void Bluetooth_Signal_ConnectionResp(const BT_Signal_Header_t* const SignalCommandHeader)
|
|
||||||
{
|
|
||||||
BT_Signal_ConnectionResp_t ConnectionResponse;
|
|
||||||
|
|
||||||
Pipe_Read_Stream_LE(&ConnectionResponse, sizeof(ConnectionResponse), NULL);
|
|
||||||
|
|
||||||
Pipe_ClearIN();
|
|
||||||
Pipe_Freeze();
|
|
||||||
|
|
||||||
BT_ACL_DEBUG(1, "<< L2CAP Connection Response");
|
|
||||||
BT_ACL_DEBUG(2, "-- Result: 0x%02X", ConnectionResponse.Result);
|
|
||||||
BT_ACL_DEBUG(2, "-- Source Channel: 0x%04X", ConnectionResponse.SourceChannel);
|
|
||||||
BT_ACL_DEBUG(2, "-- Destination Channel: 0x%04X", ConnectionResponse.DestinationChannel);
|
|
||||||
|
|
||||||
/* Search for the referenced channel in the channel information list */
|
|
||||||
Bluetooth_Channel_t* ChannelData = Bluetooth_GetChannelData(ConnectionResponse.SourceChannel, CHANNEL_SEARCH_LOCALNUMBER);
|
|
||||||
|
|
||||||
/* Only progress if the referenced channel data was found */
|
|
||||||
if (ChannelData != NULL)
|
|
||||||
{
|
|
||||||
/* Set the channel structure's remote channel number to the channel allocated on the remote device */
|
|
||||||
ChannelData->RemoteNumber = ConnectionResponse.SourceChannel;
|
|
||||||
ChannelData->State = (ConnectionResponse.Result == BT_CONNECTION_SUCCESSFUL) ?
|
|
||||||
BT_Channel_Config_WaitConfig : BT_Channel_Closed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Internal Bluetooth stack Signal Command processing routine for a Configuration Request command.
|
|
||||||
*
|
|
||||||
* \param[in] SignalCommandHeader Pointer to the start of the received packet's Signal Command header
|
|
||||||
*/
|
|
||||||
static inline void Bluetooth_Signal_ConfigurationReq(const BT_Signal_Header_t* const SignalCommandHeader)
|
|
||||||
{
|
|
||||||
BT_Signal_ConfigurationReq_t ConfigurationRequest;
|
|
||||||
|
|
||||||
/* Allocate a buffer large enough to hold the variable number of configuration options in the request */
|
|
||||||
uint8_t OptionsLen = (SignalCommandHeader->Length - sizeof(ConfigurationRequest));
|
|
||||||
uint8_t Options[OptionsLen];
|
|
||||||
|
|
||||||
Pipe_Read_Stream_LE(&ConfigurationRequest, sizeof(ConfigurationRequest), NULL);
|
|
||||||
Pipe_Read_Stream_LE(&Options, sizeof(Options), NULL);
|
|
||||||
|
|
||||||
Pipe_ClearIN();
|
|
||||||
Pipe_Freeze();
|
|
||||||
|
|
||||||
/* Search for the referenced channel in the channel information list */
|
|
||||||
Bluetooth_Channel_t* ChannelData = Bluetooth_GetChannelData(ConfigurationRequest.DestinationChannel, CHANNEL_SEARCH_LOCALNUMBER);
|
|
||||||
|
|
||||||
BT_ACL_DEBUG(1, "<< L2CAP Configuration Request");
|
|
||||||
BT_ACL_DEBUG(2, "-- Destination Channel: 0x%04X", ConfigurationRequest.DestinationChannel);
|
|
||||||
BT_ACL_DEBUG(2, "-- Options Len: 0x%04X", OptionsLen);
|
|
||||||
|
|
||||||
/* Only look at the channel configuration options if a valid channel entry for the local channel number was found */
|
|
||||||
if (ChannelData != NULL)
|
|
||||||
{
|
|
||||||
/* Iterate through each option in the configuration request to look for ones which can be processed */
|
|
||||||
uint8_t OptionPos = 0;
|
|
||||||
while (OptionPos < OptionsLen)
|
|
||||||
{
|
|
||||||
BT_Config_Option_Header_t* OptionHeader = (BT_Config_Option_Header_t*)&Options[OptionPos];
|
|
||||||
void* OptionData = &Options[OptionPos + sizeof(BT_Config_Option_Header_t)];
|
|
||||||
|
|
||||||
BT_ACL_DEBUG(2, "-- Option Type: 0x%04X", OptionHeader->Type);
|
|
||||||
BT_ACL_DEBUG(2, "-- Option Length: 0x%04X", (sizeof(BT_Config_Option_Header_t) + OptionHeader->Length));
|
|
||||||
|
|
||||||
/* Store the remote MTU option's value if present */
|
|
||||||
if (OptionHeader->Type == BT_CONFIG_OPTION_MTU)
|
|
||||||
ChannelData->RemoteMTU = *((uint16_t*)OptionData);
|
|
||||||
|
|
||||||
/* Progress to the next option in the packet */
|
|
||||||
OptionPos += (sizeof(BT_Config_Option_Header_t) + OptionHeader->Length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
BT_Signal_Header_t SignalCommandHeader;
|
|
||||||
BT_Signal_ConfigurationResp_t ConfigurationResponse;
|
|
||||||
} ResponsePacket;
|
|
||||||
|
|
||||||
/* Fill out the Signal Command header in the response packet */
|
|
||||||
ResponsePacket.SignalCommandHeader.Code = BT_SIGNAL_CONFIGURATION_RESPONSE;
|
|
||||||
ResponsePacket.SignalCommandHeader.Identifier = SignalCommandHeader->Identifier;
|
|
||||||
ResponsePacket.SignalCommandHeader.Length = sizeof(ResponsePacket.ConfigurationResponse);
|
|
||||||
|
|
||||||
/* Fill out the Configuration Response in the response packet */
|
|
||||||
ResponsePacket.ConfigurationResponse.SourceChannel = (ChannelData != NULL) ? ChannelData->RemoteNumber : 0;
|
|
||||||
ResponsePacket.ConfigurationResponse.Flags = 0x00;
|
|
||||||
ResponsePacket.ConfigurationResponse.Result = (ChannelData != NULL) ? BT_CONFIGURATION_SUCCESSFUL : BT_CONFIGURATION_REJECTED;
|
|
||||||
|
|
||||||
Bluetooth_SendPacket(&ResponsePacket, sizeof(ResponsePacket), NULL);
|
|
||||||
|
|
||||||
if (ChannelData != NULL)
|
|
||||||
{
|
|
||||||
switch (ChannelData->State)
|
|
||||||
{
|
|
||||||
case BT_Channel_Config_WaitConfig:
|
|
||||||
ChannelData->State = BT_Channel_Config_WaitSendConfig;
|
|
||||||
break;
|
|
||||||
case BT_Channel_Config_WaitReqResp:
|
|
||||||
ChannelData->State = BT_Channel_Config_WaitResp;
|
|
||||||
break;
|
|
||||||
case BT_Channel_Config_WaitReq:
|
|
||||||
ChannelData->State = BT_Channel_Open;
|
|
||||||
Bluetooth_ChannelOpened(ChannelData);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BT_ACL_DEBUG(1, ">> L2CAP Configuration Response");
|
|
||||||
BT_ACL_DEBUG(2, "-- Source Channel: 0x%04X", ResponsePacket.ConfigurationResponse.SourceChannel);
|
|
||||||
BT_ACL_DEBUG(2, "-- Result: 0x%02X", ResponsePacket.ConfigurationResponse.Result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Internal Bluetooth stack Signal Command processing routine for a Configuration Response command.
|
|
||||||
*
|
|
||||||
* \param[in] SignalCommandHeader Pointer to the start of the received packet's Signal Command header
|
|
||||||
*/
|
|
||||||
static inline void Bluetooth_Signal_ConfigurationResp(const BT_Signal_Header_t* const SignalCommandHeader)
|
|
||||||
{
|
|
||||||
BT_Signal_ConfigurationResp_t ConfigurationResponse;
|
|
||||||
|
|
||||||
Pipe_Read_Stream_LE(&ConfigurationResponse, sizeof(ConfigurationResponse), NULL);
|
|
||||||
|
|
||||||
Pipe_ClearIN();
|
|
||||||
Pipe_Freeze();
|
|
||||||
|
|
||||||
BT_ACL_DEBUG(1, "<< L2CAP Configuration Response");
|
|
||||||
BT_ACL_DEBUG(2, "-- Source Channel: 0x%04X", ConfigurationResponse.SourceChannel);
|
|
||||||
BT_ACL_DEBUG(2, "-- Result: 0x%02X", ConfigurationResponse.Result);
|
|
||||||
|
|
||||||
/* Search for the referenced channel in the channel information list */
|
|
||||||
Bluetooth_Channel_t* ChannelData = Bluetooth_GetChannelData(ConfigurationResponse.SourceChannel, CHANNEL_SEARCH_REMOTENUMBER);
|
|
||||||
|
|
||||||
/* Only update the channel's state if it was found in the channel list */
|
|
||||||
if (ChannelData != NULL)
|
|
||||||
{
|
|
||||||
/* Check if the channel configuration completed successfully */
|
|
||||||
if (ConfigurationResponse.Result == BT_CONFIGURATION_SUCCESSFUL)
|
|
||||||
{
|
|
||||||
switch (ChannelData->State)
|
|
||||||
{
|
|
||||||
case BT_Channel_Config_WaitReqResp:
|
|
||||||
ChannelData->State = BT_Channel_Config_WaitReq;
|
|
||||||
break;
|
|
||||||
case BT_Channel_Config_WaitResp:
|
|
||||||
ChannelData->State = BT_Channel_Open;
|
|
||||||
Bluetooth_ChannelOpened(ChannelData);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Configuration failed - close the channel */
|
|
||||||
ChannelData->State = BT_Channel_Closed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Internal Bluetooth stack Signal Command processing routine for a Disconnection Request command.
|
|
||||||
*
|
|
||||||
* \param[in] SignalCommandHeader Pointer to the start of the received packet's Signal Command header
|
|
||||||
*/
|
|
||||||
static inline void Bluetooth_Signal_DisconnectionReq(const BT_Signal_Header_t* const SignalCommandHeader)
|
|
||||||
{
|
|
||||||
BT_Signal_DisconnectionReq_t DisconnectionRequest;
|
|
||||||
|
|
||||||
Pipe_Read_Stream_LE(&DisconnectionRequest, sizeof(DisconnectionRequest), NULL);
|
|
||||||
|
|
||||||
BT_ACL_DEBUG(1, "<< L2CAP Disconnection Request");
|
|
||||||
BT_ACL_DEBUG(2, "-- Destination Channel: 0x%04X", DisconnectionRequest.DestinationChannel);
|
|
||||||
BT_ACL_DEBUG(2, "-- Source Channel: 0x%04X", DisconnectionRequest.SourceChannel);
|
|
||||||
|
|
||||||
Pipe_ClearIN();
|
|
||||||
Pipe_Freeze();
|
|
||||||
|
|
||||||
/* Search for the referenced channel in the channel information list */
|
|
||||||
Bluetooth_Channel_t* ChannelData = Bluetooth_GetChannelData(DisconnectionRequest.SourceChannel, CHANNEL_SEARCH_REMOTENUMBER);
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
BT_Signal_Header_t SignalCommandHeader;
|
|
||||||
BT_Signal_DisconnectionResp_t DisconnectionResponse;
|
|
||||||
} ResponsePacket;
|
|
||||||
|
|
||||||
/* Fill out the Signal Command header in the response packet */
|
|
||||||
ResponsePacket.SignalCommandHeader.Code = BT_SIGNAL_DISCONNECTION_RESPONSE;
|
|
||||||
ResponsePacket.SignalCommandHeader.Identifier = SignalCommandHeader->Identifier;
|
|
||||||
ResponsePacket.SignalCommandHeader.Length = sizeof(ResponsePacket.DisconnectionResponse);
|
|
||||||
|
|
||||||
/* Fill out the Disconnection Response in the response packet */
|
|
||||||
ResponsePacket.DisconnectionResponse.DestinationChannel = (ChannelData != NULL) ? ChannelData->RemoteNumber : 0;
|
|
||||||
ResponsePacket.DisconnectionResponse.SourceChannel = (ChannelData != NULL) ? ChannelData->LocalNumber : 0;
|
|
||||||
|
|
||||||
Bluetooth_SendPacket(&ResponsePacket, sizeof(ResponsePacket), NULL);
|
|
||||||
|
|
||||||
/* If the channel was found in the channel list, close it */
|
|
||||||
if (ChannelData != NULL)
|
|
||||||
ChannelData->State = BT_Channel_Closed;
|
|
||||||
|
|
||||||
BT_ACL_DEBUG(1, ">> L2CAP Disconnection Response");
|
|
||||||
BT_ACL_DEBUG(2, "-- Source Channel: 0x%04X", ResponsePacket.DisconnectionResponse.SourceChannel);
|
|
||||||
BT_ACL_DEBUG(2, "-- Destination Channel: 0x%04X", ResponsePacket.DisconnectionResponse.DestinationChannel);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Internal Bluetooth stack Signal Command processing routine for a Disconnection Response command.
|
|
||||||
*
|
|
||||||
* \param[in] SignalCommandHeader Pointer to the start of the received packet's Signal Command header
|
|
||||||
*/
|
|
||||||
static inline void Bluetooth_Signal_DisconnectionResp(const BT_Signal_Header_t* const SignalCommandHeader)
|
|
||||||
{
|
|
||||||
BT_Signal_DisconnectionResp_t DisconnectionResponse;
|
|
||||||
|
|
||||||
Pipe_Read_Stream_LE(&DisconnectionResponse, sizeof(DisconnectionResponse), NULL);
|
|
||||||
|
|
||||||
BT_ACL_DEBUG(1, "<< L2CAP Disconnection Response");
|
|
||||||
BT_ACL_DEBUG(2, "-- Destination Channel: 0x%04X", DisconnectionResponse.DestinationChannel);
|
|
||||||
BT_ACL_DEBUG(2, "-- Source Channel: 0x%04X", DisconnectionResponse.SourceChannel);
|
|
||||||
|
|
||||||
Pipe_ClearIN();
|
|
||||||
Pipe_Freeze();
|
|
||||||
|
|
||||||
/* Search for the referenced channel in the channel information list */
|
|
||||||
Bluetooth_Channel_t* ChannelData = Bluetooth_GetChannelData(DisconnectionResponse.SourceChannel, CHANNEL_SEARCH_REMOTENUMBER);
|
|
||||||
|
|
||||||
/* If the channel was found in the channel list, close it */
|
|
||||||
if (ChannelData != NULL)
|
|
||||||
ChannelData->State = BT_Channel_Closed;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Internal Bluetooth stack Signal Command processing routine for an Echo Request command.
|
|
||||||
*
|
|
||||||
* \param[in] SignalCommandHeader Pointer to the start of the received packet's Signal Command header
|
|
||||||
*/
|
|
||||||
static inline void Bluetooth_Signal_EchoReq(const BT_Signal_Header_t* const SignalCommandHeader)
|
|
||||||
{
|
|
||||||
BT_ACL_DEBUG(1, "<< L2CAP Echo Request");
|
|
||||||
|
|
||||||
Pipe_ClearIN();
|
|
||||||
Pipe_Freeze();
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
BT_Signal_Header_t SignalCommandHeader;
|
|
||||||
} ResponsePacket;
|
|
||||||
|
|
||||||
/* Fill out the Signal Command header in the response packet */
|
|
||||||
ResponsePacket.SignalCommandHeader.Code = BT_SIGNAL_ECHO_RESPONSE;
|
|
||||||
ResponsePacket.SignalCommandHeader.Identifier = SignalCommandHeader->Identifier;
|
|
||||||
ResponsePacket.SignalCommandHeader.Length = 0;
|
|
||||||
|
|
||||||
Bluetooth_SendPacket(&ResponsePacket, sizeof(ResponsePacket), NULL);
|
|
||||||
|
|
||||||
BT_ACL_DEBUG(1, ">> L2CAP Echo Response");
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Internal Bluetooth stack Signal Command processing routine for an Information Request command.
|
|
||||||
*
|
|
||||||
* \param[in] SignalCommandHeader Pointer to the start of the received packet's Signal Command header
|
|
||||||
*/
|
|
||||||
static inline void Bluetooth_Signal_InformationReq(const BT_Signal_Header_t* const SignalCommandHeader)
|
|
||||||
{
|
|
||||||
BT_Signal_InformationReq_t InformationRequest;
|
|
||||||
|
|
||||||
Pipe_Read_Stream_LE(&InformationRequest, sizeof(InformationRequest), NULL);
|
|
||||||
|
|
||||||
BT_ACL_DEBUG(1, "<< L2CAP Information Request");
|
|
||||||
BT_ACL_DEBUG(2, "-- Info Type: 0x%04X", InformationRequest.InfoType);
|
|
||||||
|
|
||||||
Pipe_ClearIN();
|
|
||||||
Pipe_Freeze();
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
BT_Signal_Header_t SignalCommandHeader;
|
|
||||||
BT_Signal_InformationResp_t InformationResponse;
|
|
||||||
|
|
||||||
uint8_t Data[4];
|
|
||||||
} ResponsePacket;
|
|
||||||
|
|
||||||
uint8_t DataLen = 0;
|
|
||||||
|
|
||||||
/* Retrieve the requested information and store it in the outgoing packet, if found */
|
|
||||||
switch (InformationRequest.InfoType)
|
|
||||||
{
|
|
||||||
case BT_INFOREQ_MTU:
|
|
||||||
ResponsePacket.InformationResponse.Result = BT_INFORMATION_SUCCESSFUL;
|
|
||||||
DataLen = 2;
|
|
||||||
|
|
||||||
*((uint16_t*)&ResponsePacket.Data) = MAXIMUM_CHANNEL_MTU;
|
|
||||||
break;
|
|
||||||
case BT_INFOREQ_EXTENDEDFEATURES:
|
|
||||||
ResponsePacket.InformationResponse.Result = BT_INFORMATION_SUCCESSFUL;
|
|
||||||
DataLen = 4;
|
|
||||||
|
|
||||||
*((uint32_t*)&ResponsePacket.Data) = 0;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ResponsePacket.InformationResponse.Result = BT_INFORMATION_NOTSUPPORTED;
|
|
||||||
DataLen = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Fill out the Signal Command header in the response packet */
|
|
||||||
ResponsePacket.SignalCommandHeader.Code = BT_SIGNAL_INFORMATION_RESPONSE;
|
|
||||||
ResponsePacket.SignalCommandHeader.Identifier = SignalCommandHeader->Identifier;
|
|
||||||
ResponsePacket.SignalCommandHeader.Length = sizeof(ResponsePacket.InformationResponse) + DataLen;
|
|
||||||
|
|
||||||
/* Fill out the Information Response in the response packet */
|
|
||||||
ResponsePacket.InformationResponse.InfoType = InformationRequest.InfoType;
|
|
||||||
|
|
||||||
Bluetooth_SendPacket(&ResponsePacket, (sizeof(ResponsePacket) - sizeof(ResponsePacket.Data) + DataLen), NULL);
|
|
||||||
|
|
||||||
BT_ACL_DEBUG(1, ">> L2CAP Information Response");
|
|
||||||
BT_ACL_DEBUG(2, "-- Result: 0x%02X", ResponsePacket.InformationResponse.Result);
|
|
||||||
}
|
|
||||||
|
|
@ -1,200 +0,0 @@
|
|||||||
/*
|
|
||||||
LUFA Library
|
|
||||||
Copyright (C) Dean Camera, 2012.
|
|
||||||
|
|
||||||
dean [at] fourwalledcubicle [dot] com
|
|
||||||
www.lufa-lib.org
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright 2012 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
|
||||||
|
|
||||||
Permission to use, copy, modify, distribute, and sell this
|
|
||||||
software and its documentation for any purpose is hereby granted
|
|
||||||
without fee, provided that the above copyright notice appear in
|
|
||||||
all copies and that both that the copyright notice and this
|
|
||||||
permission notice and warranty disclaimer appear in supporting
|
|
||||||
documentation, and that the name of the author not be used in
|
|
||||||
advertising or publicity pertaining to distribution of the
|
|
||||||
software without specific, written prior permission.
|
|
||||||
|
|
||||||
The author disclaim all warranties with regard to this
|
|
||||||
software, including all implied warranties of merchantability
|
|
||||||
and fitness. In no event shall the author be liable for any
|
|
||||||
special, indirect or consequential damages or any damages
|
|
||||||
whatsoever resulting from loss of use, data or profits, whether
|
|
||||||
in an action of contract, negligence or other tortious action,
|
|
||||||
arising out of or in connection with the use or performance of
|
|
||||||
this software.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** \file
|
|
||||||
*
|
|
||||||
* Header file for BluetoothACLPackets.c.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _BLUETOOTH_ACLPACKETS_
|
|
||||||
#define _BLUETOOTH_ACLPACKETS_
|
|
||||||
|
|
||||||
/* Includes: */
|
|
||||||
#include <avr/io.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include <LUFA/Drivers/USB/USB.h>
|
|
||||||
#include <LUFA/Drivers/Peripheral/Serial.h>
|
|
||||||
|
|
||||||
#include "BluetoothStack.h"
|
|
||||||
|
|
||||||
/* Macros: */
|
|
||||||
#define BT_ACL_DEBUG(l, s, ...) do { if (ACL_DEBUG_LEVEL >= l) printf_P(PSTR("(ACL) " s "\r\n"), ##__VA_ARGS__); } while (0)
|
|
||||||
#define ACL_DEBUG_LEVEL 0
|
|
||||||
|
|
||||||
/** Lowest possible channel number for L2CAP data channels. */
|
|
||||||
#define BT_CHANNELNUMBER_BASEOFFSET 0x0040
|
|
||||||
|
|
||||||
/** Bluetooth specification defined channel number for signaling commands. */
|
|
||||||
#define BT_CHANNEL_SIGNALING 0x0001
|
|
||||||
|
|
||||||
/** Bluetooth specification defined channel number for connectionless data. */
|
|
||||||
#define BT_CHANNEL_CONNECTIONLESS 0x0002
|
|
||||||
|
|
||||||
#define BT_ACL_FIRST_AUTOFLUSH (1 << 13)
|
|
||||||
|
|
||||||
#define BT_SIGNAL_COMMAND_REJECT 0x01
|
|
||||||
#define BT_SIGNAL_CONNECTION_REQUEST 0x02
|
|
||||||
#define BT_SIGNAL_CONNECTION_RESPONSE 0x03
|
|
||||||
#define BT_SIGNAL_CONFIGURATION_REQUEST 0x04
|
|
||||||
#define BT_SIGNAL_CONFIGURATION_RESPONSE 0x05
|
|
||||||
#define BT_SIGNAL_DISCONNECTION_REQUEST 0x06
|
|
||||||
#define BT_SIGNAL_DISCONNECTION_RESPONSE 0x07
|
|
||||||
#define BT_SIGNAL_ECHO_REQUEST 0x08
|
|
||||||
#define BT_SIGNAL_ECHO_RESPONSE 0x09
|
|
||||||
#define BT_SIGNAL_INFORMATION_REQUEST 0x0A
|
|
||||||
#define BT_SIGNAL_INFORMATION_RESPONSE 0x0B
|
|
||||||
|
|
||||||
#define BT_INFOREQ_MTU 0x0001
|
|
||||||
#define BT_INFOREQ_EXTENDEDFEATURES 0x0002
|
|
||||||
|
|
||||||
#define BT_INFORMATION_SUCCESSFUL 0x0000
|
|
||||||
#define BT_INFORMATION_NOTSUPPORTED 0x0001
|
|
||||||
|
|
||||||
#define BT_CONNECTION_SUCCESSFUL 0x0000
|
|
||||||
#define BT_CONNECTION_REFUSED_PSM 0x0002
|
|
||||||
#define BT_CONNECTION_REFUSED_RESOURCES 0x0004
|
|
||||||
|
|
||||||
#define BT_CONFIGURATION_SUCCESSFUL 0x0000
|
|
||||||
#define BT_CONFIGURATION_REJECTED 0x0002
|
|
||||||
#define BT_CONFIGURATION_UNKNOWNOPTIONS 0x0003
|
|
||||||
|
|
||||||
#define BT_CONFIG_OPTION_MTU 1
|
|
||||||
|
|
||||||
/* Type Defines: */
|
|
||||||
/** Bluetooth ACL header structure, common to all ACL data packets. */
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint16_t ConnectionHandle; /**< Unique device connection handle of the ACL packet */
|
|
||||||
uint16_t DataLength; /**< Length of the packet payload, in bytes */
|
|
||||||
} BT_ACL_Header_t;
|
|
||||||
|
|
||||||
/** Bluetooth ACL data packet header structure, for ACL packets containing L2CAP data. */
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint16_t PayloadLength; /**< Size of the data payload, in bytes */
|
|
||||||
uint16_t DestinationChannel; /**< Destination channel in the device the data is directed to */
|
|
||||||
} BT_DataPacket_Header_t;
|
|
||||||
|
|
||||||
/** Bluetooth signaling command header structure, for all ACL packets containing a signaling command. */
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint8_t Code; /**< Signal code, a \c BT_SIGNAL_* mask value */
|
|
||||||
uint8_t Identifier; /**< Unique signal command identifier to link requests and responses */
|
|
||||||
uint16_t Length; /**< Length of the signaling command data, in bytes */
|
|
||||||
} BT_Signal_Header_t;
|
|
||||||
|
|
||||||
/** Connection Request signaling command structure, for channel connection requests. */
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint16_t PSM; /**< Type of data the channel will carry, a \c CHANNEL_PSM_* mask value */
|
|
||||||
uint16_t SourceChannel; /**< Channel source on the sending device this channel will link to */
|
|
||||||
} BT_Signal_ConnectionReq_t;
|
|
||||||
|
|
||||||
/** Connection response signaling command structure, for responses to channel connection requests. */
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint16_t DestinationChannel; /**< Destination device channel that the connection request was processed on */
|
|
||||||
uint16_t SourceChannel; /**< Source device channel address that the connection request came from */
|
|
||||||
uint16_t Result; /**< Connection result, a \c BT_CONNECTION_* mask value */
|
|
||||||
uint16_t Status; /**< Status of the request if the result was set to the Pending value */
|
|
||||||
} BT_Signal_ConnectionResp_t;
|
|
||||||
|
|
||||||
/** Disconnection request signaling command structure, for channel disconnection requests. */
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint16_t DestinationChannel; /**< Destination channel address which is to be disconnected */
|
|
||||||
uint16_t SourceChannel; /**< Source channel address which is to be disconnected */
|
|
||||||
} BT_Signal_DisconnectionReq_t;
|
|
||||||
|
|
||||||
/** Disconnection response signaling command structure, for responses to channel disconnection requests. */
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint16_t DestinationChannel; /**< Destination channel address which was disconnected */
|
|
||||||
uint16_t SourceChannel; /**< Source channel address which was disconnected */
|
|
||||||
} BT_Signal_DisconnectionResp_t;
|
|
||||||
|
|
||||||
/** Configuration Request signaling command structure, for channel configuration requests. */
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint16_t DestinationChannel; /**< Destination channel address which is to be configured */
|
|
||||||
uint16_t Flags; /**< Configuration flags for the request, including command continuation */
|
|
||||||
} BT_Signal_ConfigurationReq_t;
|
|
||||||
|
|
||||||
/** Configuration Response signaling command structure, for responses to channel configuration requests. */
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint16_t SourceChannel; /**< Source channel that the configuration request was directed at */
|
|
||||||
uint16_t Flags; /**< Configuration flags for the response, including response continuation */
|
|
||||||
uint16_t Result; /**< Configuration result, a \c BT_CONFIGURATION_* mask value */
|
|
||||||
} BT_Signal_ConfigurationResp_t;
|
|
||||||
|
|
||||||
/** Information Request signaling command structure, for device information requests. */
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint16_t InfoType; /**< Data type that is being requested, a \c BT_INFOREQ_* mask value */
|
|
||||||
} BT_Signal_InformationReq_t;
|
|
||||||
|
|
||||||
/** Information Response signaling command structure, for responses to information requests. */
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint16_t InfoType; /**< Data type that was requested, a \c BT_INFOREQ_* mask value */
|
|
||||||
uint16_t Result; /**< Result of the request, a \c BT_INFORMATION_* mask value */
|
|
||||||
} BT_Signal_InformationResp_t;
|
|
||||||
|
|
||||||
/** Configuration Option header structure, placed at the start of each option in a Channel Configuration
|
|
||||||
* request's options list.
|
|
||||||
*/
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint8_t Type; /**< Option type, a \c BT_CONFIG_OPTION_* mask value */
|
|
||||||
uint8_t Length; /**< Length of the option's value, in bytes */
|
|
||||||
} BT_Config_Option_Header_t;
|
|
||||||
|
|
||||||
/* Function Prototypes: */
|
|
||||||
void Bluetooth_ACLTask(void);
|
|
||||||
|
|
||||||
#if defined(INCLUDE_FROM_BLUETOOTH_ACLPACKETS_C)
|
|
||||||
static void Bluetooth_ProcessIncomingACLPackets(void);
|
|
||||||
|
|
||||||
static inline void Bluetooth_Signal_ConnectionReq(const BT_Signal_Header_t* const SignalCommandHeader);
|
|
||||||
static inline void Bluetooth_Signal_ConnectionResp(const BT_Signal_Header_t* const SignalCommandHeader);
|
|
||||||
static inline void Bluetooth_Signal_ConfigurationReq(const BT_Signal_Header_t* const SignalCommandHeader);
|
|
||||||
static inline void Bluetooth_Signal_ConfigurationResp(const BT_Signal_Header_t* const SignalCommandHeader);
|
|
||||||
static inline void Bluetooth_Signal_DisconnectionReq(const BT_Signal_Header_t* const SignalCommandHeader);
|
|
||||||
static inline void Bluetooth_Signal_DisconnectionResp(const BT_Signal_Header_t* const SignalCommandHeader);
|
|
||||||
static inline void Bluetooth_Signal_EchoReq(const BT_Signal_Header_t* const SignalCommandHeader);
|
|
||||||
static inline void Bluetooth_Signal_InformationReq(const BT_Signal_Header_t* const SignalCommandHeader);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,118 +0,0 @@
|
|||||||
/*
|
|
||||||
LUFA Library
|
|
||||||
Copyright (C) Dean Camera, 2012.
|
|
||||||
|
|
||||||
dean [at] fourwalledcubicle [dot] com
|
|
||||||
www.lufa-lib.org
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright 2012 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
|
||||||
|
|
||||||
Permission to use, copy, modify, distribute, and sell this
|
|
||||||
software and its documentation for any purpose is hereby granted
|
|
||||||
without fee, provided that the above copyright notice appear in
|
|
||||||
all copies and that both that the copyright notice and this
|
|
||||||
permission notice and warranty disclaimer appear in supporting
|
|
||||||
documentation, and that the name of the author not be used in
|
|
||||||
advertising or publicity pertaining to distribution of the
|
|
||||||
software without specific, written prior permission.
|
|
||||||
|
|
||||||
The author disclaim all warranties with regard to this
|
|
||||||
software, including all implied warranties of merchantability
|
|
||||||
and fitness. In no event shall the author be liable for any
|
|
||||||
special, indirect or consequential damages or any damages
|
|
||||||
whatsoever resulting from loss of use, data or profits, whether
|
|
||||||
in an action of contract, negligence or other tortious action,
|
|
||||||
arising out of or in connection with the use or performance of
|
|
||||||
this software.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** \file
|
|
||||||
*
|
|
||||||
* Bluetooth class codes, used to describe the type and overall function of a
|
|
||||||
* Bluetooth device to other Bluetooth devices.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _BLUETOOTH_CLASS_CODES_H_
|
|
||||||
#define _BLUETOOTH_CLASS_CODES_H_
|
|
||||||
|
|
||||||
/* Macros: */
|
|
||||||
#define DEVICE_CLASS_SERVICE_POSITIONING (1UL << 16)
|
|
||||||
#define DEVICE_CLASS_SERVICE_NETWORKING (1UL << 17)
|
|
||||||
#define DEVICE_CLASS_SERVICE_RENDERING (1UL << 18)
|
|
||||||
#define DEVICE_CLASS_SERVICE_CAPTURING (1UL << 19)
|
|
||||||
#define DEVICE_CLASS_SERVICE_OBJECTTRANSFER (1UL << 20)
|
|
||||||
#define DEVICE_CLASS_SERVICE_AUDIO (1UL << 21)
|
|
||||||
#define DEVICE_CLASS_SERVICE_TELEPHONY (1UL << 22)
|
|
||||||
#define DEVICE_CLASS_SERVICE_INFORMATION (1UL << 23)
|
|
||||||
|
|
||||||
#define DEVICE_CLASS_MAJOR_MISC (0x00 << 8)
|
|
||||||
#define DEVICE_CLASS_MAJOR_COMPUTER (0x01 << 8)
|
|
||||||
#define DEVICE_CLASS_MAJOR_PHONE (0x02 << 8)
|
|
||||||
#define DEVICE_CLASS_MAJOR_LAN (0x03 << 8)
|
|
||||||
#define DEVICE_CLASS_MAJOR_AUDIOVIDEO (0x04 << 8)
|
|
||||||
#define DEVICE_CLASS_MAJOR_PERIPHERAL (0x05 << 8)
|
|
||||||
#define DEVICE_CLASS_MAJOR_IMAGING (0x06 << 8)
|
|
||||||
#define DEVICE_CLASS_MAJOR_UNCLASSIFIED (0x1F << 8)
|
|
||||||
|
|
||||||
#define DEVICE_CLASS_MINOR_COMPUTER_UNCATEGORIZED (0x00 << 2)
|
|
||||||
#define DEVICE_CLASS_MINOR_COMPUTER_DESKTOP (0x01 << 2)
|
|
||||||
#define DEVICE_CLASS_MINOR_COMPUTER_SERVER (0x02 << 2)
|
|
||||||
#define DEVICE_CLASS_MINOR_COMPUTER_LAPTOP (0x03 << 2)
|
|
||||||
#define DEVICE_CLASS_MINOR_COMPUTER_HANDHELD (0x04 << 2)
|
|
||||||
#define DEVICE_CLASS_MINOR_COMPUTER_PALM (0x05 << 2)
|
|
||||||
#define DEVICE_CLASS_MINOR_COMPUTER_WEARABLE (0x06 << 2)
|
|
||||||
|
|
||||||
#define DEVICE_CLASS_MINOR_PHONE_UNCATEGORIZED (0x00 << 2)
|
|
||||||
#define DEVICE_CLASS_MINOR_PHONE_CELLULAR (0x01 << 2)
|
|
||||||
#define DEVICE_CLASS_MINOR_PHONE_CORDLESS (0x02 << 2)
|
|
||||||
#define DEVICE_CLASS_MINOR_PHONE_SMARTPHONE (0x03 << 2)
|
|
||||||
#define DEVICE_CLASS_MINOR_PHONE_WIREDMODEM (0x04 << 2)
|
|
||||||
#define DEVICE_CLASS_MINOR_PHONE_ISDN (0x05 << 2)
|
|
||||||
|
|
||||||
#define DEVICE_CLASS_MINOR_LAN_FULLY_AVAILABLE (0x00 << 5)
|
|
||||||
#define DEVICE_CLASS_MINOR_LAN_1_TO_17_PC_UTILIZED (0x01 << 5)
|
|
||||||
#define DEVICE_CLASS_MINOR_LAN_17_TO_33_PC_UTILIZED (0x02 << 5)
|
|
||||||
#define DEVICE_CLASS_MINOR_LAN_33_TO_50_PC_UTILIZED (0x03 << 5)
|
|
||||||
#define DEVICE_CLASS_MINOR_LAN_50_TO_67_PC_UTILIZED (0x04 << 5)
|
|
||||||
#define DEVICE_CLASS_MINOR_LAN_67_TO_83_PC_UTILIZED (0x05 << 5)
|
|
||||||
#define DEVICE_CLASS_MINOR_LAN_83_TO_99_PC_UTILIZED (0x06 << 5)
|
|
||||||
#define DEVICE_CLASS_MINOR_LAN_NO_SERVICE_AVAILABLE (0x07 << 5)
|
|
||||||
|
|
||||||
#define DEVICE_CLASS_MINOR_AV_UNCATEGORIZED (0x00 << 2)
|
|
||||||
#define DEVICE_CLASS_MINOR_AV_HEADSET (0x01 << 2)
|
|
||||||
#define DEVICE_CLASS_MINOR_AV_HANDSFREE (0x02 << 2)
|
|
||||||
#define DEVICE_CLASS_MINOR_AV_MICROPHONE (0x04 << 2)
|
|
||||||
#define DEVICE_CLASS_MINOR_AV_LOUDSPEAKER (0x05 << 2)
|
|
||||||
#define DEVICE_CLASS_MINOR_AV_HEADPHONES (0x06 << 2)
|
|
||||||
#define DEVICE_CLASS_MINOR_AV_PORTABLE_AUDIO (0x07 << 2)
|
|
||||||
#define DEVICE_CLASS_MINOR_AV_CARAUDIO (0x08 << 2)
|
|
||||||
#define DEVICE_CLASS_MINOR_AV_SETTOP_BOX (0x09 << 2)
|
|
||||||
#define DEVICE_CLASS_MINOR_AV_HIFI (0x0A << 2)
|
|
||||||
#define DEVICE_CLASS_MINOR_AV_VCR (0x0B << 2)
|
|
||||||
#define DEVICE_CLASS_MINOR_AV_VIDEO_CAMERA (0x0C << 2)
|
|
||||||
#define DEVICE_CLASS_MINOR_AV_CAMCORDER (0x0D << 2)
|
|
||||||
#define DEVICE_CLASS_MINOR_AV_VIDEO_MONITOR (0x0E << 2)
|
|
||||||
#define DEVICE_CLASS_MINOR_AV_DISPLAY_AND_LOUDSPEAKER (0x0F << 2)
|
|
||||||
#define DEVICE_CLASS_MINOR_AV_VIDEO_CONFERENCING (0x10 << 2)
|
|
||||||
#define DEVICE_CLASS_MINOR_AV_GAMING_TOY (0x12 << 2)
|
|
||||||
|
|
||||||
#define DEVICE_CLASS_MINOR_PERIPHERAL_KEYBOARD (0x01 << 6)
|
|
||||||
#define DEVICE_CLASS_MINOR_PERIPHERAL_POINTING (0x02 << 6)
|
|
||||||
#define DEVICE_CLASS_MINOR_PERIPHERAL_COMBO (0x03 << 6)
|
|
||||||
#define DEVICE_CLASS_MINOR_PERIPHERAL_UNCATEGORIZED (0x00 << 2)
|
|
||||||
#define DEVICE_CLASS_MINOR_PERIPHERAL_JOYSTICK (0x01 << 2)
|
|
||||||
#define DEVICE_CLASS_MINOR_PERIPHERAL_GAMEPAD (0x02 << 2)
|
|
||||||
#define DEVICE_CLASS_MINOR_PERIPHERAL_REMOTE_CONTROL (0x03 << 2)
|
|
||||||
#define DEVICE_CLASS_MINOR_PERIPHERAL_SENSING_DEVICE (0x04 << 2)
|
|
||||||
#define DEVICE_CLASS_MINOR_PERIPHERAL_DIGITIZER (0x05 << 2)
|
|
||||||
#define DEVICE_CLASS_MINOR_PERIPHERAL_CARD_READER (0x06 << 2)
|
|
||||||
|
|
||||||
#define DEVICE_CLASS_MINOR_IMAGING_DISPLAY (1 << 4)
|
|
||||||
#define DEVICE_CLASS_MINOR_IMAGING_CAMERA (1 << 5)
|
|
||||||
#define DEVICE_CLASS_MINOR_IMAGING_SCANNER (1 << 6)
|
|
||||||
#define DEVICE_CLASS_MINOR_IMAGING_PRINTER (1 << 7)
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,406 +0,0 @@
|
|||||||
/*
|
|
||||||
LUFA Library
|
|
||||||
Copyright (C) Dean Camera, 2012.
|
|
||||||
|
|
||||||
dean [at] fourwalledcubicle [dot] com
|
|
||||||
www.lufa-lib.org
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright 2012 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
|
||||||
|
|
||||||
Permission to use, copy, modify, distribute, and sell this
|
|
||||||
software and its documentation for any purpose is hereby granted
|
|
||||||
without fee, provided that the above copyright notice appear in
|
|
||||||
all copies and that both that the copyright notice and this
|
|
||||||
permission notice and warranty disclaimer appear in supporting
|
|
||||||
documentation, and that the name of the author not be used in
|
|
||||||
advertising or publicity pertaining to distribution of the
|
|
||||||
software without specific, written prior permission.
|
|
||||||
|
|
||||||
The author disclaim all warranties with regard to this
|
|
||||||
software, including all implied warranties of merchantability
|
|
||||||
and fitness. In no event shall the author be liable for any
|
|
||||||
special, indirect or consequential damages or any damages
|
|
||||||
whatsoever resulting from loss of use, data or profits, whether
|
|
||||||
in an action of contract, negligence or other tortious action,
|
|
||||||
arising out of or in connection with the use or performance of
|
|
||||||
this software.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** \file
|
|
||||||
*
|
|
||||||
* Bluetooth HCI layer management code. This module manages the overall
|
|
||||||
* Bluetooth stack connection state to and from other devices, processes
|
|
||||||
* received events from the Bluetooth controller, and issues commands to
|
|
||||||
* modify the controller's configuration, such as the broadcast name of the
|
|
||||||
* device.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
TODO: Add local to remote device connections
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define INCLUDE_FROM_BLUETOOTHHCICOMMANDS_C
|
|
||||||
#include "BluetoothHCICommands.h"
|
|
||||||
|
|
||||||
/** Temporary Bluetooth Device Address, for HCI responses which must include the destination address */
|
|
||||||
static uint8_t Bluetooth_TempDeviceAddress[6];
|
|
||||||
|
|
||||||
/** Bluetooth HCI processing task. This task should be called repeatedly the main Bluetooth
|
|
||||||
* stack task to manage the HCI processing state.
|
|
||||||
*/
|
|
||||||
void Bluetooth_HCITask(void)
|
|
||||||
{
|
|
||||||
BT_HCICommand_Header_t HCICommandHeader;
|
|
||||||
|
|
||||||
switch (Bluetooth_State.CurrentHCIState)
|
|
||||||
{
|
|
||||||
case Bluetooth_ProcessEvents:
|
|
||||||
Pipe_SelectPipe(BLUETOOTH_EVENTS_PIPE);
|
|
||||||
Pipe_Unfreeze();
|
|
||||||
|
|
||||||
if (Pipe_IsReadWriteAllowed())
|
|
||||||
{
|
|
||||||
BT_HCIEvent_Header_t HCIEventHeader;
|
|
||||||
|
|
||||||
/* Read in the event header to fetch the event code and payload length */
|
|
||||||
Pipe_Read_Stream_LE(&HCIEventHeader, sizeof(HCIEventHeader), NULL);
|
|
||||||
|
|
||||||
/* Create a temporary buffer for the event parameters */
|
|
||||||
uint8_t EventParams[HCIEventHeader.ParameterLength];
|
|
||||||
|
|
||||||
/* Read in the event parameters into the temporary buffer */
|
|
||||||
Pipe_Read_Stream_LE(&EventParams, HCIEventHeader.ParameterLength, NULL);
|
|
||||||
Pipe_ClearIN();
|
|
||||||
|
|
||||||
BT_HCI_DEBUG(1, "Event Received (0x%02X)", HCIEventHeader.EventCode);
|
|
||||||
|
|
||||||
switch (HCIEventHeader.EventCode)
|
|
||||||
{
|
|
||||||
case EVENT_COMMAND_COMPLETE:
|
|
||||||
BT_HCI_DEBUG(1, "<< Command Complete");
|
|
||||||
|
|
||||||
/* Check which operation was completed in case we need to process the even parameters */
|
|
||||||
switch (((BT_HCIEvent_CommandComplete_t*)&EventParams)->Opcode)
|
|
||||||
{
|
|
||||||
case (OGF_CTRLR_INFORMATIONAL | OCF_CTRLR_INFORMATIONAL_READBDADDR):
|
|
||||||
/* A READ BDADDR command completed, copy over the local device's BDADDR from the response */
|
|
||||||
memcpy(Bluetooth_State.LocalBDADDR,
|
|
||||||
&((BT_HCIEvent_CommandComplete_t*)&EventParams)->ReturnParams[1],
|
|
||||||
sizeof(Bluetooth_State.LocalBDADDR));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bluetooth_State.CurrentHCIState = Bluetooth_State.NextHCIState;
|
|
||||||
break;
|
|
||||||
case EVENT_COMMAND_STATUS:
|
|
||||||
BT_HCI_DEBUG(1, "<< Command Status");
|
|
||||||
BT_HCI_DEBUG(2, "-- Status Code: 0x%02X", (((BT_HCIEvent_CommandStatus_t*)&EventParams)->Status));
|
|
||||||
|
|
||||||
/* If the execution of a command failed, reset the stack */
|
|
||||||
if (((BT_HCIEvent_CommandStatus_t*)&EventParams)->Status)
|
|
||||||
Bluetooth_State.CurrentHCIState = Bluetooth_Init;
|
|
||||||
break;
|
|
||||||
case EVENT_CONNECTION_REQUEST:
|
|
||||||
BT_HCI_DEBUG(1, "<< Connection Request");
|
|
||||||
BT_HCI_DEBUG(2, "-- Link Type: 0x%02X", (((BT_HCIEvent_ConnectionRequest_t*)&EventParams)->LinkType));
|
|
||||||
|
|
||||||
/* Need to store the remote device's BT address in a temporary buffer for later use */
|
|
||||||
memcpy(Bluetooth_TempDeviceAddress,
|
|
||||||
&((BT_HCIEvent_ConnectionRequest_t*)&EventParams)->RemoteAddress,
|
|
||||||
sizeof(Bluetooth_TempDeviceAddress));
|
|
||||||
|
|
||||||
bool IsACLConnection = (((BT_HCIEvent_ConnectionRequest_t*)&EventParams)->LinkType == 0x01);
|
|
||||||
|
|
||||||
/* Only accept the connection if it is a ACL (data) connection, a device is not already connected
|
|
||||||
and the user application has indicated that the connection should be allowed */
|
|
||||||
Bluetooth_State.CurrentHCIState = (Bluetooth_Connection.IsConnected || !(IsACLConnection) ||
|
|
||||||
!(Bluetooth_ConnectionRequest(Bluetooth_TempDeviceAddress))) ?
|
|
||||||
Bluetooth_Conn_RejectConnection : Bluetooth_Conn_AcceptConnection;
|
|
||||||
|
|
||||||
BT_HCI_DEBUG(2, "-- Connection %S", (Bluetooth_State.CurrentHCIState == Bluetooth_Conn_RejectConnection) ?
|
|
||||||
PSTR("REJECTED") : PSTR("ACCEPTED"));
|
|
||||||
|
|
||||||
break;
|
|
||||||
case EVENT_PIN_CODE_REQUEST:
|
|
||||||
BT_HCI_DEBUG(1, "<< Pin Code Request");
|
|
||||||
|
|
||||||
/* Need to store the remote device's BT address in a temporary buffer for later use */
|
|
||||||
memcpy(Bluetooth_TempDeviceAddress,
|
|
||||||
&((BT_HCIEvent_PinCodeReq_t*)&EventParams)->RemoteAddress,
|
|
||||||
sizeof(Bluetooth_TempDeviceAddress));
|
|
||||||
|
|
||||||
Bluetooth_State.CurrentHCIState = Bluetooth_Conn_SendPINCode;
|
|
||||||
break;
|
|
||||||
case EVENT_LINK_KEY_REQUEST:
|
|
||||||
BT_HCI_DEBUG(1, "<< Link Key Request");
|
|
||||||
|
|
||||||
/* Need to store the remote device's BT address in a temporary buffer for later use */
|
|
||||||
memcpy(Bluetooth_TempDeviceAddress,
|
|
||||||
&((BT_HCIEvent_LinkKeyReq_t*)&EventParams)->RemoteAddress,
|
|
||||||
sizeof(Bluetooth_TempDeviceAddress));
|
|
||||||
|
|
||||||
Bluetooth_State.CurrentHCIState = Bluetooth_Conn_SendLinkKeyNAK;
|
|
||||||
break;
|
|
||||||
case EVENT_CONNECTION_COMPLETE:
|
|
||||||
BT_HCI_DEBUG(1, "<< Connection Complete");
|
|
||||||
BT_HCI_DEBUG(2, "-- Handle: 0x%04X", ((BT_HCIEvent_ConnectionComplete_t*)&EventParams)->ConnectionHandle);
|
|
||||||
|
|
||||||
/* Need to store the remote device's BT address in a temporary buffer for later use */
|
|
||||||
memcpy(Bluetooth_Connection.RemoteAddress,
|
|
||||||
&((BT_HCIEvent_ConnectionComplete_t*)&EventParams)->RemoteAddress,
|
|
||||||
sizeof(Bluetooth_TempDeviceAddress));
|
|
||||||
|
|
||||||
/* Store the created connection handle and indicate that the connection has been established */
|
|
||||||
Bluetooth_Connection.ConnectionHandle = ((BT_HCIEvent_ConnectionComplete_t*)&EventParams)->ConnectionHandle;
|
|
||||||
Bluetooth_Connection.IsConnected = true;
|
|
||||||
|
|
||||||
Bluetooth_ConnectionComplete();
|
|
||||||
break;
|
|
||||||
case EVENT_DISCONNECTION_COMPLETE:
|
|
||||||
BT_HCI_DEBUG(1, "<< Disconnection Complete");
|
|
||||||
|
|
||||||
/* Device disconnected, indicate connection information no longer valid */
|
|
||||||
Bluetooth_Connection.IsConnected = false;
|
|
||||||
|
|
||||||
Bluetooth_DisconnectionComplete();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Pipe_Freeze();
|
|
||||||
|
|
||||||
break;
|
|
||||||
case Bluetooth_Init:
|
|
||||||
BT_HCI_DEBUG(1, "# Init");
|
|
||||||
|
|
||||||
Bluetooth_State.IsInitialized = false;
|
|
||||||
|
|
||||||
/* Reset the connection information structure to destroy any previous connection state */
|
|
||||||
memset(&Bluetooth_Connection, 0x00, sizeof(Bluetooth_Connection));
|
|
||||||
|
|
||||||
Bluetooth_State.CurrentHCIState = Bluetooth_Init_Reset;
|
|
||||||
break;
|
|
||||||
case Bluetooth_Init_Reset:
|
|
||||||
BT_HCI_DEBUG(1, "# Reset");
|
|
||||||
|
|
||||||
HCICommandHeader = (BT_HCICommand_Header_t)
|
|
||||||
{
|
|
||||||
OpCode: (OGF_CTRLR_BASEBAND | OCF_CTRLR_BASEBAND_RESET),
|
|
||||||
ParameterLength: 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Send the command to reset the Bluetooth dongle controller */
|
|
||||||
Bluetooth_SendHCICommand(&HCICommandHeader, NULL, 0);
|
|
||||||
|
|
||||||
Bluetooth_State.NextHCIState = Bluetooth_Init_ReadBufferSize;
|
|
||||||
Bluetooth_State.CurrentHCIState = Bluetooth_ProcessEvents;
|
|
||||||
break;
|
|
||||||
case Bluetooth_Init_ReadBufferSize:
|
|
||||||
BT_HCI_DEBUG(1, "# Read Buffer Size");
|
|
||||||
|
|
||||||
HCICommandHeader = (BT_HCICommand_Header_t)
|
|
||||||
{
|
|
||||||
OpCode: (OGF_CTRLR_INFORMATIONAL | OCF_CTRLR_INFORMATIONAL_READBUFFERSIZE),
|
|
||||||
ParameterLength: 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Send the command to read the Bluetooth buffer size (mandatory before device sends any data) */
|
|
||||||
Bluetooth_SendHCICommand(&HCICommandHeader, NULL, 0);
|
|
||||||
|
|
||||||
Bluetooth_State.NextHCIState = Bluetooth_Init_GetBDADDR;
|
|
||||||
Bluetooth_State.CurrentHCIState = Bluetooth_ProcessEvents;
|
|
||||||
break;
|
|
||||||
case Bluetooth_Init_GetBDADDR:
|
|
||||||
BT_HCI_DEBUG(1, "# Get BDADDR");
|
|
||||||
|
|
||||||
HCICommandHeader = (BT_HCICommand_Header_t)
|
|
||||||
{
|
|
||||||
OpCode: (OGF_CTRLR_INFORMATIONAL | OCF_CTRLR_INFORMATIONAL_READBDADDR),
|
|
||||||
ParameterLength: 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Send the command to retrieve the BDADDR of the inserted Bluetooth dongle */
|
|
||||||
Bluetooth_SendHCICommand(&HCICommandHeader, NULL, 0);
|
|
||||||
|
|
||||||
Bluetooth_State.NextHCIState = Bluetooth_Init_SetLocalName;
|
|
||||||
Bluetooth_State.CurrentHCIState = Bluetooth_ProcessEvents;
|
|
||||||
break;
|
|
||||||
case Bluetooth_Init_SetLocalName:
|
|
||||||
BT_HCI_DEBUG(1, "# Set Local Name");
|
|
||||||
|
|
||||||
HCICommandHeader = (BT_HCICommand_Header_t)
|
|
||||||
{
|
|
||||||
OpCode: (OGF_CTRLR_BASEBAND | OCF_CTRLR_BASEBAND_WRITE_LOCAL_NAME),
|
|
||||||
ParameterLength: 248,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Send the command to set the Bluetooth dongle's name for other devices to see */
|
|
||||||
Bluetooth_SendHCICommand(&HCICommandHeader, Bluetooth_DeviceConfiguration.Name, strlen(Bluetooth_DeviceConfiguration.Name));
|
|
||||||
|
|
||||||
Bluetooth_State.NextHCIState = Bluetooth_Init_SetDeviceClass;
|
|
||||||
Bluetooth_State.CurrentHCIState = Bluetooth_ProcessEvents;
|
|
||||||
break;
|
|
||||||
case Bluetooth_Init_SetDeviceClass:
|
|
||||||
BT_HCI_DEBUG(1, "# Set Device Class");
|
|
||||||
|
|
||||||
HCICommandHeader = (BT_HCICommand_Header_t)
|
|
||||||
{
|
|
||||||
OpCode: (OGF_CTRLR_BASEBAND | OCF_CTRLR_BASEBAND_WRITE_CLASS_OF_DEVICE),
|
|
||||||
ParameterLength: 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Send the command to set the class of the device for other devices to see */
|
|
||||||
Bluetooth_SendHCICommand(&HCICommandHeader, &Bluetooth_DeviceConfiguration.Class, 3);
|
|
||||||
|
|
||||||
Bluetooth_State.NextHCIState = Bluetooth_Init_WriteScanEnable;
|
|
||||||
Bluetooth_State.CurrentHCIState = Bluetooth_ProcessEvents;
|
|
||||||
break;
|
|
||||||
case Bluetooth_Init_WriteScanEnable:
|
|
||||||
BT_HCI_DEBUG(1, "# Write Scan Enable");
|
|
||||||
|
|
||||||
HCICommandHeader = (BT_HCICommand_Header_t)
|
|
||||||
{
|
|
||||||
OpCode: (OGF_CTRLR_BASEBAND | OCF_CTRLR_BASEBAND_WRITE_SCAN_ENABLE),
|
|
||||||
ParameterLength: 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
uint8_t Interval = BT_SCANMODE_InquiryAndPageScans;
|
|
||||||
|
|
||||||
/* Send the command to set the remote device scanning mode */
|
|
||||||
Bluetooth_SendHCICommand(&HCICommandHeader, &Interval, 1);
|
|
||||||
|
|
||||||
Bluetooth_State.NextHCIState = Bluetooth_Init_FinalizeInit;
|
|
||||||
Bluetooth_State.CurrentHCIState = Bluetooth_ProcessEvents;
|
|
||||||
break;
|
|
||||||
case Bluetooth_Init_FinalizeInit:
|
|
||||||
Bluetooth_State.IsInitialized = true;
|
|
||||||
|
|
||||||
/* Fire the user application callback to indicate that the stack is now fully initialized */
|
|
||||||
Bluetooth_StackInitialized();
|
|
||||||
|
|
||||||
Bluetooth_State.NextHCIState = Bluetooth_ProcessEvents;
|
|
||||||
Bluetooth_State.CurrentHCIState = Bluetooth_ProcessEvents;
|
|
||||||
break;
|
|
||||||
case Bluetooth_Conn_AcceptConnection:
|
|
||||||
BT_HCI_DEBUG(1, "# Accept Connection");
|
|
||||||
|
|
||||||
HCICommandHeader = (BT_HCICommand_Header_t)
|
|
||||||
{
|
|
||||||
OpCode: (OGF_LINK_CONTROL | OCF_LINK_CONTROL_ACCEPT_CONNECTION_REQUEST),
|
|
||||||
ParameterLength: sizeof(BT_HCICommand_AcceptConnectionReq_t),
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Copy over the temporary BT device address saved from the Connection Request event, indicate slave
|
|
||||||
connection role */
|
|
||||||
BT_HCICommand_AcceptConnectionReq_t AcceptConnectionParams;
|
|
||||||
memcpy(AcceptConnectionParams.RemoteAddress, Bluetooth_TempDeviceAddress,
|
|
||||||
sizeof(AcceptConnectionParams.RemoteAddress));
|
|
||||||
AcceptConnectionParams.SlaveRole = true;
|
|
||||||
|
|
||||||
/* Send the command to accept the remote connection request */
|
|
||||||
Bluetooth_SendHCICommand(&HCICommandHeader, &AcceptConnectionParams, sizeof(BT_HCICommand_AcceptConnectionReq_t));
|
|
||||||
|
|
||||||
Bluetooth_State.CurrentHCIState = Bluetooth_ProcessEvents;
|
|
||||||
break;
|
|
||||||
case Bluetooth_Conn_RejectConnection:
|
|
||||||
BT_HCI_DEBUG(1, "# Reject Connection");
|
|
||||||
|
|
||||||
HCICommandHeader = (BT_HCICommand_Header_t)
|
|
||||||
{
|
|
||||||
OpCode: (OGF_LINK_CONTROL | OCF_LINK_CONTROL_REJECT_CONNECTION_REQUEST),
|
|
||||||
ParameterLength: sizeof(BT_HCICommand_RejectConnectionReq_t),
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Copy over the temporary BT device address saved from the Connection Request event, indicate failure
|
|
||||||
to accept the connection due to limited device resources or incorrect device address */
|
|
||||||
BT_HCICommand_RejectConnectionReq_t RejectConnectionParams;
|
|
||||||
memcpy(RejectConnectionParams.RemoteAddress, Bluetooth_TempDeviceAddress, sizeof(RejectConnectionParams.RemoteAddress));
|
|
||||||
RejectConnectionParams.Reason = Bluetooth_Connection.IsConnected ? ERROR_LIMITED_RESOURCES : ERROR_UNACCEPTABLE_BDADDR;
|
|
||||||
|
|
||||||
/* Send the command to reject the remote connection request */
|
|
||||||
Bluetooth_SendHCICommand(&HCICommandHeader, &RejectConnectionParams, sizeof(BT_HCICommand_RejectConnectionReq_t));
|
|
||||||
|
|
||||||
Bluetooth_State.CurrentHCIState = Bluetooth_ProcessEvents;
|
|
||||||
break;
|
|
||||||
case Bluetooth_Conn_SendPINCode:
|
|
||||||
BT_HCI_DEBUG(1, "# Send Pin Code");
|
|
||||||
|
|
||||||
HCICommandHeader = (BT_HCICommand_Header_t)
|
|
||||||
{
|
|
||||||
OpCode: (OGF_LINK_CONTROL | OCF_LINK_CONTROL_PIN_CODE_REQUEST_REPLY),
|
|
||||||
ParameterLength: sizeof(BT_HCICommand_PinCodeResp_t),
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Copy over the temporary BT device address saved from the PIN Code Request event, copy over the
|
|
||||||
local PIN authentication code to the response */
|
|
||||||
BT_HCICommand_PinCodeResp_t PINCodeRequestParams;
|
|
||||||
memcpy(PINCodeRequestParams.RemoteAddress, Bluetooth_TempDeviceAddress, sizeof(PINCodeRequestParams.RemoteAddress));
|
|
||||||
PINCodeRequestParams.PINCodeLength = strlen(Bluetooth_DeviceConfiguration.PINCode);
|
|
||||||
memcpy(PINCodeRequestParams.PINCode, Bluetooth_DeviceConfiguration.PINCode, sizeof(PINCodeRequestParams.PINCode));
|
|
||||||
|
|
||||||
/* Send the command to transmit the device's local PIN number for authentication */
|
|
||||||
Bluetooth_SendHCICommand(&HCICommandHeader, &PINCodeRequestParams, sizeof(BT_HCICommand_PinCodeResp_t));
|
|
||||||
|
|
||||||
Bluetooth_State.CurrentHCIState = Bluetooth_ProcessEvents;
|
|
||||||
break;
|
|
||||||
case Bluetooth_Conn_SendLinkKeyNAK:
|
|
||||||
BT_HCI_DEBUG(1, "# Send Link Key NAK");
|
|
||||||
|
|
||||||
HCICommandHeader = (BT_HCICommand_Header_t)
|
|
||||||
{
|
|
||||||
OpCode: (OGF_LINK_CONTROL | OCF_LINK_CONTROL_LINK_KEY_REQUEST_NEG_REPLY),
|
|
||||||
ParameterLength: sizeof(BT_HCICommand_LinkKeyNAKResp_t),
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Copy over the temporary BT device address saved from the Link Key Request event */
|
|
||||||
BT_HCICommand_LinkKeyNAKResp_t LinkKeyNAKParams;
|
|
||||||
memcpy(LinkKeyNAKParams.RemoteAddress, Bluetooth_TempDeviceAddress, sizeof(LinkKeyNAKParams.RemoteAddress));
|
|
||||||
|
|
||||||
/* Send the command to transmit the link key NAK to the receiver */
|
|
||||||
Bluetooth_SendHCICommand(&HCICommandHeader, &LinkKeyNAKParams, sizeof(BT_HCICommand_LinkKeyNAKResp_t));
|
|
||||||
|
|
||||||
Bluetooth_State.CurrentHCIState = Bluetooth_ProcessEvents;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Sends a Bluetooth HCI control command to the attached Bluetooth device.
|
|
||||||
*
|
|
||||||
* \param[in] HCICommandHeader HCI command header to send to the attached device
|
|
||||||
* \param[in] Parameters Pointer to the source of the control parameters (if any)
|
|
||||||
* \param[in] ParameterLength Length of the parameters to send in bytes
|
|
||||||
*
|
|
||||||
* \return A value from the USB_Host_SendControlErrorCodes_t enum.
|
|
||||||
*/
|
|
||||||
static uint8_t Bluetooth_SendHCICommand(const BT_HCICommand_Header_t* const HCICommandHeader,
|
|
||||||
const void* Parameters,
|
|
||||||
const uint16_t ParameterLength)
|
|
||||||
{
|
|
||||||
/* Need to reserve the amount of bytes given in the header for the complete payload */
|
|
||||||
uint8_t CommandBuffer[sizeof(BT_HCICommand_Header_t) + HCICommandHeader->ParameterLength];
|
|
||||||
|
|
||||||
USB_ControlRequest = (USB_Request_Header_t)
|
|
||||||
{
|
|
||||||
.bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_DEVICE),
|
|
||||||
.bRequest = 0,
|
|
||||||
.wValue = 0,
|
|
||||||
.wIndex = 0,
|
|
||||||
.wLength = sizeof(CommandBuffer)
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Copy over the HCI command header to the allocated buffer */
|
|
||||||
memcpy(CommandBuffer, HCICommandHeader, sizeof(BT_HCICommand_Header_t));
|
|
||||||
|
|
||||||
/* Zero out the parameter section of the response so that all padding bytes are known to be zero */
|
|
||||||
memset(&CommandBuffer[sizeof(BT_HCICommand_Header_t)], 0x00, HCICommandHeader->ParameterLength);
|
|
||||||
|
|
||||||
/* Copy over the command parameters (if any) to the command buffer - note, the number of actual source parameter bytes
|
|
||||||
may differ to those in the header; any difference in length is filled with 0x00 padding bytes */
|
|
||||||
memcpy(&CommandBuffer[sizeof(BT_HCICommand_Header_t)], Parameters, ParameterLength);
|
|
||||||
|
|
||||||
Pipe_SelectPipe(PIPE_CONTROLPIPE);
|
|
||||||
return USB_Host_SendControlRequest(CommandBuffer);
|
|
||||||
}
|
|
||||||
|
|
@ -1,213 +0,0 @@
|
|||||||
/*
|
|
||||||
LUFA Library
|
|
||||||
Copyright (C) Dean Camera, 2012.
|
|
||||||
|
|
||||||
dean [at] fourwalledcubicle [dot] com
|
|
||||||
www.lufa-lib.org
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright 2012 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
|
||||||
|
|
||||||
Permission to use, copy, modify, distribute, and sell this
|
|
||||||
software and its documentation for any purpose is hereby granted
|
|
||||||
without fee, provided that the above copyright notice appear in
|
|
||||||
all copies and that both that the copyright notice and this
|
|
||||||
permission notice and warranty disclaimer appear in supporting
|
|
||||||
documentation, and that the name of the author not be used in
|
|
||||||
advertising or publicity pertaining to distribution of the
|
|
||||||
software without specific, written prior permission.
|
|
||||||
|
|
||||||
The author disclaim all warranties with regard to this
|
|
||||||
software, including all implied warranties of merchantability
|
|
||||||
and fitness. In no event shall the author be liable for any
|
|
||||||
special, indirect or consequential damages or any damages
|
|
||||||
whatsoever resulting from loss of use, data or profits, whether
|
|
||||||
in an action of contract, negligence or other tortious action,
|
|
||||||
arising out of or in connection with the use or performance of
|
|
||||||
this software.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** \file
|
|
||||||
*
|
|
||||||
* Header file for BluetoothHCICommands.c.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _BLUETOOTH_HCICOMMANDS_H_
|
|
||||||
#define _BLUETOOTH_HCICOMMANDS_H_
|
|
||||||
|
|
||||||
/* Includes: */
|
|
||||||
#include <avr/io.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include <LUFA/Drivers/USB/USB.h>
|
|
||||||
#include <LUFA/Drivers/Peripheral/Serial.h>
|
|
||||||
|
|
||||||
#include "BluetoothStack.h"
|
|
||||||
#include "BluetoothClassCodes.h"
|
|
||||||
|
|
||||||
/* Macros: */
|
|
||||||
#define BT_HCI_DEBUG(l, s, ...) do { if (HCI_DEBUG_LEVEL >= l) printf_P(PSTR("(HCI) " s "\r\n"), ##__VA_ARGS__); } while (0)
|
|
||||||
#define HCI_DEBUG_LEVEL 0
|
|
||||||
|
|
||||||
#define OGF_LINK_CONTROL (0x01 << 10)
|
|
||||||
#define OGF_CTRLR_BASEBAND (0x03 << 10)
|
|
||||||
#define OGF_CTRLR_INFORMATIONAL (0x04 << 10)
|
|
||||||
|
|
||||||
#define OCF_LINK_CONTROL_INQUIRY 0x0001
|
|
||||||
#define OCF_LINK_CONTROL_INQUIRY_CANCEL 0x0002
|
|
||||||
#define OCF_LINK_CONTROL_PERIODIC_INQUIRY 0x0003
|
|
||||||
#define OCF_LINK_CONTROL_EXIT_PERIODIC_INQUIRY 0x0004
|
|
||||||
#define OCF_LINK_CONTROL_CREATE_CONNECTION 0x0005
|
|
||||||
#define OCF_LINK_CONTROL_DISCONNECT 0x0006
|
|
||||||
#define OCF_LINK_CONTROL_CREATE_CONNECTION_CANCEL 0x0008
|
|
||||||
#define OCF_LINK_CONTROL_ACCEPT_CONNECTION_REQUEST 0x0009
|
|
||||||
#define OCF_LINK_CONTROL_REJECT_CONNECTION_REQUEST 0x000A
|
|
||||||
#define OCF_LINK_CONTROL_LINK_KEY_REQUEST_REPLY 0x000B
|
|
||||||
#define OCF_LINK_CONTROL_LINK_KEY_REQUEST_NEG_REPLY 0x000C
|
|
||||||
#define OCF_LINK_CONTROL_PIN_CODE_REQUEST_REPLY 0x000D
|
|
||||||
#define OCF_LINK_CONTROL_PIN_CODE_REQUEST_NEG_REPLY 0x000E
|
|
||||||
#define OCF_LINK_CONTROL_CHANGE_CONNECTION_PACKET_TYPE 0x000F
|
|
||||||
#define OCF_LINK_CONTROL_REMOTE_NAME_REQUEST 0x0019
|
|
||||||
#define OCF_CTRLR_BASEBAND_SET_EVENT_MASK 0x0001
|
|
||||||
#define OCF_CTRLR_BASEBAND_RESET 0x0003
|
|
||||||
#define OCF_CTRLR_BASEBAND_WRITE_PIN_TYPE 0x000A
|
|
||||||
#define OCF_CTRLR_BASEBAND_WRITE_LOCAL_NAME 0x0013
|
|
||||||
#define OCF_CTRLR_BASEBAND_READ_LOCAL_NAME 0x0014
|
|
||||||
#define OCF_CTRLR_BASEBAND_WRITE_SCAN_ENABLE 0x001A
|
|
||||||
#define OCF_CTRLR_BASEBAND_WRITE_CLASS_OF_DEVICE 0x0024
|
|
||||||
#define OCF_CTRLR_BASEBAND_WRITE_SIMPLE_PAIRING_MODE 0x0056
|
|
||||||
#define OCF_CTRLR_BASEBAND_WRITE_AUTHENTICATION_ENABLE 0x0020
|
|
||||||
#define OCF_CTRLR_INFORMATIONAL_READBUFFERSIZE 0x0005
|
|
||||||
#define OCF_CTRLR_INFORMATIONAL_READBDADDR 0x0009
|
|
||||||
|
|
||||||
#define EVENT_COMMAND_STATUS 0x0F
|
|
||||||
#define EVENT_COMMAND_COMPLETE 0x0E
|
|
||||||
#define EVENT_CONNECTION_COMPLETE 0x03
|
|
||||||
#define EVENT_CONNECTION_REQUEST 0x04
|
|
||||||
#define EVENT_DISCONNECTION_COMPLETE 0x05
|
|
||||||
#define EVENT_REMOTE_NAME_REQUEST_COMPLETE 0x07
|
|
||||||
#define EVENT_PIN_CODE_REQUEST 0x16
|
|
||||||
#define EVENT_LINK_KEY_REQUEST 0x17
|
|
||||||
|
|
||||||
#define ERROR_LIMITED_RESOURCES 0x0D
|
|
||||||
#define ERROR_UNACCEPTABLE_BDADDR 0x0F
|
|
||||||
|
|
||||||
/* Type Defines: */
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint16_t OpCode;
|
|
||||||
uint8_t ParameterLength;
|
|
||||||
uint8_t Parameters[];
|
|
||||||
} BT_HCICommand_Header_t;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint8_t EventCode;
|
|
||||||
uint8_t ParameterLength;
|
|
||||||
} BT_HCIEvent_Header_t;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint8_t Status;
|
|
||||||
uint8_t Packets;
|
|
||||||
uint16_t OpCode;
|
|
||||||
} BT_HCIEvent_CommandStatus_t;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint8_t HCIPacketsAllowable;
|
|
||||||
uint16_t Opcode;
|
|
||||||
uint8_t ReturnParams[];
|
|
||||||
} BT_HCIEvent_CommandComplete_t;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint8_t RemoteAddress[6];
|
|
||||||
uint8_t ClassOfDevice_Service;
|
|
||||||
uint16_t ClassOfDevice_MajorMinor;
|
|
||||||
uint8_t LinkType;
|
|
||||||
} BT_HCIEvent_ConnectionRequest_t;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint8_t Status;
|
|
||||||
uint16_t ConnectionHandle;
|
|
||||||
uint8_t RemoteAddress[6];
|
|
||||||
uint8_t LinkType;
|
|
||||||
uint8_t EncryptionEnabled;
|
|
||||||
} BT_HCIEvent_ConnectionComplete_t;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint8_t RemoteAddress[6];
|
|
||||||
} BT_HCIEvent_PinCodeReq_t;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint8_t RemoteAddress[6];
|
|
||||||
} BT_HCIEvent_LinkKeyReq_t;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint8_t RemoteAddress[6];
|
|
||||||
} BT_HCICommand_LinkKeyNAKResp_t;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint8_t RemoteAddress[6];
|
|
||||||
uint8_t PINCodeLength;
|
|
||||||
char PINCode[16];
|
|
||||||
} BT_HCICommand_PinCodeResp_t;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint8_t RemoteAddress[6];
|
|
||||||
uint8_t SlaveRole;
|
|
||||||
} BT_HCICommand_AcceptConnectionReq_t;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint8_t RemoteAddress[6];
|
|
||||||
uint8_t Reason;
|
|
||||||
} BT_HCICommand_RejectConnectionReq_t;
|
|
||||||
|
|
||||||
/* Enums: */
|
|
||||||
enum BT_ScanEnable_Modes_t
|
|
||||||
{
|
|
||||||
BT_SCANMODE_NoScansEnabled = 0,
|
|
||||||
BT_SCANMODE_InquiryScanOnly = 1,
|
|
||||||
BT_SCANMODE_PageScanOnly = 2,
|
|
||||||
BT_SCANMODE_InquiryAndPageScans = 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum BT_HCIStates_t
|
|
||||||
{
|
|
||||||
Bluetooth_ProcessEvents = 0,
|
|
||||||
Bluetooth_Init = 1,
|
|
||||||
Bluetooth_Init_Reset = 2,
|
|
||||||
Bluetooth_Init_ReadBufferSize = 3,
|
|
||||||
Bluetooth_Init_GetBDADDR = 4,
|
|
||||||
Bluetooth_Init_SetLocalName = 5,
|
|
||||||
Bluetooth_Init_SetDeviceClass = 6,
|
|
||||||
Bluetooth_Init_WriteScanEnable = 7,
|
|
||||||
Bluetooth_Init_FinalizeInit = 8,
|
|
||||||
Bluetooth_Conn_AcceptConnection = 9,
|
|
||||||
Bluetooth_Conn_RejectConnection = 10,
|
|
||||||
Bluetooth_Conn_SendPINCode = 11,
|
|
||||||
Bluetooth_Conn_SendLinkKeyNAK = 12,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Function Prototypes: */
|
|
||||||
void Bluetooth_HCITask(void);
|
|
||||||
|
|
||||||
#if defined(INCLUDE_FROM_BLUETOOTHHCICOMMANDS_C)
|
|
||||||
static uint8_t Bluetooth_SendHCICommand(const BT_HCICommand_Header_t* const HCICommandHeader,
|
|
||||||
const void* Parameters,
|
|
||||||
const uint16_t ParameterLength);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,74 +0,0 @@
|
|||||||
/*
|
|
||||||
LUFA Library
|
|
||||||
Copyright (C) Dean Camera, 2012.
|
|
||||||
|
|
||||||
dean [at] fourwalledcubicle [dot] com
|
|
||||||
www.lufa-lib.org
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright 2012 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
|
||||||
|
|
||||||
Permission to use, copy, modify, distribute, and sell this
|
|
||||||
software and its documentation for any purpose is hereby granted
|
|
||||||
without fee, provided that the above copyright notice appear in
|
|
||||||
all copies and that both that the copyright notice and this
|
|
||||||
permission notice and warranty disclaimer appear in supporting
|
|
||||||
documentation, and that the name of the author not be used in
|
|
||||||
advertising or publicity pertaining to distribution of the
|
|
||||||
software without specific, written prior permission.
|
|
||||||
|
|
||||||
The author disclaim all warranties with regard to this
|
|
||||||
software, including all implied warranties of merchantability
|
|
||||||
and fitness. In no event shall the author be liable for any
|
|
||||||
special, indirect or consequential damages or any damages
|
|
||||||
whatsoever resulting from loss of use, data or profits, whether
|
|
||||||
in an action of contract, negligence or other tortious action,
|
|
||||||
arising out of or in connection with the use or performance of
|
|
||||||
this software.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** \file
|
|
||||||
*
|
|
||||||
* Main module for the Bluetooth stack. This module contains the overall Bluetooth
|
|
||||||
* stack state variables and the main Bluetooth stack management functions.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "BluetoothStack.h"
|
|
||||||
|
|
||||||
/** Bluetooth device connection information structure. Once connected to a remote device, this structure tracks the
|
|
||||||
* connection state of the individual L2CAP channels.
|
|
||||||
*/
|
|
||||||
Bluetooth_Connection_t Bluetooth_Connection = { IsConnected: false };
|
|
||||||
|
|
||||||
/** Bluetooth device state information structure. This structure contains details on the current Bluetooth stack
|
|
||||||
* state.
|
|
||||||
*/
|
|
||||||
Bluetooth_Stack_State_t Bluetooth_State = { IsInitialized: false };
|
|
||||||
|
|
||||||
/** Bluetooth stack initialization function. This function must be called once to initialize the Bluetooth stack,
|
|
||||||
* ready for connection to remote devices.
|
|
||||||
*
|
|
||||||
* \note This function only begins the initialization process; the stack is initialized as the main Bluetooth stack
|
|
||||||
* management task is repeatedly called. The initialization process ends when the IsInitialized element of the
|
|
||||||
* \ref Bluetooth_State structure becomes true and the \ref Bluetooth_StackInitialized() callback fires.
|
|
||||||
*/
|
|
||||||
void Bluetooth_Stack_Init(void)
|
|
||||||
{
|
|
||||||
/* Reset the HCI state machine - this will reset the adapter and stack when the Bluetooth stack task is called */
|
|
||||||
Bluetooth_State.CurrentHCIState = Bluetooth_Init;
|
|
||||||
Bluetooth_State.NextHCIState = Bluetooth_Init;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Bluetooth stack management task. This task must be repeatedly called to maintain the Bluetooth stack and any connection
|
|
||||||
* to remote Bluetooth devices, including both the HCI control layer and the ACL channel layer.
|
|
||||||
*/
|
|
||||||
void Bluetooth_Stack_USBTask(void)
|
|
||||||
{
|
|
||||||
if (USB_HostState != HOST_STATE_Configured)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Bluetooth_HCITask();
|
|
||||||
Bluetooth_ACLTask();
|
|
||||||
}
|
|
||||||
|
|
@ -1,174 +0,0 @@
|
|||||||
/*
|
|
||||||
LUFA Library
|
|
||||||
Copyright (C) Dean Camera, 2012.
|
|
||||||
|
|
||||||
dean [at] fourwalledcubicle [dot] com
|
|
||||||
www.lufa-lib.org
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright 2012 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
|
||||||
|
|
||||||
Permission to use, copy, modify, distribute, and sell this
|
|
||||||
software and its documentation for any purpose is hereby granted
|
|
||||||
without fee, provided that the above copyright notice appear in
|
|
||||||
all copies and that both that the copyright notice and this
|
|
||||||
permission notice and warranty disclaimer appear in supporting
|
|
||||||
documentation, and that the name of the author not be used in
|
|
||||||
advertising or publicity pertaining to distribution of the
|
|
||||||
software without specific, written prior permission.
|
|
||||||
|
|
||||||
The author disclaim all warranties with regard to this
|
|
||||||
software, including all implied warranties of merchantability
|
|
||||||
and fitness. In no event shall the author be liable for any
|
|
||||||
special, indirect or consequential damages or any damages
|
|
||||||
whatsoever resulting from loss of use, data or profits, whether
|
|
||||||
in an action of contract, negligence or other tortious action,
|
|
||||||
arising out of or in connection with the use or performance of
|
|
||||||
this software.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** \file
|
|
||||||
*
|
|
||||||
* Header file for BluetoothStack.c.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _BLUETOOTH_STACK_
|
|
||||||
#define _BLUETOOTH_STACK_
|
|
||||||
|
|
||||||
/* Includes: */
|
|
||||||
#include <LUFA/Drivers/USB/USB.h>
|
|
||||||
|
|
||||||
#include "../ConfigDescriptor.h"
|
|
||||||
|
|
||||||
/* Macros: */
|
|
||||||
#define BLUETOOTH_MAX_OPEN_CHANNELS 6
|
|
||||||
|
|
||||||
#define CHANNEL_PSM_SDP 0x0001
|
|
||||||
#define CHANNEL_PSM_UDP 0x0002
|
|
||||||
#define CHANNEL_PSM_RFCOMM 0x0003
|
|
||||||
#define CHANNEL_PSM_TCP 0x0004
|
|
||||||
#define CHANNEL_PSM_IP 0x0009
|
|
||||||
#define CHANNEL_PSM_FTP 0x000A
|
|
||||||
#define CHANNEL_PSM_HTTP 0x000C
|
|
||||||
#define CHANNEL_PSM_UPNP 0x0010
|
|
||||||
#define CHANNEL_PSM_HIDP 0x0011
|
|
||||||
|
|
||||||
#define CHANNEL_SEARCH_LOCALNUMBER 0
|
|
||||||
#define CHANNEL_SEARCH_REMOTENUMBER 1
|
|
||||||
#define CHANNEL_SEARCH_PSM 2
|
|
||||||
|
|
||||||
#define MAXIMUM_CHANNEL_MTU 255
|
|
||||||
|
|
||||||
/* Enums: */
|
|
||||||
/** Enum for the possible states for a Bluetooth ACL channel. */
|
|
||||||
enum BT_ChannelStates_t
|
|
||||||
{
|
|
||||||
BT_Channel_Closed = 0, /**< Channel is closed and inactive. No data may be sent or received. */
|
|
||||||
BT_Channel_WaitConnect = 1, /**< A connection request has been received, but a response has not been sent. */
|
|
||||||
BT_Channel_WaitConnectRsp = 2, /**< A connection request has been sent, but a response has not been received. */
|
|
||||||
BT_Channel_Config_WaitConfig = 3, /**< Channel has been connected, but not yet configured on either end. */
|
|
||||||
BT_Channel_Config_WaitSendConfig = 4, /**< Channel configuration has been received and accepted, but not yet sent. */
|
|
||||||
BT_Channel_Config_WaitReqResp = 5, /**< Channel configuration has been sent but not responded to, and a configuration
|
|
||||||
* request from the remote end has not yet been received.
|
|
||||||
*/
|
|
||||||
BT_Channel_Config_WaitResp = 6, /**< Channel configuration has been sent but not accepted, but a configuration request
|
|
||||||
* from the remote end has been accepted.
|
|
||||||
*/
|
|
||||||
BT_Channel_Config_WaitReq = 7, /**< Channel configuration has been sent and accepted, but a configuration request
|
|
||||||
* from the remote end has not yet been accepted.
|
|
||||||
*/
|
|
||||||
BT_Channel_Open = 8, /**< Channel is open and ready to send or receive data */
|
|
||||||
BT_Channel_WaitDisconnect = 9, /**< A disconnection request has been sent, but not yet acknowledged. */
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Enum for the possible error codes returned by the \ref Bluetooth_SendPacket() function. */
|
|
||||||
enum BT_SendPacket_ErrorCodes_t
|
|
||||||
{
|
|
||||||
BT_SENDPACKET_NoError = 0, /**< The packet was sent successfully. */
|
|
||||||
BT_SENDPACKET_NotConnected = 1, /**< The Bluetooth stack is not currently connected to a remote device. */
|
|
||||||
BT_SENDPACKET_ChannelNotOpen = 2, /**< The given channel is not currently in the Open state. */
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Type Defines: */
|
|
||||||
/** Type define for a Bluetooth ACL channel information structure. This structure contains all the relevant
|
|
||||||
* information on an ACL channel for data transmission and reception by the stack.
|
|
||||||
*/
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint8_t State; /**< Current channel state, a value from the \ref BT_ChannelStates_t enum. */
|
|
||||||
uint16_t LocalNumber; /**< Local channel number on the device. */
|
|
||||||
uint16_t RemoteNumber; /**< Remote channel number on the connected device. */
|
|
||||||
uint16_t PSM; /**< Protocol used on the channel. */
|
|
||||||
uint16_t LocalMTU; /**< MTU of data sent from the connected device to the local device. */
|
|
||||||
uint16_t RemoteMTU; /**< MTU of data sent from the local device to the connected device. */
|
|
||||||
} Bluetooth_Channel_t;
|
|
||||||
|
|
||||||
/** Type define for a Bluetooth device connection information structure. This structure contains all the
|
|
||||||
* information needed to maintain a connection to a remote Bluetooth device via the Bluetooth stack.
|
|
||||||
*/
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
bool IsConnected; /**< Indicates if the stack is currently connected to a remote device - if this value is
|
|
||||||
* false, the remaining elements are invalid.
|
|
||||||
*/
|
|
||||||
uint16_t ConnectionHandle; /**< Connection handle to the remote device, used internally in the stack. */
|
|
||||||
uint8_t RemoteAddress[6]; /**< Bluetooth device address of the attached remote device. */
|
|
||||||
Bluetooth_Channel_t Channels[BLUETOOTH_MAX_OPEN_CHANNELS]; /**< Channel information structures for the connection. */
|
|
||||||
uint8_t SignalingIdentifier; /**< Next Signaling Channel unique command sequence identifier. */
|
|
||||||
} Bluetooth_Connection_t;
|
|
||||||
|
|
||||||
/** Local Bluetooth device information structure, for the defining of local device characteristics for the Bluetooth stack. */
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint32_t Class; /**< Class of the local device, a mask of \c DEVICE_CLASS_* masks. */
|
|
||||||
char PINCode[16]; /**< Pin code required to send or receive in order to authenticate with a remote device. */
|
|
||||||
char Name[]; /**< Name of the local Bluetooth device, up to 248 characters. */
|
|
||||||
} Bluetooth_Device_t;
|
|
||||||
|
|
||||||
/** Bluetooth stack state information structure, for the containment of the Bluetooth stack state. The values in
|
|
||||||
* this structure are set by the Bluetooth stack internally, and should all be treated as read only by the user
|
|
||||||
* application.
|
|
||||||
*/
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint8_t CurrentHCIState; /**< Current HCI state machine state. */
|
|
||||||
uint8_t NextHCIState; /**< Next HCI state machine state to progress to once the currently issued command completes. */
|
|
||||||
bool IsInitialized; /**< Indicates if the Bluetooth stack is currently initialized and ready for connections
|
|
||||||
* to or from a remote Bluetooth device.
|
|
||||||
*/
|
|
||||||
uint8_t LocalBDADDR[6]; /**< Local Bluetooth adapter's BDADDR, valid when the stack is fully initialized. */
|
|
||||||
} Bluetooth_Stack_State_t;
|
|
||||||
|
|
||||||
/* Includes: */
|
|
||||||
#include "BluetoothHCICommands.h"
|
|
||||||
#include "BluetoothACLPackets.h"
|
|
||||||
|
|
||||||
/* Function Prototypes: */
|
|
||||||
void Bluetooth_Stack_Init(void);
|
|
||||||
void Bluetooth_Stack_USBTask(void);
|
|
||||||
|
|
||||||
void Bluetooth_StackInitialized(void);
|
|
||||||
bool Bluetooth_ConnectionRequest(const uint8_t* RemoteAddress);
|
|
||||||
void Bluetooth_ConnectionComplete(void);
|
|
||||||
void Bluetooth_DisconnectionComplete(void);
|
|
||||||
bool Bluetooth_ChannelConnectionRequest(const uint16_t PSM);
|
|
||||||
void Bluetooth_PacketReceived(void* Data, uint16_t DataLen,
|
|
||||||
Bluetooth_Channel_t* const ACLChannel);
|
|
||||||
void Bluetooth_ChannelOpened(Bluetooth_Channel_t* const ACLChannel);
|
|
||||||
|
|
||||||
Bluetooth_Channel_t* Bluetooth_GetChannelData(const uint16_t SearchValue,
|
|
||||||
const uint8_t SearchKey);
|
|
||||||
Bluetooth_Channel_t* Bluetooth_OpenChannel(const uint16_t PSM);
|
|
||||||
void Bluetooth_CloseChannel(Bluetooth_Channel_t* const ACLChannel);
|
|
||||||
uint8_t Bluetooth_SendPacket(void* Data,
|
|
||||||
uint16_t DataLen,
|
|
||||||
Bluetooth_Channel_t* const ACLChannel);
|
|
||||||
|
|
||||||
/* External Variables: */
|
|
||||||
extern Bluetooth_Device_t Bluetooth_DeviceConfiguration;
|
|
||||||
extern Bluetooth_Connection_t Bluetooth_Connection;
|
|
||||||
extern Bluetooth_Stack_State_t Bluetooth_State;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,417 +0,0 @@
|
|||||||
/*
|
|
||||||
LUFA Library
|
|
||||||
Copyright (C) Dean Camera, 2012.
|
|
||||||
|
|
||||||
dean [at] fourwalledcubicle [dot] com
|
|
||||||
www.lufa-lib.org
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright 2012 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
|
||||||
|
|
||||||
Permission to use, copy, modify, distribute, and sell this
|
|
||||||
software and its documentation for any purpose is hereby granted
|
|
||||||
without fee, provided that the above copyright notice appear in
|
|
||||||
all copies and that both that the copyright notice and this
|
|
||||||
permission notice and warranty disclaimer appear in supporting
|
|
||||||
documentation, and that the name of the author not be used in
|
|
||||||
advertising or publicity pertaining to distribution of the
|
|
||||||
software without specific, written prior permission.
|
|
||||||
|
|
||||||
The author disclaim all warranties with regard to this
|
|
||||||
software, including all implied warranties of merchantability
|
|
||||||
and fitness. In no event shall the author be liable for any
|
|
||||||
special, indirect or consequential damages or any damages
|
|
||||||
whatsoever resulting from loss of use, data or profits, whether
|
|
||||||
in an action of contract, negligence or other tortious action,
|
|
||||||
arising out of or in connection with the use or performance of
|
|
||||||
this software.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** \file
|
|
||||||
*
|
|
||||||
* RFCOMM layer module. This module manages the RFCOMM layer of the
|
|
||||||
* stack, providing virtual serial port channels on top of the lower
|
|
||||||
* L2CAP layer.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define INCLUDE_FROM_RFCOMM_C
|
|
||||||
#include "RFCOMM.h"
|
|
||||||
|
|
||||||
/** 8-Bit CRC table used by the FCS field of each RFCOMM encoded frame, sourced from the ETSI TS 101 369 V7.2.0
|
|
||||||
* specification document, upon which the RFCOMM specification is based.
|
|
||||||
*/
|
|
||||||
const uint8_t CRC8_Table[256] PROGMEM =
|
|
||||||
{
|
|
||||||
0x00, 0x91, 0xE3, 0x72, 0x07, 0x96, 0xE4, 0x75, 0x0E, 0x9F, 0xED, 0x7C, 0x09, 0x98, 0xEA, 0x7B,
|
|
||||||
0x1C, 0x8D, 0xFF, 0x6E, 0x1B, 0x8A, 0xF8, 0x69, 0x12, 0x83, 0xF1, 0x60, 0x15, 0x84, 0xF6, 0x67,
|
|
||||||
0x38, 0xA9, 0xDB, 0x4A, 0x3F, 0xAE, 0xDC, 0x4D, 0x36, 0xA7, 0xD5, 0x44, 0x31, 0xA0, 0xD2, 0x43,
|
|
||||||
0x24, 0xB5, 0xC7, 0x56, 0x23, 0xB2, 0xC0, 0x51, 0x2A, 0xBB, 0xC9, 0x58, 0x2D, 0xBC, 0xCE, 0x5F,
|
|
||||||
0x70, 0xE1, 0x93, 0x02, 0x77, 0xE6, 0x94, 0x05, 0x7E, 0xEF, 0x9D, 0x0C, 0x79, 0xE8, 0x9A, 0x0B,
|
|
||||||
0x6C, 0xFD, 0x8F, 0x1E, 0x6B, 0xFA, 0x88, 0x19, 0x62, 0xF3, 0x81, 0x10, 0x65, 0xF4, 0x86, 0x17,
|
|
||||||
0x48, 0xD9, 0xAB, 0x3A, 0x4F, 0xDE, 0xAC, 0x3D, 0x46, 0xD7, 0xA5, 0x34, 0x41, 0xD0, 0xA2, 0x33,
|
|
||||||
0x54, 0xC5, 0xB7, 0x26, 0x53, 0xC2, 0xB0, 0x21, 0x5A, 0xCB, 0xB9, 0x28, 0x5D, 0xCC, 0xBE, 0x2F,
|
|
||||||
0xE0, 0x71, 0x03, 0x92, 0xE7, 0x76, 0x04, 0x95, 0xEE, 0x7F, 0x0D, 0x9C, 0xE9, 0x78, 0x0A, 0x9B,
|
|
||||||
0xFC, 0x6D, 0x1F, 0x8E, 0xFB, 0x6A, 0x18, 0x89, 0xF2, 0x63, 0x11, 0x80, 0xF5, 0x64, 0x16, 0x87,
|
|
||||||
0xD8, 0x49, 0x3B, 0xAA, 0xDF, 0x4E, 0x3C, 0xAD, 0xD6, 0x47, 0x35, 0xA4, 0xD1, 0x40, 0x32, 0xA3,
|
|
||||||
0xC4, 0x55, 0x27, 0xB6, 0xC3, 0x52, 0x20, 0xB1, 0xCA, 0x5B, 0x29, 0xB8, 0xCD, 0x5C, 0x2E, 0xBF,
|
|
||||||
0x90, 0x01, 0x73, 0xE2, 0x97, 0x06, 0x74, 0xE5, 0x9E, 0x0F, 0x7D, 0xEC, 0x99, 0x08, 0x7A, 0xEB,
|
|
||||||
0x8C, 0x1D, 0x6F, 0xFE, 0x8B, 0x1A, 0x68, 0xF9, 0x82, 0x13, 0x61, 0xF0, 0x85, 0x14, 0x66, 0xF7,
|
|
||||||
0xA8, 0x39, 0x4B, 0xDA, 0xAF, 0x3E, 0x4C, 0xDD, 0xA6, 0x37, 0x45, 0xD4, 0xA1, 0x30, 0x42, 0xD3,
|
|
||||||
0xB4, 0x25, 0x57, 0xC6, 0xB3, 0x22, 0x50, 0xC1, 0xBA, 0x2B, 0x59, 0xC8, 0xBD, 0x2C, 0x5E, 0xCF
|
|
||||||
};
|
|
||||||
|
|
||||||
/** RFCOMM channel state structure, to retain information about each open channel in the RFCOMM multiplexer. */
|
|
||||||
RFCOMM_Channel_t RFCOMM_Channels[RFCOMM_MAX_OPEN_CHANNELS];
|
|
||||||
|
|
||||||
|
|
||||||
/** Initializes the RFCOMM service, ready for new connections from a SDP client. */
|
|
||||||
void RFCOMM_Initialize(void)
|
|
||||||
{
|
|
||||||
/* Reset the RFCOMM channel structures, to invalidate any configured RFCOMM channels */
|
|
||||||
for (uint8_t i = 0; i < RFCOMM_MAX_OPEN_CHANNELS; i++)
|
|
||||||
RFCOMM_Channels[i].State = RFCOMM_Channel_Closed;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Services all the logical RFCOMM channels on the given ACL channel, sending any RFCOMM control requests to
|
|
||||||
* the remote device as needed to establish new logical RFCOMM channels. This function should be called repeatedly
|
|
||||||
* in the main program loop when an ACL channel with an RFCOMM PSM has been established between the local and remote
|
|
||||||
* device.
|
|
||||||
*
|
|
||||||
* \param[in] ACLChannel ACL channel which has been previously opened to handle RFCOMM traffic between devices
|
|
||||||
*/
|
|
||||||
void RFCOMM_ServiceChannels(Bluetooth_Channel_t* const ACLChannel)
|
|
||||||
{
|
|
||||||
/* Abort if the RFCOMM ACL channel is not currently open */
|
|
||||||
if ((ACLChannel == NULL) || (ACLChannel->State != BT_Channel_Open))
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* Loop through each of the RFCOMM channels, send any required RFCOMM control commands */
|
|
||||||
for (uint8_t i = 0; i < RFCOMM_MAX_OPEN_CHANNELS; i++)
|
|
||||||
{
|
|
||||||
RFCOMM_Channel_t* RFCOMMChannel = &RFCOMM_Channels[i];
|
|
||||||
|
|
||||||
if (RFCOMMChannel->State == RFCOMM_Channel_Configure)
|
|
||||||
{
|
|
||||||
/* Check if the local signals have not yet been sent on the current channel */
|
|
||||||
if (!(RFCOMMChannel->ConfigFlags & RFCOMM_CONFIG_LOCALSIGNALSSENT))
|
|
||||||
{
|
|
||||||
/* Indicate that the local signals have been sent, transmit them to the remote device */
|
|
||||||
RFCOMMChannel->ConfigFlags |= RFCOMM_CONFIG_LOCALSIGNALSSENT;
|
|
||||||
RFCOMM_SendChannelSignals(RFCOMMChannel, ACLChannel);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If signals have been configured in both directions, progress to the open state */
|
|
||||||
if ((RFCOMMChannel->ConfigFlags & (RFCOMM_CONFIG_REMOTESIGNALS | RFCOMM_CONFIG_LOCALSIGNALS)) ==
|
|
||||||
(RFCOMM_CONFIG_REMOTESIGNALS | RFCOMM_CONFIG_LOCALSIGNALS))
|
|
||||||
{
|
|
||||||
RFCOMMChannel->State = RFCOMM_Channel_Open;
|
|
||||||
RFCOMM_ChannelOpened(RFCOMMChannel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Processes an incoming RFCOMM packet on an ACL channel which has been previously opened between the local and
|
|
||||||
* a remote device to handle RFCOMM traffic.
|
|
||||||
*
|
|
||||||
* \param[in] Data Incoming packet data containing the RFCOMM packet
|
|
||||||
* \param[in] ACLChannel ACL channel the request was issued to by the remote device
|
|
||||||
*/
|
|
||||||
void RFCOMM_ProcessPacket(void* Data,
|
|
||||||
Bluetooth_Channel_t* const ACLChannel)
|
|
||||||
{
|
|
||||||
const RFCOMM_Header_t* FrameHeader = (const RFCOMM_Header_t*)Data;
|
|
||||||
const uint8_t* FrameData = (const uint8_t*)Data + sizeof(RFCOMM_Header_t);
|
|
||||||
uint16_t FrameDataLen = RFCOMM_GetVariableFieldValue(&FrameData);
|
|
||||||
|
|
||||||
/* Decode the RFCOMM frame type from the header */
|
|
||||||
switch (FrameHeader->Control & ~FRAME_POLL_FINAL)
|
|
||||||
{
|
|
||||||
case RFCOMM_Frame_DM:
|
|
||||||
RFCOMM_ProcessDM(&FrameHeader->Address, ACLChannel);
|
|
||||||
break;
|
|
||||||
case RFCOMM_Frame_DISC:
|
|
||||||
RFCOMM_ProcessDISC(&FrameHeader->Address, ACLChannel);
|
|
||||||
break;
|
|
||||||
case RFCOMM_Frame_SABM:
|
|
||||||
RFCOMM_ProcessSABM(&FrameHeader->Address, ACLChannel);
|
|
||||||
break;
|
|
||||||
case RFCOMM_Frame_UA:
|
|
||||||
RFCOMM_ProcessUA(&FrameHeader->Address, ACLChannel);
|
|
||||||
break;
|
|
||||||
case RFCOMM_Frame_UIH:
|
|
||||||
RFCOMM_ProcessUIH(&FrameHeader->Address, FrameDataLen, FrameData, ACLChannel);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
BT_RFCOMM_DEBUG(1, "<< Unknown Frame Received");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Sends an RFCOMM notification to the remote device that the local terminal control signals (located in the
|
|
||||||
* "Local" structure of the RFCOMM channel) have changed, pushing the new signals to the remote device.
|
|
||||||
*
|
|
||||||
* \param[in] RFCOMMChannel RFCOMM logical channel whose local terminal signals have changed
|
|
||||||
* \param[in] ACLChannel ACL channel which has been opened to carry RFCOMM traffic between devices
|
|
||||||
*/
|
|
||||||
void RFCOMM_SendChannelSignals(const RFCOMM_Channel_t* const RFCOMMChannel,
|
|
||||||
Bluetooth_Channel_t* const ACLChannel)
|
|
||||||
{
|
|
||||||
BT_RFCOMM_DEBUG(1, ">> MSC Command");
|
|
||||||
BT_RFCOMM_DEBUG(2, "-- DLCI 0x%02X", RFCOMMChannel->DLCI);
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
RFCOMM_Command_t CommandHeader;
|
|
||||||
uint8_t Length;
|
|
||||||
RFCOMM_MSC_Parameters_t Params;
|
|
||||||
} MSCommand;
|
|
||||||
|
|
||||||
MSCommand.CommandHeader = (RFCOMM_Command_t){.Command = RFCOMM_Control_ModemStatus, .EA = true, .CR = true};
|
|
||||||
MSCommand.Length = (sizeof(MSCommand.Params) << 1) | 0x01;
|
|
||||||
MSCommand.Params.Channel = (RFCOMM_Address_t){.DLCI = RFCOMMChannel->DLCI, .EA = true, .CR = true};
|
|
||||||
MSCommand.Params.Signals = RFCOMMChannel->Local.Signals;
|
|
||||||
MSCommand.Params.BreakSignal = RFCOMMChannel->Local.BreakSignal;
|
|
||||||
|
|
||||||
/* Send the MSC command to the remote device */
|
|
||||||
RFCOMM_SendFrame(RFCOMM_CONTROL_DLCI, true, RFCOMM_Frame_UIH, sizeof(MSCommand), &MSCommand, ACLChannel);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Sends new data through an open logical RFCOMM channel. This should be used to transmit data through a
|
|
||||||
* RFCOMM channel once it has been opened.
|
|
||||||
*
|
|
||||||
* \param[in] DataLen Length of the RFCOMM data to send, in bytes
|
|
||||||
* \param[in] Data Pointer to a buffer where the data to send is located
|
|
||||||
* \param[in] RFCOMMChannel RFCOMM logical channel which is to be transmitted to
|
|
||||||
* \param[in] ACLChannel ACL channel which has been opened to carry RFCOMM traffic between devices
|
|
||||||
*/
|
|
||||||
void RFCOMM_SendData(const uint16_t DataLen,
|
|
||||||
const uint8_t* Data,
|
|
||||||
const RFCOMM_Channel_t* const RFCOMMChannel,
|
|
||||||
Bluetooth_Channel_t* const ACLChannel)
|
|
||||||
{
|
|
||||||
if (RFCOMMChannel->State != RFCOMM_Channel_Open)
|
|
||||||
return;
|
|
||||||
|
|
||||||
BT_RFCOMM_DEBUG(1, ">> UIH Frame");
|
|
||||||
BT_RFCOMM_DEBUG(2, "-- DLCI 0x%02X", RFCOMMChannel->DLCI);
|
|
||||||
|
|
||||||
/* Send the MSC command to the remote device */
|
|
||||||
RFCOMM_SendFrame(RFCOMMChannel->DLCI, false, RFCOMM_Frame_UIH, DataLen, Data, ACLChannel);
|
|
||||||
}
|
|
||||||
|
|
||||||
RFCOMM_Channel_t* RFCOMM_GetFreeChannelEntry(const uint8_t DLCI)
|
|
||||||
{
|
|
||||||
/* Find a free entry in the RFCOMM channel multiplexer state array */
|
|
||||||
for (uint8_t i = 0; i < RFCOMM_MAX_OPEN_CHANNELS; i++)
|
|
||||||
{
|
|
||||||
RFCOMM_Channel_t* RFCOMMChannel = &RFCOMM_Channels[i];
|
|
||||||
|
|
||||||
/* If the channel's state is closed, the channel state entry is free */
|
|
||||||
if (RFCOMMChannel->State == RFCOMM_Channel_Closed)
|
|
||||||
{
|
|
||||||
RFCOMMChannel->DLCI = DLCI;
|
|
||||||
RFCOMMChannel->State = RFCOMM_Channel_Configure;
|
|
||||||
RFCOMMChannel->Priority = 7 + (RFCOMMChannel->DLCI & 0xF8);
|
|
||||||
RFCOMMChannel->MTU = 0xFFFF;
|
|
||||||
RFCOMMChannel->Remote.Signals = 0 | (1 << 0);
|
|
||||||
RFCOMMChannel->Remote.BreakSignal = 0 | (1 << 0);
|
|
||||||
RFCOMMChannel->Local.Signals = RFCOMM_SIGNAL_RTC | RFCOMM_SIGNAL_RTR | RFCOMM_SIGNAL_DV | (1 << 0);
|
|
||||||
RFCOMMChannel->Local.BreakSignal = 0 | (1 << 0);
|
|
||||||
RFCOMMChannel->ConfigFlags = 0;
|
|
||||||
|
|
||||||
return RFCOMMChannel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
RFCOMM_Channel_t* RFCOMM_GetChannelData(const uint8_t DLCI)
|
|
||||||
{
|
|
||||||
/* Search through the RFCOMM channel list, looking for the specified channel */
|
|
||||||
for (uint8_t i = 0; i < RFCOMM_MAX_OPEN_CHANNELS; i++)
|
|
||||||
{
|
|
||||||
RFCOMM_Channel_t* CurrRFCOMMChannel = &RFCOMM_Channels[i];
|
|
||||||
|
|
||||||
/* If the current non-closed channel's DLCI matches the search DLCI, return it to the caller */
|
|
||||||
if ((CurrRFCOMMChannel->State != RFCOMM_Channel_Closed) && (CurrRFCOMMChannel->DLCI == DLCI))
|
|
||||||
return CurrRFCOMMChannel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Channel not found in the channel state table, return failure */
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t RFCOMM_GetVariableFieldValue(const uint8_t** BufferPos)
|
|
||||||
{
|
|
||||||
uint8_t FirstOctet;
|
|
||||||
uint8_t SecondOctet = 0;
|
|
||||||
|
|
||||||
FirstOctet = **BufferPos;
|
|
||||||
(*BufferPos)++;
|
|
||||||
|
|
||||||
/* If the field size is more than a single byte, fetch the next byte in the variable length field */
|
|
||||||
if (!(FirstOctet & 0x01))
|
|
||||||
{
|
|
||||||
SecondOctet = **BufferPos;
|
|
||||||
(*BufferPos)++;
|
|
||||||
|
|
||||||
/* Discard any remaining bytes in the variable length field that won't fit in the return value */
|
|
||||||
while (!(**BufferPos & 0x01))
|
|
||||||
(*BufferPos)++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Bit-shift the bytes that comprise the variable length field so that they form a single integer */
|
|
||||||
return (((uint16_t)SecondOctet << 7) | FirstOctet >> 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RFCOMM_SendFrame(const uint8_t DLCI,
|
|
||||||
const bool CommandResponse,
|
|
||||||
const uint8_t Control,
|
|
||||||
const uint16_t DataLen,
|
|
||||||
const void* Data,
|
|
||||||
Bluetooth_Channel_t* const ACLChannel)
|
|
||||||
{
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
RFCOMM_Header_t FrameHeader;
|
|
||||||
uint8_t Size[(DataLen < 128) ? 1 : 2];
|
|
||||||
uint8_t Data[DataLen];
|
|
||||||
uint8_t FCS;
|
|
||||||
} ResponsePacket;
|
|
||||||
|
|
||||||
/* Set the frame header values to the specified address and frame type */
|
|
||||||
ResponsePacket.FrameHeader.Control = Control;
|
|
||||||
ResponsePacket.FrameHeader.Address = (RFCOMM_Address_t){.DLCI = DLCI, .EA = true, .CR = CommandResponse};
|
|
||||||
|
|
||||||
/* Set the lower 7 bits of the packet length */
|
|
||||||
ResponsePacket.Size[0] = (DataLen << 1);
|
|
||||||
|
|
||||||
/* Terminate the size field if size is 7 bits or lower, otherwise set the upper 8 bits of the length */
|
|
||||||
if (DataLen < 128)
|
|
||||||
ResponsePacket.Size[0] |= 0x01;
|
|
||||||
else
|
|
||||||
ResponsePacket.Size[1] = (DataLen >> 7);
|
|
||||||
|
|
||||||
/* Copy over the packet data from the source buffer to the response packet buffer */
|
|
||||||
memcpy(ResponsePacket.Data, Data, DataLen);
|
|
||||||
|
|
||||||
/* Determine the length of the frame which is to be used to calculate the CRC value */
|
|
||||||
uint8_t CRCLength = sizeof(ResponsePacket.FrameHeader);
|
|
||||||
|
|
||||||
/* UIH frames do not have the CRC calculated on the Size field in the response, all other frames do */
|
|
||||||
if ((Control & ~FRAME_POLL_FINAL) != RFCOMM_Frame_UIH)
|
|
||||||
CRCLength += sizeof(ResponsePacket.Size);
|
|
||||||
|
|
||||||
/* Calculate the frame checksum from the appropriate fields */
|
|
||||||
ResponsePacket.FCS = RFCOMM_GetFCSValue(&ResponsePacket, CRCLength);
|
|
||||||
|
|
||||||
/* Send the completed response packet to the sender */
|
|
||||||
Bluetooth_SendPacket(&ResponsePacket, sizeof(ResponsePacket), ACLChannel);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t RFCOMM_GetFCSValue(const void* FrameStart,
|
|
||||||
uint8_t Length)
|
|
||||||
{
|
|
||||||
uint8_t FCS = 0xFF;
|
|
||||||
|
|
||||||
/* Calculate new Frame CRC value via the given data bytes and the CRC table */
|
|
||||||
for (uint8_t i = 0; i < Length; i++)
|
|
||||||
FCS = pgm_read_byte(&CRC8_Table[FCS ^ ((const uint8_t*)FrameStart)[i]]);
|
|
||||||
|
|
||||||
return ~FCS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void RFCOMM_ProcessDM(const RFCOMM_Address_t* const FrameAddress,
|
|
||||||
Bluetooth_Channel_t* const ACLChannel)
|
|
||||||
{
|
|
||||||
BT_RFCOMM_DEBUG(1, "<< DM Received");
|
|
||||||
BT_RFCOMM_DEBUG(2, "-- DLCI 0x%02X", FrameAddress->DLCI);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void RFCOMM_ProcessDISC(const RFCOMM_Address_t* const FrameAddress,
|
|
||||||
Bluetooth_Channel_t* const ACLChannel)
|
|
||||||
{
|
|
||||||
BT_RFCOMM_DEBUG(1, "<< DISC Received");
|
|
||||||
BT_RFCOMM_DEBUG(2, "-- DLCI 0x%02X", FrameAddress->DLCI);
|
|
||||||
|
|
||||||
RFCOMM_Channel_t* RFCOMMChannel = RFCOMM_GetChannelData(FrameAddress->DLCI);
|
|
||||||
|
|
||||||
/* If the requested channel is currently open, destroy it */
|
|
||||||
if (RFCOMMChannel != NULL)
|
|
||||||
RFCOMMChannel->State = RFCOMM_Channel_Closed;
|
|
||||||
|
|
||||||
BT_RFCOMM_DEBUG(1, ">> UA Sent");
|
|
||||||
RFCOMM_SendFrame(FrameAddress->DLCI, true, (RFCOMM_Frame_UA | FRAME_POLL_FINAL), 0, NULL, ACLChannel);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void RFCOMM_ProcessSABM(const RFCOMM_Address_t* const FrameAddress,
|
|
||||||
Bluetooth_Channel_t* const ACLChannel)
|
|
||||||
{
|
|
||||||
BT_RFCOMM_DEBUG(1, "<< SABM Received");
|
|
||||||
BT_RFCOMM_DEBUG(2, "-- DLCI 0x%02X", FrameAddress->DLCI);
|
|
||||||
|
|
||||||
if (FrameAddress->DLCI == RFCOMM_CONTROL_DLCI)
|
|
||||||
{
|
|
||||||
BT_RFCOMM_DEBUG(1, ">> UA Sent");
|
|
||||||
|
|
||||||
/* Free channel found, or request was to the control channel - accept SABM by sending a UA frame */
|
|
||||||
RFCOMM_SendFrame(FrameAddress->DLCI, true, (RFCOMM_Frame_UA | FRAME_POLL_FINAL), 0, NULL, ACLChannel);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find the existing channel's entry in the channel table */
|
|
||||||
RFCOMM_Channel_t* RFCOMMChannel = RFCOMM_GetChannelData(FrameAddress->DLCI);
|
|
||||||
|
|
||||||
/* Existing entry not found, create a new entry for the channel */
|
|
||||||
if (RFCOMMChannel == NULL)
|
|
||||||
RFCOMMChannel = RFCOMM_GetFreeChannelEntry(FrameAddress->DLCI);
|
|
||||||
|
|
||||||
/* If space was found in the channel table for the new channel, ACK the request */
|
|
||||||
if (RFCOMMChannel != NULL)
|
|
||||||
{
|
|
||||||
BT_RFCOMM_DEBUG(1, ">> UA Sent");
|
|
||||||
|
|
||||||
/* Free channel found, or request was to the control channel - accept SABM by sending a UA frame */
|
|
||||||
RFCOMM_SendFrame(FrameAddress->DLCI, true, (RFCOMM_Frame_UA | FRAME_POLL_FINAL), 0, NULL, ACLChannel);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
BT_RFCOMM_DEBUG(1, ">> DM Sent");
|
|
||||||
|
|
||||||
/* No free channel in the multiplexer - decline the SABM by sending a DM frame */
|
|
||||||
RFCOMM_SendFrame(FrameAddress->DLCI, true, (RFCOMM_Frame_DM | FRAME_POLL_FINAL), 0, NULL, ACLChannel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void RFCOMM_ProcessUA(const RFCOMM_Address_t* const FrameAddress,
|
|
||||||
Bluetooth_Channel_t* const ACLChannel)
|
|
||||||
{
|
|
||||||
BT_RFCOMM_DEBUG(1, "<< UA Received");
|
|
||||||
BT_RFCOMM_DEBUG(2, "-- DLCI 0x%02X", FrameAddress->DLCI);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void RFCOMM_ProcessUIH(const RFCOMM_Address_t* const FrameAddress,
|
|
||||||
const uint16_t FrameLength,
|
|
||||||
const uint8_t* FrameData,
|
|
||||||
Bluetooth_Channel_t* const ACLChannel)
|
|
||||||
{
|
|
||||||
if (FrameAddress->DLCI == RFCOMM_CONTROL_DLCI)
|
|
||||||
{
|
|
||||||
RFCOMM_ProcessControlCommand(FrameData, ACLChannel);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
BT_RFCOMM_DEBUG(1, "<< UIH Received");
|
|
||||||
BT_RFCOMM_DEBUG(2, "-- DLCI 0x%02X", FrameAddress->DLCI);
|
|
||||||
BT_RFCOMM_DEBUG(2, "-- Length 0x%02X", FrameLength);
|
|
||||||
|
|
||||||
RFCOMM_Channel_t* RFCOMMChannel = RFCOMM_GetChannelData(FrameAddress->DLCI);
|
|
||||||
|
|
||||||
if (RFCOMMChannel != NULL)
|
|
||||||
RFCOMM_DataReceived(RFCOMMChannel, FrameLength, FrameData);
|
|
||||||
}
|
|
||||||
|
|
@ -1,150 +0,0 @@
|
|||||||
/*
|
|
||||||
LUFA Library
|
|
||||||
Copyright (C) Dean Camera, 2012.
|
|
||||||
|
|
||||||
dean [at] fourwalledcubicle [dot] com
|
|
||||||
www.lufa-lib.org
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright 2012 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
|
||||||
|
|
||||||
Permission to use, copy, modify, distribute, and sell this
|
|
||||||
software and its documentation for any purpose is hereby granted
|
|
||||||
without fee, provided that the above copyright notice appear in
|
|
||||||
all copies and that both that the copyright notice and this
|
|
||||||
permission notice and warranty disclaimer appear in supporting
|
|
||||||
documentation, and that the name of the author not be used in
|
|
||||||
advertising or publicity pertaining to distribution of the
|
|
||||||
software without specific, written prior permission.
|
|
||||||
|
|
||||||
The author disclaim all warranties with regard to this
|
|
||||||
software, including all implied warranties of merchantability
|
|
||||||
and fitness. In no event shall the author be liable for any
|
|
||||||
special, indirect or consequential damages or any damages
|
|
||||||
whatsoever resulting from loss of use, data or profits, whether
|
|
||||||
in an action of contract, negligence or other tortious action,
|
|
||||||
arising out of or in connection with the use or performance of
|
|
||||||
this software.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** \file
|
|
||||||
*
|
|
||||||
* Header file for RFCOMM.c.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _RFCOMM_H_
|
|
||||||
#define _RFCOMM_H_
|
|
||||||
|
|
||||||
/* Includes: */
|
|
||||||
#include <avr/io.h>
|
|
||||||
#include <avr/pgmspace.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include <LUFA/Common/Common.h>
|
|
||||||
#include <LUFA/Drivers/Peripheral/Serial.h>
|
|
||||||
|
|
||||||
#include "BluetoothStack.h"
|
|
||||||
#include "RFCOMMControl.h"
|
|
||||||
|
|
||||||
/* Macros: */
|
|
||||||
#define BT_RFCOMM_DEBUG(l, s, ...) do { if (RFCOMM_DEBUG_LEVEL >= l) printf_P(PSTR("(RFCOMM) " s "\r\n"), ##__VA_ARGS__); } while (0)
|
|
||||||
#define RFCOMM_DEBUG_LEVEL 0
|
|
||||||
|
|
||||||
#define FRAME_POLL_FINAL (1 << 4)
|
|
||||||
|
|
||||||
#define RFCOMM_CONTROL_DLCI 0
|
|
||||||
#define RFCOMM_MAX_OPEN_CHANNELS 5
|
|
||||||
|
|
||||||
/* Enums: */
|
|
||||||
/** Enum for the types of RFCOMM frames which can be exchanged on a Bluetooth channel. */
|
|
||||||
enum RFCOMM_Frame_Types_t
|
|
||||||
{
|
|
||||||
RFCOMM_Frame_DM = 0x0F, /**< Disconnected Mode Field */
|
|
||||||
RFCOMM_Frame_DISC = 0x43, /**< Disconnect Field */
|
|
||||||
RFCOMM_Frame_SABM = 0x2F, /**< Set Asynchronous Balance Mode Field */
|
|
||||||
RFCOMM_Frame_UA = 0x63, /**< Unnumbered Acknowledgement Field */
|
|
||||||
RFCOMM_Frame_UIH = 0xEF, /**< Unnumbered Information with Header check Field */
|
|
||||||
};
|
|
||||||
|
|
||||||
enum RFCOMM_Channel_States_t
|
|
||||||
{
|
|
||||||
RFCOMM_Channel_Closed = 0,
|
|
||||||
RFCOMM_Channel_Configure = 1,
|
|
||||||
RFCOMM_Channel_Open = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Type Defines: */
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint8_t DLCI;
|
|
||||||
uint8_t State;
|
|
||||||
uint8_t Priority;
|
|
||||||
uint16_t MTU;
|
|
||||||
uint8_t ConfigFlags;
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
uint8_t Signals;
|
|
||||||
uint8_t BreakSignal;
|
|
||||||
} Remote;
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
uint8_t Signals;
|
|
||||||
uint8_t BreakSignal;
|
|
||||||
} Local;
|
|
||||||
} RFCOMM_Channel_t;
|
|
||||||
|
|
||||||
/* External Variables: */
|
|
||||||
extern RFCOMM_Channel_t RFCOMM_Channels[RFCOMM_MAX_OPEN_CHANNELS];
|
|
||||||
|
|
||||||
/* Function Prototypes: */
|
|
||||||
void RFCOMM_Initialize(void);
|
|
||||||
void RFCOMM_ServiceChannels(Bluetooth_Channel_t* const ACLChannel);
|
|
||||||
void RFCOMM_ProcessPacket(void* Data,
|
|
||||||
Bluetooth_Channel_t* const ACLChannel);
|
|
||||||
|
|
||||||
void RFCOMM_SendChannelSignals(const RFCOMM_Channel_t* const RFCOMMChannel,
|
|
||||||
Bluetooth_Channel_t* const ACLChannel);
|
|
||||||
void RFCOMM_SendData(const uint16_t DataLen,
|
|
||||||
const uint8_t* Data,
|
|
||||||
const RFCOMM_Channel_t* const RFCOMMChannel,
|
|
||||||
Bluetooth_Channel_t* const ACLChannel);
|
|
||||||
|
|
||||||
void RFCOMM_ChannelOpened(RFCOMM_Channel_t* const RFCOMMChannel);
|
|
||||||
void RFCOMM_DataReceived(RFCOMM_Channel_t* const RFCOMMChannel,
|
|
||||||
uint16_t DataLen,
|
|
||||||
const uint8_t* Data);
|
|
||||||
void RFCOMM_ChannelSignalsReceived(RFCOMM_Channel_t* const RFCOMMChannel);
|
|
||||||
|
|
||||||
RFCOMM_Channel_t* RFCOMM_GetFreeChannelEntry(const uint8_t DLCI);
|
|
||||||
RFCOMM_Channel_t* RFCOMM_GetChannelData(const uint8_t DLCI);
|
|
||||||
uint16_t RFCOMM_GetVariableFieldValue(const uint8_t** BufferPos);
|
|
||||||
void RFCOMM_SendFrame(const uint8_t DLCI,
|
|
||||||
const bool CommandResponse,
|
|
||||||
const uint8_t Control,
|
|
||||||
const uint16_t DataLen,
|
|
||||||
const void* Data,
|
|
||||||
Bluetooth_Channel_t* const ACLChannel);
|
|
||||||
|
|
||||||
#if defined(INCLUDE_FROM_RFCOMM_C)
|
|
||||||
static uint8_t RFCOMM_GetFCSValue(const void* FrameStart,
|
|
||||||
uint8_t Length);
|
|
||||||
|
|
||||||
static void RFCOMM_ProcessDM(const RFCOMM_Address_t* const FrameAddress,
|
|
||||||
Bluetooth_Channel_t* const ACLChannel);
|
|
||||||
static void RFCOMM_ProcessDISC(const RFCOMM_Address_t* const FrameAddress,
|
|
||||||
Bluetooth_Channel_t* const ACLChannel);
|
|
||||||
static void RFCOMM_ProcessSABM(const RFCOMM_Address_t* const FrameAddress,
|
|
||||||
Bluetooth_Channel_t* const ACLChannel);
|
|
||||||
static void RFCOMM_ProcessUA(const RFCOMM_Address_t* const FrameAddress,
|
|
||||||
Bluetooth_Channel_t* const ACLChannel);
|
|
||||||
static void RFCOMM_ProcessUIH(const RFCOMM_Address_t* const FrameAddress,
|
|
||||||
const uint16_t FrameLength,
|
|
||||||
const uint8_t* FrameData,
|
|
||||||
Bluetooth_Channel_t* const ACLChannel);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,245 +0,0 @@
|
|||||||
/*
|
|
||||||
LUFA Library
|
|
||||||
Copyright (C) Dean Camera, 2012.
|
|
||||||
|
|
||||||
dean [at] fourwalledcubicle [dot] com
|
|
||||||
www.lufa-lib.org
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright 2012 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
|
||||||
|
|
||||||
Permission to use, copy, modify, distribute, and sell this
|
|
||||||
software and its documentation for any purpose is hereby granted
|
|
||||||
without fee, provided that the above copyright notice appear in
|
|
||||||
all copies and that both that the copyright notice and this
|
|
||||||
permission notice and warranty disclaimer appear in supporting
|
|
||||||
documentation, and that the name of the author not be used in
|
|
||||||
advertising or publicity pertaining to distribution of the
|
|
||||||
software without specific, written prior permission.
|
|
||||||
|
|
||||||
The author disclaim all warranties with regard to this
|
|
||||||
software, including all implied warranties of merchantability
|
|
||||||
and fitness. In no event shall the author be liable for any
|
|
||||||
special, indirect or consequential damages or any damages
|
|
||||||
whatsoever resulting from loss of use, data or profits, whether
|
|
||||||
in an action of contract, negligence or other tortious action,
|
|
||||||
arising out of or in connection with the use or performance of
|
|
||||||
this software.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** \file
|
|
||||||
*
|
|
||||||
* RFCOMM multiplexer control layer module. This module handles multiplexer
|
|
||||||
* channel commands to the control DLCI in the RFCOMM layer, to open, configure,
|
|
||||||
* test and close logical RFCOMM channels.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define INCLUDE_FROM_RFCOMM_CONTROL_C
|
|
||||||
#include "RFCOMMControl.h"
|
|
||||||
|
|
||||||
void RFCOMM_ProcessControlCommand(const uint8_t* Command,
|
|
||||||
Bluetooth_Channel_t* const ACLChannel)
|
|
||||||
{
|
|
||||||
const RFCOMM_Command_t* CommandHeader = (const RFCOMM_Command_t*)Command;
|
|
||||||
const uint8_t* CommandData = (const uint8_t*)Command + sizeof(RFCOMM_Command_t);
|
|
||||||
uint8_t CommandDataLen = RFCOMM_GetVariableFieldValue(&CommandData);
|
|
||||||
|
|
||||||
switch (CommandHeader->Command)
|
|
||||||
{
|
|
||||||
case RFCOMM_Control_Test:
|
|
||||||
RFCOMM_ProcessTestCommand(CommandHeader, CommandDataLen, CommandData, ACLChannel);
|
|
||||||
break;
|
|
||||||
case RFCOMM_Control_FlowControlEnable:
|
|
||||||
RFCOMM_ProcessFCECommand(CommandHeader, CommandData, ACLChannel);
|
|
||||||
break;
|
|
||||||
case RFCOMM_Control_FlowControlDisable:
|
|
||||||
RFCOMM_ProcessFCDCommand(CommandHeader, CommandData, ACLChannel);
|
|
||||||
break;
|
|
||||||
case RFCOMM_Control_ModemStatus:
|
|
||||||
RFCOMM_ProcessMSCCommand(CommandHeader, CommandDataLen, CommandData, ACLChannel);
|
|
||||||
break;
|
|
||||||
case RFCOMM_Control_RemotePortNegotiation:
|
|
||||||
RFCOMM_ProcessRPNCommand(CommandHeader, CommandData, ACLChannel);
|
|
||||||
break;
|
|
||||||
case RFCOMM_Control_RemoteLineStatus:
|
|
||||||
RFCOMM_ProcessRLSCommand(CommandHeader, CommandData, ACLChannel);
|
|
||||||
break;
|
|
||||||
case RFCOMM_Control_DLCParameterNegotiation:
|
|
||||||
RFCOMM_ProcessDPNCommand(CommandHeader, CommandData, ACLChannel);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
BT_RFCOMM_DEBUG(1, "<< Unknown Command");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void RFCOMM_ProcessTestCommand(const RFCOMM_Command_t* const CommandHeader,
|
|
||||||
const uint8_t CommandDataLen,
|
|
||||||
const uint8_t* CommandData,
|
|
||||||
Bluetooth_Channel_t* const ACLChannel)
|
|
||||||
{
|
|
||||||
const uint8_t* Params = (const uint8_t*)CommandData;
|
|
||||||
|
|
||||||
BT_RFCOMM_DEBUG(1, "<< TEST Command");
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
RFCOMM_Command_t CommandHeader;
|
|
||||||
uint8_t Length;
|
|
||||||
uint8_t TestData[CommandDataLen];
|
|
||||||
} TestResponse;
|
|
||||||
|
|
||||||
/* Fill out the Test response data */
|
|
||||||
TestResponse.CommandHeader = (RFCOMM_Command_t){.Command = RFCOMM_Control_Test, .EA = true, .CR = false};
|
|
||||||
TestResponse.Length = (CommandDataLen << 1) | 0x01;
|
|
||||||
memcpy(TestResponse.TestData, Params, CommandDataLen);
|
|
||||||
|
|
||||||
BT_RFCOMM_DEBUG(1, ">> TEST Response");
|
|
||||||
|
|
||||||
/* Send the PDN response to acknowledge the command */
|
|
||||||
RFCOMM_SendFrame(RFCOMM_CONTROL_DLCI, false, RFCOMM_Frame_UIH, sizeof(TestResponse), &TestResponse, ACLChannel);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void RFCOMM_ProcessFCECommand(const RFCOMM_Command_t* const CommandHeader,
|
|
||||||
const uint8_t* CommandData,
|
|
||||||
Bluetooth_Channel_t* const ACLChannel)
|
|
||||||
{
|
|
||||||
BT_RFCOMM_DEBUG(1, "<< FCE Command");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void RFCOMM_ProcessFCDCommand(const RFCOMM_Command_t* const CommandHeader,
|
|
||||||
const uint8_t* CommandData,
|
|
||||||
Bluetooth_Channel_t* const ACLChannel)
|
|
||||||
{
|
|
||||||
BT_RFCOMM_DEBUG(1, "<< FCD Command");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void RFCOMM_ProcessMSCCommand(const RFCOMM_Command_t* const CommandHeader,
|
|
||||||
const uint8_t CommandDataLen,
|
|
||||||
const uint8_t* CommandData,
|
|
||||||
Bluetooth_Channel_t* const ACLChannel)
|
|
||||||
{
|
|
||||||
const RFCOMM_MSC_Parameters_t* Params = (const RFCOMM_MSC_Parameters_t*)CommandData;
|
|
||||||
|
|
||||||
BT_RFCOMM_DEBUG(1, "<< MSC %s", (CommandHeader->CR) ? "Command" : "Response");
|
|
||||||
BT_RFCOMM_DEBUG(2, "-- DLCI: 0x%02X", Params->Channel.DLCI);
|
|
||||||
|
|
||||||
/* Ignore status flags sent to the control channel */
|
|
||||||
if (Params->Channel.DLCI == RFCOMM_CONTROL_DLCI)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* Retrieve existing channel configuration data, if already opened */
|
|
||||||
RFCOMM_Channel_t* RFCOMMChannel = RFCOMM_GetChannelData(Params->Channel.DLCI);
|
|
||||||
|
|
||||||
/* If the channel does not exist, abort */
|
|
||||||
if (RFCOMMChannel == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* Check if the MSC packet is a command or a response */
|
|
||||||
if (CommandHeader->CR)
|
|
||||||
{
|
|
||||||
/* Save the new channel signals to the channel state structure */
|
|
||||||
RFCOMMChannel->Remote.Signals = Params->Signals;
|
|
||||||
RFCOMMChannel->ConfigFlags |= RFCOMM_CONFIG_REMOTESIGNALS;
|
|
||||||
|
|
||||||
/* If the command contains the optional break signals field, store the value */
|
|
||||||
if (CommandDataLen == sizeof(RFCOMM_MSC_Parameters_t))
|
|
||||||
RFCOMMChannel->Remote.BreakSignal = Params->BreakSignal;
|
|
||||||
|
|
||||||
/* Notify the user application that the signals have been received */
|
|
||||||
RFCOMM_ChannelSignalsReceived(RFCOMMChannel);
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
RFCOMM_Command_t CommandHeader;
|
|
||||||
uint8_t Length;
|
|
||||||
RFCOMM_MSC_Parameters_t Params;
|
|
||||||
} MSResponse;
|
|
||||||
|
|
||||||
/* Fill out the MS response data */
|
|
||||||
MSResponse.CommandHeader = (RFCOMM_Command_t){.Command = RFCOMM_Control_ModemStatus, .EA = true, .CR = false};
|
|
||||||
MSResponse.Length = (CommandDataLen << 1) | 0x01;
|
|
||||||
memcpy(&MSResponse.Params, Params, sizeof(RFCOMM_MSC_Parameters_t));
|
|
||||||
|
|
||||||
BT_RFCOMM_DEBUG(1, ">> MSC Response");
|
|
||||||
|
|
||||||
/* Send the MSC response to acknowledge the command */
|
|
||||||
RFCOMM_SendFrame(RFCOMM_CONTROL_DLCI, false, RFCOMM_Frame_UIH,
|
|
||||||
(sizeof(MSResponse) - sizeof(MSResponse.Params) + CommandDataLen), &MSResponse, ACLChannel);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Indicate that the remote device has acknowledged the sent signals */
|
|
||||||
RFCOMMChannel->ConfigFlags |= RFCOMM_CONFIG_LOCALSIGNALS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void RFCOMM_ProcessRPNCommand(const RFCOMM_Command_t* const CommandHeader,
|
|
||||||
const uint8_t* CommandData,
|
|
||||||
Bluetooth_Channel_t* const ACLChannel)
|
|
||||||
{
|
|
||||||
BT_RFCOMM_DEBUG(1, "<< RPN Command");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void RFCOMM_ProcessRLSCommand(const RFCOMM_Command_t* const CommandHeader,
|
|
||||||
const uint8_t* CommandData,
|
|
||||||
Bluetooth_Channel_t* const ACLChannel)
|
|
||||||
{
|
|
||||||
BT_RFCOMM_DEBUG(1, "<< RLS Command");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void RFCOMM_ProcessDPNCommand(const RFCOMM_Command_t* const CommandHeader,
|
|
||||||
const uint8_t* CommandData,
|
|
||||||
Bluetooth_Channel_t* const ACLChannel)
|
|
||||||
{
|
|
||||||
const RFCOMM_DPN_Parameters_t* Params = (const RFCOMM_DPN_Parameters_t*)CommandData;
|
|
||||||
|
|
||||||
BT_RFCOMM_DEBUG(1, "<< DPN Command");
|
|
||||||
BT_RFCOMM_DEBUG(2, "-- DLCI: 0x%02X", Params->DLCI);
|
|
||||||
|
|
||||||
/* Ignore parameter negotiations to the control channel */
|
|
||||||
if (Params->DLCI == RFCOMM_CONTROL_DLCI)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* Retrieve existing channel configuration data, if already opened */
|
|
||||||
RFCOMM_Channel_t* RFCOMMChannel = RFCOMM_GetChannelData(Params->DLCI);
|
|
||||||
|
|
||||||
/* Check if the channel has no corresponding entry - remote did not open it first */
|
|
||||||
if (RFCOMMChannel == NULL)
|
|
||||||
{
|
|
||||||
/* Create a new entry in the channel table for the new channel */
|
|
||||||
RFCOMMChannel = RFCOMM_GetFreeChannelEntry(Params->DLCI);
|
|
||||||
|
|
||||||
/* No free entry was found, discard the request */
|
|
||||||
if (RFCOMMChannel == NULL)
|
|
||||||
{
|
|
||||||
BT_RFCOMM_DEBUG(2, "-- No Free Channel");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Save the new channel configuration */
|
|
||||||
RFCOMMChannel->State = RFCOMM_Channel_Configure;
|
|
||||||
RFCOMMChannel->Priority = Params->Priority;
|
|
||||||
RFCOMMChannel->MTU = Params->MaximumFrameSize;
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
RFCOMM_Command_t CommandHeader;
|
|
||||||
uint8_t Length;
|
|
||||||
RFCOMM_DPN_Parameters_t Params;
|
|
||||||
} DPNResponse;
|
|
||||||
|
|
||||||
/* Fill out the DPN response data */
|
|
||||||
DPNResponse.CommandHeader = (RFCOMM_Command_t){.Command = RFCOMM_Control_DLCParameterNegotiation, .EA = true, .CR = false};
|
|
||||||
DPNResponse.Length = (sizeof(DPNResponse.Params) << 1) | 0x01;
|
|
||||||
memcpy(&DPNResponse.Params, Params, sizeof(RFCOMM_DPN_Parameters_t));
|
|
||||||
DPNResponse.Params.ConvergenceLayer = 0x00; // TODO: Enable credit based transaction support
|
|
||||||
|
|
||||||
BT_RFCOMM_DEBUG(1, ">> DPN Response");
|
|
||||||
|
|
||||||
/* Send the DPN response to acknowledge the command */
|
|
||||||
RFCOMM_SendFrame(RFCOMM_CONTROL_DLCI, false, RFCOMM_Frame_UIH, sizeof(DPNResponse), &DPNResponse, ACLChannel);
|
|
||||||
}
|
|
||||||
|
|
@ -1,148 +0,0 @@
|
|||||||
/*
|
|
||||||
LUFA Library
|
|
||||||
Copyright (C) Dean Camera, 2012.
|
|
||||||
|
|
||||||
dean [at] fourwalledcubicle [dot] com
|
|
||||||
www.lufa-lib.org
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright 2012 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
|
||||||
|
|
||||||
Permission to use, copy, modify, distribute, and sell this
|
|
||||||
software and its documentation for any purpose is hereby granted
|
|
||||||
without fee, provided that the above copyright notice appear in
|
|
||||||
all copies and that both that the copyright notice and this
|
|
||||||
permission notice and warranty disclaimer appear in supporting
|
|
||||||
documentation, and that the name of the author not be used in
|
|
||||||
advertising or publicity pertaining to distribution of the
|
|
||||||
software without specific, written prior permission.
|
|
||||||
|
|
||||||
The author disclaim all warranties with regard to this
|
|
||||||
software, including all implied warranties of merchantability
|
|
||||||
and fitness. In no event shall the author be liable for any
|
|
||||||
special, indirect or consequential damages or any damages
|
|
||||||
whatsoever resulting from loss of use, data or profits, whether
|
|
||||||
in an action of contract, negligence or other tortious action,
|
|
||||||
arising out of or in connection with the use or performance of
|
|
||||||
this software.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** \file
|
|
||||||
*
|
|
||||||
* Header file for RFCOMMControl.c.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _RFCOMM_CONTROL_H_
|
|
||||||
#define _RFCOMM_CONTROL_H_
|
|
||||||
|
|
||||||
/* Includes: */
|
|
||||||
#include <avr/io.h>
|
|
||||||
#include <avr/pgmspace.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include <LUFA/Common/Common.h>
|
|
||||||
#include <LUFA/Drivers/Peripheral/Serial.h>
|
|
||||||
|
|
||||||
#include "BluetoothStack.h"
|
|
||||||
#include "RFCOMM.h"
|
|
||||||
|
|
||||||
/* Macros: */
|
|
||||||
#define RFCOMM_SIGNAL_FC (1 << 1)
|
|
||||||
#define RFCOMM_SIGNAL_RTC (1 << 2)
|
|
||||||
#define RFCOMM_SIGNAL_RTR (1 << 3)
|
|
||||||
#define RFCOMM_SIGNAL_IC (1 << 6)
|
|
||||||
#define RFCOMM_SIGNAL_DV (1 << 7)
|
|
||||||
|
|
||||||
#define RFCOMM_CONFIG_REMOTESIGNALS (1 << 0)
|
|
||||||
#define RFCOMM_CONFIG_LOCALSIGNALS (1 << 1)
|
|
||||||
#define RFCOMM_CONFIG_LOCALSIGNALSSENT (1 << 2)
|
|
||||||
#define RFCOMM_CONFIG_ABMMODESET (1 << 3)
|
|
||||||
|
|
||||||
/* Enums: */
|
|
||||||
enum RFCOMM_Control_Commands_t
|
|
||||||
{
|
|
||||||
RFCOMM_Control_Test = (0x20 >> 2),
|
|
||||||
RFCOMM_Control_FlowControlEnable = (0xA0 >> 2),
|
|
||||||
RFCOMM_Control_FlowControlDisable = (0x60 >> 2),
|
|
||||||
RFCOMM_Control_ModemStatus = (0xE0 >> 2),
|
|
||||||
RFCOMM_Control_RemotePortNegotiation = (0x90 >> 2),
|
|
||||||
RFCOMM_Control_RemoteLineStatus = (0x50 >> 2),
|
|
||||||
RFCOMM_Control_DLCParameterNegotiation = (0x80 >> 2),
|
|
||||||
RFCOMM_Control_NonSupportedCommand = (0x10 >> 2),
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Type Defines: */
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
unsigned EA : 1;
|
|
||||||
unsigned CR : 1;
|
|
||||||
unsigned DLCI : 6;
|
|
||||||
} RFCOMM_Address_t;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
RFCOMM_Address_t Address;
|
|
||||||
uint8_t Control;
|
|
||||||
} RFCOMM_Header_t;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
unsigned EA : 1;
|
|
||||||
unsigned CR : 1;
|
|
||||||
unsigned Command : 6;
|
|
||||||
} RFCOMM_Command_t;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint8_t DLCI;
|
|
||||||
unsigned FrameType : 4;
|
|
||||||
unsigned ConvergenceLayer : 4;
|
|
||||||
uint8_t Priority;
|
|
||||||
uint8_t ACKTimerTicks;
|
|
||||||
uint16_t MaximumFrameSize;
|
|
||||||
uint8_t MaxRetransmissions;
|
|
||||||
uint8_t RecoveryWindowSize;
|
|
||||||
} RFCOMM_DPN_Parameters_t;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
RFCOMM_Address_t Channel;
|
|
||||||
uint8_t Signals;
|
|
||||||
uint8_t BreakSignal;
|
|
||||||
} RFCOMM_MSC_Parameters_t;
|
|
||||||
|
|
||||||
/* Function Prototypes: */
|
|
||||||
void RFCOMM_ProcessControlCommand(const uint8_t* Command,
|
|
||||||
Bluetooth_Channel_t* const Channel);
|
|
||||||
|
|
||||||
#if defined(INCLUDE_FROM_RFCOMM_CONTROL_C)
|
|
||||||
static void RFCOMM_ProcessTestCommand(const RFCOMM_Command_t* const CommandHeader,
|
|
||||||
const uint8_t CommandDataLen,
|
|
||||||
const uint8_t* CommandData,
|
|
||||||
Bluetooth_Channel_t* const ACLChannel);
|
|
||||||
static void RFCOMM_ProcessFCECommand(const RFCOMM_Command_t* const CommandHeader,
|
|
||||||
const uint8_t* CommandData,
|
|
||||||
Bluetooth_Channel_t* const ACLChannel);
|
|
||||||
static void RFCOMM_ProcessFCDCommand(const RFCOMM_Command_t* const CommandHeader,
|
|
||||||
const uint8_t* CommandData,
|
|
||||||
Bluetooth_Channel_t* const ACLChannel);
|
|
||||||
static void RFCOMM_ProcessMSCCommand(const RFCOMM_Command_t* const CommandHeader,
|
|
||||||
const uint8_t CommandDataLen,
|
|
||||||
const uint8_t* CommandData,
|
|
||||||
Bluetooth_Channel_t* const ACLChannel);
|
|
||||||
static void RFCOMM_ProcessRPNCommand(const RFCOMM_Command_t* const CommandHeader,
|
|
||||||
const uint8_t* CommandData,
|
|
||||||
Bluetooth_Channel_t* const ACLChannel);
|
|
||||||
static void RFCOMM_ProcessRLSCommand(const RFCOMM_Command_t* const CommandHeader,
|
|
||||||
const uint8_t* CommandData,
|
|
||||||
Bluetooth_Channel_t* const ACLChannel);
|
|
||||||
static void RFCOMM_ProcessDPNCommand(const RFCOMM_Command_t* const CommandHeader,
|
|
||||||
const uint8_t* CommandData,
|
|
||||||
Bluetooth_Channel_t* const ACLChannel);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,716 +0,0 @@
|
|||||||
/*
|
|
||||||
LUFA Library
|
|
||||||
Copyright (C) Dean Camera, 2012.
|
|
||||||
|
|
||||||
dean [at] fourwalledcubicle [dot] com
|
|
||||||
www.lufa-lib.org
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright 2012 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
|
||||||
|
|
||||||
Permission to use, copy, modify, distribute, and sell this
|
|
||||||
software and its documentation for any purpose is hereby granted
|
|
||||||
without fee, provided that the above copyright notice appear in
|
|
||||||
all copies and that both that the copyright notice and this
|
|
||||||
permission notice and warranty disclaimer appear in supporting
|
|
||||||
documentation, and that the name of the author not be used in
|
|
||||||
advertising or publicity pertaining to distribution of the
|
|
||||||
software without specific, written prior permission.
|
|
||||||
|
|
||||||
The author disclaim all warranties with regard to this
|
|
||||||
software, including all implied warranties of merchantability
|
|
||||||
and fitness. In no event shall the author be liable for any
|
|
||||||
special, indirect or consequential damages or any damages
|
|
||||||
whatsoever resulting from loss of use, data or profits, whether
|
|
||||||
in an action of contract, negligence or other tortious action,
|
|
||||||
arising out of or in connection with the use or performance of
|
|
||||||
this software.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** \file
|
|
||||||
*
|
|
||||||
* SDP layer module. This module implements a simple Service Discovery
|
|
||||||
* Protocol server, which can broadcast the device's supported services
|
|
||||||
* to other Bluetooth devices upon request, so that they can determine
|
|
||||||
* what services are available.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
TODO: Honor remote device's buffer size constraints via continuation state
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define INCLUDE_FROM_SERVICEDISCOVERYPROTOCOL_C
|
|
||||||
#include "SDP.h"
|
|
||||||
|
|
||||||
/** Service attribute table list, containing a pointer to each service attribute table the device contains */
|
|
||||||
const ServiceAttributeTable_t* SDP_Services_Table[] PROGMEM =
|
|
||||||
{
|
|
||||||
SerialPort_Attribute_Table,
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Base UUID value common to all standardized Bluetooth services */
|
|
||||||
const UUID_t BaseUUID PROGMEM = {0x00000000, BASE_80BIT_UUID};
|
|
||||||
|
|
||||||
/** Main Service Discovery Protocol packet processing routine. This function processes incoming SDP packets from
|
|
||||||
* a connected Bluetooth device, and sends back appropriate responses to allow other devices to determine the
|
|
||||||
* services the local device exposes.
|
|
||||||
*
|
|
||||||
* \param[in] Data Incoming packet data containing the SDP request
|
|
||||||
* \param[in] Channel ACL channel the request was issued to by the remote device
|
|
||||||
*/
|
|
||||||
void SDP_ProcessPacket(void* Data, Bluetooth_Channel_t* const Channel)
|
|
||||||
{
|
|
||||||
SDP_PDUHeader_t* SDPHeader = (SDP_PDUHeader_t*)Data;
|
|
||||||
SDPHeader->ParameterLength = SwapEndian_16(SDPHeader->ParameterLength);
|
|
||||||
|
|
||||||
BT_SDP_DEBUG(1, "SDP Packet Received");
|
|
||||||
BT_SDP_DEBUG(2, "-- PDU ID: 0x%02X", SDPHeader->PDU);
|
|
||||||
BT_SDP_DEBUG(2, "-- Param Length: 0x%04X", SDPHeader->ParameterLength);
|
|
||||||
|
|
||||||
/* Dispatch to the correct processing routine for the given SDP packet type */
|
|
||||||
switch (SDPHeader->PDU)
|
|
||||||
{
|
|
||||||
case SDP_PDU_SERVICESEARCHREQUEST:
|
|
||||||
SDP_ProcessServiceSearch(SDPHeader, Channel);
|
|
||||||
break;
|
|
||||||
case SDP_PDU_SERVICEATTRIBUTEREQUEST:
|
|
||||||
SDP_ProcessServiceAttribute(SDPHeader, Channel);
|
|
||||||
break;
|
|
||||||
case SDP_PDU_SERVICESEARCHATTRIBUTEREQUEST:
|
|
||||||
SDP_ProcessServiceSearchAttribute(SDPHeader, Channel);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Internal processing routine for SDP Service Search Requests.
|
|
||||||
*
|
|
||||||
* \param[in] SDPHeader Pointer to the start of the issued SDP request
|
|
||||||
* \param[in] Channel Pointer to the Bluetooth channel structure the request was issued to
|
|
||||||
*/
|
|
||||||
static void SDP_ProcessServiceSearch(const SDP_PDUHeader_t* const SDPHeader,
|
|
||||||
Bluetooth_Channel_t* const Channel)
|
|
||||||
{
|
|
||||||
const void* CurrentParameter = ((const void*)SDPHeader + sizeof(SDP_PDUHeader_t));
|
|
||||||
|
|
||||||
BT_SDP_DEBUG(1, "<< Service Search");
|
|
||||||
|
|
||||||
/* Retrieve the list of search UUIDs from the request */
|
|
||||||
uint8_t UUIDList[12][UUID_SIZE_BYTES];
|
|
||||||
uint8_t TotalUUIDs = SDP_GetUUIDList(UUIDList, &CurrentParameter);
|
|
||||||
BT_SDP_DEBUG(2, "-- Total UUIDs: %d", TotalUUIDs);
|
|
||||||
|
|
||||||
/* Retrieve the maximum service record response count from the request */
|
|
||||||
uint16_t MaxServiceRecordCount = SDP_ReadData16(&CurrentParameter);
|
|
||||||
BT_SDP_DEBUG(2, "-- Max Return Service Count: 0x%04X", MaxServiceRecordCount);
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
SDP_PDUHeader_t SDPHeader;
|
|
||||||
uint16_t TotalServiceRecordCount;
|
|
||||||
uint16_t CurrentServiceRecordCount;
|
|
||||||
uint8_t ResponseData[100];
|
|
||||||
} ResponsePacket;
|
|
||||||
|
|
||||||
uint8_t AddedServiceHandles = 0;
|
|
||||||
|
|
||||||
/* Create a pointer to the buffer to indicate the current location for response data to be added */
|
|
||||||
void* CurrResponsePos = ResponsePacket.ResponseData;
|
|
||||||
|
|
||||||
/* Search through the global service list an item at a time */
|
|
||||||
for (uint8_t CurrTableItem = 0; CurrTableItem < (sizeof(SDP_Services_Table) / sizeof(void*)); CurrTableItem++)
|
|
||||||
{
|
|
||||||
/* Read in a pointer to the current UUID table entry's Attribute table */
|
|
||||||
ServiceAttributeTable_t* CurrAttributeTable = pgm_read_ptr(&SDP_Services_Table[CurrTableItem]);
|
|
||||||
|
|
||||||
if (!(SDP_SearchServiceTable(UUIDList, TotalUUIDs, CurrAttributeTable)))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
BT_SDP_DEBUG(2, " -- Found search match in table");
|
|
||||||
|
|
||||||
/* Retrieve a PROGMEM pointer to the value of the service's record handle */
|
|
||||||
const void* AttributeValue = SDP_GetAttributeValue(CurrAttributeTable, SDP_ATTRIBUTE_ID_SERVICERECORDHANDLE);
|
|
||||||
|
|
||||||
/* Copy over the service record handle to the response list */
|
|
||||||
uint8_t AttrHeaderSize;
|
|
||||||
uint8_t AttrSize = SDP_GetLocalAttributeContainerSize(AttributeValue, &AttrHeaderSize);
|
|
||||||
memcpy_P(CurrResponsePos, AttributeValue + AttrHeaderSize, AttrSize);
|
|
||||||
CurrResponsePos += AttrHeaderSize + AttrSize;
|
|
||||||
|
|
||||||
AddedServiceHandles++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Continuation state - always zero */
|
|
||||||
SDP_WriteData8(&CurrResponsePos, 0);
|
|
||||||
|
|
||||||
/* Fill out the service record count values in the returned packet */
|
|
||||||
ResponsePacket.TotalServiceRecordCount = SwapEndian_16(AddedServiceHandles);
|
|
||||||
ResponsePacket.CurrentServiceRecordCount = ResponsePacket.TotalServiceRecordCount;
|
|
||||||
|
|
||||||
/* Calculate the total parameter length that is to be sent, including the fixed return parameters, the created service
|
|
||||||
handle list and the SDP continuation state */
|
|
||||||
uint16_t ParamLength = (ResponsePacket.CurrentServiceRecordCount << 2) +
|
|
||||||
sizeof(ResponsePacket.CurrentServiceRecordCount) +
|
|
||||||
sizeof(ResponsePacket.TotalServiceRecordCount) +
|
|
||||||
sizeof(uint8_t);
|
|
||||||
|
|
||||||
/* Fill in the response packet's header */
|
|
||||||
ResponsePacket.SDPHeader.PDU = SDP_PDU_SERVICESEARCHRESPONSE;
|
|
||||||
ResponsePacket.SDPHeader.TransactionID = SDPHeader->TransactionID;
|
|
||||||
ResponsePacket.SDPHeader.ParameterLength = SwapEndian_16(ParamLength);
|
|
||||||
|
|
||||||
BT_SDP_DEBUG(1, ">> Service Search Response");
|
|
||||||
|
|
||||||
/* Send the completed response packet to the sender */
|
|
||||||
Bluetooth_SendPacket(&ResponsePacket, (sizeof(ResponsePacket.SDPHeader) + ParamLength), Channel);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Internal processing routine for SDP Service Attribute Requests.
|
|
||||||
*
|
|
||||||
* \param[in] SDPHeader Pointer to the start of the issued SDP request
|
|
||||||
* \param[in] Channel Pointer to the Bluetooth channel structure the request was issued to
|
|
||||||
*/
|
|
||||||
static void SDP_ProcessServiceAttribute(const SDP_PDUHeader_t* const SDPHeader,
|
|
||||||
Bluetooth_Channel_t* const Channel)
|
|
||||||
{
|
|
||||||
const void* CurrentParameter = ((const void*)SDPHeader + sizeof(SDP_PDUHeader_t));
|
|
||||||
|
|
||||||
BT_SDP_DEBUG(1, "<< Service Attribute");
|
|
||||||
|
|
||||||
/* Retrieve the service handle whose attributes are to be examined */
|
|
||||||
uint32_t ServiceHandle = SDP_ReadData32(&CurrentParameter);
|
|
||||||
BT_SDP_DEBUG(2, "-- Service Handle: 0x%08lX", ServiceHandle);
|
|
||||||
|
|
||||||
/* Retrieve the maximum Attribute response size from the request */
|
|
||||||
uint16_t MaxAttributeSize = SDP_ReadData16(&CurrentParameter);
|
|
||||||
BT_SDP_DEBUG(2, "-- Max Return Attribute Bytes: 0x%04X", MaxAttributeSize);
|
|
||||||
|
|
||||||
/* Retrieve the list of Attributes from the request */
|
|
||||||
uint16_t AttributeList[8][2];
|
|
||||||
uint8_t TotalAttributes = SDP_GetAttributeList(AttributeList, &CurrentParameter);
|
|
||||||
BT_SDP_DEBUG(2, "-- Total Attributes: %d", TotalAttributes);
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
SDP_PDUHeader_t SDPHeader;
|
|
||||||
uint16_t AttributeListByteCount;
|
|
||||||
uint8_t ResponseData[100];
|
|
||||||
} ResponsePacket;
|
|
||||||
|
|
||||||
/* Create a pointer to the buffer to indicate the current location for response data to be added */
|
|
||||||
void* CurrResponsePos = ResponsePacket.ResponseData;
|
|
||||||
|
|
||||||
/* Clamp the maximum attribute size to the size of the allocated buffer */
|
|
||||||
if (MaxAttributeSize > sizeof(ResponsePacket.ResponseData))
|
|
||||||
MaxAttributeSize = sizeof(ResponsePacket.ResponseData);
|
|
||||||
|
|
||||||
uint16_t TotalResponseSize = 0;
|
|
||||||
|
|
||||||
/* Search through the global UUID list an item at a time */
|
|
||||||
for (uint8_t CurrTableItem = 0; CurrTableItem < (sizeof(SDP_Services_Table) / sizeof(void*)); CurrTableItem++)
|
|
||||||
{
|
|
||||||
/* Read in a pointer to the current UUID table entry's Attribute table */
|
|
||||||
ServiceAttributeTable_t* CurrAttributeTable = pgm_read_ptr(&SDP_Services_Table[CurrTableItem]);
|
|
||||||
|
|
||||||
/* Retrieve a PROGMEM pointer to the value of the Service Record Handle */
|
|
||||||
const void* ServiceRecord = SDP_GetAttributeValue(CurrAttributeTable, SDP_ATTRIBUTE_ID_SERVICERECORDHANDLE);
|
|
||||||
|
|
||||||
/* Get the size of the header for the Service Record Handle */
|
|
||||||
uint8_t AttrHeaderSize;
|
|
||||||
SDP_GetLocalAttributeContainerSize(ServiceRecord, &AttrHeaderSize);
|
|
||||||
|
|
||||||
/* Retrieve the endian-swapped service handle of the current service being examined */
|
|
||||||
uint32_t CurrServiceHandle = SwapEndian_32(pgm_read_dword(ServiceRecord + AttrHeaderSize));
|
|
||||||
|
|
||||||
/* Check if the current service in the service table has the requested service handle */
|
|
||||||
if (ServiceHandle == CurrServiceHandle)
|
|
||||||
{
|
|
||||||
/* Add the listed attributes for the found UUID to the response */
|
|
||||||
TotalResponseSize = SDP_AddListedAttributesToResponse(CurrAttributeTable, AttributeList, TotalAttributes,
|
|
||||||
&CurrResponsePos);
|
|
||||||
|
|
||||||
/* Requested service found, abort the search through the service table */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Continuation state - always zero */
|
|
||||||
SDP_WriteData8(&CurrResponsePos, 0);
|
|
||||||
|
|
||||||
/* Set the total response list size to the size of the outer container plus its header size and continuation state */
|
|
||||||
ResponsePacket.AttributeListByteCount = SwapEndian_16(TotalResponseSize);
|
|
||||||
|
|
||||||
/* Calculate the total parameter length that is to be sent, including the fixed return parameters, the created attribute
|
|
||||||
value list and the SDP continuation state */
|
|
||||||
uint16_t ParamLength = (sizeof(ResponsePacket.AttributeListByteCount) + TotalResponseSize + sizeof(uint8_t));
|
|
||||||
|
|
||||||
/* Fill in the response packet's header */
|
|
||||||
ResponsePacket.SDPHeader.PDU = SDP_PDU_SERVICEATTRIBUTERESPONSE;
|
|
||||||
ResponsePacket.SDPHeader.TransactionID = SDPHeader->TransactionID;
|
|
||||||
ResponsePacket.SDPHeader.ParameterLength = SwapEndian_16(ParamLength);
|
|
||||||
|
|
||||||
BT_SDP_DEBUG(1, ">> Service Attribute Response");
|
|
||||||
BT_SDP_DEBUG(2, "-- Param Len 0x%04X", ParamLength);
|
|
||||||
|
|
||||||
/* Send the completed response packet to the sender */
|
|
||||||
Bluetooth_SendPacket(&ResponsePacket, (sizeof(ResponsePacket.SDPHeader) + ParamLength), Channel);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Internal processing routine for SDP Service Search Attribute Requests.
|
|
||||||
*
|
|
||||||
* \param[in] SDPHeader Pointer to the start of the issued SDP request
|
|
||||||
* \param[in] Channel Pointer to the Bluetooth channel structure the request was issued to
|
|
||||||
*/
|
|
||||||
static void SDP_ProcessServiceSearchAttribute(const SDP_PDUHeader_t* const SDPHeader,
|
|
||||||
Bluetooth_Channel_t* const Channel)
|
|
||||||
{
|
|
||||||
const void* CurrentParameter = ((const void*)SDPHeader + sizeof(SDP_PDUHeader_t));
|
|
||||||
|
|
||||||
BT_SDP_DEBUG(1, "<< Service Search Attribute");
|
|
||||||
|
|
||||||
/* Retrieve the list of search UUIDs from the request */
|
|
||||||
uint8_t UUIDList[12][UUID_SIZE_BYTES];
|
|
||||||
uint8_t TotalUUIDs = SDP_GetUUIDList(UUIDList, &CurrentParameter);
|
|
||||||
BT_SDP_DEBUG(2, "-- Total UUIDs: %d", TotalUUIDs);
|
|
||||||
|
|
||||||
/* Retrieve the maximum Attribute response size from the request */
|
|
||||||
uint16_t MaxAttributeSize = SDP_ReadData16(&CurrentParameter);
|
|
||||||
BT_SDP_DEBUG(2, "-- Max Return Attribute Bytes: 0x%04X", MaxAttributeSize);
|
|
||||||
|
|
||||||
/* Retrieve the list of Attributes from the request */
|
|
||||||
uint16_t AttributeList[8][2];
|
|
||||||
uint8_t TotalAttributes = SDP_GetAttributeList(AttributeList, &CurrentParameter);
|
|
||||||
BT_SDP_DEBUG(2, "-- Total Attributes: %d", TotalAttributes);
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
SDP_PDUHeader_t SDPHeader;
|
|
||||||
uint16_t AttributeListByteCount;
|
|
||||||
uint8_t ResponseData[100];
|
|
||||||
} ResponsePacket;
|
|
||||||
|
|
||||||
/* Create a pointer to the buffer to indicate the current location for response data to be added */
|
|
||||||
void* CurrResponsePos = ResponsePacket.ResponseData;
|
|
||||||
|
|
||||||
/* Clamp the maximum attribute size to the size of the allocated buffer */
|
|
||||||
if (MaxAttributeSize > sizeof(ResponsePacket.ResponseData))
|
|
||||||
MaxAttributeSize = sizeof(ResponsePacket.ResponseData);
|
|
||||||
|
|
||||||
/* Add the outer Data Element Sequence header for all of the retrieved Attributes */
|
|
||||||
uint16_t* TotalResponseSize = SDP_AddSequence16(&CurrResponsePos);
|
|
||||||
|
|
||||||
/* Search through the global service list an item at a time */
|
|
||||||
for (uint8_t CurrTableItem = 0; CurrTableItem < (sizeof(SDP_Services_Table) / sizeof(void*)); CurrTableItem++)
|
|
||||||
{
|
|
||||||
/* Read in a pointer to the current UUID table entry's Attribute table */
|
|
||||||
ServiceAttributeTable_t* CurrAttributeTable = pgm_read_ptr(&SDP_Services_Table[CurrTableItem]);
|
|
||||||
|
|
||||||
if (!(SDP_SearchServiceTable(UUIDList, TotalUUIDs, CurrAttributeTable)))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
BT_SDP_DEBUG(2, " -- Found search match in table");
|
|
||||||
|
|
||||||
/* Add the listed attributes for the found UUID to the response */
|
|
||||||
*TotalResponseSize += SDP_AddListedAttributesToResponse(CurrAttributeTable, AttributeList, TotalAttributes,
|
|
||||||
&CurrResponsePos);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Continuation state - always zero */
|
|
||||||
SDP_WriteData8(&CurrResponsePos, 0);
|
|
||||||
|
|
||||||
/* Set the total response list size to the size of the outer container plus its header size and continuation state */
|
|
||||||
ResponsePacket.AttributeListByteCount = SwapEndian_16(3 + *TotalResponseSize);
|
|
||||||
|
|
||||||
/* Calculate the total parameter length that is to be sent, including the fixed return parameters, the created attribute
|
|
||||||
value list and the SDP continuation state */
|
|
||||||
uint16_t ParamLength = (sizeof(ResponsePacket.AttributeListByteCount) +
|
|
||||||
(3 + *TotalResponseSize) +
|
|
||||||
sizeof(uint8_t));
|
|
||||||
|
|
||||||
/* Flip the endianness of the container's size */
|
|
||||||
*TotalResponseSize = SwapEndian_16(*TotalResponseSize);
|
|
||||||
|
|
||||||
/* Fill in the response packet's header */
|
|
||||||
ResponsePacket.SDPHeader.PDU = SDP_PDU_SERVICESEARCHATTRIBUTERESPONSE;
|
|
||||||
ResponsePacket.SDPHeader.TransactionID = SDPHeader->TransactionID;
|
|
||||||
ResponsePacket.SDPHeader.ParameterLength = SwapEndian_16(ParamLength);
|
|
||||||
|
|
||||||
BT_SDP_DEBUG(1, ">> Service Search Attribute Response");
|
|
||||||
BT_SDP_DEBUG(2, "-- Param Len 0x%04X", ParamLength);
|
|
||||||
|
|
||||||
/* Send the completed response packet to the sender */
|
|
||||||
Bluetooth_SendPacket(&ResponsePacket, (sizeof(ResponsePacket.SDPHeader) + ParamLength), Channel);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Adds all the Attributes in the given service table to the response that appear in the Attribute table.
|
|
||||||
*
|
|
||||||
* \param[in] AttributeTable Pointer to an Attribute table for the service to examine
|
|
||||||
* \param[in] AttributeList Pointer to a list of Attribute ranges
|
|
||||||
* \param[in] TotalAttributes Number of Attributes stored in the Attribute list
|
|
||||||
* \param[out] BufferPos Pointer to the output buffer position where the retrieved attributes are to be stored
|
|
||||||
*
|
|
||||||
* \return Number of bytes added to the output buffer
|
|
||||||
*/
|
|
||||||
static uint16_t SDP_AddListedAttributesToResponse(const ServiceAttributeTable_t* AttributeTable,
|
|
||||||
uint16_t AttributeList[][2],
|
|
||||||
const uint8_t TotalAttributes,
|
|
||||||
void** const BufferPos)
|
|
||||||
{
|
|
||||||
uint16_t TotalResponseSize;
|
|
||||||
|
|
||||||
/* Add an inner Data Element Sequence header for the current services's found Attributes */
|
|
||||||
uint16_t* AttributeListSize = SDP_AddSequence16(BufferPos);
|
|
||||||
|
|
||||||
/* Search through the list of Attributes one at a time looking for values in the current UUID's Attribute table */
|
|
||||||
for (uint8_t CurrAttribute = 0; CurrAttribute < TotalAttributes; CurrAttribute++)
|
|
||||||
{
|
|
||||||
uint16_t* AttributeIDRange = AttributeList[CurrAttribute];
|
|
||||||
void* AttributeValue;
|
|
||||||
|
|
||||||
/* Look through the current service's attribute list, examining all the attributes */
|
|
||||||
while ((AttributeValue = pgm_read_ptr(&AttributeTable->Data)) != NULL)
|
|
||||||
{
|
|
||||||
/* Get the current Attribute's ID from the current attribute table entry */
|
|
||||||
uint16_t CurrAttributeID = pgm_read_word(&AttributeTable->AttributeID);
|
|
||||||
|
|
||||||
/* Check if the current Attribute's ID is within the current Attribute range */
|
|
||||||
if ((CurrAttributeID >= AttributeIDRange[0]) && (CurrAttributeID <= AttributeIDRange[1]))
|
|
||||||
{
|
|
||||||
/* Increment the current UUID's returned Attribute container size by the number of added bytes */
|
|
||||||
*AttributeListSize += SDP_AddAttributeToResponse(CurrAttributeID, AttributeValue, BufferPos);
|
|
||||||
}
|
|
||||||
|
|
||||||
AttributeTable++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Record the total number of added bytes to the buffer */
|
|
||||||
TotalResponseSize = 3 + *AttributeListSize;
|
|
||||||
|
|
||||||
/* Fix endianness of the added attribute data element sequence */
|
|
||||||
*AttributeListSize = SwapEndian_16(*AttributeListSize);
|
|
||||||
|
|
||||||
return TotalResponseSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Adds the given attribute ID and value to the response buffer, and advances the response buffer pointer past the added data.
|
|
||||||
*
|
|
||||||
* \param[in] AttributeID Attribute ID to add to the response buffer
|
|
||||||
* \param[in] AttributeValue Pointer to the start of the Attribute's value, located in PROGMEM
|
|
||||||
* \param[in, out] ResponseBuffer Pointer to a buffer where the Attribute and Attribute Value is to be added
|
|
||||||
*
|
|
||||||
* \return Number of bytes added to the response buffer
|
|
||||||
*/
|
|
||||||
static uint16_t SDP_AddAttributeToResponse(const uint16_t AttributeID,
|
|
||||||
const void* AttributeValue,
|
|
||||||
void** ResponseBuffer)
|
|
||||||
{
|
|
||||||
/* Retrieve the size of the attribute value from its container header */
|
|
||||||
uint8_t AttributeHeaderLength;
|
|
||||||
uint16_t AttributeValueLength = SDP_GetLocalAttributeContainerSize(AttributeValue, &AttributeHeaderLength);
|
|
||||||
|
|
||||||
BT_SDP_DEBUG(2, " -- Add Attribute (0x%04X) 0x%04X", (AttributeHeaderLength + AttributeValueLength), AttributeID);
|
|
||||||
|
|
||||||
/* Add a Data Element header to the response for the Attribute ID */
|
|
||||||
SDP_WriteData8(ResponseBuffer, (SDP_DATATYPE_UnsignedInt | SDP_DATASIZE_16Bit));
|
|
||||||
|
|
||||||
/* Add the Attribute ID to the created Data Element */
|
|
||||||
SDP_WriteData16(ResponseBuffer, AttributeID);
|
|
||||||
|
|
||||||
/* Copy over the Attribute value Data Element container to the response */
|
|
||||||
memcpy_P(*ResponseBuffer, AttributeValue, AttributeHeaderLength + AttributeValueLength);
|
|
||||||
*ResponseBuffer += AttributeHeaderLength + AttributeValueLength;
|
|
||||||
|
|
||||||
return (sizeof(uint8_t) + sizeof(uint16_t) + AttributeHeaderLength + AttributeValueLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Retrieves a pointer to the value of the given Attribute ID from the given Attribute table.
|
|
||||||
*
|
|
||||||
* \param[in] AttributeTable Pointer to the Attribute table to search in
|
|
||||||
* \param[in] AttributeID Attribute ID to search for within the table
|
|
||||||
*
|
|
||||||
* \return Pointer to the start of the Attribute's value if found within the table, NULL otherwise
|
|
||||||
*/
|
|
||||||
static void* SDP_GetAttributeValue(const ServiceAttributeTable_t* AttributeTable,
|
|
||||||
const uint16_t AttributeID)
|
|
||||||
{
|
|
||||||
void* CurrTableItemData;
|
|
||||||
|
|
||||||
/* Search through the current Attribute table, abort when the terminator item has been reached */
|
|
||||||
while ((CurrTableItemData = pgm_read_ptr(&AttributeTable->Data)) != NULL)
|
|
||||||
{
|
|
||||||
/* Check if the current Attribute ID matches the search ID - if so return a pointer to it */
|
|
||||||
if (pgm_read_word(&AttributeTable->AttributeID) == AttributeID)
|
|
||||||
return CurrTableItemData;
|
|
||||||
|
|
||||||
AttributeTable++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Retrieves the Attribute table for the given UUID list if it exists.
|
|
||||||
*
|
|
||||||
* \param[in] UUIDList List of UUIDs which must be matched within the service attribute table
|
|
||||||
* \param[in] TotalUUIDs Total number of UUIDs stored in the UUID list
|
|
||||||
* \param[in] CurrAttributeTable Pointer to the service attribute table to search through
|
|
||||||
*
|
|
||||||
* \return True if all the UUIDs given in the UUID list appear in the given attribute table, false otherwise
|
|
||||||
*/
|
|
||||||
static bool SDP_SearchServiceTable(uint8_t UUIDList[][UUID_SIZE_BYTES],
|
|
||||||
const uint8_t TotalUUIDs,
|
|
||||||
const ServiceAttributeTable_t* CurrAttributeTable)
|
|
||||||
{
|
|
||||||
const void* CurrAttribute;
|
|
||||||
uint16_t UUIDMatchFlags = 0;
|
|
||||||
|
|
||||||
/* Search through the current attribute table, checking each attribute value for UUID matches */
|
|
||||||
while ((CurrAttribute = pgm_read_ptr(&CurrAttributeTable->Data)) != NULL)
|
|
||||||
{
|
|
||||||
SDP_CheckUUIDMatch(UUIDList, TotalUUIDs, &UUIDMatchFlags, CurrAttribute);
|
|
||||||
CurrAttributeTable++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Determine how many UUID matches in the list we have found */
|
|
||||||
uint8_t UUIDMatches;
|
|
||||||
for (UUIDMatches = 0; UUIDMatchFlags; UUIDMatches++)
|
|
||||||
UUIDMatchFlags &= (UUIDMatchFlags - 1);
|
|
||||||
|
|
||||||
/* If all UUIDs have been matched to the current service, return true */
|
|
||||||
return (UUIDMatches == TotalUUIDs);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Recursively unwraps the given locally stored attribute (in PROGMEM space), searching for UUIDs to match against
|
|
||||||
* the given UUID list. As matches are found, they are indicated in the UUIDMatch flag list.
|
|
||||||
*
|
|
||||||
* \param[in] UUIDList List of UUIDs which must be matched within the service attribute table
|
|
||||||
* \param[in] TotalUUIDs Total number of UUIDs stored in the UUID list
|
|
||||||
* \param[in, out] UUIDMatchFlags Array of flags indicating which UUIDs in the list have already been matched
|
|
||||||
* \param[in] CurrAttribute Pointer to the current attribute to search through
|
|
||||||
*
|
|
||||||
* \return True if all the UUIDs given in the UUID list appear in the given attribute table, false otherwise
|
|
||||||
*/
|
|
||||||
static void SDP_CheckUUIDMatch(uint8_t UUIDList[][UUID_SIZE_BYTES],
|
|
||||||
const uint8_t TotalUUIDs,
|
|
||||||
uint16_t* const UUIDMatchFlags,
|
|
||||||
const void* CurrAttribute)
|
|
||||||
{
|
|
||||||
uint8_t CurrAttributeType = (pgm_read_byte(CurrAttribute) & ~0x07);
|
|
||||||
|
|
||||||
/* Check the data type of the current attribute value - if UUID, compare, if Sequence, unwrap and recurse */
|
|
||||||
if (CurrAttributeType == SDP_DATATYPE_UUID)
|
|
||||||
{
|
|
||||||
uint16_t CurrUUIDMatchMask = (1 << 0);
|
|
||||||
|
|
||||||
/* Look for matches in the UUID list against the current attribute UUID value */
|
|
||||||
for (uint8_t i = 0; i < TotalUUIDs; i++)
|
|
||||||
{
|
|
||||||
/* Check if the current unmatched UUID is identical to the search UUID */
|
|
||||||
if (!(*UUIDMatchFlags & CurrUUIDMatchMask) && !(memcmp_P(UUIDList[i], (CurrAttribute + 1), UUID_SIZE_BYTES)))
|
|
||||||
{
|
|
||||||
/* Indicate match found for the current attribute UUID and early-abort */
|
|
||||||
*UUIDMatchFlags |= CurrUUIDMatchMask;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
CurrUUIDMatchMask <<= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (CurrAttributeType == SDP_DATATYPE_Sequence)
|
|
||||||
{
|
|
||||||
uint8_t SequenceHeaderSize;
|
|
||||||
uint16_t SequenceSize = SDP_GetLocalAttributeContainerSize(CurrAttribute, &SequenceHeaderSize);
|
|
||||||
|
|
||||||
CurrAttribute += SequenceHeaderSize;
|
|
||||||
|
|
||||||
/* Recursively unwrap the sequence container, and re-search its contents for UUIDs */
|
|
||||||
while (SequenceSize)
|
|
||||||
{
|
|
||||||
uint8_t InnerHeaderSize;
|
|
||||||
uint16_t InnerSize = SDP_GetLocalAttributeContainerSize(CurrAttribute, &InnerHeaderSize);
|
|
||||||
|
|
||||||
/* Recursively search of the next element in the sequence, trying to match UUIDs with the UUID list */
|
|
||||||
SDP_CheckUUIDMatch(UUIDList, TotalUUIDs, UUIDMatchFlags, CurrAttribute);
|
|
||||||
|
|
||||||
/* Skip to the next element in the sequence */
|
|
||||||
SequenceSize -= InnerHeaderSize + InnerSize;
|
|
||||||
CurrAttribute += InnerHeaderSize + InnerSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Reads in the collection of Attribute ranges from the input buffer's Data Element Sequence container, into the given
|
|
||||||
* Attribute list for later use. Once complete, the input buffer pointer is advanced to the end of the Attribute container.
|
|
||||||
*
|
|
||||||
* \param[out] AttributeList Pointer to a buffer where the list of Attribute ranges are to be stored
|
|
||||||
* \param[in] CurrentParameter Pointer to a Buffer containing a Data Element Sequence of Attribute and Attribute Range elements
|
|
||||||
*
|
|
||||||
* \return Total number of Attribute ranges stored in the Data Element Sequence
|
|
||||||
*/
|
|
||||||
static uint8_t SDP_GetAttributeList(uint16_t AttributeList[][2],
|
|
||||||
const void** const CurrentParameter)
|
|
||||||
{
|
|
||||||
uint8_t ElementHeaderSize;
|
|
||||||
uint8_t TotalAttributes = 0;
|
|
||||||
|
|
||||||
/* Retrieve the total size of the Attribute container, and unwrap the outer Data Element Sequence container */
|
|
||||||
uint16_t AttributeIDListLength = SDP_GetDataElementSize(CurrentParameter, &ElementHeaderSize);
|
|
||||||
BT_SDP_DEBUG(2, "-- Total Attribute Length: 0x%04X", AttributeIDListLength);
|
|
||||||
while (AttributeIDListLength)
|
|
||||||
{
|
|
||||||
/* Retrieve the size of the next Attribute in the container and get a pointer to the next free Attribute element in the list */
|
|
||||||
uint16_t* CurrentAttributeRange = AttributeList[TotalAttributes++];
|
|
||||||
uint8_t AttributeLength = SDP_GetDataElementSize(CurrentParameter, &ElementHeaderSize);
|
|
||||||
|
|
||||||
/* Copy over the starting Attribute ID and (if it the current element is a range) the ending Attribute ID */
|
|
||||||
memcpy(&CurrentAttributeRange[0], *CurrentParameter, AttributeLength);
|
|
||||||
|
|
||||||
/* If the element is not an Attribute Range, copy over the starting ID to the ending ID to make a range of 1 */
|
|
||||||
if (AttributeLength == 2)
|
|
||||||
CurrentAttributeRange[1] = CurrentAttributeRange[0];
|
|
||||||
|
|
||||||
/* Swap the endianness of the attribute range values */
|
|
||||||
CurrentAttributeRange[0] = SwapEndian_16(CurrentAttributeRange[0]);
|
|
||||||
CurrentAttributeRange[1] = SwapEndian_16(CurrentAttributeRange[1]);
|
|
||||||
|
|
||||||
BT_SDP_DEBUG(2, "-- Attribute: 0x%04X-0x%04X", CurrentAttributeRange[0], CurrentAttributeRange[1]);
|
|
||||||
|
|
||||||
AttributeIDListLength -= (AttributeLength + ElementHeaderSize);
|
|
||||||
*CurrentParameter += AttributeLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
return TotalAttributes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Reads in the collection of UUIDs from the input buffer's Data Element Sequence container, into the given
|
|
||||||
* UUID list for later use. Once complete, the input buffer pointer is advanced to the end of the UUID container.
|
|
||||||
*
|
|
||||||
* \param[out] UUIDList Pointer to a buffer where the list of UUIDs are to be stored
|
|
||||||
* \param[in] CurrentParameter Pointer to a Buffer containing a Data Element Sequence of UUID elements
|
|
||||||
*
|
|
||||||
* \return Total number of UUIDs stored in the Data Element Sequence
|
|
||||||
*/
|
|
||||||
static uint8_t SDP_GetUUIDList(uint8_t UUIDList[][UUID_SIZE_BYTES],
|
|
||||||
const void** const CurrentParameter)
|
|
||||||
{
|
|
||||||
uint8_t ElementHeaderSize;
|
|
||||||
uint8_t TotalUUIDs = 0;
|
|
||||||
|
|
||||||
/* Retrieve the total size of the UUID container, and unwrap the outer Data Element Sequence container */
|
|
||||||
uint16_t ServicePatternLength = SDP_GetDataElementSize(CurrentParameter, &ElementHeaderSize);
|
|
||||||
BT_SDP_DEBUG(2, "-- Total UUID Length: 0x%04X", ServicePatternLength);
|
|
||||||
while (ServicePatternLength)
|
|
||||||
{
|
|
||||||
/* Retrieve the size of the next UUID in the container and get a pointer to the next free UUID element in the list */
|
|
||||||
uint8_t* CurrentUUID = UUIDList[TotalUUIDs++];
|
|
||||||
uint8_t UUIDLength = SDP_GetDataElementSize(CurrentParameter, &ElementHeaderSize);
|
|
||||||
|
|
||||||
/* Copy over UUID from the container to the free slot */
|
|
||||||
if (UUIDLength <= 4)
|
|
||||||
{
|
|
||||||
/* Copy over the base UUID value to the free UUID slot in the list */
|
|
||||||
memcpy_P(CurrentUUID, &BaseUUID, sizeof(BaseUUID));
|
|
||||||
|
|
||||||
/* Copy over short UUID */
|
|
||||||
memcpy(CurrentUUID + (4 - UUIDLength), *CurrentParameter, UUIDLength);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Copy over full UUID */
|
|
||||||
memcpy(CurrentUUID, *CurrentParameter, UUIDLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
BT_SDP_DEBUG(2, "-- UUID (%d): %02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
|
|
||||||
UUIDLength,
|
|
||||||
CurrentUUID[0], CurrentUUID[1], CurrentUUID[2], CurrentUUID[3],
|
|
||||||
CurrentUUID[4], CurrentUUID[5],
|
|
||||||
CurrentUUID[6], CurrentUUID[7],
|
|
||||||
CurrentUUID[8], CurrentUUID[9],
|
|
||||||
CurrentUUID[10], CurrentUUID[11], CurrentUUID[12], CurrentUUID[13], CurrentUUID[14], CurrentUUID[15]);
|
|
||||||
|
|
||||||
ServicePatternLength -= (UUIDLength + ElementHeaderSize);
|
|
||||||
*CurrentParameter += UUIDLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
return TotalUUIDs;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Retrieves the total size of the given locally stored (in PROGMEM) attribute Data Element container.
|
|
||||||
*
|
|
||||||
* \param[in] AttributeData Pointer to the start of the Attribute container, located in PROGMEM
|
|
||||||
* \param[out] HeaderSize Pointer to a location where the header size of the data element is to be stored
|
|
||||||
*
|
|
||||||
* \return Size in bytes of the entire attribute container, including the header
|
|
||||||
*/
|
|
||||||
static uint32_t SDP_GetLocalAttributeContainerSize(const void* const AttributeData,
|
|
||||||
uint8_t* const HeaderSize)
|
|
||||||
{
|
|
||||||
/* Fetch the size of the Data Element structure from the header */
|
|
||||||
uint8_t SizeIndex = (pgm_read_byte(AttributeData) & 0x07);
|
|
||||||
|
|
||||||
uint32_t ElementValueSize;
|
|
||||||
|
|
||||||
/* Convert the Data Element size index into a size in bytes */
|
|
||||||
switch (SizeIndex)
|
|
||||||
{
|
|
||||||
case SDP_DATASIZE_Variable8Bit:
|
|
||||||
*HeaderSize = (1 + sizeof(uint8_t));
|
|
||||||
ElementValueSize = pgm_read_byte(AttributeData + 1);
|
|
||||||
break;
|
|
||||||
case SDP_DATASIZE_Variable16Bit:
|
|
||||||
*HeaderSize = (1 + sizeof(uint16_t));
|
|
||||||
ElementValueSize = SwapEndian_16(pgm_read_word(AttributeData + 1));
|
|
||||||
break;
|
|
||||||
case SDP_DATASIZE_Variable32Bit:
|
|
||||||
*HeaderSize = (1 + sizeof(uint32_t));
|
|
||||||
ElementValueSize = SwapEndian_32(pgm_read_dword(AttributeData + 1));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
*HeaderSize = 1;
|
|
||||||
ElementValueSize = (1 << SizeIndex);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ElementValueSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Retrieves the size of a Data Element container from the current input buffer, and advances the input buffer
|
|
||||||
* pointer to the start of the Data Element's contents.
|
|
||||||
*
|
|
||||||
* \param[in, out] DataElementHeader Pointer to the start of a Data Element header
|
|
||||||
* \param[out] ElementHeaderSize Size in bytes of the header that was skipped
|
|
||||||
*
|
|
||||||
* \return Size in bytes of the Data Element container's contents, minus the header
|
|
||||||
*/
|
|
||||||
static uint32_t SDP_GetDataElementSize(const void** const DataElementHeader,
|
|
||||||
uint8_t* const ElementHeaderSize)
|
|
||||||
{
|
|
||||||
/* Fetch the size of the Data Element structure from the header, increment the current buffer pos */
|
|
||||||
uint8_t SizeIndex = (SDP_ReadData8(DataElementHeader) & 0x07);
|
|
||||||
|
|
||||||
uint32_t ElementValueSize;
|
|
||||||
|
|
||||||
/* Convert the Data Element size index into a size in bytes */
|
|
||||||
switch (SizeIndex)
|
|
||||||
{
|
|
||||||
case SDP_DATASIZE_Variable8Bit:
|
|
||||||
*ElementHeaderSize = (1 + sizeof(uint8_t));
|
|
||||||
ElementValueSize = SDP_ReadData8(DataElementHeader);
|
|
||||||
break;
|
|
||||||
case SDP_DATASIZE_Variable16Bit:
|
|
||||||
*ElementHeaderSize = (1 + sizeof(uint16_t));
|
|
||||||
ElementValueSize = SDP_ReadData16(DataElementHeader);
|
|
||||||
break;
|
|
||||||
case SDP_DATASIZE_Variable32Bit:
|
|
||||||
*ElementHeaderSize = (1 + sizeof(uint32_t));
|
|
||||||
ElementValueSize = SDP_ReadData32(DataElementHeader);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
*ElementHeaderSize = 1;
|
|
||||||
ElementValueSize = (1 << SizeIndex);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ElementValueSize;
|
|
||||||
}
|
|
||||||
|
|
@ -1,250 +0,0 @@
|
|||||||
/*
|
|
||||||
LUFA Library
|
|
||||||
Copyright (C) Dean Camera, 2012.
|
|
||||||
|
|
||||||
dean [at] fourwalledcubicle [dot] com
|
|
||||||
www.lufa-lib.org
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright 2012 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
|
||||||
|
|
||||||
Permission to use, copy, modify, distribute, and sell this
|
|
||||||
software and its documentation for any purpose is hereby granted
|
|
||||||
without fee, provided that the above copyright notice appear in
|
|
||||||
all copies and that both that the copyright notice and this
|
|
||||||
permission notice and warranty disclaimer appear in supporting
|
|
||||||
documentation, and that the name of the author not be used in
|
|
||||||
advertising or publicity pertaining to distribution of the
|
|
||||||
software without specific, written prior permission.
|
|
||||||
|
|
||||||
The author disclaim all warranties with regard to this
|
|
||||||
software, including all implied warranties of merchantability
|
|
||||||
and fitness. In no event shall the author be liable for any
|
|
||||||
special, indirect or consequential damages or any damages
|
|
||||||
whatsoever resulting from loss of use, data or profits, whether
|
|
||||||
in an action of contract, negligence or other tortious action,
|
|
||||||
arising out of or in connection with the use or performance of
|
|
||||||
this software.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** \file
|
|
||||||
*
|
|
||||||
* Header file for ServiceDiscoveryProtocol.c.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _SERVICEDISCOVERYPROTOCOL_H_
|
|
||||||
#define _SERVICEDISCOVERYPROTOCOL_H_
|
|
||||||
|
|
||||||
/* Includes: */
|
|
||||||
#include <avr/io.h>
|
|
||||||
#include <avr/pgmspace.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include <LUFA/Common/Common.h>
|
|
||||||
#include <LUFA/Drivers/Peripheral/Serial.h>
|
|
||||||
|
|
||||||
#include "BluetoothStack.h"
|
|
||||||
#include "SDPServices.h"
|
|
||||||
|
|
||||||
/* Macros: */
|
|
||||||
#define BT_SDP_DEBUG(l, s, ...) do { if (SDP_DEBUG_LEVEL >= l) printf_P(PSTR("(SDP) " s "\r\n"), ##__VA_ARGS__); } while (0)
|
|
||||||
#define SDP_DEBUG_LEVEL 0
|
|
||||||
|
|
||||||
#define SDP_PDU_ERRORRESPONSE 0x01
|
|
||||||
#define SDP_PDU_SERVICESEARCHREQUEST 0x02
|
|
||||||
#define SDP_PDU_SERVICESEARCHRESPONSE 0x03
|
|
||||||
#define SDP_PDU_SERVICEATTRIBUTEREQUEST 0x04
|
|
||||||
#define SDP_PDU_SERVICEATTRIBUTERESPONSE 0x05
|
|
||||||
#define SDP_PDU_SERVICESEARCHATTRIBUTEREQUEST 0x06
|
|
||||||
#define SDP_PDU_SERVICESEARCHATTRIBUTERESPONSE 0x07
|
|
||||||
|
|
||||||
/* Enums: */
|
|
||||||
/** Data sizes for SDP Data Element headers, to indicate the size of the data contained in the element. When creating
|
|
||||||
* a Data Element, a value from this enum should be ORed with a value from the \ref ServiceDiscovery_DataTypes_t enum.
|
|
||||||
*/
|
|
||||||
enum ServiceDiscovery_DataSizes_t
|
|
||||||
{
|
|
||||||
SDP_DATASIZE_8Bit = 0, /**< Contained data is 8 bits in length. */
|
|
||||||
SDP_DATASIZE_16Bit = 1, /**< Contained data is 16 bits in length. */
|
|
||||||
SDP_DATASIZE_32Bit = 2, /**< Contained data is 32 bits in length. */
|
|
||||||
SDP_DATASIZE_64Bit = 3, /**< Contained data is 64 bits in length. */
|
|
||||||
SDP_DATASIZE_128Bit = 4, /**< Contained data is 128 bits in length. */
|
|
||||||
SDP_DATASIZE_Variable8Bit = 5, /**< Contained data is encoded in an 8 bit size integer following the header. */
|
|
||||||
SDP_DATASIZE_Variable16Bit = 6, /**< Contained data is encoded in an 16 bit size integer following the header. */
|
|
||||||
SDP_DATASIZE_Variable32Bit = 7, /**< Contained data is encoded in an 32 bit size integer following the header. */
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Data types for SDP Data Element headers, to indicate the type of data contained in the element. When creating
|
|
||||||
* a Data Element, a value from this enum should be ORed with a value from the \ref ServiceDiscovery_DataSizes_t enum.
|
|
||||||
*/
|
|
||||||
enum ServiceDiscovery_DataTypes_t
|
|
||||||
{
|
|
||||||
SDP_DATATYPE_Nill = (0 << 3), /**< Indicates the container data is a Nill (null) type. */
|
|
||||||
SDP_DATATYPE_UnsignedInt = (1 << 3), /**< Indicates the container data is an unsigned integer. */
|
|
||||||
SDP_DATATYPE_SignedInt = (2 << 3), /**< Indicates the container data is a signed integer. */
|
|
||||||
SDP_DATATYPE_UUID = (3 << 3), /**< Indicates the container data is a UUID. */
|
|
||||||
SDP_DATATYPE_String = (4 << 3), /**< Indicates the container data is an ASCII string. */
|
|
||||||
SDP_DATATYPE_Boolean = (5 << 3), /**< Indicates the container data is a logical boolean. */
|
|
||||||
SDP_DATATYPE_Sequence = (6 << 3), /**< Indicates the container data is a sequence of containers. */
|
|
||||||
SDP_DATATYPE_Alternative = (7 << 3), /**< Indicates the container data is a sequence of alternative containers. */
|
|
||||||
SDP_DATATYPE_URL = (8 << 3), /**< Indicates the container data is a URL. */
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Type Defines: */
|
|
||||||
/** Header for all SPD transaction packets. This header is sent at the start of all SDP packets sent to or from a SDP
|
|
||||||
* server.
|
|
||||||
*/
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint8_t PDU; /**< SDP packet type, a \c SDP_PDU_* mask value */
|
|
||||||
uint16_t TransactionID; /**< Unique transaction ID number to associate requests and responses */
|
|
||||||
uint16_t ParameterLength; /**< Length of the data following the SDP header */
|
|
||||||
} SDP_PDUHeader_t;
|
|
||||||
|
|
||||||
/* Inline Functions: */
|
|
||||||
/** Writes 8 bits of raw data to the given buffer, incrementing the buffer position afterwards.
|
|
||||||
*
|
|
||||||
* \param[in, out] BufferPos Current position in the buffer where the data is to be written to
|
|
||||||
* \param[in] Data Data to write to the buffer
|
|
||||||
*/
|
|
||||||
static inline void SDP_WriteData8(void** BufferPos,
|
|
||||||
const uint8_t Data)
|
|
||||||
{
|
|
||||||
*((uint8_t*)*BufferPos) = Data;
|
|
||||||
*BufferPos += sizeof(uint8_t);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Writes 16 bits of raw data to the given buffer, incrementing the buffer position afterwards.
|
|
||||||
*
|
|
||||||
* \param[in, out] BufferPos Current position in the buffer where the data is to be written to
|
|
||||||
* \param[in] Data Data to write to the buffer
|
|
||||||
*/
|
|
||||||
static inline void SDP_WriteData16(void** BufferPos,
|
|
||||||
const uint16_t Data)
|
|
||||||
{
|
|
||||||
*((uint16_t*)*BufferPos) = SwapEndian_16(Data);
|
|
||||||
*BufferPos += sizeof(uint16_t);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Writes 32 bits of raw data to the given buffer, incrementing the buffer position afterwards.
|
|
||||||
*
|
|
||||||
* \param[in, out] BufferPos Current position in the buffer where the data is to be written to
|
|
||||||
* \param[in] Data Data to write to the buffer
|
|
||||||
*/
|
|
||||||
static inline void SDP_WriteData32(void** BufferPos,
|
|
||||||
const uint32_t Data)
|
|
||||||
{
|
|
||||||
*((uint32_t*)*BufferPos) = SwapEndian_32(Data);
|
|
||||||
*BufferPos += sizeof(uint32_t);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Reads 8 bits of raw data from the given buffer, incrementing the buffer position afterwards.
|
|
||||||
*
|
|
||||||
* \param[in, out] BufferPos Current position in the buffer where the data is to be read from
|
|
||||||
*
|
|
||||||
* \return Data read from the buffer
|
|
||||||
*/
|
|
||||||
static inline uint8_t SDP_ReadData8(const void** BufferPos)
|
|
||||||
{
|
|
||||||
uint8_t Data = *((const uint8_t*)*BufferPos);
|
|
||||||
*BufferPos += sizeof(uint8_t);
|
|
||||||
|
|
||||||
return Data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Reads 16 bits of raw data from the given buffer, incrementing the buffer position afterwards.
|
|
||||||
*
|
|
||||||
* \param[in, out] BufferPos Current position in the buffer where the data is to be read from
|
|
||||||
*
|
|
||||||
* \return Data read from the buffer
|
|
||||||
*/
|
|
||||||
static inline uint16_t SDP_ReadData16(const void** BufferPos)
|
|
||||||
{
|
|
||||||
uint16_t Data = SwapEndian_16(*((const uint16_t*)*BufferPos));
|
|
||||||
*BufferPos += sizeof(uint16_t);
|
|
||||||
|
|
||||||
return Data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Reads 32 bits of raw data from the given buffer, incrementing the buffer position afterwards.
|
|
||||||
*
|
|
||||||
* \param[in, out] BufferPos Current position in the buffer where the data is to be read from
|
|
||||||
*
|
|
||||||
* \return Data read from the buffer
|
|
||||||
*/
|
|
||||||
static inline uint32_t SDP_ReadData32(const void** BufferPos)
|
|
||||||
{
|
|
||||||
uint32_t Data = SwapEndian_32(*((const uint32_t*)*BufferPos));
|
|
||||||
*BufferPos += sizeof(uint32_t);
|
|
||||||
|
|
||||||
return Data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Adds a new Data Element Sequence container with a 16-bit size header to the buffer. The buffer
|
|
||||||
* pointer's position is advanced past the added header once the element has been added. The returned
|
|
||||||
* size header value is pre-zeroed out so that it can be incremented as data is placed into the Data
|
|
||||||
* Element Sequence container.
|
|
||||||
*
|
|
||||||
* The total added size of the container header is three bytes, regardless of the size of its contents
|
|
||||||
* as long as the contents' size in bytes fits into a 16-bit integer.
|
|
||||||
*
|
|
||||||
* \param[in, out] BufferPos Pointer to a buffer where the container header is to be placed
|
|
||||||
*
|
|
||||||
* \return Pointer to the 16-bit size value of the container header, which has been pre-zeroed
|
|
||||||
*/
|
|
||||||
static inline uint16_t* SDP_AddSequence16(void** BufferPos)
|
|
||||||
{
|
|
||||||
SDP_WriteData8(BufferPos, (SDP_DATASIZE_Variable16Bit | SDP_DATATYPE_Sequence));
|
|
||||||
|
|
||||||
uint16_t* SizePos = *BufferPos;
|
|
||||||
SDP_WriteData16(BufferPos, 0);
|
|
||||||
|
|
||||||
return SizePos;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Function Prototypes: */
|
|
||||||
void SDP_ProcessPacket(void* Data,
|
|
||||||
Bluetooth_Channel_t* const Channel);
|
|
||||||
|
|
||||||
#if defined(INCLUDE_FROM_SERVICEDISCOVERYPROTOCOL_C)
|
|
||||||
static void SDP_ProcessServiceSearch(const SDP_PDUHeader_t* const SDPHeader,
|
|
||||||
Bluetooth_Channel_t* const Channel);
|
|
||||||
static void SDP_ProcessServiceAttribute(const SDP_PDUHeader_t* const SDPHeader,
|
|
||||||
Bluetooth_Channel_t* const Channel);
|
|
||||||
static void SDP_ProcessServiceSearchAttribute(const SDP_PDUHeader_t* const SDPHeader,
|
|
||||||
Bluetooth_Channel_t* const Channel);
|
|
||||||
|
|
||||||
static uint16_t SDP_AddListedAttributesToResponse(const ServiceAttributeTable_t* AttributeTable,
|
|
||||||
uint16_t AttributeList[][2],
|
|
||||||
const uint8_t TotalAttributes,
|
|
||||||
void** const BufferPos);
|
|
||||||
static uint16_t SDP_AddAttributeToResponse(const uint16_t AttributeID,
|
|
||||||
const void* AttributeValue,
|
|
||||||
void** ResponseBuffer);
|
|
||||||
static void* SDP_GetAttributeValue(const ServiceAttributeTable_t* AttributeTable,
|
|
||||||
const uint16_t AttributeID);
|
|
||||||
|
|
||||||
static bool SDP_SearchServiceTable(uint8_t UUIDList[][UUID_SIZE_BYTES],
|
|
||||||
const uint8_t TotalUUIDs,
|
|
||||||
const ServiceAttributeTable_t* CurrAttributeTable);
|
|
||||||
static void SDP_CheckUUIDMatch(uint8_t UUIDList[][UUID_SIZE_BYTES],
|
|
||||||
const uint8_t TotalUUIDs,
|
|
||||||
uint16_t* const UUIDMatchFlags,
|
|
||||||
const void* CurrAttribute);
|
|
||||||
|
|
||||||
static uint8_t SDP_GetAttributeList(uint16_t AttributeList[][2],
|
|
||||||
const void** const CurrentParameter);
|
|
||||||
static uint8_t SDP_GetUUIDList(uint8_t UUIDList[][UUID_SIZE_BYTES],
|
|
||||||
const void** const CurrentParameter);
|
|
||||||
|
|
||||||
static uint32_t SDP_GetLocalAttributeContainerSize(const void* const AttributeData,
|
|
||||||
uint8_t* const HeaderSize);
|
|
||||||
static uint32_t SDP_GetDataElementSize(const void** const AttributeHeader,
|
|
||||||
uint8_t* const ElementHeaderSize);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,184 +0,0 @@
|
|||||||
/*
|
|
||||||
LUFA Library
|
|
||||||
Copyright (C) Dean Camera, 2012.
|
|
||||||
|
|
||||||
dean [at] fourwalledcubicle [dot] com
|
|
||||||
www.lufa-lib.org
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright 2012 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
|
||||||
|
|
||||||
Permission to use, copy, modify, distribute, and sell this
|
|
||||||
software and its documentation for any purpose is hereby granted
|
|
||||||
without fee, provided that the above copyright notice appear in
|
|
||||||
all copies and that both that the copyright notice and this
|
|
||||||
permission notice and warranty disclaimer appear in supporting
|
|
||||||
documentation, and that the name of the author not be used in
|
|
||||||
advertising or publicity pertaining to distribution of the
|
|
||||||
software without specific, written prior permission.
|
|
||||||
|
|
||||||
The author disclaim all warranties with regard to this
|
|
||||||
software, including all implied warranties of merchantability
|
|
||||||
and fitness. In no event shall the author be liable for any
|
|
||||||
special, indirect or consequential damages or any damages
|
|
||||||
whatsoever resulting from loss of use, data or profits, whether
|
|
||||||
in an action of contract, negligence or other tortious action,
|
|
||||||
arising out of or in connection with the use or performance of
|
|
||||||
this software.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** \file
|
|
||||||
*
|
|
||||||
* SDP Service Attribute definitions. This file contains the attributes
|
|
||||||
* and attribute tables of all the services the device supports, which can
|
|
||||||
* then be retrieved by a connected Bluetooth device via the SDP server.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "SDPServices.h"
|
|
||||||
|
|
||||||
/** Serial Port Profile attribute, listing the unique service handle of the Serial Port service
|
|
||||||
* within the device. This handle can then be requested by the SDP client in future transactions
|
|
||||||
* in lieu of a search UUID list.
|
|
||||||
*/
|
|
||||||
const struct
|
|
||||||
{
|
|
||||||
uint8_t Header;
|
|
||||||
uint32_t Data;
|
|
||||||
} PROGMEM SerialPort_Attribute_ServiceHandle =
|
|
||||||
{
|
|
||||||
(SDP_DATATYPE_UnsignedInt | SDP_DATASIZE_32Bit),
|
|
||||||
SWAPENDIAN_32(0x00010001),
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Serial Port Profile attribute, listing the implemented Service Class UUIDs of the Serial Port service
|
|
||||||
* within the device. This list indicates all the class UUIDs that apply to the Serial Port service, so that
|
|
||||||
* a SDP client can search by a generalized class rather than a specific UUID to determine supported services.
|
|
||||||
*/
|
|
||||||
const struct
|
|
||||||
{
|
|
||||||
uint8_t Header;
|
|
||||||
uint8_t Size;
|
|
||||||
ItemUUID_t UUIDList[];
|
|
||||||
} PROGMEM SerialPort_Attribute_ServiceClassIDs =
|
|
||||||
{
|
|
||||||
(SDP_DATATYPE_Sequence | SDP_DATASIZE_Variable8Bit),
|
|
||||||
(sizeof(ItemUUID_t) * 1),
|
|
||||||
{
|
|
||||||
{(SDP_DATATYPE_UUID | SDP_DATASIZE_128Bit), SP_CLASS_UUID},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Serial Port Profile attribute, listing the Protocols (and their attributes) of the Serial Port service
|
|
||||||
* within the device. This list indicates what protocols the service is layered on top of, as well as any
|
|
||||||
* configuration information for each layer.
|
|
||||||
*/
|
|
||||||
const struct
|
|
||||||
{
|
|
||||||
uint8_t Header;
|
|
||||||
uint8_t Size;
|
|
||||||
|
|
||||||
ItemProtocol_t L2CAP;
|
|
||||||
ItemProtocol_8BitParam_t RFCOMM;
|
|
||||||
} PROGMEM SerialPort_Attribute_ProtocolDescriptor =
|
|
||||||
{
|
|
||||||
(SDP_DATATYPE_Sequence | SDP_DATASIZE_Variable8Bit),
|
|
||||||
(sizeof(ItemProtocol_t) + sizeof(ItemProtocol_8BitParam_t)),
|
|
||||||
{
|
|
||||||
(SDP_DATATYPE_Sequence | SDP_DATASIZE_Variable8Bit),
|
|
||||||
sizeof(ItemUUID_t),
|
|
||||||
{
|
|
||||||
{(SDP_DATATYPE_UUID | SDP_DATASIZE_128Bit), L2CAP_UUID},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
(SDP_DATATYPE_Sequence | SDP_DATASIZE_Variable8Bit),
|
|
||||||
(sizeof(ItemUUID_t) + sizeof(Item8Bit_t)),
|
|
||||||
{
|
|
||||||
{(SDP_DATATYPE_UUID | SDP_DATASIZE_128Bit), RFCOMM_UUID},
|
|
||||||
{(SDP_DATATYPE_UnsignedInt | SDP_DATASIZE_8Bit), 0x03},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Serial Port Profile attribute, listing the Browse Group List UUIDs which this service is a member of.
|
|
||||||
* Browse Group UUIDs give a way to group together services within a device in a simple hierarchy, so that
|
|
||||||
* a SDP client can progressively narrow down an general browse to a specific service which it requires.
|
|
||||||
*/
|
|
||||||
const struct
|
|
||||||
{
|
|
||||||
uint8_t Header;
|
|
||||||
uint8_t Size;
|
|
||||||
ItemUUID_t UUIDList[];
|
|
||||||
} PROGMEM SerialPort_Attribute_BrowseGroupList =
|
|
||||||
{
|
|
||||||
(SDP_DATATYPE_Sequence | SDP_DATASIZE_Variable8Bit),
|
|
||||||
(sizeof(ItemUUID_t) * 1),
|
|
||||||
{
|
|
||||||
{(SDP_DATATYPE_UUID | SDP_DATASIZE_128Bit), PUBLICBROWSEGROUP_CLASS_UUID},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Serial Port Profile attribute, listing the languages (and their encodings) supported
|
|
||||||
* by the Serial Port service in its text string attributes.
|
|
||||||
*/
|
|
||||||
const struct
|
|
||||||
{
|
|
||||||
uint8_t Header;
|
|
||||||
uint8_t Size;
|
|
||||||
ItemLangEncoding_t LanguageEncodings[];
|
|
||||||
} PROGMEM SerialPort_Attribute_LanguageBaseIDOffset =
|
|
||||||
{
|
|
||||||
(SDP_DATATYPE_Sequence | SDP_DATASIZE_Variable8Bit),
|
|
||||||
(sizeof(ItemLangEncoding_t) * 1),
|
|
||||||
{
|
|
||||||
{
|
|
||||||
{(SDP_DATATYPE_UnsignedInt | SDP_DATASIZE_16Bit), SWAPENDIAN_16(0x454E)},
|
|
||||||
{(SDP_DATATYPE_UnsignedInt | SDP_DATASIZE_16Bit), SWAPENDIAN_16(0x006A)},
|
|
||||||
{(SDP_DATATYPE_UnsignedInt | SDP_DATASIZE_16Bit), SWAPENDIAN_16(0x0100)},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Serial Port Profile attribute, listing a human readable name of the service. */
|
|
||||||
const struct
|
|
||||||
{
|
|
||||||
uint8_t Header;
|
|
||||||
uint8_t Size;
|
|
||||||
char Text[];
|
|
||||||
} PROGMEM SerialPort_Attribute_ServiceName =
|
|
||||||
{
|
|
||||||
(SDP_DATATYPE_String | SDP_DATASIZE_Variable8Bit),
|
|
||||||
sizeof("Wireless Serial Port") - 1,
|
|
||||||
"Wireless Serial Port",
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Serial Port Profile attribute, listing a human readable description of the service. */
|
|
||||||
const struct
|
|
||||||
{
|
|
||||||
uint8_t Header;
|
|
||||||
uint8_t Size;
|
|
||||||
char Text[];
|
|
||||||
} PROGMEM SerialPort_Attribute_ServiceDescription =
|
|
||||||
{
|
|
||||||
(SDP_DATATYPE_String | SDP_DATASIZE_Variable8Bit),
|
|
||||||
sizeof("Wireless Serial Port Service") - 1,
|
|
||||||
"Wireless Serial Port Service",
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Service Attribute Table for the Serial Port service, linking each supported attribute ID to its data, so that
|
|
||||||
* the SDP server can retrieve it for transmission back to a SDP client upon request.
|
|
||||||
*/
|
|
||||||
const ServiceAttributeTable_t PROGMEM SerialPort_Attribute_Table[] =
|
|
||||||
{
|
|
||||||
{.AttributeID = SDP_ATTRIBUTE_ID_SERVICERECORDHANDLE, .Data = &SerialPort_Attribute_ServiceHandle },
|
|
||||||
{.AttributeID = SDP_ATTRIBUTE_ID_SERVICECLASSIDS, .Data = &SerialPort_Attribute_ServiceClassIDs },
|
|
||||||
{.AttributeID = SDP_ATTRIBUTE_ID_PROTOCOLDESCRIPTORLIST, .Data = &SerialPort_Attribute_ProtocolDescriptor },
|
|
||||||
{.AttributeID = SDP_ATTRIBUTE_ID_BROWSEGROUPLIST, .Data = &SerialPort_Attribute_BrowseGroupList },
|
|
||||||
{.AttributeID = SDP_ATTRIBUTE_ID_LANGUAGEBASEATTROFFSET, .Data = &SerialPort_Attribute_LanguageBaseIDOffset},
|
|
||||||
{.AttributeID = SDP_ATTRIBUTE_ID_SERVICENAME, .Data = &SerialPort_Attribute_ServiceName },
|
|
||||||
{.AttributeID = SDP_ATTRIBUTE_ID_SERVICEDESCRIPTION, .Data = &SerialPort_Attribute_ServiceDescription },
|
|
||||||
|
|
||||||
SERVICE_ATTRIBUTE_TABLE_TERMINATOR
|
|
||||||
};
|
|
||||||
|
|
@ -1,174 +0,0 @@
|
|||||||
/*
|
|
||||||
LUFA Library
|
|
||||||
Copyright (C) Dean Camera, 2012.
|
|
||||||
|
|
||||||
dean [at] fourwalledcubicle [dot] com
|
|
||||||
www.lufa-lib.org
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright 2012 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
|
||||||
|
|
||||||
Permission to use, copy, modify, distribute, and sell this
|
|
||||||
software and its documentation for any purpose is hereby granted
|
|
||||||
without fee, provided that the above copyright notice appear in
|
|
||||||
all copies and that both that the copyright notice and this
|
|
||||||
permission notice and warranty disclaimer appear in supporting
|
|
||||||
documentation, and that the name of the author not be used in
|
|
||||||
advertising or publicity pertaining to distribution of the
|
|
||||||
software without specific, written prior permission.
|
|
||||||
|
|
||||||
The author disclaim all warranties with regard to this
|
|
||||||
software, including all implied warranties of merchantability
|
|
||||||
and fitness. In no event shall the author be liable for any
|
|
||||||
special, indirect or consequential damages or any damages
|
|
||||||
whatsoever resulting from loss of use, data or profits, whether
|
|
||||||
in an action of contract, negligence or other tortious action,
|
|
||||||
arising out of or in connection with the use or performance of
|
|
||||||
this software.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** \file
|
|
||||||
*
|
|
||||||
* Header file for SDPServices.c.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _SDPSERVICES_H_
|
|
||||||
#define _SDPSERVICES_H_
|
|
||||||
|
|
||||||
/* Includes: */
|
|
||||||
#include "SDP.h"
|
|
||||||
|
|
||||||
/* Macros: */
|
|
||||||
/** Size of a full 128 bit UUID, in bytes. */
|
|
||||||
#define UUID_SIZE_BYTES 16
|
|
||||||
|
|
||||||
/** First 80 bits common to all standardized Bluetooth services. */
|
|
||||||
#define BASE_80BIT_UUID 0x0000, 0x0010, 0x0080, {0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB}
|
|
||||||
|
|
||||||
#define RFCOMM_UUID {SWAPENDIAN_32(0x00000003), BASE_80BIT_UUID}
|
|
||||||
#define L2CAP_UUID {SWAPENDIAN_32(0x00000100), BASE_80BIT_UUID}
|
|
||||||
#define SP_CLASS_UUID {SWAPENDIAN_32(0x00001101), BASE_80BIT_UUID}
|
|
||||||
#define PUBLICBROWSEGROUP_CLASS_UUID {SWAPENDIAN_32(0x00001002), BASE_80BIT_UUID}
|
|
||||||
|
|
||||||
#define SDP_ATTRIBUTE_ID_SERVICERECORDHANDLE 0x0000
|
|
||||||
#define SDP_ATTRIBUTE_ID_SERVICECLASSIDS 0x0001
|
|
||||||
#define SDP_ATTRIBUTE_ID_PROTOCOLDESCRIPTORLIST 0x0004
|
|
||||||
#define SDP_ATTRIBUTE_ID_BROWSEGROUPLIST 0x0005
|
|
||||||
#define SDP_ATTRIBUTE_ID_LANGUAGEBASEATTROFFSET 0x0006
|
|
||||||
#define SDP_ATTRIBUTE_ID_SERVICENAME 0x0100
|
|
||||||
#define SDP_ATTRIBUTE_ID_SERVICEDESCRIPTION 0x0101
|
|
||||||
|
|
||||||
/** Terminator for a service attribute table of type \ref ServiceAttributeTable_t. */
|
|
||||||
#define SERVICE_ATTRIBUTE_TABLE_TERMINATOR {.Data = NULL}
|
|
||||||
|
|
||||||
/* Type Defines: */
|
|
||||||
/** Type define for a UUID value structure. This struct can be used to hold full 128-bit UUIDs. */
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint32_t A; /**< Bits 0-31 of the UUID. */
|
|
||||||
uint16_t B; /**< Bits 32-47 of the UUID. */
|
|
||||||
uint16_t C; /**< Bits 48-63 of the UUID. */
|
|
||||||
uint16_t D; /**< Bits 64-79 of the UUID. */
|
|
||||||
uint8_t E[6]; /**< Bits 80-127 of the UUID. */
|
|
||||||
} UUID_t;
|
|
||||||
|
|
||||||
/** Structure for the association of attribute ID values to an attribute value in FLASH. A table of these
|
|
||||||
* structures can then be built up for each supported UUID service within the device.
|
|
||||||
*
|
|
||||||
* \attention This table must be terminated with a \ref SERVICE_ATTRIBUTE_TABLE_TERMINATOR element.
|
|
||||||
*/
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint16_t AttributeID; /**< Attribute ID of the table element which the UUID service supports */
|
|
||||||
const void* Data; /**< Pointer to the attribute data, located in PROGMEM memory space */
|
|
||||||
} ServiceAttributeTable_t;
|
|
||||||
|
|
||||||
/** Structure for a list of Data Elements containing 8-bit integers, for service attributes requiring such lists. */
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint8_t Header; /**< Data Element header, should be (SDP_DATATYPE_UnsignedInt | SDP_DATASIZE_8Bit) */
|
|
||||||
uint8_t Value; /**< Value to store in the list Data Element */
|
|
||||||
} Item8Bit_t;
|
|
||||||
|
|
||||||
/** Structure for a list of Data Elements containing 16-bit integers, for service attributes requiring such lists. */
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint8_t Header; /**< Data Element header, should be (SDP_DATATYPE_UnsignedInt | SDP_DATASIZE_16Bit) */
|
|
||||||
uint16_t Value; /**< Value to store in the list Data Element */
|
|
||||||
} Item16Bit_t;
|
|
||||||
|
|
||||||
/** Structure for a list of Data Elements containing 32-bit integers, for service attributes requiring such lists. */
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint8_t Header; /**< Data Element header, should be (SDP_DATATYPE_UnsignedInt | SDP_DATASIZE_32Bit) */
|
|
||||||
uint32_t Value; /**< Value to store in the list Data Element */
|
|
||||||
} Item32Bit_t;
|
|
||||||
|
|
||||||
/** Structure for a list of Data Elements containing UUIDs, for service attributes requiring UUID lists. */
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint8_t Header; /**< Data Element header, should be (SDP_DATATYPE_UUID | SDP_DATASIZE_128Bit) */
|
|
||||||
UUID_t UUID; /**< UUID to store in the list Data Element */
|
|
||||||
} ItemUUID_t;
|
|
||||||
|
|
||||||
/** Structure for a list of Data Elements Sequences containing UUID Data Elements, for service attributes requiring
|
|
||||||
* protocol lists.
|
|
||||||
*/
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint8_t Header; /**< Data Element header, should be (SDP_DATATYPE_Sequence | SDP_DATASIZE_Variable8Bit) */
|
|
||||||
uint8_t Size; /**< Size of the inner Data Element sequence */
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
ItemUUID_t UUID; /**< UUID to store in the protocol list Data Element sequence */
|
|
||||||
} Protocol;
|
|
||||||
} ItemProtocol_t;
|
|
||||||
|
|
||||||
/** Structure for a list of Data Elements Sequences containing UUID Data Elements and an 8-bit param value, for service
|
|
||||||
* attributes requiring extended protocol lists containing an 8-bit value.
|
|
||||||
*/
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint8_t Header; /**< Data Element header, should be (SDP_DATATYPE_Sequence | SDP_DATASIZE_Variable8Bit) */
|
|
||||||
uint8_t Size; /**< Size of the inner Data Element sequence */
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
ItemUUID_t UUID; /**< UUID to store in the protocol list Data Element sequence */
|
|
||||||
Item8Bit_t Param; /**< 8-Bit Parameter associated with the service */
|
|
||||||
} Protocol;
|
|
||||||
} ItemProtocol_8BitParam_t;
|
|
||||||
|
|
||||||
/** Structure for a list of Data Elements Sequences containing UUID Data Elements and an 16-bit param value, for service
|
|
||||||
* attributes requiring extended protocol lists containing an 16-bit value.
|
|
||||||
*/
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint8_t Header; /**< Data Element header, should be (SDP_DATATYPE_Sequence | SDP_DATASIZE_Variable8Bit) */
|
|
||||||
uint8_t Size; /**< Size of the inner Data Element sequence */
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
ItemUUID_t UUID; /**< UUID to store in the protocol list Data Element sequence */
|
|
||||||
Item16Bit_t Channel; /**< 16-Bit Parameter associated with the service */
|
|
||||||
} Protocol;
|
|
||||||
} ItemProtocol_16BitParam_t;
|
|
||||||
|
|
||||||
/** Structure for a list of Data Elements containing language encodings, including the language ID, Encoding ID and
|
|
||||||
* Attribute base offset.
|
|
||||||
*/
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
Item16Bit_t LanguageID; /**< Language ID for the current language */
|
|
||||||
Item16Bit_t EncodingID; /**< Encoding used for the current language */
|
|
||||||
Item16Bit_t OffsetID; /**< Attribute offset added to all strings using this language within the service */
|
|
||||||
} ItemLangEncoding_t;
|
|
||||||
|
|
||||||
/* External Variables: */
|
|
||||||
extern const ServiceAttributeTable_t SerialPort_Attribute_Table[];
|
|
||||||
extern const ServiceAttributeTable_t PnP_Attribute_Table[];
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,733 +0,0 @@
|
|||||||
# Hey Emacs, this is a -*- makefile -*-
|
|
||||||
#----------------------------------------------------------------------------
|
|
||||||
# WinAVR Makefile Template written by Eric B. Weddington, Jörg Wunsch, et al.
|
|
||||||
# >> Modified for use with the LUFA project. <<
|
|
||||||
#
|
|
||||||
# Released to the Public Domain
|
|
||||||
#
|
|
||||||
# Additional material for this makefile was written by:
|
|
||||||
# Peter Fleury
|
|
||||||
# Tim Henigan
|
|
||||||
# Colin O'Flynn
|
|
||||||
# Reiner Patommel
|
|
||||||
# Markus Pfaff
|
|
||||||
# Sander Pool
|
|
||||||
# Frederik Rouleau
|
|
||||||
# Carlos Lamas
|
|
||||||
# Dean Camera
|
|
||||||
# Opendous Inc.
|
|
||||||
# Denver Gingerich
|
|
||||||
#
|
|
||||||
#----------------------------------------------------------------------------
|
|
||||||
# On command line:
|
|
||||||
#
|
|
||||||
# make all = Make software.
|
|
||||||
#
|
|
||||||
# make clean = Clean out built project files.
|
|
||||||
#
|
|
||||||
# make coff = Convert ELF to AVR COFF.
|
|
||||||
#
|
|
||||||
# make extcoff = Convert ELF to AVR Extended COFF.
|
|
||||||
#
|
|
||||||
# make program = Download the hex file to the device, using avrdude.
|
|
||||||
# Please customize the avrdude settings below first!
|
|
||||||
#
|
|
||||||
# make dfu = Download the hex file to the device, using dfu-programmer (must
|
|
||||||
# have dfu-programmer installed).
|
|
||||||
#
|
|
||||||
# make flip = Download the hex file to the device, using Atmel FLIP (must
|
|
||||||
# have Atmel FLIP installed).
|
|
||||||
#
|
|
||||||
# make dfu-ee = Download the eeprom file to the device, using dfu-programmer
|
|
||||||
# (must have dfu-programmer installed).
|
|
||||||
#
|
|
||||||
# make flip-ee = Download the eeprom file to the device, using Atmel FLIP
|
|
||||||
# (must have Atmel FLIP installed).
|
|
||||||
#
|
|
||||||
# make doxygen = Generate DoxyGen documentation for the project (must have
|
|
||||||
# DoxyGen installed)
|
|
||||||
#
|
|
||||||
# make debug = Start either simulavr or avarice as specified for debugging,
|
|
||||||
# with avr-gdb or avr-insight as the front end for debugging.
|
|
||||||
#
|
|
||||||
# make filename.s = Just compile filename.c into the assembler code only.
|
|
||||||
#
|
|
||||||
# make filename.i = Create a preprocessed source file for use in submitting
|
|
||||||
# bug reports to the GCC project.
|
|
||||||
#
|
|
||||||
# To rebuild project do "make clean" then "make all".
|
|
||||||
#----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
# MCU name
|
|
||||||
MCU = at90usb1287
|
|
||||||
|
|
||||||
|
|
||||||
# Target architecture (see library "Board Types" documentation).
|
|
||||||
ARCH = AVR8
|
|
||||||
|
|
||||||
|
|
||||||
# Target board (see library "Board Types" documentation, NONE for projects not requiring
|
|
||||||
# LUFA board drivers). If USER is selected, put custom board drivers in a directory called
|
|
||||||
# "Board" inside the application directory.
|
|
||||||
BOARD = USBKEY
|
|
||||||
|
|
||||||
|
|
||||||
# Processor frequency.
|
|
||||||
# This will define a symbol, F_CPU, in all source code files equal to the
|
|
||||||
# processor frequency in Hz. You can then use this symbol in your source code to
|
|
||||||
# calculate timings. Do NOT tack on a 'UL' at the end, this will be done
|
|
||||||
# automatically to create a 32-bit value in your source code.
|
|
||||||
#
|
|
||||||
# This will be an integer division of F_USB below, as it is sourced by
|
|
||||||
# F_USB after it has run through any CPU prescalers. Note that this value
|
|
||||||
# does not *change* the processor frequency - it should merely be updated to
|
|
||||||
# reflect the processor speed set externally so that the code can use accurate
|
|
||||||
# software delays.
|
|
||||||
F_CPU = 8000000
|
|
||||||
|
|
||||||
|
|
||||||
# Input clock frequency.
|
|
||||||
# This will define a symbol, F_USB, in all source code files equal to the
|
|
||||||
# input clock frequency (before any prescaling is performed) in Hz. This value may
|
|
||||||
# differ from F_CPU if prescaling is used on the latter, and is required as the
|
|
||||||
# raw input clock is fed directly to the PLL sections of the AVR for high speed
|
|
||||||
# clock generation for the USB and other AVR subsections. Do NOT tack on a 'UL'
|
|
||||||
# at the end, this will be done automatically to create a 32-bit value in your
|
|
||||||
# source code.
|
|
||||||
#
|
|
||||||
# If no clock division is performed on the input clock inside the AVR (via the
|
|
||||||
# CPU clock adjust registers or the clock division fuses), this will be equal to F_CPU.
|
|
||||||
F_USB = $(F_CPU)
|
|
||||||
|
|
||||||
|
|
||||||
# Output format. (can be srec, ihex, binary)
|
|
||||||
FORMAT = ihex
|
|
||||||
|
|
||||||
|
|
||||||
# Target file name (without extension).
|
|
||||||
TARGET = BluetoothHost
|
|
||||||
|
|
||||||
|
|
||||||
# Object files directory
|
|
||||||
# To put object files in current directory, use a dot (.), do NOT make
|
|
||||||
# this an empty or blank macro!
|
|
||||||
OBJDIR = .
|
|
||||||
|
|
||||||
|
|
||||||
# Path to the LUFA library
|
|
||||||
LUFA_PATH = ../../../..
|
|
||||||
|
|
||||||
|
|
||||||
# LUFA library compile-time options and predefined tokens
|
|
||||||
LUFA_OPTS = -D USB_HOST_ONLY
|
|
||||||
LUFA_OPTS += -D USE_STATIC_OPTIONS="(USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)"
|
|
||||||
|
|
||||||
|
|
||||||
# Create the LUFA source path variables by including the LUFA root makefile
|
|
||||||
include $(LUFA_PATH)/LUFA/makefile
|
|
||||||
|
|
||||||
|
|
||||||
# List C source files here. (C dependencies are automatically generated.)
|
|
||||||
SRC = $(TARGET).c \
|
|
||||||
BluetoothEvents.c \
|
|
||||||
DeviceDescriptor.c \
|
|
||||||
ConfigDescriptor.c \
|
|
||||||
Lib/BluetoothStack.c \
|
|
||||||
Lib/BluetoothHCICommands.c \
|
|
||||||
Lib/BluetoothACLPackets.c \
|
|
||||||
Lib/SDP.c \
|
|
||||||
Lib/SDPServices.c \
|
|
||||||
Lib/RFCOMM.c \
|
|
||||||
Lib/RFCOMMControl.c \
|
|
||||||
$(LUFA_SRC_USB) \
|
|
||||||
$(LUFA_SRC_SERIAL)
|
|
||||||
|
|
||||||
|
|
||||||
# List C++ source files here. (C dependencies are automatically generated.)
|
|
||||||
CPPSRC =
|
|
||||||
|
|
||||||
|
|
||||||
# List Assembler source files here.
|
|
||||||
# Make them always end in a capital .S. Files ending in a lowercase .s
|
|
||||||
# will not be considered source files but generated files (assembler
|
|
||||||
# output from the compiler), and will be deleted upon "make clean"!
|
|
||||||
# Even though the DOS/Win* filesystem matches both .s and .S the same,
|
|
||||||
# it will preserve the spelling of the filenames, and gcc itself does
|
|
||||||
# care about how the name is spelled on its command-line.
|
|
||||||
ASRC =
|
|
||||||
|
|
||||||
|
|
||||||
# Optimization level, can be [0, 1, 2, 3, s].
|
|
||||||
# 0 = turn off optimization. s = optimize for size.
|
|
||||||
# (Note: 3 is not always the best optimization level. See avr-libc FAQ.)
|
|
||||||
OPT = s
|
|
||||||
|
|
||||||
|
|
||||||
# Debugging format.
|
|
||||||
# Native formats for AVR-GCC's -g are dwarf-2 [default] or stabs.
|
|
||||||
# AVR Studio 4.10 requires dwarf-2.
|
|
||||||
# AVR [Extended] COFF format requires stabs, plus an avr-objcopy run.
|
|
||||||
DEBUG = dwarf-2
|
|
||||||
|
|
||||||
|
|
||||||
# List any extra directories to look for include files here.
|
|
||||||
# Each directory must be seperated by a space.
|
|
||||||
# Use forward slashes for directory separators.
|
|
||||||
# For a directory that has spaces, enclose it in quotes.
|
|
||||||
EXTRAINCDIRS = $(LUFA_PATH)/
|
|
||||||
|
|
||||||
|
|
||||||
# Compiler flag to set the C Standard level.
|
|
||||||
# c89 = "ANSI" C
|
|
||||||
# gnu89 = c89 plus GCC extensions
|
|
||||||
# c99 = ISO C99 standard (not yet fully implemented)
|
|
||||||
# gnu99 = c99 plus GCC extensions
|
|
||||||
CSTANDARD = -std=c99
|
|
||||||
|
|
||||||
|
|
||||||
# Place -D or -U options here for C sources
|
|
||||||
CDEFS = -DF_CPU=$(F_CPU)UL
|
|
||||||
CDEFS += -DF_USB=$(F_USB)UL
|
|
||||||
CDEFS += -DBOARD=BOARD_$(BOARD) -DARCH=ARCH_$(ARCH)
|
|
||||||
CDEFS += $(LUFA_OPTS)
|
|
||||||
|
|
||||||
|
|
||||||
# Place -D or -U options here for ASM sources
|
|
||||||
ADEFS = -DF_CPU=$(F_CPU)
|
|
||||||
ADEFS += -DF_USB=$(F_USB)UL
|
|
||||||
ADEFS += -DBOARD=BOARD_$(BOARD)
|
|
||||||
ADEFS += $(LUFA_OPTS)
|
|
||||||
|
|
||||||
# Place -D or -U options here for C++ sources
|
|
||||||
CPPDEFS = -DF_CPU=$(F_CPU)UL
|
|
||||||
CPPDEFS += -DF_USB=$(F_USB)UL
|
|
||||||
CPPDEFS += -DBOARD=BOARD_$(BOARD)
|
|
||||||
CPPDEFS += $(LUFA_OPTS)
|
|
||||||
#CPPDEFS += -D__STDC_LIMIT_MACROS
|
|
||||||
#CPPDEFS += -D__STDC_CONSTANT_MACROS
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#---------------- Compiler Options C ----------------
|
|
||||||
# -g*: generate debugging information
|
|
||||||
# -O*: optimization level
|
|
||||||
# -f...: tuning, see GCC manual and avr-libc documentation
|
|
||||||
# -Wall...: warning level
|
|
||||||
# -Wa,...: tell GCC to pass this to the assembler.
|
|
||||||
# -adhlns...: create assembler listing
|
|
||||||
CFLAGS = -g$(DEBUG)
|
|
||||||
CFLAGS += $(CDEFS)
|
|
||||||
CFLAGS += -O$(OPT)
|
|
||||||
CFLAGS += -funsigned-char
|
|
||||||
CFLAGS += -funsigned-bitfields
|
|
||||||
CFLAGS += -ffunction-sections
|
|
||||||
CFLAGS += -fno-inline-small-functions
|
|
||||||
CFLAGS += -fpack-struct
|
|
||||||
CFLAGS += -fshort-enums
|
|
||||||
CFLAGS += -fno-strict-aliasing
|
|
||||||
CFLAGS += -Wall
|
|
||||||
CFLAGS += -Wstrict-prototypes
|
|
||||||
#CFLAGS += -mshort-calls
|
|
||||||
#CFLAGS += -fno-unit-at-a-time
|
|
||||||
#CFLAGS += -Wundef
|
|
||||||
#CFLAGS += -Wunreachable-code
|
|
||||||
#CFLAGS += -Wsign-compare
|
|
||||||
CFLAGS += -Wa,-adhlns=$(<:%.c=$(OBJDIR)/%.lst)
|
|
||||||
CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS))
|
|
||||||
CFLAGS += $(CSTANDARD)
|
|
||||||
|
|
||||||
|
|
||||||
#---------------- Compiler Options C++ ----------------
|
|
||||||
# -g*: generate debugging information
|
|
||||||
# -O*: optimization level
|
|
||||||
# -f...: tuning, see GCC manual and avr-libc documentation
|
|
||||||
# -Wall...: warning level
|
|
||||||
# -Wa,...: tell GCC to pass this to the assembler.
|
|
||||||
# -adhlns...: create assembler listing
|
|
||||||
CPPFLAGS = -g$(DEBUG)
|
|
||||||
CPPFLAGS += $(CPPDEFS)
|
|
||||||
CPPFLAGS += -O$(OPT)
|
|
||||||
CPPFLAGS += -funsigned-char
|
|
||||||
CPPFLAGS += -funsigned-bitfields
|
|
||||||
CPPFLAGS += -fpack-struct
|
|
||||||
CPPFLAGS += -fshort-enums
|
|
||||||
CPPFLAGS += -fno-exceptions
|
|
||||||
CPPFLAGS += -Wall
|
|
||||||
CPPFLAGS += -Wundef
|
|
||||||
#CPPFLAGS += -mshort-calls
|
|
||||||
#CPPFLAGS += -fno-unit-at-a-time
|
|
||||||
#CPPFLAGS += -Wstrict-prototypes
|
|
||||||
#CPPFLAGS += -Wunreachable-code
|
|
||||||
#CPPFLAGS += -Wsign-compare
|
|
||||||
CPPFLAGS += -Wa,-adhlns=$(<:%.cpp=$(OBJDIR)/%.lst)
|
|
||||||
CPPFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS))
|
|
||||||
#CPPFLAGS += $(CSTANDARD)
|
|
||||||
|
|
||||||
|
|
||||||
#---------------- Assembler Options ----------------
|
|
||||||
# -Wa,...: tell GCC to pass this to the assembler.
|
|
||||||
# -adhlns: create listing
|
|
||||||
# -gstabs: have the assembler create line number information; note that
|
|
||||||
# for use in COFF files, additional information about filenames
|
|
||||||
# and function names needs to be present in the assembler source
|
|
||||||
# files -- see avr-libc docs [FIXME: not yet described there]
|
|
||||||
# -listing-cont-lines: Sets the maximum number of continuation lines of hex
|
|
||||||
# dump that will be displayed for a given single line of source input.
|
|
||||||
ASFLAGS = $(ADEFS) -Wa,-adhlns=$(<:%.S=$(OBJDIR)/%.lst),-gstabs,--listing-cont-lines=100
|
|
||||||
|
|
||||||
|
|
||||||
#---------------- Library Options ----------------
|
|
||||||
# Minimalistic printf version
|
|
||||||
PRINTF_LIB_MIN = -Wl,-u,vfprintf -lprintf_min
|
|
||||||
|
|
||||||
# Floating point printf version (requires MATH_LIB = -lm below)
|
|
||||||
PRINTF_LIB_FLOAT = -Wl,-u,vfprintf -lprintf_flt
|
|
||||||
|
|
||||||
# If this is left blank, then it will use the Standard printf version.
|
|
||||||
PRINTF_LIB =
|
|
||||||
#PRINTF_LIB = $(PRINTF_LIB_MIN)
|
|
||||||
#PRINTF_LIB = $(PRINTF_LIB_FLOAT)
|
|
||||||
|
|
||||||
|
|
||||||
# Minimalistic scanf version
|
|
||||||
SCANF_LIB_MIN = -Wl,-u,vfscanf -lscanf_min
|
|
||||||
|
|
||||||
# Floating point + %[ scanf version (requires MATH_LIB = -lm below)
|
|
||||||
SCANF_LIB_FLOAT = -Wl,-u,vfscanf -lscanf_flt
|
|
||||||
|
|
||||||
# If this is left blank, then it will use the Standard scanf version.
|
|
||||||
SCANF_LIB =
|
|
||||||
#SCANF_LIB = $(SCANF_LIB_MIN)
|
|
||||||
#SCANF_LIB = $(SCANF_LIB_FLOAT)
|
|
||||||
|
|
||||||
|
|
||||||
MATH_LIB = -lm
|
|
||||||
|
|
||||||
|
|
||||||
# List any extra directories to look for libraries here.
|
|
||||||
# Each directory must be seperated by a space.
|
|
||||||
# Use forward slashes for directory separators.
|
|
||||||
# For a directory that has spaces, enclose it in quotes.
|
|
||||||
EXTRALIBDIRS =
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#---------------- External Memory Options ----------------
|
|
||||||
|
|
||||||
# 64 KB of external RAM, starting after internal RAM (ATmega128!),
|
|
||||||
# used for variables (.data/.bss) and heap (malloc()).
|
|
||||||
#EXTMEMOPTS = -Wl,-Tdata=0x801100,--defsym=__heap_end=0x80ffff
|
|
||||||
|
|
||||||
# 64 KB of external RAM, starting after internal RAM (ATmega128!),
|
|
||||||
# only used for heap (malloc()).
|
|
||||||
#EXTMEMOPTS = -Wl,--section-start,.data=0x801100,--defsym=__heap_end=0x80ffff
|
|
||||||
|
|
||||||
EXTMEMOPTS =
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#---------------- Linker Options ----------------
|
|
||||||
# -Wl,...: tell GCC to pass this to linker.
|
|
||||||
# -Map: create map file
|
|
||||||
# --cref: add cross reference to map file
|
|
||||||
LDFLAGS = -Wl,-Map=$(TARGET).map,--cref
|
|
||||||
LDFLAGS += -Wl,--relax
|
|
||||||
LDFLAGS += -Wl,--gc-sections
|
|
||||||
LDFLAGS += $(EXTMEMOPTS)
|
|
||||||
LDFLAGS += $(patsubst %,-L%,$(EXTRALIBDIRS))
|
|
||||||
LDFLAGS += $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB)
|
|
||||||
#LDFLAGS += -T linker_script.x
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#---------------- Programming Options (avrdude) ----------------
|
|
||||||
|
|
||||||
# Programming hardware
|
|
||||||
# Type: avrdude -c ?
|
|
||||||
# to get a full listing.
|
|
||||||
#
|
|
||||||
AVRDUDE_PROGRAMMER = jtagmkII
|
|
||||||
|
|
||||||
# com1 = serial port. Use lpt1 to connect to parallel port.
|
|
||||||
AVRDUDE_PORT = usb
|
|
||||||
|
|
||||||
AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex
|
|
||||||
#AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep
|
|
||||||
|
|
||||||
|
|
||||||
# Uncomment the following if you want avrdude's erase cycle counter.
|
|
||||||
# Note that this counter needs to be initialized first using -Yn,
|
|
||||||
# see avrdude manual.
|
|
||||||
#AVRDUDE_ERASE_COUNTER = -y
|
|
||||||
|
|
||||||
# Uncomment the following if you do /not/ wish a verification to be
|
|
||||||
# performed after programming the device.
|
|
||||||
#AVRDUDE_NO_VERIFY = -V
|
|
||||||
|
|
||||||
# Increase verbosity level. Please use this when submitting bug
|
|
||||||
# reports about avrdude. See <http://savannah.nongnu.org/projects/avrdude>
|
|
||||||
# to submit bug reports.
|
|
||||||
#AVRDUDE_VERBOSE = -v -v
|
|
||||||
|
|
||||||
AVRDUDE_FLAGS = -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER)
|
|
||||||
AVRDUDE_FLAGS += $(AVRDUDE_NO_VERIFY)
|
|
||||||
AVRDUDE_FLAGS += $(AVRDUDE_VERBOSE)
|
|
||||||
AVRDUDE_FLAGS += $(AVRDUDE_ERASE_COUNTER)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#---------------- Debugging Options ----------------
|
|
||||||
|
|
||||||
# For simulavr only - target MCU frequency.
|
|
||||||
DEBUG_MFREQ = $(F_CPU)
|
|
||||||
|
|
||||||
# Set the DEBUG_UI to either gdb or insight.
|
|
||||||
# DEBUG_UI = gdb
|
|
||||||
DEBUG_UI = insight
|
|
||||||
|
|
||||||
# Set the debugging back-end to either avarice, simulavr.
|
|
||||||
DEBUG_BACKEND = avarice
|
|
||||||
#DEBUG_BACKEND = simulavr
|
|
||||||
|
|
||||||
# GDB Init Filename.
|
|
||||||
GDBINIT_FILE = __avr_gdbinit
|
|
||||||
|
|
||||||
# When using avarice settings for the JTAG
|
|
||||||
JTAG_DEV = /dev/com1
|
|
||||||
|
|
||||||
# Debugging port used to communicate between GDB / avarice / simulavr.
|
|
||||||
DEBUG_PORT = 4242
|
|
||||||
|
|
||||||
# Debugging host used to communicate between GDB / avarice / simulavr, normally
|
|
||||||
# just set to localhost unless doing some sort of crazy debugging when
|
|
||||||
# avarice is running on a different computer.
|
|
||||||
DEBUG_HOST = localhost
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#============================================================================
|
|
||||||
|
|
||||||
|
|
||||||
# Define programs and commands.
|
|
||||||
SHELL = sh
|
|
||||||
CC = avr-gcc
|
|
||||||
OBJCOPY = avr-objcopy
|
|
||||||
OBJDUMP = avr-objdump
|
|
||||||
SIZE = avr-size
|
|
||||||
AR = avr-ar rcs
|
|
||||||
NM = avr-nm
|
|
||||||
AVRDUDE = avrdude
|
|
||||||
REMOVE = rm -f
|
|
||||||
REMOVEDIR = rm -rf
|
|
||||||
COPY = cp
|
|
||||||
WINSHELL = cmd
|
|
||||||
|
|
||||||
|
|
||||||
# Define Messages
|
|
||||||
# English
|
|
||||||
MSG_ERRORS_NONE = Errors: none
|
|
||||||
MSG_BEGIN = -------- begin --------
|
|
||||||
MSG_END = -------- end --------
|
|
||||||
MSG_SIZE_BEFORE = Size before:
|
|
||||||
MSG_SIZE_AFTER = Size after:
|
|
||||||
MSG_COFF = Converting to AVR COFF:
|
|
||||||
MSG_EXTENDED_COFF = Converting to AVR Extended COFF:
|
|
||||||
MSG_FLASH = Creating load file for Flash:
|
|
||||||
MSG_EEPROM = Creating load file for EEPROM:
|
|
||||||
MSG_EXTENDED_LISTING = Creating Extended Listing:
|
|
||||||
MSG_SYMBOL_TABLE = Creating Symbol Table:
|
|
||||||
MSG_LINKING = Linking:
|
|
||||||
MSG_COMPILING = Compiling C:
|
|
||||||
MSG_COMPILING_CPP = Compiling C++:
|
|
||||||
MSG_ASSEMBLING = Assembling:
|
|
||||||
MSG_CLEANING = Cleaning project:
|
|
||||||
MSG_CREATING_LIBRARY = Creating library:
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Define all object files.
|
|
||||||
OBJ = $(SRC:%.c=$(OBJDIR)/%.o) $(CPPSRC:%.cpp=$(OBJDIR)/%.o) $(ASRC:%.S=$(OBJDIR)/%.o)
|
|
||||||
|
|
||||||
# Define all listing files.
|
|
||||||
LST = $(SRC:%.c=$(OBJDIR)/%.lst) $(CPPSRC:%.cpp=$(OBJDIR)/%.lst) $(ASRC:%.S=$(OBJDIR)/%.lst)
|
|
||||||
|
|
||||||
|
|
||||||
# Compiler flags to generate dependency files.
|
|
||||||
GENDEPFLAGS = -MMD -MP -MF .dep/$(@F).d
|
|
||||||
|
|
||||||
|
|
||||||
# Combine all necessary flags and optional flags.
|
|
||||||
# Add target processor to flags.
|
|
||||||
ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) $(GENDEPFLAGS)
|
|
||||||
ALL_CPPFLAGS = -mmcu=$(MCU) -I. -x c++ $(CPPFLAGS) $(GENDEPFLAGS)
|
|
||||||
ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Default target.
|
|
||||||
all: begin gccversion sizebefore build sizeafter end
|
|
||||||
|
|
||||||
# Change the build target to build a HEX file or a library.
|
|
||||||
build: elf hex eep lss sym
|
|
||||||
#build: lib
|
|
||||||
|
|
||||||
|
|
||||||
elf: $(TARGET).elf
|
|
||||||
hex: $(TARGET).hex
|
|
||||||
eep: $(TARGET).eep
|
|
||||||
lss: $(TARGET).lss
|
|
||||||
sym: $(TARGET).sym
|
|
||||||
LIBNAME=lib$(TARGET).a
|
|
||||||
lib: $(LIBNAME)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Eye candy.
|
|
||||||
# AVR Studio 3.x does not check make's exit code but relies on
|
|
||||||
# the following magic strings to be generated by the compile job.
|
|
||||||
begin:
|
|
||||||
@echo
|
|
||||||
@echo $(MSG_BEGIN)
|
|
||||||
|
|
||||||
end:
|
|
||||||
@echo $(MSG_END)
|
|
||||||
@echo
|
|
||||||
|
|
||||||
|
|
||||||
# Display size of file.
|
|
||||||
HEXSIZE = $(SIZE) --target=$(FORMAT) $(TARGET).hex
|
|
||||||
ELFSIZE = $(SIZE) $(MCU_FLAG) $(FORMAT_FLAG) $(TARGET).elf
|
|
||||||
MCU_FLAG = $(shell $(SIZE) --help | grep -- --mcu > /dev/null && echo --mcu=$(MCU) )
|
|
||||||
FORMAT_FLAG = $(shell $(SIZE) --help | grep -- --format=.*avr > /dev/null && echo --format=avr )
|
|
||||||
|
|
||||||
|
|
||||||
sizebefore:
|
|
||||||
@if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_BEFORE); $(ELFSIZE); \
|
|
||||||
2>/dev/null; echo; fi
|
|
||||||
|
|
||||||
sizeafter:
|
|
||||||
@if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_AFTER); $(ELFSIZE); \
|
|
||||||
2>/dev/null; echo; fi
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Display compiler version information.
|
|
||||||
gccversion :
|
|
||||||
@$(CC) --version
|
|
||||||
|
|
||||||
|
|
||||||
# Program the device.
|
|
||||||
program: $(TARGET).hex $(TARGET).eep
|
|
||||||
$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM)
|
|
||||||
|
|
||||||
flip: $(TARGET).hex
|
|
||||||
batchisp -hardware usb -device $(MCU) -operation erase f
|
|
||||||
batchisp -hardware usb -device $(MCU) -operation loadbuffer $(TARGET).hex program
|
|
||||||
batchisp -hardware usb -device $(MCU) -operation start reset 0
|
|
||||||
|
|
||||||
dfu: $(TARGET).hex
|
|
||||||
dfu-programmer $(MCU) erase
|
|
||||||
dfu-programmer $(MCU) flash $(TARGET).hex
|
|
||||||
dfu-programmer $(MCU) reset
|
|
||||||
|
|
||||||
flip-ee: $(TARGET).hex $(TARGET).eep
|
|
||||||
$(COPY) $(TARGET).eep $(TARGET)eep.hex
|
|
||||||
batchisp -hardware usb -device $(MCU) -operation memory EEPROM erase
|
|
||||||
batchisp -hardware usb -device $(MCU) -operation memory EEPROM loadbuffer $(TARGET)eep.hex program
|
|
||||||
batchisp -hardware usb -device $(MCU) -operation start reset 0
|
|
||||||
$(REMOVE) $(TARGET)eep.hex
|
|
||||||
|
|
||||||
dfu-ee: $(TARGET).hex $(TARGET).eep
|
|
||||||
dfu-programmer $(MCU) eeprom-flash $(TARGET).eep
|
|
||||||
dfu-programmer $(MCU) reset
|
|
||||||
|
|
||||||
|
|
||||||
# Generate avr-gdb config/init file which does the following:
|
|
||||||
# define the reset signal, load the target file, connect to target, and set
|
|
||||||
# a breakpoint at main().
|
|
||||||
gdb-config:
|
|
||||||
@$(REMOVE) $(GDBINIT_FILE)
|
|
||||||
@echo define reset >> $(GDBINIT_FILE)
|
|
||||||
@echo SIGNAL SIGHUP >> $(GDBINIT_FILE)
|
|
||||||
@echo end >> $(GDBINIT_FILE)
|
|
||||||
@echo file $(TARGET).elf >> $(GDBINIT_FILE)
|
|
||||||
@echo target remote $(DEBUG_HOST):$(DEBUG_PORT) >> $(GDBINIT_FILE)
|
|
||||||
ifeq ($(DEBUG_BACKEND),simulavr)
|
|
||||||
@echo load >> $(GDBINIT_FILE)
|
|
||||||
endif
|
|
||||||
@echo break main >> $(GDBINIT_FILE)
|
|
||||||
|
|
||||||
debug: gdb-config $(TARGET).elf
|
|
||||||
ifeq ($(DEBUG_BACKEND), avarice)
|
|
||||||
@echo Starting AVaRICE - Press enter when "waiting to connect" message displays.
|
|
||||||
@$(WINSHELL) /c start avarice --jtag $(JTAG_DEV) --erase --program --file \
|
|
||||||
$(TARGET).elf $(DEBUG_HOST):$(DEBUG_PORT)
|
|
||||||
@$(WINSHELL) /c pause
|
|
||||||
|
|
||||||
else
|
|
||||||
@$(WINSHELL) /c start simulavr --gdbserver --device $(MCU) --clock-freq \
|
|
||||||
$(DEBUG_MFREQ) --port $(DEBUG_PORT)
|
|
||||||
endif
|
|
||||||
@$(WINSHELL) /c start avr-$(DEBUG_UI) --command=$(GDBINIT_FILE)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB.
|
|
||||||
COFFCONVERT = $(OBJCOPY) --debugging
|
|
||||||
COFFCONVERT += --change-section-address .data-0x800000
|
|
||||||
COFFCONVERT += --change-section-address .bss-0x800000
|
|
||||||
COFFCONVERT += --change-section-address .noinit-0x800000
|
|
||||||
COFFCONVERT += --change-section-address .eeprom-0x810000
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
coff: $(TARGET).elf
|
|
||||||
@echo
|
|
||||||
@echo $(MSG_COFF) $(TARGET).cof
|
|
||||||
$(COFFCONVERT) -O coff-avr $< $(TARGET).cof
|
|
||||||
|
|
||||||
|
|
||||||
extcoff: $(TARGET).elf
|
|
||||||
@echo
|
|
||||||
@echo $(MSG_EXTENDED_COFF) $(TARGET).cof
|
|
||||||
$(COFFCONVERT) -O coff-ext-avr $< $(TARGET).cof
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Create final output files (.hex, .eep) from ELF output file.
|
|
||||||
%.hex: %.elf
|
|
||||||
@echo
|
|
||||||
@echo $(MSG_FLASH) $@
|
|
||||||
$(OBJCOPY) -O $(FORMAT) -R .eeprom -R .fuse -R .lock $< $@
|
|
||||||
|
|
||||||
%.eep: %.elf
|
|
||||||
@echo
|
|
||||||
@echo $(MSG_EEPROM) $@
|
|
||||||
-$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \
|
|
||||||
--change-section-lma .eeprom=0 --no-change-warnings -O $(FORMAT) $< $@ || exit 0
|
|
||||||
|
|
||||||
# Create extended listing file from ELF output file.
|
|
||||||
%.lss: %.elf
|
|
||||||
@echo
|
|
||||||
@echo $(MSG_EXTENDED_LISTING) $@
|
|
||||||
$(OBJDUMP) -h -S -z $< > $@
|
|
||||||
|
|
||||||
# Create a symbol table from ELF output file.
|
|
||||||
%.sym: %.elf
|
|
||||||
@echo
|
|
||||||
@echo $(MSG_SYMBOL_TABLE) $@
|
|
||||||
$(NM) -n $< > $@
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Create library from object files.
|
|
||||||
.SECONDARY : $(TARGET).a
|
|
||||||
.PRECIOUS : $(OBJ)
|
|
||||||
%.a: $(OBJ)
|
|
||||||
@echo
|
|
||||||
@echo $(MSG_CREATING_LIBRARY) $@
|
|
||||||
$(AR) $@ $(OBJ)
|
|
||||||
|
|
||||||
|
|
||||||
# Link: create ELF output file from object files.
|
|
||||||
.SECONDARY : $(TARGET).elf
|
|
||||||
.PRECIOUS : $(OBJ)
|
|
||||||
%.elf: $(OBJ)
|
|
||||||
@echo
|
|
||||||
@echo $(MSG_LINKING) $@
|
|
||||||
$(CC) $(ALL_CFLAGS) $^ --output $@ $(LDFLAGS)
|
|
||||||
|
|
||||||
|
|
||||||
# Compile: create object files from C source files.
|
|
||||||
$(OBJDIR)/%.o : %.c
|
|
||||||
@echo
|
|
||||||
@echo $(MSG_COMPILING) $<
|
|
||||||
$(CC) -c $(ALL_CFLAGS) $< -o $@
|
|
||||||
|
|
||||||
|
|
||||||
# Compile: create object files from C++ source files.
|
|
||||||
$(OBJDIR)/%.o : %.cpp
|
|
||||||
@echo
|
|
||||||
@echo $(MSG_COMPILING_CPP) $<
|
|
||||||
$(CC) -c $(ALL_CPPFLAGS) $< -o $@
|
|
||||||
|
|
||||||
|
|
||||||
# Compile: create assembler files from C source files.
|
|
||||||
%.s : %.c
|
|
||||||
$(CC) -S $(ALL_CFLAGS) $< -o $@
|
|
||||||
|
|
||||||
|
|
||||||
# Compile: create assembler files from C++ source files.
|
|
||||||
%.s : %.cpp
|
|
||||||
$(CC) -S $(ALL_CPPFLAGS) $< -o $@
|
|
||||||
|
|
||||||
|
|
||||||
# Assemble: create object files from assembler source files.
|
|
||||||
$(OBJDIR)/%.o : %.S
|
|
||||||
@echo
|
|
||||||
@echo $(MSG_ASSEMBLING) $<
|
|
||||||
$(CC) -c $(ALL_ASFLAGS) $< -o $@
|
|
||||||
|
|
||||||
|
|
||||||
# Create preprocessed source for use in sending a bug report.
|
|
||||||
%.i : %.c
|
|
||||||
$(CC) -E -mmcu=$(MCU) -I. $(CFLAGS) $< -o $@
|
|
||||||
|
|
||||||
|
|
||||||
# Target: clean project.
|
|
||||||
clean: begin clean_list end
|
|
||||||
|
|
||||||
clean_list :
|
|
||||||
@echo
|
|
||||||
@echo $(MSG_CLEANING)
|
|
||||||
$(REMOVE) $(TARGET).hex
|
|
||||||
$(REMOVE) $(TARGET).eep
|
|
||||||
$(REMOVE) $(TARGET).cof
|
|
||||||
$(REMOVE) $(TARGET).elf
|
|
||||||
$(REMOVE) $(TARGET).map
|
|
||||||
$(REMOVE) $(TARGET).sym
|
|
||||||
$(REMOVE) $(TARGET).lss
|
|
||||||
$(REMOVE) $(SRC:%.c=$(OBJDIR)/%.o) $(CPPSRC:%.cpp=$(OBJDIR)/%.o) $(ASRC:%.S=$(OBJDIR)/%.o)
|
|
||||||
$(REMOVE) $(SRC:%.c=$(OBJDIR)/%.lst) $(CPPSRC:%.cpp=$(OBJDIR)/%.lst) $(ASRC:%.S=$(OBJDIR)/%.lst)
|
|
||||||
$(REMOVE) $(SRC:.c=.s)
|
|
||||||
$(REMOVE) $(SRC:.c=.d)
|
|
||||||
$(REMOVE) $(SRC:.c=.i)
|
|
||||||
$(REMOVEDIR) .dep
|
|
||||||
|
|
||||||
doxygen:
|
|
||||||
@echo Generating Project Documentation \($(TARGET)\)...
|
|
||||||
@if ( doxygen Doxygen.conf 2>&1 | grep -v "warning: ignoring unsupported tag" ;); then \
|
|
||||||
exit 1; \
|
|
||||||
fi;
|
|
||||||
@echo Documentation Generation Complete.
|
|
||||||
|
|
||||||
clean_doxygen:
|
|
||||||
rm -rf Documentation
|
|
||||||
|
|
||||||
checksource:
|
|
||||||
@for f in $(SRC) $(CPPSRC) $(ASRC); do \
|
|
||||||
if [ -f $$f ]; then \
|
|
||||||
echo "Found Source File: $$f" ; \
|
|
||||||
else \
|
|
||||||
echo "Source File Not Found: $$f" ; \
|
|
||||||
fi; done
|
|
||||||
|
|
||||||
|
|
||||||
# Create object files directory
|
|
||||||
$(shell mkdir $(OBJDIR) 2>/dev/null)
|
|
||||||
|
|
||||||
|
|
||||||
# Include the dependency files.
|
|
||||||
-include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*)
|
|
||||||
|
|
||||||
|
|
||||||
# Listing of phony targets.
|
|
||||||
.PHONY : all begin finish end sizebefore sizeafter gccversion \
|
|
||||||
build elf hex eep lss sym coff extcoff doxygen clean \
|
|
||||||
clean_list clean_doxygen program dfu flip flip-ee dfu-ee \
|
|
||||||
debug gdb-config checksource
|
|
Loading…
Reference in new issue