Make RNDISHost demo validate the set Packet Filter to ensure that it is being sent correctly.

Add new (incomplete) StandaloneProgrammer project, using the ELM Petite FAT library to read files stored on the board's dataflash by the host.
pull/1469/head
Dean Camera 15 years ago
parent 79e54580ae
commit 9b20114555

@ -42,9 +42,10 @@
#include "MassStorage.h"
#include "Descriptors.h"
#include <LUFA/Common/Common.h> // Function Attribute, Atomic, Debug and ISR Macros
#include <LUFA/Drivers/USB/USB.h> // USB Functionality
#include <LUFA/Drivers/Board/Dataflash.h> // Dataflash chip driver
#include <LUFA/Common/Common.h> // Function Attribute, Atomic, Debug and ISR Macros
#include <LUFA/Drivers/USB/USB.h> // USB Functionality
#include <LUFA/Drivers/USB/Class/MassStorage.h> // Mass Storage Class Driver
#include <LUFA/Drivers/Board/Dataflash.h> // Dataflash chip driver
/* Preprocessor Checks: */
#if (DATAFLASH_PAGE_SIZE % 16)

@ -47,9 +47,7 @@
#include "Lib/DataflashManager.h"
#include <LUFA/Version.h>
#include <LUFA/Drivers/Board/Joystick.h>
#include <LUFA/Drivers/Board/LEDs.h>
#include <LUFA/Drivers/Board/Buttons.h>
#include <LUFA/Drivers/USB/USB.h>
#include <LUFA/Drivers/USB/Class/MassStorage.h>

@ -72,7 +72,7 @@ uint8_t RNDIS_GetEncapsulatedResponse(void* Buffer, uint16_t Length)
return USB_Host_SendControlRequest(Buffer);
}
uint8_t RNDIS_KeepAlive(void)
uint8_t RNDIS_SendKeepAlive(void)
{
uint8_t ErrorCode;

@ -203,7 +203,7 @@
uint8_t RNDIS_SendEncapsulatedCommand(void* Buffer, uint16_t Length);
uint8_t RNDIS_GetEncapsulatedResponse(void* Buffer, uint16_t Length);
uint8_t RNDIS_KeepAlive(void);
uint8_t RNDIS_SendKeepAlive(void);
uint8_t RNDIS_InitializeDevice(uint16_t HostMaxPacketSize, uint16_t* DeviceMaxPacketSize);
uint8_t RNDIS_SetRNDISProperty(uint32_t Oid, void* Buffer, uint16_t Length);
uint8_t RNDIS_QueryRNDISProperty(uint32_t Oid, void* Buffer, uint16_t MaxLength);

@ -247,6 +247,24 @@ void RNDIS_Host_Task(void)
break;
}
uint32_t RetrievedPacketFilter;
if ((ErrorCode = RNDIS_QueryRNDISProperty(OID_GEN_CURRENT_PACKET_FILTER,
&RetrievedPacketFilter, sizeof(RetrievedPacketFilter))) != HOST_SENDCONTROL_Successful)
{
printf_P(PSTR(ESC_FG_RED "Error Getting Packet Filter.\r\n"
" -- Error Code: %d\r\n" ESC_FG_WHITE), ErrorCode);
/* Indicate error via status LEDs */
LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
/* Wait until USB device disconnected */
USB_HostState = HOST_STATE_WaitForDeviceRemoval;
break;
}
if (RetrievedPacketFilter != PacketFilter)
printf("ERROR: Retrieved Packet Filter %08lx != Set Packet Filter %08lx!\r\n", RetrievedPacketFilter, PacketFilter);
uint32_t VendorID;
if ((ErrorCode = RNDIS_QueryRNDISProperty(OID_GEN_VENDOR_ID,
&VendorID, sizeof(VendorID))) != HOST_SENDCONTROL_Successful)

File diff suppressed because one or more lines are too long

@ -76,16 +76,16 @@
*/
#define HID_NON_BOOT_PROTOCOL 0x00
/** Constant for the protocol value of a HID interface descriptor, indicating that the interface supports the
* HID class Mouse boot protocol (see HID Class Specification).
*/
#define HID_BOOT_MOUSE_PROTOCOL 0x02
/** Constant for the protocol value of a HID interface descriptor, indicating that the interface supports the
* HID class Keyboard boot protocol (see HID Class Specification).
*/
#define HID_BOOT_KEYBOARD_PROTOCOL 0x01
/** Constant for the protocol value of a HID interface descriptor, indicating that the interface supports the
* HID class Mouse boot protocol (see HID Class Specification).
*/
#define HID_BOOT_MOUSE_PROTOCOL 0x02
/* Type Defines: */
/** Enum for the different types of HID reports. */
enum HID_ReportItemTypes_t

@ -29,6 +29,7 @@
* - Make new demos
* -# Keyboard/Mouse Dual Class Host
* -# Multiple-Report HID device
* -# Device/Host bridge
* - Port LUFA codebase
* -# AVR32 UC3B series microcontrollers
* -# Atmel ARM7 series microcontrollers

@ -0,0 +1,325 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2009.
dean [at] fourwalledcubicle [dot] com
www.fourwalledcubicle.com
*/
/*
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, and distribute this software
and its documentation for any purpose and without fee is hereby
granted, 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"
/* On some devices, there is a factory set internal serial number which can be automatically sent to the host as
* the device's serial number when the Device Descriptor's .SerialNumStrIndex entry is set to USE_INTERNAL_SERIAL.
* This allows the host to track a device across insertions on different ports, allowing them to retain allocated
* resources like COM port numbers and drivers. On demos using this feature, give a warning on unsupported devices
* so that the user can supply their own serial number descriptor instead or remove the USE_INTERNAL_SERIAL value
* from the Device Descriptor (forcing the host to generate a serial number for each device from the VID, PID and
* port location).
*/
#if (USE_INTERNAL_SERIAL == NO_DESCRIPTOR)
#warning USE_INTERNAL_SERIAL is not available on this AVR - please manually construct a device serial descriptor.
#endif
/** 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.
*/
USB_Descriptor_Device_t PROGMEM DeviceDescriptor =
{
.Header = {.Size = sizeof(USB_Descriptor_Device_t), .Type = DTYPE_Device},
.USBSpecification = VERSION_BCD(01.10),
.Class = 0xEF,
.SubClass = 0x02,
.Protocol = 0x01,
.Endpoint0Size = FIXED_CONTROL_ENDPOINT_SIZE,
.VendorID = 0x03EB,
.ProductID = 0x2063,
.ReleaseNumber = 0x0000,
.ManufacturerStrIndex = 0x01,
.ProductStrIndex = 0x02,
.SerialNumStrIndex = USE_INTERNAL_SERIAL,
.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.
*/
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 = 3,
.ConfigurationNumber = 1,
.ConfigurationStrIndex = NO_DESCRIPTOR,
.ConfigAttributes = USB_CONFIG_ATTR_BUSPOWERED,
.MaxPowerConsumption = USB_CONFIG_POWER_MA(100)
},
.CDC_IAD =
{
.Header = {.Size = sizeof(USB_Descriptor_Interface_Association_t), .Type = DTYPE_InterfaceAssociation},
.FirstInterfaceIndex = 0,
.TotalInterfaces = 2,
.Class = 0x02,
.SubClass = 0x02,
.Protocol = 0x01,
.IADStrIndex = NO_DESCRIPTOR
},
.CCI_Interface =
{
.Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface},
.InterfaceNumber = 0,
.AlternateSetting = 0,
.TotalEndpoints = 1,
.Class = 0x02,
.SubClass = 0x02,
.Protocol = 0x01,
.InterfaceStrIndex = NO_DESCRIPTOR
},
.CDC_Functional_IntHeader =
{
.Header = {.Size = sizeof(CDC_FUNCTIONAL_DESCRIPTOR(2)), .Type = 0x24},
.SubType = 0x00,
.Data = {0x01, 0x10}
},
.CDC_Functional_CallManagement =
{
.Header = {.Size = sizeof(CDC_FUNCTIONAL_DESCRIPTOR(2)), .Type = 0x24},
.SubType = 0x01,
.Data = {0x03, 0x01}
},
.CDC_Functional_AbstractControlManagement =
{
.Header = {.Size = sizeof(CDC_FUNCTIONAL_DESCRIPTOR(1)), .Type = 0x24},
.SubType = 0x02,
.Data = {0x06}
},
.CDC_Functional_Union =
{
.Header = {.Size = sizeof(CDC_FUNCTIONAL_DESCRIPTOR(2)), .Type = 0x24},
.SubType = 0x06,
.Data = {0x00, 0x01}
},
.ManagementEndpoint =
{
.Header = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint},
.EndpointAddress = (ENDPOINT_DESCRIPTOR_DIR_IN | CDC_NOTIFICATION_EPNUM),
.Attributes = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
.EndpointSize = CDC_NOTIFICATION_EPSIZE,
.PollingIntervalMS = 0xFF
},
.DCI_Interface =
{
.Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface},
.InterfaceNumber = 1,
.AlternateSetting = 0,
.TotalEndpoints = 2,
.Class = 0x0A,
.SubClass = 0x00,
.Protocol = 0x00,
.InterfaceStrIndex = NO_DESCRIPTOR
},
.DataOutEndpoint =
{
.Header = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint},
.EndpointAddress = (ENDPOINT_DESCRIPTOR_DIR_OUT | CDC_RX_EPNUM),
.Attributes = (EP_TYPE_BULK | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
.EndpointSize = CDC_TXRX_EPSIZE,
.PollingIntervalMS = 0x00
},
.DataInEndpoint =
{
.Header = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint},
.EndpointAddress = (ENDPOINT_DESCRIPTOR_DIR_IN | CDC_TX_EPNUM),
.Attributes = (EP_TYPE_BULK | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
.EndpointSize = CDC_TXRX_EPSIZE,
.PollingIntervalMS = 0x00
},
.MSInterface =
{
.Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface},
.InterfaceNumber = 2,
.AlternateSetting = 0,
.TotalEndpoints = 2,
.Class = 0x08,
.SubClass = 0x06,
.Protocol = 0x50,
.InterfaceStrIndex = NO_DESCRIPTOR
},
.MSDataInEndpoint =
{
.Header = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint},
.EndpointAddress = (ENDPOINT_DESCRIPTOR_DIR_IN | MASS_STORAGE_IN_EPNUM),
.Attributes = (EP_TYPE_BULK | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
.EndpointSize = MASS_STORAGE_IO_EPSIZE,
.PollingIntervalMS = 0x00
},
.MSDataOutEndpoint =
{
.Header = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint},
.EndpointAddress = (ENDPOINT_DESCRIPTOR_DIR_OUT | MASS_STORAGE_OUT_EPNUM),
.Attributes = (EP_TYPE_BULK | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
.EndpointSize = MASS_STORAGE_IO_EPSIZE,
.PollingIntervalMS = 0x00
}
};
/** 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.
*/
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.
*/
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.
*/
USB_Descriptor_String_t PROGMEM ProductString =
{
.Header = {.Size = USB_STRING_LEN(26), .Type = DTYPE_String},
.UnicodeString = L"LUFA Standalone Programmer"
};
/** 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, void** const DescriptorAddress)
{
const uint8_t DescriptorType = (wValue >> 8);
const uint8_t DescriptorNumber = (wValue & 0xFF);
void* Address = NULL;
uint16_t Size = NO_DESCRIPTOR;
switch (DescriptorType)
{
case DTYPE_Device:
Address = (void*)&DeviceDescriptor;
Size = sizeof(USB_Descriptor_Device_t);
break;
case DTYPE_Configuration:
Address = (void*)&ConfigurationDescriptor;
Size = sizeof(USB_Descriptor_Configuration_t);
break;
case DTYPE_String:
switch (DescriptorNumber)
{
case 0x00:
Address = (void*)&LanguageString;
Size = pgm_read_byte(&LanguageString.Header.Size);
break;
case 0x01:
Address = (void*)&ManufacturerString;
Size = pgm_read_byte(&ManufacturerString.Header.Size);
break;
case 0x02:
Address = (void*)&ProductString;
Size = pgm_read_byte(&ProductString.Header.Size);
break;
}
break;
}
*DescriptorAddress = Address;
return Size;
}

@ -0,0 +1,98 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2009.
dean [at] fourwalledcubicle [dot] com
www.fourwalledcubicle.com
*/
/*
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, and distribute this software
and its documentation for any purpose and without fee is hereby
granted, 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 <avr/pgmspace.h>
#include <LUFA/Drivers/USB/USB.h>
#include <LUFA/Drivers/USB/Class/MassStorage.h>
#include <LUFA/Drivers/USB/Class/CDC.h>
/* Macros: */
/** Endpoint number of the CDC device-to-host notification IN endpoint. */
#define CDC_NOTIFICATION_EPNUM 5
/** Endpoint number of the CDC device-to-host data IN endpoint. */
#define CDC_TX_EPNUM 1
/** Endpoint number of the CDC host-to-device data OUT endpoint. */
#define CDC_RX_EPNUM 2
/** Size in bytes of the CDC device-to-host notification IN endpoint. */
#define CDC_NOTIFICATION_EPSIZE 8
/** Size in bytes of the CDC data IN and OUT endpoints. */
#define CDC_TXRX_EPSIZE 16
/** Endpoint number of the Mass Storage device-to-host data IN endpoint. */
#define MASS_STORAGE_IN_EPNUM 3
/** Endpoint number of the Mass Storage host-to-device data OUT endpoint. */
#define MASS_STORAGE_OUT_EPNUM 4
/** Size in bytes of the Mass Storage data endpoints. */
#define MASS_STORAGE_IO_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;
USB_Descriptor_Interface_Association_t CDC_IAD;
USB_Descriptor_Interface_t CCI_Interface;
CDC_FUNCTIONAL_DESCRIPTOR(2) CDC_Functional_IntHeader;
CDC_FUNCTIONAL_DESCRIPTOR(2) CDC_Functional_CallManagement;
CDC_FUNCTIONAL_DESCRIPTOR(1) CDC_Functional_AbstractControlManagement;
CDC_FUNCTIONAL_DESCRIPTOR(2) CDC_Functional_Union;
USB_Descriptor_Endpoint_t ManagementEndpoint;
USB_Descriptor_Interface_t DCI_Interface;
USB_Descriptor_Endpoint_t DataOutEndpoint;
USB_Descriptor_Endpoint_t DataInEndpoint;
USB_Descriptor_Interface_t MSInterface;
USB_Descriptor_Endpoint_t MSDataInEndpoint;
USB_Descriptor_Endpoint_t MSDataOutEndpoint;
} USB_Descriptor_Configuration_t;
/* Function Prototypes: */
uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, const uint8_t wIndex, void** const DescriptorAddress)
ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(3);
#endif

@ -0,0 +1,525 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2009.
dean [at] fourwalledcubicle [dot] com
www.fourwalledcubicle.com
*/
/*
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, and distribute this software
and its documentation for any purpose and without fee is hereby
granted, 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
*
* Functions to manage the physical dataflash media, including reading and writing of
* blocks of data. These functions are called by the SCSI layer when data must be stored
* or retrieved to/from the physical storage media. If a different media is used (such
* as a SD card or EEPROM), functions similar to these will need to be generated.
*/
#define INCLUDE_FROM_DATAFLASHMANAGER_C
#include "DataflashManager.h"
/** Writes blocks (OS blocks, not Dataflash pages) to the storage medium, the board dataflash IC(s), from
* the pre-selected data OUT endpoint. This routine reads in OS sized blocks from the endpoint and writes
* them to the dataflash in Dataflash page sized blocks.
*
* \param[in] MSInterfaceInfo Pointer to a structure containing a Mass Storage Class configuration and state
* \param[in] BlockAddress Data block starting address for the write sequence
* \param[in] TotalBlocks Number of blocks of data to write
*/
void DataflashManager_WriteBlocks(USB_ClassInfo_MS_Device_t* MSInterfaceInfo, const uint32_t BlockAddress, uint16_t TotalBlocks)
{
uint16_t CurrDFPage = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) / DATAFLASH_PAGE_SIZE);
uint16_t CurrDFPageByte = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) % DATAFLASH_PAGE_SIZE);
uint8_t CurrDFPageByteDiv16 = (CurrDFPageByte >> 4);
bool UsingSecondBuffer = false;
/* Select the correct starting Dataflash IC for the block requested */
Dataflash_SelectChipFromPage(CurrDFPage);
#if (DATAFLASH_PAGE_SIZE > VIRTUAL_MEMORY_BLOCK_SIZE)
/* Copy selected dataflash's current page contents to the dataflash buffer */
Dataflash_SendByte(DF_CMD_MAINMEMTOBUFF1);
Dataflash_SendAddressBytes(CurrDFPage, 0);
Dataflash_WaitWhileBusy();
#endif
/* Send the dataflash buffer write command */
Dataflash_SendByte(DF_CMD_BUFF1WRITE);
Dataflash_SendAddressBytes(0, CurrDFPageByte);
/* Wait until endpoint is ready before continuing */
if (Endpoint_WaitUntilReady())
return;
while (TotalBlocks)
{
uint8_t BytesInBlockDiv16 = 0;
/* Write an endpoint packet sized data block to the dataflash */
while (BytesInBlockDiv16 < (VIRTUAL_MEMORY_BLOCK_SIZE >> 4))
{
/* Check if the endpoint is currently empty */
if (!(Endpoint_IsReadWriteAllowed()))
{
/* Clear the current endpoint bank */
Endpoint_ClearOUT();
/* Wait until the host has sent another packet */
if (Endpoint_WaitUntilReady())
return;
}
/* Check if end of dataflash page reached */
if (CurrDFPageByteDiv16 == (DATAFLASH_PAGE_SIZE >> 4))
{
/* Write the dataflash buffer contents back to the dataflash page */
Dataflash_WaitWhileBusy();
Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_BUFF2TOMAINMEMWITHERASE : DF_CMD_BUFF1TOMAINMEMWITHERASE);
Dataflash_SendAddressBytes(CurrDFPage, 0);
/* Reset the dataflash buffer counter, increment the page counter */
CurrDFPageByteDiv16 = 0;
CurrDFPage++;
/* Once all the dataflash ICs have had their first buffers filled, switch buffers to maintain throughput */
if (Dataflash_GetSelectedChip() == DATAFLASH_CHIP_MASK(DATAFLASH_TOTALCHIPS))
UsingSecondBuffer = !(UsingSecondBuffer);
/* Select the next dataflash chip based on the new dataflash page index */
Dataflash_SelectChipFromPage(CurrDFPage);
#if (DATAFLASH_PAGE_SIZE > VIRTUAL_MEMORY_BLOCK_SIZE)
/* If less than one dataflash page remaining, copy over the existing page to preserve trailing data */
if ((TotalBlocks * (VIRTUAL_MEMORY_BLOCK_SIZE >> 4)) < (DATAFLASH_PAGE_SIZE >> 4))
{
/* Copy selected dataflash's current page contents to the dataflash buffer */
Dataflash_WaitWhileBusy();
Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_MAINMEMTOBUFF2 : DF_CMD_MAINMEMTOBUFF1);
Dataflash_SendAddressBytes(CurrDFPage, 0);
Dataflash_WaitWhileBusy();
}
#endif
/* Send the dataflash buffer write command */
Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_BUFF2WRITE : DF_CMD_BUFF1WRITE);
Dataflash_SendAddressBytes(0, 0);
}
/* Write one 16-byte chunk of data to the dataflash */
Dataflash_SendByte(Endpoint_Read_Byte());
Dataflash_SendByte(Endpoint_Read_Byte());
Dataflash_SendByte(Endpoint_Read_Byte());
Dataflash_SendByte(Endpoint_Read_Byte());
Dataflash_SendByte(Endpoint_Read_Byte());
Dataflash_SendByte(Endpoint_Read_Byte());
Dataflash_SendByte(Endpoint_Read_Byte());
Dataflash_SendByte(Endpoint_Read_Byte());
Dataflash_SendByte(Endpoint_Read_Byte());
Dataflash_SendByte(Endpoint_Read_Byte());
Dataflash_SendByte(Endpoint_Read_Byte());
Dataflash_SendByte(Endpoint_Read_Byte());
Dataflash_SendByte(Endpoint_Read_Byte());
Dataflash_SendByte(Endpoint_Read_Byte());
Dataflash_SendByte(Endpoint_Read_Byte());
Dataflash_SendByte(Endpoint_Read_Byte());
/* Increment the dataflash page 16 byte block counter */
CurrDFPageByteDiv16++;
/* Increment the block 16 byte block counter */
BytesInBlockDiv16++;
/* Check if the current command is being aborted by the host */
if (MSInterfaceInfo->State.IsMassStoreReset)
return;
}
/* Decrement the blocks remaining counter and reset the sub block counter */
TotalBlocks--;
}
/* Write the dataflash buffer contents back to the dataflash page */
Dataflash_WaitWhileBusy();
Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_BUFF2TOMAINMEMWITHERASE : DF_CMD_BUFF1TOMAINMEMWITHERASE);
Dataflash_SendAddressBytes(CurrDFPage, 0x00);
Dataflash_WaitWhileBusy();
/* If the endpoint is empty, clear it ready for the next packet from the host */
if (!(Endpoint_IsReadWriteAllowed()))
Endpoint_ClearOUT();
/* Deselect all dataflash chips */
Dataflash_DeselectChip();
}
/** Reads blocks (OS blocks, not Dataflash pages) from the storage medium, the board dataflash IC(s), into
* the pre-selected data IN endpoint. This routine reads in Dataflash page sized blocks from the Dataflash
* and writes them in OS sized blocks to the endpoint.
*
* \param[in] MSInterfaceInfo Pointer to a structure containing a Mass Storage Class configuration and state
* \param[in] BlockAddress Data block starting address for the read sequence
* \param[in] TotalBlocks Number of blocks of data to read
*/
void DataflashManager_ReadBlocks(USB_ClassInfo_MS_Device_t* MSInterfaceInfo, const uint32_t BlockAddress, uint16_t TotalBlocks)
{
uint16_t CurrDFPage = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) / DATAFLASH_PAGE_SIZE);
uint16_t CurrDFPageByte = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) % DATAFLASH_PAGE_SIZE);
uint8_t CurrDFPageByteDiv16 = (CurrDFPageByte >> 4);
/* Select the correct starting Dataflash IC for the block requested */
Dataflash_SelectChipFromPage(CurrDFPage);
/* Send the dataflash main memory page read command */
Dataflash_SendByte(DF_CMD_MAINMEMPAGEREAD);
Dataflash_SendAddressBytes(CurrDFPage, CurrDFPageByte);
Dataflash_SendByte(0x00);
Dataflash_SendByte(0x00);
Dataflash_SendByte(0x00);
Dataflash_SendByte(0x00);
/* Wait until endpoint is ready before continuing */
if (Endpoint_WaitUntilReady())
return;
while (TotalBlocks)
{
uint8_t BytesInBlockDiv16 = 0;
/* Write an endpoint packet sized data block to the dataflash */
while (BytesInBlockDiv16 < (VIRTUAL_MEMORY_BLOCK_SIZE >> 4))
{
/* Check if the endpoint is currently full */
if (!(Endpoint_IsReadWriteAllowed()))
{
/* Clear the endpoint bank to send its contents to the host */
Endpoint_ClearIN();
/* Wait until the endpoint is ready for more data */
if (Endpoint_WaitUntilReady())
return;
}
/* Check if end of dataflash page reached */
if (CurrDFPageByteDiv16 == (DATAFLASH_PAGE_SIZE >> 4))
{
/* Reset the dataflash buffer counter, increment the page counter */
CurrDFPageByteDiv16 = 0;
CurrDFPage++;
/* Select the next dataflash chip based on the new dataflash page index */
Dataflash_SelectChipFromPage(CurrDFPage);
/* Send the dataflash main memory page read command */
Dataflash_SendByte(DF_CMD_MAINMEMPAGEREAD);
Dataflash_SendAddressBytes(CurrDFPage, 0);
Dataflash_SendByte(0x00);
Dataflash_SendByte(0x00);
Dataflash_SendByte(0x00);
Dataflash_SendByte(0x00);
}
/* Read one 16-byte chunk of data from the dataflash */
Endpoint_Write_Byte(Dataflash_ReceiveByte());
Endpoint_Write_Byte(Dataflash_ReceiveByte());
Endpoint_Write_Byte(Dataflash_ReceiveByte());
Endpoint_Write_Byte(Dataflash_ReceiveByte());
Endpoint_Write_Byte(Dataflash_ReceiveByte());
Endpoint_Write_Byte(Dataflash_ReceiveByte());
Endpoint_Write_Byte(Dataflash_ReceiveByte());
Endpoint_Write_Byte(Dataflash_ReceiveByte());
Endpoint_Write_Byte(Dataflash_ReceiveByte());
Endpoint_Write_Byte(Dataflash_ReceiveByte());
Endpoint_Write_Byte(Dataflash_ReceiveByte());
Endpoint_Write_Byte(Dataflash_ReceiveByte());
Endpoint_Write_Byte(Dataflash_ReceiveByte());
Endpoint_Write_Byte(Dataflash_ReceiveByte());
Endpoint_Write_Byte(Dataflash_ReceiveByte());
Endpoint_Write_Byte(Dataflash_ReceiveByte());
/* Increment the dataflash page 16 byte block counter */
CurrDFPageByteDiv16++;
/* Increment the block 16 byte block counter */
BytesInBlockDiv16++;
/* Check if the current command is being aborted by the host */
if (MSInterfaceInfo->State.IsMassStoreReset)
return;
}
/* Decrement the blocks remaining counter */
TotalBlocks--;
}
/* If the endpoint is full, send its contents to the host */
if (!(Endpoint_IsReadWriteAllowed()))
Endpoint_ClearIN();
/* Deselect all dataflash chips */
Dataflash_DeselectChip();
}
/** Writes blocks (OS blocks, not Dataflash pages) to the storage medium, the board dataflash IC(s), from
* the a given RAM buffer. This routine reads in OS sized blocks from the buffer and writes them to the
* dataflash in Dataflash page sized blocks. This can be linked to FAT libraries to write files to the
* dataflash.
*
* \param[in] BlockAddress Data block starting address for the write sequence
* \param[in] TotalBlocks Number of blocks of data to write
* \param[in] BufferPtr Pointer to the data source RAM buffer
*/
void DataflashManager_WriteBlocks_RAM(const uint32_t BlockAddress, uint16_t TotalBlocks, uint8_t* BufferPtr)
{
uint16_t CurrDFPage = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) / DATAFLASH_PAGE_SIZE);
uint16_t CurrDFPageByte = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) % DATAFLASH_PAGE_SIZE);
uint8_t CurrDFPageByteDiv16 = (CurrDFPageByte >> 4);
bool UsingSecondBuffer = false;
/* Select the correct starting Dataflash IC for the block requested */
Dataflash_SelectChipFromPage(CurrDFPage);
#if (DATAFLASH_PAGE_SIZE > VIRTUAL_MEMORY_BLOCK_SIZE)
/* Copy selected dataflash's current page contents to the dataflash buffer */
Dataflash_SendByte(DF_CMD_MAINMEMTOBUFF1);
Dataflash_SendAddressBytes(CurrDFPage, 0);
Dataflash_WaitWhileBusy();
#endif
/* Send the dataflash buffer write command */
Dataflash_SendByte(DF_CMD_BUFF1WRITE);
Dataflash_SendAddressBytes(0, CurrDFPageByte);
while (TotalBlocks)
{
uint8_t BytesInBlockDiv16 = 0;
/* Write an endpoint packet sized data block to the dataflash */
while (BytesInBlockDiv16 < (VIRTUAL_MEMORY_BLOCK_SIZE >> 4))
{
/* Check if end of dataflash page reached */
if (CurrDFPageByteDiv16 == (DATAFLASH_PAGE_SIZE >> 4))
{
/* Write the dataflash buffer contents back to the dataflash page */
Dataflash_WaitWhileBusy();
Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_BUFF2TOMAINMEMWITHERASE : DF_CMD_BUFF1TOMAINMEMWITHERASE);
Dataflash_SendAddressBytes(CurrDFPage, 0);
/* Reset the dataflash buffer counter, increment the page counter */
CurrDFPageByteDiv16 = 0;
CurrDFPage++;
/* Once all the dataflash ICs have had their first buffers filled, switch buffers to maintain throughput */
if (Dataflash_GetSelectedChip() == DATAFLASH_CHIP_MASK(DATAFLASH_TOTALCHIPS))
UsingSecondBuffer = !(UsingSecondBuffer);
/* Select the next dataflash chip based on the new dataflash page index */
Dataflash_SelectChipFromPage(CurrDFPage);
#if (DATAFLASH_PAGE_SIZE > VIRTUAL_MEMORY_BLOCK_SIZE)
/* If less than one dataflash page remaining, copy over the existing page to preserve trailing data */
if ((TotalBlocks * (VIRTUAL_MEMORY_BLOCK_SIZE >> 4)) < (DATAFLASH_PAGE_SIZE >> 4))
{
/* Copy selected dataflash's current page contents to the dataflash buffer */
Dataflash_WaitWhileBusy();
Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_MAINMEMTOBUFF2 : DF_CMD_MAINMEMTOBUFF1);
Dataflash_SendAddressBytes(CurrDFPage, 0);
Dataflash_WaitWhileBusy();
}
#endif
/* Send the dataflash buffer write command */
Dataflash_ToggleSelectedChipCS();
Dataflash_SendByte(DF_CMD_BUFF1WRITE);
Dataflash_SendAddressBytes(0, 0);
}
/* Write one 16-byte chunk of data to the dataflash */
for (uint8_t ByteNum = 0; ByteNum < 16; ByteNum++)
Dataflash_SendByte(*(BufferPtr++));
/* Increment the dataflash page 16 byte block counter */
CurrDFPageByteDiv16++;
/* Increment the block 16 byte block counter */
BytesInBlockDiv16++;
}
/* Decrement the blocks remaining counter and reset the sub block counter */
TotalBlocks--;
}
/* Write the dataflash buffer contents back to the dataflash page */
Dataflash_WaitWhileBusy();
Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_BUFF2TOMAINMEMWITHERASE : DF_CMD_BUFF1TOMAINMEMWITHERASE);
Dataflash_SendAddressBytes(CurrDFPage, 0x00);
Dataflash_WaitWhileBusy();
/* Deselect all dataflash chips */
Dataflash_DeselectChip();
}
/** Reads blocks (OS blocks, not Dataflash pages) from the storage medium, the board dataflash IC(s), into
* the a preallocated RAM buffer. This routine reads in Dataflash page sized blocks from the Dataflash
* and writes them in OS sized blocks to the given buffer. This can be linked to FAT libraries to read
* the files stored on the dataflash.
*
* \param[in] BlockAddress Data block starting address for the read sequence
* \param[in] TotalBlocks Number of blocks of data to read
* \param[out] BufferPtr Pointer to the data destination RAM buffer
*/
void DataflashManager_ReadBlocks_RAM(const uint32_t BlockAddress, uint16_t TotalBlocks, uint8_t* BufferPtr)
{
uint16_t CurrDFPage = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) / DATAFLASH_PAGE_SIZE);
uint16_t CurrDFPageByte = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) % DATAFLASH_PAGE_SIZE);
uint8_t CurrDFPageByteDiv16 = (CurrDFPageByte >> 4);
/* Select the correct starting Dataflash IC for the block requested */
Dataflash_SelectChipFromPage(CurrDFPage);
/* Send the dataflash main memory page read command */
Dataflash_SendByte(DF_CMD_MAINMEMPAGEREAD);
Dataflash_SendAddressBytes(CurrDFPage, CurrDFPageByte);
Dataflash_SendByte(0x00);
Dataflash_SendByte(0x00);
Dataflash_SendByte(0x00);
Dataflash_SendByte(0x00);
while (TotalBlocks)
{
uint8_t BytesInBlockDiv16 = 0;
/* Write an endpoint packet sized data block to the dataflash */
while (BytesInBlockDiv16 < (VIRTUAL_MEMORY_BLOCK_SIZE >> 4))
{
/* Check if end of dataflash page reached */
if (CurrDFPageByteDiv16 == (DATAFLASH_PAGE_SIZE >> 4))
{
/* Reset the dataflash buffer counter, increment the page counter */
CurrDFPageByteDiv16 = 0;
CurrDFPage++;
/* Select the next dataflash chip based on the new dataflash page index */
Dataflash_SelectChipFromPage(CurrDFPage);
/* Send the dataflash main memory page read command */
Dataflash_SendByte(DF_CMD_MAINMEMPAGEREAD);
Dataflash_SendAddressBytes(CurrDFPage, 0);
Dataflash_SendByte(0x00);
Dataflash_SendByte(0x00);
Dataflash_SendByte(0x00);
Dataflash_SendByte(0x00);
}
/* Read one 16-byte chunk of data from the dataflash */
for (uint8_t ByteNum = 0; ByteNum < 16; ByteNum++)
*(BufferPtr++) = Dataflash_ReceiveByte();
/* Increment the dataflash page 16 byte block counter */
CurrDFPageByteDiv16++;
/* Increment the block 16 byte block counter */
BytesInBlockDiv16++;
}
/* Decrement the blocks remaining counter */
TotalBlocks--;
}
/* Deselect all dataflash chips */
Dataflash_DeselectChip();
}
/** Disables the dataflash memory write protection bits on the board Dataflash ICs, if enabled. */
void DataflashManager_ResetDataflashProtections(void)
{
/* Select first dataflash chip, send the read status register command */
Dataflash_SelectChip(DATAFLASH_CHIP1);
Dataflash_SendByte(DF_CMD_GETSTATUS);
/* Check if sector protection is enabled */
if (Dataflash_ReceiveByte() & DF_STATUS_SECTORPROTECTION_ON)
{
Dataflash_ToggleSelectedChipCS();
/* Send the commands to disable sector protection */
Dataflash_SendByte(DF_CMD_SECTORPROTECTIONOFF[0]);
Dataflash_SendByte(DF_CMD_SECTORPROTECTIONOFF[1]);
Dataflash_SendByte(DF_CMD_SECTORPROTECTIONOFF[2]);
Dataflash_SendByte(DF_CMD_SECTORPROTECTIONOFF[3]);
}
/* Select second dataflash chip (if present on selected board), send read status register command */
#if (DATAFLASH_TOTALCHIPS == 2)
Dataflash_SelectChip(DATAFLASH_CHIP2);
Dataflash_SendByte(DF_CMD_GETSTATUS);
/* Check if sector protection is enabled */
if (Dataflash_ReceiveByte() & DF_STATUS_SECTORPROTECTION_ON)
{
Dataflash_ToggleSelectedChipCS();
/* Send the commands to disable sector protection */
Dataflash_SendByte(DF_CMD_SECTORPROTECTIONOFF[0]);
Dataflash_SendByte(DF_CMD_SECTORPROTECTIONOFF[1]);
Dataflash_SendByte(DF_CMD_SECTORPROTECTIONOFF[2]);
Dataflash_SendByte(DF_CMD_SECTORPROTECTIONOFF[3]);
}
#endif
/* Deselect current dataflash chip */
Dataflash_DeselectChip();
}
/** Performs a simple test on the attached Dataflash IC(s) to ensure that they are working.
*
* \return Boolean true if all media chips are working, false otherwise
*/
bool DataflashManager_CheckDataflashOperation(void)
{
uint8_t ReturnByte;
/* Test first Dataflash IC is present and responding to commands */
Dataflash_SelectChip(DATAFLASH_CHIP1);
Dataflash_SendByte(DF_CMD_READMANUFACTURERDEVICEINFO);
ReturnByte = Dataflash_ReceiveByte();
Dataflash_DeselectChip();
/* If returned data is invalid, fail the command */
if (ReturnByte != DF_MANUFACTURER_ATMEL)
return false;
#if (DATAFLASH_TOTALCHIPS == 2)
/* Test second Dataflash IC is present and responding to commands */
Dataflash_SelectChip(DATAFLASH_CHIP2);
Dataflash_SendByte(DF_CMD_READMANUFACTURERDEVICEINFO);
ReturnByte = Dataflash_ReceiveByte();
Dataflash_DeselectChip();
/* If returned data is invalid, fail the command */
if (ReturnByte != DF_MANUFACTURER_ATMEL)
return false;
#endif
return true;
}

@ -0,0 +1,81 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2009.
dean [at] fourwalledcubicle [dot] com
www.fourwalledcubicle.com
*/
/*
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, and distribute this software
and its documentation for any purpose and without fee is hereby
granted, 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 DataflashManager.c.
*/
#ifndef _DATAFLASH_MANAGER_H
#define _DATAFLASH_MANAGER_H
/* Includes: */
#include <avr/io.h>
#include "StandaloneProgrammer.h"
#include "Descriptors.h"
#include <LUFA/Common/Common.h> // Function Attribute, Atomic, Debug and ISR Macros
#include <LUFA/Drivers/USB/USB.h> // USB Functionality
#include <LUFA/Drivers/USB/Class/MassStorage.h> // Mass Storage Class Driver
#include <LUFA/Drivers/Board/Dataflash.h> // Dataflash chip driver
/* Preprocessor Checks: */
#if (DATAFLASH_PAGE_SIZE % 16)
#error Dataflash page size must be a multiple of 16 bytes.
#endif
/* Defines: */
/** Total number of bytes of the storage medium, comprised of one or more dataflash ICs. */
#define VIRTUAL_MEMORY_BYTES ((uint32_t)DATAFLASH_PAGES * DATAFLASH_PAGE_SIZE * DATAFLASH_TOTALCHIPS)
/** Block size of the device. This is kept at 512 to remain compatible with the OS despite the underlying
* storage media (Dataflash) using a different native block size. Do not change this value.
*/
#define VIRTUAL_MEMORY_BLOCK_SIZE 512
/** Total number of blocks of the virtual memory for reporting to the host as the device's total capacity. Do not
* change this value; change VIRTUAL_MEMORY_BYTES instead to alter the media size.
*/
#define VIRTUAL_MEMORY_BLOCKS (VIRTUAL_MEMORY_BYTES / VIRTUAL_MEMORY_BLOCK_SIZE)
/* Function Prototypes: */
void DataflashManager_WriteBlocks(USB_ClassInfo_MS_Device_t* MSInterfaceInfo, const uint32_t BlockAddress,
uint16_t TotalBlocks);
void DataflashManager_ReadBlocks(USB_ClassInfo_MS_Device_t* MSInterfaceInfo, const uint32_t BlockAddress,
uint16_t TotalBlocks);
void DataflashManager_WriteBlocks_RAM(const uint32_t BlockAddress, uint16_t TotalBlocks,
uint8_t* BufferPtr) ATTR_NON_NULL_PTR_ARG(3);
void DataflashManager_ReadBlocks_RAM(const uint32_t BlockAddress, uint16_t TotalBlocks,
uint8_t* BufferPtr) ATTR_NON_NULL_PTR_ARG(3);
void DataflashManager_ResetDataflashProtections(void);
bool DataflashManager_CheckDataflashOperation(void);
#endif

@ -0,0 +1,36 @@
Petit FatFs Module Source Files R0.01a (C)ChaN, 2009
FILES
pff.h Common include file for Petit FatFs and application module.
pff.c Petit FatFs module.
diskio.h Common include file for Petit FatFs and disk I/O module.
diskio.c Skeleton of low level disk I/O module.
integer.h Alternative type definitions for integer variables.
Low level disk I/O module is not included in this archive because the Petit
FatFs module is only a generic file system layer and not depend on any
specific storage device. You have to provide a low level disk I/O module that
written to control your storage device.
AGREEMENTS
Petit FatFs module is an open source software to implement FAT file system to
small embedded systems. This is a free software and is opened for education,
research and commercial developments under license policy of following trems.
Copyright (C) 2009, ChaN, all right reserved.
* The Petit FatFs module is a free software and there is NO WARRANTY.
* No restriction on use. You can use, modify and redistribute it for
personal, non-profit or commercial use UNDER YOUR RESPONSIBILITY.
* Redistributions of source code must retain the above copyright notice.
REVISION HISTORY
Jun 15, 2009 R0.01a First release (Branched from FatFs R0.07b)

@ -0,0 +1,46 @@
/*-----------------------------------------------------------------------*/
/* Low level disk I/O module skeleton for Petit FatFs (C)ChaN, 2009 */
/*-----------------------------------------------------------------------*/
#include "diskio.h"
#include <string.h>
#include "../DataflashManager.h"
/*-----------------------------------------------------------------------*/
/* Initialize Disk Drive */
/*-----------------------------------------------------------------------*/
DSTATUS disk_initialize (void)
{
DSTATUS stat;
stat = RES_OK;
return stat;
}
/*-----------------------------------------------------------------------*/
/* Read Partial Sector */
/*-----------------------------------------------------------------------*/
DRESULT disk_readp (
void* dest, /* Pointer to the destination object */
DWORD sector, /* Sector number (LBA) */
WORD sofs, /* Offset in the sector */
WORD count /* Byte count (bit15:destination) */
)
{
DRESULT res;
uint8_t BlockTemp[512];
DataflashManager_ReadBlocks_RAM(sector, 1, BlockTemp);
memcpy(dest, &BlockTemp[sofs], count);
res = RES_OK;
return res;
}

@ -0,0 +1,36 @@
/*-----------------------------------------------------------------------
/ PFF - Low level disk interface modlue include file (C)ChaN, 2009
/-----------------------------------------------------------------------*/
#ifndef _DISKIO
#include "integer.h"
/* Status of Disk Functions */
typedef BYTE DSTATUS;
/* Results of Disk Functions */
typedef enum {
RES_OK = 0, /* 0: Function succeeded */
RES_ERROR, /* 1: Disk error */
RES_STRERR, /* 2: Seream error */
RES_NOTRDY, /* 3: Not ready */
RES_PARERR /* 4: Invalid parameter */
} DRESULT;
/*---------------------------------------*/
/* Prototypes for disk control functions */
DSTATUS disk_initialize (void);
DRESULT disk_readp (void*, DWORD, WORD, WORD);
BOOL assign_drives (int argc, char *argv[]);
#define STA_NOINIT 0x01 /* Drive not initialized */
#define STA_NODISK 0x02 /* No medium in the drive */
#define _DISKIO
#endif

@ -0,0 +1,37 @@
/*-------------------------------------------*/
/* Integer type definitions for FatFs module */
/*-------------------------------------------*/
#ifndef _INTEGER
#if 0
#include <windows.h>
#else
/* These types must be 16-bit, 32-bit or larger integer */
typedef int INT;
typedef unsigned int UINT;
/* These types must be 8-bit integer */
typedef signed char CHAR;
typedef unsigned char UCHAR;
typedef unsigned char BYTE;
/* These types must be 16-bit integer */
typedef short SHORT;
typedef unsigned short USHORT;
typedef unsigned short WORD;
typedef unsigned short WCHAR;
/* These types must be 32-bit integer */
typedef long LONG;
typedef unsigned long ULONG;
typedef unsigned long DWORD;
/* Boolean type */
typedef enum { FALSE = 0, TRUE } BOOL;
#endif
#define _INTEGER
#endif

@ -0,0 +1,777 @@
/*----------------------------------------------------------------------------/
/ Petit FatFs - FAT file system module R0.01a (C)ChaN, 2009
/-----------------------------------------------------------------------------/
/ Petit FatFs module is an open source software to implement FAT file system to
/ small embedded systems. This is a free software and is opened for education,
/ research and commercial developments under license policy of following trems.
/
/ Copyright (C) 2009, ChaN, all right reserved.
/
/ * The Petit FatFs module is a free software and there is NO WARRANTY.
/ * No restriction on use. You can use, modify and redistribute it for
/ personal, non-profit or commercial use UNDER YOUR RESPONSIBILITY.
/ * Redistributions of source code must retain the above copyright notice.
/
/-----------------------------------------------------------------------------/
/ Jun 15,'09 R0.01a Branched from FatFs R0.07b
/----------------------------------------------------------------------------*/
#include "pff.h" /* Petit FatFs configurations and declarations */
#include "diskio.h" /* Declarations of low level disk I/O functions */
/*--------------------------------------------------------------------------
Private Work Area
---------------------------------------------------------------------------*/
static
FATFS *FatFs; /* Pointer to the file system object (logical drive) */
/*--------------------------------------------------------------------------
Private Functions
---------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------*/
/* String functions */
/*-----------------------------------------------------------------------*/
/* Fill memory */
static
void mem_set (void* dst, int val, int cnt) {
char *d = (char*)dst;
while (cnt--) *d++ = (char)val;
}
/* Compare memory to memory */
static
int mem_cmp (const void* dst, const void* src, int cnt) {
const char *d = (const char *)dst, *s = (const char *)src;
int r = 0;
while (cnt-- && (r = *d++ - *s++) == 0) ;
return r;
}
/* Check if chr is contained in the string */
static
int chk_chr (const char* str, int chr) {
while (*str && *str != chr) str++;
return *str;
}
/*-----------------------------------------------------------------------*/
/* FAT access - Read value of a FAT entry */
/*-----------------------------------------------------------------------*/
static
CLUST get_fat ( /* 1:IO error, Else:Cluster status */
CLUST clst /* Cluster# to get the link information */
)
{
WORD wc, bc, ofs;
BYTE buf[4];
FATFS *fs = FatFs;
if (clst < 2 || clst >= fs->max_clust) /* Range check */
return 1;
switch (fs->fs_type) {
case FS_FAT12 :
bc = (WORD)clst; bc += bc / 2;
ofs = bc % 512; bc /= 512;
if (ofs != 511) {
if (disk_readp(buf, fs->fatbase + bc, ofs, 2)) break;
} else {
if (disk_readp(buf, fs->fatbase + bc, 511, 1)) break;
if (disk_readp(buf+1, fs->fatbase + bc + 1, 0, 1)) break;
}
wc = LD_WORD(buf);
return (clst & 1) ? (wc >> 4) : (wc & 0xFFF);
case FS_FAT16 :
if (disk_readp(buf, fs->fatbase + clst / 256, (WORD)(((WORD)clst % 256) * 2), 2)) break;
return LD_WORD(buf);
#if _FS_FAT32
case FS_FAT32 :
if (disk_readp(buf, fs->fatbase + clst / 128, (WORD)(((WORD)clst % 128) * 4), 4)) break;
return LD_DWORD(buf) & 0x0FFFFFFF;
#endif
}
return 1; /* An error occured at the disk I/O layer */
}
/*-----------------------------------------------------------------------*/
/* Get sector# from cluster# */
/*-----------------------------------------------------------------------*/
static
DWORD clust2sect ( /* !=0: Sector number, 0: Failed - invalid cluster# */
CLUST clst /* Cluster# to be converted */
)
{
FATFS *fs = FatFs;
clst -= 2;
if (clst >= (fs->max_clust - 2)) return 0; /* Invalid cluster# */
return (DWORD)clst * fs->csize + fs->database;
}
/*-----------------------------------------------------------------------*/
/* Directory handling - Rewind directory index */
/*-----------------------------------------------------------------------*/
static
FRESULT dir_rewind (
DIR *dj /* Pointer to directory object */
)
{
CLUST clst;
FATFS *fs = FatFs;
dj->index = 0;
clst = dj->sclust;
if (clst == 1 || clst >= fs->max_clust) /* Check start cluster range */
return FR_DISK_ERR;
#if _FS_FAT32
if (!clst && fs->fs_type == FS_FAT32) /* Replace cluster# 0 with root cluster# if in FAT32 */
clst = fs->dirbase;
#endif
dj->clust = clst; /* Current cluster */
dj->sect = clst ? clust2sect(clst) : fs->dirbase; /* Current sector */
return FR_OK; /* Seek succeeded */
}
/*-----------------------------------------------------------------------*/
/* Directory handling - Move directory index next */
/*-----------------------------------------------------------------------*/
static
FRESULT dir_next ( /* FR_OK:Succeeded, FR_NO_FILE:End of table, FR_DENIED:EOT and could not streach */
DIR *dj /* Pointer to directory object */
)
{
CLUST clst;
WORD i;
FATFS *fs = FatFs;
i = dj->index + 1;
if (!i || !dj->sect) /* Report EOT when index has reached 65535 */
return FR_NO_FILE;
if (!(i & (16-1))) { /* Sector changed? */
dj->sect++; /* Next sector */
if (dj->clust == 0) { /* Static table */
if (i >= fs->n_rootdir) /* Report EOT when end of table */
return FR_NO_FILE;
}
else { /* Dynamic table */
if (((i / 16) & (fs->csize-1)) == 0) { /* Cluster changed? */
clst = get_fat(dj->clust); /* Get next cluster */
if (clst <= 1) return FR_DISK_ERR;
if (clst >= fs->max_clust) /* When it reached end of dynamic table */
return FR_NO_FILE; /* Report EOT */
dj->clust = clst; /* Initialize data for new cluster */
dj->sect = clust2sect(clst);
}
}
}
dj->index = i;
return FR_OK;
}
/*-----------------------------------------------------------------------*/
/* Directory handling - Find an object in the directory */
/*-----------------------------------------------------------------------*/
static
FRESULT dir_find (
DIR *dj /* Pointer to the directory object linked to the file name */
)
{
FRESULT res;
BYTE c, *dir;
res = dir_rewind(dj); /* Rewind directory object */
if (res != FR_OK) return res;
dir = FatFs->buf;
do {
res = disk_readp(dir, dj->sect, (WORD)((dj->index % 16) * 32), 32) /* Read an entry */
? FR_DISK_ERR : FR_OK;
if (res != FR_OK) break;
c = dir[DIR_Name]; /* First character */
if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */
if (!(dir[DIR_Attr] & AM_VOL) && !mem_cmp(dir, dj->fn, 11)) /* Is it a valid entry? */
break;
res = dir_next(dj); /* Next entry */
} while (res == FR_OK);
return res;
}
/*-----------------------------------------------------------------------*/
/* Read an object from the directory */
/*-----------------------------------------------------------------------*/
#if _USE_DIR
static
FRESULT dir_read (
DIR *dj /* Pointer to the directory object to store read object name */
)
{
FRESULT res;
BYTE a, c, *dir;
res = FR_NO_FILE;
while (dj->sect) {
dir = FatFs->buf;
res = disk_readp(dir, dj->sect, (WORD)((dj->index % 16) * 32), 32) /* Read an entry */
? FR_DISK_ERR : FR_OK;
if (res != FR_OK) break;
c = dir[DIR_Name];
if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */
a = dir[DIR_Attr] & AM_MASK;
if (c != 0xE5 && c != '.' && !(a & AM_VOL)) /* Is it a valid entry? */
break;
res = dir_next(dj); /* Next entry */
if (res != FR_OK) break;
}
if (res != FR_OK) dj->sect = 0;
return res;
}
#endif
/*-----------------------------------------------------------------------*/
/* Pick a segment and create the object name in directory form */
/*-----------------------------------------------------------------------*/
static
FRESULT create_name (
DIR *dj, /* Pointer to the directory object */
const char **path /* Pointer to pointer to the segment in the path string */
)
{
BYTE c, ni, si, i, *sfn;
const char *p;
/* Create file name in directory form */
sfn = dj->fn;
mem_set(sfn, ' ', 11);
si = i = 0; ni = 8;
p = *path;
for (;;) {
c = p[si++];
if (c < ' ' || c == '/') break; /* Break on end of segment */
if (c == '.' || i >= ni) {
if (ni != 8 || c != '.') return FR_INVALID_NAME;
i = 8; ni = 11;
continue;
}
if (c >= 0x7F || chk_chr(" +,;[=\\]\"*:<>\?|", c)) /* Reject unallowable chrs for SFN */
return FR_INVALID_NAME;
if (c >='a' && c <= 'z') c -= 0x20;
sfn[i++] = c;
}
if (!i) return FR_INVALID_NAME; /* Reject null string */
*path = &p[si]; /* Rerurn pointer to the next segment */
sfn[11] = (c < ' ') ? 1 : 0; /* Set last segment flag if end of path */
return FR_OK;
}
/*-----------------------------------------------------------------------*/
/* Get file information from directory entry */
/*-----------------------------------------------------------------------*/
#if _USE_DIR
static
void get_fileinfo ( /* No return code */
DIR *dj, /* Pointer to the directory object */
FILINFO *fno /* Pointer to store the file information */
)
{
BYTE i, c, *dir;
char *p;
p = fno->fname;
if (dj->sect) {
dir = FatFs->buf;
for (i = 0; i < 8; i++) { /* Copy file name body */
c = dir[i];
if (c == ' ') break;
if (c == 0x05) c = 0xE5;
*p++ = c;
}
if (dir[8] != ' ') { /* Copy file name extension */
*p++ = '.';
for (i = 8; i < 11; i++) {
c = dir[i];
if (c == ' ') break;
*p++ = c;
}
}
fno->fattrib = dir[DIR_Attr]; /* Attribute */
fno->fsize = LD_DWORD(dir+DIR_FileSize); /* Size */
fno->fdate = LD_WORD(dir+DIR_WrtDate); /* Date */
fno->ftime = LD_WORD(dir+DIR_WrtTime); /* Time */
}
*p = 0;
}
#endif /* _USE_DIR */
/*-----------------------------------------------------------------------*/
/* Follow a file path */
/*-----------------------------------------------------------------------*/
static
FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */
DIR *dj, /* Directory object to return last directory and found object */
const char *path /* Full-path string to find a file or directory */
)
{
FRESULT res;
BYTE *dir;
if (*path == '/') path++; /* Strip heading separator */
dj->sclust = 0; /* Set start directory (always root dir) */
if ((BYTE)*path < ' ') { /* Null path means the root directory */
res = dir_rewind(dj);
FatFs->buf[0] = 0;
} else { /* Follow path */
for (;;) {
res = create_name(dj, &path); /* Get a segment */
if (res != FR_OK) break;
res = dir_find(dj); /* Find it */
if (res != FR_OK) { /* Could not find the object */
if (res == FR_NO_FILE && !*(dj->fn+11))
res = FR_NO_PATH;
break;
}
if (*(dj->fn+11)) break; /* Last segment match. Function completed. */
dir = FatFs->buf; /* There is next segment. Follow the sub directory */
if (!(dir[DIR_Attr] & AM_DIR)) { /* Cannot follow because it is a file */
res = FR_NO_PATH; break;
}
dj->sclust =
#if _FS_FAT32
((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) |
#endif
LD_WORD(dir+DIR_FstClusLO);
}
}
return res;
}
/*-----------------------------------------------------------------------*/
/* Check a sector if it is an FAT boot record */
/*-----------------------------------------------------------------------*/
static
BYTE check_fs ( /* 0:The FAT boot record, 1:Valid boot record but not an FAT, 2:Not a boot record, 3:Error */
BYTE *buf, /* Working buffer */
DWORD sect /* Sector# (lba) to check if it is an FAT boot record or not */
)
{
if (disk_readp(buf, sect, 510, 2)) /* Read the boot sector */
return 3;
if (LD_WORD(buf) != 0xAA55) /* Check record signature */
return 2;
if (!disk_readp(buf, sect, BS_FilSysType, 2) && LD_WORD(buf) == 0x4146) /* Check FAT12/16 */
return 0;
#if _FS_FAT32
if (!disk_readp(buf, sect, BS_FilSysType32, 2) && LD_WORD(buf) == 0x4146) /* Check FAT32 */
return 0;
#endif
return 1;
}
/*--------------------------------------------------------------------------
Public Functions
--------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------*/
/* Mount/Unmount a Locical Drive */
/*-----------------------------------------------------------------------*/
FRESULT pf_mount (
FATFS *fs /* Pointer to new file system object (NULL: Unmount) */
)
{
BYTE fmt, buf[36];
DWORD bsect, fsize, tsect, mclst;
FatFs = 0;
if (!fs) return FR_OK; /* Unregister fs object */
if (disk_initialize() & STA_NOINIT) /* Check if the drive is ready or not */
return FR_NOT_READY;
/* Search FAT partition on the drive */
bsect = 0;
fmt = check_fs(buf, bsect); /* Check sector 0 as an SFD format */
if (fmt == 1) { /* Not an FAT boot record, it may be FDISK format */
/* Check a partition listed in top of the partition table */
if (disk_readp(buf, bsect, MBR_Table, 16)) { /* 1st partition entry */
fmt = 3;
} else {
if (buf[4]) { /* Is the partition existing? */
bsect = LD_DWORD(&buf[8]); /* Partition offset in LBA */
fmt = check_fs(buf, bsect); /* Check the partition */
}
}
}
if (fmt == 3) return FR_DISK_ERR;
if (fmt) return FR_NO_FILESYSTEM; /* No valid FAT patition is found */
/* Initialize the file system object */
if (disk_readp(buf, bsect, 13, sizeof(buf))) return FR_DISK_ERR;
fsize = LD_WORD(buf+BPB_FATSz16-13); /* Number of sectors per FAT */
if (!fsize) fsize = LD_DWORD(buf+BPB_FATSz32-13);
fsize *= buf[BPB_NumFATs-13]; /* Number of sectors in FAT area */
fs->fatbase = bsect + LD_WORD(buf+BPB_RsvdSecCnt-13); /* FAT start sector (lba) */
fs->csize = buf[BPB_SecPerClus-13]; /* Number of sectors per cluster */
fs->n_rootdir = LD_WORD(buf+BPB_RootEntCnt-13); /* Nmuber of root directory entries */
tsect = LD_WORD(buf+BPB_TotSec16-13); /* Number of sectors on the file system */
if (!tsect) tsect = LD_DWORD(buf+BPB_TotSec32-13);
mclst = (tsect /* Last cluster# + 1 */
- LD_WORD(buf+BPB_RsvdSecCnt-13) - fsize - fs->n_rootdir / 16
) / fs->csize + 2;
fs->max_clust = (CLUST)mclst;
fmt = FS_FAT12; /* Determine the FAT sub type */
if (mclst >= 0xFF7) fmt = FS_FAT16; /* Number of clusters >= 0xFF5 */
if (mclst >= 0xFFF7) /* Number of clusters >= 0xFFF5 */
#if _FS_FAT32
fmt = FS_FAT32;
#else
return FR_NO_FILESYSTEM;
#endif
fs->fs_type = fmt; /* FAT sub-type */
#if _FS_FAT32
if (fmt == FS_FAT32)
fs->dirbase = LD_DWORD(buf+(BPB_RootClus-13)); /* Root directory start cluster */
else
#endif
fs->dirbase = fs->fatbase + fsize; /* Root directory start sector (lba) */
fs->database = fs->fatbase + fsize + fs->n_rootdir / 16; /* Data start sector (lba) */
fs->flag = 0;
FatFs = fs;
return FR_OK;
}
/*-----------------------------------------------------------------------*/
/* Open or Create a File */
/*-----------------------------------------------------------------------*/
FRESULT pf_open (
const char *path /* Pointer to the file name */
)
{
FRESULT res;
DIR dj;
BYTE sp[12], dir[32];
FATFS *fs = FatFs;
if (!fs) /* Check file system */
return FR_NOT_ENABLED;
fs->flag = 0;
fs->buf = dir;
dj.fn = sp;
res = follow_path(&dj, path); /* Follow the file path */
if (res != FR_OK) return res; /* Follow failed */
if (!dir[0] || (dir[DIR_Attr] & AM_DIR)) /* It is a directory */
return FR_NO_FILE;
fs->org_clust = /* File start cluster */
#if _FS_FAT32
((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) |
#endif
LD_WORD(dir+DIR_FstClusLO);
fs->fsize = LD_DWORD(dir+DIR_FileSize); /* File size */
fs->fptr = 0; /* File pointer */
fs->flag = FA_READ;
return FR_OK;
}
/*-----------------------------------------------------------------------*/
/* Read File */
/*-----------------------------------------------------------------------*/
FRESULT pf_read (
void* dest, /* Pointer to the destination object */
WORD btr, /* Number of bytes to read (bit15:destination) */
WORD* br /* Pointer to number of bytes read */
)
{
DRESULT dr;
CLUST clst;
DWORD sect, remain;
WORD rcnt;
BYTE *rbuff = dest;
FATFS *fs = FatFs;
*br = 0;
if (!fs) return FR_NOT_ENABLED; /* Check file system */
if (!(fs->flag & FA_READ))
return FR_INVALID_OBJECT;
remain = fs->fsize - fs->fptr;
if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */
for ( ; btr; /* Repeat until all data transferred */
rbuff += rcnt, fs->fptr += rcnt, *br += rcnt, btr -= rcnt) {
if ((fs->fptr % 512) == 0) { /* On the sector boundary? */
if ((fs->fptr / 512 % fs->csize) == 0) { /* On the cluster boundary? */
clst = (fs->fptr == 0) ? /* On the top of the file? */
fs->org_clust : get_fat(fs->curr_clust);
if (clst <= 1) {
fs->flag = 0; return FR_DISK_ERR;
}
fs->curr_clust = clst; /* Update current cluster */
fs->csect = 0; /* Reset sector offset in the cluster */
}
sect = clust2sect(fs->curr_clust); /* Get current sector */
if (!sect) {
fs->flag = 0; return FR_DISK_ERR;
}
sect += fs->csect;
fs->dsect = sect;
fs->csect++; /* Next sector address in the cluster */
}
rcnt = 512 - ((WORD)fs->fptr % 512); /* Get partial sector data from sector buffer */
if (rcnt > btr) rcnt = btr;
if (fs->flag & FA_STREAM) {
dr = disk_readp(dest, fs->dsect, (WORD)(fs->fptr % 512), (WORD)(rcnt | 0x8000));
} else {
dr = disk_readp(rbuff, fs->dsect, (WORD)(fs->fptr % 512), rcnt);
}
if (dr) {
fs->flag = 0;
return (dr == RES_STRERR) ? FR_STREAM_ERR : FR_DISK_ERR;
}
}
return FR_OK;
}
#if _USE_LSEEK
/*-----------------------------------------------------------------------*/
/* Seek File R/W Pointer */
/*-----------------------------------------------------------------------*/
FRESULT pf_lseek (
DWORD ofs /* File pointer from top of file */
)
{
CLUST clst;
DWORD bcs, nsect, ifptr;
FATFS *fs = FatFs;
if (!fs) return FR_NOT_ENABLED; /* Check file system */
if (!(fs->flag & FA_READ))
return FR_INVALID_OBJECT;
if (ofs > fs->fsize) ofs = fs->fsize; /* Clip offset with the file size */
ifptr = fs->fptr;
fs->fptr = 0;
if (ofs > 0) {
bcs = (DWORD)fs->csize * 512; /* Cluster size (byte) */
if (ifptr > 0 &&
(ofs - 1) / bcs >= (ifptr - 1) / bcs) { /* When seek to same or following cluster, */
fs->fptr = (ifptr - 1) & ~(bcs - 1); /* start from the current cluster */
ofs -= fs->fptr;
clst = fs->curr_clust;
} else { /* When seek to back cluster, */
clst = fs->org_clust; /* start from the first cluster */
fs->curr_clust = clst;
}
while (ofs > bcs) { /* Cluster following loop */
clst = get_fat(clst); /* Follow cluster chain if not in write mode */
if (clst <= 1 || clst >= fs->max_clust) {
fs->flag = 0; return FR_DISK_ERR;
}
fs->curr_clust = clst;
fs->fptr += bcs;
ofs -= bcs;
}
fs->fptr += ofs;
fs->csect = (BYTE)(ofs / 512) + 1; /* Sector offset in the cluster */
nsect = clust2sect(clst); /* Current sector */
if (!nsect) {
fs->flag = 0; return FR_DISK_ERR;
}
fs->dsect = nsect + fs->csect - 1;
}
return FR_OK;
}
#endif
#if _USE_DIR
/*-----------------------------------------------------------------------*/
/* Create a Directroy Object */
/*-----------------------------------------------------------------------*/
FRESULT pf_opendir (
DIR *dj, /* Pointer to directory object to create */
const char *path /* Pointer to the directory path */
)
{
FRESULT res;
BYTE sp[12], dir[32];
FATFS *fs = FatFs;
if (!fs) { /* Check file system */
res = FR_NOT_ENABLED;
} else {
fs->buf = dir;
dj->fn = sp;
res = follow_path(dj, path); /* Follow the path to the directory */
if (res == FR_OK) { /* Follow completed */
if (dir[0]) { /* It is not the root dir */
if (dir[DIR_Attr] & AM_DIR) { /* The object is a directory */
dj->sclust =
#if _FS_FAT32
((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) |
#endif
LD_WORD(dir+DIR_FstClusLO);
} else { /* The object is not a directory */
res = FR_NO_PATH;
}
}
if (res == FR_OK) {
res = dir_rewind(dj); /* Rewind dir */
}
}
if (res == FR_NO_FILE) res = FR_NO_PATH;
}
return res;
}
/*-----------------------------------------------------------------------*/
/* Read Directory Entry in Sequense */
/*-----------------------------------------------------------------------*/
FRESULT pf_readdir (
DIR *dj, /* Pointer to the open directory object */
FILINFO *fno /* Pointer to file information to return */
)
{
FRESULT res;
BYTE sp[12], dir[32];
FATFS *fs = FatFs;
if (!fs) { /* Check file system */
res = FR_NOT_ENABLED;
} else {
fs->buf = dir;
dj->fn = sp;
if (!fno) {
res = dir_rewind(dj);
} else {
res = dir_read(dj);
if (res == FR_NO_FILE) {
dj->sect = 0;
res = FR_OK;
}
if (res == FR_OK) { /* A valid entry is found */
get_fileinfo(dj, fno); /* Get the object information */
res = dir_next(dj); /* Increment index for next */
if (res == FR_NO_FILE) {
dj->sect = 0;
res = FR_OK;
}
}
}
}
return res;
}
#endif /* _FS_DIR */

@ -0,0 +1,237 @@
/*---------------------------------------------------------------------------/
/ Petit FatFs - FAT file system module include file R0.01a (C)ChaN, 2009
/----------------------------------------------------------------------------/
/ Petit FatFs module is an open source software to implement FAT file system to
/ small embedded systems. This is a free software and is opened for education,
/ research and commercial developments under license policy of following trems.
/
/ Copyright (C) 2009, ChaN, all right reserved.
/
/ * The Petit FatFs module is a free software and there is NO WARRANTY.
/ * No restriction on use. You can use, modify and redistribute it for
/ personal, non-profit or commercial use UNDER YOUR RESPONSIBILITY.
/ * Redistributions of source code must retain the above copyright notice.
/----------------------------------------------------------------------------*/
#include "integer.h"
/*---------------------------------------------------------------------------/
/ Petit FatFs Configuration Options
/
/ CAUTION! Do not forget to make clean the project after any changes to
/ the configuration options.
/
/----------------------------------------------------------------------------*/
#ifndef _FATFS
#define _FATFS
#define _WORD_ACCESS 0
/* The _WORD_ACCESS option defines which access method is used to the word
/ data in the FAT structure.
/
/ 0: Byte-by-byte access. Always compatible with all platforms.
/ 1: Word access. Do not choose this unless following condition is met.
/
/ When the byte order on the memory is big-endian or address miss-aligned
/ word access results incorrect behavior, the _WORD_ACCESS must be set to 0.
/ If it is not the case, the value can also be set to 1 to improve the
/ performance and code efficiency. */
#define _USE_DIR 0
/* To enable pf_opendir and pf_readdir function, set _USE_DIR to 1. */
#define _USE_LSEEK 0
/* To enable pf_lseek function, set _USE_LSEEK to 1. */
#define _FS_FAT32 0
/* To enable FAT32 support, set _FS_FAT32 to 1. */
/* End of configuration options. Do not change followings without care. */
/*--------------------------------------------------------------------------*/
#if _FS_FAT32
#define CLUST DWORD
#else
#define CLUST WORD
#endif
/* File system object structure */
typedef struct _FATFS_ {
BYTE fs_type; /* FAT sub type */
BYTE csize; /* Number of sectors per cluster */
BYTE flag; /* File status flags */
BYTE csect; /* File sector address in the cluster */
WORD n_rootdir; /* Number of root directory entries (0 on FAT32) */
BYTE* buf; /* Pointer to the disk access buffer */
CLUST max_clust; /* Maximum cluster# + 1. Number of clusters is max_clust - 2 */
DWORD fatbase; /* FAT start sector */
DWORD dirbase; /* Root directory start sector (Cluster# on FAT32) */
DWORD database; /* Data start sector */
DWORD fptr; /* File R/W pointer */
DWORD fsize; /* File size */
CLUST org_clust; /* File start cluster */
CLUST curr_clust; /* File current cluster */
DWORD dsect; /* File current data sector */
} FATFS;
/* Directory object structure */
typedef struct _DIR_ {
WORD index; /* Current read/write index number */
BYTE* fn; /* Pointer to the SFN (in/out) {file[8],ext[3],status[1]} */
CLUST sclust; /* Table start cluster (0:Static table) */
CLUST clust; /* Current cluster */
DWORD sect; /* Current sector */
} DIR;
/* File status structure */
typedef struct _FILINFO_ {
DWORD fsize; /* File size */
WORD fdate; /* Last modified date */
WORD ftime; /* Last modified time */
BYTE fattrib; /* Attribute */
char fname[13]; /* File name */
} FILINFO;
/* File function return code (FRESULT) */
typedef enum {
FR_OK = 0, /* 0 */
FR_DISK_ERR, /* 1 */
FR_NOT_READY, /* 2 */
FR_NO_FILE, /* 3 */
FR_NO_PATH, /* 4 */
FR_INVALID_NAME, /* 5 */
FR_STREAM_ERR, /* 6 */
FR_INVALID_OBJECT, /* 7 */
FR_NOT_ENABLED, /* 8 */
FR_NO_FILESYSTEM /* 9 */
} FRESULT;
/*--------------------------------------------------------------*/
/* Petit FatFs module application interface */
FRESULT pf_mount (FATFS*); /* Mount/Unmount a logical drive */
FRESULT pf_open (const char*); /* Open a file */
FRESULT pf_read (void*, WORD, WORD*); /* Read data from a file */
FRESULT pf_lseek (DWORD); /* Move file pointer of a file object */
FRESULT pf_opendir (DIR*, const char*); /* Open an existing directory */
FRESULT pf_readdir (DIR*, FILINFO*); /* Read a directory item */
/*--------------------------------------------------------------*/
/* Flags and offset address */
/* File status flag (FATFS.flag) */
#define FA_READ 0x01
#define FA_STREAM 0x40
#define FA__ERROR 0x80
/* FAT sub type (FATFS.fs_type) */
#define FS_FAT12 1
#define FS_FAT16 2
#define FS_FAT32 3
/* File attribute bits for directory entry */
#define AM_RDO 0x01 /* Read only */
#define AM_HID 0x02 /* Hidden */
#define AM_SYS 0x04 /* System */
#define AM_VOL 0x08 /* Volume label */
#define AM_LFN 0x0F /* LFN entry */
#define AM_DIR 0x10 /* Directory */
#define AM_ARC 0x20 /* Archive */
#define AM_MASK 0x3F /* Mask of defined bits */
/* FatFs refers the members in the FAT structures with byte offset instead
/ of structure member because there are incompatibility of the packing option
/ between various compilers. */
#define BS_jmpBoot 0
#define BS_OEMName 3
#define BPB_BytsPerSec 11
#define BPB_SecPerClus 13
#define BPB_RsvdSecCnt 14
#define BPB_NumFATs 16
#define BPB_RootEntCnt 17
#define BPB_TotSec16 19
#define BPB_Media 21
#define BPB_FATSz16 22
#define BPB_SecPerTrk 24
#define BPB_NumHeads 26
#define BPB_HiddSec 28
#define BPB_TotSec32 32
#define BS_55AA 510
#define BS_DrvNum 36
#define BS_BootSig 38
#define BS_VolID 39
#define BS_VolLab 43
#define BS_FilSysType 54
#define BPB_FATSz32 36
#define BPB_ExtFlags 40
#define BPB_FSVer 42
#define BPB_RootClus 44
#define BPB_FSInfo 48
#define BPB_BkBootSec 50
#define BS_DrvNum32 64
#define BS_BootSig32 66
#define BS_VolID32 67
#define BS_VolLab32 71
#define BS_FilSysType32 82
#define MBR_Table 446
#define DIR_Name 0
#define DIR_Attr 11
#define DIR_NTres 12
#define DIR_CrtTime 14
#define DIR_CrtDate 16
#define DIR_FstClusHI 20
#define DIR_WrtTime 22
#define DIR_WrtDate 24
#define DIR_FstClusLO 26
#define DIR_FileSize 28
/*--------------------------------*/
/* Multi-byte word access macros */
#if _WORD_ACCESS == 1 /* Enable word access to the FAT structure */
#define LD_WORD(ptr) (WORD)(*(WORD*)(BYTE*)(ptr))
#define LD_DWORD(ptr) (DWORD)(*(DWORD*)(BYTE*)(ptr))
#define ST_WORD(ptr,val) *(WORD*)(BYTE*)(ptr)=(WORD)(val)
#define ST_DWORD(ptr,val) *(DWORD*)(BYTE*)(ptr)=(DWORD)(val)
#else /* Use byte-by-byte access to the FAT structure */
#define LD_WORD(ptr) (WORD)(((WORD)*(BYTE*)((ptr)+1)<<8)|(WORD)*(BYTE*)(ptr))
#define LD_DWORD(ptr) (DWORD)(((DWORD)*(BYTE*)((ptr)+3)<<24)|((DWORD)*(BYTE*)((ptr)+2)<<16)|((WORD)*(BYTE*)((ptr)+1)<<8)|*(BYTE*)(ptr))
#define ST_WORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *(BYTE*)((ptr)+1)=(BYTE)((WORD)(val)>>8)
#define ST_DWORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *(BYTE*)((ptr)+1)=(BYTE)((WORD)(val)>>8); *(BYTE*)((ptr)+2)=(BYTE)((DWORD)(val)>>16); *(BYTE*)((ptr)+3)=(BYTE)((DWORD)(val)>>24)
#endif
#endif /* _FATFS */

@ -0,0 +1,77 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2009.
dean [at] fourwalledcubicle [dot] com
www.fourwalledcubicle.com
*/
/*
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, and distribute this software
and its documentation for any purpose and without fee is hereby
granted, 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.
*/
#include "ProgrammerConfig.h"
struct
{
uint16_t SigBytes[4];
bool EnforceSigBytes;
uint32_t ProgrammingSpeed;
} ProgrammerConfig;
bool ProgrammerConfig_ProcessConfiguration(void)
{
memset(&ProgrammerConfig, sizeof(ProgrammerConfig), 0x00);
if (!(pf_open("CONF.txt") == FR_OK))
{
fputs(" >> ERROR: CONF.txt File Not Found.\r\n", &USBSerialStream);
return false;
}
char LineBuff[100];
char* CurrentLine;
do
{
CurrentLine = fgets(LineBuff, sizeof(LineBuff), &DataflashStream);
if (CurrentLine)
{
sscanf(CurrentLine, "SIGNATURE = %02x %02x %02x %02x", &ProgrammerConfig.SigBytes[0],
&ProgrammerConfig.SigBytes[1],
&ProgrammerConfig.SigBytes[2],
&ProgrammerConfig.SigBytes[3]);
sscanf(CurrentLine, "SPEED = %lu", &ProgrammerConfig.ProgrammingSpeed);
}
} while (CurrentLine);
fprintf(&USBSerialStream, " >> *** Configuration: ***\r\n");
fprintf(&USBSerialStream, " >> Device Signature: 0x%02x 0x%02x 0x%02x 0x%02x\r\n", ProgrammerConfig.SigBytes[0],
ProgrammerConfig.SigBytes[1],
ProgrammerConfig.SigBytes[2],
ProgrammerConfig.SigBytes[3]);
fprintf(&USBSerialStream, " >> Programming Speed: %lu Hz\r\n", ProgrammerConfig.ProgrammingSpeed);
return true;
}

@ -0,0 +1,44 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2009.
dean [at] fourwalledcubicle [dot] com
www.fourwalledcubicle.com
*/
/*
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, and distribute this software
and its documentation for any purpose and without fee is hereby
granted, 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.
*/
#ifndef _PROGRAMMER_CONFIG_H_
#define _PROGRAMMER_CONFIG_H_
/* Includes: */
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include "../StandaloneProgrammer.h"
/* Function Prototypes: */
bool ProgrammerConfig_ProcessConfiguration(void);
#endif

@ -0,0 +1,281 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2009.
dean [at] fourwalledcubicle [dot] com
www.fourwalledcubicle.com
*/
/*
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, and distribute this software
and its documentation for any purpose and without fee is hereby
granted, 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
*
* SCSI command processing routines, for SCSI commands issued by the host. Mass Storage
* devices use a thin "Bulk-Only Transport" protocol for issuing commands and status information,
* which wrap around standard SCSI device commands for controlling the actual storage medium.
*/
#define INCLUDE_FROM_SCSI_C
#include "SCSI.h"
/** Structure to hold the SCSI response data to a SCSI INQUIRY command. This gives information about the device's
* features and capabilities.
*/
SCSI_Inquiry_Response_t InquiryData =
{
.DeviceType = DEVICE_TYPE_BLOCK,
.PeripheralQualifier = 0,
.Removable = true,
.Version = 0,
.ResponseDataFormat = 2,
.NormACA = false,
.TrmTsk = false,
.AERC = false,
.AdditionalLength = 0x1F,
.SoftReset = false,
.CmdQue = false,
.Linked = false,
.Sync = false,
.WideBus16Bit = false,
.WideBus32Bit = false,
.RelAddr = false,
.VendorID = "LUFA",
.ProductID = "Dataflash Disk",
.RevisionID = {'0','.','0','0'},
};
/** Structure to hold the sense data for the last issued SCSI command, which is returned to the host after a SCSI REQUEST SENSE
* command is issued. This gives information on exactly why the last command failed to complete.
*/
SCSI_Request_Sense_Response_t SenseData =
{
.ResponseCode = 0x70,
.AdditionalLength = 0x0A,
};
/** Main routine to process the SCSI command located in the Command Block Wrapper read from the host. This dispatches
* to the appropriate SCSI command handling routine if the issued command is supported by the device, else it returns
* a command failure due to a ILLEGAL REQUEST.
*
* \param[in] MSInterfaceInfo Pointer to the Mass Storage class interface structure that the command is associated with
*/
bool SCSI_DecodeSCSICommand(USB_ClassInfo_MS_Device_t* MSInterfaceInfo)
{
/* Set initial sense data, before the requested command is processed */
SCSI_SET_SENSE(SCSI_SENSE_KEY_GOOD,
SCSI_ASENSE_NO_ADDITIONAL_INFORMATION,
SCSI_ASENSEQ_NO_QUALIFIER);
/* Run the appropriate SCSI command hander function based on the passed command */
switch (MSInterfaceInfo->State.CommandBlock.SCSICommandData[0])
{
case SCSI_CMD_INQUIRY:
SCSI_Command_Inquiry(MSInterfaceInfo);
break;
case SCSI_CMD_REQUEST_SENSE:
SCSI_Command_Request_Sense(MSInterfaceInfo);
break;
case SCSI_CMD_READ_CAPACITY_10:
SCSI_Command_Read_Capacity_10(MSInterfaceInfo);
break;
case SCSI_CMD_SEND_DIAGNOSTIC:
SCSI_Command_Send_Diagnostic(MSInterfaceInfo);
break;
case SCSI_CMD_WRITE_10:
SCSI_Command_ReadWrite_10(MSInterfaceInfo, DATA_WRITE);
break;
case SCSI_CMD_READ_10:
SCSI_Command_ReadWrite_10(MSInterfaceInfo, DATA_READ);
break;
case SCSI_CMD_TEST_UNIT_READY:
case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
case SCSI_CMD_VERIFY_10:
/* These commands should just succeed, no handling required */
MSInterfaceInfo->State.CommandBlock.DataTransferLength = 0;
break;
default:
/* Update the SENSE key to reflect the invalid command */
SCSI_SET_SENSE(SCSI_SENSE_KEY_ILLEGAL_REQUEST,
SCSI_ASENSE_INVALID_COMMAND,
SCSI_ASENSEQ_NO_QUALIFIER);
break;
}
return (SenseData.SenseKey == SCSI_SENSE_KEY_GOOD);
}
/** Command processing for an issued SCSI INQUIRY command. This command returns information about the device's features
* and capabilities to the host.
*
* \param[in] MSInterfaceInfo Pointer to the Mass Storage class interface structure that the command is associated with
*/
static void SCSI_Command_Inquiry(USB_ClassInfo_MS_Device_t* MSInterfaceInfo)
{
uint16_t AllocationLength = (((uint16_t)MSInterfaceInfo->State.CommandBlock.SCSICommandData[3] << 8) |
MSInterfaceInfo->State.CommandBlock.SCSICommandData[4]);
uint16_t BytesTransferred = (AllocationLength < sizeof(InquiryData))? AllocationLength :
sizeof(InquiryData);
/* Only the standard INQUIRY data is supported, check if any optional INQUIRY bits set */
if ((MSInterfaceInfo->State.CommandBlock.SCSICommandData[1] & ((1 << 0) | (1 << 1))) ||
MSInterfaceInfo->State.CommandBlock.SCSICommandData[2])
{
/* Optional but unsupported bits set - update the SENSE key and fail the request */
SCSI_SET_SENSE(SCSI_SENSE_KEY_ILLEGAL_REQUEST,
SCSI_ASENSE_INVALID_FIELD_IN_CDB,
SCSI_ASENSEQ_NO_QUALIFIER);
return;
}
Endpoint_Write_Stream_LE(&InquiryData, BytesTransferred, NO_STREAM_CALLBACK);
uint8_t PadBytes[AllocationLength - BytesTransferred];
/* Pad out remaining bytes with 0x00 */
Endpoint_Write_Stream_LE(&PadBytes, (AllocationLength - BytesTransferred), NO_STREAM_CALLBACK);
/* Finalize the stream transfer to send the last packet */
Endpoint_ClearIN();
/* Succeed the command and update the bytes transferred counter */
MSInterfaceInfo->State.CommandBlock.DataTransferLength -= BytesTransferred;
}
/** Command processing for an issued SCSI REQUEST SENSE command. This command returns information about the last issued command,
* including the error code and additional error information so that the host can determine why a command failed to complete.
*
* \param[in] MSInterfaceInfo Pointer to the Mass Storage class interface structure that the command is associated with
*/
static void SCSI_Command_Request_Sense(USB_ClassInfo_MS_Device_t* MSInterfaceInfo)
{
uint8_t AllocationLength = MSInterfaceInfo->State.CommandBlock.SCSICommandData[4];
uint8_t BytesTransferred = (AllocationLength < sizeof(SenseData))? AllocationLength : sizeof(SenseData);
uint8_t PadBytes[AllocationLength - BytesTransferred];
Endpoint_Write_Stream_LE(&SenseData, BytesTransferred, NO_STREAM_CALLBACK);
Endpoint_Write_Stream_LE(&PadBytes, (AllocationLength - BytesTransferred), NO_STREAM_CALLBACK);
Endpoint_ClearIN();
/* Succeed the command and update the bytes transferred counter */
MSInterfaceInfo->State.CommandBlock.DataTransferLength -= BytesTransferred;
}
/** Command processing for an issued SCSI READ CAPACITY (10) command. This command returns information about the device's capacity
* on the selected Logical Unit (drive), as a number of OS-sized blocks.
*
* \param[in] MSInterfaceInfo Pointer to the Mass Storage class interface structure that the command is associated with
*/
static void SCSI_Command_Read_Capacity_10(USB_ClassInfo_MS_Device_t* MSInterfaceInfo)
{
uint32_t LastBlockAddressInLUN = (VIRTUAL_MEMORY_BLOCKS - 1);
uint32_t MediaBlockSize = VIRTUAL_MEMORY_BLOCK_SIZE;
Endpoint_Write_Stream_BE(&LastBlockAddressInLUN, sizeof(LastBlockAddressInLUN), NO_STREAM_CALLBACK);
Endpoint_Write_Stream_BE(&MediaBlockSize, sizeof(MediaBlockSize), NO_STREAM_CALLBACK);
Endpoint_ClearIN();
/* Succeed the command and update the bytes transferred counter */
MSInterfaceInfo->State.CommandBlock.DataTransferLength -= 8;
}
/** Command processing for an issued SCSI SEND DIAGNOSTIC command. This command performs a quick check of the Dataflash ICs on the
* board, and indicates if they are present and functioning correctly. Only the Self-Test portion of the diagnostic command is
* supported.
*
* \param[in] MSInterfaceInfo Pointer to the Mass Storage class interface structure that the command is associated with
*/
static void SCSI_Command_Send_Diagnostic(USB_ClassInfo_MS_Device_t* MSInterfaceInfo)
{
/* Check to see if the SELF TEST bit is not set */
if (!(MSInterfaceInfo->State.CommandBlock.SCSICommandData[1] & (1 << 2)))
{
/* Only self-test supported - update SENSE key and fail the command */
SCSI_SET_SENSE(SCSI_SENSE_KEY_ILLEGAL_REQUEST,
SCSI_ASENSE_INVALID_FIELD_IN_CDB,
SCSI_ASENSEQ_NO_QUALIFIER);
return;
}
/* Check to see if all attached Dataflash ICs are functional */
if (!(DataflashManager_CheckDataflashOperation()))
{
/* Update SENSE key with a hardware error condition and return command fail */
SCSI_SET_SENSE(SCSI_SENSE_KEY_HARDWARE_ERROR,
SCSI_ASENSE_NO_ADDITIONAL_INFORMATION,
SCSI_ASENSEQ_NO_QUALIFIER);
return;
}
/* Succeed the command and update the bytes transferred counter */
MSInterfaceInfo->State.CommandBlock.DataTransferLength = 0;
}
/** Command processing for an issued SCSI READ (10) or WRITE (10) command. This command reads in the block start address
* and total number of blocks to process, then calls the appropriate low-level dataflash routine to handle the actual
* reading and writing of the data.
*
* \param[in] MSInterfaceInfo Pointer to the Mass Storage class interface structure that the command is associated with
* \param[in] IsDataRead Indicates if the command is a READ (10) command or WRITE (10) command (DATA_READ or DATA_WRITE)
*/
static void SCSI_Command_ReadWrite_10(USB_ClassInfo_MS_Device_t* MSInterfaceInfo, const bool IsDataRead)
{
uint32_t BlockAddress;
uint16_t TotalBlocks;
/* Load in the 32-bit block address (SCSI uses big-endian, so have to reverse the byte order) */
BlockAddress = SwapEndian_32(*(uint32_t*)&MSInterfaceInfo->State.CommandBlock.SCSICommandData[2]);
/* Load in the 16-bit total blocks (SCSI uses big-endian, so have to reverse the byte order) */
TotalBlocks = SwapEndian_16(*(uint32_t*)&MSInterfaceInfo->State.CommandBlock.SCSICommandData[7]);
/* Check if the block address is outside the maximum allowable value for the LUN */
if (BlockAddress >= VIRTUAL_MEMORY_BLOCKS)
{
/* Block address is invalid, update SENSE key and return command fail */
SCSI_SET_SENSE(SCSI_SENSE_KEY_ILLEGAL_REQUEST,
SCSI_ASENSE_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE,
SCSI_ASENSEQ_NO_QUALIFIER);
return;
}
/* Determine if the packet is a READ (10) or WRITE (10) command, call appropriate function */
if (IsDataRead == DATA_READ)
DataflashManager_ReadBlocks(MSInterfaceInfo, BlockAddress, TotalBlocks);
else
DataflashManager_WriteBlocks(MSInterfaceInfo, BlockAddress, TotalBlocks);
/* Update the bytes transferred counter and succeed the command */
MSInterfaceInfo->State.CommandBlock.DataTransferLength -= ((uint32_t)TotalBlocks * VIRTUAL_MEMORY_BLOCK_SIZE);
}

@ -0,0 +1,146 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2009.
dean [at] fourwalledcubicle [dot] com
www.fourwalledcubicle.com
*/
/*
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, and distribute this software
and its documentation for any purpose and without fee is hereby
granted, 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 SCSI.c.
*/
#ifndef _SCSI_H_
#define _SCSI_H_
/* Includes: */
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <LUFA/Drivers/USB/USB.h>
#include <LUFA/Drivers/USB/Class/MassStorage.h>
#include "Descriptors.h"
#include "DataflashManager.h"
/* Macros: */
/** Macro to set the current SCSI sense data to the given key, additional sense code and additional sense qualifier. This
* is for convenience, as it allows for all three sense values (returned upon request to the host to give information about
* the last command failure) in a quick and easy manner.
*
* \param[in] key New SCSI sense key to set the sense code to
* \param[in] acode New SCSI additional sense key to set the additional sense code to
* \param[in] aqual New SCSI additional sense key qualifier to set the additional sense qualifier code to
*/
#define SCSI_SET_SENSE(key, acode, aqual) MACROS{ SenseData.SenseKey = key; \
SenseData.AdditionalSenseCode = acode; \
SenseData.AdditionalSenseQualifier = aqual; }MACROE
/** Macro for the SCSI_Command_ReadWrite_10() function, to indicate that data is to be read from the storage medium. */
#define DATA_READ true
/** Macro for the SCSI_Command_ReadWrite_10() function, to indicate that data is to be written to the storage medium. */
#define DATA_WRITE false
/** Value for the DeviceType entry in the SCSI_Inquiry_Response_t enum, indicating a Block Media device. */
#define DEVICE_TYPE_BLOCK 0x00
/** Value for the DeviceType entry in the SCSI_Inquiry_Response_t enum, indicating a CD-ROM device. */
#define DEVICE_TYPE_CDROM 0x05
/* Type Defines: */
/** Type define for a SCSI response structure to a SCSI INQUIRY command. For details of the
* structure contents, refer to the SCSI specifications.
*/
typedef struct
{
unsigned char DeviceType : 5;
unsigned char PeripheralQualifier : 3;
unsigned char _RESERVED1 : 7;
unsigned char Removable : 1;
uint8_t Version;
unsigned char ResponseDataFormat : 4;
unsigned char _RESERVED2 : 1;
unsigned char NormACA : 1;
unsigned char TrmTsk : 1;
unsigned char AERC : 1;
uint8_t AdditionalLength;
uint8_t _RESERVED3[2];
unsigned char SoftReset : 1;
unsigned char CmdQue : 1;
unsigned char _RESERVED4 : 1;
unsigned char Linked : 1;
unsigned char Sync : 1;
unsigned char WideBus16Bit : 1;
unsigned char WideBus32Bit : 1;
unsigned char RelAddr : 1;
uint8_t VendorID[8];
uint8_t ProductID[16];
uint8_t RevisionID[4];
} SCSI_Inquiry_Response_t;
/** Type define for a SCSI sense structure to a SCSI REQUEST SENSE command. For details of the
* structure contents, refer to the SCSI specifications.
*/
typedef struct
{
uint8_t ResponseCode;
uint8_t SegmentNumber;
unsigned char SenseKey : 4;
unsigned char _RESERVED1 : 1;
unsigned char ILI : 1;
unsigned char EOM : 1;
unsigned char FileMark : 1;
uint8_t Information[4];
uint8_t AdditionalLength;
uint8_t CmdSpecificInformation[4];
uint8_t AdditionalSenseCode;
uint8_t AdditionalSenseQualifier;
uint8_t FieldReplaceableUnitCode;
uint8_t SenseKeySpecific[3];
} SCSI_Request_Sense_Response_t;
/* Function Prototypes: */
bool SCSI_DecodeSCSICommand(USB_ClassInfo_MS_Device_t* MSInterfaceInfo);
#if defined(INCLUDE_FROM_SCSI_C)
static void SCSI_Command_Inquiry(USB_ClassInfo_MS_Device_t* MSInterfaceInfo);
static void SCSI_Command_Request_Sense(USB_ClassInfo_MS_Device_t* MSInterfaceInfo);
static void SCSI_Command_Read_Capacity_10(USB_ClassInfo_MS_Device_t* MSInterfaceInfo);
static void SCSI_Command_Send_Diagnostic(USB_ClassInfo_MS_Device_t* MSInterfaceInfo);
static void SCSI_Command_ReadWrite_10(USB_ClassInfo_MS_Device_t* MSInterfaceInfo, const bool IsDataRead);
#endif
#endif

@ -0,0 +1,106 @@
;************************************************************
; Windows USB CDC ACM Setup File
; Copyright (c) 2000 Microsoft Corporation
[Version]
Signature="$Windows NT$"
Class=Ports
ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318}
Provider=%MFGNAME%
LayoutFile=layout.inf
CatalogFile=%MFGFILENAME%.cat
DriverVer=11/15/2007,5.1.2600.0
[Manufacturer]
%MFGNAME%=DeviceList, NTamd64
[DestinationDirs]
DefaultDestDir=12
;------------------------------------------------------------------------------
; Windows 2000/XP/Vista-32bit Sections
;------------------------------------------------------------------------------
[DriverInstall.nt]
include=mdmcpq.inf
CopyFiles=DriverCopyFiles.nt
AddReg=DriverInstall.nt.AddReg
[DriverCopyFiles.nt]
usbser.sys,,,0x20
[DriverInstall.nt.AddReg]
HKR,,DevLoader,,*ntkern
HKR,,NTMPDriver,,%DRIVERFILENAME%.sys
HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider"
[DriverInstall.nt.Services]
AddService=usbser, 0x00000002, DriverService.nt
[DriverService.nt]
DisplayName=%SERVICE%
ServiceType=1
StartType=3
ErrorControl=1
ServiceBinary=%12%\%DRIVERFILENAME%.sys
;------------------------------------------------------------------------------
; Vista-64bit Sections
;------------------------------------------------------------------------------
[DriverInstall.NTamd64]
include=mdmcpq.inf
CopyFiles=DriverCopyFiles.NTamd64
AddReg=DriverInstall.NTamd64.AddReg
[DriverCopyFiles.NTamd64]
%DRIVERFILENAME%.sys,,,0x20
[DriverInstall.NTamd64.AddReg]
HKR,,DevLoader,,*ntkern
HKR,,NTMPDriver,,%DRIVERFILENAME%.sys
HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider"
[DriverInstall.NTamd64.Services]
AddService=usbser, 0x00000002, DriverService.NTamd64
[DriverService.NTamd64]
DisplayName=%SERVICE%
ServiceType=1
StartType=3
ErrorControl=1
ServiceBinary=%12%\%DRIVERFILENAME%.sys
;------------------------------------------------------------------------------
; Vendor and Product ID Definitions
;------------------------------------------------------------------------------
; When developing your USB device, the VID and PID used in the PC side
; application program and the firmware on the microcontroller must match.
; Modify the below line to use your VID and PID. Use the format as shown below.
; Note: One INF file can be used for multiple devices with different VID and PIDs.
; For each supported device, append ",USB\VID_xxxx&PID_yyyy" to the end of the line.
;------------------------------------------------------------------------------
[SourceDisksFiles]
[SourceDisksNames]
[DeviceList]
%DESCRIPTION%=DriverInstall, USB\VID_03EB&PID_2063&MI_00
[DeviceList.NTamd64]
%DESCRIPTION%=DriverInstall, USB\VID_03EB&PID_2063&MI_00
;------------------------------------------------------------------------------
; String Definitions
;------------------------------------------------------------------------------
;Modify these strings to customize your device
;------------------------------------------------------------------------------
[Strings]
MFGFILENAME="CDC_vista"
DRIVERFILENAME ="usbser"
MFGNAME="CCS, Inc."
INSTDISK="LUFA Benito Programmer Driver Installer"
DESCRIPTION="Communications Port"
SERVICE="USB RS-232 Emulation Driver"

@ -0,0 +1,234 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2009.
dean [at] fourwalledcubicle [dot] com
www.fourwalledcubicle.com
*/
/*
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, and distribute this software
and its documentation for any purpose and without fee is hereby
granted, 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 Standalone Programmer project. This file contains the main tasks of
* the demo and is responsible for the initial application hardware configuration.
*/
#define INCLUDE_FROM_STANDALONEPROG_C
#include "StandaloneProgrammer.h"
/** LUFA Mass Storage Class driver interface configuration and state information. This structure is
* passed to all Mass Storage Class driver functions, so that multiple instances of the same class
* within a device can be differentiated from one another.
*/
USB_ClassInfo_MS_Device_t Disk_MS_Interface =
{
.Config =
{
.InterfaceNumber = 0,
.DataINEndpointNumber = MASS_STORAGE_IN_EPNUM,
.DataINEndpointSize = MASS_STORAGE_IO_EPSIZE,
.DataINEndpointDoubleBank = false,
.DataOUTEndpointNumber = MASS_STORAGE_OUT_EPNUM,
.DataOUTEndpointSize = MASS_STORAGE_IO_EPSIZE,
.DataOUTEndpointDoubleBank = false,
.TotalLUNs = 1,
},
};
/** LUFA CDC Class driver interface configuration and state information. This structure is
* passed to all CDC Class driver functions, so that multiple instances of the same class
* within a device can be differentiated from one another.
*/
USB_ClassInfo_CDC_Device_t VirtualSerial_CDC_Interface =
{
.Config =
{
.ControlInterfaceNumber = 0,
.DataINEndpointNumber = CDC_TX_EPNUM,
.DataINEndpointSize = CDC_TXRX_EPSIZE,
.DataINEndpointDoubleBank = false,
.DataOUTEndpointNumber = CDC_RX_EPNUM,
.DataOUTEndpointSize = CDC_TXRX_EPSIZE,
.DataOUTEndpointDoubleBank = false,
.NotificationEndpointNumber = CDC_NOTIFICATION_EPNUM,
.NotificationEndpointSize = CDC_NOTIFICATION_EPSIZE,
.NotificationEndpointDoubleBank = false,
},
};
/** Standard file stream for the CDC interface when set up, so that the virtual CDC COM port can be
* used like any regular character stream in the C APIs
*/
FILE USBSerialStream;
/** Standard file stream for the currently open file on the dataflash disk. */
FILE DataflashStream = FDEV_SETUP_STREAM(NULL, Dataflash_getchar, _FDEV_SETUP_READ);
/** Petite FAT Fs structure to hold the internal state of the FAT driver for the dataflash contents. */
FATFS DataflashData;
/** Stream character fetching routine for the FAT driver so that characters from the currently open file can be
* readin sequence when applied to a stdio stream.
*/
static int Dataflash_getchar(FILE* Stream)
{
char ReadByte;
WORD ByteWasRead;
if (pf_read(&ReadByte, 1, &ByteWasRead) != FR_OK)
return _FDEV_ERR;
return (ByteWasRead ? ReadByte : _FDEV_EOF);
}
/** Task to determine if the user is wishes to start the programming sequence, and if so executes the
* required functions to program the attached target (if any) with the files loaded to the dataflash.
*/
void Programmer_Task(void)
{
static bool HasAttempted = false;
if (Buttons_GetStatus() & BUTTONS_BUTTON1)
{
if (!(HasAttempted))
HasAttempted = true;
else
return;
fputs("==== PROGRAMMING CYCLE STARTED ====\r\n", &USBSerialStream);
fputs("Reading Configuration File...\r\n", &USBSerialStream);
if (!(ProgrammerConfig_ProcessConfiguration()))
goto EndOfProgCycle;
EndOfProgCycle:
fputs("==== PROGRAMMING CYCLE FINISHED ====\r\n", &USBSerialStream);
}
else
{
HasAttempted = false;
}
}
/** 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();
/* Create a regular character stream for the interface so that it can be used with the stdio.h functions */
CDC_Device_CreateStream(&VirtualSerial_CDC_Interface, &USBSerialStream);
LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
for (;;)
{
Programmer_Task();
/* Must throw away unused bytes from the host, or it will lock up while waiting for the device */
while (CDC_Device_BytesReceived(&VirtualSerial_CDC_Interface))
CDC_Device_ReceiveByte(&VirtualSerial_CDC_Interface);
CDC_Device_USBTask(&VirtualSerial_CDC_Interface);
MS_Device_USBTask(&Disk_MS_Interface);
USB_USBTask();
}
}
/** Configures the board hardware and chip peripherals for the demo's functionality. */
void SetupHardware(void)
{
/* Disable watchdog if enabled by bootloader/fuses */
MCUSR &= ~(1 << WDRF);
wdt_disable();
/* Disable clock division */
clock_prescale_set(clock_div_1);
/* Hardware Initialization */
LEDs_Init();
SPI_Init(SPI_SPEED_FCPU_DIV_2 | SPI_SCK_LEAD_FALLING | SPI_SAMPLE_TRAILING | SPI_MODE_MASTER);
Dataflash_Init();
USB_Init();
Buttons_Init();
pf_mount(&DataflashData);
/* Clear Dataflash sector protections, if enabled */
DataflashManager_ResetDataflashProtections();
}
/** Event handler for the library USB Connection event. */
void EVENT_USB_Device_Connect(void)
{
LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING);
}
/** Event handler for the library USB Disconnection event. */
void EVENT_USB_Device_Disconnect(void)
{
LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
}
/** Event handler for the library USB Configuration Changed event. */
void EVENT_USB_Device_ConfigurationChanged(void)
{
LEDs_SetAllLEDs(LEDMASK_USB_READY);
if (!(MS_Device_ConfigureEndpoints(&Disk_MS_Interface)))
LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
if (!(CDC_Device_ConfigureEndpoints(&VirtualSerial_CDC_Interface)))
LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
}
/** Event handler for the library USB Unhandled Control Request event. */
void EVENT_USB_Device_UnhandledControlRequest(void)
{
MS_Device_ProcessControlRequest(&Disk_MS_Interface);
CDC_Device_ProcessControlRequest(&VirtualSerial_CDC_Interface);
}
/** Mass Storage class driver callback function the reception of SCSI commands from the host, which must be processed.
*
* \param[in] MSInterfaceInfo Pointer to the Mass Storage class interface configuration structure being referenced
*/
bool CALLBACK_MS_Device_SCSICommandReceived(USB_ClassInfo_MS_Device_t* MSInterfaceInfo)
{
bool CommandSuccess;
LEDs_SetAllLEDs(LEDMASK_USB_BUSY);
CommandSuccess = SCSI_DecodeSCSICommand(MSInterfaceInfo);
LEDs_SetAllLEDs(LEDMASK_USB_READY);
return CommandSuccess;
}

@ -0,0 +1,94 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2009.
dean [at] fourwalledcubicle [dot] com
www.fourwalledcubicle.com
*/
/*
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, and distribute this software
and its documentation for any purpose and without fee is hereby
granted, 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 StandaloneProgrammer.c.
*/
#ifndef _STANDALONE_PROG_H_
#define _STANDALONE_PROG_H_
/* Includes: */
#include <avr/io.h>
#include <avr/wdt.h>
#include <avr/power.h>
#include <stdio.h>
#include "Descriptors.h"
#include "Lib/SCSI.h"
#include "Lib/DataflashManager.h"
#include "Lib/ProgrammerConfig.h"
#include "Lib/PetiteFATFs/pff.h"
#include <LUFA/Version.h>
#include <LUFA/Drivers/Board/LEDs.h>
#include <LUFA/Drivers/Board/Buttons.h>
#include <LUFA/Drivers/USB/USB.h>
#include <LUFA/Drivers/USB/Class/MassStorage.h>
#include <LUFA/Drivers/USB/Class/CDC.h>
/* Macros: */
/** LED mask for the library LED driver, to indicate that the USB interface is not ready. */
#define LEDMASK_USB_NOTREADY LEDS_LED1
/** LED mask for the library LED driver, to indicate that the USB interface is enumerating. */
#define LEDMASK_USB_ENUMERATING (LEDS_LED2 | LEDS_LED3)
/** LED mask for the library LED driver, to indicate that the USB interface is ready. */
#define LEDMASK_USB_READY (LEDS_LED2 | LEDS_LED4)
/** LED mask for the library LED driver, to indicate that an error has occurred in the USB interface. */
#define LEDMASK_USB_ERROR (LEDS_LED1 | LEDS_LED3)
/** LED mask for the library LED driver, to indicate that the USB interface is busy. */
#define LEDMASK_USB_BUSY (LEDS_LED2)
/* External Variables: */
extern FILE USBSerialStream;
extern FILE DataflashStream;
/* Function Prototypes: */
#if defined(INCLUDE_FROM_STANDALONEPROG_C)
static int Dataflash_getchar(FILE* Stream);
#endif
void SetupHardware(void);
void Programmer_Task(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);
bool CALLBACK_MS_Device_SCSICommandReceived(USB_ClassInfo_MS_Device_t* MSInterfaceInfo);
#endif

@ -0,0 +1,746 @@
# Hey Emacs, this is a -*- makefile -*-
#----------------------------------------------------------------------------
# WinAVR Makefile Template written by Eric B. Weddington, Jörg Wunsch, et al.
# >> Modified for use with the LUFA project. <<
#
# Released to the Public Domain
#
# Additional material for this makefile was written by:
# Peter Fleury
# Tim Henigan
# Colin O'Flynn
# Reiner Patommel
# Markus Pfaff
# Sander Pool
# Frederik Rouleau
# Carlos Lamas
# Dean Camera
# Opendous Inc.
# Denver Gingerich
#
#----------------------------------------------------------------------------
# On command line:
#
# make all = Make software.
#
# make clean = Clean out built project files.
#
# make coff = Convert ELF to AVR COFF.
#
# make extcoff = Convert ELF to AVR Extended COFF.
#
# make program = Download the hex file to the device, using avrdude.
# Please customize the avrdude settings below first!
#
# make dfu = Download the hex file to the device, using dfu-programmer (must
# have dfu-programmer installed).
#
# make flip = Download the hex file to the device, using Atmel FLIP (must
# have Atmel FLIP installed).
#
# make dfu-ee = Download the eeprom file to the device, using dfu-programmer
# (must have dfu-programmer installed).
#
# make flip-ee = Download the eeprom file to the device, using Atmel FLIP
# (must have Atmel FLIP installed).
#
# make doxygen = Generate DoxyGen documentation for the project (must have
# DoxyGen installed)
#
# make debug = Start either simulavr or avarice as specified for debugging,
# with avr-gdb or avr-insight as the front end for debugging.
#
# make filename.s = Just compile filename.c into the assembler code only.
#
# make filename.i = Create a preprocessed source file for use in submitting
# bug reports to the GCC project.
#
# To rebuild project do "make clean" then "make all".
#----------------------------------------------------------------------------
# MCU name
MCU = at90usb1287
# Target board (see library "Board Types" documentation, USER or blank for projects not requiring
# LUFA board drivers). If USER is selected, put custom board drivers in a directory called
# "Board" inside the application directory.
BOARD = USBKEY
# Processor frequency.
# This will define a symbol, F_CPU, in all source code files equal to the
# processor frequency in Hz. You can then use this symbol in your source code to
# calculate timings. Do NOT tack on a 'UL' at the end, this will be done
# automatically to create a 32-bit value in your source code.
#
# This will be an integer division of F_CLOCK below, as it is sourced by
# F_CLOCK after it has run through any CPU prescalers. Note that this value
# does not *change* the processor frequency - it should merely be updated to
# reflect the processor speed set externally so that the code can use accurate
# software delays.
F_CPU = 8000000
# Input clock frequency.
# This will define a symbol, F_CLOCK, in all source code files equal to the
# input clock frequency (before any prescaling is performed) in Hz. This value may
# differ from F_CPU if prescaling is used on the latter, and is required as the
# raw input clock is fed directly to the PLL sections of the AVR for high speed
# clock generation for the USB and other AVR subsections. Do NOT tack on a 'UL'
# at the end, this will be done automatically to create a 32-bit value in your
# source code.
#
# If no clock division is performed on the input clock inside the AVR (via the
# CPU clock adjust registers or the clock division fuses), this will be equal to F_CPU.
F_CLOCK = $(F_CPU)
# Output format. (can be srec, ihex, binary)
FORMAT = ihex
# Target file name (without extension).
TARGET = StandaloneProgrammer
# Object files directory
# To put object files in current directory, use a dot (.), do NOT make
# this an empty or blank macro!
OBJDIR = .
# Path to the LUFA library
LUFA_PATH = ../../../
# LUFA library compile-time options
LUFA_OPTS = -D USB_DEVICE_ONLY
LUFA_OPTS += -D FIXED_CONTROL_ENDPOINT_SIZE=8
LUFA_OPTS += -D FIXED_NUM_CONFIGURATIONS=1
LUFA_OPTS += -D USE_FLASH_DESCRIPTORS
LUFA_OPTS += -D USE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)"
LUFA_OPTS += -D INTERRUPT_CONTROL_ENDPOINT
# List C source files here. (C dependencies are automatically generated.)
SRC = $(TARGET).c \
Descriptors.c \
Lib/SCSI.c \
Lib/DataflashManager.c \
Lib/ProgrammerConfig.c \
Lib/PetiteFATFs/diskio.c \
Lib/PetiteFATFs/pff.c \
$(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c \
$(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Endpoint.c \
$(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Host.c \
$(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/HostChapter9.c \
$(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/LowLevel.c \
$(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Pipe.c \
$(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/Events.c \
$(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c \
$(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBTask.c \
$(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c \
$(LUFA_PATH)/LUFA/Drivers/USB/Class/Device/MassStorage.c \
$(LUFA_PATH)/LUFA/Drivers/USB/Class/Host/MassStorage.c \
$(LUFA_PATH)/LUFA/Drivers/USB/Class/Device/CDC.c \
$(LUFA_PATH)/LUFA/Drivers/USB/Class/Host/CDC.c \
# List C++ source files here. (C dependencies are automatically generated.)
CPPSRC =
# List Assembler source files here.
# Make them always end in a capital .S. Files ending in a lowercase .s
# will not be considered source files but generated files (assembler
# output from the compiler), and will be deleted upon "make clean"!
# Even though the DOS/Win* filesystem matches both .s and .S the same,
# it will preserve the spelling of the filenames, and gcc itself does
# care about how the name is spelled on its command-line.
ASRC =
# Optimization level, can be [0, 1, 2, 3, s].
# 0 = turn off optimization. s = optimize for size.
# (Note: 3 is not always the best optimization level. See avr-libc FAQ.)
OPT = s
# Debugging format.
# Native formats for AVR-GCC's -g are dwarf-2 [default] or stabs.
# AVR Studio 4.10 requires dwarf-2.
# AVR [Extended] COFF format requires stabs, plus an avr-objcopy run.
DEBUG = dwarf-2
# List any extra directories to look for include files here.
# Each directory must be seperated by a space.
# Use forward slashes for directory separators.
# For a directory that has spaces, enclose it in quotes.
EXTRAINCDIRS = $(LUFA_PATH)/
# Compiler flag to set the C Standard level.
# c89 = "ANSI" C
# gnu89 = c89 plus GCC extensions
# c99 = ISO C99 standard (not yet fully implemented)
# gnu99 = c99 plus GCC extensions
CSTANDARD = -std=gnu99
# Place -D or -U options here for C sources
CDEFS = -DF_CPU=$(F_CPU)UL -DF_CLOCK=$(F_CLOCK)UL -DBOARD=BOARD_$(BOARD) $(LUFA_OPTS)
# Place -D or -U options here for ASM sources
ADEFS = -DF_CPU=$(F_CPU)
# Place -D or -U options here for C++ sources
CPPDEFS = -DF_CPU=$(F_CPU)UL
#CPPDEFS += -D__STDC_LIMIT_MACROS
#CPPDEFS += -D__STDC_CONSTANT_MACROS
#---------------- Compiler Options C ----------------
# -g*: generate debugging information
# -O*: optimization level
# -f...: tuning, see GCC manual and avr-libc documentation
# -Wall...: warning level
# -Wa,...: tell GCC to pass this to the assembler.
# -adhlns...: create assembler listing
CFLAGS = -g$(DEBUG)
CFLAGS += $(CDEFS)
CFLAGS += -O$(OPT)
CFLAGS += -funsigned-char
CFLAGS += -funsigned-bitfields
CFLAGS += -ffunction-sections
CFLAGS += -fno-inline-small-functions
CFLAGS += -fpack-struct
CFLAGS += -fshort-enums
CFLAGS += -Wall
CFLAGS += -Wstrict-prototypes
CFLAGS += -Wundef
#CFLAGS += -fno-unit-at-a-time
#CFLAGS += -Wunreachable-code
#CFLAGS += -Wsign-compare
CFLAGS += -Wa,-adhlns=$(<:%.c=$(OBJDIR)/%.lst)
CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS))
CFLAGS += $(CSTANDARD)
#---------------- Compiler Options C++ ----------------
# -g*: generate debugging information
# -O*: optimization level
# -f...: tuning, see GCC manual and avr-libc documentation
# -Wall...: warning level
# -Wa,...: tell GCC to pass this to the assembler.
# -adhlns...: create assembler listing
CPPFLAGS = -g$(DEBUG)
CPPFLAGS += $(CPPDEFS)
CPPFLAGS += -O$(OPT)
CPPFLAGS += -funsigned-char
CPPFLAGS += -funsigned-bitfields
CPPFLAGS += -fpack-struct
CPPFLAGS += -fshort-enums
CPPFLAGS += -fno-exceptions
CPPFLAGS += -Wall
CFLAGS += -Wundef
#CPPFLAGS += -mshort-calls
#CPPFLAGS += -fno-unit-at-a-time
#CPPFLAGS += -Wstrict-prototypes
#CPPFLAGS += -Wunreachable-code
#CPPFLAGS += -Wsign-compare
CPPFLAGS += -Wa,-adhlns=$(<:%.cpp=$(OBJDIR)/%.lst)
CPPFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS))
#CPPFLAGS += $(CSTANDARD)
#---------------- Assembler Options ----------------
# -Wa,...: tell GCC to pass this to the assembler.
# -adhlns: create listing
# -gstabs: have the assembler create line number information; note that
# for use in COFF files, additional information about filenames
# and function names needs to be present in the assembler source
# files -- see avr-libc docs [FIXME: not yet described there]
# -listing-cont-lines: Sets the maximum number of continuation lines of hex
# dump that will be displayed for a given single line of source input.
ASFLAGS = $(ADEFS) -Wa,-adhlns=$(<:%.S=$(OBJDIR)/%.lst),-gstabs,--listing-cont-lines=100
#---------------- Library Options ----------------
# Minimalistic printf version
PRINTF_LIB_MIN = -Wl,-u,vfprintf -lprintf_min
# Floating point printf version (requires MATH_LIB = -lm below)
PRINTF_LIB_FLOAT = -Wl,-u,vfprintf -lprintf_flt
# If this is left blank, then it will use the Standard printf version.
PRINTF_LIB =
#PRINTF_LIB = $(PRINTF_LIB_MIN)
#PRINTF_LIB = $(PRINTF_LIB_FLOAT)
# Minimalistic scanf version
SCANF_LIB_MIN = -Wl,-u,vfscanf -lscanf_min
# Floating point + %[ scanf version (requires MATH_LIB = -lm below)
SCANF_LIB_FLOAT = -Wl,-u,vfscanf -lscanf_flt
# If this is left blank, then it will use the Standard scanf version.
SCANF_LIB =
#SCANF_LIB = $(SCANF_LIB_MIN)
#SCANF_LIB = $(SCANF_LIB_FLOAT)
MATH_LIB = -lm
# List any extra directories to look for libraries here.
# Each directory must be seperated by a space.
# Use forward slashes for directory separators.
# For a directory that has spaces, enclose it in quotes.
EXTRALIBDIRS =
#---------------- External Memory Options ----------------
# 64 KB of external RAM, starting after internal RAM (ATmega128!),
# used for variables (.data/.bss) and heap (malloc()).
#EXTMEMOPTS = -Wl,-Tdata=0x801100,--defsym=__heap_end=0x80ffff
# 64 KB of external RAM, starting after internal RAM (ATmega128!),
# only used for heap (malloc()).
#EXTMEMOPTS = -Wl,--section-start,.data=0x801100,--defsym=__heap_end=0x80ffff
EXTMEMOPTS =
#---------------- Linker Options ----------------
# -Wl,...: tell GCC to pass this to linker.
# -Map: create map file
# --cref: add cross reference to map file
LDFLAGS = -Wl,-Map=$(TARGET).map,--cref
LDFLAGS += -Wl,--relax
LDFLAGS += -Wl,--gc-sections
LDFLAGS += $(EXTMEMOPTS)
LDFLAGS += $(patsubst %,-L%,$(EXTRALIBDIRS))
LDFLAGS += $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB)
#LDFLAGS += -T linker_script.x
#---------------- Programming Options (avrdude) ----------------
# Programming hardware: alf avr910 avrisp bascom bsd
# dt006 pavr picoweb pony-stk200 sp12 stk200 stk500
#
# Type: avrdude -c ?
# to get a full listing.
#
AVRDUDE_PROGRAMMER = jtagmkII
# com1 = serial port. Use lpt1 to connect to parallel port.
AVRDUDE_PORT = usb
AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex
#AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep
# Uncomment the following if you want avrdude's erase cycle counter.
# Note that this counter needs to be initialized first using -Yn,
# see avrdude manual.
#AVRDUDE_ERASE_COUNTER = -y
# Uncomment the following if you do /not/ wish a verification to be
# performed after programming the device.
#AVRDUDE_NO_VERIFY = -V
# Increase verbosity level. Please use this when submitting bug
# reports about avrdude. See <http://savannah.nongnu.org/projects/avrdude>
# to submit bug reports.
#AVRDUDE_VERBOSE = -v -v
AVRDUDE_FLAGS = -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER)
AVRDUDE_FLAGS += $(AVRDUDE_NO_VERIFY)
AVRDUDE_FLAGS += $(AVRDUDE_VERBOSE)
AVRDUDE_FLAGS += $(AVRDUDE_ERASE_COUNTER)
#---------------- Debugging Options ----------------
# For simulavr only - target MCU frequency.
DEBUG_MFREQ = $(F_CPU)
# Set the DEBUG_UI to either gdb or insight.
# DEBUG_UI = gdb
DEBUG_UI = insight
# Set the debugging back-end to either avarice, simulavr.
DEBUG_BACKEND = avarice
#DEBUG_BACKEND = simulavr
# GDB Init Filename.
GDBINIT_FILE = __avr_gdbinit
# When using avarice settings for the JTAG
JTAG_DEV = /dev/com1
# Debugging port used to communicate between GDB / avarice / simulavr.
DEBUG_PORT = 4242
# Debugging host used to communicate between GDB / avarice / simulavr, normally
# just set to localhost unless doing some sort of crazy debugging when
# avarice is running on a different computer.
DEBUG_HOST = localhost
#============================================================================
# Define programs and commands.
SHELL = sh
CC = avr-gcc
OBJCOPY = avr-objcopy
OBJDUMP = avr-objdump
SIZE = avr-size
AR = avr-ar rcs
NM = avr-nm
AVRDUDE = avrdude
REMOVE = rm -f
REMOVEDIR = rm -rf
COPY = cp
WINSHELL = cmd
# Define Messages
# English
MSG_ERRORS_NONE = Errors: none
MSG_BEGIN = -------- begin --------
MSG_END = -------- end --------
MSG_SIZE_BEFORE = Size before:
MSG_SIZE_AFTER = Size after:
MSG_COFF = Converting to AVR COFF:
MSG_EXTENDED_COFF = Converting to AVR Extended COFF:
MSG_FLASH = Creating load file for Flash:
MSG_EEPROM = Creating load file for EEPROM:
MSG_EXTENDED_LISTING = Creating Extended Listing:
MSG_SYMBOL_TABLE = Creating Symbol Table:
MSG_LINKING = Linking:
MSG_COMPILING = Compiling C:
MSG_COMPILING_CPP = Compiling C++:
MSG_ASSEMBLING = Assembling:
MSG_CLEANING = Cleaning project:
MSG_CREATING_LIBRARY = Creating library:
# Define all object files.
OBJ = $(SRC:%.c=$(OBJDIR)/%.o) $(CPPSRC:%.cpp=$(OBJDIR)/%.o) $(ASRC:%.S=$(OBJDIR)/%.o)
# Define all listing files.
LST = $(SRC:%.c=$(OBJDIR)/%.lst) $(CPPSRC:%.cpp=$(OBJDIR)/%.lst) $(ASRC:%.S=$(OBJDIR)/%.lst)
# Compiler flags to generate dependency files.
GENDEPFLAGS = -MMD -MP -MF .dep/$(@F).d
# Combine all necessary flags and optional flags.
# Add target processor to flags.
ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) $(GENDEPFLAGS)
ALL_CPPFLAGS = -mmcu=$(MCU) -I. -x c++ $(CPPFLAGS) $(GENDEPFLAGS)
ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS)
# Default target.
all: begin gccversion sizebefore build checkinvalidevents showliboptions showtarget sizeafter end
# Change the build target to build a HEX file or a library.
build: elf hex eep lss sym
#build: lib
elf: $(TARGET).elf
hex: $(TARGET).hex
eep: $(TARGET).eep
lss: $(TARGET).lss
sym: $(TARGET).sym
LIBNAME=lib$(TARGET).a
lib: $(LIBNAME)
# Eye candy.
# AVR Studio 3.x does not check make's exit code but relies on
# the following magic strings to be generated by the compile job.
begin:
@echo
@echo $(MSG_BEGIN)
end:
@echo $(MSG_END)
@echo
# Display size of file.
HEXSIZE = $(SIZE) --target=$(FORMAT) $(TARGET).hex
ELFSIZE = $(SIZE) $(MCU_FLAG) $(FORMAT_FLAG) $(TARGET).elf
MCU_FLAG = $(shell $(SIZE) --help | grep -- --mcu > /dev/null && echo --mcu=$(MCU) )
FORMAT_FLAG = $(shell $(SIZE) --help | grep -- --format=.*avr > /dev/null && echo --format=avr )
sizebefore:
@if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_BEFORE); $(ELFSIZE); \
2>/dev/null; echo; fi
sizeafter:
@if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_AFTER); $(ELFSIZE); \
2>/dev/null; echo; fi
$(LUFA_PATH)/LUFA/LUFA_Events.lst:
@make -C $(LUFA_PATH)/LUFA/ LUFA_Events.lst
checkinvalidevents: $(LUFA_PATH)/LUFA/LUFA_Events.lst
@echo
@echo Checking for invalid events...
@$(shell) avr-nm $(OBJ) | sed -n -e 's/^.*EVENT_/EVENT_/p' | \
grep -F -v --file=$(LUFA_PATH)/LUFA/LUFA_Events.lst > InvalidEvents.tmp || true
@sed -n -e 's/^/ WARNING - INVALID EVENT NAME: /p' InvalidEvents.tmp
@if test -s InvalidEvents.tmp; then exit 1; fi
showliboptions:
@echo
@echo ---- Compile Time Library Options ----
@for i in $(LUFA_OPTS:-D%=%); do \
echo $$i; \
done
@echo --------------------------------------
showtarget:
@echo
@echo --------- Target Information ---------
@echo AVR Model: $(MCU)
@echo Board: $(BOARD)
@echo Clock: $(F_CPU)Hz CPU, $(F_CLOCK)Hz Master
@echo --------------------------------------
# Display compiler version information.
gccversion :
@$(CC) --version
# Program the device.
program: $(TARGET).hex $(TARGET).eep
$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM)
flip: $(TARGET).hex
batchisp -hardware usb -device $(MCU) -operation erase f
batchisp -hardware usb -device $(MCU) -operation loadbuffer $(TARGET).hex program
batchisp -hardware usb -device $(MCU) -operation start reset 0
dfu: $(TARGET).hex
dfu-programmer $(MCU) erase
dfu-programmer $(MCU) flash --debug 1 $(TARGET).hex
dfu-programmer $(MCU) reset
flip-ee: $(TARGET).hex $(TARGET).eep
$(COPY) $(TARGET).eep $(TARGET)eep.hex
batchisp -hardware usb -device $(MCU) -operation memory EEPROM erase
batchisp -hardware usb -device $(MCU) -operation memory EEPROM loadbuffer $(TARGET)eep.hex program
batchisp -hardware usb -device $(MCU) -operation start reset 0
$(REMOVE) $(TARGET)eep.hex
dfu-ee: $(TARGET).hex $(TARGET).eep
dfu-programmer $(MCU) flash-eeprom --debug 1 --suppress-bootloader-mem $(TARGET).eep
dfu-programmer $(MCU) reset
# Generate avr-gdb config/init file which does the following:
# define the reset signal, load the target file, connect to target, and set
# a breakpoint at main().
gdb-config:
@$(REMOVE) $(GDBINIT_FILE)
@echo define reset >> $(GDBINIT_FILE)
@echo SIGNAL SIGHUP >> $(GDBINIT_FILE)
@echo end >> $(GDBINIT_FILE)
@echo file $(TARGET).elf >> $(GDBINIT_FILE)
@echo target remote $(DEBUG_HOST):$(DEBUG_PORT) >> $(GDBINIT_FILE)
ifeq ($(DEBUG_BACKEND),simulavr)
@echo load >> $(GDBINIT_FILE)
endif
@echo break main >> $(GDBINIT_FILE)
debug: gdb-config $(TARGET).elf
ifeq ($(DEBUG_BACKEND), avarice)
@echo Starting AVaRICE - Press enter when "waiting to connect" message displays.
@$(WINSHELL) /c start avarice --jtag $(JTAG_DEV) --erase --program --file \
$(TARGET).elf $(DEBUG_HOST):$(DEBUG_PORT)
@$(WINSHELL) /c pause
else
@$(WINSHELL) /c start simulavr --gdbserver --device $(MCU) --clock-freq \
$(DEBUG_MFREQ) --port $(DEBUG_PORT)
endif
@$(WINSHELL) /c start avr-$(DEBUG_UI) --command=$(GDBINIT_FILE)
# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB.
COFFCONVERT = $(OBJCOPY) --debugging
COFFCONVERT += --change-section-address .data-0x800000
COFFCONVERT += --change-section-address .bss-0x800000
COFFCONVERT += --change-section-address .noinit-0x800000
COFFCONVERT += --change-section-address .eeprom-0x810000
coff: $(TARGET).elf
@echo
@echo $(MSG_COFF) $(TARGET).cof
$(COFFCONVERT) -O coff-avr $< $(TARGET).cof
extcoff: $(TARGET).elf
@echo
@echo $(MSG_EXTENDED_COFF) $(TARGET).cof
$(COFFCONVERT) -O coff-ext-avr $< $(TARGET).cof
# Create final output files (.hex, .eep) from ELF output file.
%.hex: %.elf
@echo
@echo $(MSG_FLASH) $@
$(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@
%.eep: %.elf
@echo
@echo $(MSG_EEPROM) $@
-$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \
--change-section-lma .eeprom=0 --no-change-warnings -O $(FORMAT) $< $@ || exit 0
# Create extended listing file from ELF output file.
%.lss: %.elf
@echo
@echo $(MSG_EXTENDED_LISTING) $@
$(OBJDUMP) -h -z -S $< > $@
# Create a symbol table from ELF output file.
%.sym: %.elf
@echo
@echo $(MSG_SYMBOL_TABLE) $@
$(NM) -n $< > $@
# Create library from object files.
.SECONDARY : $(TARGET).a
.PRECIOUS : $(OBJ)
%.a: $(OBJ)
@echo
@echo $(MSG_CREATING_LIBRARY) $@
$(AR) $@ $(OBJ)
# Link: create ELF output file from object files.
.SECONDARY : $(TARGET).elf
.PRECIOUS : $(OBJ)
%.elf: $(OBJ)
@echo
@echo $(MSG_LINKING) $@
$(CC) $(ALL_CFLAGS) $^ --output $@ $(LDFLAGS)
# Compile: create object files from C source files.
$(OBJDIR)/%.o : %.c
@echo
@echo $(MSG_COMPILING) $<
$(CC) -c $(ALL_CFLAGS) $< -o $@
# Compile: create object files from C++ source files.
$(OBJDIR)/%.o : %.cpp
@echo
@echo $(MSG_COMPILING_CPP) $<
$(CC) -c $(ALL_CPPFLAGS) $< -o $@
# Compile: create assembler files from C source files.
%.s : %.c
$(CC) -S $(ALL_CFLAGS) $< -o $@
# Compile: create assembler files from C++ source files.
%.s : %.cpp
$(CC) -S $(ALL_CPPFLAGS) $< -o $@
# Assemble: create object files from assembler source files.
$(OBJDIR)/%.o : %.S
@echo
@echo $(MSG_ASSEMBLING) $<
$(CC) -c $(ALL_ASFLAGS) $< -o $@
# Create preprocessed source for use in sending a bug report.
%.i : %.c
$(CC) -E -mmcu=$(MCU) -I. $(CFLAGS) $< -o $@
# Target: clean project.
clean: begin clean_list clean_binary end
clean_binary:
$(REMOVE) $(TARGET).hex
clean_list:
@echo $(MSG_CLEANING)
$(REMOVE) $(TARGET).eep
$(REMOVE) $(TARGET)eep.hex
$(REMOVE) $(TARGET).cof
$(REMOVE) $(TARGET).elf
$(REMOVE) $(TARGET).map
$(REMOVE) $(TARGET).sym
$(REMOVE) $(TARGET).lss
$(REMOVE) $(SRC:%.c=$(OBJDIR)/%.o)
$(REMOVE) $(SRC:%.c=$(OBJDIR)/%.lst)
$(REMOVE) $(SRC:.c=.s)
$(REMOVE) $(SRC:.c=.d)
$(REMOVE) $(SRC:.c=.i)
$(REMOVE) InvalidEvents.tmp
$(REMOVEDIR) .dep
doxygen:
@echo Generating Project Documentation...
@doxygen Doxygen.conf
@echo Documentation Generation Complete.
clean_doxygen:
rm -rf Documentation
# Create object files directory
$(shell mkdir $(OBJDIR) 2>/dev/null)
# Include the dependency files.
-include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*)
# Listing of phony targets.
.PHONY : all checkinvalidevents showliboptions \
showtarget begin finish end sizebefore sizeafter \
gccversion build elf hex eep lss sym coff extcoff \
program dfu flip flip-ee dfu-ee clean debug \
clean_list clean_binary gdb-config doxygen
Loading…
Cancel
Save