Add missing SVN eol-style property to files where it was missing.
This commit is contained in:
parent
a36012fc4b
commit
0c2ad9eb34
105 changed files with 27742 additions and 27742 deletions
File diff suppressed because it is too large
Load diff
|
@ -1,320 +1,320 @@
|
|||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2011.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.lufa-lib.org
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2011 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 HIDReportViewer project. This file contains the main tasks of
|
||||
* the project and is responsible for the initial application hardware configuration.
|
||||
*/
|
||||
|
||||
#include "HIDReportViewer.h"
|
||||
|
||||
/** Processed HID report descriptor items structure, containing information on each HID report element */
|
||||
static HID_ReportInfo_t HIDReportInfo;
|
||||
|
||||
/** LUFA HID Class driver interface configuration and state information. This structure is
|
||||
* passed to all HID Class driver functions, so that multiple instances of the same class
|
||||
* within a device can be differentiated from one another.
|
||||
*/
|
||||
USB_ClassInfo_HID_Host_t Device_HID_Interface =
|
||||
{
|
||||
.Config =
|
||||
{
|
||||
.DataINPipeNumber = 1,
|
||||
.DataINPipeDoubleBank = false,
|
||||
|
||||
.DataOUTPipeNumber = 2,
|
||||
.DataOUTPipeDoubleBank = false,
|
||||
|
||||
.HIDInterfaceProtocol = HID_CSCP_NonBootProtocol,
|
||||
|
||||
.HIDParserData = &HIDReportInfo
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
/** 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 "HID Device Report Viewer Running.\r\n" ESC_FG_WHITE));
|
||||
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
|
||||
sei();
|
||||
|
||||
for (;;)
|
||||
{
|
||||
RetrieveDeviceData();
|
||||
|
||||
HID_Host_USBTask(&Device_HID_Interface);
|
||||
USB_USBTask();
|
||||
}
|
||||
}
|
||||
|
||||
/** Task to retrieve the HID device information from an attached device, and output
|
||||
* the relevant data to the serial port for analysis.
|
||||
*/
|
||||
void RetrieveDeviceData(void)
|
||||
{
|
||||
if (USB_CurrentMode != USB_MODE_Host)
|
||||
return;
|
||||
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_BUSY);
|
||||
|
||||
OutputReportSizes();
|
||||
OutputParsedReportItems();
|
||||
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_READY);
|
||||
USB_Host_SetDeviceConfiguration(0);
|
||||
}
|
||||
|
||||
/** Prints a summary of the device's HID report sizes from the HID parser output to the serial port
|
||||
* for display to the user.
|
||||
*/
|
||||
void OutputReportSizes(void)
|
||||
{
|
||||
printf_P(PSTR("\r\n\r\nTotal Device Reports: %" PRId8 "\r\n"), HIDReportInfo.TotalDeviceReports);
|
||||
|
||||
for (uint8_t ReportIndex = 0; ReportIndex < HIDReportInfo.TotalDeviceReports; ReportIndex++)
|
||||
{
|
||||
const HID_ReportSizeInfo_t* CurrReportIDInfo = &HIDReportInfo.ReportIDSizes[ReportIndex];
|
||||
|
||||
uint8_t ReportSizeInBits = CurrReportIDInfo->ReportSizeBits[HID_REPORT_ITEM_In];
|
||||
uint8_t ReportSizeOutBits = CurrReportIDInfo->ReportSizeBits[HID_REPORT_ITEM_Out];
|
||||
uint8_t ReportSizeFeatureBits = CurrReportIDInfo->ReportSizeBits[HID_REPORT_ITEM_Feature];
|
||||
|
||||
/* Print out the byte sizes of each report within the device */
|
||||
printf_P(PSTR(" + Report ID 0x%02" PRIX8 "\r\n"
|
||||
" - Input Data: %" PRId8 " bits (%" PRId8 " bytes)\r\n"
|
||||
" - Output Data: %" PRId8 " bits (%" PRId8 " bytes)\r\n"
|
||||
" - Feature Data: %" PRId8 " bits (%" PRId8 " bytes)\r\n"),
|
||||
CurrReportIDInfo->ReportID,
|
||||
ReportSizeInBits,
|
||||
((ReportSizeInBits >> 3) + ((ReportSizeInBits & 0x07) != 0)),
|
||||
ReportSizeOutBits,
|
||||
((ReportSizeOutBits >> 3) + ((ReportSizeOutBits & 0x07) != 0)),
|
||||
ReportSizeFeatureBits,
|
||||
((ReportSizeFeatureBits >> 3) + ((ReportSizeFeatureBits & 0x07) != 0)));
|
||||
}
|
||||
}
|
||||
|
||||
/** Prints a summary of the device's parsed and stored report items along with their attributes
|
||||
* to the serial port for display to the user.
|
||||
*/
|
||||
void OutputParsedReportItems(void)
|
||||
{
|
||||
printf_P(PSTR("\r\nReport Items (%" PRId8 " in Table):\r\n"), HIDReportInfo.TotalReportItems);
|
||||
|
||||
for (uint8_t ItemIndex = 0; ItemIndex < HIDReportInfo.TotalReportItems; ItemIndex++)
|
||||
{
|
||||
const HID_ReportItem_t* RItem = &HIDReportInfo.ReportItems[ItemIndex];
|
||||
|
||||
printf_P(PSTR(" + Item %" PRId8 ":\r\n"
|
||||
" - Report ID: 0x%02" PRIX8 "\r\n"
|
||||
" - Data Direction: %s\r\n"
|
||||
" - Item Flags: 0x%02" PRIX8 "\r\n"
|
||||
" - Item Offset (Bits): 0x%02" PRIX8 "\r\n"
|
||||
" - Item Size (Bits): 0x%02" PRIX8 "\r\n"
|
||||
" - Usage Page: 0x%04" PRIX16 "\r\n"
|
||||
" - Usage: 0x%04" PRIX16 "\r\n"
|
||||
" - Unit Type: 0x%08" PRIX32 "\r\n"
|
||||
" - Unit Exponent: 0x%02" PRIX8 "\r\n"
|
||||
" - Logical Minimum: 0x%08" PRIX32 "\r\n"
|
||||
" - Logical Maximum: 0x%08" PRIX32 "\r\n"
|
||||
" - Physical Minimum: 0x%08" PRIX32 "\r\n"
|
||||
" - Physical Maximum: 0x%08" PRIX32 "\r\n"
|
||||
" - Collection Path:\r\n"),
|
||||
ItemIndex,
|
||||
RItem->ReportID,
|
||||
((RItem->ItemType == HID_REPORT_ITEM_In) ? "IN" : ((RItem->ItemType == HID_REPORT_ITEM_Out) ? "OUT" : "FEATURE")),
|
||||
RItem->ItemFlags,
|
||||
RItem->BitOffset,
|
||||
RItem->Attributes.BitSize,
|
||||
RItem->Attributes.Usage.Page,
|
||||
RItem->Attributes.Usage.Usage,
|
||||
RItem->Attributes.Unit.Type,
|
||||
RItem->Attributes.Unit.Exponent,
|
||||
RItem->Attributes.Logical.Minimum,
|
||||
RItem->Attributes.Logical.Maximum,
|
||||
RItem->Attributes.Physical.Minimum,
|
||||
RItem->Attributes.Physical.Maximum);
|
||||
|
||||
OutputCollectionPath(RItem->CollectionPath);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prints the HID Collection path (along with each node's attributes) to the serial port
|
||||
* for display to the user, from the given starting node to the root node.
|
||||
*
|
||||
* \param[in] CollectionPath Starting HID Collection node to print
|
||||
*/
|
||||
void OutputCollectionPath(const HID_CollectionPath_t* const CollectionPath)
|
||||
{
|
||||
const HID_CollectionPath_t* CurrentNode = CollectionPath;
|
||||
|
||||
while (CurrentNode != NULL)
|
||||
{
|
||||
printf_P(PSTR(" |\r\n"
|
||||
" - Type: 0x%02" PRIX8 "\r\n"
|
||||
" - Usage: 0x%02" PRIX8 "\r\n"),
|
||||
CurrentNode->Type, CurrentNode->Usage);
|
||||
|
||||
CurrentNode = CurrentNode->Parent;
|
||||
}
|
||||
|
||||
printf_P(PSTR(" |\r\n"
|
||||
" END\r\n"));
|
||||
}
|
||||
|
||||
/** 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("Device Attached.\r\n"));
|
||||
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("\r\nDevice Unattached.\r\n"));
|
||||
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)
|
||||
{
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING);
|
||||
|
||||
uint16_t ConfigDescriptorSize;
|
||||
uint8_t ConfigDescriptorData[512];
|
||||
|
||||
if (USB_Host_GetDeviceConfigDescriptor(1, &ConfigDescriptorSize, ConfigDescriptorData,
|
||||
sizeof(ConfigDescriptorData)) != HOST_GETCONFIG_Successful)
|
||||
{
|
||||
puts_P(PSTR("Error Retrieving Configuration Descriptor.\r\n"));
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (HID_Host_ConfigurePipes(&Device_HID_Interface,
|
||||
ConfigDescriptorSize, ConfigDescriptorData) != HID_ENUMERROR_NoError)
|
||||
{
|
||||
puts_P(PSTR("Attached Device Not a Valid HID Device.\r\n"));
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (USB_Host_SetDeviceConfiguration(1) != HOST_SENDCONTROL_Successful)
|
||||
{
|
||||
puts_P(PSTR("Error Setting Device Configuration.\r\n"));
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (HID_Host_SetReportProtocol(&Device_HID_Interface) != 0)
|
||||
{
|
||||
puts_P(PSTR("Error Setting Report Protocol Mode.\r\n"));
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
|
||||
USB_Host_SetDeviceConfiguration(0);
|
||||
return;
|
||||
}
|
||||
|
||||
puts_P(PSTR("HID Device Enumerated.\r\n"));
|
||||
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);
|
||||
}
|
||||
|
||||
/** Callback for the HID Report Parser. This function is called each time the HID report parser is about to store
|
||||
* an IN, OUT or FEATURE item into the HIDReportInfo structure. To save on RAM, we are able to filter out items
|
||||
* we aren't interested in (preventing us from being able to extract them later on, but saving on the RAM they would
|
||||
* have occupied).
|
||||
*
|
||||
* \param[in] CurrentItem Pointer to the item the HID report parser is currently working with
|
||||
*
|
||||
* \return Boolean true if the item should be stored into the HID report structure, false if it should be discarded
|
||||
*/
|
||||
bool CALLBACK_HIDParser_FilterHIDReportItem(HID_ReportItem_t* const CurrentItem)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2011.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.lufa-lib.org
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2011 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 HIDReportViewer project. This file contains the main tasks of
|
||||
* the project and is responsible for the initial application hardware configuration.
|
||||
*/
|
||||
|
||||
#include "HIDReportViewer.h"
|
||||
|
||||
/** Processed HID report descriptor items structure, containing information on each HID report element */
|
||||
static HID_ReportInfo_t HIDReportInfo;
|
||||
|
||||
/** LUFA HID Class driver interface configuration and state information. This structure is
|
||||
* passed to all HID Class driver functions, so that multiple instances of the same class
|
||||
* within a device can be differentiated from one another.
|
||||
*/
|
||||
USB_ClassInfo_HID_Host_t Device_HID_Interface =
|
||||
{
|
||||
.Config =
|
||||
{
|
||||
.DataINPipeNumber = 1,
|
||||
.DataINPipeDoubleBank = false,
|
||||
|
||||
.DataOUTPipeNumber = 2,
|
||||
.DataOUTPipeDoubleBank = false,
|
||||
|
||||
.HIDInterfaceProtocol = HID_CSCP_NonBootProtocol,
|
||||
|
||||
.HIDParserData = &HIDReportInfo
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
/** 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 "HID Device Report Viewer Running.\r\n" ESC_FG_WHITE));
|
||||
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
|
||||
sei();
|
||||
|
||||
for (;;)
|
||||
{
|
||||
RetrieveDeviceData();
|
||||
|
||||
HID_Host_USBTask(&Device_HID_Interface);
|
||||
USB_USBTask();
|
||||
}
|
||||
}
|
||||
|
||||
/** Task to retrieve the HID device information from an attached device, and output
|
||||
* the relevant data to the serial port for analysis.
|
||||
*/
|
||||
void RetrieveDeviceData(void)
|
||||
{
|
||||
if (USB_CurrentMode != USB_MODE_Host)
|
||||
return;
|
||||
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_BUSY);
|
||||
|
||||
OutputReportSizes();
|
||||
OutputParsedReportItems();
|
||||
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_READY);
|
||||
USB_Host_SetDeviceConfiguration(0);
|
||||
}
|
||||
|
||||
/** Prints a summary of the device's HID report sizes from the HID parser output to the serial port
|
||||
* for display to the user.
|
||||
*/
|
||||
void OutputReportSizes(void)
|
||||
{
|
||||
printf_P(PSTR("\r\n\r\nTotal Device Reports: %" PRId8 "\r\n"), HIDReportInfo.TotalDeviceReports);
|
||||
|
||||
for (uint8_t ReportIndex = 0; ReportIndex < HIDReportInfo.TotalDeviceReports; ReportIndex++)
|
||||
{
|
||||
const HID_ReportSizeInfo_t* CurrReportIDInfo = &HIDReportInfo.ReportIDSizes[ReportIndex];
|
||||
|
||||
uint8_t ReportSizeInBits = CurrReportIDInfo->ReportSizeBits[HID_REPORT_ITEM_In];
|
||||
uint8_t ReportSizeOutBits = CurrReportIDInfo->ReportSizeBits[HID_REPORT_ITEM_Out];
|
||||
uint8_t ReportSizeFeatureBits = CurrReportIDInfo->ReportSizeBits[HID_REPORT_ITEM_Feature];
|
||||
|
||||
/* Print out the byte sizes of each report within the device */
|
||||
printf_P(PSTR(" + Report ID 0x%02" PRIX8 "\r\n"
|
||||
" - Input Data: %" PRId8 " bits (%" PRId8 " bytes)\r\n"
|
||||
" - Output Data: %" PRId8 " bits (%" PRId8 " bytes)\r\n"
|
||||
" - Feature Data: %" PRId8 " bits (%" PRId8 " bytes)\r\n"),
|
||||
CurrReportIDInfo->ReportID,
|
||||
ReportSizeInBits,
|
||||
((ReportSizeInBits >> 3) + ((ReportSizeInBits & 0x07) != 0)),
|
||||
ReportSizeOutBits,
|
||||
((ReportSizeOutBits >> 3) + ((ReportSizeOutBits & 0x07) != 0)),
|
||||
ReportSizeFeatureBits,
|
||||
((ReportSizeFeatureBits >> 3) + ((ReportSizeFeatureBits & 0x07) != 0)));
|
||||
}
|
||||
}
|
||||
|
||||
/** Prints a summary of the device's parsed and stored report items along with their attributes
|
||||
* to the serial port for display to the user.
|
||||
*/
|
||||
void OutputParsedReportItems(void)
|
||||
{
|
||||
printf_P(PSTR("\r\nReport Items (%" PRId8 " in Table):\r\n"), HIDReportInfo.TotalReportItems);
|
||||
|
||||
for (uint8_t ItemIndex = 0; ItemIndex < HIDReportInfo.TotalReportItems; ItemIndex++)
|
||||
{
|
||||
const HID_ReportItem_t* RItem = &HIDReportInfo.ReportItems[ItemIndex];
|
||||
|
||||
printf_P(PSTR(" + Item %" PRId8 ":\r\n"
|
||||
" - Report ID: 0x%02" PRIX8 "\r\n"
|
||||
" - Data Direction: %s\r\n"
|
||||
" - Item Flags: 0x%02" PRIX8 "\r\n"
|
||||
" - Item Offset (Bits): 0x%02" PRIX8 "\r\n"
|
||||
" - Item Size (Bits): 0x%02" PRIX8 "\r\n"
|
||||
" - Usage Page: 0x%04" PRIX16 "\r\n"
|
||||
" - Usage: 0x%04" PRIX16 "\r\n"
|
||||
" - Unit Type: 0x%08" PRIX32 "\r\n"
|
||||
" - Unit Exponent: 0x%02" PRIX8 "\r\n"
|
||||
" - Logical Minimum: 0x%08" PRIX32 "\r\n"
|
||||
" - Logical Maximum: 0x%08" PRIX32 "\r\n"
|
||||
" - Physical Minimum: 0x%08" PRIX32 "\r\n"
|
||||
" - Physical Maximum: 0x%08" PRIX32 "\r\n"
|
||||
" - Collection Path:\r\n"),
|
||||
ItemIndex,
|
||||
RItem->ReportID,
|
||||
((RItem->ItemType == HID_REPORT_ITEM_In) ? "IN" : ((RItem->ItemType == HID_REPORT_ITEM_Out) ? "OUT" : "FEATURE")),
|
||||
RItem->ItemFlags,
|
||||
RItem->BitOffset,
|
||||
RItem->Attributes.BitSize,
|
||||
RItem->Attributes.Usage.Page,
|
||||
RItem->Attributes.Usage.Usage,
|
||||
RItem->Attributes.Unit.Type,
|
||||
RItem->Attributes.Unit.Exponent,
|
||||
RItem->Attributes.Logical.Minimum,
|
||||
RItem->Attributes.Logical.Maximum,
|
||||
RItem->Attributes.Physical.Minimum,
|
||||
RItem->Attributes.Physical.Maximum);
|
||||
|
||||
OutputCollectionPath(RItem->CollectionPath);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prints the HID Collection path (along with each node's attributes) to the serial port
|
||||
* for display to the user, from the given starting node to the root node.
|
||||
*
|
||||
* \param[in] CollectionPath Starting HID Collection node to print
|
||||
*/
|
||||
void OutputCollectionPath(const HID_CollectionPath_t* const CollectionPath)
|
||||
{
|
||||
const HID_CollectionPath_t* CurrentNode = CollectionPath;
|
||||
|
||||
while (CurrentNode != NULL)
|
||||
{
|
||||
printf_P(PSTR(" |\r\n"
|
||||
" - Type: 0x%02" PRIX8 "\r\n"
|
||||
" - Usage: 0x%02" PRIX8 "\r\n"),
|
||||
CurrentNode->Type, CurrentNode->Usage);
|
||||
|
||||
CurrentNode = CurrentNode->Parent;
|
||||
}
|
||||
|
||||
printf_P(PSTR(" |\r\n"
|
||||
" END\r\n"));
|
||||
}
|
||||
|
||||
/** 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("Device Attached.\r\n"));
|
||||
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("\r\nDevice Unattached.\r\n"));
|
||||
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)
|
||||
{
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING);
|
||||
|
||||
uint16_t ConfigDescriptorSize;
|
||||
uint8_t ConfigDescriptorData[512];
|
||||
|
||||
if (USB_Host_GetDeviceConfigDescriptor(1, &ConfigDescriptorSize, ConfigDescriptorData,
|
||||
sizeof(ConfigDescriptorData)) != HOST_GETCONFIG_Successful)
|
||||
{
|
||||
puts_P(PSTR("Error Retrieving Configuration Descriptor.\r\n"));
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (HID_Host_ConfigurePipes(&Device_HID_Interface,
|
||||
ConfigDescriptorSize, ConfigDescriptorData) != HID_ENUMERROR_NoError)
|
||||
{
|
||||
puts_P(PSTR("Attached Device Not a Valid HID Device.\r\n"));
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (USB_Host_SetDeviceConfiguration(1) != HOST_SENDCONTROL_Successful)
|
||||
{
|
||||
puts_P(PSTR("Error Setting Device Configuration.\r\n"));
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (HID_Host_SetReportProtocol(&Device_HID_Interface) != 0)
|
||||
{
|
||||
puts_P(PSTR("Error Setting Report Protocol Mode.\r\n"));
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
|
||||
USB_Host_SetDeviceConfiguration(0);
|
||||
return;
|
||||
}
|
||||
|
||||
puts_P(PSTR("HID Device Enumerated.\r\n"));
|
||||
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);
|
||||
}
|
||||
|
||||
/** Callback for the HID Report Parser. This function is called each time the HID report parser is about to store
|
||||
* an IN, OUT or FEATURE item into the HIDReportInfo structure. To save on RAM, we are able to filter out items
|
||||
* we aren't interested in (preventing us from being able to extract them later on, but saving on the RAM they would
|
||||
* have occupied).
|
||||
*
|
||||
* \param[in] CurrentItem Pointer to the item the HID report parser is currently working with
|
||||
*
|
||||
* \return Boolean true if the item should be stored into the HID report structure, false if it should be discarded
|
||||
*/
|
||||
bool CALLBACK_HIDParser_FilterHIDReportItem(HID_ReportItem_t* const CurrentItem)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,87 +1,87 @@
|
|||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2011.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.lufa-lib.org
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2011 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 HIDReportViewer.c.
|
||||
*/
|
||||
|
||||
#ifndef _HID_REPORT_VIEWER_H_
|
||||
#define _HID_REPORT_VIEWER_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 <inttypes.h>
|
||||
|
||||
#include <LUFA/Version.h>
|
||||
#include <LUFA/Drivers/Misc/TerminalCodes.h>
|
||||
#include <LUFA/Drivers/Peripheral/Serial.h>
|
||||
#include <LUFA/Drivers/Board/LEDs.h>
|
||||
#include <LUFA/Drivers/USB/USB.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_LED1 | LEDS_LED3 | LEDS_LED4)
|
||||
|
||||
/* Function Prototypes: */
|
||||
void SetupHardware(void);
|
||||
void RetrieveDeviceData(void);
|
||||
void OutputReportSizes(void);
|
||||
void OutputParsedReportItems(void);
|
||||
void OutputCollectionPath(const HID_CollectionPath_t* const CollectionPath);
|
||||
|
||||
void EVENT_USB_Host_HostError(const uint8_t ErrorCode);
|
||||
void EVENT_USB_Host_DeviceAttached(void);
|
||||
void EVENT_USB_Host_DeviceUnattached(void);
|
||||
void EVENT_USB_Host_DeviceEnumerationFailed(const uint8_t ErrorCode,
|
||||
const uint8_t SubErrorCode);
|
||||
void EVENT_USB_Host_DeviceEnumerationComplete(void);
|
||||
|
||||
bool CALLBACK_HIDParser_FilterHIDReportItem(HID_ReportItem_t* const CurrentItem);
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2011.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.lufa-lib.org
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2011 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 HIDReportViewer.c.
|
||||
*/
|
||||
|
||||
#ifndef _HID_REPORT_VIEWER_H_
|
||||
#define _HID_REPORT_VIEWER_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 <inttypes.h>
|
||||
|
||||
#include <LUFA/Version.h>
|
||||
#include <LUFA/Drivers/Misc/TerminalCodes.h>
|
||||
#include <LUFA/Drivers/Peripheral/Serial.h>
|
||||
#include <LUFA/Drivers/Board/LEDs.h>
|
||||
#include <LUFA/Drivers/USB/USB.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_LED1 | LEDS_LED3 | LEDS_LED4)
|
||||
|
||||
/* Function Prototypes: */
|
||||
void SetupHardware(void);
|
||||
void RetrieveDeviceData(void);
|
||||
void OutputReportSizes(void);
|
||||
void OutputParsedReportItems(void);
|
||||
void OutputCollectionPath(const HID_CollectionPath_t* const CollectionPath);
|
||||
|
||||
void EVENT_USB_Host_HostError(const uint8_t ErrorCode);
|
||||
void EVENT_USB_Host_DeviceAttached(void);
|
||||
void EVENT_USB_Host_DeviceUnattached(void);
|
||||
void EVENT_USB_Host_DeviceEnumerationFailed(const uint8_t ErrorCode,
|
||||
const uint8_t SubErrorCode);
|
||||
void EVENT_USB_Host_DeviceEnumerationComplete(void);
|
||||
|
||||
bool CALLBACK_HIDParser_FilterHIDReportItem(HID_ReportItem_t* const CurrentItem);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -1,64 +1,64 @@
|
|||
/** \file
|
||||
*
|
||||
* This file contains special DoxyGen information for the generation of the main page and other special
|
||||
* documentation pages. It is not a project source file.
|
||||
*/
|
||||
|
||||
/** \mainpage HID Device Report Viewer Programmer Project
|
||||
*
|
||||
* \section Sec_Compat Project Compatibility:
|
||||
*
|
||||
* The following list indicates what microcontrollers are compatible with this project.
|
||||
*
|
||||
* - Series 7 USB AVRs (AT90USBxxx7)
|
||||
*
|
||||
* \section Sec_Info USB Information:
|
||||
*
|
||||
* The following table gives a rundown of the USB utilization of this project.
|
||||
*
|
||||
* <table>
|
||||
* <tr>
|
||||
* <td><b>USB Mode:</b></td>
|
||||
* <td>Host</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td><b>USB Class:</b></td>
|
||||
* <td>Human Interface Device (HID)</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td><b>USB Subclass:</b></td>
|
||||
* <td>N/A</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td><b>Relevant Standards:</b></td>
|
||||
* <td>USBIF HID Specification \n
|
||||
* USBIF HID Usage Tables</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td><b>Usable Speeds:</b></td>
|
||||
* <td>Low Speed Mode \n
|
||||
* Full Speed Mode</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*
|
||||
* \section Sec_Description Project Description:
|
||||
*
|
||||
* Firmware for a HID Report viewer. This project is designed to aid in the debugging of USB HID Hosts, where the contents of an
|
||||
* unknown HID device's HID Report need to be examined. Once a HID device has been plugged into this application, the HID report
|
||||
* descriptor will be parsed using the internal LUFA HID report parser, and the results dumped to the serial port in a human
|
||||
* readable format. This output will contain information on the sizes of the reports within the device's HID interface, as well as
|
||||
* information on each report element (size, usage, minimum/maximum values, etc.).
|
||||
*
|
||||
* \section Sec_Options Project Options
|
||||
*
|
||||
* The following defines can be found in this project, which can control the project behaviour when defined, or changed in value.
|
||||
*
|
||||
* <table>
|
||||
* <tr>
|
||||
* <td>
|
||||
* None
|
||||
* </td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*/
|
||||
|
||||
/** \file
|
||||
*
|
||||
* This file contains special DoxyGen information for the generation of the main page and other special
|
||||
* documentation pages. It is not a project source file.
|
||||
*/
|
||||
|
||||
/** \mainpage HID Device Report Viewer Programmer Project
|
||||
*
|
||||
* \section Sec_Compat Project Compatibility:
|
||||
*
|
||||
* The following list indicates what microcontrollers are compatible with this project.
|
||||
*
|
||||
* - Series 7 USB AVRs (AT90USBxxx7)
|
||||
*
|
||||
* \section Sec_Info USB Information:
|
||||
*
|
||||
* The following table gives a rundown of the USB utilization of this project.
|
||||
*
|
||||
* <table>
|
||||
* <tr>
|
||||
* <td><b>USB Mode:</b></td>
|
||||
* <td>Host</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td><b>USB Class:</b></td>
|
||||
* <td>Human Interface Device (HID)</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td><b>USB Subclass:</b></td>
|
||||
* <td>N/A</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td><b>Relevant Standards:</b></td>
|
||||
* <td>USBIF HID Specification \n
|
||||
* USBIF HID Usage Tables</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td><b>Usable Speeds:</b></td>
|
||||
* <td>Low Speed Mode \n
|
||||
* Full Speed Mode</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*
|
||||
* \section Sec_Description Project Description:
|
||||
*
|
||||
* Firmware for a HID Report viewer. This project is designed to aid in the debugging of USB HID Hosts, where the contents of an
|
||||
* unknown HID device's HID Report need to be examined. Once a HID device has been plugged into this application, the HID report
|
||||
* descriptor will be parsed using the internal LUFA HID report parser, and the results dumped to the serial port in a human
|
||||
* readable format. This output will contain information on the sizes of the reports within the device's HID interface, as well as
|
||||
* information on each report element (size, usage, minimum/maximum values, etc.).
|
||||
*
|
||||
* \section Sec_Options Project Options
|
||||
*
|
||||
* The following defines can be found in this project, which can control the project behaviour when defined, or changed in value.
|
||||
*
|
||||
* <table>
|
||||
* <tr>
|
||||
* <td>
|
||||
* None
|
||||
* </td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*/
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,329 +1,329 @@
|
|||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2011.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.lufa-lib.org
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2011 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 Descriptors, for library use when in USB device mode. Descriptors are special
|
||||
* computer-readable structures which the host requests upon device enumeration, to determine
|
||||
* the device's capabilities and functions.
|
||||
*/
|
||||
|
||||
#include "Descriptors.h"
|
||||
|
||||
/** Device descriptor structure. This descriptor, located in FLASH memory, describes the overall
|
||||
* device characteristics, including the supported USB version, control endpoint size and the
|
||||
* number of device configurations. The descriptor is read out by the USB host when the enumeration
|
||||
* process begins.
|
||||
*/
|
||||
const USB_Descriptor_Device_t PROGMEM DeviceDescriptor =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_Descriptor_Device_t), .Type = DTYPE_Device},
|
||||
|
||||
.USBSpecification = VERSION_BCD(01.10),
|
||||
.Class = USB_CSCP_NoDeviceClass,
|
||||
.SubClass = USB_CSCP_NoDeviceSubclass,
|
||||
.Protocol = USB_CSCP_NoDeviceProtocol,
|
||||
|
||||
.Endpoint0Size = FIXED_CONTROL_ENDPOINT_SIZE,
|
||||
|
||||
.VendorID = 0x03EB,
|
||||
.ProductID = 0x2048,
|
||||
.ReleaseNumber = VERSION_BCD(00.01),
|
||||
|
||||
.ManufacturerStrIndex = 0x01,
|
||||
.ProductStrIndex = 0x02,
|
||||
.SerialNumStrIndex = NO_DESCRIPTOR,
|
||||
|
||||
.NumberOfConfigurations = FIXED_NUM_CONFIGURATIONS
|
||||
};
|
||||
|
||||
/** Configuration descriptor structure. This descriptor, located in FLASH memory, describes the usage
|
||||
* of the device in one of its supported configurations, including information about any device interfaces
|
||||
* and endpoints. The descriptor is read out by the USB host during the enumeration process when selecting
|
||||
* a configuration so that the host may correctly communicate with the USB device.
|
||||
*/
|
||||
const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor =
|
||||
{
|
||||
.Config =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_Descriptor_Configuration_Header_t), .Type = DTYPE_Configuration},
|
||||
|
||||
.TotalConfigurationSize = sizeof(USB_Descriptor_Configuration_t),
|
||||
.TotalInterfaces = 2,
|
||||
|
||||
.ConfigurationNumber = 1,
|
||||
.ConfigurationStrIndex = NO_DESCRIPTOR,
|
||||
|
||||
.ConfigAttributes = (USB_CONFIG_ATTR_BUSPOWERED | USB_CONFIG_ATTR_SELFPOWERED),
|
||||
|
||||
.MaxPowerConsumption = USB_CONFIG_POWER_MA(100)
|
||||
},
|
||||
|
||||
.Audio_ControlInterface =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface},
|
||||
|
||||
.InterfaceNumber = 0,
|
||||
.AlternateSetting = 0,
|
||||
|
||||
.TotalEndpoints = 0,
|
||||
|
||||
.Class = AUDIO_CSCP_AudioClass,
|
||||
.SubClass = AUDIO_CSCP_ControlSubclass,
|
||||
.Protocol = AUDIO_CSCP_ControlProtocol,
|
||||
|
||||
.InterfaceStrIndex = NO_DESCRIPTOR
|
||||
},
|
||||
|
||||
.Audio_ControlInterface_SPC =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_Audio_Descriptor_Interface_AC_t), .Type = DTYPE_CSInterface},
|
||||
.Subtype = AUDIO_DSUBTYPE_CSInterface_Header,
|
||||
|
||||
.ACSpecification = VERSION_BCD(01.00),
|
||||
.TotalLength = sizeof(USB_Audio_Descriptor_Interface_AC_t),
|
||||
|
||||
.InCollection = 1,
|
||||
.InterfaceNumber = 1,
|
||||
},
|
||||
|
||||
.Audio_StreamInterface =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface},
|
||||
|
||||
.InterfaceNumber = 1,
|
||||
.AlternateSetting = 0,
|
||||
|
||||
.TotalEndpoints = 2,
|
||||
|
||||
.Class = AUDIO_CSCP_AudioClass,
|
||||
.SubClass = AUDIO_CSCP_MIDIStreamingSubclass,
|
||||
.Protocol = AUDIO_CSCP_StreamingProtocol,
|
||||
|
||||
.InterfaceStrIndex = NO_DESCRIPTOR
|
||||
},
|
||||
|
||||
.Audio_StreamInterface_SPC =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_MIDI_Descriptor_AudioInterface_AS_t), .Type = DTYPE_CSInterface},
|
||||
.Subtype = AUDIO_DSUBTYPE_CSInterface_General,
|
||||
|
||||
.AudioSpecification = VERSION_BCD(01.00),
|
||||
|
||||
.TotalLength = (sizeof(USB_Descriptor_Configuration_t) -
|
||||
offsetof(USB_Descriptor_Configuration_t, Audio_StreamInterface_SPC))
|
||||
},
|
||||
|
||||
.MIDI_In_Jack_Emb =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_MIDI_Descriptor_InputJack_t), .Type = DTYPE_CSInterface},
|
||||
.Subtype = AUDIO_DSUBTYPE_CSInterface_InputTerminal,
|
||||
|
||||
.JackType = MIDI_JACKTYPE_Embedded,
|
||||
.JackID = 0x01,
|
||||
|
||||
.JackStrIndex = NO_DESCRIPTOR
|
||||
},
|
||||
|
||||
.MIDI_In_Jack_Ext =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_MIDI_Descriptor_InputJack_t), .Type = DTYPE_CSInterface},
|
||||
.Subtype = AUDIO_DSUBTYPE_CSInterface_InputTerminal,
|
||||
|
||||
.JackType = MIDI_JACKTYPE_External,
|
||||
.JackID = 0x02,
|
||||
|
||||
.JackStrIndex = NO_DESCRIPTOR
|
||||
},
|
||||
|
||||
.MIDI_Out_Jack_Emb =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_MIDI_Descriptor_OutputJack_t), .Type = DTYPE_CSInterface},
|
||||
.Subtype = AUDIO_DSUBTYPE_CSInterface_OutputTerminal,
|
||||
|
||||
.JackType = MIDI_JACKTYPE_Embedded,
|
||||
.JackID = 0x03,
|
||||
|
||||
.NumberOfPins = 1,
|
||||
.SourceJackID = {0x02},
|
||||
.SourcePinID = {0x01},
|
||||
|
||||
.JackStrIndex = NO_DESCRIPTOR
|
||||
},
|
||||
|
||||
.MIDI_Out_Jack_Ext =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_MIDI_Descriptor_OutputJack_t), .Type = DTYPE_CSInterface},
|
||||
.Subtype = AUDIO_DSUBTYPE_CSInterface_OutputTerminal,
|
||||
|
||||
.JackType = MIDI_JACKTYPE_External,
|
||||
.JackID = 0x04,
|
||||
|
||||
.NumberOfPins = 1,
|
||||
.SourceJackID = {0x01},
|
||||
.SourcePinID = {0x01},
|
||||
|
||||
.JackStrIndex = NO_DESCRIPTOR
|
||||
},
|
||||
|
||||
.MIDI_In_Jack_Endpoint =
|
||||
{
|
||||
.Endpoint =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_Audio_Descriptor_StreamEndpoint_Std_t), .Type = DTYPE_Endpoint},
|
||||
|
||||
.EndpointAddress = (ENDPOINT_DESCRIPTOR_DIR_OUT | MIDI_STREAM_OUT_EPNUM),
|
||||
.Attributes = (EP_TYPE_BULK | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
|
||||
.EndpointSize = MIDI_STREAM_EPSIZE,
|
||||
.PollingIntervalMS = 0x01
|
||||
},
|
||||
|
||||
.Refresh = 0,
|
||||
.SyncEndpointNumber = 0
|
||||
},
|
||||
|
||||
.MIDI_In_Jack_Endpoint_SPC =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_MIDI_Descriptor_Jack_Endpoint_t), .Type = DTYPE_CSEndpoint},
|
||||
.Subtype = AUDIO_DSUBTYPE_CSEndpoint_General,
|
||||
|
||||
.TotalEmbeddedJacks = 0x01,
|
||||
.AssociatedJackID = {0x01}
|
||||
},
|
||||
|
||||
.MIDI_Out_Jack_Endpoint =
|
||||
{
|
||||
.Endpoint =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_Audio_Descriptor_StreamEndpoint_Std_t), .Type = DTYPE_Endpoint},
|
||||
|
||||
.EndpointAddress = (ENDPOINT_DESCRIPTOR_DIR_IN | MIDI_STREAM_IN_EPNUM),
|
||||
.Attributes = (EP_TYPE_BULK | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
|
||||
.EndpointSize = MIDI_STREAM_EPSIZE,
|
||||
.PollingIntervalMS = 0x01
|
||||
},
|
||||
|
||||
.Refresh = 0,
|
||||
.SyncEndpointNumber = 0
|
||||
},
|
||||
|
||||
.MIDI_Out_Jack_Endpoint_SPC =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_MIDI_Descriptor_Jack_Endpoint_t), .Type = DTYPE_CSEndpoint},
|
||||
.Subtype = AUDIO_DSUBTYPE_CSEndpoint_General,
|
||||
|
||||
.TotalEmbeddedJacks = 0x01,
|
||||
.AssociatedJackID = {0x03}
|
||||
}
|
||||
};
|
||||
|
||||
/** Language descriptor structure. This descriptor, located in FLASH memory, is returned when the host requests
|
||||
* the string descriptor with index 0 (the first index). It is actually an array of 16-bit integers, which indicate
|
||||
* via the language ID table available at USB.org what languages the device supports for its string descriptors.
|
||||
*/
|
||||
const USB_Descriptor_String_t PROGMEM LanguageString =
|
||||
{
|
||||
.Header = {.Size = USB_STRING_LEN(1), .Type = DTYPE_String},
|
||||
|
||||
.UnicodeString = {LANGUAGE_ID_ENG}
|
||||
};
|
||||
|
||||
/** Manufacturer descriptor string. This is a Unicode string containing the manufacturer's details in human readable
|
||||
* form, and is read out upon request by the host when the appropriate string ID is requested, listed in the Device
|
||||
* Descriptor.
|
||||
*/
|
||||
const USB_Descriptor_String_t PROGMEM ManufacturerString =
|
||||
{
|
||||
.Header = {.Size = USB_STRING_LEN(11), .Type = DTYPE_String},
|
||||
|
||||
.UnicodeString = L"Dean Camera"
|
||||
};
|
||||
|
||||
/** Product descriptor string. This is a Unicode string containing the product's details in human readable form,
|
||||
* and is read out upon request by the host when the appropriate string ID is requested, listed in the Device
|
||||
* Descriptor.
|
||||
*/
|
||||
const USB_Descriptor_String_t PROGMEM ProductString =
|
||||
{
|
||||
.Header = {.Size = USB_STRING_LEN(14), .Type = DTYPE_String},
|
||||
|
||||
.UnicodeString = L"LUFA MIDI Demo"
|
||||
};
|
||||
|
||||
/** This function is called by the library when in device mode, and must be overridden (see library "USB Descriptors"
|
||||
* documentation) by the application code so that the address and size of a requested descriptor can be given
|
||||
* to the USB library. When the device receives a Get Descriptor request on the control endpoint, this function
|
||||
* is called so that the descriptor details can be passed back and the appropriate descriptor sent back to the
|
||||
* USB host.
|
||||
*/
|
||||
uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue,
|
||||
const uint8_t wIndex,
|
||||
const void** const DescriptorAddress)
|
||||
{
|
||||
const uint8_t DescriptorType = (wValue >> 8);
|
||||
const uint8_t DescriptorNumber = (wValue & 0xFF);
|
||||
|
||||
const void* Address = NULL;
|
||||
uint16_t Size = NO_DESCRIPTOR;
|
||||
|
||||
switch (DescriptorType)
|
||||
{
|
||||
case DTYPE_Device:
|
||||
Address = &DeviceDescriptor;
|
||||
Size = sizeof(USB_Descriptor_Device_t);
|
||||
break;
|
||||
case DTYPE_Configuration:
|
||||
Address = &ConfigurationDescriptor;
|
||||
Size = sizeof(USB_Descriptor_Configuration_t);
|
||||
break;
|
||||
case DTYPE_String:
|
||||
switch (DescriptorNumber)
|
||||
{
|
||||
case 0x00:
|
||||
Address = &LanguageString;
|
||||
Size = pgm_read_byte(&LanguageString.Header.Size);
|
||||
break;
|
||||
case 0x01:
|
||||
Address = &ManufacturerString;
|
||||
Size = pgm_read_byte(&ManufacturerString.Header.Size);
|
||||
break;
|
||||
case 0x02:
|
||||
Address = &ProductString;
|
||||
Size = pgm_read_byte(&ProductString.Header.Size);
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
*DescriptorAddress = Address;
|
||||
return Size;
|
||||
}
|
||||
|
||||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2011.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.lufa-lib.org
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2011 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 Descriptors, for library use when in USB device mode. Descriptors are special
|
||||
* computer-readable structures which the host requests upon device enumeration, to determine
|
||||
* the device's capabilities and functions.
|
||||
*/
|
||||
|
||||
#include "Descriptors.h"
|
||||
|
||||
/** Device descriptor structure. This descriptor, located in FLASH memory, describes the overall
|
||||
* device characteristics, including the supported USB version, control endpoint size and the
|
||||
* number of device configurations. The descriptor is read out by the USB host when the enumeration
|
||||
* process begins.
|
||||
*/
|
||||
const USB_Descriptor_Device_t PROGMEM DeviceDescriptor =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_Descriptor_Device_t), .Type = DTYPE_Device},
|
||||
|
||||
.USBSpecification = VERSION_BCD(01.10),
|
||||
.Class = USB_CSCP_NoDeviceClass,
|
||||
.SubClass = USB_CSCP_NoDeviceSubclass,
|
||||
.Protocol = USB_CSCP_NoDeviceProtocol,
|
||||
|
||||
.Endpoint0Size = FIXED_CONTROL_ENDPOINT_SIZE,
|
||||
|
||||
.VendorID = 0x03EB,
|
||||
.ProductID = 0x2048,
|
||||
.ReleaseNumber = VERSION_BCD(00.01),
|
||||
|
||||
.ManufacturerStrIndex = 0x01,
|
||||
.ProductStrIndex = 0x02,
|
||||
.SerialNumStrIndex = NO_DESCRIPTOR,
|
||||
|
||||
.NumberOfConfigurations = FIXED_NUM_CONFIGURATIONS
|
||||
};
|
||||
|
||||
/** Configuration descriptor structure. This descriptor, located in FLASH memory, describes the usage
|
||||
* of the device in one of its supported configurations, including information about any device interfaces
|
||||
* and endpoints. The descriptor is read out by the USB host during the enumeration process when selecting
|
||||
* a configuration so that the host may correctly communicate with the USB device.
|
||||
*/
|
||||
const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor =
|
||||
{
|
||||
.Config =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_Descriptor_Configuration_Header_t), .Type = DTYPE_Configuration},
|
||||
|
||||
.TotalConfigurationSize = sizeof(USB_Descriptor_Configuration_t),
|
||||
.TotalInterfaces = 2,
|
||||
|
||||
.ConfigurationNumber = 1,
|
||||
.ConfigurationStrIndex = NO_DESCRIPTOR,
|
||||
|
||||
.ConfigAttributes = (USB_CONFIG_ATTR_BUSPOWERED | USB_CONFIG_ATTR_SELFPOWERED),
|
||||
|
||||
.MaxPowerConsumption = USB_CONFIG_POWER_MA(100)
|
||||
},
|
||||
|
||||
.Audio_ControlInterface =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface},
|
||||
|
||||
.InterfaceNumber = 0,
|
||||
.AlternateSetting = 0,
|
||||
|
||||
.TotalEndpoints = 0,
|
||||
|
||||
.Class = AUDIO_CSCP_AudioClass,
|
||||
.SubClass = AUDIO_CSCP_ControlSubclass,
|
||||
.Protocol = AUDIO_CSCP_ControlProtocol,
|
||||
|
||||
.InterfaceStrIndex = NO_DESCRIPTOR
|
||||
},
|
||||
|
||||
.Audio_ControlInterface_SPC =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_Audio_Descriptor_Interface_AC_t), .Type = DTYPE_CSInterface},
|
||||
.Subtype = AUDIO_DSUBTYPE_CSInterface_Header,
|
||||
|
||||
.ACSpecification = VERSION_BCD(01.00),
|
||||
.TotalLength = sizeof(USB_Audio_Descriptor_Interface_AC_t),
|
||||
|
||||
.InCollection = 1,
|
||||
.InterfaceNumber = 1,
|
||||
},
|
||||
|
||||
.Audio_StreamInterface =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface},
|
||||
|
||||
.InterfaceNumber = 1,
|
||||
.AlternateSetting = 0,
|
||||
|
||||
.TotalEndpoints = 2,
|
||||
|
||||
.Class = AUDIO_CSCP_AudioClass,
|
||||
.SubClass = AUDIO_CSCP_MIDIStreamingSubclass,
|
||||
.Protocol = AUDIO_CSCP_StreamingProtocol,
|
||||
|
||||
.InterfaceStrIndex = NO_DESCRIPTOR
|
||||
},
|
||||
|
||||
.Audio_StreamInterface_SPC =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_MIDI_Descriptor_AudioInterface_AS_t), .Type = DTYPE_CSInterface},
|
||||
.Subtype = AUDIO_DSUBTYPE_CSInterface_General,
|
||||
|
||||
.AudioSpecification = VERSION_BCD(01.00),
|
||||
|
||||
.TotalLength = (sizeof(USB_Descriptor_Configuration_t) -
|
||||
offsetof(USB_Descriptor_Configuration_t, Audio_StreamInterface_SPC))
|
||||
},
|
||||
|
||||
.MIDI_In_Jack_Emb =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_MIDI_Descriptor_InputJack_t), .Type = DTYPE_CSInterface},
|
||||
.Subtype = AUDIO_DSUBTYPE_CSInterface_InputTerminal,
|
||||
|
||||
.JackType = MIDI_JACKTYPE_Embedded,
|
||||
.JackID = 0x01,
|
||||
|
||||
.JackStrIndex = NO_DESCRIPTOR
|
||||
},
|
||||
|
||||
.MIDI_In_Jack_Ext =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_MIDI_Descriptor_InputJack_t), .Type = DTYPE_CSInterface},
|
||||
.Subtype = AUDIO_DSUBTYPE_CSInterface_InputTerminal,
|
||||
|
||||
.JackType = MIDI_JACKTYPE_External,
|
||||
.JackID = 0x02,
|
||||
|
||||
.JackStrIndex = NO_DESCRIPTOR
|
||||
},
|
||||
|
||||
.MIDI_Out_Jack_Emb =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_MIDI_Descriptor_OutputJack_t), .Type = DTYPE_CSInterface},
|
||||
.Subtype = AUDIO_DSUBTYPE_CSInterface_OutputTerminal,
|
||||
|
||||
.JackType = MIDI_JACKTYPE_Embedded,
|
||||
.JackID = 0x03,
|
||||
|
||||
.NumberOfPins = 1,
|
||||
.SourceJackID = {0x02},
|
||||
.SourcePinID = {0x01},
|
||||
|
||||
.JackStrIndex = NO_DESCRIPTOR
|
||||
},
|
||||
|
||||
.MIDI_Out_Jack_Ext =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_MIDI_Descriptor_OutputJack_t), .Type = DTYPE_CSInterface},
|
||||
.Subtype = AUDIO_DSUBTYPE_CSInterface_OutputTerminal,
|
||||
|
||||
.JackType = MIDI_JACKTYPE_External,
|
||||
.JackID = 0x04,
|
||||
|
||||
.NumberOfPins = 1,
|
||||
.SourceJackID = {0x01},
|
||||
.SourcePinID = {0x01},
|
||||
|
||||
.JackStrIndex = NO_DESCRIPTOR
|
||||
},
|
||||
|
||||
.MIDI_In_Jack_Endpoint =
|
||||
{
|
||||
.Endpoint =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_Audio_Descriptor_StreamEndpoint_Std_t), .Type = DTYPE_Endpoint},
|
||||
|
||||
.EndpointAddress = (ENDPOINT_DESCRIPTOR_DIR_OUT | MIDI_STREAM_OUT_EPNUM),
|
||||
.Attributes = (EP_TYPE_BULK | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
|
||||
.EndpointSize = MIDI_STREAM_EPSIZE,
|
||||
.PollingIntervalMS = 0x01
|
||||
},
|
||||
|
||||
.Refresh = 0,
|
||||
.SyncEndpointNumber = 0
|
||||
},
|
||||
|
||||
.MIDI_In_Jack_Endpoint_SPC =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_MIDI_Descriptor_Jack_Endpoint_t), .Type = DTYPE_CSEndpoint},
|
||||
.Subtype = AUDIO_DSUBTYPE_CSEndpoint_General,
|
||||
|
||||
.TotalEmbeddedJacks = 0x01,
|
||||
.AssociatedJackID = {0x01}
|
||||
},
|
||||
|
||||
.MIDI_Out_Jack_Endpoint =
|
||||
{
|
||||
.Endpoint =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_Audio_Descriptor_StreamEndpoint_Std_t), .Type = DTYPE_Endpoint},
|
||||
|
||||
.EndpointAddress = (ENDPOINT_DESCRIPTOR_DIR_IN | MIDI_STREAM_IN_EPNUM),
|
||||
.Attributes = (EP_TYPE_BULK | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
|
||||
.EndpointSize = MIDI_STREAM_EPSIZE,
|
||||
.PollingIntervalMS = 0x01
|
||||
},
|
||||
|
||||
.Refresh = 0,
|
||||
.SyncEndpointNumber = 0
|
||||
},
|
||||
|
||||
.MIDI_Out_Jack_Endpoint_SPC =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_MIDI_Descriptor_Jack_Endpoint_t), .Type = DTYPE_CSEndpoint},
|
||||
.Subtype = AUDIO_DSUBTYPE_CSEndpoint_General,
|
||||
|
||||
.TotalEmbeddedJacks = 0x01,
|
||||
.AssociatedJackID = {0x03}
|
||||
}
|
||||
};
|
||||
|
||||
/** Language descriptor structure. This descriptor, located in FLASH memory, is returned when the host requests
|
||||
* the string descriptor with index 0 (the first index). It is actually an array of 16-bit integers, which indicate
|
||||
* via the language ID table available at USB.org what languages the device supports for its string descriptors.
|
||||
*/
|
||||
const USB_Descriptor_String_t PROGMEM LanguageString =
|
||||
{
|
||||
.Header = {.Size = USB_STRING_LEN(1), .Type = DTYPE_String},
|
||||
|
||||
.UnicodeString = {LANGUAGE_ID_ENG}
|
||||
};
|
||||
|
||||
/** Manufacturer descriptor string. This is a Unicode string containing the manufacturer's details in human readable
|
||||
* form, and is read out upon request by the host when the appropriate string ID is requested, listed in the Device
|
||||
* Descriptor.
|
||||
*/
|
||||
const USB_Descriptor_String_t PROGMEM ManufacturerString =
|
||||
{
|
||||
.Header = {.Size = USB_STRING_LEN(11), .Type = DTYPE_String},
|
||||
|
||||
.UnicodeString = L"Dean Camera"
|
||||
};
|
||||
|
||||
/** Product descriptor string. This is a Unicode string containing the product's details in human readable form,
|
||||
* and is read out upon request by the host when the appropriate string ID is requested, listed in the Device
|
||||
* Descriptor.
|
||||
*/
|
||||
const USB_Descriptor_String_t PROGMEM ProductString =
|
||||
{
|
||||
.Header = {.Size = USB_STRING_LEN(14), .Type = DTYPE_String},
|
||||
|
||||
.UnicodeString = L"LUFA MIDI Demo"
|
||||
};
|
||||
|
||||
/** This function is called by the library when in device mode, and must be overridden (see library "USB Descriptors"
|
||||
* documentation) by the application code so that the address and size of a requested descriptor can be given
|
||||
* to the USB library. When the device receives a Get Descriptor request on the control endpoint, this function
|
||||
* is called so that the descriptor details can be passed back and the appropriate descriptor sent back to the
|
||||
* USB host.
|
||||
*/
|
||||
uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue,
|
||||
const uint8_t wIndex,
|
||||
const void** const DescriptorAddress)
|
||||
{
|
||||
const uint8_t DescriptorType = (wValue >> 8);
|
||||
const uint8_t DescriptorNumber = (wValue & 0xFF);
|
||||
|
||||
const void* Address = NULL;
|
||||
uint16_t Size = NO_DESCRIPTOR;
|
||||
|
||||
switch (DescriptorType)
|
||||
{
|
||||
case DTYPE_Device:
|
||||
Address = &DeviceDescriptor;
|
||||
Size = sizeof(USB_Descriptor_Device_t);
|
||||
break;
|
||||
case DTYPE_Configuration:
|
||||
Address = &ConfigurationDescriptor;
|
||||
Size = sizeof(USB_Descriptor_Configuration_t);
|
||||
break;
|
||||
case DTYPE_String:
|
||||
switch (DescriptorNumber)
|
||||
{
|
||||
case 0x00:
|
||||
Address = &LanguageString;
|
||||
Size = pgm_read_byte(&LanguageString.Header.Size);
|
||||
break;
|
||||
case 0x01:
|
||||
Address = &ManufacturerString;
|
||||
Size = pgm_read_byte(&ManufacturerString.Header.Size);
|
||||
break;
|
||||
case 0x02:
|
||||
Address = &ProductString;
|
||||
Size = pgm_read_byte(&ProductString.Header.Size);
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
*DescriptorAddress = Address;
|
||||
return Size;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,87 +1,87 @@
|
|||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2011.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.lufa-lib.org
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2011 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 Descriptors.c.
|
||||
*/
|
||||
|
||||
#ifndef _DESCRIPTORS_H_
|
||||
#define _DESCRIPTORS_H_
|
||||
|
||||
/* Includes: */
|
||||
#include <LUFA/Drivers/USB/USB.h>
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
/* Macros: */
|
||||
/** Endpoint number of the MIDI streaming data IN endpoint, for device-to-host data transfers. */
|
||||
#define MIDI_STREAM_IN_EPNUM 2
|
||||
|
||||
/** Endpoint number of the MIDI streaming data OUT endpoint, for host-to-device data transfers. */
|
||||
#define MIDI_STREAM_OUT_EPNUM 1
|
||||
|
||||
/** Endpoint size in bytes of the Audio isochronous streaming data IN and OUT endpoints. */
|
||||
#define MIDI_STREAM_EPSIZE 64
|
||||
|
||||
/* Type Defines: */
|
||||
/** Type define for the device configuration descriptor structure. This must be defined in the
|
||||
* application code, as the configuration descriptor contains several sub-descriptors which
|
||||
* vary between devices, and which describe the device's usage to the host.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
USB_Descriptor_Configuration_Header_t Config;
|
||||
|
||||
// MIDI Audio Control Interface
|
||||
USB_Descriptor_Interface_t Audio_ControlInterface;
|
||||
USB_Audio_Descriptor_Interface_AC_t Audio_ControlInterface_SPC;
|
||||
|
||||
// MIDI Audio Streaming Interface
|
||||
USB_Descriptor_Interface_t Audio_StreamInterface;
|
||||
USB_MIDI_Descriptor_AudioInterface_AS_t Audio_StreamInterface_SPC;
|
||||
USB_MIDI_Descriptor_InputJack_t MIDI_In_Jack_Emb;
|
||||
USB_MIDI_Descriptor_InputJack_t MIDI_In_Jack_Ext;
|
||||
USB_MIDI_Descriptor_OutputJack_t MIDI_Out_Jack_Emb;
|
||||
USB_MIDI_Descriptor_OutputJack_t MIDI_Out_Jack_Ext;
|
||||
USB_Audio_Descriptor_StreamEndpoint_Std_t MIDI_In_Jack_Endpoint;
|
||||
USB_MIDI_Descriptor_Jack_Endpoint_t MIDI_In_Jack_Endpoint_SPC;
|
||||
USB_Audio_Descriptor_StreamEndpoint_Std_t MIDI_Out_Jack_Endpoint;
|
||||
USB_MIDI_Descriptor_Jack_Endpoint_t MIDI_Out_Jack_Endpoint_SPC;
|
||||
} USB_Descriptor_Configuration_t;
|
||||
|
||||
/* Function Prototypes: */
|
||||
uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue,
|
||||
const uint8_t wIndex,
|
||||
const void** const DescriptorAddress)
|
||||
ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(3);
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2011.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.lufa-lib.org
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2011 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 Descriptors.c.
|
||||
*/
|
||||
|
||||
#ifndef _DESCRIPTORS_H_
|
||||
#define _DESCRIPTORS_H_
|
||||
|
||||
/* Includes: */
|
||||
#include <LUFA/Drivers/USB/USB.h>
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
/* Macros: */
|
||||
/** Endpoint number of the MIDI streaming data IN endpoint, for device-to-host data transfers. */
|
||||
#define MIDI_STREAM_IN_EPNUM 2
|
||||
|
||||
/** Endpoint number of the MIDI streaming data OUT endpoint, for host-to-device data transfers. */
|
||||
#define MIDI_STREAM_OUT_EPNUM 1
|
||||
|
||||
/** Endpoint size in bytes of the Audio isochronous streaming data IN and OUT endpoints. */
|
||||
#define MIDI_STREAM_EPSIZE 64
|
||||
|
||||
/* Type Defines: */
|
||||
/** Type define for the device configuration descriptor structure. This must be defined in the
|
||||
* application code, as the configuration descriptor contains several sub-descriptors which
|
||||
* vary between devices, and which describe the device's usage to the host.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
USB_Descriptor_Configuration_Header_t Config;
|
||||
|
||||
// MIDI Audio Control Interface
|
||||
USB_Descriptor_Interface_t Audio_ControlInterface;
|
||||
USB_Audio_Descriptor_Interface_AC_t Audio_ControlInterface_SPC;
|
||||
|
||||
// MIDI Audio Streaming Interface
|
||||
USB_Descriptor_Interface_t Audio_StreamInterface;
|
||||
USB_MIDI_Descriptor_AudioInterface_AS_t Audio_StreamInterface_SPC;
|
||||
USB_MIDI_Descriptor_InputJack_t MIDI_In_Jack_Emb;
|
||||
USB_MIDI_Descriptor_InputJack_t MIDI_In_Jack_Ext;
|
||||
USB_MIDI_Descriptor_OutputJack_t MIDI_Out_Jack_Emb;
|
||||
USB_MIDI_Descriptor_OutputJack_t MIDI_Out_Jack_Ext;
|
||||
USB_Audio_Descriptor_StreamEndpoint_Std_t MIDI_In_Jack_Endpoint;
|
||||
USB_MIDI_Descriptor_Jack_Endpoint_t MIDI_In_Jack_Endpoint_SPC;
|
||||
USB_Audio_Descriptor_StreamEndpoint_Std_t MIDI_Out_Jack_Endpoint;
|
||||
USB_MIDI_Descriptor_Jack_Endpoint_t MIDI_Out_Jack_Endpoint_SPC;
|
||||
} USB_Descriptor_Configuration_t;
|
||||
|
||||
/* Function Prototypes: */
|
||||
uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue,
|
||||
const uint8_t wIndex,
|
||||
const void** const DescriptorAddress)
|
||||
ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(3);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,245 +1,245 @@
|
|||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2011.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.fourwalledcubicle.com
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2011 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 MIDI demo. This file contains the main tasks of
|
||||
* the demo and is responsible for the initial application hardware configuration.
|
||||
*/
|
||||
|
||||
#include "MIDIToneGenerator.h"
|
||||
|
||||
/** LUFA MIDI Class driver interface configuration and state information. This structure is
|
||||
* passed to all MIDI Class driver functions, so that multiple instances of the same class
|
||||
* within a device can be differentiated from one another.
|
||||
*/
|
||||
USB_ClassInfo_MIDI_Device_t Keyboard_MIDI_Interface =
|
||||
{
|
||||
.Config =
|
||||
{
|
||||
.StreamingInterfaceNumber = 1,
|
||||
|
||||
.DataINEndpointNumber = MIDI_STREAM_IN_EPNUM,
|
||||
.DataINEndpointSize = MIDI_STREAM_EPSIZE,
|
||||
.DataINEndpointDoubleBank = false,
|
||||
|
||||
.DataOUTEndpointNumber = MIDI_STREAM_OUT_EPNUM,
|
||||
.DataOUTEndpointSize = MIDI_STREAM_EPSIZE,
|
||||
.DataOUTEndpointDoubleBank = false,
|
||||
},
|
||||
};
|
||||
|
||||
/** 8-bit 256 entry Sine Wave lookup table */
|
||||
static const uint8_t SineTable[256] =
|
||||
{
|
||||
128, 131, 134, 137, 140, 143, 146, 149, 152, 156, 159, 162, 165, 168, 171, 174,
|
||||
176, 179, 182, 185, 188, 191, 193, 196, 199, 201, 204, 206, 209, 211, 213, 216,
|
||||
218, 220, 222, 224, 226, 228, 230, 232, 234, 236, 237, 239, 240, 242, 243, 245,
|
||||
246, 247, 248, 249, 250, 251, 252, 252, 253, 254, 254, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 254, 254, 253, 252, 252, 251, 250, 249, 248, 247,
|
||||
246, 245, 243, 242, 240, 239, 237, 236, 234, 232, 230, 228, 226, 224, 222, 220,
|
||||
218, 216, 213, 211, 209, 206, 204, 201, 199, 196, 193, 191, 188, 185, 182, 179,
|
||||
176, 174, 171, 168, 165, 162, 159, 156, 152, 149, 146, 143, 140, 137, 134, 131,
|
||||
128, 124, 121, 118, 115, 112, 109, 106, 103, 99, 96, 93, 90, 87, 84, 81,
|
||||
79, 76, 73, 70, 67, 64, 62, 59, 56, 54, 51, 49, 46, 44, 42, 39,
|
||||
37, 35, 33, 31, 29, 27, 25, 23, 21, 19, 18, 16, 15, 13, 12, 10,
|
||||
9, 8, 7, 6, 5, 4, 3, 3, 2, 1, 1, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 3, 4, 5, 6, 7, 8,
|
||||
9, 10, 12, 13, 15, 16, 18, 19, 21, 23, 25, 27, 29, 31, 33, 35,
|
||||
37, 39, 42, 44, 46, 49, 51, 54, 56, 59, 62, 64, 67, 70, 73, 76,
|
||||
79, 81, 84, 87, 90, 93, 96, 99, 103, 106, 109, 112, 115, 118, 121, 124,
|
||||
};
|
||||
|
||||
/** Array of structures describing each note being generated */
|
||||
static DDSNoteData NoteData[MAX_SIMULTANEOUS_NOTES];
|
||||
|
||||
|
||||
/** Main program entry point. This routine contains the overall program flow, including initial
|
||||
* setup of all components and the main program loop.
|
||||
*/
|
||||
int main(void)
|
||||
{
|
||||
SetupHardware();
|
||||
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
|
||||
sei();
|
||||
|
||||
for (;;)
|
||||
{
|
||||
MIDI_EventPacket_t ReceivedMIDIEvent;
|
||||
if (MIDI_Device_ReceiveEventPacket(&Keyboard_MIDI_Interface, &ReceivedMIDIEvent))
|
||||
{
|
||||
if ((ReceivedMIDIEvent.Command == (MIDI_COMMAND_NOTE_ON >> 4)) && ((ReceivedMIDIEvent.Data1 & 0x0F) == 0))
|
||||
{
|
||||
DDSNoteData* LRUNoteStruct = &NoteData[0];
|
||||
|
||||
/* Find a free entry in the note table to use for the note being turned on */
|
||||
for (uint8_t i = 0; i < MAX_SIMULTANEOUS_NOTES; i++)
|
||||
{
|
||||
/* Check if the note is unused */
|
||||
if (!(NoteData[i].Pitch))
|
||||
{
|
||||
/* If a note is unused, it's age is essentially infinite - always prefer unused not entries */
|
||||
LRUNoteStruct = &NoteData[i];
|
||||
break;
|
||||
}
|
||||
else if (NoteData[i].LRUAge >= LRUNoteStruct->LRUAge)
|
||||
{
|
||||
/* If an older entry that the current entry has been found, prefer overwriting that one */
|
||||
LRUNoteStruct = &NoteData[i];
|
||||
}
|
||||
|
||||
NoteData[i].LRUAge++;
|
||||
}
|
||||
|
||||
/* Update the oldest note entry with the new note data and reset its age */
|
||||
LRUNoteStruct->Pitch = ReceivedMIDIEvent.Data2;
|
||||
LRUNoteStruct->TableIncrement = (uint32_t)(BASE_INCREMENT * SCALE_FACTOR) +
|
||||
((uint32_t)(BASE_INCREMENT * NOTE_OCTIVE_RATIO * SCALE_FACTOR) *
|
||||
(ReceivedMIDIEvent.Data2 - BASE_PITCH_INDEX));
|
||||
LRUNoteStruct->TablePosition = 0;
|
||||
LRUNoteStruct->LRUAge = 0;
|
||||
|
||||
/* Turn on indicator LED to indicate note generation activity */
|
||||
LEDs_SetAllLEDs(LEDS_LED1);
|
||||
}
|
||||
else if ((ReceivedMIDIEvent.Command == (MIDI_COMMAND_NOTE_OFF >> 4)) && ((ReceivedMIDIEvent.Data1 & 0x0F) == 0))
|
||||
{
|
||||
bool FoundActiveNote = false;
|
||||
|
||||
/* Find the note in the note table to turn off */
|
||||
for (uint8_t i = 0; i < MAX_SIMULTANEOUS_NOTES; i++)
|
||||
{
|
||||
if (NoteData[i].Pitch == ReceivedMIDIEvent.Data2)
|
||||
NoteData[i].Pitch = 0;
|
||||
else if (NoteData[i].Pitch)
|
||||
FoundActiveNote = true;
|
||||
}
|
||||
|
||||
/* If all notes off, turn off the indicator LED */
|
||||
if (!(FoundActiveNote))
|
||||
LEDs_SetAllLEDs(LEDS_NO_LEDS);
|
||||
}
|
||||
}
|
||||
|
||||
MIDI_Device_USBTask(&Keyboard_MIDI_Interface);
|
||||
USB_USBTask();
|
||||
}
|
||||
}
|
||||
|
||||
/** ISR to handle the reloading of the PWM timer with the next sample. */
|
||||
ISR(TIMER0_COMPA_vect, ISR_BLOCK)
|
||||
{
|
||||
uint16_t MixedSample = 0;
|
||||
|
||||
/* Sum together all the active notes to form a single sample */
|
||||
for (uint8_t i = 0; i < MAX_SIMULTANEOUS_NOTES; i++)
|
||||
{
|
||||
/* A non-zero pitch indicates the note is active */
|
||||
if (NoteData[i].Pitch)
|
||||
{
|
||||
/* Use the top 8 bits of the table position as the sample table index */
|
||||
uint8_t TableIndex = (NoteData[i].TablePosition >> 24);
|
||||
|
||||
/* Add the new tone sample to the accumulator and increment the table position */
|
||||
MixedSample += SineTable[TableIndex];
|
||||
NoteData[i].TablePosition += NoteData[i].TableIncrement;
|
||||
}
|
||||
}
|
||||
|
||||
/* Output clamped mixed sample value to the PWM */
|
||||
OCR3A = (MixedSample <= 0xFF) ? MixedSample : 0xFF;
|
||||
}
|
||||
|
||||
/** 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 */
|
||||
LEDs_Init();
|
||||
USB_Init();
|
||||
|
||||
/* Sample reload timer initialization */
|
||||
TIMSK0 = (1 << OCIE0A);
|
||||
OCR0A = (VIRTUAL_SAMPLE_TABLE_SIZE / 8);
|
||||
TCCR0A = (1 << WGM01); // CTC mode
|
||||
TCCR0B = (1 << CS01); // Fcpu/8 speed
|
||||
|
||||
/* Set speaker as output */
|
||||
DDRC |= (1 << 6);
|
||||
|
||||
/* PWM speaker timer initialization */
|
||||
TCCR3A = ((1 << WGM31) | (1 << COM3A1) | (1 << COM3A0)); // Set on match, clear on TOP
|
||||
TCCR3B = ((1 << WGM32) | (1 << CS30)); // Fast 8-Bit PWM, Fcpu speed
|
||||
}
|
||||
|
||||
/** Event handler for the library USB Connection event. */
|
||||
void EVENT_USB_Device_Connect(void)
|
||||
{
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING);
|
||||
|
||||
/* Set speaker as output */
|
||||
DDRC |= (1 << 6);
|
||||
}
|
||||
|
||||
/** Event handler for the library USB Disconnection event. */
|
||||
void EVENT_USB_Device_Disconnect(void)
|
||||
{
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
|
||||
|
||||
/* Disable any notes currently being played */
|
||||
for (uint8_t i = 0; i < MAX_SIMULTANEOUS_NOTES; i++)
|
||||
NoteData[i].Pitch = 0;
|
||||
|
||||
/* Set speaker as input to reduce current draw */
|
||||
DDRC &= ~(1 << 6);
|
||||
}
|
||||
|
||||
/** Event handler for the library USB Configuration Changed event. */
|
||||
void EVENT_USB_Device_ConfigurationChanged(void)
|
||||
{
|
||||
bool ConfigSuccess = true;
|
||||
|
||||
ConfigSuccess &= MIDI_Device_ConfigureEndpoints(&Keyboard_MIDI_Interface);
|
||||
|
||||
LEDs_SetAllLEDs(ConfigSuccess ? LEDMASK_USB_READY : LEDMASK_USB_ERROR);
|
||||
}
|
||||
|
||||
/** Event handler for the library USB Control Request event. */
|
||||
void EVENT_USB_Device_ControlRequest(void)
|
||||
{
|
||||
MIDI_Device_ProcessControlRequest(&Keyboard_MIDI_Interface);
|
||||
}
|
||||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2011.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.fourwalledcubicle.com
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2011 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 MIDI demo. This file contains the main tasks of
|
||||
* the demo and is responsible for the initial application hardware configuration.
|
||||
*/
|
||||
|
||||
#include "MIDIToneGenerator.h"
|
||||
|
||||
/** LUFA MIDI Class driver interface configuration and state information. This structure is
|
||||
* passed to all MIDI Class driver functions, so that multiple instances of the same class
|
||||
* within a device can be differentiated from one another.
|
||||
*/
|
||||
USB_ClassInfo_MIDI_Device_t Keyboard_MIDI_Interface =
|
||||
{
|
||||
.Config =
|
||||
{
|
||||
.StreamingInterfaceNumber = 1,
|
||||
|
||||
.DataINEndpointNumber = MIDI_STREAM_IN_EPNUM,
|
||||
.DataINEndpointSize = MIDI_STREAM_EPSIZE,
|
||||
.DataINEndpointDoubleBank = false,
|
||||
|
||||
.DataOUTEndpointNumber = MIDI_STREAM_OUT_EPNUM,
|
||||
.DataOUTEndpointSize = MIDI_STREAM_EPSIZE,
|
||||
.DataOUTEndpointDoubleBank = false,
|
||||
},
|
||||
};
|
||||
|
||||
/** 8-bit 256 entry Sine Wave lookup table */
|
||||
static const uint8_t SineTable[256] =
|
||||
{
|
||||
128, 131, 134, 137, 140, 143, 146, 149, 152, 156, 159, 162, 165, 168, 171, 174,
|
||||
176, 179, 182, 185, 188, 191, 193, 196, 199, 201, 204, 206, 209, 211, 213, 216,
|
||||
218, 220, 222, 224, 226, 228, 230, 232, 234, 236, 237, 239, 240, 242, 243, 245,
|
||||
246, 247, 248, 249, 250, 251, 252, 252, 253, 254, 254, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 254, 254, 253, 252, 252, 251, 250, 249, 248, 247,
|
||||
246, 245, 243, 242, 240, 239, 237, 236, 234, 232, 230, 228, 226, 224, 222, 220,
|
||||
218, 216, 213, 211, 209, 206, 204, 201, 199, 196, 193, 191, 188, 185, 182, 179,
|
||||
176, 174, 171, 168, 165, 162, 159, 156, 152, 149, 146, 143, 140, 137, 134, 131,
|
||||
128, 124, 121, 118, 115, 112, 109, 106, 103, 99, 96, 93, 90, 87, 84, 81,
|
||||
79, 76, 73, 70, 67, 64, 62, 59, 56, 54, 51, 49, 46, 44, 42, 39,
|
||||
37, 35, 33, 31, 29, 27, 25, 23, 21, 19, 18, 16, 15, 13, 12, 10,
|
||||
9, 8, 7, 6, 5, 4, 3, 3, 2, 1, 1, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 3, 4, 5, 6, 7, 8,
|
||||
9, 10, 12, 13, 15, 16, 18, 19, 21, 23, 25, 27, 29, 31, 33, 35,
|
||||
37, 39, 42, 44, 46, 49, 51, 54, 56, 59, 62, 64, 67, 70, 73, 76,
|
||||
79, 81, 84, 87, 90, 93, 96, 99, 103, 106, 109, 112, 115, 118, 121, 124,
|
||||
};
|
||||
|
||||
/** Array of structures describing each note being generated */
|
||||
static DDSNoteData NoteData[MAX_SIMULTANEOUS_NOTES];
|
||||
|
||||
|
||||
/** Main program entry point. This routine contains the overall program flow, including initial
|
||||
* setup of all components and the main program loop.
|
||||
*/
|
||||
int main(void)
|
||||
{
|
||||
SetupHardware();
|
||||
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
|
||||
sei();
|
||||
|
||||
for (;;)
|
||||
{
|
||||
MIDI_EventPacket_t ReceivedMIDIEvent;
|
||||
if (MIDI_Device_ReceiveEventPacket(&Keyboard_MIDI_Interface, &ReceivedMIDIEvent))
|
||||
{
|
||||
if ((ReceivedMIDIEvent.Command == (MIDI_COMMAND_NOTE_ON >> 4)) && ((ReceivedMIDIEvent.Data1 & 0x0F) == 0))
|
||||
{
|
||||
DDSNoteData* LRUNoteStruct = &NoteData[0];
|
||||
|
||||
/* Find a free entry in the note table to use for the note being turned on */
|
||||
for (uint8_t i = 0; i < MAX_SIMULTANEOUS_NOTES; i++)
|
||||
{
|
||||
/* Check if the note is unused */
|
||||
if (!(NoteData[i].Pitch))
|
||||
{
|
||||
/* If a note is unused, it's age is essentially infinite - always prefer unused not entries */
|
||||
LRUNoteStruct = &NoteData[i];
|
||||
break;
|
||||
}
|
||||
else if (NoteData[i].LRUAge >= LRUNoteStruct->LRUAge)
|
||||
{
|
||||
/* If an older entry that the current entry has been found, prefer overwriting that one */
|
||||
LRUNoteStruct = &NoteData[i];
|
||||
}
|
||||
|
||||
NoteData[i].LRUAge++;
|
||||
}
|
||||
|
||||
/* Update the oldest note entry with the new note data and reset its age */
|
||||
LRUNoteStruct->Pitch = ReceivedMIDIEvent.Data2;
|
||||
LRUNoteStruct->TableIncrement = (uint32_t)(BASE_INCREMENT * SCALE_FACTOR) +
|
||||
((uint32_t)(BASE_INCREMENT * NOTE_OCTIVE_RATIO * SCALE_FACTOR) *
|
||||
(ReceivedMIDIEvent.Data2 - BASE_PITCH_INDEX));
|
||||
LRUNoteStruct->TablePosition = 0;
|
||||
LRUNoteStruct->LRUAge = 0;
|
||||
|
||||
/* Turn on indicator LED to indicate note generation activity */
|
||||
LEDs_SetAllLEDs(LEDS_LED1);
|
||||
}
|
||||
else if ((ReceivedMIDIEvent.Command == (MIDI_COMMAND_NOTE_OFF >> 4)) && ((ReceivedMIDIEvent.Data1 & 0x0F) == 0))
|
||||
{
|
||||
bool FoundActiveNote = false;
|
||||
|
||||
/* Find the note in the note table to turn off */
|
||||
for (uint8_t i = 0; i < MAX_SIMULTANEOUS_NOTES; i++)
|
||||
{
|
||||
if (NoteData[i].Pitch == ReceivedMIDIEvent.Data2)
|
||||
NoteData[i].Pitch = 0;
|
||||
else if (NoteData[i].Pitch)
|
||||
FoundActiveNote = true;
|
||||
}
|
||||
|
||||
/* If all notes off, turn off the indicator LED */
|
||||
if (!(FoundActiveNote))
|
||||
LEDs_SetAllLEDs(LEDS_NO_LEDS);
|
||||
}
|
||||
}
|
||||
|
||||
MIDI_Device_USBTask(&Keyboard_MIDI_Interface);
|
||||
USB_USBTask();
|
||||
}
|
||||
}
|
||||
|
||||
/** ISR to handle the reloading of the PWM timer with the next sample. */
|
||||
ISR(TIMER0_COMPA_vect, ISR_BLOCK)
|
||||
{
|
||||
uint16_t MixedSample = 0;
|
||||
|
||||
/* Sum together all the active notes to form a single sample */
|
||||
for (uint8_t i = 0; i < MAX_SIMULTANEOUS_NOTES; i++)
|
||||
{
|
||||
/* A non-zero pitch indicates the note is active */
|
||||
if (NoteData[i].Pitch)
|
||||
{
|
||||
/* Use the top 8 bits of the table position as the sample table index */
|
||||
uint8_t TableIndex = (NoteData[i].TablePosition >> 24);
|
||||
|
||||
/* Add the new tone sample to the accumulator and increment the table position */
|
||||
MixedSample += SineTable[TableIndex];
|
||||
NoteData[i].TablePosition += NoteData[i].TableIncrement;
|
||||
}
|
||||
}
|
||||
|
||||
/* Output clamped mixed sample value to the PWM */
|
||||
OCR3A = (MixedSample <= 0xFF) ? MixedSample : 0xFF;
|
||||
}
|
||||
|
||||
/** 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 */
|
||||
LEDs_Init();
|
||||
USB_Init();
|
||||
|
||||
/* Sample reload timer initialization */
|
||||
TIMSK0 = (1 << OCIE0A);
|
||||
OCR0A = (VIRTUAL_SAMPLE_TABLE_SIZE / 8);
|
||||
TCCR0A = (1 << WGM01); // CTC mode
|
||||
TCCR0B = (1 << CS01); // Fcpu/8 speed
|
||||
|
||||
/* Set speaker as output */
|
||||
DDRC |= (1 << 6);
|
||||
|
||||
/* PWM speaker timer initialization */
|
||||
TCCR3A = ((1 << WGM31) | (1 << COM3A1) | (1 << COM3A0)); // Set on match, clear on TOP
|
||||
TCCR3B = ((1 << WGM32) | (1 << CS30)); // Fast 8-Bit PWM, Fcpu speed
|
||||
}
|
||||
|
||||
/** Event handler for the library USB Connection event. */
|
||||
void EVENT_USB_Device_Connect(void)
|
||||
{
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING);
|
||||
|
||||
/* Set speaker as output */
|
||||
DDRC |= (1 << 6);
|
||||
}
|
||||
|
||||
/** Event handler for the library USB Disconnection event. */
|
||||
void EVENT_USB_Device_Disconnect(void)
|
||||
{
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
|
||||
|
||||
/* Disable any notes currently being played */
|
||||
for (uint8_t i = 0; i < MAX_SIMULTANEOUS_NOTES; i++)
|
||||
NoteData[i].Pitch = 0;
|
||||
|
||||
/* Set speaker as input to reduce current draw */
|
||||
DDRC &= ~(1 << 6);
|
||||
}
|
||||
|
||||
/** Event handler for the library USB Configuration Changed event. */
|
||||
void EVENT_USB_Device_ConfigurationChanged(void)
|
||||
{
|
||||
bool ConfigSuccess = true;
|
||||
|
||||
ConfigSuccess &= MIDI_Device_ConfigureEndpoints(&Keyboard_MIDI_Interface);
|
||||
|
||||
LEDs_SetAllLEDs(ConfigSuccess ? LEDMASK_USB_READY : LEDMASK_USB_ERROR);
|
||||
}
|
||||
|
||||
/** Event handler for the library USB Control Request event. */
|
||||
void EVENT_USB_Device_ControlRequest(void)
|
||||
{
|
||||
MIDI_Device_ProcessControlRequest(&Keyboard_MIDI_Interface);
|
||||
}
|
||||
|
|
|
@ -1,108 +1,108 @@
|
|||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2011.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.fourwalledcubicle.com
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2011 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 AudioOutput.c.
|
||||
*/
|
||||
|
||||
#ifndef _AUDIO_OUTPUT_H_
|
||||
#define _AUDIO_OUTPUT_H_
|
||||
|
||||
/* Includes: */
|
||||
#include <avr/io.h>
|
||||
#include <avr/wdt.h>
|
||||
#include <avr/power.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "Descriptors.h"
|
||||
|
||||
#include <LUFA/Version.h>
|
||||
#include <LUFA/Drivers/Board/LEDs.h>
|
||||
#include <LUFA/Drivers/Peripheral/ADC.h>
|
||||
#include <LUFA/Drivers/USB/USB.h>
|
||||
#include <LUFA/Drivers/USB/Class/MIDI.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)
|
||||
|
||||
/** Scale factor used to convert the floating point frequencies and ratios into a fixed point number */
|
||||
#define SCALE_FACTOR 65536
|
||||
|
||||
/** Base (lowest) allowable MIDI note frequency */
|
||||
#define BASE_FREQUENCY 27.5
|
||||
|
||||
/** Ratio between each note in an octave */
|
||||
#define NOTE_OCTIVE_RATIO 1.05946
|
||||
|
||||
/** Lowest valid MIDI pitch index */
|
||||
#define BASE_PITCH_INDEX 21
|
||||
|
||||
/** Maximum number of MIDI notes that can be played simultaneously */
|
||||
#define MAX_SIMULTANEOUS_NOTES 3
|
||||
|
||||
/** Number of samples in the virtual sample table (can be expanded to lower maximum frequency, but allow for
|
||||
* more simultaneous notes due to the reduced amount of processing time needed when the samples are spaced out)
|
||||
*/
|
||||
#define VIRTUAL_SAMPLE_TABLE_SIZE 512
|
||||
|
||||
/** Sample table increments per period for the base MIDI note frequency */
|
||||
#define BASE_INCREMENT (((F_CPU / VIRTUAL_SAMPLE_TABLE_SIZE / 2) / BASE_FREQUENCY))
|
||||
|
||||
/* Type Defines: */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t LRUAge;
|
||||
uint8_t Pitch;
|
||||
uint32_t TableIncrement;
|
||||
uint32_t TablePosition;
|
||||
} DDSNoteData;
|
||||
|
||||
/* Function Prototypes: */
|
||||
void SetupHardware(void);
|
||||
|
||||
void EVENT_USB_Device_Connect(void);
|
||||
void EVENT_USB_Device_Disconnect(void);
|
||||
void EVENT_USB_Device_ConfigurationChanged(void);
|
||||
void EVENT_USB_Device_UnhandledControlRequest(void);
|
||||
|
||||
#endif
|
||||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2011.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.fourwalledcubicle.com
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2011 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 AudioOutput.c.
|
||||
*/
|
||||
|
||||
#ifndef _AUDIO_OUTPUT_H_
|
||||
#define _AUDIO_OUTPUT_H_
|
||||
|
||||
/* Includes: */
|
||||
#include <avr/io.h>
|
||||
#include <avr/wdt.h>
|
||||
#include <avr/power.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "Descriptors.h"
|
||||
|
||||
#include <LUFA/Version.h>
|
||||
#include <LUFA/Drivers/Board/LEDs.h>
|
||||
#include <LUFA/Drivers/Peripheral/ADC.h>
|
||||
#include <LUFA/Drivers/USB/USB.h>
|
||||
#include <LUFA/Drivers/USB/Class/MIDI.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)
|
||||
|
||||
/** Scale factor used to convert the floating point frequencies and ratios into a fixed point number */
|
||||
#define SCALE_FACTOR 65536
|
||||
|
||||
/** Base (lowest) allowable MIDI note frequency */
|
||||
#define BASE_FREQUENCY 27.5
|
||||
|
||||
/** Ratio between each note in an octave */
|
||||
#define NOTE_OCTIVE_RATIO 1.05946
|
||||
|
||||
/** Lowest valid MIDI pitch index */
|
||||
#define BASE_PITCH_INDEX 21
|
||||
|
||||
/** Maximum number of MIDI notes that can be played simultaneously */
|
||||
#define MAX_SIMULTANEOUS_NOTES 3
|
||||
|
||||
/** Number of samples in the virtual sample table (can be expanded to lower maximum frequency, but allow for
|
||||
* more simultaneous notes due to the reduced amount of processing time needed when the samples are spaced out)
|
||||
*/
|
||||
#define VIRTUAL_SAMPLE_TABLE_SIZE 512
|
||||
|
||||
/** Sample table increments per period for the base MIDI note frequency */
|
||||
#define BASE_INCREMENT (((F_CPU / VIRTUAL_SAMPLE_TABLE_SIZE / 2) / BASE_FREQUENCY))
|
||||
|
||||
/* Type Defines: */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t LRUAge;
|
||||
uint8_t Pitch;
|
||||
uint32_t TableIncrement;
|
||||
uint32_t TablePosition;
|
||||
} DDSNoteData;
|
||||
|
||||
/* Function Prototypes: */
|
||||
void SetupHardware(void);
|
||||
|
||||
void EVENT_USB_Device_Connect(void);
|
||||
void EVENT_USB_Device_Disconnect(void);
|
||||
void EVENT_USB_Device_ConfigurationChanged(void);
|
||||
void EVENT_USB_Device_UnhandledControlRequest(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,73 +1,73 @@
|
|||
/** \file
|
||||
*
|
||||
* This file contains special DoxyGen information for the generation of the main page and other special
|
||||
* documentation pages. It is not a project source file.
|
||||
*/
|
||||
|
||||
/** \mainpage MIDI Tone Generator Project
|
||||
*
|
||||
* \section Sec_Compat Project Compatibility:
|
||||
*
|
||||
* The following list indicates what microcontrollers are compatible with this project.
|
||||
*
|
||||
* - Series 7 USB AVRs (AT90USBxxx7)
|
||||
* - Series 6 USB AVRs (AT90USBxxx6)
|
||||
* - Series 4 USB AVRs (ATMEGAxxU4)
|
||||
*
|
||||
* \section Sec_Info USB Information:
|
||||
*
|
||||
* The following table gives a rundown of the USB utilization of this project.
|
||||
*
|
||||
* <table>
|
||||
* <tr>
|
||||
* <td><b>USB Mode:</b></td>
|
||||
* <td>Device</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td><b>USB Class:</b></td>
|
||||
* <td>Audio Class</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td><b>USB Subclass:</b></td>
|
||||
* <td>Standard Audio Device</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td><b>Relevant Standards:</b></td>
|
||||
* <td>USBIF Audio Class Specification \n
|
||||
* USB-MIDI Audio Class Extension Specification \n
|
||||
* General MIDI Specification</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td><b>Usable Speeds:</b></td>
|
||||
* <td>Full Speed Mode</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*
|
||||
* \section Sec_Description Project Description:
|
||||
*
|
||||
* MIDI note synthesiser project. This project implements a basic DDS frequency synthesiser, capable of producing 8-bit PWM sine
|
||||
* waves of variable frequency. When attached to a USB host, this project will allow for multiple MIDI notes to be synthesised into
|
||||
* audiable sound via PWM, using the notes sent to MIDI channel 1.
|
||||
*
|
||||
* Outgoing audio will output in 8-bit PWM onto the timer 3 output compare channel A. Decouple the audio output with a capacitor
|
||||
* and attach to a speaker to hear the audio.
|
||||
*
|
||||
* \section Sec_Options Project Options
|
||||
*
|
||||
* The following defines can be found in this project, which can control the project behaviour when defined, or changed in value.
|
||||
*
|
||||
* <table>
|
||||
* <tr>
|
||||
* <td><b>Define Name:</b></td>
|
||||
* <td><b>Location:</b></td>
|
||||
* <td><b>Description:</b></td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>MAX_SIMULTANEOUS_NOTES</td>
|
||||
* <td>MIDIToneGenerator.h</td>
|
||||
* <td>Sets the maximum number of MIDI notes that can be generated simultaneously. More notes require more processing time,
|
||||
* and thus a value that is too high will cause audiable sound distortion due to insufficient CPU time.</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*/
|
||||
|
||||
/** \file
|
||||
*
|
||||
* This file contains special DoxyGen information for the generation of the main page and other special
|
||||
* documentation pages. It is not a project source file.
|
||||
*/
|
||||
|
||||
/** \mainpage MIDI Tone Generator Project
|
||||
*
|
||||
* \section Sec_Compat Project Compatibility:
|
||||
*
|
||||
* The following list indicates what microcontrollers are compatible with this project.
|
||||
*
|
||||
* - Series 7 USB AVRs (AT90USBxxx7)
|
||||
* - Series 6 USB AVRs (AT90USBxxx6)
|
||||
* - Series 4 USB AVRs (ATMEGAxxU4)
|
||||
*
|
||||
* \section Sec_Info USB Information:
|
||||
*
|
||||
* The following table gives a rundown of the USB utilization of this project.
|
||||
*
|
||||
* <table>
|
||||
* <tr>
|
||||
* <td><b>USB Mode:</b></td>
|
||||
* <td>Device</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td><b>USB Class:</b></td>
|
||||
* <td>Audio Class</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td><b>USB Subclass:</b></td>
|
||||
* <td>Standard Audio Device</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td><b>Relevant Standards:</b></td>
|
||||
* <td>USBIF Audio Class Specification \n
|
||||
* USB-MIDI Audio Class Extension Specification \n
|
||||
* General MIDI Specification</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td><b>Usable Speeds:</b></td>
|
||||
* <td>Full Speed Mode</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*
|
||||
* \section Sec_Description Project Description:
|
||||
*
|
||||
* MIDI note synthesiser project. This project implements a basic DDS frequency synthesiser, capable of producing 8-bit PWM sine
|
||||
* waves of variable frequency. When attached to a USB host, this project will allow for multiple MIDI notes to be synthesised into
|
||||
* audiable sound via PWM, using the notes sent to MIDI channel 1.
|
||||
*
|
||||
* Outgoing audio will output in 8-bit PWM onto the timer 3 output compare channel A. Decouple the audio output with a capacitor
|
||||
* and attach to a speaker to hear the audio.
|
||||
*
|
||||
* \section Sec_Options Project Options
|
||||
*
|
||||
* The following defines can be found in this project, which can control the project behaviour when defined, or changed in value.
|
||||
*
|
||||
* <table>
|
||||
* <tr>
|
||||
* <td><b>Define Name:</b></td>
|
||||
* <td><b>Location:</b></td>
|
||||
* <td><b>Description:</b></td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>MAX_SIMULTANEOUS_NOTES</td>
|
||||
* <td>MIDIToneGenerator.h</td>
|
||||
* <td>Sets the maximum number of MIDI notes that can be generated simultaneously. More notes require more processing time,
|
||||
* and thus a value that is too high will cause audiable sound distortion due to insufficient CPU time.</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*/
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,52 +1,52 @@
|
|||
; Windows LUFA RNDIS Setup File
|
||||
; Copyright (c) 2000 Microsoft Corporation
|
||||
|
||||
[Version]
|
||||
Signature = "$Windows NT$"
|
||||
Class = Net
|
||||
ClassGUID = {4d36e972-e325-11ce-bfc1-08002be10318}
|
||||
Provider = %COMPANY%
|
||||
DriverVer = 06/21/2006,6.0.6000.16384
|
||||
;CatalogFile = device.cat
|
||||
|
||||
[Manufacturer]
|
||||
%COMPANY% = RndisDevices,NTx86,NTamd64,NTia64
|
||||
|
||||
; Decoration for x86 architecture
|
||||
[RndisDevices.NTx86]
|
||||
%RNDISDEV% = RNDIS.NT.5.1, USB\VID_03EB&PID_2069&MI_00
|
||||
|
||||
; Decoration for x64 architecture
|
||||
[RndisDevices.NTamd64]
|
||||
%RNDISDEV% = RNDIS.NT.5.1, USB\VID_03EB&PID_2069&MI_00
|
||||
|
||||
; Decoration for ia64 architecture
|
||||
[RndisDevices.NTia64]
|
||||
%RNDISDEV% = RNDIS.NT.5.1, USB\VID_03EB&PID_2069&MI_00
|
||||
|
||||
;@@@ This is the common setting for setup
|
||||
[ControlFlags]
|
||||
ExcludeFromSelect=*
|
||||
|
||||
; DDInstall section
|
||||
; References the in-build Netrndis.inf
|
||||
[RNDIS.NT.5.1]
|
||||
Characteristics = 0x84 ; NCF_PHYSICAL + NCF_HAS_UI
|
||||
BusType = 15
|
||||
; NEVER REMOVE THE FOLLOWING REFERENCE FOR NETRNDIS.INF
|
||||
include = netrndis.inf
|
||||
needs = Usb_Rndis.ndi
|
||||
AddReg = Rndis_AddReg_Vista
|
||||
|
||||
; DDInstal.Services section
|
||||
[RNDIS.NT.5.1.Services]
|
||||
include = netrndis.inf
|
||||
needs = Usb_Rndis.ndi.Services
|
||||
|
||||
; No sys copyfiles - the sys files are already in-build
|
||||
; (part of the operating system).
|
||||
|
||||
; Modify these strings for your device as needed.
|
||||
[Strings]
|
||||
COMPANY="LUFA Library"
|
||||
; Windows LUFA RNDIS Setup File
|
||||
; Copyright (c) 2000 Microsoft Corporation
|
||||
|
||||
[Version]
|
||||
Signature = "$Windows NT$"
|
||||
Class = Net
|
||||
ClassGUID = {4d36e972-e325-11ce-bfc1-08002be10318}
|
||||
Provider = %COMPANY%
|
||||
DriverVer = 06/21/2006,6.0.6000.16384
|
||||
;CatalogFile = device.cat
|
||||
|
||||
[Manufacturer]
|
||||
%COMPANY% = RndisDevices,NTx86,NTamd64,NTia64
|
||||
|
||||
; Decoration for x86 architecture
|
||||
[RndisDevices.NTx86]
|
||||
%RNDISDEV% = RNDIS.NT.5.1, USB\VID_03EB&PID_2069&MI_00
|
||||
|
||||
; Decoration for x64 architecture
|
||||
[RndisDevices.NTamd64]
|
||||
%RNDISDEV% = RNDIS.NT.5.1, USB\VID_03EB&PID_2069&MI_00
|
||||
|
||||
; Decoration for ia64 architecture
|
||||
[RndisDevices.NTia64]
|
||||
%RNDISDEV% = RNDIS.NT.5.1, USB\VID_03EB&PID_2069&MI_00
|
||||
|
||||
;@@@ This is the common setting for setup
|
||||
[ControlFlags]
|
||||
ExcludeFromSelect=*
|
||||
|
||||
; DDInstall section
|
||||
; References the in-build Netrndis.inf
|
||||
[RNDIS.NT.5.1]
|
||||
Characteristics = 0x84 ; NCF_PHYSICAL + NCF_HAS_UI
|
||||
BusType = 15
|
||||
; NEVER REMOVE THE FOLLOWING REFERENCE FOR NETRNDIS.INF
|
||||
include = netrndis.inf
|
||||
needs = Usb_Rndis.ndi
|
||||
AddReg = Rndis_AddReg_Vista
|
||||
|
||||
; DDInstal.Services section
|
||||
[RNDIS.NT.5.1.Services]
|
||||
include = netrndis.inf
|
||||
needs = Usb_Rndis.ndi.Services
|
||||
|
||||
; No sys copyfiles - the sys files are already in-build
|
||||
; (part of the operating system).
|
||||
|
||||
; Modify these strings for your device as needed.
|
||||
[Strings]
|
||||
COMPANY="LUFA Library"
|
||||
RNDISDEV="LUFA USB RNDIS Webserver"
|
|
@ -1,265 +1,265 @@
|
|||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2011.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.lufa-lib.org
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2011 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.
|
||||
*/
|
||||
|
||||
#if defined(ENABLE_DHCP_SERVER) || defined(__DOXYGEN__)
|
||||
|
||||
/** \file
|
||||
*
|
||||
* DHCP Server Application. When connected to the uIP stack, this will send IP configuration settings to a
|
||||
* DHCP client on the network.
|
||||
*/
|
||||
|
||||
#define INCLUDE_FROM_DHCPSERVERAPP_C
|
||||
#include "DHCPServerApp.h"
|
||||
|
||||
struct uip_conn* BroadcastConnection;
|
||||
|
||||
uint8_t LeasedIPs[255 / 8];
|
||||
|
||||
/** Initialization function for the DHCP server. */
|
||||
void DHCPServerApp_Init(void)
|
||||
{
|
||||
/* Listen on port 67 for DHCP server connections from hosts */
|
||||
uip_listen(HTONS(DHCP_SERVER_PORT));
|
||||
|
||||
/* Create a new UDP connection to the DHCP server port for the DHCP solicitation */
|
||||
struct uip_udp_conn* BroadcastConnection = uip_udp_new(&uip_broadcast_addr, HTONS(DHCP_CLIENT_PORT));
|
||||
|
||||
/* If the connection was successfully created, bind it to the local DHCP client port */
|
||||
if (BroadcastConnection != NULL)
|
||||
uip_udp_bind(BroadcastConnection, HTONS(DHCP_SERVER_PORT));
|
||||
|
||||
/* Set all IP addresses as unleased */
|
||||
memset(LeasedIPs, 0x00, sizeof(LeasedIPs));
|
||||
}
|
||||
|
||||
/** uIP stack application callback for the DHCP server. This function must be called each time the TCP/IP stack
|
||||
* needs a UDP packet to be processed.
|
||||
*/
|
||||
void DHCPServerApp_Callback(void)
|
||||
{
|
||||
DHCP_Header_t* const AppData = (DHCP_Header_t*)uip_appdata;
|
||||
uint16_t AppDataSize = 0;
|
||||
|
||||
/* Only process when new data arrives - don't retransmit lost packets */
|
||||
if (uip_newdata())
|
||||
{
|
||||
/* Get the DHCP message type (if present), otherwise early-abort */
|
||||
uint8_t DHCPMessageType;
|
||||
if (!(DHCPCommon_GetOption(AppData->Options, DHCP_OPTION_MSG_TYPE, &DHCPMessageType)))
|
||||
return;
|
||||
|
||||
uip_ipaddr_t Netmask, GatewayIPAddress, PreferredClientIP;
|
||||
struct uip_eth_addr RemoteMACAddress;
|
||||
uint32_t TransactionID;
|
||||
|
||||
/* Get configured network mask, gateway IP and extract out DHCP transaction ID and remote IP */
|
||||
uip_getnetmask(&Netmask);
|
||||
uip_getdraddr(&GatewayIPAddress);
|
||||
memcpy(&RemoteMACAddress, &AppData->ClientHardwareAddress, sizeof(struct uip_eth_addr));
|
||||
TransactionID = AppData->TransactionID;
|
||||
|
||||
/* Try to extract out the client's preferred IP address if it is indicated in the packet */
|
||||
if (!(DHCPCommon_GetOption(AppData->Options, DHCP_OPTION_REQ_IPADDR, &PreferredClientIP)))
|
||||
memcpy(&PreferredClientIP, &uip_all_zeroes_addr, sizeof(uip_ipaddr_t));
|
||||
|
||||
switch (DHCPMessageType)
|
||||
{
|
||||
case DHCP_DISCOVER:
|
||||
/* If no preference was made or the preferred IP is already taken, find a new address */
|
||||
if (DHCPServerApp_CheckIfIPLeased(&PreferredClientIP))
|
||||
DHCPServerApp_GetUnleasedIP(&PreferredClientIP);
|
||||
|
||||
/* Create a new DHCP OFFER packet with the offered IP address */
|
||||
AppDataSize += DHCPServerApp_FillDHCPHeader(AppData, DHCP_OFFER, &RemoteMACAddress, &PreferredClientIP, TransactionID);
|
||||
|
||||
/* Add network mask and router information to the list of DHCP OFFER packet options */
|
||||
AppDataSize += DHCPCommon_SetOption(AppData->Options, DHCP_OPTION_SUBNET_MASK,
|
||||
sizeof(uip_ipaddr_t), &Netmask);
|
||||
AppDataSize += DHCPCommon_SetOption(AppData->Options, DHCP_OPTION_ROUTER,
|
||||
sizeof(uip_ipaddr_t), &GatewayIPAddress);
|
||||
|
||||
/* Send the DHCP OFFER packet */
|
||||
uip_poll_conn(BroadcastConnection);
|
||||
memcpy(&uip_udp_conn->ripaddr, &uip_broadcast_addr, sizeof(uip_ipaddr_t));
|
||||
uip_udp_send(AppDataSize);
|
||||
|
||||
break;
|
||||
case DHCP_REQUEST:
|
||||
/* Check to see if the requested IP address has already been leased to a client */
|
||||
if (!(DHCPServerApp_CheckIfIPLeased(&PreferredClientIP)))
|
||||
{
|
||||
/* Create a new DHCP ACK packet to accept the IP address lease */
|
||||
AppDataSize += DHCPServerApp_FillDHCPHeader(AppData, DHCP_ACK, &RemoteMACAddress, &PreferredClientIP, TransactionID);
|
||||
|
||||
/* Add network mask and router information to the list of DHCP ACK packet options */
|
||||
AppDataSize += DHCPCommon_SetOption(AppData->Options, DHCP_OPTION_SUBNET_MASK,
|
||||
sizeof(uip_ipaddr_t), &Netmask);
|
||||
AppDataSize += DHCPCommon_SetOption(AppData->Options, DHCP_OPTION_ROUTER,
|
||||
sizeof(uip_ipaddr_t), &GatewayIPAddress);
|
||||
|
||||
/* Mark the requested IP as leased to a client */
|
||||
DHCPServerApp_LeaseIP(&PreferredClientIP);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Create a new DHCP NAK packet to reject the requested allocation */
|
||||
AppDataSize += DHCPServerApp_FillDHCPHeader(AppData, DHCP_NAK, &RemoteMACAddress, &uip_all_zeroes_addr, TransactionID);
|
||||
}
|
||||
|
||||
/* Send the DHCP ACK or NAK packet */
|
||||
uip_poll_conn(BroadcastConnection);
|
||||
memcpy(&uip_udp_conn->ripaddr, &uip_broadcast_addr, sizeof(uip_ipaddr_t));
|
||||
uip_udp_send(AppDataSize);
|
||||
|
||||
break;
|
||||
case DHCP_RELEASE:
|
||||
/* Mark the IP address as released in the allocation table */
|
||||
DHCPServerApp_UnleaseIP(&uip_udp_conn->ripaddr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Fills the DHCP packet response with the appropriate BOOTP header for DHCP. This fills out all the required
|
||||
* fields, leaving only the additional DHCP options to be added to the packet before it is sent to the DHCP client.
|
||||
*
|
||||
* \param[out] DHCPHeader Location in the packet buffer where the BOOTP header should be written to
|
||||
* \param[in] DHCPMessageType DHCP Message type, such as DHCP_DISCOVER
|
||||
* \param[in] ClientHardwareAddress Client MAC address the created transaction should be directed to
|
||||
* \param[in] PreferredClientIP Preferred IP that should be given to the client if it is unallocated
|
||||
* \param[in] TransactionID Transaction ID the created transaction should be associated with
|
||||
*
|
||||
* \return Size in bytes of the created DHCP packet
|
||||
*/
|
||||
static uint16_t DHCPServerApp_FillDHCPHeader(DHCP_Header_t* const DHCPHeader,
|
||||
const uint8_t DHCPMessageType,
|
||||
const struct uip_eth_addr* const ClientHardwareAddress,
|
||||
const uip_ipaddr_t* const PreferredClientIP,
|
||||
const uint32_t TransactionID)
|
||||
{
|
||||
/* Erase existing packet data so that we start will all 0x00 DHCP header data */
|
||||
memset(DHCPHeader, 0, sizeof(DHCP_Header_t));
|
||||
|
||||
DHCPHeader->Operation = DHCPMessageType;
|
||||
DHCPHeader->HardwareType = DHCP_HTYPE_ETHERNET;
|
||||
DHCPHeader->HardwareAddressLength = sizeof(MACAddress);
|
||||
DHCPHeader->Hops = 0;
|
||||
DHCPHeader->TransactionID = TransactionID;
|
||||
DHCPHeader->ElapsedSeconds = 0;
|
||||
DHCPHeader->Flags = 0;
|
||||
memcpy(&DHCPHeader->NextServerIP, &uip_hostaddr, sizeof(uip_ipaddr_t));
|
||||
memcpy(&DHCPHeader->YourIP, PreferredClientIP, sizeof(uip_ipaddr_t));
|
||||
memcpy(&DHCPHeader->ClientHardwareAddress, ClientHardwareAddress, sizeof(struct uip_eth_addr));
|
||||
DHCPHeader->Cookie = DHCP_MAGIC_COOKIE;
|
||||
|
||||
/* Add a DHCP message type and terminator options to the start of the DHCP options field */
|
||||
DHCPHeader->Options[0] = DHCP_OPTION_MSG_TYPE;
|
||||
DHCPHeader->Options[1] = 1;
|
||||
DHCPHeader->Options[2] = DHCPMessageType;
|
||||
DHCPHeader->Options[3] = DHCP_OPTION_END;
|
||||
|
||||
/* Calculate the total number of bytes added to the outgoing packet */
|
||||
return (sizeof(DHCP_Header_t) + 4);
|
||||
}
|
||||
|
||||
/** Checks to see if the nominated IP address has already been allocated to a client.
|
||||
*
|
||||
* \param[in] IPAddress IP Address whose lease status should be checked
|
||||
*
|
||||
* \pre The IP address must be within the same /24 subnet as the virtual webserver.
|
||||
*
|
||||
* \return Boolean true if the IP has already been leased to a client, false otherwise.
|
||||
*/
|
||||
static bool DHCPServerApp_CheckIfIPLeased(const uip_ipaddr_t* const IPAddress)
|
||||
{
|
||||
uint8_t Byte = (IPAddress->u8[3] / 8);
|
||||
uint8_t Mask = (1 << (IPAddress->u8[3] % 8));
|
||||
|
||||
/* Make sure that the requested IP address isn't already leased to the virtual server or another client */
|
||||
if (IPAddress->u8[3] && !(IPAddress->u8[3] == uip_hostaddr.u8[3]) && !(LeasedIPs[Byte] & Mask))
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Retrieves the next unleased IP in the IP address pool.
|
||||
*
|
||||
* \param[out] NewIPAddress Location where the generated IP Address should be stored
|
||||
*/
|
||||
static void DHCPServerApp_GetUnleasedIP(uip_ipaddr_t* const NewIPAddress)
|
||||
{
|
||||
uip_ipaddr_copy(NewIPAddress, &uip_hostaddr);
|
||||
|
||||
/** Look through the current subnet, skipping the broadcast and zero IP addresses */
|
||||
for (uint8_t IP = 1; IP < 254; IP++)
|
||||
{
|
||||
/* Update new IP address to lease with the current IP address to test */
|
||||
NewIPAddress->u8[3] = IP;
|
||||
|
||||
/* If we've found an unleased IP, abort with the updated IP stored for the called */
|
||||
if (!(DHCPServerApp_CheckIfIPLeased(NewIPAddress)))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/** Marks the given IP Address as leased in the address pool, so that it will not be
|
||||
* allocated to another client unless it is first released.
|
||||
*
|
||||
* \param[in] IPAddress IP Address to mark as leased
|
||||
*
|
||||
* \pre The IP address must be within the same /24 subnet as the virtual webserver.
|
||||
*/
|
||||
static void DHCPServerApp_LeaseIP(const uip_ipaddr_t* const IPAddress)
|
||||
{
|
||||
uint8_t Byte = (IPAddress->u8[3] / 8);
|
||||
uint8_t Mask = (1 << (IPAddress->u8[3] % 8));
|
||||
|
||||
/* Mark the IP address as leased in the allocation table */
|
||||
LeasedIPs[Byte] |= Mask;
|
||||
}
|
||||
|
||||
/** Marks the given IP Address as not leased in the address pool, so that it can be
|
||||
* allocated to another client upon request.
|
||||
*
|
||||
* \param[in] IPAddress IP Address to mark as not leased
|
||||
*
|
||||
* \pre The IP address must be within the same /24 subnet as the virtual webserver.
|
||||
*/
|
||||
static void DHCPServerApp_UnleaseIP(const uip_ipaddr_t* const IPAddress)
|
||||
{
|
||||
uint8_t Byte = (IPAddress->u8[3] / 8);
|
||||
uint8_t Mask = (1 << (IPAddress->u8[3] % 8));
|
||||
|
||||
/* Mark the IP address as unleased in the allocation table */
|
||||
LeasedIPs[Byte] &= ~Mask;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2011.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.lufa-lib.org
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2011 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.
|
||||
*/
|
||||
|
||||
#if defined(ENABLE_DHCP_SERVER) || defined(__DOXYGEN__)
|
||||
|
||||
/** \file
|
||||
*
|
||||
* DHCP Server Application. When connected to the uIP stack, this will send IP configuration settings to a
|
||||
* DHCP client on the network.
|
||||
*/
|
||||
|
||||
#define INCLUDE_FROM_DHCPSERVERAPP_C
|
||||
#include "DHCPServerApp.h"
|
||||
|
||||
struct uip_conn* BroadcastConnection;
|
||||
|
||||
uint8_t LeasedIPs[255 / 8];
|
||||
|
||||
/** Initialization function for the DHCP server. */
|
||||
void DHCPServerApp_Init(void)
|
||||
{
|
||||
/* Listen on port 67 for DHCP server connections from hosts */
|
||||
uip_listen(HTONS(DHCP_SERVER_PORT));
|
||||
|
||||
/* Create a new UDP connection to the DHCP server port for the DHCP solicitation */
|
||||
struct uip_udp_conn* BroadcastConnection = uip_udp_new(&uip_broadcast_addr, HTONS(DHCP_CLIENT_PORT));
|
||||
|
||||
/* If the connection was successfully created, bind it to the local DHCP client port */
|
||||
if (BroadcastConnection != NULL)
|
||||
uip_udp_bind(BroadcastConnection, HTONS(DHCP_SERVER_PORT));
|
||||
|
||||
/* Set all IP addresses as unleased */
|
||||
memset(LeasedIPs, 0x00, sizeof(LeasedIPs));
|
||||
}
|
||||
|
||||
/** uIP stack application callback for the DHCP server. This function must be called each time the TCP/IP stack
|
||||
* needs a UDP packet to be processed.
|
||||
*/
|
||||
void DHCPServerApp_Callback(void)
|
||||
{
|
||||
DHCP_Header_t* const AppData = (DHCP_Header_t*)uip_appdata;
|
||||
uint16_t AppDataSize = 0;
|
||||
|
||||
/* Only process when new data arrives - don't retransmit lost packets */
|
||||
if (uip_newdata())
|
||||
{
|
||||
/* Get the DHCP message type (if present), otherwise early-abort */
|
||||
uint8_t DHCPMessageType;
|
||||
if (!(DHCPCommon_GetOption(AppData->Options, DHCP_OPTION_MSG_TYPE, &DHCPMessageType)))
|
||||
return;
|
||||
|
||||
uip_ipaddr_t Netmask, GatewayIPAddress, PreferredClientIP;
|
||||
struct uip_eth_addr RemoteMACAddress;
|
||||
uint32_t TransactionID;
|
||||
|
||||
/* Get configured network mask, gateway IP and extract out DHCP transaction ID and remote IP */
|
||||
uip_getnetmask(&Netmask);
|
||||
uip_getdraddr(&GatewayIPAddress);
|
||||
memcpy(&RemoteMACAddress, &AppData->ClientHardwareAddress, sizeof(struct uip_eth_addr));
|
||||
TransactionID = AppData->TransactionID;
|
||||
|
||||
/* Try to extract out the client's preferred IP address if it is indicated in the packet */
|
||||
if (!(DHCPCommon_GetOption(AppData->Options, DHCP_OPTION_REQ_IPADDR, &PreferredClientIP)))
|
||||
memcpy(&PreferredClientIP, &uip_all_zeroes_addr, sizeof(uip_ipaddr_t));
|
||||
|
||||
switch (DHCPMessageType)
|
||||
{
|
||||
case DHCP_DISCOVER:
|
||||
/* If no preference was made or the preferred IP is already taken, find a new address */
|
||||
if (DHCPServerApp_CheckIfIPLeased(&PreferredClientIP))
|
||||
DHCPServerApp_GetUnleasedIP(&PreferredClientIP);
|
||||
|
||||
/* Create a new DHCP OFFER packet with the offered IP address */
|
||||
AppDataSize += DHCPServerApp_FillDHCPHeader(AppData, DHCP_OFFER, &RemoteMACAddress, &PreferredClientIP, TransactionID);
|
||||
|
||||
/* Add network mask and router information to the list of DHCP OFFER packet options */
|
||||
AppDataSize += DHCPCommon_SetOption(AppData->Options, DHCP_OPTION_SUBNET_MASK,
|
||||
sizeof(uip_ipaddr_t), &Netmask);
|
||||
AppDataSize += DHCPCommon_SetOption(AppData->Options, DHCP_OPTION_ROUTER,
|
||||
sizeof(uip_ipaddr_t), &GatewayIPAddress);
|
||||
|
||||
/* Send the DHCP OFFER packet */
|
||||
uip_poll_conn(BroadcastConnection);
|
||||
memcpy(&uip_udp_conn->ripaddr, &uip_broadcast_addr, sizeof(uip_ipaddr_t));
|
||||
uip_udp_send(AppDataSize);
|
||||
|
||||
break;
|
||||
case DHCP_REQUEST:
|
||||
/* Check to see if the requested IP address has already been leased to a client */
|
||||
if (!(DHCPServerApp_CheckIfIPLeased(&PreferredClientIP)))
|
||||
{
|
||||
/* Create a new DHCP ACK packet to accept the IP address lease */
|
||||
AppDataSize += DHCPServerApp_FillDHCPHeader(AppData, DHCP_ACK, &RemoteMACAddress, &PreferredClientIP, TransactionID);
|
||||
|
||||
/* Add network mask and router information to the list of DHCP ACK packet options */
|
||||
AppDataSize += DHCPCommon_SetOption(AppData->Options, DHCP_OPTION_SUBNET_MASK,
|
||||
sizeof(uip_ipaddr_t), &Netmask);
|
||||
AppDataSize += DHCPCommon_SetOption(AppData->Options, DHCP_OPTION_ROUTER,
|
||||
sizeof(uip_ipaddr_t), &GatewayIPAddress);
|
||||
|
||||
/* Mark the requested IP as leased to a client */
|
||||
DHCPServerApp_LeaseIP(&PreferredClientIP);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Create a new DHCP NAK packet to reject the requested allocation */
|
||||
AppDataSize += DHCPServerApp_FillDHCPHeader(AppData, DHCP_NAK, &RemoteMACAddress, &uip_all_zeroes_addr, TransactionID);
|
||||
}
|
||||
|
||||
/* Send the DHCP ACK or NAK packet */
|
||||
uip_poll_conn(BroadcastConnection);
|
||||
memcpy(&uip_udp_conn->ripaddr, &uip_broadcast_addr, sizeof(uip_ipaddr_t));
|
||||
uip_udp_send(AppDataSize);
|
||||
|
||||
break;
|
||||
case DHCP_RELEASE:
|
||||
/* Mark the IP address as released in the allocation table */
|
||||
DHCPServerApp_UnleaseIP(&uip_udp_conn->ripaddr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Fills the DHCP packet response with the appropriate BOOTP header for DHCP. This fills out all the required
|
||||
* fields, leaving only the additional DHCP options to be added to the packet before it is sent to the DHCP client.
|
||||
*
|
||||
* \param[out] DHCPHeader Location in the packet buffer where the BOOTP header should be written to
|
||||
* \param[in] DHCPMessageType DHCP Message type, such as DHCP_DISCOVER
|
||||
* \param[in] ClientHardwareAddress Client MAC address the created transaction should be directed to
|
||||
* \param[in] PreferredClientIP Preferred IP that should be given to the client if it is unallocated
|
||||
* \param[in] TransactionID Transaction ID the created transaction should be associated with
|
||||
*
|
||||
* \return Size in bytes of the created DHCP packet
|
||||
*/
|
||||
static uint16_t DHCPServerApp_FillDHCPHeader(DHCP_Header_t* const DHCPHeader,
|
||||
const uint8_t DHCPMessageType,
|
||||
const struct uip_eth_addr* const ClientHardwareAddress,
|
||||
const uip_ipaddr_t* const PreferredClientIP,
|
||||
const uint32_t TransactionID)
|
||||
{
|
||||
/* Erase existing packet data so that we start will all 0x00 DHCP header data */
|
||||
memset(DHCPHeader, 0, sizeof(DHCP_Header_t));
|
||||
|
||||
DHCPHeader->Operation = DHCPMessageType;
|
||||
DHCPHeader->HardwareType = DHCP_HTYPE_ETHERNET;
|
||||
DHCPHeader->HardwareAddressLength = sizeof(MACAddress);
|
||||
DHCPHeader->Hops = 0;
|
||||
DHCPHeader->TransactionID = TransactionID;
|
||||
DHCPHeader->ElapsedSeconds = 0;
|
||||
DHCPHeader->Flags = 0;
|
||||
memcpy(&DHCPHeader->NextServerIP, &uip_hostaddr, sizeof(uip_ipaddr_t));
|
||||
memcpy(&DHCPHeader->YourIP, PreferredClientIP, sizeof(uip_ipaddr_t));
|
||||
memcpy(&DHCPHeader->ClientHardwareAddress, ClientHardwareAddress, sizeof(struct uip_eth_addr));
|
||||
DHCPHeader->Cookie = DHCP_MAGIC_COOKIE;
|
||||
|
||||
/* Add a DHCP message type and terminator options to the start of the DHCP options field */
|
||||
DHCPHeader->Options[0] = DHCP_OPTION_MSG_TYPE;
|
||||
DHCPHeader->Options[1] = 1;
|
||||
DHCPHeader->Options[2] = DHCPMessageType;
|
||||
DHCPHeader->Options[3] = DHCP_OPTION_END;
|
||||
|
||||
/* Calculate the total number of bytes added to the outgoing packet */
|
||||
return (sizeof(DHCP_Header_t) + 4);
|
||||
}
|
||||
|
||||
/** Checks to see if the nominated IP address has already been allocated to a client.
|
||||
*
|
||||
* \param[in] IPAddress IP Address whose lease status should be checked
|
||||
*
|
||||
* \pre The IP address must be within the same /24 subnet as the virtual webserver.
|
||||
*
|
||||
* \return Boolean true if the IP has already been leased to a client, false otherwise.
|
||||
*/
|
||||
static bool DHCPServerApp_CheckIfIPLeased(const uip_ipaddr_t* const IPAddress)
|
||||
{
|
||||
uint8_t Byte = (IPAddress->u8[3] / 8);
|
||||
uint8_t Mask = (1 << (IPAddress->u8[3] % 8));
|
||||
|
||||
/* Make sure that the requested IP address isn't already leased to the virtual server or another client */
|
||||
if (IPAddress->u8[3] && !(IPAddress->u8[3] == uip_hostaddr.u8[3]) && !(LeasedIPs[Byte] & Mask))
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Retrieves the next unleased IP in the IP address pool.
|
||||
*
|
||||
* \param[out] NewIPAddress Location where the generated IP Address should be stored
|
||||
*/
|
||||
static void DHCPServerApp_GetUnleasedIP(uip_ipaddr_t* const NewIPAddress)
|
||||
{
|
||||
uip_ipaddr_copy(NewIPAddress, &uip_hostaddr);
|
||||
|
||||
/** Look through the current subnet, skipping the broadcast and zero IP addresses */
|
||||
for (uint8_t IP = 1; IP < 254; IP++)
|
||||
{
|
||||
/* Update new IP address to lease with the current IP address to test */
|
||||
NewIPAddress->u8[3] = IP;
|
||||
|
||||
/* If we've found an unleased IP, abort with the updated IP stored for the called */
|
||||
if (!(DHCPServerApp_CheckIfIPLeased(NewIPAddress)))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/** Marks the given IP Address as leased in the address pool, so that it will not be
|
||||
* allocated to another client unless it is first released.
|
||||
*
|
||||
* \param[in] IPAddress IP Address to mark as leased
|
||||
*
|
||||
* \pre The IP address must be within the same /24 subnet as the virtual webserver.
|
||||
*/
|
||||
static void DHCPServerApp_LeaseIP(const uip_ipaddr_t* const IPAddress)
|
||||
{
|
||||
uint8_t Byte = (IPAddress->u8[3] / 8);
|
||||
uint8_t Mask = (1 << (IPAddress->u8[3] % 8));
|
||||
|
||||
/* Mark the IP address as leased in the allocation table */
|
||||
LeasedIPs[Byte] |= Mask;
|
||||
}
|
||||
|
||||
/** Marks the given IP Address as not leased in the address pool, so that it can be
|
||||
* allocated to another client upon request.
|
||||
*
|
||||
* \param[in] IPAddress IP Address to mark as not leased
|
||||
*
|
||||
* \pre The IP address must be within the same /24 subnet as the virtual webserver.
|
||||
*/
|
||||
static void DHCPServerApp_UnleaseIP(const uip_ipaddr_t* const IPAddress)
|
||||
{
|
||||
uint8_t Byte = (IPAddress->u8[3] / 8);
|
||||
uint8_t Mask = (1 << (IPAddress->u8[3] % 8));
|
||||
|
||||
/* Mark the IP address as unleased in the allocation table */
|
||||
LeasedIPs[Byte] &= ~Mask;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -1,63 +1,63 @@
|
|||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2011.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.lufa-lib.org
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2011 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 DHCPServerApp.c.
|
||||
*/
|
||||
|
||||
#ifndef _DHCPSERVER_APP_H_
|
||||
#define _DHCPSERVER_APP_H_
|
||||
|
||||
/* Includes: */
|
||||
#include <stdio.h>
|
||||
|
||||
#include <uip.h>
|
||||
|
||||
#include "../Webserver.h"
|
||||
#include "DHCPCommon.h"
|
||||
|
||||
/* Function Prototypes: */
|
||||
void DHCPServerApp_Init(void);
|
||||
void DHCPServerApp_Callback(void);
|
||||
|
||||
#if defined(INCLUDE_FROM_DHCPSERVERAPP_C)
|
||||
static uint16_t DHCPServerApp_FillDHCPHeader(DHCP_Header_t* const DHCPHeader,
|
||||
const uint8_t DHCPMessageType,
|
||||
const struct uip_eth_addr* const ClientHardwareAddress,
|
||||
const uip_ipaddr_t* const PreferredClientIP,
|
||||
const uint32_t TransactionID);
|
||||
static bool DHCPServerApp_CheckIfIPLeased(const uip_ipaddr_t* const IPAddress);
|
||||
static void DHCPServerApp_GetUnleasedIP(uip_ipaddr_t* const NewIPAddress);
|
||||
static void DHCPServerApp_LeaseIP(const uip_ipaddr_t* const IPAddress);
|
||||
static void DHCPServerApp_UnleaseIP(const uip_ipaddr_t* const IPAddress);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2011.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.lufa-lib.org
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2011 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 DHCPServerApp.c.
|
||||
*/
|
||||
|
||||
#ifndef _DHCPSERVER_APP_H_
|
||||
#define _DHCPSERVER_APP_H_
|
||||
|
||||
/* Includes: */
|
||||
#include <stdio.h>
|
||||
|
||||
#include <uip.h>
|
||||
|
||||
#include "../Webserver.h"
|
||||
#include "DHCPCommon.h"
|
||||
|
||||
/* Function Prototypes: */
|
||||
void DHCPServerApp_Init(void);
|
||||
void DHCPServerApp_Callback(void);
|
||||
|
||||
#if defined(INCLUDE_FROM_DHCPSERVERAPP_C)
|
||||
static uint16_t DHCPServerApp_FillDHCPHeader(DHCP_Header_t* const DHCPHeader,
|
||||
const uint8_t DHCPMessageType,
|
||||
const struct uip_eth_addr* const ClientHardwareAddress,
|
||||
const uip_ipaddr_t* const PreferredClientIP,
|
||||
const uint32_t TransactionID);
|
||||
static bool DHCPServerApp_CheckIfIPLeased(const uip_ipaddr_t* const IPAddress);
|
||||
static void DHCPServerApp_GetUnleasedIP(uip_ipaddr_t* const NewIPAddress);
|
||||
static void DHCPServerApp_LeaseIP(const uip_ipaddr_t* const IPAddress);
|
||||
static void DHCPServerApp_UnleaseIP(const uip_ipaddr_t* const IPAddress);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue