1
0
Fork 0

Squashed 'tmk_core/' changes from caca2c0..dc0e46e

dc0e46e Rename LUFA to LUFA-git
3bfa7fa Remove LUFA-120730
215b764 Merge commit 'afa0f22a9299686fd88f58ce09c5b521ac917e8f' as 'protocol/lufa/LUFA'
afa0f22 Squashed 'protocol/lufa/LUFA/' content from commit def7fca
c0c42fa Remove submodule of LUFA
30f897d Merge commit '87ced33feb74e79c3281dda36eb6d6d153399b41' as 'protocol/usb_hid/USB_Host_Shield_2.0'
87ced33 Squashed 'protocol/usb_hid/USB_Host_Shield_2.0/' content from commit aab4a69
14f6d49 Remove submodule of USB_Host_Shield_2.0

git-subtree-dir: tmk_core
git-subtree-split: dc0e46eaa4367d4e218f8816e3c117895820f07c
This commit is contained in:
tmk 2015-05-13 11:13:10 +09:00
parent 4d116a04e9
commit f6d56675f9
1575 changed files with 421901 additions and 63190 deletions

View file

@ -0,0 +1,534 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2014.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2014 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, provided that the above copyright notice appear in
all copies and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of the author not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
The author disclaims 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* const 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_8());
Dataflash_SendByte(Endpoint_Read_8());
Dataflash_SendByte(Endpoint_Read_8());
Dataflash_SendByte(Endpoint_Read_8());
Dataflash_SendByte(Endpoint_Read_8());
Dataflash_SendByte(Endpoint_Read_8());
Dataflash_SendByte(Endpoint_Read_8());
Dataflash_SendByte(Endpoint_Read_8());
Dataflash_SendByte(Endpoint_Read_8());
Dataflash_SendByte(Endpoint_Read_8());
Dataflash_SendByte(Endpoint_Read_8());
Dataflash_SendByte(Endpoint_Read_8());
Dataflash_SendByte(Endpoint_Read_8());
Dataflash_SendByte(Endpoint_Read_8());
Dataflash_SendByte(Endpoint_Read_8());
Dataflash_SendByte(Endpoint_Read_8());
/* 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--;
}
/* 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* const 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_8(Dataflash_ReceiveByte());
Endpoint_Write_8(Dataflash_ReceiveByte());
Endpoint_Write_8(Dataflash_ReceiveByte());
Endpoint_Write_8(Dataflash_ReceiveByte());
Endpoint_Write_8(Dataflash_ReceiveByte());
Endpoint_Write_8(Dataflash_ReceiveByte());
Endpoint_Write_8(Dataflash_ReceiveByte());
Endpoint_Write_8(Dataflash_ReceiveByte());
Endpoint_Write_8(Dataflash_ReceiveByte());
Endpoint_Write_8(Dataflash_ReceiveByte());
Endpoint_Write_8(Dataflash_ReceiveByte());
Endpoint_Write_8(Dataflash_ReceiveByte());
Endpoint_Write_8(Dataflash_ReceiveByte());
Endpoint_Write_8(Dataflash_ReceiveByte());
Endpoint_Write_8(Dataflash_ReceiveByte());
Endpoint_Write_8(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 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,
const 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(UsingSecondBuffer ? DF_CMD_BUFF2WRITE : 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 */
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 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 \c true if all media chips are working, \c 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;
}

View file

@ -0,0 +1,86 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2014.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2014 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, provided that the above copyright notice appear in
all copies and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of the author not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
The author disclaims 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 "../TempDataLogger.h"
#include "../Descriptors.h"
#include "Config/AppConfig.h"
#include <LUFA/Common/Common.h>
#include <LUFA/Drivers/USB/USB.h>
#include <LUFA/Drivers/Board/Dataflash.h>
/* 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* const MSInterfaceInfo,
const uint32_t BlockAddress,
uint16_t TotalBlocks);
void DataflashManager_ReadBlocks(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo,
const uint32_t BlockAddress,
uint16_t TotalBlocks);
void DataflashManager_WriteBlocks_RAM(const uint32_t BlockAddress,
uint16_t TotalBlocks,
const 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

View file

@ -0,0 +1,135 @@
FatFs Module Source Files R0.09a (C)ChaN, 2012
FILES
ffconf.h Configuration file for FatFs module.
ff.h Common include file for FatFs and application module.
ff.c FatFs module.
diskio.h Common include file for FatFs and disk I/O module.
diskio.c An example of glue function to attach existing disk I/O module to FatFs.
integer.h Integer type definitions for FatFs.
option Optional external functions.
Low level disk I/O module is not included in this archive because the 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
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) 2012, ChaN, all right reserved.
* The 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 product UNDER YOUR RESPONSIBILITY.
* Redistributions of source code must retain the above copyright notice.
REVISION HISTORY
Feb 26, 2006 R0.00 Prototype
Apr 29, 2006 R0.01 First release.
Jun 01, 2006 R0.02 Added FAT12.
Removed unbuffered mode.
Fixed a problem on small (<32M) patition.
Jun 10, 2006 R0.02a Added a configuration option _FS_MINIMUM.
Sep 22, 2006 R0.03 Added f_rename.
Changed option _FS_MINIMUM to _FS_MINIMIZE.
Dec 11, 2006 R0.03a Improved cluster scan algolithm to write files fast.
Fixed f_mkdir creates incorrect directory on FAT32.
Feb 04, 2007 R0.04 Supported multiple drive system. (FatFs)
Changed some APIs for multiple drive system.
Added f_mkfs. (FatFs)
Added _USE_FAT32 option. (Tiny-FatFs)
Apr 01, 2007 R0.04a Supported multiple partitions on a plysical drive. (FatFs)
Fixed an endian sensitive code in f_mkfs. (FatFs)
Added a capability of extending the file size to f_lseek.
Added minimization level 3.
Fixed a problem that can collapse a sector when recreate an
existing file in any sub-directory at non FAT32 cfg. (Tiny-FatFs)
May 05, 2007 R0.04b Added _USE_NTFLAG option.
Added FSInfo support.
Fixed some problems corresponds to FAT32. (Tiny-FatFs)
Fixed DBCS name can result FR_INVALID_NAME.
Fixed short seek (0 < ofs <= csize) collapses the file object.
Aug 25, 2007 R0.05 Changed arguments of f_read, f_write.
Changed arguments of f_mkfs. (FatFs)
Fixed f_mkfs on FAT32 creates incorrect FSInfo. (FatFs)
Fixed f_mkdir on FAT32 creates incorrect directory. (FatFs)
Feb 03, 2008 R0.05a Added f_truncate().
Added f_utime().
Fixed off by one error at FAT sub-type determination.
Fixed btr in f_read() can be mistruncated.
Fixed cached sector is not flushed when create and close without write.
Apr 01, 2008 R0.06 Added f_forward(). (Tiny-FatFs)
Added string functions: fputc(), fputs(), fprintf() and fgets().
Improved performance of f_lseek() on move to the same or following cluster.
Apr 01, 2009, R0.07 Merged Tiny-FatFs as a buffer configuration option.
Added long file name support.
Added multiple code page support.
Added re-entrancy for multitask operation.
Added auto cluster size selection to f_mkfs().
Added rewind option to f_readdir().
Changed result code of critical errors.
Renamed string functions to avoid name collision.
Apr 14, 2009, R0.07a Separated out OS dependent code on reentrant cfg.
Added multiple sector size support.
Jun 21, 2009, R0.07c Fixed f_unlink() may return FR_OK on error.
Fixed wrong cache control in f_lseek().
Added relative path feature.
Added f_chdir().
Added f_chdrive().
Added proper case conversion for extended characters.
Nov 03, 2009 R0.07e Separated out configuration options from ff.h to ffconf.h.
Added a configuration option, _LFN_UNICODE.
Fixed f_unlink() fails to remove a sub-dir on _FS_RPATH.
Fixed name matching error on the 13 char boundary.
Changed f_readdir() to return the SFN with always upper case on non-LFN cfg.
May 15, 2010, R0.08 Added a memory configuration option. (_USE_LFN)
Added file lock feature. (_FS_SHARE)
Added fast seek feature. (_USE_FASTSEEK)
Changed some types on the API, XCHAR->TCHAR.
Changed fname member in the FILINFO structure on Unicode cfg.
String functions support UTF-8 encoding files on Unicode cfg.
Aug 16,'10 R0.08a Added f_getcwd(). (_FS_RPATH = 2)
Added sector erase feature. (_USE_ERASE)
Moved file lock semaphore table from fs object to the bss.
Fixed a wrong directory entry is created on non-LFN cfg when the given name contains ';'.
Fixed f_mkfs() creates wrong FAT32 volume.
Jan 15,'11 R0.08b Fast seek feature is also applied to f_read() and f_write().
f_lseek() reports required table size on creating CLMP.
Extended format syntax of f_printf function.
Ignores duplicated directory separators in given path names.
Sep 06,'11 R0.09 f_mkfs() supports multiple partition to finish the multiple partition feature.
Added f_fdisk(). (_MULTI_PARTITION = 2)
Aug 27,'12 R0.09a Fixed assertion failure due to OS/2 EA on FAT12/16.
Changed API rejects null object pointer to avoid crash.
Changed option name _FS_SHARE to _FS_LOCK.

View file

@ -0,0 +1,98 @@
/*-----------------------------------------------------------------------*/
/* Low level disk I/O module skeleton for FatFs (C)ChaN, 2007 */
/*-----------------------------------------------------------------------*/
/* This is a stub disk I/O module that acts as front end of the existing */
/* disk I/O modules and attach it to FatFs module with common interface. */
/*-----------------------------------------------------------------------*/
#include "diskio.h"
/*-----------------------------------------------------------------------*/
/* Initialize a Drive */
DSTATUS disk_initialize (
BYTE drv /* Physical drive number (0..) */
)
{
return FR_OK;
}
/*-----------------------------------------------------------------------*/
/* Return Disk Status */
DSTATUS disk_status (
BYTE drv /* Physical drive number (0..) */
)
{
return FR_OK;
}
/*-----------------------------------------------------------------------*/
/* Read Sector(s) */
DRESULT disk_read (
BYTE drv, /* Physical drive number (0..) */
BYTE *buff, /* Data buffer to store read data */
DWORD sector, /* Sector address (LBA) */
BYTE count /* Number of sectors to read (1..128) */
)
{
DataflashManager_ReadBlocks_RAM(sector, count, buff);
return RES_OK;
}
/*-----------------------------------------------------------------------*/
/* Write Sector(s) */
#if _READONLY == 0
DRESULT disk_write (
BYTE drv, /* Physical drive number (0..) */
const BYTE *buff, /* Data to be written */
DWORD sector, /* Sector address (LBA) */
BYTE count /* Number of sectors to write (1..128) */
)
{
DataflashManager_WriteBlocks_RAM(sector, count, buff);
return RES_OK;
}
#endif /* _READONLY */
/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions */
DRESULT disk_ioctl (
BYTE drv, /* Physical drive number (0..) */
BYTE ctrl, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
if (ctrl == CTRL_SYNC)
return RES_OK;
else
return RES_PARERR;
}
DWORD get_fattime (void)
{
TimeDate_t CurrTimeDate;
RTC_GetTimeDate(&CurrTimeDate);
return ((DWORD)(20 + CurrTimeDate.Year) << 25) |
((DWORD)CurrTimeDate.Month << 21) |
((DWORD)CurrTimeDate.Day << 16) |
((DWORD)CurrTimeDate.Hour << 11) |
((DWORD)CurrTimeDate.Minute << 5) |
(((DWORD)CurrTimeDate.Second >> 1) << 0);
}

View file

@ -0,0 +1,55 @@
/*-----------------------------------------------------------------------
/ Low level disk interface module include file
/-----------------------------------------------------------------------*/
#ifndef _DISKIO_DEFINED
#define _DISKIO_DEFINED
#ifdef __cplusplus
extern "C" {
#endif
#include "integer.h"
#include "../DataflashManager.h"
/* Status of Disk Functions */
typedef BYTE DSTATUS;
/* Results of Disk Functions */
typedef enum {
RES_OK = 0, /* 0: Successful */
RES_ERROR, /* 1: R/W Error */
RES_WRPRT, /* 2: Write Protected */
RES_NOTRDY, /* 3: Not Ready */
RES_PARERR /* 4: Invalid Parameter */
} DRESULT;
/*---------------------------------------*/
/* Prototypes for disk control functions */
DSTATUS disk_initialize (BYTE);
DSTATUS disk_status (BYTE);
DRESULT disk_read (BYTE, BYTE*, DWORD, BYTE);
#if _READONLY == 0
DRESULT disk_write (BYTE, const BYTE*, DWORD, BYTE);
#endif
DRESULT disk_ioctl (BYTE, BYTE, void*);
/* Disk Status Bits (DSTATUS) */
#define STA_NOINIT 0x01 /* Drive not initialized */
#define STA_NODISK 0x02 /* No medium in the drive */
#define STA_PROTECT 0x04 /* Write protected */
/* Generic command */
#define CTRL_SYNC 0 /* Mandatory for write functions */
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,337 @@
/*---------------------------------------------------------------------------/
/ FatFs - FAT file system module include file R0.09a (C)ChaN, 2012
/----------------------------------------------------------------------------/
/ FatFs module is a generic FAT file system module for small embedded systems.
/ This is a free software that opened for education, research and commercial
/ developments under license policy of following terms.
/
/ Copyright (C) 2012, ChaN, all right reserved.
/
/ * The 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 product UNDER YOUR RESPONSIBILITY.
/ * Redistributions of source code must retain the above copyright notice.
/
/----------------------------------------------------------------------------*/
#ifndef _FATFS
#define _FATFS 4004 /* Revision ID */
#ifdef __cplusplus
extern "C" {
#endif
#include "integer.h" /* Basic integer types */
#include "ffconf.h" /* FatFs configuration options */
#if _FATFS != _FFCONF
#error Wrong configuration file (ffconf.h).
#endif
/* Definitions of volume management */
#if _MULTI_PARTITION /* Multiple partition configuration */
typedef struct {
BYTE pd; /* Physical drive number */
BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */
} PARTITION;
extern PARTITION VolToPart[]; /* Volume - Partition resolution table */
#define LD2PD(vol) (VolToPart[vol].pd) /* Get physical drive number */
#define LD2PT(vol) (VolToPart[vol].pt) /* Get partition index */
#else /* Single partition configuration */
#define LD2PD(vol) (BYTE)(vol) /* Each logical drive is bound to the same physical drive number */
#define LD2PT(vol) 0 /* Always mounts the 1st partition or in SFD */
#endif
/* Type of path name strings on FatFs API */
#if _LFN_UNICODE /* Unicode string */
#if !_USE_LFN
#error _LFN_UNICODE must be 0 in non-LFN cfg.
#endif
#ifndef _INC_TCHAR
typedef WCHAR TCHAR;
#define _T(x) L ## x
#define _TEXT(x) L ## x
#endif
#else /* ANSI/OEM string */
#ifndef _INC_TCHAR
typedef char TCHAR;
#define _T(x) x
#define _TEXT(x) x
#endif
#endif
/* File system object structure (FATFS) */
typedef struct {
BYTE fs_type; /* FAT sub-type (0:Not mounted) */
BYTE drv; /* Physical drive number */
BYTE csize; /* Sectors per cluster (1,2,4...128) */
BYTE n_fats; /* Number of FAT copies (1,2) */
BYTE wflag; /* win[] dirty flag (1:must be written back) */
BYTE fsi_flag; /* fsinfo dirty flag (1:must be written back) */
WORD id; /* File system mount ID */
WORD n_rootdir; /* Number of root directory entries (FAT12/16) */
#if _MAX_SS != 512
WORD ssize; /* Bytes per sector (512, 1024, 2048 or 4096) */
#endif
#if _FS_REENTRANT
_SYNC_t sobj; /* Identifier of sync object */
#endif
#if !_FS_READONLY
DWORD last_clust; /* Last allocated cluster */
DWORD free_clust; /* Number of free clusters */
DWORD fsi_sector; /* fsinfo sector (FAT32) */
#endif
#if _FS_RPATH
DWORD cdir; /* Current directory start cluster (0:root) */
#endif
DWORD n_fatent; /* Number of FAT entries (= number of clusters + 2) */
DWORD fsize; /* Sectors per FAT */
DWORD fatbase; /* FAT start sector */
DWORD dirbase; /* Root directory start sector (FAT32:Cluster#) */
DWORD database; /* Data start sector */
DWORD winsect; /* Current sector appearing in the win[] */
BYTE win[_MAX_SS]; /* Disk access window for Directory, FAT (and Data on tiny cfg) */
} FATFS;
/* File object structure (FIL) */
typedef struct {
FATFS* fs; /* Pointer to the related file system object */
WORD id; /* File system mount ID of the related file system object */
BYTE flag; /* File status flags */
BYTE pad1;
DWORD fptr; /* File read/write pointer (0ed on file open) */
DWORD fsize; /* File size */
DWORD sclust; /* File data start cluster (0:no data cluster, always 0 when fsize is 0) */
DWORD clust; /* Current cluster of fpter */
DWORD dsect; /* Current data sector of fpter */
#if !_FS_READONLY
DWORD dir_sect; /* Sector containing the directory entry */
BYTE* dir_ptr; /* Pointer to the directory entry in the window */
#endif
#if _USE_FASTSEEK
DWORD* cltbl; /* Pointer to the cluster link map table (null on file open) */
#endif
#if _FS_LOCK
UINT lockid; /* File lock ID (index of file semaphore table Files[]) */
#endif
#if !_FS_TINY
BYTE buf[_MAX_SS]; /* File data read/write buffer */
#endif
} FIL;
/* Directory object structure (DIR) */
typedef struct {
FATFS* fs; /* Pointer to the owner file system object */
WORD id; /* Owner file system mount ID */
WORD index; /* Current read/write index number */
DWORD sclust; /* Table start cluster (0:Root dir) */
DWORD clust; /* Current cluster */
DWORD sect; /* Current sector */
BYTE* dir; /* Pointer to the current SFN entry in the win[] */
BYTE* fn; /* Pointer to the SFN (in/out) {file[8],ext[3],status[1]} */
#if _USE_LFN
WCHAR* lfn; /* Pointer to the LFN working buffer */
WORD lfn_idx; /* Last matched LFN index number (0xFFFF:No LFN) */
#endif
} DIR;
/* File status structure (FILINFO) */
typedef struct {
DWORD fsize; /* File size */
WORD fdate; /* Last modified date */
WORD ftime; /* Last modified time */
BYTE fattrib; /* Attribute */
TCHAR fname[13]; /* Short file name (8.3 format) */
#if _USE_LFN
TCHAR* lfname; /* Pointer to the LFN buffer */
UINT lfsize; /* Size of LFN buffer in TCHAR */
#endif
} FILINFO;
/* File function return code (FRESULT) */
typedef enum {
FR_OK = 0, /* (0) Succeeded */
FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */
FR_INT_ERR, /* (2) Assertion failed */
FR_NOT_READY, /* (3) The physical drive cannot work */
FR_NO_FILE, /* (4) Could not find the file */
FR_NO_PATH, /* (5) Could not find the path */
FR_INVALID_NAME, /* (6) The path name format is invalid */
FR_DENIED, /* (7) Access denied due to prohibited access or directory full */
FR_EXIST, /* (8) Access denied due to prohibited access */
FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */
FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */
FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */
FR_NOT_ENABLED, /* (12) The volume has no work area */
FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */
FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any parameter error */
FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */
FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_SHARE */
FR_INVALID_PARAMETER /* (19) Given parameter is invalid */
} FRESULT;
/*--------------------------------------------------------------*/
/* FatFs module application interface */
FRESULT f_mount (BYTE, FATFS*); /* Mount/Unmount a logical drive */
FRESULT f_open (FIL*, const TCHAR*, BYTE); /* Open or create a file */
FRESULT f_read (FIL*, void*, UINT, UINT*); /* Read data from a file */
FRESULT f_lseek (FIL*, DWORD); /* Move file pointer of a file object */
FRESULT f_close (FIL*); /* Close an open file object */
FRESULT f_opendir (DIR*, const TCHAR*); /* Open an existing directory */
FRESULT f_readdir (DIR*, FILINFO*); /* Read a directory item */
FRESULT f_stat (const TCHAR*, FILINFO*); /* Get file status */
FRESULT f_write (FIL*, const void*, UINT, UINT*); /* Write data to a file */
FRESULT f_getfree (const TCHAR*, DWORD*, FATFS**); /* Get number of free clusters on the drive */
FRESULT f_truncate (FIL*); /* Truncate file */
FRESULT f_sync (FIL*); /* Flush cached data of a writing file */
FRESULT f_unlink (const TCHAR*); /* Delete an existing file or directory */
FRESULT f_mkdir (const TCHAR*); /* Create a new directory */
FRESULT f_chmod (const TCHAR*, BYTE, BYTE); /* Change attribute of the file/dir */
FRESULT f_utime (const TCHAR*, const FILINFO*); /* Change times-tamp of the file/dir */
FRESULT f_rename (const TCHAR*, const TCHAR*); /* Rename/Move a file or directory */
FRESULT f_chdrive (BYTE); /* Change current drive */
FRESULT f_chdir (const TCHAR*); /* Change current directory */
FRESULT f_getcwd (TCHAR*, UINT); /* Get current directory */
FRESULT f_forward (FIL*, UINT(*)(const BYTE*,UINT), UINT, UINT*); /* Forward data to the stream */
FRESULT f_mkfs (BYTE, BYTE, UINT); /* Create a file system on the drive */
FRESULT f_fdisk (BYTE, const DWORD[], void*); /* Divide a physical drive into some partitions */
int f_putc (TCHAR, FIL*); /* Put a character to the file */
int f_puts (const TCHAR*, FIL*); /* Put a string to the file */
int f_printf (FIL*, const TCHAR*, ...); /* Put a formatted string to the file */
TCHAR* f_gets (TCHAR*, int, FIL*); /* Get a string from the file */
#define f_eof(fp) (((fp)->fptr == (fp)->fsize) ? 1 : 0)
#define f_error(fp) (((fp)->flag & FA__ERROR) ? 1 : 0)
#define f_tell(fp) ((fp)->fptr)
#define f_size(fp) ((fp)->fsize)
#ifndef EOF
#define EOF (-1)
#endif
/*--------------------------------------------------------------*/
/* Additional user defined functions */
/* RTC function */
#if !_FS_READONLY
DWORD get_fattime (void);
#endif
/* Unicode support functions */
#if _USE_LFN /* Unicode - OEM code conversion */
WCHAR ff_convert (WCHAR, UINT); /* OEM-Unicode bidirectional conversion */
WCHAR ff_wtoupper (WCHAR); /* Unicode upper-case conversion */
#if _USE_LFN == 3 /* Memory functions */
void* ff_memalloc (UINT); /* Allocate memory block */
void ff_memfree (void*); /* Free memory block */
#endif
#endif
/* Sync functions */
#if _FS_REENTRANT
int ff_cre_syncobj (BYTE, _SYNC_t*);/* Create a sync object */
int ff_req_grant (_SYNC_t); /* Lock sync object */
void ff_rel_grant (_SYNC_t); /* Unlock sync object */
int ff_del_syncobj (_SYNC_t); /* Delete a sync object */
#endif
/*--------------------------------------------------------------*/
/* Flags and offset address */
/* File access control and file status flags (FIL.flag) */
#define FA_READ 0x01
#define FA_OPEN_EXISTING 0x00
#define FA__ERROR 0x80
#if !_FS_READONLY
#define FA_WRITE 0x02
#define FA_CREATE_NEW 0x04
#define FA_CREATE_ALWAYS 0x08
#define FA_OPEN_ALWAYS 0x10
#define FA__WRITTEN 0x20
#define FA__DIRTY 0x40
#endif
/* 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 */
/* Fast seek feature */
#define CREATE_LINKMAP 0xFFFFFFFF
/*--------------------------------*/
/* 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
#ifdef __cplusplus
}
#endif
#endif /* _FATFS */

View file

@ -0,0 +1,191 @@
/*---------------------------------------------------------------------------/
/ FatFs - FAT file system module configuration file R0.09a (C)ChaN, 2012
/----------------------------------------------------------------------------/
/
/ CAUTION! Do not forget to make clean the project after any changes to
/ the configuration options.
/
/----------------------------------------------------------------------------*/
#ifndef _FFCONF
#define _FFCONF 4004 /* Revision ID */
/*---------------------------------------------------------------------------/
/ Function and Buffer Configurations
/----------------------------------------------------------------------------*/
#define _FS_TINY 1 /* 0:Normal or 1:Tiny */
/* When _FS_TINY is set to 1, FatFs uses the sector buffer in the file system
/ object instead of the sector buffer in the individual file object for file
/ data transfer. This reduces memory consumption 512 bytes each file object. */
#define _FS_READONLY 0 /* 0:Read/Write or 1:Read only */
/* Setting _FS_READONLY to 1 defines read only configuration. This removes
/ writing functions, f_write, f_sync, f_unlink, f_mkdir, f_chmod, f_rename,
/ f_truncate and useless f_getfree. */
#define _FS_MINIMIZE 2 /* 0 to 3 */
/* The _FS_MINIMIZE option defines minimization level to remove some functions.
/
/ 0: Full function.
/ 1: f_stat, f_getfree, f_unlink, f_mkdir, f_chmod, f_truncate and f_rename
/ are removed.
/ 2: f_opendir and f_readdir are removed in addition to 1.
/ 3: f_lseek is removed in addition to 2. */
#define _USE_STRFUNC 0 /* 0:Disable or 1-2:Enable */
/* To enable string functions, set _USE_STRFUNC to 1 or 2. */
#define _USE_MKFS 0 /* 0:Disable or 1:Enable */
/* To enable f_mkfs function, set _USE_MKFS to 1 and set _FS_READONLY to 0 */
#define _USE_FORWARD 0 /* 0:Disable or 1:Enable */
/* To enable f_forward function, set _USE_FORWARD to 1 and set _FS_TINY to 1. */
#define _USE_FASTSEEK 0 /* 0:Disable or 1:Enable */
/* To enable fast seek feature, set _USE_FASTSEEK to 1. */
/*---------------------------------------------------------------------------/
/ Locale and Namespace Configurations
/----------------------------------------------------------------------------*/
#define _CODE_PAGE 932
/* The _CODE_PAGE specifies the OEM code page to be used on the target system.
/ Incorrect setting of the code page can cause a file open failure.
/
/ 932 - Japanese Shift-JIS (DBCS, OEM, Windows)
/ 936 - Simplified Chinese GBK (DBCS, OEM, Windows)
/ 949 - Korean (DBCS, OEM, Windows)
/ 950 - Traditional Chinese Big5 (DBCS, OEM, Windows)
/ 1250 - Central Europe (Windows)
/ 1251 - Cyrillic (Windows)
/ 1252 - Latin 1 (Windows)
/ 1253 - Greek (Windows)
/ 1254 - Turkish (Windows)
/ 1255 - Hebrew (Windows)
/ 1256 - Arabic (Windows)
/ 1257 - Baltic (Windows)
/ 1258 - Vietnam (OEM, Windows)
/ 437 - U.S. (OEM)
/ 720 - Arabic (OEM)
/ 737 - Greek (OEM)
/ 775 - Baltic (OEM)
/ 850 - Multilingual Latin 1 (OEM)
/ 858 - Multilingual Latin 1 + Euro (OEM)
/ 852 - Latin 2 (OEM)
/ 855 - Cyrillic (OEM)
/ 866 - Russian (OEM)
/ 857 - Turkish (OEM)
/ 862 - Hebrew (OEM)
/ 874 - Thai (OEM, Windows)
/ 1 - ASCII only (Valid for non LFN cfg.)
*/
#define _USE_LFN 0 /* 0 to 3 */
#define _MAX_LFN 255 /* Maximum LFN length to handle (12 to 255) */
/* The _USE_LFN option switches the LFN support.
/
/ 0: Disable LFN feature. _MAX_LFN and _LFN_UNICODE have no effect.
/ 1: Enable LFN with static working buffer on the BSS. Always NOT reentrant.
/ 2: Enable LFN with dynamic working buffer on the STACK.
/ 3: Enable LFN with dynamic working buffer on the HEAP.
/
/ The LFN working buffer occupies (_MAX_LFN + 1) * 2 bytes. To enable LFN,
/ Unicode handling functions ff_convert() and ff_wtoupper() must be added
/ to the project. When enable to use heap, memory control functions
/ ff_memalloc() and ff_memfree() must be added to the project. */
#define _LFN_UNICODE 0 /* 0:ANSI/OEM or 1:Unicode */
/* To switch the character code set on FatFs API to Unicode,
/ enable LFN feature and set _LFN_UNICODE to 1. */
#define _FS_RPATH 0 /* 0 to 2 */
/* The _FS_RPATH option configures relative path feature.
/
/ 0: Disable relative path feature and remove related functions.
/ 1: Enable relative path. f_chdrive() and f_chdir() are available.
/ 2: f_getcwd() is available in addition to 1.
/
/ Note that output of the f_readdir fnction is affected by this option. */
/*---------------------------------------------------------------------------/
/ Physical Drive Configurations
/----------------------------------------------------------------------------*/
#define _VOLUMES 1
/* Number of volumes (logical drives) to be used. */
#define _MAX_SS 512 /* 512, 1024, 2048 or 4096 */
/* Maximum sector size to be handled.
/ Always set 512 for memory card and hard disk but a larger value may be
/ required for on-board flash memory, floppy disk and optical disk.
/ When _MAX_SS is larger than 512, it configures FatFs to variable sector size
/ and GET_SECTOR_SIZE command must be implememted to the disk_ioctl function. */
#define _MULTI_PARTITION 0 /* 0:Single partition, 1/2:Enable multiple partition */
/* When set to 0, each volume is bound to the same physical drive number and
/ it can mount only first primaly partition. When it is set to 1, each volume
/ is tied to the partitions listed in VolToPart[]. */
#define _USE_ERASE 0 /* 0:Disable or 1:Enable */
/* To enable sector erase feature, set _USE_ERASE to 1. CTRL_ERASE_SECTOR command
/ should be added to the disk_ioctl functio. */
/*---------------------------------------------------------------------------/
/ System Configurations
/----------------------------------------------------------------------------*/
#define _WORD_ACCESS 1 /* 0 or 1 */
/* Set 0 first and it is always compatible with all platforms. The _WORD_ACCESS
/ option defines which access method is used to the word data on the FAT volume.
/
/ 0: Byte-by-byte access.
/ 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 size.
*/
/* A header file that defines sync object types on the O/S, such as
/ windows.h, ucos_ii.h and semphr.h, must be included prior to ff.h. */
#define _FS_REENTRANT 0 /* 0:Disable or 1:Enable */
#define _FS_TIMEOUT 1000 /* Timeout period in unit of time ticks */
#define _SYNC_t HANDLE /* O/S dependent type of sync object. e.g. HANDLE, OS_EVENT*, ID and etc.. */
/* The _FS_REENTRANT option switches the reentrancy (thread safe) of the FatFs module.
/
/ 0: Disable reentrancy. _SYNC_t and _FS_TIMEOUT have no effect.
/ 1: Enable reentrancy. Also user provided synchronization handlers,
/ ff_req_grant, ff_rel_grant, ff_del_syncobj and ff_cre_syncobj
/ function must be added to the project. */
#define _FS_LOCK 0 /* 0:Disable or >=1:Enable */
/* To enable file lock control feature, set _FS_LOCK to 1 or greater.
The value defines how many files can be opened simultaneously. */
#endif /* _FFCONFIG */

View file

@ -0,0 +1,38 @@
/*-------------------------------------------*/
/* Integer type definitions for FatFs module */
/*-------------------------------------------*/
#ifndef _INTEGER
#define _INTEGER
#ifdef _WIN32 /* FatFs development platform */
#include <windows.h>
#include <tchar.h>
#else /* Embedded platform */
/* 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 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;
#endif
#endif

View file

@ -0,0 +1,159 @@
/*
Copyright (C) Dean Camera, 2014.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
#include "RTC.h"
#if defined(DUMMY_RTC)
/** Current dummy RTC time and date */
static volatile TimeDate_t DummyRTC_Count;
void RTC_Init(void)
{
DummyRTC_Count.Hour = 0;
DummyRTC_Count.Minute = 0;
DummyRTC_Count.Second = 0;
DummyRTC_Count.Day = 1;
DummyRTC_Count.Month = 1;
DummyRTC_Count.Year = 00;
}
void RTC_Tick500ms(void)
{
static bool HalfSecondElapsed = false;
HalfSecondElapsed = !HalfSecondElapsed;
if (HalfSecondElapsed == false)
return;
if (++DummyRTC_Count.Second < 60)
return;
DummyRTC_Count.Second = 0;
if (++DummyRTC_Count.Minute < 60)
return;
DummyRTC_Count.Minute = 0;
if (++DummyRTC_Count.Hour < 24)
return;
DummyRTC_Count.Hour = 0;
static const char MonthLength[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
uint8_t DaysInMonth = MonthLength[DummyRTC_Count.Month - 1];
/* Check if we need to account for a leap year */
if ((DummyRTC_Count.Month == 2) &&
((!(DummyRTC_Count.Year % 400)) || ((DummyRTC_Count.Year % 100) && !(DummyRTC_Count.Year % 4))))
{
DaysInMonth++;
}
if (++DummyRTC_Count.Day <= DaysInMonth)
return;
DummyRTC_Count.Day = 1;
if (++DummyRTC_Count.Month <= 12)
return;
DummyRTC_Count.Month = 1;
DummyRTC_Count.Year++;
}
bool RTC_SetTimeDate(const TimeDate_t* NewTimeDate)
{
GlobalInterruptDisable();
DummyRTC_Count = *NewTimeDate;
GlobalInterruptEnable();
return true;
}
bool RTC_GetTimeDate(TimeDate_t* const TimeDate)
{
GlobalInterruptDisable();
*TimeDate = DummyRTC_Count;
GlobalInterruptEnable();
return true;
}
#else
void RTC_Init(void)
{
/* Unused for a real external DS1307 RTC device */
}
void RTC_Tick500ms(void)
{
/* Unused for a real external DS1307 RTC device */
}
bool RTC_SetTimeDate(const TimeDate_t* NewTimeDate)
{
DS1307_DateTimeRegs_t NewRegValues;
const uint8_t WriteAddress = 0;
// Convert new time data to the DS1307's time register layout
NewRegValues.Byte1.Fields.TenSec = (NewTimeDate->Second / 10);
NewRegValues.Byte1.Fields.Sec = (NewTimeDate->Second % 10);
NewRegValues.Byte1.Fields.CH = false;
NewRegValues.Byte2.Fields.TenMin = (NewTimeDate->Minute / 10);
NewRegValues.Byte2.Fields.Min = (NewTimeDate->Minute % 10);
NewRegValues.Byte3.Fields.TenHour = (NewTimeDate->Hour / 10);
NewRegValues.Byte3.Fields.Hour = (NewTimeDate->Hour % 10);
NewRegValues.Byte3.Fields.TwelveHourMode = false;
// Convert new date data to the DS1307's date register layout
NewRegValues.Byte4.Fields.DayOfWeek = 0;
NewRegValues.Byte5.Fields.TenDay = (NewTimeDate->Day / 10);
NewRegValues.Byte5.Fields.Day = (NewTimeDate->Day % 10);
NewRegValues.Byte6.Fields.TenMonth = (NewTimeDate->Month / 10);
NewRegValues.Byte6.Fields.Month = (NewTimeDate->Month % 10);
NewRegValues.Byte7.Fields.TenYear = (NewTimeDate->Year / 10);
NewRegValues.Byte7.Fields.Year = (NewTimeDate->Year % 10);
// Write the new Time and Date into the DS1307
if (TWI_WritePacket(DS1307_ADDRESS, 10, &WriteAddress, sizeof(WriteAddress),
(uint8_t*)&NewRegValues, sizeof(DS1307_DateTimeRegs_t)) != TWI_ERROR_NoError)
{
return false;
}
return true;
}
bool RTC_GetTimeDate(TimeDate_t* const TimeDate)
{
DS1307_DateTimeRegs_t CurrentRegValues;
const uint8_t ReadAddress = 0;
// Read in the stored Time and Date from the DS1307
if (TWI_ReadPacket(DS1307_ADDRESS, 10, &ReadAddress, sizeof(ReadAddress),
(uint8_t*)&CurrentRegValues, sizeof(DS1307_DateTimeRegs_t)) != TWI_ERROR_NoError)
{
return false;
}
// Convert stored time value into decimal
TimeDate->Second = (CurrentRegValues.Byte1.Fields.TenSec * 10) + CurrentRegValues.Byte1.Fields.Sec;
TimeDate->Minute = (CurrentRegValues.Byte2.Fields.TenMin * 10) + CurrentRegValues.Byte2.Fields.Min;
TimeDate->Hour = (CurrentRegValues.Byte3.Fields.TenHour * 10) + CurrentRegValues.Byte3.Fields.Hour;
// Convert stored date value into decimal
TimeDate->Day = (CurrentRegValues.Byte5.Fields.TenDay * 10) + CurrentRegValues.Byte5.Fields.Day;
TimeDate->Month = (CurrentRegValues.Byte6.Fields.TenMonth * 10) + CurrentRegValues.Byte6.Fields.Month;
TimeDate->Year = (CurrentRegValues.Byte7.Fields.TenYear * 10) + CurrentRegValues.Byte7.Fields.Year;
return true;
}
#endif

View file

@ -0,0 +1,126 @@
/*
Copyright (C) Dean Camera, 2014.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
#ifndef _RTC_H_
#define _RTC_H_
/* Includes: */
#include <avr/io.h>
#include <LUFA/Drivers/Peripheral/TWI.h>
#include "Config/AppConfig.h"
/* Type Defines: */
typedef struct
{
uint8_t Hour;
uint8_t Minute;
uint8_t Second;
uint8_t Day;
uint8_t Month;
uint8_t Year;
} TimeDate_t;
typedef struct
{
union
{
struct
{
unsigned Sec : 4;
unsigned TenSec : 3;
unsigned CH : 1;
} Fields;
uint8_t IntVal;
} Byte1;
union
{
struct
{
unsigned Min : 4;
unsigned TenMin : 3;
unsigned Reserved : 1;
} Fields;
uint8_t IntVal;
} Byte2;
union
{
struct
{
unsigned Hour : 4;
unsigned TenHour : 2;
unsigned TwelveHourMode : 1;
unsigned Reserved : 1;
} Fields;
uint8_t IntVal;
} Byte3;
union
{
struct
{
unsigned DayOfWeek : 3;
unsigned Reserved : 5;
} Fields;
uint8_t IntVal;
} Byte4;
union
{
struct
{
unsigned Day : 4;
unsigned TenDay : 2;
unsigned Reserved : 2;
} Fields;
uint8_t IntVal;
} Byte5;
union
{
struct
{
unsigned Month : 4;
unsigned TenMonth : 1;
unsigned Reserved : 3;
} Fields;
uint8_t IntVal;
} Byte6;
union
{
struct
{
unsigned Year : 4;
unsigned TenYear : 4;
} Fields;
uint8_t IntVal;
} Byte7;
} DS1307_DateTimeRegs_t;
/* Macros: */
/** TWI address of the DS1307 device on the bus. */
#define DS1307_ADDRESS 0xD0
/* Function Prototypes: */
void RTC_Init(void);
void RTC_Tick500ms(void);
bool RTC_SetTimeDate(const TimeDate_t* NewTimeDate);
bool RTC_GetTimeDate(TimeDate_t* const TimeDate);
#endif

View file

@ -0,0 +1,344 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2014.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2014 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, provided that the above copyright notice appear in
all copies and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of the author not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
The author disclaims 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.
*/
static const 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.
*/
static 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
*
* \return Boolean \c true if the command completed successfully, \c false otherwise
*/
bool SCSI_DecodeSCSICommand(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo)
{
bool CommandSuccess = false;
/* Run the appropriate SCSI command hander function based on the passed command */
switch (MSInterfaceInfo->State.CommandBlock.SCSICommandData[0])
{
case SCSI_CMD_INQUIRY:
CommandSuccess = SCSI_Command_Inquiry(MSInterfaceInfo);
break;
case SCSI_CMD_REQUEST_SENSE:
CommandSuccess = SCSI_Command_Request_Sense(MSInterfaceInfo);
break;
case SCSI_CMD_READ_CAPACITY_10:
CommandSuccess = SCSI_Command_Read_Capacity_10(MSInterfaceInfo);
break;
case SCSI_CMD_SEND_DIAGNOSTIC:
CommandSuccess = SCSI_Command_Send_Diagnostic(MSInterfaceInfo);
break;
case SCSI_CMD_WRITE_10:
CommandSuccess = SCSI_Command_ReadWrite_10(MSInterfaceInfo, DATA_WRITE);
break;
case SCSI_CMD_READ_10:
CommandSuccess = SCSI_Command_ReadWrite_10(MSInterfaceInfo, DATA_READ);
break;
case SCSI_CMD_MODE_SENSE_6:
CommandSuccess = SCSI_Command_ModeSense_6(MSInterfaceInfo);
break;
case SCSI_CMD_START_STOP_UNIT:
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 */
CommandSuccess = true;
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;
}
/* Check if command was successfully processed */
if (CommandSuccess)
{
SCSI_SET_SENSE(SCSI_SENSE_KEY_GOOD,
SCSI_ASENSE_NO_ADDITIONAL_INFORMATION,
SCSI_ASENSEQ_NO_QUALIFIER);
return true;
}
return false;
}
/** 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
*
* \return Boolean \c true if the command completed successfully, \c false otherwise.
*/
static bool SCSI_Command_Inquiry(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo)
{
uint16_t AllocationLength = SwapEndian_16(*(uint16_t*)&MSInterfaceInfo->State.CommandBlock.SCSICommandData[3]);
uint16_t BytesTransferred = MIN(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 false;
}
Endpoint_Write_Stream_LE(&InquiryData, BytesTransferred, NULL);
/* Pad out remaining bytes with 0x00 */
Endpoint_Null_Stream((AllocationLength - BytesTransferred), NULL);
/* 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;
return true;
}
/** 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
*
* \return Boolean \c true if the command completed successfully, \c false otherwise.
*/
static bool SCSI_Command_Request_Sense(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo)
{
uint8_t AllocationLength = MSInterfaceInfo->State.CommandBlock.SCSICommandData[4];
uint8_t BytesTransferred = MIN(AllocationLength, sizeof(SenseData));
Endpoint_Write_Stream_LE(&SenseData, BytesTransferred, NULL);
Endpoint_Null_Stream((AllocationLength - BytesTransferred), NULL);
Endpoint_ClearIN();
/* Succeed the command and update the bytes transferred counter */
MSInterfaceInfo->State.CommandBlock.DataTransferLength -= BytesTransferred;
return true;
}
/** 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
*
* \return Boolean \c true if the command completed successfully, \c false otherwise.
*/
static bool SCSI_Command_Read_Capacity_10(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo)
{
uint32_t LastBlockAddressInLUN = (VIRTUAL_MEMORY_BLOCKS - 1);
uint32_t MediaBlockSize = VIRTUAL_MEMORY_BLOCK_SIZE;
Endpoint_Write_Stream_BE(&LastBlockAddressInLUN, sizeof(LastBlockAddressInLUN), NULL);
Endpoint_Write_Stream_BE(&MediaBlockSize, sizeof(MediaBlockSize), NULL);
Endpoint_ClearIN();
/* Succeed the command and update the bytes transferred counter */
MSInterfaceInfo->State.CommandBlock.DataTransferLength -= 8;
return true;
}
/** 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
*
* \return Boolean \c true if the command completed successfully, \c false otherwise.
*/
static bool SCSI_Command_Send_Diagnostic(USB_ClassInfo_MS_Device_t* const 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 false;
}
/* 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 false;
}
/* Succeed the command and update the bytes transferred counter */
MSInterfaceInfo->State.CommandBlock.DataTransferLength = 0;
return true;
}
/** 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)
*
* \return Boolean \c true if the command completed successfully, \c false otherwise.
*/
static bool SCSI_Command_ReadWrite_10(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo,
const bool IsDataRead)
{
uint32_t BlockAddress;
uint16_t TotalBlocks;
/* Check if the disk is write protected or not */
if ((IsDataRead == DATA_WRITE) && DISK_READ_ONLY)
{
/* Block address is invalid, update SENSE key and return command fail */
SCSI_SET_SENSE(SCSI_SENSE_KEY_DATA_PROTECT,
SCSI_ASENSE_WRITE_PROTECTED,
SCSI_ASENSEQ_NO_QUALIFIER);
return false;
}
/* 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(*(uint16_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 false;
}
/* 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);
return true;
}
/** Command processing for an issued SCSI MODE SENSE (6) command. This command returns various informational pages about
* the SCSI device, as well as the device's Write Protect status.
*
* \param[in] MSInterfaceInfo Pointer to the Mass Storage class interface structure that the command is associated with
*
* \return Boolean \c true if the command completed successfully, \c false otherwise.
*/
static bool SCSI_Command_ModeSense_6(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo)
{
/* Send an empty header response with the Write Protect flag status */
Endpoint_Write_8(0x00);
Endpoint_Write_8(0x00);
Endpoint_Write_8(DISK_READ_ONLY ? 0x80 : 0x00);
Endpoint_Write_8(0x00);
Endpoint_ClearIN();
/* Update the bytes transferred counter and succeed the command */
MSInterfaceInfo->State.CommandBlock.DataTransferLength -= 4;
return true;
}

View file

@ -0,0 +1,89 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2014.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2014 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, provided that the above copyright notice appear in
all copies and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of the author not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
The author disclaims 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 "../TempDataLogger.h"
#include "../Descriptors.h"
#include "DataflashManager.h"
#include "Config/AppConfig.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) do { SenseData.SenseKey = (Key); \
SenseData.AdditionalSenseCode = (Acode); \
SenseData.AdditionalSenseQualifier = (Aqual); } while (0)
/** Macro for the \ref SCSI_Command_ReadWrite_10() function, to indicate that data is to be read from the storage medium. */
#define DATA_READ true
/** Macro for the \ref 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
/* Function Prototypes: */
bool SCSI_DecodeSCSICommand(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo);
#if defined(INCLUDE_FROM_SCSI_C)
static bool SCSI_Command_Inquiry(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo);
static bool SCSI_Command_Request_Sense(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo);
static bool SCSI_Command_Read_Capacity_10(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo);
static bool SCSI_Command_Send_Diagnostic(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo);
static bool SCSI_Command_ReadWrite_10(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo,
const bool IsDataRead);
static bool SCSI_Command_ModeSense_6(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo);
#endif
#endif