Add documentation to the incomplete Mass Storage class bootloader, update the virtual FAT file entry so that the bootloader section is omitted (not user readable/writable). Fix some minor documentation errors in the Printer class bootloader.
This commit is contained in:
		
							parent
							
								
									6c9632ae38
								
							
						
					
					
						commit
						df9b04c87f
					
				
					 7 changed files with 154 additions and 38 deletions
				
			
		|  | @ -61,8 +61,8 @@ USB_ClassInfo_MS_Device_t Disk_MS_Interface = | |||
| 	}; | ||||
| 
 | ||||
| 
 | ||||
| /** Main program entry point. This routine contains the overall program flow, including initial
 | ||||
|  *  setup of all components and the main program loop. | ||||
| /** Main program entry point. This routine configures the hardware required by the application, then
 | ||||
|  *  enters a loop to run the application tasks in sequence. | ||||
|  */ | ||||
| int main(void) | ||||
| { | ||||
|  | @ -107,15 +107,19 @@ ISR(TIMER1_OVF_vect, ISR_BLOCK) | |||
| 	LEDs_ToggleLEDs(LEDS_LED1 | LEDS_LED2); | ||||
| } | ||||
| 
 | ||||
| /** Event handler for the library USB Connection event. */ | ||||
| /** Event handler for the USB_Connect event. This indicates that the device is enumerating via the status LEDs. */ | ||||
| void EVENT_USB_Device_Connect(void) | ||||
| { | ||||
| 	/* Indicate USB enumerating */ | ||||
| 	LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING); | ||||
| } | ||||
| 
 | ||||
| /** Event handler for the library USB Disconnection event. */ | ||||
| /** Event handler for the USB_Disconnect event. This indicates that the device is no longer connected to a host via
 | ||||
|  *  the status LEDs and stops the Mass Storage management task. | ||||
|  */ | ||||
| void EVENT_USB_Device_Disconnect(void) | ||||
| { | ||||
| 	/* Indicate USB not ready */ | ||||
| 	LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); | ||||
| } | ||||
| 
 | ||||
|  | @ -124,8 +128,10 @@ void EVENT_USB_Device_ConfigurationChanged(void) | |||
| { | ||||
| 	bool ConfigSuccess = true; | ||||
| 
 | ||||
| 	/* Setup Mass Storage Data Endpoints */ | ||||
| 	ConfigSuccess &= MS_Device_ConfigureEndpoints(&Disk_MS_Interface); | ||||
| 
 | ||||
| 	/* Indicate endpoint configuration success or failure */ | ||||
| 	LEDs_SetAllLEDs(ConfigSuccess ? LEDMASK_USB_READY : LEDMASK_USB_ERROR); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -30,11 +30,11 @@ | |||
| 
 | ||||
| /** \file
 | ||||
|  * | ||||
|  *  Header file for MassStorage.c. | ||||
|  *  Header file for BootloaderMassStorage.c. | ||||
|  */ | ||||
| 
 | ||||
| #ifndef _MASS_STORAGE_H_ | ||||
| #define _MASS_STORAGE_H_ | ||||
| #ifndef _BOOTLOADER_MASS_STORAGE_H_ | ||||
| #define _BOOTLOADER_MASS_STORAGE_H_ | ||||
| 
 | ||||
| 	/* Includes: */ | ||||
| 		#include <avr/io.h> | ||||
|  |  | |||
|  | @ -162,12 +162,10 @@ uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, | |||
| 			Size    = sizeof(USB_Descriptor_Configuration_t); | ||||
| 			break; | ||||
| 		case DTYPE_String: | ||||
| 			switch (DescriptorNumber) | ||||
| 			if (!(DescriptorNumber)) | ||||
| 			{ | ||||
| 				case 0x00: | ||||
| 					Address = &LanguageString; | ||||
| 					Size    = pgm_read_byte(&LanguageString.Header.Size); | ||||
| 					break; | ||||
| 			} | ||||
| 
 | ||||
| 			break; | ||||
|  |  | |||
|  | @ -28,8 +28,26 @@ | |||
|   this software. | ||||
| */ | ||||
| 
 | ||||
| /** \file
 | ||||
|  * | ||||
|  *  Virtualized FAT12 filesystem implementation, to perform self-programming | ||||
|  *  in response to read and write requests to the virtual filesystem by the | ||||
|  *  host PC. | ||||
|  */ | ||||
| 
 | ||||
| #define  INCLUDE_FROM_VIRTUAL_FAT_C | ||||
| #include "VirtualFAT.h" | ||||
| 
 | ||||
| /** FAT filesystem boot sector block, must be the first sector on the physical
 | ||||
|  *  disk so that the host can identify the presence of a FAT filesystem. This | ||||
|  *  block is truncated; normally a large bootstrap section is located near the | ||||
|  *  end of the block for booting purposes however as this is not meant to be a | ||||
|  *  bootable disk it is omitted for space reasons. | ||||
|  * | ||||
|  *  \note When returning the boot block to the host, the magic signature 0xAA55 | ||||
|  *        must be added to the very end of the block to identify it as a boot | ||||
|  *        block. | ||||
|  */ | ||||
| static const FATBootBlock_t BootBlock = | ||||
| 	{ | ||||
| 		.Bootstrap               = {0xEB, 0x3C, 0x90}, | ||||
|  | @ -42,8 +60,8 @@ static const FATBootBlock_t BootBlock = | |||
| 		.TotalSectors16          = LUN_MEDIA_BLOCKS, | ||||
| 		.MediaDescriptor         = 0xF8, | ||||
| 		.SectorsPerFAT           = 1, | ||||
| 		.SectorsPerTrack         = LUN_MEDIA_BLOCKS % 64, | ||||
| 		.Heads                   = LUN_MEDIA_BLOCKS / 64, | ||||
| 		.SectorsPerTrack         = (LUN_MEDIA_BLOCKS % 64), | ||||
| 		.Heads                   = (LUN_MEDIA_BLOCKS / 64), | ||||
| 		.HiddenSectors           = 0, | ||||
| 		.TotalSectors32          = 0, | ||||
| 		.PhysicalDriveNum        = 0, | ||||
|  | @ -53,6 +71,7 @@ static const FATBootBlock_t BootBlock = | |||
| 		.FilesystemIdentifier    = "FAT12   ", | ||||
| 	}; | ||||
| 
 | ||||
| /** FAT 8.3 style directory entry, for the virtual FLASH contents file. */ | ||||
| static FATDirectoryEntry_t FirmwareFileEntry = | ||||
| 	{ | ||||
| 		.Filename               = "FIRMWARE", | ||||
|  | @ -62,11 +81,22 @@ static FATDirectoryEntry_t FirmwareFileEntry = | |||
| 		.CreationTime           = FAT_TIME(1, 1, 0), | ||||
| 		.CreationDate           = FAT_DATE(14, 2, 1989), | ||||
| 		.StartingCluster        = 2, | ||||
| 		.FileSizeBytes          = FIRMWARE_FILE_SIZE, | ||||
| 		.FileSizeBytes          = FIRMWARE_FILE_SIZE_BYTES, | ||||
| 	}; | ||||
| 
 | ||||
| 
 | ||||
| static void UpdateFAT12ClusterEntry(uint8_t* FATTable, | ||||
| /** Updates a FAT12 cluster entry in the FAT file table with the specified next
 | ||||
|  *  chain index. If the cluster is the last in the file chain, the magic value | ||||
|  *  0xFFF is used. | ||||
|  * | ||||
|  *  \note FAT data cluster indexes are offset by 2, so that cluster 2 is the | ||||
|  *        first file data cluster on the disk. See the FAT specification. | ||||
|  * | ||||
|  *  \param[out]  FATTable    Pointer to the FAT12 allocation table | ||||
|  *  \param[in]   Index       Index of the cluster entry to update | ||||
|  *  \param[in]   ChainEntry  Next cluster index in the file chain | ||||
|  */ | ||||
| static void UpdateFAT12ClusterEntry(uint8_t* const FATTable, | ||||
|                                     const uint16_t Index, | ||||
|                                     const uint16_t ChainEntry) | ||||
| { | ||||
|  | @ -88,7 +118,12 @@ static void UpdateFAT12ClusterEntry(uint8_t* FATTable, | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void WriteBlock(const uint16_t BlockNumber) | ||||
| /** Writes a block of data to the virtual FAT filesystem, from the USB Mass
 | ||||
|  *  Storage interface. | ||||
|  * | ||||
|  *  \param[in]  BlockNumber  Index of the block to write. | ||||
|  */ | ||||
| static void WriteVirtualBlock(const uint16_t BlockNumber) | ||||
| { | ||||
| 	uint8_t BlockBuffer[SECTOR_SIZE_BYTES]; | ||||
| 
 | ||||
|  | @ -96,16 +131,12 @@ static void WriteBlock(const uint16_t BlockNumber) | |||
| 	Endpoint_Read_Stream_LE(BlockBuffer, sizeof(BlockBuffer), NULL); | ||||
| 	Endpoint_ClearOUT(); | ||||
| 
 | ||||
| 	if ((BlockNumber >= 4) && (BlockNumber < (4 + (FIRMWARE_FILE_SIZE / SECTOR_SIZE_BYTES)))) | ||||
| 	if ((BlockNumber >= 4) && (BlockNumber < (4 + FILE_SECTORS(FIRMWARE_FILE_SIZE_BYTES)))) | ||||
| 	{ | ||||
| 		uint32_t WriteFlashAddress = (uint32_t)(BlockNumber - 4) * SECTOR_SIZE_BYTES; | ||||
| 
 | ||||
| 		for (uint16_t i = 0; i < SECTOR_SIZE_BYTES; i += 2) | ||||
| 		{ | ||||
| 			/* Disallow writing to the bootloader section */ | ||||
| 			if (WriteFlashAddress > BOOT_START_ADDR) | ||||
| 			  continue; | ||||
| 
 | ||||
| 			if ((WriteFlashAddress % SPM_PAGESIZE) == 0) | ||||
| 			{ | ||||
| 				/* Erase the given FLASH page, ready to be programmed */ | ||||
|  | @ -127,7 +158,12 @@ static void WriteBlock(const uint16_t BlockNumber) | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void ReadBlock(const uint16_t BlockNumber) | ||||
| /** Reads a block of data from the virtual FAT filesystem, and sends it to the
 | ||||
|  *  host via the USB Mass Storage interface. | ||||
|  * | ||||
|  *  \param[in]  BlockNumber  Index of the block to read. | ||||
|  */ | ||||
| static void ReadVirtualBlock(const uint16_t BlockNumber) | ||||
| { | ||||
| 	uint8_t BlockBuffer[SECTOR_SIZE_BYTES]; | ||||
| 	memset(BlockBuffer, 0x00, sizeof(BlockBuffer)); | ||||
|  | @ -151,11 +187,11 @@ static void ReadBlock(const uint16_t BlockNumber) | |||
| 			UpdateFAT12ClusterEntry(BlockBuffer, 1, 0xFFF); | ||||
| 
 | ||||
| 			/* Cluster 2 onwards: Cluster chain of FIRMWARE.BIN */ | ||||
| 			for (uint16_t i = 0; i < FILE_CLUSTERS(FIRMWARE_FILE_SIZE); i++) | ||||
| 			for (uint16_t i = 0; i < FILE_CLUSTERS(FIRMWARE_FILE_SIZE_BYTES); i++) | ||||
| 			  UpdateFAT12ClusterEntry(BlockBuffer, i+2, i+3); | ||||
| 
 | ||||
| 			/* Mark last cluster as end of file */ | ||||
| 			UpdateFAT12ClusterEntry(BlockBuffer, FILE_CLUSTERS(FIRMWARE_FILE_SIZE) + 1, 0xFFF); | ||||
| 			UpdateFAT12ClusterEntry(BlockBuffer, FILE_CLUSTERS(FIRMWARE_FILE_SIZE_BYTES) + 1, 0xFFF); | ||||
| 			break; | ||||
| 
 | ||||
| 		case 3: /* Block 3: Root file entries */ | ||||
|  | @ -163,7 +199,7 @@ static void ReadBlock(const uint16_t BlockNumber) | |||
| 			break; | ||||
| 
 | ||||
| 		default: /* Blocks 4 onwards: Data allocation section */ | ||||
| 			if ((BlockNumber >= 4) && (BlockNumber < (4 + (FIRMWARE_FILE_SIZE / SECTOR_SIZE_BYTES)))) | ||||
| 			if ((BlockNumber >= 4) && (BlockNumber < (4 + FILE_SECTORS(FIRMWARE_FILE_SIZE_BYTES)))) | ||||
| 			{ | ||||
| 				uint32_t ReadFlashAddress = (uint32_t)(BlockNumber - 4) * SECTOR_SIZE_BYTES; | ||||
| 
 | ||||
|  | @ -179,6 +215,13 @@ static void ReadBlock(const uint16_t BlockNumber) | |||
| 	Endpoint_ClearIN(); | ||||
| } | ||||
| 
 | ||||
| /** Writes a number of blocks to the virtual FAT file system, from the host
 | ||||
|  *  PC via the USB Mass Storage interface. | ||||
|  * | ||||
|  *  \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 VirtualFAT_WriteBlocks(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo, | ||||
|                             const uint32_t BlockAddress, | ||||
|                             uint16_t TotalBlocks) | ||||
|  | @ -188,9 +231,16 @@ void VirtualFAT_WriteBlocks(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo, | |||
| 	/* Emulated FAT is performed per-block, pass each requested block index
 | ||||
| 	 * to the emulated FAT block write function */ | ||||
| 	while (TotalBlocks--) | ||||
| 	  WriteBlock(CurrentBlock++); | ||||
| 	  WriteVirtualBlock(CurrentBlock++); | ||||
| } | ||||
| 
 | ||||
| /** Reads a number of blocks from the virtual FAT file system, and sends them
 | ||||
|  *  to the host PC via the USB Mass Storage interface. | ||||
|  * | ||||
|  *  \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 VirtualFAT_ReadBlocks(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo, | ||||
|                            const uint32_t BlockAddress, | ||||
|                            uint16_t TotalBlocks) | ||||
|  | @ -200,6 +250,6 @@ void VirtualFAT_ReadBlocks(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo, | |||
| 	/* Emulated FAT is performed per-block, pass each requested block index
 | ||||
| 	 * to the emulated FAT block read function */ | ||||
| 	while (TotalBlocks--) | ||||
| 	  ReadBlock(CurrentBlock++); | ||||
| 	  ReadVirtualBlock(CurrentBlock++); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -38,19 +38,68 @@ | |||
| 		#include <LUFA/Drivers/USB/USB.h> | ||||
| 
 | ||||
| 	/* Macros: */ | ||||
| 		#define FIRMWARE_FILE_SIZE     (FLASHEND + 1UL) | ||||
| 		/** Size of the virtual FIRMWARE.BIN file in bytes. */ | ||||
| 		#define FIRMWARE_FILE_SIZE_BYTES  (FLASHEND - (FLASHEND - BOOT_START_ADDR) + 1UL) | ||||
| 
 | ||||
| 		#define SECTOR_SIZE_BYTES      512 | ||||
| 		#define SECTOR_PER_CLUSTER     4 | ||||
| 		#define CLUSTER_SIZE_BYTES     (SECTOR_PER_CLUSTER * SECTOR_SIZE_BYTES) | ||||
| 		#define FILE_CLUSTERS(size)    ((size / CLUSTER_SIZE_BYTES) + ((size % CLUSTER_SIZE_BYTES) ? 1 : 0)) | ||||
| 		/** Number of sectors that comprise a single logical disk cluster. */ | ||||
| 		#define SECTOR_PER_CLUSTER        4 | ||||
| 
 | ||||
| 		#define LUN_MEDIA_BLOCKS       ((FIRMWARE_FILE_SIZE / SECTOR_SIZE_BYTES) + 32) | ||||
| 		/** Size of a single logical sector on the disk. */ | ||||
| 		#define SECTOR_SIZE_BYTES         512 | ||||
| 
 | ||||
| 		#define FAT_TIME(h, m, s)      ((h << 11) | (m << 5) | (s >> 1)) | ||||
| 		#define FAT_DATE(d, m, y)      (((y - 1980) << 9) | (m << 5) | (d << 0)) | ||||
| 		/** Size of a logical cluster on the disk, in bytes */ | ||||
| 		#define CLUSTER_SIZE_BYTES        (SECTOR_PER_CLUSTER * SECTOR_SIZE_BYTES) | ||||
| 
 | ||||
| 		/** Number of sectors required to store a given size in bytes.
 | ||||
| 		 * | ||||
| 		 *  \param[in] size  Size of the data that needs to be stored | ||||
| 		 * | ||||
| 		 *  \return Number of sectors required to store the given data on the disk. | ||||
| 		 */ | ||||
| 		#define FILE_SECTORS(size)        ((size / SECTOR_SIZE_BYTES)  + ((size % SECTOR_SIZE_BYTES)  ? 1 : 0)) | ||||
| 
 | ||||
| 		/** Number of clusters required to store a given size in bytes.
 | ||||
| 		 * | ||||
| 		 *  \param[in] size  Size of the data that needs to be stored | ||||
| 		 * | ||||
| 		 *  \return Number of clusters required to store the given data on the disk. | ||||
| 		 */ | ||||
| 		#define FILE_CLUSTERS(size)       ((size / CLUSTER_SIZE_BYTES) + ((size % CLUSTER_SIZE_BYTES) ? 1 : 0)) | ||||
| 
 | ||||
| 		/** Total number of logical sectors/blocks on the disk. */ | ||||
| 		#define LUN_MEDIA_BLOCKS          (FILE_SECTORS(FIRMWARE_FILE_SIZE_BYTES) + 32) | ||||
| 
 | ||||
| 		/** Converts a given time in HH:MM:SS format to a FAT filesystem time.
 | ||||
| 		 * | ||||
| 		 *  \note The minimum seconds resolution of FAT is 2, thus odd seconds | ||||
| 		 *        will be truncated to the previous integer multiple of 2 seconds. | ||||
| 		 * | ||||
| 		 *  \param[in] hh  Hours (0-23) | ||||
| 		 *  \param[in] mm  Minutes (0-59) | ||||
| 		 *  \param[in] ss  Seconds (0-59) | ||||
| 		 * | ||||
| 		 *  \return Given time encoded as a FAT filesystem timestamp | ||||
| 		 */ | ||||
| 		#define FAT_TIME(h, m, s)         ((hh << 11) | (mm << 5) | (ss >> 1)) | ||||
| 
 | ||||
| 		/** Converts a given date in DD/MM/YYYY format to a FAT filesystem date.
 | ||||
| 		 * | ||||
| 		 *  \param[in] dd    Days in the month (1-31) | ||||
| 		 *  \param[in] mm    Months in the year (1-12) | ||||
| 		 *  \param[in] yyyy  Year (1980 - 2107) | ||||
| 		 * | ||||
| 		 *  \return Given date encoded as a FAT filesystem datestamp | ||||
| 		 */ | ||||
| 		#define FAT_DATE(d, m, y)         (((yyyy - 1980) << 9) | (mm << 5) | (dd << 0)) | ||||
| 
 | ||||
| 	/* Type Definitions: */ | ||||
| 		/** FAT boot block structure definition, used to identify the core
 | ||||
| 		 *  parameters of a FAT filesystem stored on a disk. | ||||
| 		 * | ||||
| 		 *  \note This definition is truncated to save space; the magic signature | ||||
| 		 *        0xAA55 must be appended to the very end of the block for it to | ||||
| 		 *        be detected by the host as a valid boot block. | ||||
| 		 */ | ||||
| 		typedef struct | ||||
| 		{ | ||||
| 			uint8_t  Bootstrap[3]; | ||||
|  | @ -72,8 +121,13 @@ | |||
| 			uint32_t VolumeSerialNumber; | ||||
| 			uint8_t  VolumeLabel[11]; | ||||
| 			uint8_t  FilesystemIdentifier[8]; | ||||
| 			/* uint8_t  BootstrapProgram[448]; */ | ||||
| 			/* uint16_t MagicSignature; */ | ||||
| 		} FATBootBlock_t; | ||||
| 
 | ||||
| 		/** FAT legacy 8.3 style directory entry structure definition, used to
 | ||||
| 		 *  identify the files and folders of FAT filesystem stored on a disk. | ||||
| 		 */ | ||||
| 		typedef struct | ||||
| 		{ | ||||
| 			uint8_t  Filename[8]; | ||||
|  | @ -87,6 +141,14 @@ | |||
| 		} FATDirectoryEntry_t; | ||||
| 
 | ||||
| 	/* Function Prototypes: */ | ||||
| 		#if defined(INCLUDE_FROM_VIRTUAL_FAT_C) | ||||
| 			static void UpdateFAT12ClusterEntry(uint8_t* const FATTable, | ||||
| 			                                    const uint16_t Index, | ||||
| 			                                    const uint16_t ChainEntry); | ||||
| 			static void WriteVirtualBlock(const uint16_t BlockNumber); | ||||
| 			static void ReadVirtualBlock(const uint16_t BlockNumber); | ||||
| 		#endif | ||||
| 
 | ||||
| 		void VirtualFAT_WriteBlocks(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo, | ||||
| 		                            const uint32_t BlockAddress, | ||||
| 		                            uint16_t TotalBlocks); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Dean Camera
						Dean Camera