USBMSD SD card Hello World for Mbed platforms
Dependencies: mbed USBMSD_SD USBDevice
Revision 7:6494da2a5c60, committed 2011-11-14
- Comitter:
- samux
- Date:
- Mon Nov 14 12:08:32 2011 +0000
- Parent:
- 6:126c4d980196
- Child:
- 8:534fd41d8cc7
- Commit message:
- will try to use ChaNFSSD
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ChaNFS/.lib Mon Nov 14 12:08:32 2011 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/NeoBelerophon/libraries/ChaNFS/llxkji \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ChaNFS/CHAN_FS/diskio.c Mon Nov 14 12:08:32 2011 +0000
@@ -0,0 +1,105 @@
+/*-----------------------------------------------------------------------*/
+/* 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"
+#include <stdio.h>
+#include <string.h>
+#include "FATFileSystem.h"
+
+#include "mbed.h"
+
+DSTATUS disk_initialize (
+ BYTE drv /* Physical drive nmuber (0..) */
+)
+{
+ FFSDEBUG("disk_initialize on drv [%d]\n", drv);
+ return (DSTATUS)FATFileSystem::_ffs[drv]->disk_initialize();
+}
+
+DSTATUS disk_status (
+ BYTE drv /* Physical drive nmuber (0..) */
+)
+{
+ FFSDEBUG("disk_status on drv [%d]\n", drv);
+ return (DSTATUS)FATFileSystem::_ffs[drv]->disk_status();
+}
+
+DRESULT disk_read (
+ BYTE drv, /* Physical drive nmuber (0..) */
+ BYTE *buff, /* Data buffer to store read data */
+ DWORD sector, /* Sector address (LBA) */
+ BYTE count /* Number of sectors to read (1..255) */
+)
+{
+ FFSDEBUG("disk_read(sector %d, count %d) on drv [%d]\n", sector, count, drv);
+ for(int s=sector; s<sector+count; s++) {
+ FFSDEBUG(" disk_read(sector %d)\n", s);
+ int res = FATFileSystem::_ffs[drv]->disk_read((char*)buff, s);
+ if(res) {
+ return RES_PARERR;
+ }
+ buff += 512;
+ }
+ return RES_OK;
+}
+
+#if _READONLY == 0
+DRESULT disk_write (
+ BYTE drv, /* Physical drive nmuber (0..) */
+ const BYTE *buff, /* Data to be written */
+ DWORD sector, /* Sector address (LBA) */
+ BYTE count /* Number of sectors to write (1..255) */
+)
+{
+ FFSDEBUG("disk_write(sector %d, count %d) on drv [%d]\n", sector, count, drv);
+ for(int s=sector; s<sector+count; s++) {
+ FFSDEBUG(" disk_write(sector %d)\n", s);
+ int res = FATFileSystem::_ffs[drv]->disk_write((char*)buff, sector);
+ if(res) {
+ return RES_PARERR;
+ }
+ buff += 512;
+ }
+ return RES_OK;
+}
+#endif /* _READONLY */
+
+DRESULT disk_ioctl (
+ BYTE drv, /* Physical drive nmuber (0..) */
+ BYTE ctrl, /* Control code */
+ void *buff /* Buffer to send/receive control data */
+)
+{
+ FFSDEBUG("disk_ioctl(%d)\n", ctrl);
+ switch(ctrl) {
+ case CTRL_SYNC:
+ if(FATFileSystem::_ffs[drv] == NULL) {
+ return RES_NOTRDY;
+ } else if(FATFileSystem::_ffs[drv]->disk_sync()) {
+ return RES_ERROR;
+ }
+ return RES_OK;
+ case GET_SECTOR_COUNT:
+ if(FATFileSystem::_ffs[drv] == NULL) {
+ return RES_NOTRDY;
+ } else {
+ int res = FATFileSystem::_ffs[drv]->disk_sectors();
+ if(res > 0) {
+ *((DWORD*)buff) = res; // minimum allowed
+ return RES_OK;
+ } else {
+ return RES_ERROR;
+ }
+ }
+ case GET_BLOCK_SIZE:
+ *((DWORD*)buff) = 1; // default when not known
+ return RES_OK;
+
+ }
+ return RES_PARERR;
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ChaNFS/CHAN_FS/diskio.h Mon Nov 14 12:08:32 2011 +0000
@@ -0,0 +1,80 @@
+/*-----------------------------------------------------------------------
+/ Low level disk interface modlue include file
+/-----------------------------------------------------------------------*/
+
+#ifndef _DISKIO
+
+#define _READONLY 0 /* 1: Remove write functions */
+#define _USE_IOCTL 1 /* 1: Use disk_ioctl fucntion */
+
+#include "integer.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 */
+
+int assign_drives (int, int);
+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*);
+void disk_timerproc (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 */
+
+
+/* Command code for disk_ioctrl fucntion */
+
+/* Generic command (defined for FatFs) */
+#define CTRL_SYNC 0 /* Flush disk cache (for write functions) */
+#define GET_SECTOR_COUNT 1 /* Get media size (for only f_mkfs()) */
+#define GET_SECTOR_SIZE 2 /* Get sector size (for multiple sector size (_MAX_SS >= 1024)) */
+#define GET_BLOCK_SIZE 3 /* Get erase block size (for only f_mkfs()) */
+#define CTRL_ERASE_SECTOR 4 /* Force erased a block of sectors (for only _USE_ERASE) */
+
+/* Generic command */
+#define CTRL_POWER 5 /* Get/Set power status */
+#define CTRL_LOCK 6 /* Lock/Unlock media removal */
+#define CTRL_EJECT 7 /* Eject media */
+
+/* MMC/SDC specific ioctl command */
+#define MMC_GET_TYPE 10 /* Get card type */
+#define MMC_GET_CSD 11 /* Get CSD */
+#define MMC_GET_CID 12 /* Get CID */
+#define MMC_GET_OCR 13 /* Get OCR */
+#define MMC_GET_SDSTAT 14 /* Get SD status */
+
+/* ATA/CF specific ioctl command */
+#define ATA_GET_REV 20 /* Get F/W revision */
+#define ATA_GET_MODEL 21 /* Get model name */
+#define ATA_GET_SN 22 /* Get serial number */
+
+/* NAND specific ioctl command */
+#define NAND_FORMAT 30 /* Create physical format */
+
+
+#define _DISKIO
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ChaNFS/CHAN_FS/ff.c Mon Nov 14 12:08:32 2011 +0000
@@ -0,0 +1,3982 @@
+/*----------------------------------------------------------------------------/
+/ FatFs - FAT file system module R0.08b (C)ChaN, 2011
+/-----------------------------------------------------------------------------/
+/ 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) 2011, 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 products UNDER YOUR RESPONSIBILITY.
+/ * Redistributions of source code must retain the above copyright notice.
+/
+/-----------------------------------------------------------------------------/
+/ Feb 26,'06 R0.00 Prototype.
+/
+/ Apr 29,'06 R0.01 First stable version.
+/
+/ Jun 01,'06 R0.02 Added FAT12 support.
+/ Removed unbuffered mode.
+/ Fixed a problem on small (<32M) partition.
+/ Jun 10,'06 R0.02a Added a configuration option (_FS_MINIMUM).
+/
+/ Sep 22,'06 R0.03 Added f_rename().
+/ Changed option _FS_MINIMUM to _FS_MINIMIZE.
+/ Dec 11,'06 R0.03a Improved cluster scan algorithm to write files fast.
+/ Fixed f_mkdir() creates incorrect directory on FAT32.
+/
+/ Feb 04,'07 R0.04 Supported multiple drive system.
+/ Changed some interfaces for multiple drive system.
+/ Changed f_mountdrv() to f_mount().
+/ Added f_mkfs().
+/ Apr 01,'07 R0.04a Supported multiple partitions on a physical drive.
+/ Added a capability of extending file size to f_lseek().
+/ Added minimization level 3.
+/ Fixed an endian sensitive code in f_mkfs().
+/ May 05,'07 R0.04b Added a configuration option _USE_NTFLAG.
+/ Added FSInfo support.
+/ Fixed DBCS name can result FR_INVALID_NAME.
+/ Fixed short seek (<= csize) collapses the file object.
+/
+/ Aug 25,'07 R0.05 Changed arguments of f_read(), f_write() and f_mkfs().
+/ Fixed f_mkfs() on FAT32 creates incorrect FSInfo.
+/ Fixed f_mkdir() on FAT32 creates incorrect directory.
+/ Feb 03,'08 R0.05a Added f_truncate() and 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,'08 R0.06 Added fputc(), fputs(), fprintf() and fgets().
+/ Improved performance of f_lseek() on moving to the same or following cluster.
+/
+/ Apr 01,'09 R0.07 Merged Tiny-FatFs as a configuration option. (_FS_TINY)
+/ Added long file name feature.
+/ Added multiple code page feature.
+/ 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,'09 R0.07a Separated out OS dependent code on reentrant cfg.
+/ Added multiple sector size feature.
+/ Jun 21,'09 R0.07c Fixed f_unlink() can return FR_OK on error.
+/ Fixed wrong cache control in f_lseek().
+/ Added relative path feature.
+/ Added f_chdir() and f_chdrive().
+/ Added proper case conversion to extended char.
+/ Nov 03,'09 R0.07e Separated out configuration options from ff.h to ffconf.h.
+/ Fixed f_unlink() fails to remove a sub-dir on _FS_RPATH.
+/ Fixed name matching error on the 13 char boundary.
+/ Added a configuration option, _LFN_UNICODE.
+/ Changed f_readdir() to return the SFN with always upper case on non-LFN cfg.
+/
+/ May 15,'10 R0.08 Added a memory configuration option. (_USE_LFN = 3)
+/ 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.
+/---------------------------------------------------------------------------*/
+
+#include "ff.h" /* FatFs configurations and declarations */
+#include "diskio.h" /* Declarations of low level disk I/O functions */
+#include "mbed.h"
+
+
+/*--------------------------------------------------------------------------
+
+ Module Private Definitions
+
+---------------------------------------------------------------------------*/
+
+#if _FATFS != 8237
+#error Wrong include file (ff.h).
+#endif
+
+
+/* Definitions on sector size */
+#if _MAX_SS != 512 && _MAX_SS != 1024 && _MAX_SS != 2048 && _MAX_SS != 4096
+#error Wrong sector size.
+#endif
+#if _MAX_SS != 512
+#define SS(fs) ((fs)->ssize) /* Multiple sector size */
+#else
+#define SS(fs) 512U /* Fixed sector size */
+#endif
+
+
+/* Reentrancy related */
+#if _FS_REENTRANT
+#if _USE_LFN == 1
+#error Static LFN work area must not be used in re-entrant configuration.
+#endif
+#define ENTER_FF(fs) { if (!lock_fs(fs)) return FR_TIMEOUT; }
+#define LEAVE_FF(fs, res) { unlock_fs(fs, res); return res; }
+#else
+#define ENTER_FF(fs)
+#define LEAVE_FF(fs, res) return res
+#endif
+
+#define ABORT(fs, res) { fp->flag |= FA__ERROR; LEAVE_FF(fs, res); }
+
+
+/* File shareing feature */
+#if _FS_SHARE
+#if _FS_READONLY
+#error _FS_SHARE must be 0 on read-only cfg.
+#endif
+typedef struct {
+ FATFS *fs; /* File ID 1, volume (NULL:blank entry) */
+ DWORD clu; /* File ID 2, directory */
+ WORD idx; /* File ID 3, directory index */
+ WORD ctr; /* File open counter, 0:none, 0x01..0xFF:read open count, 0x100:write mode */
+} FILESEM;
+#endif
+
+
+/* Misc definitions */
+#define LD_CLUST(dir) (((DWORD)LD_WORD(dir+DIR_FstClusHI)<<16) | LD_WORD(dir+DIR_FstClusLO))
+#define ST_CLUST(dir,cl) {ST_WORD(dir+DIR_FstClusLO, cl); ST_WORD(dir+DIR_FstClusHI, (DWORD)cl>>16);}
+
+
+/* DBCS code ranges and SBCS extend char conversion table */
+
+#if _CODE_PAGE == 932 /* Japanese Shift-JIS */
+#define _DF1S 0x81 /* DBC 1st byte range 1 start */
+#define _DF1E 0x9F /* DBC 1st byte range 1 end */
+#define _DF2S 0xE0 /* DBC 1st byte range 2 start */
+#define _DF2E 0xFC /* DBC 1st byte range 2 end */
+#define _DS1S 0x40 /* DBC 2nd byte range 1 start */
+#define _DS1E 0x7E /* DBC 2nd byte range 1 end */
+#define _DS2S 0x80 /* DBC 2nd byte range 2 start */
+#define _DS2E 0xFC /* DBC 2nd byte range 2 end */
+
+#elif _CODE_PAGE == 936 /* Simplified Chinese GBK */
+#define _DF1S 0x81
+#define _DF1E 0xFE
+#define _DS1S 0x40
+#define _DS1E 0x7E
+#define _DS2S 0x80
+#define _DS2E 0xFE
+
+#elif _CODE_PAGE == 949 /* Korean */
+#define _DF1S 0x81
+#define _DF1E 0xFE
+#define _DS1S 0x41
+#define _DS1E 0x5A
+#define _DS2S 0x61
+#define _DS2E 0x7A
+#define _DS3S 0x81
+#define _DS3E 0xFE
+
+#elif _CODE_PAGE == 950 /* Traditional Chinese Big5 */
+#define _DF1S 0x81
+#define _DF1E 0xFE
+#define _DS1S 0x40
+#define _DS1E 0x7E
+#define _DS2S 0xA1
+#define _DS2E 0xFE
+
+#elif _CODE_PAGE == 437 /* U.S. (OEM) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F,0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+ 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 720 /* Arabic (OEM) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x45,0x41,0x84,0x41,0x86,0x43,0x45,0x45,0x45,0x49,0x49,0x8D,0x8E,0x8F,0x90,0x92,0x92,0x93,0x94,0x95,0x49,0x49,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+ 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 737 /* Greek (OEM) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x92,0x92,0x93,0x94,0x95,0x96,0x97,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87, \
+ 0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0xAA,0x92,0x93,0x94,0x95,0x96,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0x97,0xEA,0xEB,0xEC,0xE4,0xED,0xEE,0xE7,0xE8,0xF1,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 775 /* Baltic (OEM) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x9A,0x91,0xA0,0x8E,0x95,0x8F,0x80,0xAD,0xED,0x8A,0x8A,0xA1,0x8D,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0x95,0x96,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \
+ 0xA0,0xA1,0xE0,0xA3,0xA3,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xA5,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE3,0xE8,0xE8,0xEA,0xEA,0xEE,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 850 /* Multilingual Latin 1 (OEM) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0xDE,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x59,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \
+ 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE7,0xE9,0xEA,0xEB,0xED,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 852 /* Latin 2 (OEM) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xDE,0x8F,0x80,0x9D,0xD3,0x8A,0x8A,0xD7,0x8D,0x8E,0x8F,0x90,0x91,0x91,0xE2,0x99,0x95,0x95,0x97,0x97,0x99,0x9A,0x9B,0x9B,0x9D,0x9E,0x9F, \
+ 0xB5,0xD6,0xE0,0xE9,0xA4,0xA4,0xA6,0xA6,0xA8,0xA8,0xAA,0x8D,0xAC,0xB8,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBD,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC6,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD2,0xD3,0xD2,0xD5,0xD6,0xD7,0xB7,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xE0,0xE1,0xE2,0xE3,0xE3,0xD5,0xE6,0xE6,0xE8,0xE9,0xE8,0xEB,0xED,0xED,0xDD,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xEB,0xFC,0xFC,0xFE,0xFF}
+
+#elif _CODE_PAGE == 855 /* Cyrillic (OEM) */
+#define _DF1S 0
+#define _EXCVT {0x81,0x81,0x83,0x83,0x85,0x85,0x87,0x87,0x89,0x89,0x8B,0x8B,0x8D,0x8D,0x8F,0x8F,0x91,0x91,0x93,0x93,0x95,0x95,0x97,0x97,0x99,0x99,0x9B,0x9B,0x9D,0x9D,0x9F,0x9F, \
+ 0xA1,0xA1,0xA3,0xA3,0xA5,0xA5,0xA7,0xA7,0xA9,0xA9,0xAB,0xAB,0xAD,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB6,0xB6,0xB8,0xB8,0xB9,0xBA,0xBB,0xBC,0xBE,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD3,0xD3,0xD5,0xD5,0xD7,0xD7,0xDD,0xD9,0xDA,0xDB,0xDC,0xDD,0xE0,0xDF, \
+ 0xE0,0xE2,0xE2,0xE4,0xE4,0xE6,0xE6,0xE8,0xE8,0xEA,0xEA,0xEC,0xEC,0xEE,0xEE,0xEF,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 857 /* Turkish (OEM) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0x98,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x98,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9E, \
+ 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA6,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xDE,0x59,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 858 /* Multilingual Latin 1 + Euro (OEM) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0xDE,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x59,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \
+ 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE7,0xE9,0xEA,0xEB,0xED,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 862 /* Hebrew (OEM) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+ 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 866 /* Russian (OEM) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0x90,0x91,0x92,0x93,0x9d,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 874 /* Thai (OEM, Windows) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+ 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 1250 /* Central Europe (Windows) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x8D,0x8E,0x8F, \
+ 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xA3,0xB4,0xB5,0xB6,0xB7,0xB8,0xA5,0xAA,0xBB,0xBC,0xBD,0xBC,0xAF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xFF}
+
+#elif _CODE_PAGE == 1251 /* Cyrillic (Windows) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x82,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x80,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x8D,0x8E,0x8F, \
+ 0xA0,0xA2,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB2,0xA5,0xB5,0xB6,0xB7,0xA8,0xB9,0xAA,0xBB,0xA3,0xBD,0xBD,0xAF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF}
+
+#elif _CODE_PAGE == 1252 /* Latin 1 (Windows) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0xAd,0x9B,0x8C,0x9D,0xAE,0x9F, \
+ 0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x9F}
+
+#elif _CODE_PAGE == 1253 /* Greek (Windows) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+ 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xA2,0xB8,0xB9,0xBA, \
+ 0xE0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xF2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xFB,0xBC,0xFD,0xBF,0xFF}
+
+#elif _CODE_PAGE == 1254 /* Turkish (Windows) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x9D,0x9E,0x9F, \
+ 0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x9F}
+
+#elif _CODE_PAGE == 1255 /* Hebrew (Windows) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+ 0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 1256 /* Arabic (Windows) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x8C,0x9D,0x9E,0x9F, \
+ 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0x41,0xE1,0x41,0xE3,0xE4,0xE5,0xE6,0x43,0x45,0x45,0x45,0x45,0xEC,0xED,0x49,0x49,0xF0,0xF1,0xF2,0xF3,0x4F,0xF5,0xF6,0xF7,0xF8,0x55,0xFA,0x55,0x55,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 1257 /* Baltic (Windows) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+ 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xA8,0xB9,0xAA,0xBB,0xBC,0xBD,0xBE,0xAF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xFF}
+
+#elif _CODE_PAGE == 1258 /* Vietnam (OEM, Windows) */
+#define _DF1S 0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0xAC,0x9D,0x9E,0x9F, \
+ 0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xEC,0xCD,0xCE,0xCF,0xD0,0xD1,0xF2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xFE,0x9F}
+
+#elif _CODE_PAGE == 1 /* ASCII (for only non-LFN cfg) */
+#if _USE_LFN
+#error Cannot use LFN feature without valid code page.
+#endif
+#define _DF1S 0
+
+#else
+#error Unknown code page
+
+#endif
+
+
+/* Character code support macros */
+#define IsUpper(c) (((c)>='A')&&((c)<='Z'))
+#define IsLower(c) (((c)>='a')&&((c)<='z'))
+#define IsDigit(c) (((c)>='0')&&((c)<='9'))
+
+#if _DF1S /* Code page is DBCS */
+
+#ifdef _DF2S /* Two 1st byte areas */
+#define IsDBCS1(c) (((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E) || ((BYTE)(c) >= _DF2S && (BYTE)(c) <= _DF2E))
+#else /* One 1st byte area */
+#define IsDBCS1(c) ((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E)
+#endif
+
+#ifdef _DS3S /* Three 2nd byte areas */
+#define IsDBCS2(c) (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E) || ((BYTE)(c) >= _DS3S && (BYTE)(c) <= _DS3E))
+#else /* Two 2nd byte areas */
+#define IsDBCS2(c) (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E))
+#endif
+
+#else /* Code page is SBCS */
+
+#define IsDBCS1(c) 0
+#define IsDBCS2(c) 0
+
+#endif /* _DF1S */
+
+
+/* Name status flags */
+#define NS 11 /* Index of name status byte in fn[] */
+#define NS_LOSS 0x01 /* Out of 8.3 format */
+#define NS_LFN 0x02 /* Force to create LFN entry */
+#define NS_LAST 0x04 /* Last segment */
+#define NS_BODY 0x08 /* Lower case flag (body) */
+#define NS_EXT 0x10 /* Lower case flag (ext) */
+#define NS_DOT 0x20 /* Dot entry */
+
+
+/* FAT sub-type boundaries */
+/* Note that the FAT spec by Microsoft says 4085 but Windows works with 4087! */
+#define MIN_FAT16 4086 /* Minimum number of clusters for FAT16 */
+#define MIN_FAT32 65526 /* Minimum number of clusters for FAT32 */
+
+
+/* FatFs refers the members in the FAT structures as byte array instead of
+/ structure member because the structure is not binary compatible between
+/ different platforms */
+
+#define BS_jmpBoot 0 /* Jump instruction (3) */
+#define BS_OEMName 3 /* OEM name (8) */
+#define BPB_BytsPerSec 11 /* Sector size [byte] (2) */
+#define BPB_SecPerClus 13 /* Cluster size [sector] (1) */
+#define BPB_RsvdSecCnt 14 /* Size of reserved area [sector] (2) */
+#define BPB_NumFATs 16 /* Number of FAT copies (1) */
+#define BPB_RootEntCnt 17 /* Number of root dir entries for FAT12/16 (2) */
+#define BPB_TotSec16 19 /* Volume size [sector] (2) */
+#define BPB_Media 21 /* Media descriptor (1) */
+#define BPB_FATSz16 22 /* FAT size [sector] (2) */
+#define BPB_SecPerTrk 24 /* Track size [sector] (2) */
+#define BPB_NumHeads 26 /* Number of heads (2) */
+#define BPB_HiddSec 28 /* Number of special hidden sectors (4) */
+#define BPB_TotSec32 32 /* Volume size [sector] (4) */
+#define BS_DrvNum 36 /* Physical drive number (2) */
+#define BS_BootSig 38 /* Extended boot signature (1) */
+#define BS_VolID 39 /* Volume serial number (4) */
+#define BS_VolLab 43 /* Volume label (8) */
+#define BS_FilSysType 54 /* File system type (1) */
+#define BPB_FATSz32 36 /* FAT size [sector] (4) */
+#define BPB_ExtFlags 40 /* Extended flags (2) */
+#define BPB_FSVer 42 /* File system version (2) */
+#define BPB_RootClus 44 /* Root dir first cluster (4) */
+#define BPB_FSInfo 48 /* Offset of FSInfo sector (2) */
+#define BPB_BkBootSec 50 /* Offset of backup boot sectot (2) */
+#define BS_DrvNum32 64 /* Physical drive number (2) */
+#define BS_BootSig32 66 /* Extended boot signature (1) */
+#define BS_VolID32 67 /* Volume serial number (4) */
+#define BS_VolLab32 71 /* Volume label (8) */
+#define BS_FilSysType32 82 /* File system type (1) */
+#define FSI_LeadSig 0 /* FSI: Leading signature (4) */
+#define FSI_StrucSig 484 /* FSI: Structure signature (4) */
+#define FSI_Free_Count 488 /* FSI: Number of free clusters (4) */
+#define FSI_Nxt_Free 492 /* FSI: Last allocated cluster (4) */
+#define MBR_Table 446 /* MBR: Partition table offset (2) */
+#define SZ_PTE 16 /* MBR: Size of a partition table entry */
+#define BS_55AA 510 /* Boot sector signature (2) */
+
+#define DIR_Name 0 /* Short file name (11) */
+#define DIR_Attr 11 /* Attribute (1) */
+#define DIR_NTres 12 /* NT flag (1) */
+#define DIR_CrtTime 14 /* Created time (2) */
+#define DIR_CrtDate 16 /* Created date (2) */
+#define DIR_FstClusHI 20 /* Higher 16-bit of first cluster (2) */
+#define DIR_WrtTime 22 /* Modified time (2) */
+#define DIR_WrtDate 24 /* Modified date (2) */
+#define DIR_FstClusLO 26 /* Lower 16-bit of first cluster (2) */
+#define DIR_FileSize 28 /* File size (4) */
+#define LDIR_Ord 0 /* LFN entry order and LLE flag (1) */
+#define LDIR_Attr 11 /* LFN attribute (1) */
+#define LDIR_Type 12 /* LFN type (1) */
+#define LDIR_Chksum 13 /* Sum of corresponding SFN entry */
+#define LDIR_FstClusLO 26 /* Filled by zero (0) */
+#define SZ_DIR 32 /* Size of a directory entry */
+#define LLE 0x40 /* Last long entry flag in LDIR_Ord */
+#define DDE 0xE5 /* Deleted directory enrty mark in DIR_Name[0] */
+#define NDDE 0x05 /* Replacement of a character collides with DDE */
+
+
+/*------------------------------------------------------------*/
+/* Work area */
+
+#if _VOLUMES
+static
+FATFS *FatFs[_VOLUMES]; /* Pointer to the file system objects (logical drives) */
+#else
+#error Number of drives must not be 0.
+#endif
+
+static
+WORD Fsid; /* File system mount ID */
+
+#if _FS_RPATH
+static
+BYTE CurrVol; /* Current drive */
+#endif
+
+#if _FS_SHARE
+static
+FILESEM Files[_FS_SHARE]; /* File lock semaphores */
+#endif
+
+#if _USE_LFN == 0 /* No LFN */
+#define DEF_NAMEBUF BYTE sfn[12]
+#define INIT_BUF(dobj) (dobj).fn = sfn
+#define FREE_BUF()
+
+#elif _USE_LFN == 1 /* LFN with static LFN working buffer */
+static WCHAR LfnBuf[_MAX_LFN+1];
+#define DEF_NAMEBUF BYTE sfn[12]
+#define INIT_BUF(dobj) { (dobj).fn = sfn; (dobj).lfn = LfnBuf; }
+#define FREE_BUF()
+
+#elif _USE_LFN == 2 /* LFN with dynamic LFN working buffer on the stack */
+#define DEF_NAMEBUF BYTE sfn[12]; WCHAR lbuf[_MAX_LFN+1]
+#define INIT_BUF(dobj) { (dobj).fn = sfn; (dobj).lfn = lbuf; }
+#define FREE_BUF()
+
+#elif _USE_LFN == 3 /* LFN with dynamic LFN working buffer on the heap */
+#define DEF_NAMEBUF BYTE sfn[12]; WCHAR *lfn
+#define INIT_BUF(dobj) { lfn = ff_memalloc((_MAX_LFN + 1) * 2); \
+ if (!lfn) LEAVE_FF((dobj).fs, FR_NOT_ENOUGH_CORE); \
+ (dobj).lfn = lfn; (dobj).fn = sfn; }
+#define FREE_BUF() ff_memfree(lfn)
+
+#else
+#error Wrong LFN configuration.
+#endif
+
+
+
+
+/*--------------------------------------------------------------------------
+
+ Module Private Functions
+
+---------------------------------------------------------------------------*/
+
+//static FATFS *FatFs[_DRIVES]; /* Pointer to the file system objects (logical drives) */
+//static WORD fsid; /* File system mount ID */
+
+/*-----------------------------------------------------------------------*/
+/* String functions */
+/*-----------------------------------------------------------------------*/
+
+/* Copy memory to memory */
+static
+void mem_cpy (void* dst, const void* src, UINT cnt) {
+ BYTE *d = (BYTE*)dst;
+ const BYTE *s = (const BYTE*)src;
+
+#if _WORD_ACCESS == 1
+ while (cnt >= sizeof(int)) {
+ *(int*)d = *(int*)s;
+ d += sizeof(int); s += sizeof(int);
+ cnt -= sizeof(int);
+ }
+#endif
+ while (cnt--)
+ *d++ = *s++;
+}
+
+/* Fill memory */
+static
+void mem_set (void* dst, int val, UINT cnt) {
+ BYTE *d = (BYTE*)dst;
+
+ while (cnt--)
+ *d++ = (BYTE)val;
+}
+
+/* Compare memory to memory */
+static
+int mem_cmp (const void* dst, const void* src, UINT cnt) {
+ const BYTE *d = (const BYTE *)dst, *s = (const BYTE *)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;
+}
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Request/Release grant to access the volume */
+/*-----------------------------------------------------------------------*/
+#if _FS_REENTRANT
+
+static
+int lock_fs (
+ FATFS *fs /* File system object */
+)
+{
+ return ff_req_grant(fs->sobj);
+}
+
+
+static
+void unlock_fs (
+ FATFS *fs, /* File system object */
+ FRESULT res /* Result code to be returned */
+)
+{
+ if (res != FR_NOT_ENABLED &&
+ res != FR_INVALID_DRIVE &&
+ res != FR_INVALID_OBJECT &&
+ res != FR_TIMEOUT) {
+ ff_rel_grant(fs->sobj);
+ }
+}
+#endif
+
+
+
+/*-----------------------------------------------------------------------*/
+/* File shareing control functions */
+/*-----------------------------------------------------------------------*/
+#if _FS_SHARE
+
+static
+FRESULT chk_lock ( /* Check if the file can be accessed */
+ DIR* dj, /* Directory object pointing the file to be checked */
+ int acc /* Desired access (0:Read, 1:Write, 2:Delete/Rename) */
+)
+{
+ UINT i, be;
+
+ /* Search file semaphore table */
+ for (i = be = 0; i < _FS_SHARE; i++) {
+ if (Files[i].fs) { /* Existing entry */
+ if (Files[i].fs == dj->fs && /* Check if the file matched with an open file */
+ Files[i].clu == dj->sclust &&
+ Files[i].idx == dj->index) break;
+ } else { /* Blank entry */
+ be++;
+ }
+ }
+ if (i == _FS_SHARE) /* The file is not opened */
+ return (be || acc == 2) ? FR_OK : FR_TOO_MANY_OPEN_FILES; /* Is there a blank entry for new file? */
+
+ /* The file has been opened. Reject any open against writing file and all write mode open */
+ return (acc || Files[i].ctr == 0x100) ? FR_LOCKED : FR_OK;
+}
+
+
+static
+int enq_lock ( /* Check if an entry is available for a new file */
+ FATFS* fs /* File system object */
+)
+{
+ UINT i;
+
+ for (i = 0; i < _FS_SHARE && Files[i].fs; i++) ;
+ return (i == _FS_SHARE) ? 0 : 1;
+}
+
+
+static
+UINT inc_lock ( /* Increment file open counter and returns its index (0:int error) */
+ DIR* dj, /* Directory object pointing the file to register or increment */
+ int acc /* Desired access mode (0:Read, !0:Write) */
+)
+{
+ UINT i;
+
+
+ for (i = 0; i < _FS_SHARE; i++) { /* Find the file */
+ if (Files[i].fs == dj->fs &&
+ Files[i].clu == dj->sclust &&
+ Files[i].idx == dj->index) break;
+ }
+
+ if (i == _FS_SHARE) { /* Not opened. Register it as new. */
+ for (i = 0; i < _FS_SHARE && Files[i].fs; i++) ;
+ if (i == _FS_SHARE) return 0; /* No space to register (int err) */
+ Files[i].fs = dj->fs;
+ Files[i].clu = dj->sclust;
+ Files[i].idx = dj->index;
+ Files[i].ctr = 0;
+ }
+
+ if (acc && Files[i].ctr) return 0; /* Access violation (int err) */
+
+ Files[i].ctr = acc ? 0x100 : Files[i].ctr + 1; /* Set semaphore value */
+
+ return i + 1;
+}
+
+
+static
+FRESULT dec_lock ( /* Decrement file open counter */
+ UINT i /* Semaphore index */
+)
+{
+ WORD n;
+ FRESULT res;
+
+
+ if (--i < _FS_SHARE) {
+ n = Files[i].ctr;
+ if (n == 0x100) n = 0;
+ if (n) n--;
+ Files[i].ctr = n;
+ if (!n) Files[i].fs = 0;
+ res = FR_OK;
+ } else {
+ res = FR_INT_ERR;
+ }
+ return res;
+}
+
+
+static
+void clear_lock ( /* Clear lock entries of the volume */
+ FATFS *fs
+)
+{
+ UINT i;
+
+ for (i = 0; i < _FS_SHARE; i++) {
+ if (Files[i].fs == fs) Files[i].fs = 0;
+ }
+}
+#endif
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Change window offset */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT move_window (
+ FATFS *fs, /* File system object */
+ DWORD sector /* Sector number to make appearance in the fs->win[] */
+) /* Move to zero only writes back dirty window */
+{
+ DWORD wsect;
+
+
+ wsect = fs->winsect;
+ if (wsect != sector) { /* Changed current window */
+#if !_FS_READONLY
+ if (fs->wflag) { /* Write back dirty window if needed */
+ if (disk_write(fs->drv, fs->win, wsect, 1) != RES_OK)
+ return FR_DISK_ERR;
+ fs->wflag = 0;
+ if (wsect < (fs->fatbase + fs->fsize)) { /* In FAT area */
+ BYTE nf;
+ for (nf = fs->n_fats; nf > 1; nf--) { /* Reflect the change to all FAT copies */
+ wsect += fs->fsize;
+ disk_write(fs->drv, fs->win, wsect, 1);
+ }
+ }
+ }
+#endif
+ if (sector) {
+ if (disk_read(fs->drv, fs->win, sector, 1) != RES_OK)
+ return FR_DISK_ERR;
+ fs->winsect = sector;
+ }
+ }
+
+ return FR_OK;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Clean-up cached data */
+/*-----------------------------------------------------------------------*/
+#if !_FS_READONLY
+static
+FRESULT sync ( /* FR_OK: successful, FR_DISK_ERR: failed */
+ FATFS *fs /* File system object */
+)
+{
+ FRESULT res;
+
+
+ res = move_window(fs, 0);
+ if (res == FR_OK) {
+ /* Update FSInfo sector if needed */
+ if (fs->fs_type == FS_FAT32 && fs->fsi_flag) {
+ fs->winsect = 0;
+ /* Create FSInfo structure */
+ mem_set(fs->win, 0, 512);
+ ST_WORD(fs->win+BS_55AA, 0xAA55);
+ ST_DWORD(fs->win+FSI_LeadSig, 0x41615252);
+ ST_DWORD(fs->win+FSI_StrucSig, 0x61417272);
+ ST_DWORD(fs->win+FSI_Free_Count, fs->free_clust);
+ ST_DWORD(fs->win+FSI_Nxt_Free, fs->last_clust);
+ /* Write it into the FSInfo sector */
+ disk_write(fs->drv, fs->win, fs->fsi_sector, 1);
+ fs->fsi_flag = 0;
+ }
+ /* Make sure that no pending write process in the physical drive */
+ if (disk_ioctl(fs->drv, CTRL_SYNC, (void*)0) != RES_OK)
+ res = FR_DISK_ERR;
+ }
+
+ return res;
+}
+#endif
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Get sector# from cluster# */
+/*-----------------------------------------------------------------------*/
+
+
+DWORD clust2sect ( /* !=0: Sector number, 0: Failed - invalid cluster# */
+ FATFS *fs, /* File system object */
+ DWORD clst /* Cluster# to be converted */
+)
+{
+ clst -= 2;
+ if (clst >= (fs->n_fatent - 2)) return 0; /* Invalid cluster# */
+ return clst * fs->csize + fs->database;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* FAT access - Read value of a FAT entry */
+/*-----------------------------------------------------------------------*/
+
+
+DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, Else:Cluster status */
+ FATFS *fs, /* File system object */
+ DWORD clst /* Cluster# to get the link information */
+)
+{
+ UINT wc, bc;
+ BYTE *p;
+
+
+ if (clst < 2 || clst >= fs->n_fatent) /* Chack range */
+ return 1;
+
+ switch (fs->fs_type) {
+ case FS_FAT12 :
+ bc = (UINT)clst; bc += bc / 2;
+ if (move_window(fs, fs->fatbase + (bc / SS(fs)))) break;
+ wc = fs->win[bc % SS(fs)]; bc++;
+ if (move_window(fs, fs->fatbase + (bc / SS(fs)))) break;
+ wc |= fs->win[bc % SS(fs)] << 8;
+ return (clst & 1) ? (wc >> 4) : (wc & 0xFFF);
+
+ case FS_FAT16 :
+ if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 2)))) break;
+ p = &fs->win[clst * 2 % SS(fs)];
+ return LD_WORD(p);
+
+ case FS_FAT32 :
+ if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4)))) break;
+ p = &fs->win[clst * 4 % SS(fs)];
+ return LD_DWORD(p) & 0x0FFFFFFF;
+ }
+
+ return 0xFFFFFFFF; /* An error occurred at the disk I/O layer */
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* FAT access - Change value of a FAT entry */
+/*-----------------------------------------------------------------------*/
+#if !_FS_READONLY
+
+FRESULT put_fat (
+ FATFS *fs, /* File system object */
+ DWORD clst, /* Cluster# to be changed in range of 2 to fs->n_fatent - 1 */
+ DWORD val /* New value to mark the cluster */
+)
+{
+ UINT bc;
+ BYTE *p;
+ FRESULT res;
+
+
+ if (clst < 2 || clst >= fs->n_fatent) { /* Check range */
+ res = FR_INT_ERR;
+
+ } else {
+ switch (fs->fs_type) {
+ case FS_FAT12 :
+ bc = clst; bc += bc / 2;
+ res = move_window(fs, fs->fatbase + (bc / SS(fs)));
+ if (res != FR_OK) break;
+ p = &fs->win[bc % SS(fs)];
+ *p = (clst & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val;
+ bc++;
+ fs->wflag = 1;
+ res = move_window(fs, fs->fatbase + (bc / SS(fs)));
+ if (res != FR_OK) break;
+ p = &fs->win[bc % SS(fs)];
+ *p = (clst & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F));
+ break;
+
+ case FS_FAT16 :
+ res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 2)));
+ if (res != FR_OK) break;
+ p = &fs->win[clst * 2 % SS(fs)];
+ ST_WORD(p, (WORD)val);
+ break;
+
+ case FS_FAT32 :
+ res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 4)));
+ if (res != FR_OK) break;
+ p = &fs->win[clst * 4 % SS(fs)];
+ val |= LD_DWORD(p) & 0xF0000000;
+ ST_DWORD(p, val);
+ break;
+
+ default :
+ res = FR_INT_ERR;
+ }
+ fs->wflag = 1;
+ }
+
+ return res;
+}
+#endif /* !_FS_READONLY */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* FAT handling - Remove a cluster chain */
+/*-----------------------------------------------------------------------*/
+#if !_FS_READONLY
+static
+FRESULT remove_chain (
+ FATFS *fs, /* File system object */
+ DWORD clst /* Cluster# to remove a chain from */
+)
+{
+ FRESULT res;
+ DWORD nxt;
+#if _USE_ERASE
+ DWORD scl = clst, ecl = clst, resion[2];
+#endif
+
+ if (clst < 2 || clst >= fs->n_fatent) { /* Check range */
+ res = FR_INT_ERR;
+
+ } else {
+ res = FR_OK;
+ while (clst < fs->n_fatent) { /* Not a last link? */
+ nxt = get_fat(fs, clst); /* Get cluster status */
+ if (nxt == 0) break; /* Empty cluster? */
+ if (nxt == 1) { res = FR_INT_ERR; break; } /* Internal error? */
+ if (nxt == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } /* Disk error? */
+ res = put_fat(fs, clst, 0); /* Mark the cluster "empty" */
+ if (res != FR_OK) break;
+ if (fs->free_clust != 0xFFFFFFFF) { /* Update FSInfo */
+ fs->free_clust++;
+ fs->fsi_flag = 1;
+ }
+#if _USE_ERASE
+ if (ecl + 1 == nxt) { /* Next cluster is contiguous */
+ ecl = nxt;
+ } else { /* End of contiguous clusters */
+ resion[0] = clust2sect(fs, scl); /* Start sector */
+ resion[1] = clust2sect(fs, ecl) + fs->csize - 1; /* End sector */
+ disk_ioctl(fs->drv, CTRL_ERASE_SECTOR, resion); /* Erase the block */
+ scl = ecl = nxt;
+ }
+#endif
+ clst = nxt; /* Next cluster */
+ }
+ }
+
+ return res;
+}
+#endif
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* FAT handling - Stretch or Create a cluster chain */
+/*-----------------------------------------------------------------------*/
+#if !_FS_READONLY
+static
+DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */
+ FATFS *fs, /* File system object */
+ DWORD clst /* Cluster# to stretch. 0 means create a new chain. */
+)
+{
+ DWORD cs, ncl, scl;
+ FRESULT res;
+
+
+ if (clst == 0) { /* Create a new chain */
+ scl = fs->last_clust; /* Get suggested start point */
+ if (!scl || scl >= fs->n_fatent) scl = 1;
+ }
+ else { /* Stretch the current chain */
+ cs = get_fat(fs, clst); /* Check the cluster status */
+ if (cs < 2) return 1; /* It is an invalid cluster */
+ if (cs < fs->n_fatent) return cs; /* It is already followed by next cluster */
+ scl = clst;
+ }
+
+ ncl = scl; /* Start cluster */
+ for (;;) {
+ ncl++; /* Next cluster */
+ if (ncl >= fs->n_fatent) { /* Wrap around */
+ ncl = 2;
+ if (ncl > scl) return 0; /* No free cluster */
+ }
+ cs = get_fat(fs, ncl); /* Get the cluster status */
+ if (cs == 0) break; /* Found a free cluster */
+ if (cs == 0xFFFFFFFF || cs == 1)/* An error occurred */
+ return cs;
+ if (ncl == scl) return 0; /* No free cluster */
+ }
+
+ res = put_fat(fs, ncl, 0x0FFFFFFF); /* Mark the new cluster "last link" */
+ if (res == FR_OK && clst != 0) {
+ res = put_fat(fs, clst, ncl); /* Link it to the previous one if needed */
+ }
+ if (res == FR_OK) {
+ fs->last_clust = ncl; /* Update FSINFO */
+ if (fs->free_clust != 0xFFFFFFFF) {
+ fs->free_clust--;
+ fs->fsi_flag = 1;
+ }
+ } else {
+ ncl = (res == FR_DISK_ERR) ? 0xFFFFFFFF : 1;
+ }
+
+ return ncl; /* Return new cluster number or error code */
+}
+#endif /* !_FS_READONLY */
+
+
+
+/*-----------------------------------------------------------------------*/
+/* FAT handling - Convert offset into cluster with link map table */
+/*-----------------------------------------------------------------------*/
+
+#if _USE_FASTSEEK
+static
+DWORD clmt_clust ( /* <2:Error, >=2:Cluster number */
+ FIL* fp, /* Pointer to the file object */
+ DWORD ofs /* File offset to be converted to cluster# */
+)
+{
+ DWORD cl, ncl, *tbl;
+
+
+ tbl = fp->cltbl + 1; /* Top of CLMT */
+ cl = ofs / SS(fp->fs) / fp->fs->csize; /* Cluster order from top of the file */
+ for (;;) {
+ ncl = *tbl++; /* Number of cluters in the fragment */
+ if (!ncl) return 0; /* End of table? (error) */
+ if (cl < ncl) break; /* In this fragment? */
+ cl -= ncl; tbl++; /* Next fragment */
+ }
+ return cl + *tbl; /* Return the cluster number */
+}
+#endif /* _USE_FASTSEEK */
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Directory handling - Set directory index */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT dir_sdi (
+ DIR_t *dj, /* Pointer to directory object */
+ WORD idx /* Directory index number */
+)
+{
+ DWORD clst;
+ WORD ic;
+
+
+ dj->index = idx;
+ clst = dj->sclust;
+ if (clst == 1 || clst >= dj->fs->n_fatent) /* Check start cluster range */
+ return FR_INT_ERR;
+ if (!clst && dj->fs->fs_type == FS_FAT32) /* Replace cluster# 0 with root cluster# if in FAT32 */
+ clst = dj->fs->dirbase;
+
+ if (clst == 0) { /* Static table (root-dir in FAT12/16) */
+ dj->clust = clst;
+ if (idx >= dj->fs->n_rootdir) /* Index is out of range */
+ return FR_INT_ERR;
+ dj->sect = dj->fs->dirbase + idx / (SS(dj->fs) / SZ_DIR); /* Sector# */
+ }
+ else { /* Dynamic table (sub-dirs or root-dir in FAT32) */
+ ic = SS(dj->fs) / SZ_DIR * dj->fs->csize; /* Entries per cluster */
+ while (idx >= ic) { /* Follow cluster chain */
+ clst = get_fat(dj->fs, clst); /* Get next cluster */
+ if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */
+ if (clst < 2 || clst >= dj->fs->n_fatent) /* Reached to end of table or int error */
+ return FR_INT_ERR;
+ idx -= ic;
+ }
+ dj->clust = clst;
+ dj->sect = clust2sect(dj->fs, clst) + idx / (SS(dj->fs) / SZ_DIR); /* Sector# */
+ }
+
+ dj->dir = dj->fs->win + (idx % (SS(dj->fs) / SZ_DIR)) * SZ_DIR; /* Ptr to the entry in the 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 stretch */
+ DIR_t *dj, /* Pointer to directory object */
+ int stretch /* 0: Do not stretch table, 1: Stretch table if needed */
+)
+{
+ DWORD clst;
+ WORD i;
+
+
+ i = dj->index + 1;
+ if (!i || !dj->sect) /* Report EOT when index has reached 65535 */
+ return FR_NO_FILE;
+
+ if (!(i % (SS(dj->fs) / SZ_DIR))) { /* Sector changed? */
+ dj->sect++; /* Next sector */
+
+ if (dj->clust == 0) { /* Static table */
+ if (i >= dj->fs->n_rootdir) /* Report EOT when end of table */
+ return FR_NO_FILE;
+ }
+ else { /* Dynamic table */
+ if (((i / (SS(dj->fs) / SZ_DIR)) & (dj->fs->csize - 1)) == 0) { /* Cluster changed? */
+ clst = get_fat(dj->fs, dj->clust); /* Get next cluster */
+ if (clst <= 1) return FR_INT_ERR;
+ if (clst == 0xFFFFFFFF) return FR_DISK_ERR;
+ if (clst >= dj->fs->n_fatent) { /* When it reached end of dynamic table */
+#if !_FS_READONLY
+ BYTE c;
+ if (!stretch) return FR_NO_FILE; /* When do not stretch, report EOT */
+ clst = create_chain(dj->fs, dj->clust); /* Stretch cluster chain */
+ if (clst == 0) return FR_DENIED; /* No free cluster */
+ if (clst == 1) return FR_INT_ERR;
+ if (clst == 0xFFFFFFFF) return FR_DISK_ERR;
+ /* Clean-up stretched table */
+ if (move_window(dj->fs, 0)) return FR_DISK_ERR; /* Flush active window */
+ mem_set(dj->fs->win, 0, SS(dj->fs)); /* Clear window buffer */
+ dj->fs->winsect = clust2sect(dj->fs, clst); /* Cluster start sector */
+ for (c = 0; c < dj->fs->csize; c++) { /* Fill the new cluster with 0 */
+ dj->fs->wflag = 1;
+ if (move_window(dj->fs, 0)) return FR_DISK_ERR;
+ dj->fs->winsect++;
+ }
+ dj->fs->winsect -= c; /* Rewind window address */
+#else
+ return FR_NO_FILE; /* Report EOT */
+#endif
+ }
+ dj->clust = clst; /* Initialize data for new cluster */
+ dj->sect = clust2sect(dj->fs, clst);
+ }
+ }
+ }
+
+ dj->index = i;
+ dj->dir = dj->fs->win + (i % (SS(dj->fs) / SZ_DIR)) * SZ_DIR;
+
+ return FR_OK;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* LFN handling - Test/Pick/Fit an LFN segment from/to directory entry */
+/*-----------------------------------------------------------------------*/
+#if _USE_LFN
+static
+const BYTE LfnOfs[] = {1,3,5,7,9,14,16,18,20,22,24,28,30}; /* Offset of LFN chars in the directory entry */
+
+
+static
+int cmp_lfn ( /* 1:Matched, 0:Not matched */
+ WCHAR *lfnbuf, /* Pointer to the LFN to be compared */
+ BYTE *dir /* Pointer to the directory entry containing a part of LFN */
+)
+{
+ UINT i, s;
+ WCHAR wc, uc;
+
+
+ i = ((dir[LDIR_Ord] & ~LLE) - 1) * 13; /* Get offset in the LFN buffer */
+ s = 0; wc = 1;
+ do {
+ uc = LD_WORD(dir+LfnOfs[s]); /* Pick an LFN character from the entry */
+ if (wc) { /* Last char has not been processed */
+ wc = ff_wtoupper(uc); /* Convert it to upper case */
+ if (i >= _MAX_LFN || wc != ff_wtoupper(lfnbuf[i++])) /* Compare it */
+ return 0; /* Not matched */
+ } else {
+ if (uc != 0xFFFF) return 0; /* Check filler */
+ }
+ } while (++s < 13); /* Repeat until all chars in the entry are checked */
+
+ if ((dir[LDIR_Ord] & LLE) && wc && lfnbuf[i]) /* Last segment matched but different length */
+ return 0;
+
+ return 1; /* The part of LFN matched */
+ }
+
+
+
+static
+int pick_lfn ( /* 1:Succeeded, 0:Buffer overflow */
+ WCHAR *lfnbuf, /* Pointer to the Unicode-LFN buffer */
+ BYTE *dir /* Pointer to the directory entry */
+)
+{
+ UINT i, s;
+ WCHAR wc, uc;
+
+
+ i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the LFN buffer */
+
+ s = 0; wc = 1;
+ do {
+ uc = LD_WORD(dir+LfnOfs[s]); /* Pick an LFN character from the entry */
+ if (wc) { /* Last char has not been processed */
+ if (i >= _MAX_LFN) return 0; /* Buffer overflow? */
+ lfnbuf[i++] = wc = uc; /* Store it */
+ } else {
+ if (uc != 0xFFFF) return 0; /* Check filler */
+ }
+ } while (++s < 13); /* Read all character in the entry */
+
+ if (dir[LDIR_Ord] & LLE) { /* Put terminator if it is the last LFN part */
+ if (i >= _MAX_LFN) return 0; /* Buffer overflow? */
+ lfnbuf[i] = 0;
+}
+
+ return 1;
+}
+
+
+#if !_FS_READONLY
+static
+void fit_lfn (
+ const WCHAR *lfnbuf, /* Pointer to the LFN buffer */
+ BYTE *dir, /* Pointer to the directory entry */
+ BYTE ord, /* LFN order (1-20) */
+ BYTE sum /* SFN sum */
+)
+{
+ UINT i, s;
+ WCHAR wc;
+
+
+ dir[LDIR_Chksum] = sum; /* Set check sum */
+ dir[LDIR_Attr] = AM_LFN; /* Set attribute. LFN entry */
+ dir[LDIR_Type] = 0;
+ ST_WORD(dir+LDIR_FstClusLO, 0);
+
+ i = (ord - 1) * 13; /* Get offset in the LFN buffer */
+ s = wc = 0;
+ do {
+ if (wc != 0xFFFF) wc = lfnbuf[i++]; /* Get an effective char */
+ ST_WORD(dir+LfnOfs[s], wc); /* Put it */
+ if (!wc) wc = 0xFFFF; /* Padding chars following last char */
+ } while (++s < 13);
+ if (wc == 0xFFFF || !lfnbuf[i]) ord |= LLE; /* Bottom LFN part is the start of LFN sequence */
+ dir[LDIR_Ord] = ord; /* Set the LFN order */
+}
+
+#endif
+#endif
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Create numbered name */
+/*-----------------------------------------------------------------------*/
+#if _USE_LFN
+void gen_numname (
+ BYTE *dst, /* Pointer to generated SFN */
+ const BYTE *src, /* Pointer to source SFN to be modified */
+ const WCHAR *lfn, /* Pointer to LFN */
+ WORD seq /* Sequence number */
+)
+{
+ BYTE ns[8], c;
+ UINT i, j;
+
+
+ mem_cpy(dst, src, 11);
+
+ if (seq > 5) { /* On many collisions, generate a hash number instead of sequential number */
+ do seq = (seq >> 1) + (seq << 15) + (WORD)*lfn++; while (*lfn);
+ }
+
+ /* itoa (hexdecimal) */
+ i = 7;
+ do {
+ c = (seq % 16) + '0';
+ if (c > '9') c += 7;
+ ns[i--] = c;
+ seq /= 16;
+ } while (seq);
+ ns[i] = '~';
+
+ /* Append the number */
+ for (j = 0; j < i && dst[j] != ' '; j++) {
+ if (IsDBCS1(dst[j])) {
+ if (j == i - 1) break;
+ j++;
+ }
+ }
+ do {
+ dst[j++] = (i < 8) ? ns[i++] : ' ';
+ } while (j < 8);
+}
+#endif
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Calculate sum of an SFN */
+/*-----------------------------------------------------------------------*/
+#if _USE_LFN
+static
+BYTE sum_sfn (
+ const BYTE *dir /* Ptr to directory entry */
+)
+{
+ BYTE sum = 0;
+ UINT n = 11;
+
+ do sum = (sum >> 1) + (sum << 7) + *dir++; while (--n);
+ return sum;
+}
+#endif
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Directory handling - Find an object in the directory */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT dir_find (
+ DIR_t *dj /* Pointer to the directory object linked to the file name */
+)
+{
+ FRESULT res;
+ BYTE c, *dir;
+#if _USE_LFN
+ BYTE a, ord, sum;
+#endif
+
+ res = dir_sdi(dj, 0); /* Rewind directory object */
+ if (res != FR_OK) return res;
+
+#if _USE_LFN
+ ord = sum = 0xFF;
+#endif
+ do {
+ res = move_window(dj->fs, dj->sect);
+ if (res != FR_OK) break;
+ dir = dj->dir; /* Ptr to the directory entry of current index */
+ c = dir[DIR_Name];
+ if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */
+#if _USE_LFN /* LFN configuration */
+ a = dir[DIR_Attr] & AM_MASK;
+ if (c == DDE || ((a & AM_VOL) && a != AM_LFN)) { /* An entry without valid data */
+ ord = 0xFF;
+ } else {
+ if (a == AM_LFN) { /* An LFN entry is found */
+ if (dj->lfn) {
+ if (c & LLE) { /* Is it start of LFN sequence? */
+ sum = dir[LDIR_Chksum];
+ c &= ~LLE; ord = c; /* LFN start order */
+ dj->lfn_idx = dj->index;
+ }
+ /* Check validity of the LFN entry and compare it with given name */
+ ord = (c == ord && sum == dir[LDIR_Chksum] && cmp_lfn(dj->lfn, dir)) ? ord - 1 : 0xFF;
+ }
+ } else { /* An SFN entry is found */
+ if (!ord && sum == sum_sfn(dir)) break; /* LFN matched? */
+ ord = 0xFF; dj->lfn_idx = 0xFFFF; /* Reset LFN sequence */
+ if (!(dj->fn[NS] & NS_LOSS) && !mem_cmp(dir, dj->fn, 11)) break; /* SFN matched? */
+ }
+ }
+#else /* Non LFN configuration */
+ if (!(dir[DIR_Attr] & AM_VOL) && !mem_cmp(dir, dj->fn, 11)) /* Is it a valid entry? */
+ break;
+#endif
+ res = dir_next(dj, 0); /* Next entry */
+ } while (res == FR_OK);
+
+ return res;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Read an object from the directory */
+/*-----------------------------------------------------------------------*/
+#if _FS_MINIMIZE <= 1
+static
+FRESULT dir_read (
+ DIR_t *dj /* Pointer to the directory object that pointing the entry to be read */
+)
+{
+ FRESULT res;
+ BYTE c, *dir;
+#if _USE_LFN
+ BYTE a, ord = 0xFF, sum = 0xFF;
+#endif
+
+ res = FR_NO_FILE;
+ while (dj->sect) {
+ res = move_window(dj->fs, dj->sect);
+ if (res != FR_OK) break;
+ dir = dj->dir; /* Ptr to the directory entry of current index */
+ c = dir[DIR_Name];
+ if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */
+#if _USE_LFN /* LFN configuration */
+ a = dir[DIR_Attr] & AM_MASK;
+ if (c == DDE || (!_FS_RPATH && c == '.') || ((a & AM_VOL) && a != AM_LFN)) { /* An entry without valid data */
+ ord = 0xFF;
+ } else {
+ if (a == AM_LFN) { /* An LFN entry is found */
+ if (c & LLE) { /* Is it start of LFN sequence? */
+ sum = dir[LDIR_Chksum];
+ c &= ~LLE; ord = c;
+ dj->lfn_idx = dj->index;
+ }
+ /* Check LFN validity and capture it */
+ ord = (c == ord && sum == dir[LDIR_Chksum] && pick_lfn(dj->lfn, dir)) ? ord - 1 : 0xFF;
+ } else { /* An SFN entry is found */
+ if (ord || sum != sum_sfn(dir)) /* Is there a valid LFN? */
+ dj->lfn_idx = 0xFFFF; /* It has no LFN. */
+ break;
+ }
+ }
+#else /* Non LFN configuration */
+ if (c != DDE && (_FS_RPATH || c != '.') && !(dir[DIR_Attr] & AM_VOL)) /* Is it a valid entry? */
+ break;
+#endif
+ res = dir_next(dj, 0); /* Next entry */
+ if (res != FR_OK) break;
+ }
+
+ if (res != FR_OK) dj->sect = 0;
+
+ return res;
+ }
+#endif
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Register an object to the directory */
+/*-----------------------------------------------------------------------*/
+#if !_FS_READONLY
+static
+FRESULT dir_register ( /* FR_OK:Successful, FR_DENIED:No free entry or too many SFN collision, FR_DISK_ERR:Disk error */
+ DIR_t *dj /* Target directory with object name to be created */
+)
+{
+ FRESULT res;
+ BYTE c, *dir;
+#if _USE_LFN /* LFN configuration */
+ WORD n, ne, is;
+ BYTE sn[12], *fn, sum;
+ WCHAR *lfn;
+
+
+ fn = dj->fn; lfn = dj->lfn;
+ mem_cpy(sn, fn, 12);
+
+ if (_FS_RPATH && (sn[NS] & NS_DOT)) /* Cannot create dot entry */
+ return FR_INVALID_NAME;
+
+ if (sn[NS] & NS_LOSS) { /* When LFN is out of 8.3 format, generate a numbered name */
+ fn[NS] = 0; dj->lfn = 0; /* Find only SFN */
+ for (n = 1; n < 100; n++) {
+ gen_numname(fn, sn, lfn, n); /* Generate a numbered name */
+ res = dir_find(dj); /* Check if the name collides with existing SFN */
+ if (res != FR_OK) break;
+ }
+ if (n == 100) return FR_DENIED; /* Abort if too many collisions */
+ if (res != FR_NO_FILE) return res; /* Abort if the result is other than 'not collided' */
+ fn[NS] = sn[NS]; dj->lfn = lfn;
+}
+
+ if (sn[NS] & NS_LFN) { /* When LFN is to be created, reserve an SFN + LFN entries. */
+ for (ne = 0; lfn[ne]; ne++) ;
+ ne = (ne + 25) / 13;
+ } else { /* Otherwise reserve only an SFN entry. */
+ ne = 1;
+ }
+
+ /* Reserve contiguous entries */
+ res = dir_sdi(dj, 0);
+ if (res != FR_OK) return res;
+ n = is = 0;
+ do {
+ res = move_window(dj->fs, dj->sect);
+ if (res != FR_OK) break;
+ c = *dj->dir; /* Check the entry status */
+ if (c == DDE || c == 0) { /* Is it a blank entry? */
+ if (n == 0) is = dj->index; /* First index of the contiguous entry */
+ if (++n == ne) break; /* A contiguous entry that required count is found */
+ } else {
+ n = 0; /* Not a blank entry. Restart to search */
+ }
+ res = dir_next(dj, 1); /* Next entry with table stretch */
+ } while (res == FR_OK);
+
+ if (res == FR_OK && ne > 1) { /* Initialize LFN entry if needed */
+ res = dir_sdi(dj, is);
+ if (res == FR_OK) {
+ sum = sum_sfn(dj->fn); /* Sum of the SFN tied to the LFN */
+ ne--;
+ do { /* Store LFN entries in bottom first */
+ res = move_window(dj->fs, dj->sect);
+ if (res != FR_OK) break;
+ fit_lfn(dj->lfn, dj->dir, (BYTE)ne, sum);
+ dj->fs->wflag = 1;
+ res = dir_next(dj, 0); /* Next entry */
+ } while (res == FR_OK && --ne);
+ }
+ }
+
+#else /* Non LFN configuration */
+ res = dir_sdi(dj, 0);
+ if (res == FR_OK) {
+ do { /* Find a blank entry for the SFN */
+ res = move_window(dj->fs, dj->sect);
+ if (res != FR_OK) break;
+ c = *dj->dir;
+ if (c == DDE || c == 0) break; /* Is it a blank entry? */
+ res = dir_next(dj, 1); /* Next entry with table stretch */
+ } while (res == FR_OK);
+ }
+#endif
+
+ if (res == FR_OK) { /* Initialize the SFN entry */
+ res = move_window(dj->fs, dj->sect);
+ if (res == FR_OK) {
+ dir = dj->dir;
+ mem_set(dir, 0, SZ_DIR); /* Clean the entry */
+ mem_cpy(dir, dj->fn, 11); /* Put SFN */
+#if _USE_LFN
+ dir[DIR_NTres] = *(dj->fn+NS) & (NS_BODY | NS_EXT); /* Put NT flag */
+#endif
+ dj->fs->wflag = 1;
+ }
+ }
+
+ return res;
+}
+#endif /* !_FS_READONLY */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Remove an object from the directory */
+/*-----------------------------------------------------------------------*/
+#if !_FS_READONLY && !_FS_MINIMIZE
+static
+FRESULT dir_remove ( /* FR_OK: Successful, FR_DISK_ERR: A disk error */
+ DIR_t *dj /* Directory object pointing the entry to be removed */
+)
+{
+ FRESULT res;
+#if _USE_LFN /* LFN configuration */
+ WORD i;
+
+ i = dj->index; /* SFN index */
+ res = dir_sdi(dj, (WORD)((dj->lfn_idx == 0xFFFF) ? i : dj->lfn_idx)); /* Goto the SFN or top of the LFN entries */
+ if (res == FR_OK) {
+ do {
+ res = move_window(dj->fs, dj->sect);
+ if (res != FR_OK) break;
+ *dj->dir = DDE; /* Mark the entry "deleted" */
+ dj->fs->wflag = 1;
+ if (dj->index >= i) break; /* When reached SFN, all entries of the object has been deleted. */
+ res = dir_next(dj, 0); /* Next entry */
+ } while (res == FR_OK);
+ if (res == FR_NO_FILE) res = FR_INT_ERR;
+ }
+
+#else /* Non LFN configuration */
+ res = dir_sdi(dj, dj->index);
+ if (res == FR_OK) {
+ res = move_window(dj->fs, dj->sect);
+ if (res == FR_OK) {
+ *dj->dir = DDE; /* Mark the entry "deleted" */
+ dj->fs->wflag = 1;
+ }
+ }
+#endif
+
+ return res;
+}
+#endif /* !_FS_READONLY */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Pick a segment and create the object name in directory form */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT create_name (
+ DIR_t *dj, /* Pointer to the directory object */
+ const TCHAR **path /* Pointer to pointer to the segment in the path string */
+)
+{
+#ifdef _EXCVT
+ static const BYTE excvt[] = _EXCVT; /* Upper conversion table for extended chars */
+#endif
+
+#if _USE_LFN /* LFN configuration */
+ BYTE b, cf;
+ WCHAR w, *lfn;
+ UINT i, ni, si, di;
+ const TCHAR *p;
+
+ /* Create LFN in Unicode */
+ for (p = *path; *p == '/' || *p == '\\'; p++) ; /* Strip duplicated separator */
+ lfn = dj->lfn;
+ si = di = 0;
+ for (;;) {
+ w = p[si++]; /* Get a character */
+ if (w < ' ' || w == '/' || w == '\\') break; /* Break on end of segment */
+ if (di >= _MAX_LFN) /* Reject too long name */
+ return FR_INVALID_NAME;
+#if !_LFN_UNICODE
+ w &= 0xFF;
+ if (IsDBCS1(w)) { /* Check if it is a DBC 1st byte (always false on SBCS cfg) */
+ b = (BYTE)p[si++]; /* Get 2nd byte */
+ if (!IsDBCS2(b))
+ return FR_INVALID_NAME; /* Reject invalid sequence */
+ w = (w << 8) + b; /* Create a DBC */
+ }
+ w = ff_convert(w, 1); /* Convert ANSI/OEM to Unicode */
+ if (!w) return FR_INVALID_NAME; /* Reject invalid code */
+#endif
+ if (w < 0x80 && chk_chr("\"*:<>\?|\x7F", w)) /* Reject illegal chars for LFN */
+ return FR_INVALID_NAME;
+ lfn[di++] = w; /* Store the Unicode char */
+ }
+ *path = &p[si]; /* Return pointer to the next segment */
+ cf = (w < ' ') ? NS_LAST : 0; /* Set last segment flag if end of path */
+#if _FS_RPATH
+ if ((di == 1 && lfn[di-1] == '.') || /* Is this a dot entry? */
+ (di == 2 && lfn[di-1] == '.' && lfn[di-2] == '.')) {
+ lfn[di] = 0;
+ for (i = 0; i < 11; i++)
+ dj->fn[i] = (i < di) ? '.' : ' ';
+ dj->fn[i] = cf | NS_DOT; /* This is a dot entry */
+ return FR_OK;
+ }
+#endif
+ while (di) { /* Strip trailing spaces and dots */
+ w = lfn[di-1];
+ if (w != ' ' && w != '.') break;
+ di--;
+ }
+ if (!di) return FR_INVALID_NAME; /* Reject nul string */
+
+ lfn[di] = 0; /* LFN is created */
+
+ /* Create SFN in directory form */
+ mem_set(dj->fn, ' ', 11);
+ for (si = 0; lfn[si] == ' ' || lfn[si] == '.'; si++) ; /* Strip leading spaces and dots */
+ if (si) cf |= NS_LOSS | NS_LFN;
+ while (di && lfn[di - 1] != '.') di--; /* Find extension (di<=si: no extension) */
+
+ b = i = 0; ni = 8;
+ for (;;) {
+ w = lfn[si++]; /* Get an LFN char */
+ if (!w) break; /* Break on end of the LFN */
+ if (w == ' ' || (w == '.' && si != di)) { /* Remove spaces and dots */
+ cf |= NS_LOSS | NS_LFN; continue;
+ }
+
+ if (i >= ni || si == di) { /* Extension or end of SFN */
+ if (ni == 11) { /* Long extension */
+ cf |= NS_LOSS | NS_LFN; break;
+ }
+ if (si != di) cf |= NS_LOSS | NS_LFN; /* Out of 8.3 format */
+ if (si > di) break; /* No extension */
+ si = di; i = 8; ni = 11; /* Enter extension section */
+ b <<= 2; continue;
+ }
+
+ if (w >= 0x80) { /* Non ASCII char */
+#ifdef _EXCVT
+ w = ff_convert(w, 0); /* Unicode -> OEM code */
+ if (w) w = excvt[w - 0x80]; /* Convert extended char to upper (SBCS) */
+#else
+ w = ff_convert(ff_wtoupper(w), 0); /* Upper converted Unicode -> OEM code */
+#endif
+ cf |= NS_LFN; /* Force create LFN entry */
+ }
+
+ if (_DF1S && w >= 0x100) { /* Double byte char (always false on SBCS cfg) */
+ if (i >= ni - 1) {
+ cf |= NS_LOSS | NS_LFN; i = ni; continue;
+ }
+ dj->fn[i++] = (BYTE)(w >> 8);
+ } else { /* Single byte char */
+ if (!w || chk_chr("+,;=[]", w)) { /* Replace illegal chars for SFN */
+ w = '_'; cf |= NS_LOSS | NS_LFN;/* Lossy conversion */
+ } else {
+ if (IsUpper(w)) { /* ASCII large capital */
+ b |= 2;
+ } else {
+ if (IsLower(w)) { /* ASCII small capital */
+ b |= 1; w -= 0x20;
+ }
+ }
+ }
+ }
+ dj->fn[i++] = (BYTE)w;
+ }
+
+ if (dj->fn[0] == DDE) dj->fn[0] = NDDE; /* If the first char collides with deleted mark, replace it with 0x05 */
+
+ if (ni == 8) b <<= 2;
+ if ((b & 0x0C) == 0x0C || (b & 0x03) == 0x03) /* Create LFN entry when there are composite capitals */
+ cf |= NS_LFN;
+ if (!(cf & NS_LFN)) { /* When LFN is in 8.3 format without extended char, NT flags are created */
+ if ((b & 0x03) == 0x01) cf |= NS_EXT; /* NT flag (Extension has only small capital) */
+ if ((b & 0x0C) == 0x04) cf |= NS_BODY; /* NT flag (Filename has only small capital) */
+ }
+
+ dj->fn[NS] = cf; /* SFN is created */
+
+ return FR_OK;
+
+
+#else /* Non-LFN configuration */
+ BYTE b, c, d, *sfn;
+ UINT ni, si, i;
+ const char *p;
+
+ /* Create file name in directory form */
+ for (p = *path; *p == '/' || *p == '\\'; p++) ; /* Strip duplicated separator */
+ sfn = dj->fn;
+ mem_set(sfn, ' ', 11);
+ si = i = b = 0; ni = 8;
+#if _FS_RPATH
+ if (p[si] == '.') { /* Is this a dot entry? */
+ for (;;) {
+ c = (BYTE)p[si++];
+ if (c != '.' || si >= 3) break;
+ sfn[i++] = c;
+ }
+ if (c != '/' && c != '\\' && c > ' ') return FR_INVALID_NAME;
+ *path = &p[si]; /* Return pointer to the next segment */
+ sfn[NS] = (c <= ' ') ? NS_LAST | NS_DOT : NS_DOT; /* Set last segment flag if end of path */
+ return FR_OK;
+ }
+#endif
+ for (;;) {
+ c = (BYTE)p[si++];
+ if (c <= ' ' || c == '/' || c == '\\') break; /* Break on end of segment */
+ if (c == '.' || i >= ni) {
+ if (ni != 8 || c != '.') return FR_INVALID_NAME;
+ i = 8; ni = 11;
+ b <<= 2; continue;
+ }
+ if (c >= 0x80) { /* Extended char? */
+ b |= 3; /* Eliminate NT flag */
+#ifdef _EXCVT
+ c = excvt[c-0x80]; /* Upper conversion (SBCS) */
+#else
+#if !_DF1S /* ASCII only cfg */
+ return FR_INVALID_NAME;
+#endif
+#endif
+ }
+ if (IsDBCS1(c)) { /* Check if it is a DBC 1st byte (always false on SBCS cfg) */
+ d = (BYTE)p[si++]; /* Get 2nd byte */
+ if (!IsDBCS2(d) || i >= ni - 1) /* Reject invalid DBC */
+ return FR_INVALID_NAME;
+ sfn[i++] = c;
+ sfn[i++] = d;
+ } else { /* Single byte code */
+ if (chk_chr("\"*+,:;<=>\?[]|\x7F", c)) /* Reject illegal chrs for SFN */
+ return FR_INVALID_NAME;
+ if (IsUpper(c)) { /* ASCII large capital? */
+ b |= 2;
+ } else {
+ if (IsLower(c)) { /* ASCII small capital? */
+ b |= 1; c -= 0x20;
+ }
+ }
+ sfn[i++] = c;
+ }
+ }
+ *path = &p[si]; /* Return pointer to the next segment */
+ c = (c <= ' ') ? NS_LAST : 0; /* Set last segment flag if end of path */
+
+ if (!i) return FR_INVALID_NAME; /* Reject nul string */
+ if (sfn[0] == DDE) sfn[0] = NDDE; /* When first char collides with DDE, replace it with 0x05 */
+
+ if (ni == 8) b <<= 2;
+ if ((b & 0x03) == 0x01) c |= NS_EXT; /* NT flag (Name extension has only small capital) */
+ if ((b & 0x0C) == 0x04) c |= NS_BODY; /* NT flag (Name body has only small capital) */
+
+ sfn[NS] = c; /* Store NT flag, File name is created */
+
+ return FR_OK;
+#endif
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Get file information from directory entry */
+/*-----------------------------------------------------------------------*/
+#if _FS_MINIMIZE <= 1
+static
+void get_fileinfo ( /* No return code */
+ DIR_t *dj, /* Pointer to the directory object */
+ FILINFO *fno /* Pointer to the file information to be filled */
+)
+{
+ UINT i;
+ BYTE nt, *dir;
+ TCHAR *p, c;
+ p = fno->fname;
+
+ if (dj->sect) {
+ dir = dj->dir;
+ nt = dir[DIR_NTres]; /* NT flag */
+ for (i = 0; i < 8; i++) { /* Copy name body */
+ c = dir[i];
+ if (c == ' ') break;
+ if (c == NDDE) c = (TCHAR)DDE;
+ if (_USE_LFN && (nt & NS_BODY) && IsUpper(c)) c += 0x20;
+#if _LFN_UNICODE
+ if (IsDBCS1(c) && i < 7 && IsDBCS2(dir[i+1]))
+ c = (c << 8) | dir[++i];
+ c = ff_convert(c, 1);
+ if (!c) c = '?';
+#endif
+ *p++ = c;
+ }
+ if (dir[8] != ' ') { /* Copy name extension */
+ *p++ = '.';
+ for (i = 8; i < 11; i++) {
+ c = dir[i];
+ if (c == ' ') break;
+ if (_USE_LFN && (nt & NS_EXT) && IsUpper(c)) c += 0x20;
+#if _LFN_UNICODE
+ if (IsDBCS1(c) && i < 10 && IsDBCS2(dir[i+1]))
+ c = (c << 8) | dir[++i];
+ c = ff_convert(c, 1);
+ if (!c) c = '?';
+#endif
+ *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; /* Terminate SFN str by a \0 */
+
+#if _USE_LFN
+ if (fno->lfname && fno->lfsize) {
+ TCHAR *tp = fno->lfname;
+ WCHAR w, *lfn;
+
+ i = 0;
+ if (dj->sect && dj->lfn_idx != 0xFFFF) {/* Get LFN if available */
+ lfn = dj->lfn;
+ while ((w = *lfn++) != 0) { /* Get an LFN char */
+#if !_LFN_UNICODE
+ w = ff_convert(w, 0); /* Unicode -> OEM conversion */
+ if (!w) { i = 0; break; } /* Could not convert, no LFN */
+ if (_DF1S && w >= 0x100) /* Put 1st byte if it is a DBC (always false on SBCS cfg) */
+ tp[i++] = (TCHAR)(w >> 8);
+#endif
+ if (i >= fno->lfsize - 1) { i = 0; break; } /* Buffer overflow, no LFN */
+ tp[i++] = (TCHAR)w;
+ }
+
+ }
+ tp[i] = 0; /* Terminate the LFN str by a \0 */
+ }
+#endif
+}
+#endif /* _FS_MINIMIZE <= 1 */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Follow a file path */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */
+ DIR_t *dj, /* Directory object to return last directory and found object */
+ const TCHAR *path /* Full-path string to find a file or directory */
+)
+{
+ FRESULT res;
+ BYTE *dir, ns;
+
+
+#if _FS_RPATH
+ if (*path == '/' || *path == '\\') { /* There is a heading separator */
+ path++; dj->sclust = 0; /* Strip it and start from the root dir */
+ } else { /* No heading separator */
+ dj->sclust = dj->fs->cdir; /* Start from the current dir */
+ }
+#else
+ if (*path == '/' || *path == '\\') /* Strip heading separator if exist */
+ path++;
+ dj->sclust = 0; /* Start from the root dir */
+#endif
+
+ if ((UINT)*path < ' ') { /* Nul path means the start directory itself */
+ res = dir_sdi(dj, 0);
+ dj->dir = 0;
+
+ } else { /* Follow path */
+ for (;;) {
+ res = create_name(dj, &path); /* Get a segment */
+ if (res != FR_OK) break;
+ res = dir_find(dj); /* Find it */
+ ns = *(dj->fn+NS);
+ if (res != FR_OK) { /* Failed to find the object */
+ if (res != FR_NO_FILE) break; /* Abort if any hard error occured */
+ /* Object not found */
+ if (_FS_RPATH && (ns & NS_DOT)) { /* If dot entry is not exit */
+ dj->sclust = 0; dj->dir = 0; /* It is the root dir */
+ res = FR_OK;
+ if (!(ns & NS_LAST)) continue;
+ } else { /* Could not find the object */
+ if (!(ns & NS_LAST)) res = FR_NO_PATH;
+ }
+ break;
+ }
+ if (ns & NS_LAST) break; /* Last segment match. Function completed. */
+ dir = dj->dir; /* 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 = LD_CLUST(dir);
+ }
+ }
+
+ return res;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Load boot record and check if it is an FAT boot record */
+/*-----------------------------------------------------------------------*/
+
+static
+BYTE check_fs ( /* 0:The FAT BR, 1:Valid BR but not an FAT, 2:Not a BR, 3:Disk error */
+ FATFS *fs, /* File system object */
+ DWORD sect /* Sector# (lba) to check if it is an FAT boot record or not */
+)
+{
+ if (disk_read(fs->drv, fs->win, sect, 1) != RES_OK) /* Load boot record */
+ return 3;
+ if (LD_WORD(&fs->win[BS_55AA]) != 0xAA55) /* Check record signature (always placed at offset 510 even if the sector size is >512) */
+ return 2;
+
+ if ((LD_DWORD(&fs->win[BS_FilSysType]) & 0xFFFFFF) == 0x544146) /* Check "FAT" string */
+ return 0;
+ if ((LD_DWORD(&fs->win[BS_FilSysType32]) & 0xFFFFFF) == 0x544146)
+ return 0;
+
+ return 1;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Check if the file system object is valid or not */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT chk_mounted ( /* FR_OK(0): successful, !=0: any error occurred */
+ const TCHAR **path, /* Pointer to pointer to the path name (drive number) */
+ FATFS **rfs, /* Pointer to pointer to the found file system object */
+ BYTE chk_wp /* !=0: Check media write protection for write access */
+)
+{
+ BYTE fmt, b, *tbl;
+ UINT vol;
+ DSTATUS stat;
+ DWORD bsect, fasize, tsect, sysect, nclst, szbfat;
+ WORD nrsv;
+ const TCHAR *p = *path;
+ FATFS *fs;
+
+ /* Get logical drive number from the path name */
+ vol = p[0] - '0'; /* Is there a drive number? */
+ if (vol <= 9 && p[1] == ':') { /* Found a drive number, get and strip it */
+ p += 2; *path = p; /* Return pointer to the path name */
+ } else { /* No drive number is given */
+#if _FS_RPATH
+ vol = CurrVol; /* Use current drive */
+#else
+ vol = 0; /* Use drive 0 */
+#endif
+ }
+
+ /* Check if the logical drive is valid or not */
+ if (vol >= _VOLUMES) /* Is the drive number valid? */
+ return FR_INVALID_DRIVE;
+ *rfs = fs = FatFs[vol]; /* Return pointer to the corresponding file system object */
+ if (!fs) return FR_NOT_ENABLED; /* Is the file system object available? */
+
+ ENTER_FF(fs); /* Lock file system */
+
+ if (fs->fs_type) { /* If the logical drive has been mounted */
+ stat = disk_status(fs->drv);
+ if (!(stat & STA_NOINIT)) { /* and the physical drive is kept initialized (has not been changed), */
+#if !_FS_READONLY
+ if (chk_wp && (stat & STA_PROTECT)) /* Check write protection if needed */
+ return FR_WRITE_PROTECTED;
+#endif
+ return FR_OK; /* The file system object is valid */
+ }
+ }
+
+ /* The logical drive must be mounted. */
+ /* Following code attempts to mount a volume. (analyze BPB and initialize the fs object) */
+
+ fs->fs_type = 0; /* Clear the file system object */
+ fs->drv = (BYTE)LD2PD(vol); /* Bind the logical drive and a physical drive */
+ stat = disk_initialize(fs->drv); /* Initialize low level disk I/O layer */
+ if (stat & STA_NOINIT) /* Check if the initialization succeeded */
+ return FR_NOT_READY; /* Failed to initialize due to no media or hard error */
+#if _MAX_SS != 512 /* Get disk sector size (variable sector size cfg only) */
+ if (disk_ioctl(fs->drv, GET_SECTOR_SIZE, &fs->ssize) != RES_OK)
+ return FR_DISK_ERR;
+#endif
+#if !_FS_READONLY
+ if (chk_wp && (stat & STA_PROTECT)) /* Check disk write protection if needed */
+ return FR_WRITE_PROTECTED;
+#endif
+ /* Search FAT partition on the drive. Supports only generic partitionings, FDISK and SFD. */
+ fmt = check_fs(fs, bsect = 0); /* Check sector 0 if it is a VBR */
+ if (fmt == 1) { /* Not an FAT-VBR, the disk may be partitioned */
+ /* Check the partition listed in top of the partition table */
+ tbl = &fs->win[MBR_Table + LD2PT(vol) * SZ_PTE];/* Partition table */
+ if (tbl[4]) { /* Is the partition existing? */
+ bsect = LD_DWORD(&tbl[8]); /* Partition offset in LBA */
+ fmt = check_fs(fs, bsect); /* Check the partition */
+ }
+ }
+ if (fmt == 3) return FR_DISK_ERR;
+ if (fmt) return FR_NO_FILESYSTEM; /* No FAT volume is found */
+
+ /* Following code initializes the file system object */
+
+ if (LD_WORD(fs->win+BPB_BytsPerSec) != SS(fs)) /* (BPB_BytsPerSec must be equal to the physical sector size) */
+ return FR_NO_FILESYSTEM;
+
+ fasize = LD_WORD(fs->win+BPB_FATSz16); /* Number of sectors per FAT */
+ if (!fasize) fasize = LD_DWORD(fs->win+BPB_FATSz32);
+ fs->fsize = fasize;
+
+ fs->n_fats = b = fs->win[BPB_NumFATs]; /* Number of FAT copies */
+ if (b != 1 && b != 2) return FR_NO_FILESYSTEM; /* (Must be 1 or 2) */
+ fasize *= b; /* Number of sectors for FAT area */
+
+ fs->csize = b = fs->win[BPB_SecPerClus]; /* Number of sectors per cluster */
+ if (!b || (b & (b - 1))) return FR_NO_FILESYSTEM; /* (Must be power of 2) */
+
+ fs->n_rootdir = LD_WORD(fs->win+BPB_RootEntCnt); /* Number of root directory entries */
+ if (fs->n_rootdir % (SS(fs) / SZ_DIR)) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be sector aligned) */
+
+ tsect = LD_WORD(fs->win+BPB_TotSec16); /* Number of sectors on the volume */
+ if (!tsect) tsect = LD_DWORD(fs->win+BPB_TotSec32);
+
+ nrsv = LD_WORD(fs->win+BPB_RsvdSecCnt); /* Number of reserved sectors */
+ if (!nrsv) return FR_NO_FILESYSTEM; /* (BPB_RsvdSecCnt must not be 0) */
+
+ /* Determine the FAT sub type */
+ sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZ_DIR); /* RSV+FAT+DIR */
+ if (tsect < sysect) return FR_NO_FILESYSTEM; /* (Invalid volume size) */
+ nclst = (tsect - sysect) / fs->csize; /* Number of clusters */
+ if (!nclst) return FR_NO_FILESYSTEM; /* (Invalid volume size) */
+ fmt = FS_FAT12;
+ if (nclst >= MIN_FAT16) fmt = FS_FAT16;
+ if (nclst >= MIN_FAT32) fmt = FS_FAT32;
+
+ /* Boundaries and Limits */
+ fs->n_fatent = nclst + 2; /* Number of FAT entries */
+ fs->database = bsect + sysect; /* Data start sector */
+ fs->fatbase = bsect + nrsv; /* FAT start sector */
+ if (fmt == FS_FAT32) {
+ if (fs->n_rootdir) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */
+ fs->dirbase = LD_DWORD(fs->win+BPB_RootClus); /* Root directory start cluster */
+ szbfat = fs->n_fatent * 4; /* (Required FAT size) */
+ } else {
+ if (!fs->n_rootdir) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must not be 0) */
+ fs->dirbase = fs->fatbase + fasize; /* Root directory start sector */
+ szbfat = (fmt == FS_FAT16) ? /* (Required FAT size) */
+ fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1);
+ }
+ if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) /* (BPB_FATSz must not be less than required) */
+ return FR_NO_FILESYSTEM;
+
+#if !_FS_READONLY
+ /* Initialize cluster allocation information */
+ fs->free_clust = 0xFFFFFFFF;
+ fs->last_clust = 0;
+
+ /* Get fsinfo if available */
+ if (fmt == FS_FAT32) {
+ fs->fsi_flag = 0;
+ fs->fsi_sector = bsect + LD_WORD(fs->win+BPB_FSInfo);
+ if (disk_read(fs->drv, fs->win, fs->fsi_sector, 1) == RES_OK &&
+ LD_WORD(fs->win+BS_55AA) == 0xAA55 &&
+ LD_DWORD(fs->win+FSI_LeadSig) == 0x41615252 &&
+ LD_DWORD(fs->win+FSI_StrucSig) == 0x61417272) {
+ fs->last_clust = LD_DWORD(fs->win+FSI_Nxt_Free);
+ fs->free_clust = LD_DWORD(fs->win+FSI_Free_Count);
+ }
+ }
+#endif
+ fs->fs_type = fmt; /* FAT sub-type */
+ fs->id = ++Fsid; /* File system mount ID */
+ fs->winsect = 0; /* Invalidate sector cache */
+ fs->wflag = 0;
+#if _FS_RPATH
+ fs->cdir = 0; /* Current directory (root dir) */
+#endif
+#if _FS_SHARE /* Clear file lock semaphores */
+ clear_lock(fs);
+#endif
+
+ return FR_OK;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Check if the file/dir object is valid or not */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT validate ( /* FR_OK(0): The object is valid, !=0: Invalid */
+ FATFS *fs, /* Pointer to the file system object */
+ WORD id /* Member id of the target object to be checked */
+)
+{
+ if (!fs || !fs->fs_type || fs->id != id)
+ return FR_INVALID_OBJECT;
+
+ ENTER_FF(fs); /* Lock file system */
+
+ if (disk_status(fs->drv) & STA_NOINIT)
+ return FR_NOT_READY;
+
+ return FR_OK;
+}
+
+
+
+
+/*--------------------------------------------------------------------------
+
+ Public Functions
+
+--------------------------------------------------------------------------*/
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Mount/Unmount a Logical Drive */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_mount (
+ BYTE vol, /* Logical drive number to be mounted/unmounted */
+ FATFS *fs /* Pointer to new file system object (NULL for unmount)*/
+)
+{
+ FATFS *rfs;
+
+
+ if (vol >= _VOLUMES) /* Check if the drive number is valid */
+ return FR_INVALID_DRIVE;
+ rfs = FatFs[vol]; /* Get current fs object */
+
+ if (rfs) {
+#if _FS_SHARE
+ clear_lock(rfs);
+#endif
+#if _FS_REENTRANT /* Discard sync object of the current volume */
+ if (!ff_del_syncobj(rfs->sobj)) return FR_INT_ERR;
+#endif
+ rfs->fs_type = 0; /* Clear old fs object */
+ }
+
+ if (fs) {
+ fs->fs_type = 0; /* Clear new fs object */
+#if _FS_REENTRANT /* Create sync object for the new volume */
+ if (!ff_cre_syncobj(vol, &fs->sobj)) return FR_INT_ERR;
+#endif
+ }
+ FatFs[vol] = fs; /* Register new fs object */
+
+ return FR_OK;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Open or Create a File */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_open (
+ FIL_t *fp, /* Pointer to the blank file object */
+ const TCHAR *path, /* Pointer to the file name */
+ BYTE mode /* Access mode and file open mode flags */
+)
+{
+ FRESULT res;
+ DIR_t dj;
+ BYTE *dir;
+ DEF_NAMEBUF;
+
+
+ fp->fs = 0; /* Clear file object */
+
+#if !_FS_READONLY
+ mode &= FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW;
+ res = chk_mounted(&path, &dj.fs, (BYTE)(mode & ~FA_READ));
+#else
+ mode &= FA_READ;
+ res = chk_mounted(&path, &dj.fs, 0);
+#endif
+ INIT_BUF(dj);
+ if (res == FR_OK)
+ res = follow_path(&dj, path); /* Follow the file path */
+ dir = dj.dir;
+
+#if !_FS_READONLY /* R/W configuration */
+ if (res == FR_OK) {
+ if (!dir) /* Current dir itself */
+ res = FR_INVALID_NAME;
+#if _FS_SHARE
+ else
+ res = chk_lock(&dj, (mode & ~FA_READ) ? 1 : 0);
+#endif
+ }
+ /* Create or Open a file */
+ if (mode & (FA_CREATE_ALWAYS|FA_OPEN_ALWAYS|FA_CREATE_NEW)) {
+ DWORD dw, cl;
+
+ if (res != FR_OK) { /* No file, create new */
+ if (res == FR_NO_FILE) /* There is no file to open, create a new entry */
+#if _FS_SHARE
+ res = enq_lock(dj.fs) ? dir_register(&dj) : FR_TOO_MANY_OPEN_FILES;
+#else
+ res = dir_register(&dj);
+#endif
+ mode |= FA_CREATE_ALWAYS; /* File is created */
+ dir = dj.dir; /* New entry */
+ }
+ else { /* Any object is already existing */
+ if (dir[DIR_Attr] & (AM_RDO | AM_DIR)) { /* Cannot overwrite it (R/O or DIR) */
+ res = FR_DENIED;
+ } else {
+ if (mode & FA_CREATE_NEW) /* Cannot create as new file */
+ res = FR_EXIST;
+ }
+ }
+ if (res == FR_OK && (mode & FA_CREATE_ALWAYS)) { /* Truncate it if overwrite mode */
+ dw = get_fattime(); /* Created time */
+ ST_DWORD(dir+DIR_CrtTime, dw);
+ dir[DIR_Attr] = 0; /* Reset attribute */
+ ST_DWORD(dir+DIR_FileSize, 0); /* size = 0 */
+ cl = LD_CLUST(dir); /* Get start cluster */
+ ST_CLUST(dir, 0); /* cluster = 0 */
+ dj.fs->wflag = 1;
+ if (cl) { /* Remove the cluster chain if exist */
+ dw = dj.fs->winsect;
+ res = remove_chain(dj.fs, cl);
+ if (res == FR_OK) {
+ dj.fs->last_clust = cl - 1; /* Reuse the cluster hole */
+ res = move_window(dj.fs, dw);
+ }
+ }
+ }
+ }
+ else { /* Open an existing file */
+ if (res == FR_OK) { /* Follow succeeded */
+ if (dir[DIR_Attr] & AM_DIR) { /* It is a directory */
+ res = FR_NO_FILE;
+ } else {
+ if ((mode & FA_WRITE) && (dir[DIR_Attr] & AM_RDO)) /* R/O violation */
+ res = FR_DENIED;
+ }
+ }
+ }
+ if (res == FR_OK) {
+ if (mode & FA_CREATE_ALWAYS) /* Set file change flag if created or overwritten */
+ mode |= FA__WRITTEN;
+ fp->dir_sect = dj.fs->winsect; /* Pointer to the directory entry */
+ fp->dir_ptr = dir;
+#if _FS_SHARE
+ fp->lockid = inc_lock(&dj, (mode & ~FA_READ) ? 1 : 0);
+ if (!fp->lockid) res = FR_INT_ERR;
+#endif
+ }
+
+#else /* R/O configuration */
+ if (res == FR_OK) { /* Follow succeeded */
+ if (!dir) { /* Current dir itself */
+ res = FR_INVALID_NAME;
+ } else {
+ if (dir[DIR_Attr] & AM_DIR) /* It is a directory */
+ res = FR_NO_FILE;
+ }
+ }
+#endif
+ FREE_BUF();
+
+ if (res == FR_OK) {
+ fp->flag = mode; /* File access mode */
+ fp->sclust = LD_CLUST(dir); /* File start cluster */
+ fp->fsize = LD_DWORD(dir+DIR_FileSize); /* File size */
+ fp->fptr = 0; /* File pointer */
+ fp->dsect = 0;
+#if _USE_FASTSEEK
+ fp->cltbl = 0; /* Normal seek mode */
+#endif
+ fp->fs = dj.fs; fp->id = dj.fs->id; /* Validate file object */
+ }
+
+ LEAVE_FF(dj.fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Read File */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_read (
+ FIL_t *fp, /* Pointer to the file object */
+ void *buff, /* Pointer to data buffer */
+ UINT btr, /* Number of bytes to read */
+ UINT *br /* Pointer to number of bytes read */
+)
+{
+ FRESULT res;
+ DWORD clst, sect, remain;
+ UINT rcnt, cc;
+ BYTE csect, *rbuff = (BYTE*)buff;
+
+
+ *br = 0; /* Initialize byte counter */
+
+ res = validate(fp->fs, fp->id); /* Check validity */
+ if (res != FR_OK) LEAVE_FF(fp->fs, res);
+ if (fp->flag & FA__ERROR) /* Aborted file? */
+ LEAVE_FF(fp->fs, FR_INT_ERR);
+ if (!(fp->flag & FA_READ)) /* Check access mode */
+ LEAVE_FF(fp->fs, FR_DENIED);
+ remain = fp->fsize - fp->fptr;
+ if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */
+
+ for ( ; btr; /* Repeat until all data read */
+ rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) {
+ if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */
+ csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */
+ if (!csect) { /* On the cluster boundary? */
+ if (fp->fptr == 0) { /* On the top of the file? */
+ clst = fp->sclust; /* Follow from the origin */
+ } else { /* Middle or end of the file */
+#if _USE_FASTSEEK
+ if (fp->cltbl)
+ clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */
+ else
+#endif
+ clst = get_fat(fp->fs, fp->clust); /* Follow cluster chain on the FAT */
+ }
+ if (clst < 2) ABORT(fp->fs, FR_INT_ERR);
+ if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
+ fp->clust = clst; /* Update current cluster */
+ }
+ sect = clust2sect(fp->fs, fp->clust); /* Get current sector */
+ if (!sect) ABORT(fp->fs, FR_INT_ERR);
+ sect += csect;
+ cc = btr / SS(fp->fs); /* When remaining bytes >= sector size, */
+ if (cc) { /* Read maximum contiguous sectors directly */
+ if (csect + cc > fp->fs->csize) /* Clip at cluster boundary */
+ cc = fp->fs->csize - csect;
+ if (disk_read(fp->fs->drv, rbuff, sect, (BYTE)cc) != RES_OK)
+ ABORT(fp->fs, FR_DISK_ERR);
+#if !_FS_READONLY && _FS_MINIMIZE <= 2 /* Replace one of the read sectors with cached data if it contains a dirty sector */
+#if _FS_TINY
+ if (fp->fs->wflag && fp->fs->winsect - sect < cc)
+ mem_cpy(rbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), fp->fs->win, SS(fp->fs));
+#else
+ if ((fp->flag & FA__DIRTY) && fp->dsect - sect < cc)
+ mem_cpy(rbuff + ((fp->dsect - sect) * SS(fp->fs)), fp->buf, SS(fp->fs));
+#endif
+#endif
+ rcnt = SS(fp->fs) * cc; /* Number of bytes transferred */
+ continue;
+ }
+#if !_FS_TINY
+ if (fp->dsect != sect) { /* Load data sector if not in cache */
+#if !_FS_READONLY
+ if (fp->flag & FA__DIRTY) { /* Write-back dirty sector cache */
+ if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
+ ABORT(fp->fs, FR_DISK_ERR);
+ fp->flag &= ~FA__DIRTY;
+ }
+#endif
+ if (disk_read(fp->fs->drv, fp->buf, sect, 1) != RES_OK) /* Fill sector cache */
+ ABORT(fp->fs, FR_DISK_ERR);
+ }
+#endif
+ fp->dsect = sect;
+ }
+ rcnt = SS(fp->fs) - (fp->fptr % SS(fp->fs)); /* Get partial sector data from sector buffer */
+ if (rcnt > btr) rcnt = btr;
+#if _FS_TINY
+ if (move_window(fp->fs, fp->dsect)) /* Move sector window */
+ ABORT(fp->fs, FR_DISK_ERR);
+ mem_cpy(rbuff, &fp->fs->win[fp->fptr % SS(fp->fs)], rcnt); /* Pick partial sector */
+#else
+ mem_cpy(rbuff, &fp->buf[fp->fptr % SS(fp->fs)], rcnt); /* Pick partial sector */
+#endif
+ }
+
+ LEAVE_FF(fp->fs, FR_OK);
+}
+
+
+
+
+#if !_FS_READONLY
+/*-----------------------------------------------------------------------*/
+/* Write File */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_write (
+ FIL_t *fp, /* Pointer to the file object */
+ const void *buff, /* Pointer to the data to be written */
+ UINT btw, /* Number of bytes to write */
+ UINT *bw /* Pointer to number of bytes written */
+)
+{
+ FRESULT res;
+ DWORD clst, sect;
+ UINT wcnt, cc;
+ const BYTE *wbuff = (BYTE*)buff;
+ BYTE csect;
+
+
+ *bw = 0; /* Initialize byte counter */
+
+ res = validate(fp->fs, fp->id); /* Check validity */
+ if (res != FR_OK) LEAVE_FF(fp->fs, res);
+ if (fp->flag & FA__ERROR) /* Aborted file? */
+ LEAVE_FF(fp->fs, FR_INT_ERR);
+ if (!(fp->flag & FA_WRITE)) /* Check access mode */
+ LEAVE_FF(fp->fs, FR_DENIED);
+ if ((DWORD)(fp->fsize + btw) < fp->fsize) btw = 0; /* File size cannot reach 4GB */
+
+ for ( ; btw; /* Repeat until all data written */
+ wbuff += wcnt, fp->fptr += wcnt, *bw += wcnt, btw -= wcnt) {
+ if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */
+ csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */
+ if (!csect) { /* On the cluster boundary? */
+ if (fp->fptr == 0) { /* On the top of the file? */
+ clst = fp->sclust; /* Follow from the origin */
+ if (clst == 0) /* When no cluster is allocated, */
+ fp->sclust = clst = create_chain(fp->fs, 0); /* Create a new cluster chain */
+ } else { /* Middle or end of the file */
+#if _USE_FASTSEEK
+ if (fp->cltbl)
+ clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */
+ else
+#endif
+ clst = create_chain(fp->fs, fp->clust); /* Follow or stretch cluster chain on the FAT */
+ }
+ if (clst == 0) break; /* Could not allocate a new cluster (disk full) */
+ if (clst == 1) ABORT(fp->fs, FR_INT_ERR);
+ if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
+ fp->clust = clst; /* Update current cluster */
+ }
+#if _FS_TINY
+ if (fp->fs->winsect == fp->dsect && move_window(fp->fs, 0)) /* Write-back sector cache */
+ ABORT(fp->fs, FR_DISK_ERR);
+#else
+ if (fp->flag & FA__DIRTY) { /* Write-back sector cache */
+ if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
+ ABORT(fp->fs, FR_DISK_ERR);
+ fp->flag &= ~FA__DIRTY;
+ }
+#endif
+ sect = clust2sect(fp->fs, fp->clust); /* Get current sector */
+ if (!sect) ABORT(fp->fs, FR_INT_ERR);
+ sect += csect;
+ cc = btw / SS(fp->fs); /* When remaining bytes >= sector size, */
+ if (cc) { /* Write maximum contiguous sectors directly */
+ if (csect + cc > fp->fs->csize) /* Clip at cluster boundary */
+ cc = fp->fs->csize - csect;
+ if (disk_write(fp->fs->drv, wbuff, sect, (BYTE)cc) != RES_OK)
+ ABORT(fp->fs, FR_DISK_ERR);
+#if _FS_TINY
+ if (fp->fs->winsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */
+ mem_cpy(fp->fs->win, wbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), SS(fp->fs));
+ fp->fs->wflag = 0;
+ }
+#else
+ if (fp->dsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */
+ mem_cpy(fp->buf, wbuff + ((fp->dsect - sect) * SS(fp->fs)), SS(fp->fs));
+ fp->flag &= ~FA__DIRTY;
+ }
+#endif
+ wcnt = SS(fp->fs) * cc; /* Number of bytes transferred */
+ continue;
+ }
+#if _FS_TINY
+ if (fp->fptr >= fp->fsize) { /* Avoid silly cache filling at growing edge */
+ if (move_window(fp->fs, 0)) ABORT(fp->fs, FR_DISK_ERR);
+ fp->fs->winsect = sect;
+ }
+#else
+ if (fp->dsect != sect) { /* Fill sector cache with file data */
+ if (fp->fptr < fp->fsize &&
+ disk_read(fp->fs->drv, fp->buf, sect, 1) != RES_OK)
+ ABORT(fp->fs, FR_DISK_ERR);
+ }
+#endif
+ fp->dsect = sect;
+ }
+ wcnt = SS(fp->fs) - (fp->fptr % SS(fp->fs)); /* Put partial sector into file I/O buffer */
+ if (wcnt > btw) wcnt = btw;
+#if _FS_TINY
+ if (move_window(fp->fs, fp->dsect)) /* Move sector window */
+ ABORT(fp->fs, FR_DISK_ERR);
+ mem_cpy(&fp->fs->win[fp->fptr % SS(fp->fs)], wbuff, wcnt); /* Fit partial sector */
+ fp->fs->wflag = 1;
+#else
+ mem_cpy(&fp->buf[fp->fptr % SS(fp->fs)], wbuff, wcnt); /* Fit partial sector */
+ fp->flag |= FA__DIRTY;
+#endif
+ }
+
+ if (fp->fptr > fp->fsize) fp->fsize = fp->fptr; /* Update file size if needed */
+ fp->flag |= FA__WRITTEN; /* Set file change flag */
+
+ LEAVE_FF(fp->fs, FR_OK);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Synchronize the File Object */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_sync (
+ FIL_t *fp /* Pointer to the file object */
+)
+{
+ FRESULT res;
+ DWORD tim;
+ BYTE *dir;
+
+
+ res = validate(fp->fs, fp->id); /* Check validity of the object */
+ if (res == FR_OK) {
+ if (fp->flag & FA__WRITTEN) { /* Has the file been written? */
+#if !_FS_TINY /* Write-back dirty buffer */
+ if (fp->flag & FA__DIRTY) {
+ if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
+ LEAVE_FF(fp->fs, FR_DISK_ERR);
+ fp->flag &= ~FA__DIRTY;
+ }
+#endif
+ /* Update the directory entry */
+ res = move_window(fp->fs, fp->dir_sect);
+ if (res == FR_OK) {
+ dir = fp->dir_ptr;
+ dir[DIR_Attr] |= AM_ARC; /* Set archive bit */
+ ST_DWORD(dir+DIR_FileSize, fp->fsize); /* Update file size */
+ ST_CLUST(dir, fp->sclust); /* Update start cluster */
+ tim = get_fattime(); /* Update updated time */
+ ST_DWORD(dir+DIR_WrtTime, tim);
+ fp->flag &= ~FA__WRITTEN;
+ fp->fs->wflag = 1;
+ res = sync(fp->fs);
+ }
+ }
+ }
+
+ LEAVE_FF(fp->fs, res);
+}
+
+#endif /* !_FS_READONLY */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Close File */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_close (
+ FIL_t *fp /* Pointer to the file object to be closed */
+)
+{
+ FRESULT res;
+
+#if _FS_READONLY
+ FATFS *fs = fp->fs;
+ res = validate(fs, fp->id);
+ if (res == FR_OK) fp->fs = 0; /* Discard file object */
+ LEAVE_FF(fs, res);
+
+#else
+ res = f_sync(fp); /* Flush cached data */
+#if _FS_SHARE
+ if (res == FR_OK) { /* Decrement open counter */
+#if _FS_REENTRANT
+ res = validate(fp->fs, fp->id);
+ if (res == FR_OK) {
+ res = dec_lock(fp->lockid);
+ unlock_fs(fp->fs, FR_OK);
+ }
+#else
+ res = dec_lock(fp->lockid);
+#endif
+ }
+#endif
+ if (res == FR_OK) fp->fs = 0; /* Discard file object */
+ return res;
+#endif
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Current Drive/Directory Handlings */
+/*-----------------------------------------------------------------------*/
+
+#if _FS_RPATH >= 1
+
+FRESULT f_chdrive (
+ BYTE drv /* Drive number */
+)
+{
+ if (drv >= _VOLUMES) return FR_INVALID_DRIVE;
+
+ CurrVol = drv;
+
+ return FR_OK;
+}
+
+
+
+FRESULT f_chdir (
+ const TCHAR *path /* Pointer to the directory path */
+)
+{
+ FRESULT res;
+ DIR_t dj;
+ DEF_NAMEBUF;
+
+
+ res = chk_mounted(&path, &dj.fs, 0);
+ if (res == FR_OK) {
+ INIT_BUF(dj);
+ res = follow_path(&dj, path); /* Follow the path */
+ FREE_BUF();
+ if (res == FR_OK) { /* Follow completed */
+ if (!dj.dir) {
+ dj.fs->cdir = dj.sclust; /* Start directory itself */
+ } else {
+ if (dj.dir[DIR_Attr] & AM_DIR) /* Reached to the directory */
+ dj.fs->cdir = LD_CLUST(dj.dir);
+ else
+ res = FR_NO_PATH; /* Reached but a file */
+ }
+ }
+ if (res == FR_NO_FILE) res = FR_NO_PATH;
+ }
+
+ LEAVE_FF(dj.fs, res);
+}
+
+
+#if _FS_RPATH >= 2
+FRESULT f_getcwd (
+ TCHAR *path, /* Pointer to the directory path */
+ UINT sz_path /* Size of path */
+)
+{
+ FRESULT res;
+ DIR_t dj;
+ UINT i, n;
+ DWORD ccl;
+ TCHAR *tp;
+ FILINFO fno;
+ DEF_NAMEBUF;
+
+
+ *path = 0;
+ res = chk_mounted((const TCHAR**)&path, &dj.fs, 0); /* Get current volume */
+ if (res == FR_OK) {
+ INIT_BUF(dj);
+ i = sz_path; /* Bottom of buffer (dir stack base) */
+ dj.sclust = dj.fs->cdir; /* Start to follow upper dir from current dir */
+ while ((ccl = dj.sclust) != 0) { /* Repeat while current dir is a sub-dir */
+ res = dir_sdi(&dj, 1); /* Get parent dir */
+ if (res != FR_OK) break;
+ res = dir_read(&dj);
+ if (res != FR_OK) break;
+ dj.sclust = LD_CLUST(dj.dir); /* Goto parent dir */
+ res = dir_sdi(&dj, 0);
+ if (res != FR_OK) break;
+ do { /* Find the entry links to the child dir */
+ res = dir_read(&dj);
+ if (res != FR_OK) break;
+ if (ccl == LD_CLUST(dj.dir)) break; /* Found the entry */
+ res = dir_next(&dj, 0);
+ } while (res == FR_OK);
+ if (res == FR_NO_FILE) res = FR_INT_ERR;/* It cannot be 'not found'. */
+ if (res != FR_OK) break;
+#if _USE_LFN
+ fno.lfname = path;
+ fno.lfsize = i;
+#endif
+ get_fileinfo(&dj, &fno); /* Get the dir name and push it to the buffer */
+ tp = fno.fname;
+ if (_USE_LFN && *path) tp = path;
+ for (n = 0; tp[n]; n++) ;
+ if (i < n + 3) {
+ res = FR_NOT_ENOUGH_CORE; break;
+ }
+ while (n) path[--i] = tp[--n];
+ path[--i] = '/';
+ }
+ tp = path;
+ if (res == FR_OK) {
+ *tp++ = '0' + CurrVol; /* Put drive number */
+ *tp++ = ':';
+ if (i == sz_path) { /* Root-dir */
+ *tp++ = '/';
+ } else { /* Sub-dir */
+ do /* Add stacked path str */
+ *tp++ = path[i++];
+ while (i < sz_path);
+ }
+ }
+ *tp = 0;
+ FREE_BUF();
+ }
+
+ LEAVE_FF(dj.fs, res);
+}
+#endif /* _FS_RPATH >= 2 */
+#endif /* _FS_RPATH >= 1 */
+
+
+
+#if _FS_MINIMIZE <= 2
+/*-----------------------------------------------------------------------*/
+/* Seek File R/W Pointer */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_lseek (
+ FIL_t *fp, /* Pointer to the file object */
+ DWORD ofs /* File pointer from top of file */
+)
+{
+ FRESULT res;
+
+
+ res = validate(fp->fs, fp->id); /* Check validity of the object */
+ if (res != FR_OK) LEAVE_FF(fp->fs, res);
+ if (fp->flag & FA__ERROR) /* Check abort flag */
+ LEAVE_FF(fp->fs, FR_INT_ERR);
+
+#if _USE_FASTSEEK
+ if (fp->cltbl) { /* Fast seek */
+ DWORD cl, pcl, ncl, tcl, dsc, tlen, ulen, *tbl;
+
+ if (ofs == CREATE_LINKMAP) { /* Create CLMT */
+ tbl = fp->cltbl;
+ tlen = *tbl++; ulen = 2; /* Given table size and required table size */
+ cl = fp->sclust; /* Top of the chain */
+ if (cl) {
+ do {
+ /* Get a fragment */
+ tcl = cl; ncl = 0; ulen += 2; /* Top, length and used items */
+ do {
+ pcl = cl; ncl++;
+ cl = get_fat(fp->fs, cl);
+ if (cl <= 1) ABORT(fp->fs, FR_INT_ERR);
+ if (cl == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
+ } while (cl == pcl + 1);
+ if (ulen <= tlen) { /* Store the length and top of the fragment */
+ *tbl++ = ncl; *tbl++ = tcl;
+ }
+ } while (cl < fp->fs->n_fatent); /* Repeat until end of chain */
+ }
+ *fp->cltbl = ulen; /* Number of items used */
+ if (ulen <= tlen)
+ *tbl = 0; /* Terminate table */
+ else
+ res = FR_NOT_ENOUGH_CORE; /* Given table size is smaller than required */
+
+ } else { /* Fast seek */
+ if (ofs > fp->fsize) /* Clip offset at the file size */
+ ofs = fp->fsize;
+ fp->fptr = ofs; /* Set file pointer */
+ if (ofs) {
+ fp->clust = clmt_clust(fp, ofs - 1);
+ dsc = clust2sect(fp->fs, fp->clust);
+ if (!dsc) ABORT(fp->fs, FR_INT_ERR);
+ dsc += (ofs - 1) / SS(fp->fs) & (fp->fs->csize - 1);
+ if (fp->fptr % SS(fp->fs) && dsc != fp->dsect) { /* Refill sector cache if needed */
+#if !_FS_TINY
+#if !_FS_READONLY
+ if (fp->flag & FA__DIRTY) { /* Write-back dirty sector cache */
+ if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
+ ABORT(fp->fs, FR_DISK_ERR);
+ fp->flag &= ~FA__DIRTY;
+ }
+#endif
+ if (disk_read(fp->fs->drv, fp->buf, dsc, 1) != RES_OK) /* Load current sector */
+ ABORT(fp->fs, FR_DISK_ERR);
+#endif
+ fp->dsect = dsc;
+ }
+ }
+ }
+ } else
+#endif
+
+ /* Normal Seek */
+ {
+ DWORD clst, bcs, nsect, ifptr;
+
+ if (ofs > fp->fsize /* In read-only mode, clip offset with the file size */
+#if !_FS_READONLY
+ && !(fp->flag & FA_WRITE)
+#endif
+ ) ofs = fp->fsize;
+
+ ifptr = fp->fptr;
+ fp->fptr = nsect = 0;
+ if (ofs) {
+ bcs = (DWORD)fp->fs->csize * SS(fp->fs); /* Cluster size (byte) */
+ if (ifptr > 0 &&
+ (ofs - 1) / bcs >= (ifptr - 1) / bcs) { /* When seek to same or following cluster, */
+ fp->fptr = (ifptr - 1) & ~(bcs - 1); /* start from the current cluster */
+ ofs -= fp->fptr;
+ clst = fp->clust;
+ } else { /* When seek to back cluster, */
+ clst = fp->sclust; /* start from the first cluster */
+#if !_FS_READONLY
+ if (clst == 0) { /* If no cluster chain, create a new chain */
+ clst = create_chain(fp->fs, 0);
+ if (clst == 1) ABORT(fp->fs, FR_INT_ERR);
+ if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
+ fp->sclust = clst;
+ }
+#endif
+ fp->clust = clst;
+ }
+ if (clst != 0) {
+ while (ofs > bcs) { /* Cluster following loop */
+#if !_FS_READONLY
+ if (fp->flag & FA_WRITE) { /* Check if in write mode or not */
+ clst = create_chain(fp->fs, clst); /* Force stretch if in write mode */
+ if (clst == 0) { /* When disk gets full, clip file size */
+ ofs = bcs; break;
+ }
+ } else
+#endif
+ clst = get_fat(fp->fs, clst); /* Follow cluster chain if not in write mode */
+ if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
+ if (clst <= 1 || clst >= fp->fs->n_fatent) ABORT(fp->fs, FR_INT_ERR);
+ fp->clust = clst;
+ fp->fptr += bcs;
+ ofs -= bcs;
+ }
+ fp->fptr += ofs;
+ if (ofs % SS(fp->fs)) {
+ nsect = clust2sect(fp->fs, clst); /* Current sector */
+ if (!nsect) ABORT(fp->fs, FR_INT_ERR);
+ nsect += ofs / SS(fp->fs);
+ }
+ }
+ }
+ if (fp->fptr % SS(fp->fs) && nsect != fp->dsect) { /* Fill sector cache if needed */
+#if !_FS_TINY
+#if !_FS_READONLY
+ if (fp->flag & FA__DIRTY) { /* Write-back dirty sector cache */
+ if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
+ ABORT(fp->fs, FR_DISK_ERR);
+ fp->flag &= ~FA__DIRTY;
+ }
+#endif
+ if (disk_read(fp->fs->drv, fp->buf, nsect, 1) != RES_OK) /* Fill sector cache */
+ ABORT(fp->fs, FR_DISK_ERR);
+#endif
+ fp->dsect = nsect;
+ }
+#if !_FS_READONLY
+ if (fp->fptr > fp->fsize) { /* Set file change flag if the file size is extended */
+ fp->fsize = fp->fptr;
+ fp->flag |= FA__WRITTEN;
+ }
+#endif
+}
+
+ LEAVE_FF(fp->fs, res);
+}
+
+
+
+#if _FS_MINIMIZE <= 1
+/*-----------------------------------------------------------------------*/
+/* Create a Directroy Object */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_opendir (
+ DIR_t *dj, /* Pointer to directory object to create */
+ const TCHAR *path /* Pointer to the directory path */
+)
+{
+ FRESULT res;
+ DEF_NAMEBUF;
+
+
+ res = chk_mounted(&path, &dj->fs, 0);
+ if (res == FR_OK) {
+ INIT_BUF(*dj);
+ res = follow_path(dj, path); /* Follow the path to the directory */
+ FREE_BUF();
+ if (res == FR_OK) { /* Follow completed */
+ if (dj->dir) { /* It is not the root dir */
+ if (dj->dir[DIR_Attr] & AM_DIR) { /* The object is a directory */
+ dj->sclust = LD_CLUST(dj->dir);
+ } else { /* The object is not a directory */
+ res = FR_NO_PATH;
+ }
+ }
+ if (res == FR_OK) {
+ dj->id = dj->fs->id;
+ res = dir_sdi(dj, 0); /* Rewind dir */
+ }
+ }
+ if (res == FR_NO_FILE) res = FR_NO_PATH;
+ }
+
+ LEAVE_FF(dj->fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Read Directory Entry in Sequense */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_readdir (
+ DIR_t *dj, /* Pointer to the open directory object */
+ FILINFO *fno /* Pointer to file information to return */
+)
+{
+ FRESULT res;
+ DEF_NAMEBUF;
+
+ res = validate(dj->fs, dj->id); /* Check validity of the object */
+ if (res == FR_OK) {
+ if (!fno) {
+ res = dir_sdi(dj, 0); /* Rewind the directory object */
+ } else {
+ INIT_BUF(*dj);
+ res = dir_read(dj); /* Read an directory item */
+ if (res == FR_NO_FILE) { /* Reached end of dir */
+ 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, 0); /* Increment index for next */
+ if (res == FR_NO_FILE) {
+ dj->sect = 0;
+ res = FR_OK;
+ }
+ }
+ FREE_BUF();
+ }
+ }
+
+ LEAVE_FF(dj->fs, res);
+}
+
+
+
+#if _FS_MINIMIZE == 0
+/*-----------------------------------------------------------------------*/
+/* Get File Status */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_stat (
+ const TCHAR *path, /* Pointer to the file path */
+ FILINFO *fno /* Pointer to file information to return */
+)
+{
+ FRESULT res;
+ DIR_t dj;
+ DEF_NAMEBUF;
+
+
+ res = chk_mounted(&path, &dj.fs, 0);
+ if (res == FR_OK) {
+ INIT_BUF(dj);
+ res = follow_path(&dj, path); /* Follow the file path */
+ if (res == FR_OK) { /* Follow completed */
+ if (dj.dir) /* Found an object */
+ get_fileinfo(&dj, fno);
+ else /* It is root dir */
+ res = FR_INVALID_NAME;
+ }
+ FREE_BUF();
+ }
+
+ LEAVE_FF(dj.fs, res);
+}
+
+
+
+#if !_FS_READONLY
+/*-----------------------------------------------------------------------*/
+/* Get Number of Free Clusters */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_getfree (
+ const TCHAR *path, /* Pointer to the logical drive number (root dir) */
+ DWORD *nclst, /* Pointer to the variable to return number of free clusters */
+ FATFS **fatfs /* Pointer to pointer to corresponding file system object to return */
+)
+{
+ FRESULT res;
+ DWORD n, clst, sect, stat;
+ UINT i;
+ BYTE fat, *p;
+
+
+ /* Get drive number */
+ res = chk_mounted(&path, fatfs, 0);
+ if (res == FR_OK) {
+ /* If free_clust is valid, return it without full cluster scan */
+ if ((*fatfs)->free_clust <= (*fatfs)->n_fatent - 2) {
+ *nclst = (*fatfs)->free_clust;
+ } else {
+ /* Get number of free clusters */
+ fat = (*fatfs)->fs_type;
+ n = 0;
+ if (fat == FS_FAT12) {
+ clst = 2;
+ do {
+ stat = get_fat(*fatfs, clst);
+ if (stat == 0xFFFFFFFF) { res = FR_DISK_ERR; break; }
+ if (stat == 1) { res = FR_INT_ERR; break; }
+ if (stat == 0) n++;
+ } while (++clst < (*fatfs)->n_fatent);
+ } else {
+ clst = (*fatfs)->n_fatent;
+ sect = (*fatfs)->fatbase;
+ i = 0; p = 0;
+ do {
+ if (!i) {
+ res = move_window(*fatfs, sect++);
+ if (res != FR_OK) break;
+ p = (*fatfs)->win;
+ i = SS(*fatfs);
+ }
+ if (fat == FS_FAT16) {
+ if (LD_WORD(p) == 0) n++;
+ p += 2; i -= 2;
+ } else {
+ if ((LD_DWORD(p) & 0x0FFFFFFF) == 0) n++;
+ p += 4; i -= 4;
+ }
+ } while (--clst);
+ }
+ (*fatfs)->free_clust = n;
+ if (fat == FS_FAT32) (*fatfs)->fsi_flag = 1;
+ *nclst = n;
+ }
+ }
+ LEAVE_FF(*fatfs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Truncate File */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_truncate (
+ FIL_t *fp /* Pointer to the file object */
+)
+{
+ FRESULT res;
+ DWORD ncl;
+
+
+ res = validate(fp->fs, fp->id); /* Check validity of the object */
+ if (res == FR_OK) {
+ if (fp->flag & FA__ERROR) { /* Check abort flag */
+ res = FR_INT_ERR;
+ } else {
+ if (!(fp->flag & FA_WRITE)) /* Check access mode */
+ res = FR_DENIED;
+ }
+ }
+ if (res == FR_OK) {
+ if (fp->fsize > fp->fptr) {
+ fp->fsize = fp->fptr; /* Set file size to current R/W point */
+ fp->flag |= FA__WRITTEN;
+ if (fp->fptr == 0) { /* When set file size to zero, remove entire cluster chain */
+ res = remove_chain(fp->fs, fp->sclust);
+ fp->sclust = 0;
+ } else { /* When truncate a part of the file, remove remaining clusters */
+ ncl = get_fat(fp->fs, fp->clust);
+ res = FR_OK;
+ if (ncl == 0xFFFFFFFF) res = FR_DISK_ERR;
+ if (ncl == 1) res = FR_INT_ERR;
+ if (res == FR_OK && ncl < fp->fs->n_fatent) {
+ res = put_fat(fp->fs, fp->clust, 0x0FFFFFFF);
+ if (res == FR_OK) res = remove_chain(fp->fs, ncl);
+ }
+ }
+ }
+ if (res != FR_OK) fp->flag |= FA__ERROR;
+ }
+
+ LEAVE_FF(fp->fs, res);
+ }
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Delete a File or Directory */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_unlink (
+ const TCHAR *path /* Pointer to the file or directory path */
+)
+{
+ FRESULT res;
+ DIR_t dj, sdj;
+ BYTE *dir;
+ DWORD dclst;
+ DEF_NAMEBUF;
+
+
+ res = chk_mounted(&path, &dj.fs, 1);
+ if (res == FR_OK) {
+ INIT_BUF(dj);
+ res = follow_path(&dj, path); /* Follow the file path */
+ if (_FS_RPATH && res == FR_OK && (dj.fn[NS] & NS_DOT))
+ res = FR_INVALID_NAME; /* Cannot remove dot entry */
+#if _FS_SHARE
+ if (res == FR_OK) res = chk_lock(&dj, 2); /* Cannot remove open file */
+#endif
+ if (res == FR_OK) { /* The object is accessible */
+ dir = dj.dir;
+ if (!dir) {
+ res = FR_INVALID_NAME; /* Cannot remove the start directory */
+ } else {
+ if (dir[DIR_Attr] & AM_RDO)
+ res = FR_DENIED; /* Cannot remove R/O object */
+ }
+ dclst = LD_CLUST(dir);
+ if (res == FR_OK && (dir[DIR_Attr] & AM_DIR)) { /* Is it a sub-dir? */
+ if (dclst < 2) {
+ res = FR_INT_ERR;
+ } else {
+ mem_cpy(&sdj, &dj, sizeof(DIR_t)); /* Check if the sub-dir is empty or not */
+ sdj.sclust = dclst;
+ res = dir_sdi(&sdj, 2); /* Exclude dot entries */
+ if (res == FR_OK) {
+ res = dir_read(&sdj);
+ if (res == FR_OK /* Not empty dir */
+#if _FS_RPATH
+ || dclst == sdj.fs->cdir /* Current dir */
+#endif
+ ) res = FR_DENIED;
+ if (res == FR_NO_FILE) res = FR_OK; /* Empty */
+ }
+ }
+ }
+ if (res == FR_OK) {
+ res = dir_remove(&dj); /* Remove the directory entry */
+ if (res == FR_OK) {
+ if (dclst) /* Remove the cluster chain if exist */
+ res = remove_chain(dj.fs, dclst);
+ if (res == FR_OK) res = sync(dj.fs);
+ }
+ }
+ }
+ FREE_BUF();
+ }
+ LEAVE_FF(dj.fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Create a Directory */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_mkdir (
+ const TCHAR *path /* Pointer to the directory path */
+)
+{
+ FRESULT res;
+ DIR_t dj;
+ BYTE *dir, n;
+ DWORD dsc, dcl, pcl, tim = get_fattime();
+ DEF_NAMEBUF;
+
+
+ res = chk_mounted(&path, &dj.fs, 1);
+ if (res == FR_OK) {
+ INIT_BUF(dj);
+ res = follow_path(&dj, path); /* Follow the file path */
+ if (res == FR_OK) res = FR_EXIST; /* Any object with same name is already existing */
+ if (_FS_RPATH && res == FR_NO_FILE && (dj.fn[NS] & NS_DOT))
+ res = FR_INVALID_NAME;
+ if (res == FR_NO_FILE) { /* Can create a new directory */
+ dcl = create_chain(dj.fs, 0); /* Allocate a cluster for the new directory table */
+ res = FR_OK;
+ if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster */
+ if (dcl == 1) res = FR_INT_ERR;
+ if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR;
+ if (res == FR_OK) /* Flush FAT */
+ res = move_window(dj.fs, 0);
+ if (res == FR_OK) { /* Initialize the new directory table */
+ dsc = clust2sect(dj.fs, dcl);
+ dir = dj.fs->win;
+ mem_set(dir, 0, SS(dj.fs));
+ mem_set(dir+DIR_Name, ' ', 8+3); /* Create "." entry */
+ dir[DIR_Name] = '.';
+ dir[DIR_Attr] = AM_DIR;
+ ST_DWORD(dir+DIR_WrtTime, tim);
+ ST_CLUST(dir, dcl);
+ mem_cpy(dir+SZ_DIR, dir, SZ_DIR); /* Create ".." entry */
+ dir[33] = '.'; pcl = dj.sclust;
+ if (dj.fs->fs_type == FS_FAT32 && pcl == dj.fs->dirbase)
+ pcl = 0;
+ ST_CLUST(dir+SZ_DIR, pcl);
+ for (n = dj.fs->csize; n; n--) { /* Write dot entries and clear following sectors */
+ dj.fs->winsect = dsc++;
+ dj.fs->wflag = 1;
+ res = move_window(dj.fs, 0);
+ if (res != FR_OK) break;
+ mem_set(dir, 0, SS(dj.fs));
+ }
+ }
+ if (res == FR_OK) res = dir_register(&dj); /* Register the object to the directoy */
+ if (res != FR_OK) {
+ remove_chain(dj.fs, dcl); /* Could not register, remove cluster chain */
+ } else {
+ dir = dj.dir;
+ dir[DIR_Attr] = AM_DIR; /* Attribute */
+ ST_DWORD(dir+DIR_WrtTime, tim); /* Created time */
+ ST_CLUST(dir, dcl); /* Table start cluster */
+ dj.fs->wflag = 1;
+ res = sync(dj.fs);
+ }
+ }
+ FREE_BUF();
+ }
+
+ LEAVE_FF(dj.fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Change Attribute */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_chmod (
+ const TCHAR *path, /* Pointer to the file path */
+ BYTE value, /* Attribute bits */
+ BYTE mask /* Attribute mask to change */
+)
+{
+ FRESULT res;
+ DIR_t dj;
+ BYTE *dir;
+ DEF_NAMEBUF;
+
+
+ res = chk_mounted(&path, &dj.fs, 1);
+ if (res == FR_OK) {
+ INIT_BUF(dj);
+ res = follow_path(&dj, path); /* Follow the file path */
+ FREE_BUF();
+ if (_FS_RPATH && res == FR_OK && (dj.fn[NS] & NS_DOT))
+ res = FR_INVALID_NAME;
+ if (res == FR_OK) {
+ dir = dj.dir;
+ if (!dir) { /* Is it a root directory? */
+ res = FR_INVALID_NAME;
+ } else { /* File or sub directory */
+ mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC; /* Valid attribute mask */
+ dir[DIR_Attr] = (value & mask) | (dir[DIR_Attr] & (BYTE)~mask); /* Apply attribute change */
+ dj.fs->wflag = 1;
+ res = sync(dj.fs);
+ }
+ }
+ }
+
+ LEAVE_FF(dj.fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Change Timestamp */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_utime (
+ const TCHAR *path, /* Pointer to the file/directory name */
+ const FILINFO *fno /* Pointer to the time stamp to be set */
+)
+{
+ FRESULT res;
+ DIR_t dj;
+ BYTE *dir;
+ DEF_NAMEBUF;
+
+
+ res = chk_mounted(&path, &dj.fs, 1);
+ if (res == FR_OK) {
+ INIT_BUF(dj);
+ res = follow_path(&dj, path); /* Follow the file path */
+ FREE_BUF();
+ if (_FS_RPATH && res == FR_OK && (dj.fn[NS] & NS_DOT))
+ res = FR_INVALID_NAME;
+ if (res == FR_OK) {
+ dir = dj.dir;
+ if (!dir) { /* Root directory */
+ res = FR_INVALID_NAME;
+ } else { /* File or sub-directory */
+ ST_WORD(dir+DIR_WrtTime, fno->ftime);
+ ST_WORD(dir+DIR_WrtDate, fno->fdate);
+ dj.fs->wflag = 1;
+ res = sync(dj.fs);
+ }
+ }
+ }
+
+ LEAVE_FF(dj.fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Rename File/Directory */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_rename (
+ const TCHAR *path_old, /* Pointer to the old name */
+ const TCHAR *path_new /* Pointer to the new name */
+)
+{
+ FRESULT res;
+ DIR_t djo, djn;
+ BYTE buf[21], *dir;
+ DWORD dw;
+ DEF_NAMEBUF;
+
+
+ res = chk_mounted(&path_old, &djo.fs, 1);
+ if (res == FR_OK) {
+ djn.fs = djo.fs;
+ INIT_BUF(djo);
+ res = follow_path(&djo, path_old); /* Check old object */
+ if (_FS_RPATH && res == FR_OK && (djo.fn[NS] & NS_DOT))
+ res = FR_INVALID_NAME;
+#if _FS_SHARE
+ if (res == FR_OK) res = chk_lock(&djo, 2);
+#endif
+ if (res == FR_OK) { /* Old object is found */
+ if (!djo.dir) { /* Is root dir? */
+ res = FR_NO_FILE;
+ } else {
+ mem_cpy(buf, djo.dir+DIR_Attr, 21); /* Save the object information except for name */
+ mem_cpy(&djn, &djo, sizeof(DIR_t)); /* Check new object */
+ res = follow_path(&djn, path_new);
+ if (res == FR_OK) res = FR_EXIST; /* The new object name is already existing */
+ if (res == FR_NO_FILE) { /* Is it a valid path and no name collision? */
+/* Start critical section that any interruption or error can cause cross-link */
+ res = dir_register(&djn); /* Register the new entry */
+ if (res == FR_OK) {
+ dir = djn.dir; /* Copy object information except for name */
+ mem_cpy(dir+13, buf+2, 19);
+ dir[DIR_Attr] = buf[0] | AM_ARC;
+ djo.fs->wflag = 1;
+ if (djo.sclust != djn.sclust && (dir[DIR_Attr] & AM_DIR)) { /* Update .. entry in the directory if needed */
+ dw = clust2sect(djn.fs, LD_CLUST(dir));
+ if (!dw) {
+ res = FR_INT_ERR;
+ } else {
+ res = move_window(djn.fs, dw);
+ dir = djn.fs->win+SZ_DIR; /* .. entry */
+ if (res == FR_OK && dir[1] == '.') {
+ dw = (djn.fs->fs_type == FS_FAT32 && djn.sclust == djn.fs->dirbase) ? 0 : djn.sclust;
+ ST_CLUST(dir, dw);
+ djn.fs->wflag = 1;
+ }
+ }
+ }
+ if (res == FR_OK) {
+ res = dir_remove(&djo); /* Remove old entry */
+ if (res == FR_OK)
+ res = sync(djo.fs);
+ }
+ }
+/* End critical section */
+ }
+ }
+ }
+ FREE_BUF();
+ }
+ LEAVE_FF(djo.fs, res);
+}
+
+#endif /* !_FS_READONLY */
+#endif /* _FS_MINIMIZE == 0 */
+#endif /* _FS_MINIMIZE <= 1 */
+#endif /* _FS_MINIMIZE <= 2 */
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Forward data to the stream directly (available on only tiny cfg) */
+/*-----------------------------------------------------------------------*/
+#if _USE_FORWARD && _FS_TINY
+
+FRESULT f_forward (
+ FIL_t *fp, /* Pointer to the file object */
+ UINT (*func)(const BYTE*,UINT), /* Pointer to the streaming function */
+ UINT btr, /* Number of bytes to forward */
+ UINT *bf /* Pointer to number of bytes forwarded */
+)
+{
+ FRESULT res;
+ DWORD remain, clst, sect;
+ UINT rcnt;
+ BYTE csect;
+
+
+ *bf = 0; /* Initialize byte counter */
+
+ res = validate(fp->fs, fp->id); /* Check validity of the object */
+ if (res != FR_OK) LEAVE_FF(fp->fs, res);
+ if (fp->flag & FA__ERROR) /* Check error flag */
+ LEAVE_FF(fp->fs, FR_INT_ERR);
+ if (!(fp->flag & FA_READ)) /* Check access mode */
+ LEAVE_FF(fp->fs, FR_DENIED);
+
+ remain = fp->fsize - fp->fptr;
+ if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */
+
+ for ( ; btr && (*func)(0, 0); /* Repeat until all data transferred or stream becomes busy */
+ fp->fptr += rcnt, *bf += rcnt, btr -= rcnt) {
+ csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */
+ if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */
+ if (!csect) { /* On the cluster boundary? */
+ clst = (fp->fptr == 0) ? /* On the top of the file? */
+ fp->sclust : get_fat(fp->fs, fp->clust);
+ if (clst <= 1) ABORT(fp->fs, FR_INT_ERR);
+ if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
+ fp->clust = clst; /* Update current cluster */
+ }
+ }
+ sect = clust2sect(fp->fs, fp->clust); /* Get current data sector */
+ if (!sect) ABORT(fp->fs, FR_INT_ERR);
+ sect += csect;
+ if (move_window(fp->fs, sect)) /* Move sector window */
+ ABORT(fp->fs, FR_DISK_ERR);
+ fp->dsect = sect;
+ rcnt = SS(fp->fs) - (WORD)(fp->fptr % SS(fp->fs)); /* Forward data from sector window */
+ if (rcnt > btr) rcnt = btr;
+ rcnt = (*func)(&fp->fs->win[(WORD)fp->fptr % SS(fp->fs)], rcnt);
+ if (!rcnt) ABORT(fp->fs, FR_INT_ERR);
+}
+
+ LEAVE_FF(fp->fs, FR_OK);
+}
+#endif /* _USE_FORWARD */
+
+
+
+#if _USE_MKFS && !_FS_READONLY
+/*-----------------------------------------------------------------------*/
+/* Create File System on the Drive */
+/*-----------------------------------------------------------------------*/
+#define N_ROOTDIR 512 /* Number of root dir entries for FAT12/16 */
+#define N_FATS 1 /* Number of FAT copies (1 or 2) */
+
+
+FRESULT f_mkfs (
+ BYTE drv, /* Logical drive number */
+ BYTE sfd, /* Partitioning rule 0:FDISK, 1:SFD */
+ UINT au /* Allocation unit size [bytes] */
+)
+{
+ static const WORD vst[] = { 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 0};
+ static const WORD cst[] = {32768, 16384, 8192, 4096, 2048, 16384, 8192, 4096, 2048, 1024, 512};
+ BYTE fmt, md, *tbl;
+ DWORD n_clst, vs, n, wsect;
+ UINT i;
+ DWORD b_vol, b_fat, b_dir, b_data; /* Offset (LBA) */
+ DWORD n_vol, n_rsv, n_fat, n_dir; /* Size */
+ FATFS *fs;
+ DSTATUS stat;
+
+
+ /* Check mounted drive and clear work area */
+ if (drv >= _VOLUMES) return FR_INVALID_DRIVE;
+ fs = FatFs[drv];
+ if (!fs) return FR_NOT_ENABLED;
+ fs->fs_type = 0;
+ drv = LD2PD(drv);
+
+ /* Get disk statics */
+ stat = disk_initialize(drv);
+ if (stat & STA_NOINIT) return FR_NOT_READY;
+ if (stat & STA_PROTECT) return FR_WRITE_PROTECTED;
+#if _MAX_SS != 512 /* Get disk sector size */
+ if (disk_ioctl(drv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK)
+ return FR_DISK_ERR;
+#endif
+ if (disk_ioctl(drv, GET_SECTOR_COUNT, &n_vol) != RES_OK || n_vol < 128)
+ return FR_DISK_ERR;
+ b_vol = (sfd) ? 0 : 63; /* Volume start sector */
+ n_vol -= b_vol;
+ if (au & (au - 1)) au = 0; /* Check validity of the AU size */
+ if (!au) { /* AU auto selection */
+ vs = n_vol / (2000 / (SS(fs) / 512));
+ for (i = 0; vs < vst[i]; i++) ;
+ au = cst[i];
+ }
+ au /= SS(fs); /* Number of sectors per cluster */
+ if (au == 0) au = 1;
+ if (au > 128) au = 128;
+
+ /* Pre-compute number of clusters and FAT syb-type */
+ n_clst = n_vol / au;
+ fmt = FS_FAT12;
+ if (n_clst >= MIN_FAT16) fmt = FS_FAT16;
+ if (n_clst >= MIN_FAT32) fmt = FS_FAT32;
+
+ /* Determine offset and size of FAT structure */
+ if (fmt == FS_FAT32) {
+ n_fat = ((n_clst * 4) + 8 + SS(fs) - 1) / SS(fs);
+ n_rsv = 32;
+ n_dir = 0;
+ } else {
+ n_fat = (fmt == FS_FAT12) ? (n_clst * 3 + 1) / 2 + 3 : (n_clst * 2) + 4;
+ n_fat = (n_fat + SS(fs) - 1) / SS(fs);
+ n_rsv = 1;
+ n_dir = (DWORD)N_ROOTDIR * SZ_DIR / SS(fs);
+ }
+ b_fat = b_vol + n_rsv; /* FAT area start sector */
+ b_dir = b_fat + n_fat * N_FATS; /* Directory area start sector */
+ b_data = b_dir + n_dir; /* Data area start sector */
+ if (n_vol < b_data + au) return FR_MKFS_ABORTED; /* Too small volume */
+
+ /* Align data start sector to erase block boundary (for flash memory media) */
+ if (disk_ioctl(drv, GET_BLOCK_SIZE, &n) != RES_OK || !n || n > 32768) n = 1;
+ n = (b_data + n - 1) & ~(n - 1); /* Next nearest erase block from current data start */
+ n = (n - b_data) / N_FATS;
+ if (fmt == FS_FAT32) { /* FAT32: Move FAT offset */
+ n_rsv += n;
+ b_fat += n;
+ } else { /* FAT12/16: Expand FAT size */
+ n_fat += n;
+ }
+
+ /* Determine number of clusters and final check of validity of the FAT sub-type */
+ n_clst = (n_vol - n_rsv - n_fat * N_FATS - n_dir) / au;
+ if ( (fmt == FS_FAT16 && n_clst < MIN_FAT16)
+ || (fmt == FS_FAT32 && n_clst < MIN_FAT32))
+ return FR_MKFS_ABORTED;
+
+ /* Create partition table if required */
+ if (sfd) { /* No patition table (SFD) */
+ md = 0xF0;
+ } else { /* With patition table (FDISK) */
+ DWORD n_disk = b_vol + n_vol;
+
+ mem_set(fs->win, 0, SS(fs));
+ tbl = fs->win+MBR_Table;
+ ST_DWORD(tbl, 0x00010180); /* Partition start in CHS */
+ if (n_disk < 63UL * 255 * 1024) { /* Partition end in CHS */
+ n_disk = n_disk / 63 / 255;
+ tbl[7] = (BYTE)n_disk;
+ tbl[6] = (BYTE)((n_disk >> 2) | 63);
+ } else {
+ ST_WORD(&tbl[6], 0xFFFF); /* CHS saturated */
+ }
+ tbl[5] = 254;
+ if (fmt != FS_FAT32) /* System ID */
+ tbl[4] = (n_vol < 0x10000) ? 0x04 : 0x06;
+ else
+ tbl[4] = 0x0c;
+ ST_DWORD(tbl+8, 63); /* Partition start in LBA */
+ ST_DWORD(tbl+12, n_vol); /* Partition size in LBA */
+ ST_WORD(fs->win+BS_55AA, 0xAA55); /* MBR signature */
+ if (disk_write(drv, fs->win, 0, 1) != RES_OK) /* Put the MBR into first physical sector */
+ return FR_DISK_ERR;
+ md = 0xF8;
+ }
+
+ /* Create volume boot record */
+ tbl = fs->win; /* Clear sector */
+ mem_set(tbl, 0, SS(fs));
+ mem_cpy(tbl, "\xEB\xFE\x90" "MSDOS5.0", 11);/* Boot jump code, OEM name */
+ i = SS(fs); /* Sector size */
+ ST_WORD(tbl+BPB_BytsPerSec, i);
+ tbl[BPB_SecPerClus] = (BYTE)au; /* Sectors per cluster */
+ ST_WORD(tbl+BPB_RsvdSecCnt, n_rsv); /* Reserved sectors */
+ tbl[BPB_NumFATs] = N_FATS; /* Number of FATs */
+ i = (fmt == FS_FAT32) ? 0 : N_ROOTDIR; /* Number of rootdir entries */
+ ST_WORD(tbl+BPB_RootEntCnt, i);
+ if (n_vol < 0x10000) { /* Number of total sectors */
+ ST_WORD(tbl+BPB_TotSec16, n_vol);
+ } else {
+ ST_DWORD(tbl+BPB_TotSec32, n_vol);
+ }
+ tbl[BPB_Media] = md; /* Media descriptor */
+ ST_WORD(tbl+BPB_SecPerTrk, 63); /* Number of sectors per track */
+ ST_WORD(tbl+BPB_NumHeads, 255); /* Number of heads */
+ ST_DWORD(tbl+BPB_HiddSec, b_vol); /* Hidden sectors */
+ n = get_fattime(); /* Use current time as VSN */
+ if (fmt == FS_FAT32) {
+ ST_DWORD(tbl+BS_VolID32, n); /* VSN */
+ ST_DWORD(tbl+BPB_FATSz32, n_fat); /* Number of sectors per FAT */
+ ST_DWORD(tbl+BPB_RootClus, 2); /* Root directory start cluster (2) */
+ ST_WORD(tbl+BPB_FSInfo, 1); /* FSInfo record offset (VBR+1) */
+ ST_WORD(tbl+BPB_BkBootSec, 6); /* Backup boot record offset (VBR+6) */
+ tbl[BS_DrvNum32] = 0x80; /* Drive number */
+ tbl[BS_BootSig32] = 0x29; /* Extended boot signature */
+ mem_cpy(tbl+BS_VolLab32, "NO NAME " "FAT32 ", 19); /* Volume label, FAT signature */
+ } else {
+ ST_DWORD(tbl+BS_VolID, n); /* VSN */
+ ST_WORD(tbl+BPB_FATSz16, n_fat); /* Number of sectors per FAT */
+ tbl[BS_DrvNum] = 0x80; /* Drive number */
+ tbl[BS_BootSig] = 0x29; /* Extended boot signature */
+ mem_cpy(tbl+BS_VolLab, "NO NAME " "FAT ", 19); /* Volume label, FAT signature */
+ }
+ ST_WORD(tbl+BS_55AA, 0xAA55); /* Signature (Offset is fixed here regardless of sector size) */
+ if (disk_write(drv, tbl, b_vol, 1) != RES_OK) /* Write VBR */
+ return FR_DISK_ERR;
+ if (fmt == FS_FAT32) /* Write backup VBR if needed (VBR+6) */
+ disk_write(drv, tbl, b_vol + 6, 1);
+
+ /* Initialize FAT area */
+ wsect = b_fat;
+ for (i = 0; i < N_FATS; i++) { /* Initialize each FAT copy */
+ mem_set(tbl, 0, SS(fs)); /* 1st sector of the FAT */
+ n = md; /* Media descriptor byte */
+ if (fmt != FS_FAT32) {
+ n |= (fmt == FS_FAT12) ? 0x00FFFF00 : 0xFFFFFF00;
+ ST_DWORD(tbl+0, n); /* Reserve cluster #0-1 (FAT12/16) */
+ } else {
+ n |= 0xFFFFFF00;
+ ST_DWORD(tbl+0, n); /* Reserve cluster #0-1 (FAT32) */
+ ST_DWORD(tbl+4, 0xFFFFFFFF);
+ ST_DWORD(tbl+8, 0x0FFFFFFF); /* Reserve cluster #2 for root dir */
+ }
+ if (disk_write(drv, tbl, wsect++, 1) != RES_OK)
+ return FR_DISK_ERR;
+ mem_set(tbl, 0, SS(fs)); /* Fill following FAT entries with zero */
+ for (n = 1; n < n_fat; n++) { /* This loop may take a time on FAT32 volume due to many single sector writes */
+ if (disk_write(drv, tbl, wsect++, 1) != RES_OK)
+ return FR_DISK_ERR;
+ }
+ }
+
+ /* Initialize root directory */
+ i = (fmt == FS_FAT32) ? au : n_dir;
+ do {
+ if (disk_write(drv, tbl, wsect++, 1) != RES_OK)
+ return FR_DISK_ERR;
+ } while (--i);
+
+#if _USE_ERASE /* Erase data area if needed */
+ {
+ DWORD eb[2];
+
+ eb[0] = wsect; eb[1] = wsect + (n_clst - ((fmt == FS_FAT32) ? 1 : 0)) * au - 1;
+ disk_ioctl(drv, CTRL_ERASE_SECTOR, eb);
+ }
+#endif
+
+ /* Create FSInfo if needed */
+ if (fmt == FS_FAT32) {
+ ST_DWORD(tbl+FSI_LeadSig, 0x41615252);
+ ST_DWORD(tbl+FSI_StrucSig, 0x61417272);
+ ST_DWORD(tbl+FSI_Free_Count, n_clst - 1); /* Number of free clusters */
+ ST_DWORD(tbl+FSI_Nxt_Free, 2); /* Last allocated cluster# */
+ ST_WORD(tbl+BS_55AA, 0xAA55);
+ disk_write(drv, tbl, b_vol + 1, 1); /* Write original (VBR+1) */
+ disk_write(drv, tbl, b_vol + 7, 1); /* Write backup (VBR+7) */
+ }
+
+ return (disk_ioctl(drv, CTRL_SYNC, (void*)0) == RES_OK) ? FR_OK : FR_DISK_ERR;
+}
+
+#endif /* _USE_MKFS && !_FS_READONLY */
+
+
+
+
+#if _USE_STRFUNC
+/*-----------------------------------------------------------------------*/
+/* Get a string from the file */
+/*-----------------------------------------------------------------------*/
+TCHAR* f_gets (
+ TCHAR* buff, /* Pointer to the string buffer to read */
+ int len, /* Size of string buffer (characters) */
+ FIL_t* fil /* Pointer to the file object */
+)
+{
+ int n = 0;
+ TCHAR c, *p = buff;
+ BYTE s[2];
+ UINT rc;
+
+
+ while (n < len - 1) { /* Read bytes until buffer gets filled */
+ f_read(fil, s, 1, &rc);
+ if (rc != 1) break; /* Break on EOF or error */
+ c = s[0];
+#if _LFN_UNICODE /* Read a character in UTF-8 encoding */
+ if (c >= 0x80) {
+ if (c < 0xC0) continue; /* Skip stray trailer */
+ if (c < 0xE0) { /* Two-byte sequense */
+ f_read(fil, s, 1, &rc);
+ if (rc != 1) break;
+ c = ((c & 0x1F) << 6) | (s[0] & 0x3F);
+ if (c < 0x80) c = '?';
+ } else {
+ if (c < 0xF0) { /* Three-byte sequense */
+ f_read(fil, s, 2, &rc);
+ if (rc != 2) break;
+ c = (c << 12) | ((s[0] & 0x3F) << 6) | (s[1] & 0x3F);
+ if (c < 0x800) c = '?';
+ } else { /* Reject four-byte sequense */
+ c = '?';
+ }
+ }
+ }
+#endif
+#if _USE_STRFUNC >= 2
+ if (c == '\r') continue; /* Strip '\r' */
+#endif
+ *p++ = c;
+ n++;
+ if (c == '\n') break; /* Break on EOL */
+ }
+ *p = 0;
+ return n ? buff : 0; /* When no data read (eof or error), return with error. */
+}
+
+
+
+#if !_FS_READONLY
+#include <stdarg.h>
+/*-----------------------------------------------------------------------*/
+/* Put a character to the file */
+/*-----------------------------------------------------------------------*/
+int f_putc (
+ TCHAR c, /* A character to be output */
+ FIL_t* fil /* Pointer to the file object */
+)
+{
+ UINT bw, btw;
+ BYTE s[3];
+
+
+#if _USE_STRFUNC >= 2
+ if (c == '\n') f_putc ('\r', fil); /* LF -> CRLF conversion */
+#endif
+
+#if _LFN_UNICODE /* Write the character in UTF-8 encoding */
+ if (c < 0x80) { /* 7-bit */
+ s[0] = (BYTE)c;
+ btw = 1;
+ } else {
+ if (c < 0x800) { /* 11-bit */
+ s[0] = (BYTE)(0xC0 | (c >> 6));
+ s[1] = (BYTE)(0x80 | (c & 0x3F));
+ btw = 2;
+ } else { /* 16-bit */
+ s[0] = (BYTE)(0xE0 | (c >> 12));
+ s[1] = (BYTE)(0x80 | ((c >> 6) & 0x3F));
+ s[2] = (BYTE)(0x80 | (c & 0x3F));
+ btw = 3;
+ }
+ }
+#else /* Write the character without conversion */
+ s[0] = (BYTE)c;
+ btw = 1;
+#endif
+ f_write(fil, s, btw, &bw); /* Write the char to the file */
+ return (bw == btw) ? 1 : EOF; /* Return the result */
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Put a string to the file */
+/*-----------------------------------------------------------------------*/
+int f_puts (
+ const TCHAR* str, /* Pointer to the string to be output */
+ FIL_t* fil /* Pointer to the file object */
+)
+{
+ int n;
+
+
+ for (n = 0; *str; str++, n++) {
+ if (f_putc(*str, fil) == EOF) return EOF;
+ }
+ return n;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Put a formatted string to the file */
+/*-----------------------------------------------------------------------*/
+int f_printf (
+ FIL_t* fil, /* Pointer to the file object */
+ const TCHAR* str, /* Pointer to the format string */
+ ... /* Optional arguments... */
+)
+{
+ va_list arp;
+ BYTE f, r;
+ UINT i, j, w;
+ ULONG v;
+ TCHAR c, d, s[16], *p;
+ int res, cc;
+
+
+ va_start(arp, str);
+
+ for (cc = res = 0; cc != EOF; res += cc) {
+ c = *str++;
+ if (c == 0) break; /* End of string */
+ if (c != '%') { /* Non escape character */
+ cc = f_putc(c, fil);
+ if (cc != EOF) cc = 1;
+ continue;
+ }
+ w = f = 0;
+ c = *str++;
+ if (c == '0') { /* Flag: '0' padding */
+ f = 1; c = *str++;
+ } else {
+ if (c == '-') { /* Flag: left justified */
+ f = 2; c = *str++;
+ }
+ }
+ while (IsDigit(c)) { /* Precision */
+ w = w * 10 + c - '0';
+ c = *str++;
+ }
+ if (c == 'l' || c == 'L') { /* Prefix: Size is long int */
+ f |= 4; c = *str++;
+ }
+ if (!c) break;
+ d = c;
+ if (IsLower(d)) d -= 0x20;
+ switch (d) { /* Type is... */
+ case 'S' : /* String */
+ p = va_arg(arp, TCHAR*);
+ for (j = 0; p[j]; j++) ;
+ res = 0;
+ while (!(f & 2) && j++ < w) res += (cc = f_putc(' ', fil));
+ res += (cc = f_puts(p, fil));
+ while (j++ < w) res += (cc = f_putc(' ', fil));
+ if (cc != EOF) cc = res;
+ continue;
+ case 'C' : /* Character */
+ cc = f_putc((TCHAR)va_arg(arp, int), fil); continue;
+ case 'B' : /* Binary */
+ r = 2; break;
+ case 'O' : /* Octal */
+ r = 8; break;
+ case 'D' : /* Signed decimal */
+ case 'U' : /* Unsigned decimal */
+ r = 10; break;
+ case 'X' : /* Hexdecimal */
+ r = 16; break;
+ default: /* Unknown type (passthrough) */
+ cc = f_putc(c, fil); continue;
+ }
+
+ /* Get an argument and put it in numeral */
+ v = (f & 4) ? va_arg(arp, long) : ((d == 'D') ? (long)va_arg(arp, int) : va_arg(arp, unsigned int));
+ if (d == 'D' && (v & 0x80000000)) {
+ v = 0 - v;
+ f |= 8;
+ }
+ i = 0;
+ do {
+ d = (TCHAR)(v % r); v /= r;
+ if (d > 9) d += (c == 'x') ? 0x27 : 0x07;
+ s[i++] = d + '0';
+ } while (v && i < sizeof(s) / sizeof(s[0]));
+ if (f & 8) s[i++] = '-';
+ j = i; d = (f & 1) ? '0' : ' ';
+ res = 0;
+ while (!(f & 2) && j++ < w) res += (cc = f_putc(d, fil));
+ do res += (cc = f_putc(s[--i], fil)); while(i);
+ while (j++ < w) res += (cc = f_putc(' ', fil));
+ if (cc != EOF) cc = res;
+ }
+
+ va_end(arp);
+ return (cc == EOF) ? cc : res;
+}
+
+#endif /* !_FS_READONLY */
+#endif /* _USE_STRFUNC */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ChaNFS/CHAN_FS/ff.h Mon Nov 14 12:08:32 2011 +0000
@@ -0,0 +1,337 @@
+/*---------------------------------------------------------------------------/
+/ FatFs - FAT file system module include file R0.08b (C)ChaN, 2011
+/----------------------------------------------------------------------------/
+/ 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 trems.
+/
+/ Copyright (C) 2011, 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 8237 /* 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
+
+
+
+#define _DRIVES 4
+/* Number of logical drives to be used. This affects the size of internal table. */
+/* Definitions of volume management */
+
+#if _MULTI_PARTITION /* Multiple partition configuration */
+#define LD2PD(vol) (VolToPart[vol].pd) /* Get physical drive# */
+#define LD2PT(vol) (VolToPart[vol].pt) /* Get partition# */
+typedef struct {
+ BYTE pd; /* Physical drive# */
+ BYTE pt; /* Partition # (0-3) */
+} PARTITION;
+extern const PARTITION VolToPart[]; /* Volume - Physical location resolution table */
+
+#else /* Single partition configuration */
+#define LD2PD(vol) (vol) /* Logical drive# is bound to the same physical drive# */
+#define LD2PT(vol) 0 /* Always mounts the 1st partition */
+
+#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,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 owner file system object */
+ WORD id; /* Owner file system mount ID */
+ BYTE flag; /* File status flags */
+ BYTE pad1;
+ DWORD fptr; /* File read/write pointer (0 on file open) */
+ DWORD fsize; /* File size */
+ DWORD sclust; /* File start cluster (0 when fsize==0) */
+ DWORD clust; /* Current cluster */
+ DWORD dsect; /* Current data sector */
+#if !_FS_READONLY
+ DWORD dir_sect; /* Sector containing the directory entry */
+ BYTE* dir_ptr; /* Ponter 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_SHARE
+ UINT lockid; /* File lock ID (index of file semaphore table) */
+#endif
+#if !_FS_TINY
+ BYTE buf[_MAX_SS]; /* File data read/write buffer */
+#endif
+} FIL_t;
+
+
+
+/* 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_t;
+
+
+
+/* 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 occured 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) Acces denied due to prohibited access or directory full */
+ FR_EXIST, /* (8) Acces 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 on the physical drive */
+ 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 shareing 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 */
+} FRESULT;
+
+
+
+/*--------------------------------------------------------------*/
+/* FatFs module application interface */
+
+FRESULT f_mount (BYTE, FATFS*); /* Mount/Unmount a logical drive */
+FRESULT f_open (FIL_t*, const TCHAR*, BYTE); /* Open or create a file */
+FRESULT f_read (FIL_t*, void*, UINT, UINT*); /* Read data from a file */
+FRESULT f_lseek (FIL_t*, DWORD); /* Move file pointer of a file object */
+FRESULT f_close (FIL_t*); /* Close an open file object */
+FRESULT f_opendir (DIR_t*, const TCHAR*); /* Open an existing directory */
+FRESULT f_readdir (DIR_t*, FILINFO*); /* Read a directory item */
+FRESULT f_stat (const TCHAR*, FILINFO*); /* Get file status */
+FRESULT f_write (FIL_t*, 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_t*); /* Truncate file */
+FRESULT f_sync (FIL_t*); /* 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 attriburte of the file/dir */
+FRESULT f_utime (const TCHAR*, const FILINFO*); /* Change timestamp of the file/dir */
+FRESULT f_rename (const TCHAR*, const TCHAR*); /* Rename/Move a file or directory */
+FRESULT f_forward (FIL_t*, 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_chdrive (BYTE); /* Change current drive */
+FRESULT f_chdir (const TCHAR*); /* Change current directory */
+FRESULT f_getcwd (TCHAR*, UINT); /* Get current directory */
+int f_putc (TCHAR, FIL_t*); /* Put a character to the file */
+int f_puts (const TCHAR*, FIL_t*); /* Put a string to the file */
+int f_printf (FIL_t*, const TCHAR*, ...); /* Put a formatted string to the file */
+TCHAR* f_gets (TCHAR*, int, FIL_t*); /* Get a string from the file */
+
+#ifndef EOF
+#define EOF (-1)
+#endif
+
+#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)
+
+
+
+
+/*--------------------------------------------------------------*/
+/* 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 function */
+#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 */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ChaNFS/CHAN_FS/ffconf.h Mon Nov 14 12:08:32 2011 +0000 @@ -0,0 +1,189 @@ +/*---------------------------------------------------------------------------/ +/ FatFs - FAT file system module configuration file R0.08b (C)ChaN, 2011 +/----------------------------------------------------------------------------/ +/ +/ CAUTION! Do not forget to make clean the project after any changes to +/ the configuration options. +/ +/----------------------------------------------------------------------------*/ +#ifndef _FFCONF +#define _FFCONF 8237 /* Revision ID */ + + +/*---------------------------------------------------------------------------/ +/ Function and Buffer Configurations +/----------------------------------------------------------------------------*/ + +#define _FS_TINY 0 /* 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 0 /* 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 1 /* 0:Disable or 1/2:Enable */ +/* To enable string functions, set _USE_STRFUNC to 1 or 2. */ + + +#define _USE_MKFS 1 /* 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 1252 +/* 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 1 /* 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 or 1: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 0 /* 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_SHARE 0 /* 0:Disable or >=1:Enable */ +/* To enable file shareing feature, set _FS_SHARE to 1 or greater. The value + defines how many files can be opened simultaneously. */ + + +#endif /* _FFCONFIG */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ChaNFS/CHAN_FS/integer.h Mon Nov 14 12:08:32 2011 +0000 @@ -0,0 +1,37 @@ +/*-------------------------------------------*/ +/* 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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ChaNFS/CHAN_FS/option/ccsbcs.c Mon Nov 14 12:08:32 2011 +0000
@@ -0,0 +1,540 @@
+/*------------------------------------------------------------------------*/
+/* Unicode - Local code bidirectional converter (C)ChaN, 2009 */
+/* (SBCS code pages) */
+/*------------------------------------------------------------------------*/
+/* 437 U.S. (OEM)
+/ 720 Arabic (OEM)
+/ 1256 Arabic (Windows)
+/ 737 Greek (OEM)
+/ 1253 Greek (Windows)
+/ 1250 Central Europe (Windows)
+/ 775 Baltic (OEM)
+/ 1257 Baltic (Windows)
+/ 850 Multilingual Latin 1 (OEM)
+/ 852 Latin 2 (OEM)
+/ 1252 Latin 1 (Windows)
+/ 855 Cyrillic (OEM)
+/ 1251 Cyrillic (Windows)
+/ 866 Russian (OEM)
+/ 857 Turkish (OEM)
+/ 1254 Turkish (Windows)
+/ 858 Multilingual Latin 1 + Euro (OEM)
+/ 862 Hebrew (OEM)
+/ 1255 Hebrew (Windows)
+/ 874 Thai (OEM, Windows)
+/ 1258 Vietnam (OEM, Windows)
+*/
+
+#include "../ff.h"
+
+
+#if _CODE_PAGE == 437
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = { /* CP437(0x80-0xFF) to Unicode conversion table */
+ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7,
+ 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
+ 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9,
+ 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192,
+ 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA,
+ 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
+ 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
+ 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
+ 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
+ 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
+ 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
+ 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4,
+ 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
+ 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248,
+ 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 720
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = { /* CP720(0x80-0xFF) to Unicode conversion table */
+ 0x0000, 0x0000, 0x00E9, 0x00E2, 0x0000, 0x00E0, 0x0000, 0x00E7,
+ 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0651, 0x0652, 0x00F4, 0x00A4, 0x0640, 0x00FB, 0x00F9,
+ 0x0621, 0x0622, 0x0623, 0x0624, 0x00A3, 0x0625, 0x0626, 0x0627,
+ 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F,
+ 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x00AB, 0x00BB,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
+ 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
+ 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
+ 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
+ 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
+ 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
+ 0x0636, 0x0637, 0x0638, 0x0639, 0x063A, 0x0641, 0x00B5, 0x0642,
+ 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, 0x0648, 0x0649, 0x064A,
+ 0x2261, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F, 0xO650, 0x2248,
+ 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 737
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = { /* CP737(0x80-0xFF) to Unicode conversion table */
+ 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398,
+ 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, 0x03A0,
+ 0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9,
+ 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8,
+ 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0,
+ 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
+ 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
+ 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
+ 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
+ 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
+ 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
+ 0x03C9, 0x03AC, 0x03AD, 0x03AE, 0x03CA, 0x03AF, 0x03CC, 0x03CD,
+ 0x03CB, 0x03CE, 0x0386, 0x0388, 0x0389, 0x038A, 0x038C, 0x038E,
+ 0x038F, 0x00B1, 0x2265, 0x2264, 0x03AA, 0x03AB, 0x00F7, 0x2248,
+ 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 775
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = { /* CP775(0x80-0xFF) to Unicode conversion table */
+ 0x0106, 0x00FC, 0x00E9, 0x0101, 0x00E4, 0x0123, 0x00E5, 0x0107,
+ 0x0142, 0x0113, 0x0156, 0x0157, 0x012B, 0x0179, 0x00C4, 0x00C5,
+ 0x00C9, 0x00E6, 0x00C6, 0x014D, 0x00F6, 0x0122, 0x00A2, 0x015A,
+ 0x015B, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x00A4,
+ 0x0100, 0x012A, 0x00F3, 0x017B, 0x017C, 0x017A, 0x201D, 0x00A6,
+ 0x00A9, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x0141, 0x00AB, 0x00BB,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0104, 0x010C, 0x0118,
+ 0x0116, 0x2563, 0x2551, 0x2557, 0x255D, 0x012E, 0x0160, 0x2510,
+ 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0172, 0x016A,
+ 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x017D,
+ 0x0105, 0x010D, 0x0119, 0x0117, 0x012F, 0x0161, 0x0173, 0x016B,
+ 0x017E, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
+ 0x00D3, 0x00DF, 0x014C, 0x0143, 0x00F5, 0x00D5, 0x00B5, 0x0144,
+ 0x0136, 0x0137, 0x013B, 0x013C, 0x0146, 0x0112, 0x0145, 0x2019,
+ 0x00AD, 0x00B1, 0x201C, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x201E,
+ 0x00B0, 0x2219, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 850
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = { /* CP850(0x80-0xFF) to Unicode conversion table */
+ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7,
+ 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
+ 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9,
+ 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192,
+ 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA,
+ 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0,
+ 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510,
+ 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3,
+ 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
+ 0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x0131, 0x00CD, 0x00CE,
+ 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580,
+ 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE,
+ 0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4,
+ 0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8,
+ 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 852
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = { /* CP852(0x80-0xFF) to Unicode conversion table */
+ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x016F, 0x0107, 0x00E7,
+ 0x0142, 0x00EB, 0x0150, 0x0151, 0x00EE, 0x0179, 0x00C4, 0x0106,
+ 0x00C9, 0x0139, 0x013A, 0x00F4, 0x00F6, 0x013D, 0x013E, 0x015A,
+ 0x015B, 0x00D6, 0x00DC, 0x0164, 0x0165, 0x0141, 0x00D7, 0x010D,
+ 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x0104, 0x0105, 0x017D, 0x017E,
+ 0x0118, 0x0119, 0x00AC, 0x017A, 0x010C, 0x015F, 0x00AB, 0x00BB,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x011A,
+ 0x015E, 0x2563, 0x2551, 0x2557, 0x255D, 0x017B, 0x017C, 0x2510,
+ 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0102, 0x0103,
+ 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
+ 0x0111, 0x0110, 0x010E, 0x00CB, 0x010F, 0x0147, 0x00CD, 0x00CE,
+ 0x011B, 0x2518, 0x250C, 0x2588, 0x2584, 0x0162, 0x016E, 0x2580,
+ 0x00D3, 0x00DF, 0x00D4, 0x0143, 0x0144, 0x0148, 0x0160, 0x0161,
+ 0x0154, 0x00DA, 0x0155, 0x0170, 0x00FD, 0x00DD, 0x0163, 0x00B4,
+ 0x00AD, 0x02DD, 0x02DB, 0x02C7, 0x02D8, 0x00A7, 0x00F7, 0x00B8,
+ 0x00B0, 0x00A8, 0x02D9, 0x0171, 0x0158, 0x0159, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 855
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = { /* CP855(0x80-0xFF) to Unicode conversion table */
+ 0x0452, 0x0402, 0x0453, 0x0403, 0x0451, 0x0401, 0x0454, 0x0404,
+ 0x0455, 0x0405, 0x0456, 0x0406, 0x0457, 0x0407, 0x0458, 0x0408,
+ 0x0459, 0x0409, 0x045A, 0x040A, 0x045B, 0x040B, 0x045C, 0x040C,
+ 0x045E, 0x040E, 0x045F, 0x040F, 0x044E, 0x042E, 0x044A, 0x042A,
+ 0x0430, 0x0410, 0x0431, 0x0411, 0x0446, 0x0426, 0x0434, 0x0414,
+ 0x0435, 0x0415, 0x0444, 0x0424, 0x0433, 0x0413, 0x00AB, 0x00BB,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0445, 0x0425, 0x0438,
+ 0x0418, 0x2563, 0x2551, 0x2557, 0x255D, 0x0439, 0x0419, 0x2510,
+ 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x043A, 0x041A,
+ 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
+ 0x043B, 0x041B, 0x043C, 0x041C, 0x043D, 0x041D, 0x043E, 0x041E,
+ 0x043F, 0x2518, 0x250C, 0x2588, 0x2584, 0x041F, 0x044F, 0x2580,
+ 0x042F, 0x0440, 0x0420, 0x0441, 0x0421, 0x0442, 0x0422, 0x0443,
+ 0x0423, 0x0436, 0x0416, 0x0432, 0x0412, 0x044C, 0x042C, 0x2116,
+ 0x00AD, 0x044B, 0x042B, 0x0437, 0x0417, 0x0448, 0x0428, 0x044D,
+ 0x042D, 0x0449, 0x0429, 0x0447, 0x0427, 0x00A7, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 857
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = { /* CP857(0x80-0xFF) to Unicode conversion table */
+ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7,
+ 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0131, 0x00C4, 0x00C5,
+ 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9,
+ 0x0130, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x015E, 0x015F,
+ 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x011E, 0x011F,
+ 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0,
+ 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510,
+ 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3,
+ 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
+ 0x00BA, 0x00AA, 0x00CA, 0x00CB, 0x00C8, 0x0000, 0x00CD, 0x00CE,
+ 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580,
+ 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x0000,
+ 0x00D7, 0x00DA, 0x00DB, 0x00D9, 0x00EC, 0x00FF, 0x00AF, 0x00B4,
+ 0x00AD, 0x00B1, 0x0000, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8,
+ 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 858
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = { /* CP858(0x80-0xFF) to Unicode conversion table */
+ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7,
+ 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
+ 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9,
+ 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192,
+ 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA,
+ 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0,
+ 0x00A9, 0x2563, 0x2551, 0x2557, 0x2550, 0x00A2, 0x00A5, 0x2510,
+ 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3,
+ 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
+ 0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x20AC, 0x00CD, 0x00CE,
+ 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00C6, 0x00CC, 0x2580,
+ 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE,
+ 0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4,
+ 0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8,
+ 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 862
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = { /* CP862(0x80-0xFF) to Unicode conversion table */
+ 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7,
+ 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
+ 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7,
+ 0x05E8, 0x05E9, 0x05EA, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192,
+ 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA,
+ 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
+ 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
+ 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
+ 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
+ 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
+ 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
+ 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4,
+ 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
+ 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248,
+ 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 866
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = { /* CP866(0x80-0xFF) to Unicode conversion table */
+ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,
+ 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
+ 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427,
+ 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
+ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
+ 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
+ 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
+ 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
+ 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
+ 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
+ 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
+ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
+ 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
+ 0x0401, 0x0451, 0x0404, 0x0454, 0x0407, 0x0457, 0x040E, 0x045E,
+ 0x00B0, 0x2219, 0x00B7, 0x221A, 0x2116, 0x00A4, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 874
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = { /* CP874(0x80-0xFF) to Unicode conversion table */
+ 0x20AC, 0x0000, 0x0000, 0x0000, 0x0000, 0x2026, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x00A0, 0x0E01, 0x0E02, 0x0E03, 0x0E04, 0x0E05, 0x0E06, 0x0E07,
+ 0x0E08, 0x0E09, 0x0E0A, 0x0E0B, 0x0E0C, 0x0E0D, 0x0E0E, 0x0E0F,
+ 0x0E10, 0x0E11, 0x0E12, 0x0E13, 0x0E14, 0x0E15, 0x0E16, 0x0E17,
+ 0x0E18, 0x0E19, 0x0E1A, 0x0E1B, 0x0E1C, 0x0E1D, 0x0E1E, 0x0E1F,
+ 0x0E20, 0x0E21, 0x0E22, 0x0E23, 0x0E24, 0x0E25, 0x0E26, 0x0E27,
+ 0x0E28, 0x0E29, 0x0E2A, 0x0E2B, 0x0E2C, 0x0E2D, 0x0E2E, 0x0E2F,
+ 0x0E30, 0x0E31, 0x0E32, 0x0E33, 0x0E34, 0x0E35, 0x0E36, 0x0E37,
+ 0x0E38, 0x0E39, 0x0E3A, 0x0000, 0x0000, 0x0000, 0x0000, 0x0E3F,
+ 0x0E40, 0x0E41, 0x0E42, 0x0E43, 0x0E44, 0x0E45, 0x0E46, 0x0E47,
+ 0x0E48, 0x0E49, 0x0E4A, 0x0E4B, 0x0E4C, 0x0E4D, 0x0E4E, 0x0E4F,
+ 0x0E50, 0x0E51, 0x0E52, 0x0E53, 0x0E54, 0x0E55, 0x0E56, 0x0E57,
+ 0x0E58, 0x0E59, 0x0E5A, 0x0E5B, 0x0000, 0x0000, 0x0000, 0x0000
+};
+
+#elif _CODE_PAGE == 1250
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = { /* CP1250(0x80-0xFF) to Unicode conversion table */
+ 0x20AC, 0x0000, 0x201A, 0x0000, 0x201E, 0x2026, 0x2020, 0x2021,
+ 0x0000, 0x2030, 0x0160, 0x2039, 0x015A, 0x0164, 0x017D, 0x0179,
+ 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+ 0x0000, 0x2122, 0x0161, 0x203A, 0x015B, 0x0165, 0x017E, 0x017A,
+ 0x00A0, 0x02C7, 0x02D8, 0x0141, 0x00A4, 0x0104, 0x00A6, 0x00A7,
+ 0x00A8, 0x00A9, 0x015E, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x017B,
+ 0x00B0, 0x00B1, 0x02DB, 0x0142, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+ 0x00B8, 0x0105, 0x015F, 0x00BB, 0x013D, 0x02DD, 0x013E, 0x017C,
+ 0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7,
+ 0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E,
+ 0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7,
+ 0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF,
+ 0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7,
+ 0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F,
+ 0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7,
+ 0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9
+};
+
+#elif _CODE_PAGE == 1251
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = { /* CP1251(0x80-0xFF) to Unicode conversion table */
+ 0x0402, 0x0403, 0x201A, 0x0453, 0x201E, 0x2026, 0x2020, 0x2021,
+ 0x20AC, 0x2030, 0x0409, 0x2039, 0x040A, 0x040C, 0x040B, 0x040F,
+ 0x0452, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+ 0x0000, 0x2111, 0x0459, 0x203A, 0x045A, 0x045C, 0x045B, 0x045F,
+ 0x00A0, 0x040E, 0x045E, 0x0408, 0x00A4, 0x0490, 0x00A6, 0x00A7,
+ 0x0401, 0x00A9, 0x0404, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x0407,
+ 0x00B0, 0x00B1, 0x0406, 0x0456, 0x0491, 0x00B5, 0x00B6, 0x00B7,
+ 0x0451, 0x2116, 0x0454, 0x00BB, 0x0458, 0x0405, 0x0455, 0x0457,
+ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,
+ 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
+ 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427,
+ 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
+ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
+ 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
+ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
+ 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F
+};
+
+#elif _CODE_PAGE == 1252
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = { /* CP1252(0x80-0xFF) to Unicode conversion table */
+ 0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
+ 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0x0000, 0x017D, 0x0000,
+ 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+ 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0x0000, 0x017E, 0x0178,
+ 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+ 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+ 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
+ 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
+ 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
+ 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
+ 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF,
+ 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
+ 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
+ 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7,
+ 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF
+};
+
+#elif _CODE_PAGE == 1253
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = { /* CP1253(0x80-0xFF) to Unicode conversion table */
+ 0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
+ 0x0000, 0x2030, 0x0000, 0x2039, 0x000C, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+ 0x0000, 0x2122, 0x0000, 0x203A, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x00A0, 0x0385, 0x0386, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+ 0x00A8, 0x00A9, 0x0000, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x2015,
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x0384, 0x00B5, 0x00B6, 0x00B7,
+ 0x0388, 0x0389, 0x038A, 0x00BB, 0x038C, 0x00BD, 0x038E, 0x038F,
+ 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397,
+ 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F,
+ 0x03A0, 0x03A1, 0x0000, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7,
+ 0x03A8, 0x03A9, 0x03AA, 0x03AD, 0x03AC, 0x03AD, 0x03AE, 0x03AF,
+ 0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7,
+ 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
+ 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7,
+ 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0x0000
+};
+
+#elif _CODE_PAGE == 1254
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = { /* CP1254(0x80-0xFF) to Unicode conversion table */
+ 0x20AC, 0x0000, 0x210A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
+ 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+ 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0x0000, 0x0000, 0x0178,
+ 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+ 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+ 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
+ 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
+ 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
+ 0x011E, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
+ 0x00D8, 0x00D9, 0x00DA, 0x00BD, 0x00DC, 0x0130, 0x015E, 0x00DF,
+ 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
+ 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
+ 0x011F, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7,
+ 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0131, 0x015F, 0x00FF
+};
+
+#elif _CODE_PAGE == 1255
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = { /* CP1255(0x80-0xFF) to Unicode conversion table */
+ 0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
+ 0x02C6, 0x2030, 0x0000, 0x2039, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+ 0x02DC, 0x2122, 0x0000, 0x203A, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+ 0x00A8, 0x00A9, 0x00D7, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+ 0x00B8, 0x00B9, 0x00F7, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
+ 0x05B0, 0x05B1, 0x05B2, 0x05B3, 0x05B4, 0x05B5, 0x05B6, 0x05B7,
+ 0x05B8, 0x05B9, 0x0000, 0x05BB, 0x05BC, 0x05BD, 0x05BE, 0x05BF,
+ 0x05C0, 0x05C1, 0x05C2, 0x05C3, 0x05F0, 0x05F1, 0x05F2, 0x05F3,
+ 0x05F4, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7,
+ 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
+ 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7,
+ 0x05E8, 0x05E9, 0x05EA, 0x0000, 0x0000, 0x200E, 0x200F, 0x0000
+};
+
+#elif _CODE_PAGE == 1256
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = { /* CP1256(0x80-0xFF) to Unicode conversion table */
+ 0x20AC, 0x067E, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
+ 0x02C6, 0x2030, 0x0679, 0x2039, 0x0152, 0x0686, 0x0698, 0x0688,
+ 0x06AF, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+ 0x06A9, 0x2122, 0x0691, 0x203A, 0x0153, 0x200C, 0x200D, 0x06BA,
+ 0x00A0, 0x060C, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+ 0x00A8, 0x00A9, 0x06BE, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+ 0x00B8, 0x00B9, 0x061B, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x061F,
+ 0x06C1, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627,
+ 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F,
+ 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x00D7,
+ 0x0637, 0x0638, 0x0639, 0x063A, 0x0640, 0x0640, 0x0642, 0x0643,
+ 0x00E0, 0x0644, 0x00E2, 0x0645, 0x0646, 0x0647, 0x0648, 0x00E7,
+ 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x0649, 0x064A, 0x00EE, 0x00EF,
+ 0x064B, 0x064C, 0x064D, 0x064E, 0x00F4, 0x064F, 0x0650, 0x00F7,
+ 0x0651, 0x00F9, 0x0652, 0x00FB, 0x00FC, 0x200E, 0x200F, 0x06D2
+}
+
+#elif _CODE_PAGE == 1257
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = { /* CP1257(0x80-0xFF) to Unicode conversion table */
+ 0x20AC, 0x0000, 0x201A, 0x0000, 0x201E, 0x2026, 0x2020, 0x2021,
+ 0x0000, 0x2030, 0x0000, 0x2039, 0x0000, 0x00A8, 0x02C7, 0x00B8,
+ 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+ 0x0000, 0x2122, 0x0000, 0x203A, 0x0000, 0x00AF, 0x02DB, 0x0000,
+ 0x00A0, 0x0000, 0x00A2, 0x00A3, 0x00A4, 0x0000, 0x00A6, 0x00A7,
+ 0x00D8, 0x00A9, 0x0156, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+ 0x00B8, 0x00B9, 0x0157, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00E6,
+ 0x0104, 0x012E, 0x0100, 0x0106, 0x00C4, 0x00C5, 0x0118, 0x0112,
+ 0x010C, 0x00C9, 0x0179, 0x0116, 0x0122, 0x0136, 0x012A, 0x013B,
+ 0x0160, 0x0143, 0x0145, 0x00D3, 0x014C, 0x00D5, 0x00D6, 0x00D7,
+ 0x0172, 0x0141, 0x015A, 0x016A, 0x00DC, 0x017B, 0x017D, 0x00DF,
+ 0x0105, 0x012F, 0x0101, 0x0107, 0x00E4, 0x00E5, 0x0119, 0x0113,
+ 0x010D, 0x00E9, 0x017A, 0x0117, 0x0123, 0x0137, 0x012B, 0x013C,
+ 0x0161, 0x0144, 0x0146, 0x00F3, 0x014D, 0x00F5, 0x00F6, 0x00F7,
+ 0x0173, 0x014E, 0x015B, 0x016B, 0x00FC, 0x017C, 0x017E, 0x02D9
+};
+
+#elif _CODE_PAGE == 1258
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = { /* CP1258(0x80-0xFF) to Unicode conversion table */
+ 0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
+ 0x02C6, 0x2030, 0x0000, 0x2039, 0x0152, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+ 0x02DC, 0x2122, 0x0000, 0x203A, 0x0153, 0x0000, 0x0000, 0x0178,
+ 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+ 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+ 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
+ 0x00C0, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
+ 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x0300, 0x00CD, 0x00CE, 0x00CF,
+ 0x0110, 0x00D1, 0x0309, 0x00D3, 0x00D4, 0x01A0, 0x00D6, 0x00D7,
+ 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x01AF, 0x0303, 0x00DF,
+ 0x00E0, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
+ 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x0301, 0x00ED, 0x00EE, 0x00EF,
+ 0x0111, 0x00F1, 0x0323, 0x00F3, 0x00F4, 0x01A1, 0x00F6, 0x00F7,
+ 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x01B0, 0x20AB, 0x00FF
+};
+
+#endif
+
+
+#if !_TBLDEF || !_USE_LFN
+#error This file is not needed in current configuration. Remove from the project.
+#endif
+
+
+WCHAR ff_convert ( /* Converted character, Returns zero on error */
+ WCHAR src, /* Character code to be converted */
+ UINT dir /* 0: Unicode to OEMCP, 1: OEMCP to Unicode */
+)
+{
+ WCHAR c;
+
+
+ if (src < 0x80) { /* ASCII */
+ c = src;
+
+ } else {
+ if (dir) { /* OEMCP to Unicode */
+ c = (src >= 0x100) ? 0 : Tbl[src - 0x80];
+
+ } else { /* Unicode to OEMCP */
+ for (c = 0; c < 0x80; c++) {
+ if (src == Tbl[c]) break;
+ }
+ c = (c + 0x80) & 0xFF;
+ }
+ }
+
+ return c;
+}
+
+
+WCHAR ff_wtoupper ( /* Upper converted character */
+ WCHAR chr /* Input character */
+)
+{
+ static const WCHAR tbl_lower[] = { 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0xA1, 0x00A2, 0x00A3, 0x00A5, 0x00AC, 0x00AF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0x0FF, 0x101, 0x103, 0x105, 0x107, 0x109, 0x10B, 0x10D, 0x10F, 0x111, 0x113, 0x115, 0x117, 0x119, 0x11B, 0x11D, 0x11F, 0x121, 0x123, 0x125, 0x127, 0x129, 0x12B, 0x12D, 0x12F, 0x131, 0x133, 0x135, 0x137, 0x13A, 0x13C, 0x13E, 0x140, 0x142, 0x144, 0x146, 0x148, 0x14B, 0x14D, 0x14F, 0x151, 0x153, 0x155, 0x157, 0x159, 0x15B, 0x15D, 0x15F, 0x161, 0x163, 0x165, 0x167, 0x169, 0x16B, 0x16D, 0x16F, 0x171, 0x173, 0x175, 0x177, 0x17A, 0x17C, 0x17E, 0x192, 0x3B1, 0x3B2, 0x3B3, 0x3B4, 0x3B5, 0x3B6, 0x3B7, 0x3B8, 0x3B9, 0x3BA, 0x3BB, 0x3BC, 0x3BD, 0x3BE, 0x3BF, 0x3C0, 0x3C1, 0x3C3, 0x3C4, 0x3C5, 0x3C6, 0x3C7, 0x3C8, 0x3C9, 0x3CA, 0x430, 0x431, 0x432, 0x433, 0x434, 0x435, 0x436, 0x437, 0x438, 0x439, 0x43A, 0x43B, 0x43C, 0x43D, 0x43E, 0x43F, 0x440, 0x441, 0x442, 0x443, 0x444, 0x445, 0x446, 0x447, 0x448, 0x449, 0x44A, 0x44B, 0x44C, 0x44D, 0x44E, 0x44F, 0x451, 0x452, 0x453, 0x454, 0x455, 0x456, 0x457, 0x458, 0x459, 0x45A, 0x45B, 0x45C, 0x45E, 0x45F, 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177, 0x2178, 0x2179, 0x217A, 0x217B, 0x217C, 0x217D, 0x217E, 0x217F, 0xFF41, 0xFF42, 0xFF43, 0xFF44, 0xFF45, 0xFF46, 0xFF47, 0xFF48, 0xFF49, 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, 0xFF4E, 0xFF4F, 0xFF50, 0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55, 0xFF56, 0xFF57, 0xFF58, 0xFF59, 0xFF5A, 0 };
+ static const WCHAR tbl_upper[] = { 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x21, 0xFFE0, 0xFFE1, 0xFFE5, 0xFFE2, 0xFFE3, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0x178, 0x100, 0x102, 0x104, 0x106, 0x108, 0x10A, 0x10C, 0x10E, 0x110, 0x112, 0x114, 0x116, 0x118, 0x11A, 0x11C, 0x11E, 0x120, 0x122, 0x124, 0x126, 0x128, 0x12A, 0x12C, 0x12E, 0x130, 0x132, 0x134, 0x136, 0x139, 0x13B, 0x13D, 0x13F, 0x141, 0x143, 0x145, 0x147, 0x14A, 0x14C, 0x14E, 0x150, 0x152, 0x154, 0x156, 0x158, 0x15A, 0x15C, 0x15E, 0x160, 0x162, 0x164, 0x166, 0x168, 0x16A, 0x16C, 0x16E, 0x170, 0x172, 0x174, 0x176, 0x179, 0x17B, 0x17D, 0x191, 0x391, 0x392, 0x393, 0x394, 0x395, 0x396, 0x397, 0x398, 0x399, 0x39A, 0x39B, 0x39C, 0x39D, 0x39E, 0x39F, 0x3A0, 0x3A1, 0x3A3, 0x3A4, 0x3A5, 0x3A6, 0x3A7, 0x3A8, 0x3A9, 0x3AA, 0x410, 0x411, 0x412, 0x413, 0x414, 0x415, 0x416, 0x417, 0x418, 0x419, 0x41A, 0x41B, 0x41C, 0x41D, 0x41E, 0x41F, 0x420, 0x421, 0x422, 0x423, 0x424, 0x425, 0x426, 0x427, 0x428, 0x429, 0x42A, 0x42B, 0x42C, 0x42D, 0x42E, 0x42F, 0x401, 0x402, 0x403, 0x404, 0x405, 0x406, 0x407, 0x408, 0x409, 0x40A, 0x40B, 0x40C, 0x40E, 0x40F, 0x2160, 0x2161, 0x2162, 0x2163, 0x2164, 0x2165, 0x2166, 0x2167, 0x2168, 0x2169, 0x216A, 0x216B, 0x216C, 0x216D, 0x216E, 0x216F, 0xFF21, 0xFF22, 0xFF23, 0xFF24, 0xFF25, 0xFF26, 0xFF27, 0xFF28, 0xFF29, 0xFF2A, 0xFF2B, 0xFF2C, 0xFF2D, 0xFF2E, 0xFF2F, 0xFF30, 0xFF31, 0xFF32, 0xFF33, 0xFF34, 0xFF35, 0xFF36, 0xFF37, 0xFF38, 0xFF39, 0xFF3A, 0 };
+ int i;
+
+
+ for (i = 0; tbl_lower[i] && chr != tbl_lower[i]; i++) ;
+
+ return tbl_lower[i] ? tbl_upper[i] : chr;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ChaNFS/FATDirHandle.cpp Mon Nov 14 12:08:32 2011 +0000
@@ -0,0 +1,61 @@
+/* mbed Microcontroller Library - FATDirHandle
+ * Copyright (c) 2008, sford
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "ff.h"
+#include "FATDirHandle.h"
+#include "FATFileSystem.h"
+
+namespace mbed {
+
+FATDirHandle::FATDirHandle(const DIR_t &the_dir) {
+ dir = the_dir;
+}
+
+int FATDirHandle::closedir() {
+ delete this;
+ return 0;
+}
+
+struct dirent *FATDirHandle::readdir() {
+ FILINFO finfo;
+#if _USE_LFN
+ static char lfn[_MAX_LFN * (_LFN_UNICODE ? 2 : 1) + 1];
+ finfo.lfname = lfn;
+ finfo.lfsize = sizeof(lfn);
+#endif
+ FRESULT res = f_readdir(&dir, &finfo);
+ if(res != 0 || finfo.fname[0]==0) {
+ return NULL;
+ } else {
+ char* fn;
+ int stringSize = 0;
+#if _USE_LFN
+ fn = *finfo.lfname ? finfo.lfname : finfo.fname;
+ stringSize = finfo.lfsize;
+#else
+ fn = fno.fname;
+ stringSize = sizeof(finfo.fname);
+#endif
+ memcpy(cur_entry.d_name, fn, stringSize);
+ return &cur_entry;
+ }
+}
+
+void FATDirHandle::rewinddir() {
+ dir.index = 0;
+}
+
+off_t FATDirHandle::telldir() {
+ return dir.index;
+}
+
+void FATDirHandle::seekdir(off_t location) {
+ dir.index = location;
+}
+
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ChaNFS/FATDirHandle.h Mon Nov 14 12:08:32 2011 +0000
@@ -0,0 +1,31 @@
+/* mbed Microcontroller Library - FATDirHandle
+ * Copyright (c) 2008, sford
+ */
+
+#ifndef MBED_FATDIRHANDLE_H
+#define MBED_FATDIRHANDLE_H
+
+#include "DirHandle.h"
+#include "ff.h"
+
+namespace mbed {
+
+class FATDirHandle : public DirHandle {
+
+ public:
+ FATDirHandle(const DIR_t &the_dir);
+ virtual int closedir();
+ virtual struct dirent *readdir();
+ virtual void rewinddir();
+ virtual off_t telldir();
+ virtual void seekdir(off_t location);
+
+ private:
+ DIR_t dir;
+ struct dirent cur_entry;
+
+};
+
+}
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ChaNFS/FATFileHandle.cpp Mon Nov 14 12:08:32 2011 +0000
@@ -0,0 +1,102 @@
+/* mbed Microcontroller Library - FATFileHandle
+ * Copyright (c) 2008, sford
+ */
+
+#include "FATFileHandle.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "ff.h"
+#include "FATFileSystem.h"
+
+namespace mbed {
+
+#if FFSDEBUG_ENABLED
+static const char *FR_ERRORS[] = {
+ "FR_OK = 0",
+ "FR_NOT_READY",
+ "FR_NO_FILE",
+ "FR_NO_PATH",
+ "FR_INVALID_NAME",
+ "FR_INVALID_DRIVE",
+ "FR_DENIED",
+ "FR_EXIST",
+ "FR_RW_ERROR",
+ "FR_WRITE_PROTECTED",
+ "FR_NOT_ENABLED",
+ "FR_NO_FILESYSTEM",
+ "FR_INVALID_OBJECT",
+ "FR_MKFS_ABORTED"
+};
+#endif
+
+FATFileHandle::FATFileHandle(FIL_t fh) {
+ _fh = fh;
+}
+
+int FATFileHandle::close() {
+ FFSDEBUG("close\n");
+ int retval = f_close(&_fh);
+ delete this;
+ return retval;
+}
+
+ssize_t FATFileHandle::write(const void* buffer, size_t length) {
+ FFSDEBUG("write(%d)\n", length);
+ UINT n;
+ FRESULT res = f_write(&_fh, buffer, length, &n);
+ if(res) {
+ FFSDEBUG("f_write() failed (%d, %s)", res, FR_ERRORS[res]);
+ return -1;
+ }
+ return n;
+}
+
+ssize_t FATFileHandle::read(void* buffer, size_t length) {
+ FFSDEBUG("read(%d)\n", length);
+ UINT n;
+ FRESULT res = f_read(&_fh, buffer, length, &n);
+ if(res) {
+ FFSDEBUG("f_read() failed (%d, %s)\n", res, FR_ERRORS[res]);
+ return -1;
+ }
+ return n;
+}
+
+int FATFileHandle::isatty() {
+ return 0;
+}
+
+off_t FATFileHandle::lseek(off_t position, int whence) {
+ FFSDEBUG("lseek(%i,%i)\n",position,whence);
+ if(whence == SEEK_END) {
+ position += _fh.fsize;
+ } else if(whence==SEEK_CUR) {
+ position += _fh.fptr;
+ }
+ FRESULT res = f_lseek(&_fh, position);
+ if(res) {
+ FFSDEBUG("lseek failed (%d, %s)\n", res, FR_ERRORS[res]);
+ return -1;
+ } else {
+ FFSDEBUG("lseek OK, returning %i\n", _fh.fptr);
+ return _fh.fptr;
+ }
+}
+
+int FATFileHandle::fsync() {
+ FFSDEBUG("fsync()\n");
+ FRESULT res = f_sync(&_fh);
+ if (res) {
+ FFSDEBUG("f_sync() failed (%d, %s)\n", res, FR_ERRORS[res]);
+ return -1;
+ }
+ return 0;
+}
+
+off_t FATFileHandle::flen() {
+ FFSDEBUG("flen\n");
+ return _fh.fsize;
+}
+
+} // namespace mbed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ChaNFS/FATFileHandle.h Mon Nov 14 12:08:32 2011 +0000
@@ -0,0 +1,33 @@
+/* mbed Microcontroller Library - FATFileHandle
+ * Copyright (c) 2008, sford
+ */
+
+#ifndef MBED_FATFILEHANDLE_H
+#define MBED_FATFILEHANDLE_H
+
+#include "FileHandle.h"
+#include "ff.h"
+
+namespace mbed {
+
+class FATFileHandle : public FileHandle {
+public:
+
+ FATFileHandle(FIL_t fh);
+ virtual int close();
+ virtual ssize_t write(const void* buffer, size_t length);
+ virtual ssize_t read(void* buffer, size_t length);
+ virtual int isatty();
+ virtual off_t lseek(off_t position, int whence);
+ virtual int fsync();
+ virtual off_t flen();
+
+protected:
+
+ FIL_t _fh;
+
+};
+
+}
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ChaNFS/FATFileSystem.cpp Mon Nov 14 12:08:32 2011 +0000
@@ -0,0 +1,134 @@
+/* mbed Microcontroller Library - FATFileSystem
+ * Copyright (c) 2008, sford
+ */
+
+#include "FATFileSystem.h"
+
+#include "mbed.h"
+
+#include "FileSystemLike.h"
+#include "FATFileHandle.h"
+#include "FATDirHandle.h"
+#include "ff.h"
+//#include "Debug.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+DWORD get_fattime (void) {
+ return 999;
+}
+
+namespace mbed {
+
+#if FFSDEBUG_ENABLED
+static const char *FR_ERRORS[] = {
+ "FR_OK = 0",
+ "FR_NOT_READY",
+ "FR_NO_FILE",
+ "FR_NO_PATH",
+ "FR_INVALID_NAME",
+ "FR_INVALID_DRIVE",
+ "FR_DENIED",
+ "FR_EXIST",
+ "FR_RW_ERROR",
+ "FR_WRITE_PROTECTED",
+ "FR_NOT_ENABLED",
+ "FR_NO_FILESYSTEM",
+ "FR_INVALID_OBJECT",
+ "FR_MKFS_ABORTED"
+};
+#endif
+
+FATFileSystem *FATFileSystem::_ffs[_DRIVES] = {0};
+
+FATFileSystem::FATFileSystem(const char* n) : FileSystemLike(n) {
+ FFSDEBUG("FATFileSystem(%s)\n", n);
+ for(int i=0; i<_DRIVES; i++) {
+ if(_ffs[i] == 0) {
+ _ffs[i] = this;
+ _fsid = i;
+ FFSDEBUG("Mounting [%s] on ffs drive [%d]\n", _name, _fsid);
+ f_mount(i, &_fs);
+ return;
+ }
+ }
+ error("Couldn't create %s in FATFileSystem::FATFileSystem\n",n);
+}
+
+FATFileSystem::~FATFileSystem() {
+ for(int i=0; i<_DRIVES; i++) {
+ if(_ffs[i] == this) {
+ _ffs[i] = 0;
+ f_mount(i, NULL);
+ }
+ }
+}
+
+FileHandle *FATFileSystem::open(const char* name, int flags) {
+ FFSDEBUG("open(%s) on filesystem [%s], drv [%d]\n", name, _name, _fsid);
+ char n[64];
+ sprintf(n, "%d:/%s", _fsid, name);
+
+ /* POSIX flags -> FatFS open mode */
+ BYTE openmode;
+ if(flags & O_RDWR) {
+ openmode = FA_READ|FA_WRITE;
+ } else if(flags & O_WRONLY) {
+ openmode = FA_WRITE;
+ } else {
+ openmode = FA_READ;
+ }
+ if(flags & O_CREAT) {
+ if(flags & O_TRUNC) {
+ openmode |= FA_CREATE_ALWAYS;
+ } else {
+ openmode |= FA_OPEN_ALWAYS;
+ }
+ }
+
+ FIL_t fh;
+ FRESULT res = f_open(&fh, n, openmode);
+ if(res) {
+ FFSDEBUG("f_open('w') failed (%d, %s)\n", res, FR_ERRORS[res]);
+ return NULL;
+ }
+ if(flags & O_APPEND) {
+ f_lseek(&fh, fh.fsize);
+ }
+ return new FATFileHandle(fh);
+}
+
+int FATFileSystem::remove(const char *filename) {
+ FRESULT res = f_unlink(filename);
+ if(res) {
+ FFSDEBUG("f_unlink() failed (%d, %s)\n", res, FR_ERRORS[res]);
+ return -1;
+ }
+ return 0;
+}
+
+int FATFileSystem::format() {
+ FFSDEBUG("format()\n");
+ FRESULT res = f_mkfs(_fsid, 0, 512); // Logical drive number, Partitioning rule, Allocation unit size (bytes per cluster)
+ if(res) {
+ FFSDEBUG("f_mkfs() failed (%d, %s)\n", res, FR_ERRORS[res]);
+ return -1;
+ }
+ return 0;
+}
+
+DirHandle *FATFileSystem::opendir(const char *name) {
+ DIR_t dir;
+ FRESULT res = f_opendir(&dir, name);
+ if(res != 0) {
+ return NULL;
+ }
+ return new FATDirHandle(dir);
+}
+
+int FATFileSystem::mkdir(const char *name, mode_t mode) {
+ FRESULT res = f_mkdir(name);
+ return res == 0 ? 0 : -1;
+}
+
+} // namespace mbed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ChaNFS/FATFileSystem.h Mon Nov 14 12:08:32 2011 +0000
@@ -0,0 +1,61 @@
+/* mbed Microcontroller Library - FATFileSystem
+ * Copyright (c) 2008, sford
+ */
+
+/* Library: FATFileSystem.h
+ * A library of stuff to make a fat filesystem on top of a block device
+ */
+
+#ifndef MBED_FATFILESYSTEM_H
+#define MBED_FATFILESYSTEM_H
+
+#ifndef FFSDEBUG_ENABLED
+#define FFSDEBUG_ENABLED 0
+#endif
+
+#if FFSDEBUG_ENABLED
+#define FFSDEBUG(FMT, ...) printf(FMT, ##__VA_ARGS__)
+#else
+#define FFSDEBUG(FMT, ...)
+#endif
+
+#include "FileSystemLike.h"
+#include "FileHandle.h"
+#include "ff.h"
+#include "diskio.h"
+
+namespace mbed {
+/* Class: FATFileSystem
+ * The class itself
+ */
+class FATFileSystem : public FileSystemLike {
+public:
+
+ FATFileSystem(const char* n);
+ virtual ~FATFileSystem();
+
+ /* Function: open
+ * open a file on the filesystem. never called directly
+ */
+ virtual FileHandle *open(const char* name, int flags);
+ virtual int remove(const char *filename);
+ virtual int format();
+ virtual DirHandle *opendir(const char *name);
+ virtual int mkdir(const char *name, mode_t mode);
+
+ FATFS _fs; // Work area (file system object) for logical drive
+ static FATFileSystem *_ffs[_DRIVES]; // FATFileSystem objects, as parallel to FatFs drives array
+ int _fsid;
+
+ virtual int disk_initialize() { return 0; }
+ virtual int disk_status() { return 0; }
+ virtual int disk_read(char *buffer, int sector) = 0;
+ virtual int disk_write(const char *buffer, int sector) = 0;
+ virtual int disk_sync() { return 0; }
+ virtual int disk_sectors() = 0;
+
+};
+
+}
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ChaNFSSD/.lib Mon Nov 14 12:08:32 2011 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/NeoBelerophon/libraries/ChaNFSSD/llyfwh \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ChaNFSSD/SDFileSystem.cpp Mon Nov 14 12:08:32 2011 +0000
@@ -0,0 +1,457 @@
+/* mbed SDFileSystem Library, for providing file access to SD cards
+ * Copyright (c) 2008-2010, sford
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* Introduction
+ * ------------
+ * SD and MMC cards support a number of interfaces, but common to them all
+ * is one based on SPI. This is the one I'm implmenting because it means
+ * it is much more portable even though not so performant, and we already
+ * have the mbed SPI Interface!
+ *
+ * The main reference I'm using is Chapter 7, "SPI Mode" of:
+ * http://www.sdcard.org/developers/tech/sdcard/pls/Simplified_Physical_Layer_Spec.pdf
+ *
+ * SPI Startup
+ * -----------
+ * The SD card powers up in SD mode. The SPI interface mode is selected by
+ * asserting CS low and sending the reset command (CMD0). The card will
+ * respond with a (R1) response.
+ *
+ * CMD8 is optionally sent to determine the voltage range supported, and
+ * indirectly determine whether it is a version 1.x SD/non-SD card or
+ * version 2.x. I'll just ignore this for now.
+ *
+ * ACMD41 is repeatedly issued to initialise the card, until "in idle"
+ * (bit 0) of the R1 response goes to '0', indicating it is initialised.
+ *
+ * You should also indicate whether the host supports High Capicity cards,
+ * and check whether the card is high capacity - i'll also ignore this
+ *
+ * SPI Protocol
+ * ------------
+ * The SD SPI protocol is based on transactions made up of 8-bit words, with
+ * the host starting every bus transaction by asserting the CS signal low. The
+ * card always responds to commands, data blocks and errors.
+ *
+ * The protocol supports a CRC, but by default it is off (except for the
+ * first reset CMD0, where the CRC can just be pre-calculated, and CMD8)
+ * I'll leave the CRC off I think!
+ *
+ * Standard capacity cards have variable data block sizes, whereas High
+ * Capacity cards fix the size of data block to 512 bytes. I'll therefore
+ * just always use the Standard Capacity cards with a block size of 512 bytes.
+ * This is set with CMD16.
+ *
+ * You can read and write single blocks (CMD17, CMD25) or multiple blocks
+ * (CMD18, CMD25). For simplicity, I'll just use single block accesses. When
+ * the card gets a read command, it responds with a response token, and then
+ * a data token or an error.
+ *
+ * SPI Command Format
+ * ------------------
+ * Commands are 6-bytes long, containing the command, 32-bit argument, and CRC.
+ *
+ * +---------------+------------+------------+-----------+----------+--------------+
+ * | 01 | cmd[5:0] | arg[31:24] | arg[23:16] | arg[15:8] | arg[7:0] | crc[6:0] | 1 |
+ * +---------------+------------+------------+-----------+----------+--------------+
+ *
+ * As I'm not using CRC, I can fix that byte to what is needed for CMD0 (0x95)
+ *
+ * All Application Specific commands shall be preceded with APP_CMD (CMD55).
+ *
+ * SPI Response Format
+ * -------------------
+ * The main response format (R1) is a status byte (normally zero). Key flags:
+ * idle - 1 if the card is in an idle state/initialising
+ * cmd - 1 if an illegal command code was detected
+ *
+ * +-------------------------------------------------+
+ * R1 | 0 | arg | addr | seq | crc | cmd | erase | idle |
+ * +-------------------------------------------------+
+ *
+ * R1b is the same, except it is followed by a busy signal (zeros) until
+ * the first non-zero byte when it is ready again.
+ *
+ * Data Response Token
+ * -------------------
+ * Every data block written to the card is acknowledged by a byte
+ * response token
+ *
+ * +----------------------+
+ * | xxx | 0 | status | 1 |
+ * +----------------------+
+ * 010 - OK!
+ * 101 - CRC Error
+ * 110 - Write Error
+ *
+ * Single Block Read and Write
+ * ---------------------------
+ *
+ * Block transfers have a byte header, followed by the data, followed
+ * by a 16-bit CRC. In our case, the data will always be 512 bytes.
+ *
+ * +------+---------+---------+- - - -+---------+-----------+----------+
+ * | 0xFE | data[0] | data[1] | | data[n] | crc[15:8] | crc[7:0] |
+ * +------+---------+---------+- - - -+---------+-----------+----------+
+ */
+
+#include "SDFileSystem.h"
+
+#define SD_COMMAND_TIMEOUT 5000
+
+SDFileSystem::SDFileSystem(PinName mosi, PinName miso, PinName sclk, PinName cs, const char* name) :
+ FATFileSystem(name), _spi(mosi, miso, sclk), _cs(cs) {
+ _cs = 1;
+}
+
+#define R1_IDLE_STATE (1 << 0)
+#define R1_ERASE_RESET (1 << 1)
+#define R1_ILLEGAL_COMMAND (1 << 2)
+#define R1_COM_CRC_ERROR (1 << 3)
+#define R1_ERASE_SEQUENCE_ERROR (1 << 4)
+#define R1_ADDRESS_ERROR (1 << 5)
+#define R1_PARAMETER_ERROR (1 << 6)
+
+// Types
+// - v1.x Standard Capacity
+// - v2.x Standard Capacity
+// - v2.x High Capacity
+// - Not recognised as an SD Card
+
+#define SDCARD_FAIL 0
+#define SDCARD_V1 1
+#define SDCARD_V2 2
+#define SDCARD_V2HC 3
+
+int SDFileSystem::initialise_card() {
+ // Set to 100kHz for initialisation, and clock card with cs = 1
+ _spi.frequency(100000);
+ _cs = 1;
+ for(int i=0; i<16; i++) {
+ _spi.write(0xFF);
+ }
+
+ // send CMD0, should return with all zeros except IDLE STATE set (bit 0)
+ if(_cmd(0, 0) != R1_IDLE_STATE) {
+ fprintf(stderr, "No disk, or could not put SD card in to SPI idle state\n");
+ return SDCARD_FAIL;
+ }
+
+ // send CMD8 to determine whther it is ver 2.x
+ int r = _cmd8();
+ if(r == R1_IDLE_STATE) {
+ return initialise_card_v2();
+ } else if(r == (R1_IDLE_STATE | R1_ILLEGAL_COMMAND)) {
+ return initialise_card_v1();
+ } else {
+ fprintf(stderr, "Not in idle state after sending CMD8 (not an SD card?)\n");
+ return SDCARD_FAIL;
+ }
+}
+
+int SDFileSystem::initialise_card_v1() {
+ for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
+ _cmd(55, 0);
+ if(_cmd(41, 0) == 0) {
+ return SDCARD_V1;
+ }
+ }
+
+ fprintf(stderr, "Timeout waiting for v1.x card\n");
+ return SDCARD_FAIL;
+}
+
+int SDFileSystem::initialise_card_v2() {
+
+ for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
+ _cmd(55, 0);
+ if(_cmd(41, 0) == 0) {
+ _cmd58();
+ return SDCARD_V2;
+ }
+ }
+
+ fprintf(stderr, "Timeout waiting for v2.x card\n");
+ return SDCARD_FAIL;
+}
+
+int SDFileSystem::disk_initialize() {
+
+ int i = initialise_card();
+// printf("init card = %d\n", i);
+// printf("OK\n");
+
+ _sectors = _sd_sectors();
+
+ // Set block length to 512 (CMD16)
+ if(_cmd(16, 512) != 0) {
+ fprintf(stderr, "Set 512-byte block timed out\n");
+ return 1;
+ }
+
+ _spi.frequency(1000000); // Set to 1MHz for data transfer
+ return 0;
+}
+
+int SDFileSystem::disk_write(const char *buffer, int block_number) {
+ // set write address for single block (CMD24)
+ if(_cmd(24, block_number * 512) != 0) {
+ return 1;
+ }
+
+ // send the data block
+ _write(buffer, 512);
+ return 0;
+}
+
+int SDFileSystem::disk_read(char *buffer, int block_number) {
+ // set read address for single block (CMD17)
+ if(_cmd(17, block_number * 512) != 0) {
+ return 1;
+ }
+
+ // receive the data
+ _read(buffer, 512);
+ return 0;
+}
+
+int SDFileSystem::disk_status() { return 0; }
+int SDFileSystem::disk_sync() { return 0; }
+int SDFileSystem::disk_sectors() { return _sectors; }
+
+// PRIVATE FUNCTIONS
+
+int SDFileSystem::_cmd(int cmd, int arg) {
+ _cs = 0;
+
+ // send a command
+ _spi.write(0x40 | cmd);
+ _spi.write(arg >> 24);
+ _spi.write(arg >> 16);
+ _spi.write(arg >> 8);
+ _spi.write(arg >> 0);
+ _spi.write(0x95);
+
+ // wait for the repsonse (response[7] == 0)
+ for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
+ int response = _spi.write(0xFF);
+ if(!(response & 0x80)) {
+ _cs = 1;
+ _spi.write(0xFF);
+ return response;
+ }
+ }
+ _cs = 1;
+ _spi.write(0xFF);
+ return -1; // timeout
+}
+int SDFileSystem::_cmdx(int cmd, int arg) {
+ _cs = 0;
+
+ // send a command
+ _spi.write(0x40 | cmd);
+ _spi.write(arg >> 24);
+ _spi.write(arg >> 16);
+ _spi.write(arg >> 8);
+ _spi.write(arg >> 0);
+ _spi.write(0x95);
+
+ // wait for the repsonse (response[7] == 0)
+ for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
+ int response = _spi.write(0xFF);
+ if(!(response & 0x80)) {
+ return response;
+ }
+ }
+ _cs = 1;
+ _spi.write(0xFF);
+ return -1; // timeout
+}
+
+
+int SDFileSystem::_cmd58() {
+ _cs = 0;
+ int arg = 0;
+
+ // send a command
+ _spi.write(0x40 | 58);
+ _spi.write(arg >> 24);
+ _spi.write(arg >> 16);
+ _spi.write(arg >> 8);
+ _spi.write(arg >> 0);
+ _spi.write(0x95);
+
+ // wait for the repsonse (response[7] == 0)
+ for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
+ int response = _spi.write(0xFF);
+ if(!(response & 0x80)) {
+ int ocr = _spi.write(0xFF) << 24;
+ ocr |= _spi.write(0xFF) << 16;
+ ocr |= _spi.write(0xFF) << 8;
+ ocr |= _spi.write(0xFF) << 0;
+// printf("OCR = 0x%08X\n", ocr);
+ _cs = 1;
+ _spi.write(0xFF);
+ return response;
+ }
+ }
+ _cs = 1;
+ _spi.write(0xFF);
+ return -1; // timeout
+}
+
+int SDFileSystem::_cmd8() {
+ _cs = 0;
+
+ // send a command
+ _spi.write(0x40 | 8); // CMD8
+ _spi.write(0x00); // reserved
+ _spi.write(0x00); // reserved
+ _spi.write(0x01); // 3.3v
+ _spi.write(0xAA); // check pattern
+ _spi.write(0x87); // crc
+
+ // wait for the repsonse (response[7] == 0)
+ for(int i=0; i<SD_COMMAND_TIMEOUT * 1000; i++) {
+ char response[5];
+ response[0] = _spi.write(0xFF);
+ if(!(response[0] & 0x80)) {
+ for(int j=1; j<5; j++) {
+ response[i] = _spi.write(0xFF);
+ }
+ _cs = 1;
+ _spi.write(0xFF);
+ return response[0];
+ }
+ }
+ _cs = 1;
+ _spi.write(0xFF);
+ return -1; // timeout
+}
+
+int SDFileSystem::_read(char *buffer, int length) {
+ _cs = 0;
+
+ // read until start byte (0xFF)
+ while(_spi.write(0xFF) != 0xFE);
+
+ // read data
+ for(int i=0; i<length; i++) {
+ buffer[i] = _spi.write(0xFF);
+ }
+ _spi.write(0xFF); // checksum
+ _spi.write(0xFF);
+
+ _cs = 1;
+ _spi.write(0xFF);
+ return 0;
+}
+
+int SDFileSystem::_write(const char *buffer, int length) {
+ _cs = 0;
+
+ // indicate start of block
+ _spi.write(0xFE);
+
+ // write the data
+ for(int i=0; i<length; i++) {
+ _spi.write(buffer[i]);
+ }
+
+ // write the checksum
+ _spi.write(0xFF);
+ _spi.write(0xFF);
+
+ // check the repsonse token
+ if((_spi.write(0xFF) & 0x1F) != 0x05) {
+ _cs = 1;
+ _spi.write(0xFF);
+ return 1;
+ }
+
+ // wait for write to finish
+ while(_spi.write(0xFF) == 0);
+
+ _cs = 1;
+ _spi.write(0xFF);
+ return 0;
+}
+
+static int ext_bits(char *data, int msb, int lsb) {
+ int bits = 0;
+ int size = 1 + msb - lsb;
+ for(int i=0; i<size; i++) {
+ int position = lsb + i;
+ int byte = 15 - (position >> 3);
+ int bit = position & 0x7;
+ int value = (data[byte] >> bit) & 1;
+ bits |= value << i;
+ }
+ return bits;
+}
+
+int SDFileSystem::_sd_sectors() {
+
+ // CMD9, Response R2 (R1 byte + 16-byte block read)
+ if(_cmdx(9, 0) != 0) {
+ fprintf(stderr, "Didn't get a response from the disk\n");
+ return 0;
+ }
+
+ char csd[16];
+ if(_read(csd, 16) != 0) {
+ fprintf(stderr, "Couldn't read csd response from disk\n");
+ return 0;
+ }
+
+ // csd_structure : csd[127:126]
+ // c_size : csd[73:62]
+ // c_size_mult : csd[49:47]
+ // read_bl_len : csd[83:80] - the *maximum* read block length
+
+ int csd_structure = ext_bits(csd, 127, 126);
+ int c_size = ext_bits(csd, 73, 62);
+ int c_size_mult = ext_bits(csd, 49, 47);
+ int read_bl_len = ext_bits(csd, 83, 80);
+
+// printf("CSD_STRUCT = %d\n", csd_structure);
+
+ if(csd_structure != 0) {
+ fprintf(stderr, "This disk tastes funny! I only know about type 0 CSD structures\n");
+ return 0;
+ }
+
+ // memory capacity = BLOCKNR * BLOCK_LEN
+ // where
+ // BLOCKNR = (C_SIZE+1) * MULT
+ // MULT = 2^(C_SIZE_MULT+2) (C_SIZE_MULT < 8)
+ // BLOCK_LEN = 2^READ_BL_LEN, (READ_BL_LEN < 12)
+
+ int block_len = 1 << read_bl_len;
+ int mult = 1 << (c_size_mult + 2);
+ int blocknr = (c_size + 1) * mult;
+ int capacity = blocknr * block_len;
+
+ int blocks = capacity / 512;
+
+ return blocks;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ChaNFSSD/SDFileSystem.h Mon Nov 14 12:08:32 2011 +0000
@@ -0,0 +1,81 @@
+/* mbed SDFileSystem Library, for providing file access to SD cards
+ * Copyright (c) 2008-2010, sford
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MBED_SDFILESYSTEM_H
+#define MBED_SDFILESYSTEM_H
+
+#include "mbed.h"
+#include "FATFileSystem.h"
+
+/** Access the filesystem on an SD Card using SPI
+ *
+ * @code
+ * #include "mbed.h"
+ * #include "SDFileSystem.h"
+ *
+ * SDFileSystem sd(p5, p6, p7, p12, "sd"); // mosi, miso, sclk, cs
+ *
+ * int main() {
+ * FILE *fp = fopen("/sd/myfile.txt", "w");
+ * fprintf(fp, "Hello World!\n");
+ * fclose(fp);
+ * }
+ */
+class SDFileSystem : public FATFileSystem {
+public:
+
+ /** Create the File System for accessing an SD Card using SPI
+ *
+ * @param mosi SPI mosi pin connected to SD Card
+ * @param miso SPI miso pin conencted to SD Card
+ * @param sclk SPI sclk pin connected to SD Card
+ * @param cs DigitalOut pin used as SD Card chip select
+ * @param name The name used to access the virtual filesystem
+ */
+ SDFileSystem(PinName mosi, PinName miso, PinName sclk, PinName cs, const char* name);
+ virtual int disk_initialize();
+ virtual int disk_write(const char *buffer, int block_number);
+ virtual int disk_read(char *buffer, int block_number);
+ virtual int disk_status();
+ virtual int disk_sync();
+ virtual int disk_sectors();
+
+protected:
+
+ int _cmd(int cmd, int arg);
+ int _cmdx(int cmd, int arg);
+ int _cmd8();
+ int _cmd58();
+ int initialise_card();
+ int initialise_card_v1();
+ int initialise_card_v2();
+
+ int _read(char *buffer, int length);
+ int _write(const char *buffer, int length);
+ int _sd_sectors();
+ int _sectors;
+
+ SPI _spi;
+ DigitalOut _cs;
+};
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBDevice.lib Mon Nov 14 12:08:32 2011 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/samux/libraries/USBDevice/m0nepw \ No newline at end of file
--- a/USBDevice/.lib Mon Nov 14 10:00:07 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -http://mbed.org/users/samux/libraries/USBDevice/m0hrm9 \ No newline at end of file
--- a/USBDevice/USBDevice/USBBusInterface.h Mon Nov 14 10:00:07 2011 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-/* USBBusInterface.h */
-/* USB Bus Interface */
-/* Copyright (c) 2011 ARM Limited. All rights reserved. */
-
-#ifndef USBBUSINTERFACE_H
-#define USBBUSINTERFACE_H
-
-#include "mbed.h"
-#include "USBEndpoints.h"
-
-class USBHAL {
-public:
- /* Configuration */
- USBHAL();
- ~USBHAL();
- void connect(void);
- void disconnect(void);
- void configureDevice(void);
- void unconfigureDevice(void);
- void setAddress(uint8_t address);
- void remoteWakeup(void);
-
- /* Endpoint 0 */
- void EP0setup(uint8_t *buffer);
- void EP0read(void);
- uint32_t EP0getReadResult(uint8_t *buffer);
- void EP0write(uint8_t *buffer, uint32_t size);
- void EP0getWriteResult(void);
- void EP0stall(void);
-
- /* Other endpoints */
- EP_STATUS endpointRead(uint8_t endpoint, uint32_t maximumSize);
- EP_STATUS endpointReadResult(uint8_t endpoint, uint8_t *data, uint32_t *bytesRead);
- EP_STATUS endpointWrite(uint8_t endpoint, uint8_t *data, uint32_t size);
- EP_STATUS endpointWriteResult(uint8_t endpoint);
- void stallEndpoint(uint8_t endpoint);
- void unstallEndpoint(uint8_t endpoint);
- bool realiseEndpoint(uint8_t endpoint, uint32_t maxPacket, uint32_t options);
- bool getEndpointStallState(unsigned char endpoint);
-
-protected:
- virtual void busReset(void){};
- virtual void EP0setupCallback(void){};
- virtual void EP0out(void){};
- virtual void EP0in(void){};
- virtual void connectStateChanged(unsigned int connected){};
- virtual void suspendStateChanged(unsigned int suspended){};
- virtual void SOF(int frameNumber){};
- virtual bool EP1_OUT_callback(){return false;};
- virtual bool EP1_IN_callback(){return false;};
- virtual bool EP2_OUT_callback(){return false;};
- virtual bool EP2_IN_callback(){return false;};
- virtual bool EP3_OUT_callback(){return false;};
- virtual bool EP3_IN_callback(){return false;};
-
-private:
- void usbisr(void);
- static void _usbisr(void);
- static USBHAL * instance;
-};
-#endif
-
-
--- a/USBDevice/USBDevice/USBBusInterface_LPC11U.cpp Mon Nov 14 10:00:07 2011 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,699 +0,0 @@
-// USBBusInterface_LPC11U.c
-// USB Bus Interface for NXP LPC11Uxx
-// Copyright (c) 2011 ARM Limited. All rights reserved.
-
-// Reference:
-// NXP UM10462 LPC11U1x User manual Rev. 1 � 14 April 2011
-
-#ifdef TARGET_LPC11U24
-
-#include "USBBusInterface.h"
-
-USBHAL * USBHAL::instance;
-
-
-// Valid physical endpoint numbers are 0 to (NUMBER_OF_PHYSICAL_ENDPOINTS-1)
-#define LAST_PHYSICAL_ENDPOINT (NUMBER_OF_PHYSICAL_ENDPOINTS-1)
-
-// Convert physical endpoint number to register bit
-#define EP(endpoint) (1UL<<endpoint)
-
-// Convert physical to logical
-#define PHY_TO_LOG(endpoint) ((endpoint)>>1)
-
-// Get endpoint direction
-#define IN_EP(endpoint) ((endpoint) & 1U ? true : false)
-#define OUT_EP(endpoint) ((endpoint) & 1U ? false : true)
-
-// USB RAM
-#define USB_RAM_START (0x20004000)
-#define USB_RAM_SIZE (0x00000800)
-
-// SYSAHBCLKCTRL
-#define CLK_USB (1UL<<14)
-#define CLK_USBRAM (1UL<<27)
-
-// USB Information register
-#define FRAME_NR(a) ((a) & 0x7ff) // Frame number
-
-// USB Device Command/Status register
-#define DEV_ADDR_MASK (0x7f) // Device address
-#define DEV_ADDR(a) ((a) & DEV_ADDR_MASK)
-#define DEV_EN (1UL<<7) // Device enable
-#define SETUP (1UL<<8) // SETUP token received
-#define PLL_ON (1UL<<9) // PLL enabled in suspend
-#define DCON (1UL<<16) // Device status - connect
-#define DSUS (1UL<<17) // Device status - suspend
-#define DCON_C (1UL<<24) // Connect change
-#define DSUS_C (1UL<<25) // Suspend change
-#define DRES_C (1UL<<26) // Reset change
-#define VBUSDEBOUNCED (1UL<<28) // Vbus detected
-
-// Endpoint Command/Status list
-#define CMDSTS_A (1UL<<31) // Active
-#define CMDSTS_D (1UL<<30) // Disable
-#define CMDSTS_S (1UL<<29) // Stall
-#define CMDSTS_TR (1UL<<28) // Toggle Reset
-#define CMDSTS_RF (1UL<<27) // Rate Feedback mode
-#define CMDSTS_TV (1UL<<27) // Toggle Value
-#define CMDSTS_T (1UL<<26) // Endpoint Type
-#define CMDSTS_NBYTES(n) (((n)&0x3ff)<<16) // Number of bytes
-#define CMDSTS_ADDRESS_OFFSET(a) (((a)>>6)&0xffff) // Buffer start address
-
-#define BYTES_REMAINING(s) (((s)>>16)&0x3ff) // Bytes remaining after transfer
-
-// USB Non-endpoint interrupt sources
-#define FRAME_INT (1UL<<30)
-#define DEV_INT (1UL<<31)
-
-static int epComplete = 0;
-
-// One entry for a double-buffered logical endpoint in the endpoint
-// command/status list. Endpoint 0 is single buffered, out[1] is used
-// for the SETUP packet and in[1] is not used
-typedef __packed struct {
- uint32_t out[2];
- uint32_t in[2];
-} EP_COMMAND_STATUS;
-
-typedef __packed struct {
- uint8_t out[MAX_PACKET_SIZE_EP0];
- uint8_t in[MAX_PACKET_SIZE_EP0];
- uint8_t setup[SETUP_PACKET_SIZE];
-} CONTROL_TRANSFER;
-
-typedef __packed struct {
- uint32_t maxPacket;
- uint32_t buffer[2];
- uint32_t options;
-} EP_STATE;
-
-static volatile EP_STATE endpointState[NUMBER_OF_PHYSICAL_ENDPOINTS];
-
-// Pointer to the endpoint command/status list
-static EP_COMMAND_STATUS *ep = NULL;
-
-// Pointer to endpoint 0 data (IN/OUT and SETUP)
-static CONTROL_TRANSFER *ct = NULL;
-
-// Shadow DEVCMDSTAT register to avoid accidentally clearing flags or
-// initiating a remote wakeup event.
-static volatile uint32_t devCmdStat;
-
-// Pointers used to allocate USB RAM
-static uint32_t usbRamPtr = USB_RAM_START;
-static uint32_t epRamPtr = 0; // Buffers for endpoints > 0 start here
-
-#define ROUND_UP_TO_MULTIPLE(x, m) ((((x)+((m)-1))/(m))*(m))
-
-void USBMemCopy(uint8_t *dst, uint8_t *src, uint32_t size);
-void USBMemCopy(uint8_t *dst, uint8_t *src, uint32_t size) {
- if (size > 0) {
- do {
- *dst++ = *src++;
- } while (--size > 0);
- }
-}
-
-
-USBHAL::USBHAL(void) {
- NVIC_DisableIRQ(USB_IRQn);
-
- // nUSB_CONNECT output
- LPC_IOCON->PIO0_6 = 0x00000001;
-
- // Enable clocks (USB registers, USB RAM)
- LPC_SYSCON->SYSAHBCLKCTRL |= CLK_USB | CLK_USBRAM;
-
- // Ensure device disconnected (DCON not set)
- LPC_USB->DEVCMDSTAT = 0;
-
- // to ensure that the USB host sees the device as
- // disconnected if the target CPU is reset.
- wait(0.3);
-
- // Reserve space in USB RAM for endpoint command/status list
- // Must be 256 byte aligned
- usbRamPtr = ROUND_UP_TO_MULTIPLE(usbRamPtr, 256);
- ep = (EP_COMMAND_STATUS *)usbRamPtr;
- usbRamPtr += (sizeof(EP_COMMAND_STATUS) * NUMBER_OF_LOGICAL_ENDPOINTS);
- LPC_USB->EPLISTSTART = (uint32_t)(ep) & 0xffffff00;
-
- // Reserve space in USB RAM for Endpoint 0
- // Must be 64 byte aligned
- usbRamPtr = ROUND_UP_TO_MULTIPLE(usbRamPtr, 64);
- ct = (CONTROL_TRANSFER *)usbRamPtr;
- usbRamPtr += sizeof(CONTROL_TRANSFER);
- LPC_USB->DATABUFSTART =(uint32_t)(ct) & 0xffc00000;
-
- // Setup command/status list for EP0
- ep[0].out[0] = 0;
- ep[0].in[0] = 0;
- ep[0].out[1] = CMDSTS_ADDRESS_OFFSET((uint32_t)ct->setup);
-
- // Route all interrupts to IRQ, some can be routed to
- // USB_FIQ if you wish.
- LPC_USB->INTROUTING = 0;
-
- // Set device address 0, enable USB device, no remote wakeup
- devCmdStat = DEV_ADDR(0) | DEV_EN | DSUS;
- LPC_USB->DEVCMDSTAT = devCmdStat;
-
- // Enable interrupts for device events and EP0
- LPC_USB->INTEN = DEV_INT | EP(EP0IN) | EP(EP0OUT);
- instance = this;
-
- //attach IRQ handler and enable interrupts
- NVIC_SetVector(USB_IRQn, (uint32_t)&_usbisr);
- NVIC_EnableIRQ(USB_IRQn);
-}
-
-USBHAL::~USBHAL(void) {
- // Ensure device disconnected (DCON not set)
- LPC_USB->DEVCMDSTAT = 0;
-
- // Disable USB interrupts
- NVIC_DisableIRQ(USB_IRQn);
-}
-
-void USBHAL::connect(void) {
- devCmdStat |= DCON;
- LPC_USB->DEVCMDSTAT = devCmdStat;
-}
-
-void USBHAL::disconnect(void) {
- devCmdStat &= ~DCON;
- LPC_USB->DEVCMDSTAT = devCmdStat;
-}
-
-void USBHAL::configureDevice(void) {
-}
-
-void USBHAL::unconfigureDevice(void) {
-}
-
-void USBHAL::EP0setup(uint8_t *buffer) {
- // Copy setup packet data
- USBMemCopy(buffer, ct->setup, SETUP_PACKET_SIZE);
-}
-
-void USBHAL::EP0read(void) {
- // Start an endpoint 0 read
-
- // The USB ISR will call USBDevice_EP0out() when a packet has been read,
- // the USBDevice layer then calls USBBusInterface_EP0getReadResult() to
- // read the data.
-
- ep[0].out[0] = CMDSTS_A |CMDSTS_NBYTES(MAX_PACKET_SIZE_EP0) \
- | CMDSTS_ADDRESS_OFFSET((uint32_t)ct->out);
-}
-
-uint32_t USBHAL::EP0getReadResult(uint8_t *buffer) {
- // Complete an endpoint 0 read
- uint32_t bytesRead;
-
- // Find how many bytes were read
- bytesRead = MAX_PACKET_SIZE_EP0 - BYTES_REMAINING(ep[0].out[0]);
-
- // Copy data
- USBMemCopy(buffer, ct->out, bytesRead);
- return bytesRead;
-}
-
-void USBHAL::EP0write(uint8_t *buffer, uint32_t size) {
- // Start and endpoint 0 write
-
- // The USB ISR will call USBDevice_EP0in() when the data has
- // been written, the USBDevice layer then calls
- // USBBusInterface_EP0getWriteResult() to complete the transaction.
-
- // Copy data
- USBMemCopy(ct->in, buffer, size);
-
- // Start transfer
- ep[0].in[0] = CMDSTS_A | CMDSTS_NBYTES(size) \
- | CMDSTS_ADDRESS_OFFSET((uint32_t)ct->in);
-}
-
-
-EP_STATUS USBHAL::endpointRead(uint8_t endpoint, uint32_t maximumSize) {
- uint8_t bf = 0;
-
- //check which buffer must be filled
- if (LPC_USB->EPBUFCFG & EP(endpoint)) {
- // Double buffered
- if (LPC_USB->EPINUSE & EP(endpoint)) {
- bf = 1;
- } else {
- bf = 0;
- }
- }
-
- //Active the endpoint for reading
- ep[PHY_TO_LOG(endpoint)].out[bf] = CMDSTS_A | CMDSTS_NBYTES(maximumSize) \
- | CMDSTS_ADDRESS_OFFSET((uint32_t)ct->out);
- return EP_PENDING;
-}
-
-EP_STATUS USBHAL::endpointReadResult(uint8_t endpoint, uint8_t *data, uint32_t *bytesRead) {
-
- uint8_t bf = 0;
-
- if (!(epComplete & EP(endpoint)))
- return EP_PENDING;
- else {
- epComplete &= ~EP(endpoint);
-
- //check which buffer has been filled
- if (LPC_USB->EPBUFCFG & EP(endpoint)) {
- // Double buffered (here we read the previous buffer which was used)
- if (LPC_USB->EPINUSE & EP(endpoint)) {
- bf = 0;
- } else {
- bf = 1;
- }
- }
-
- // Find how many bytes were read
- *bytesRead = (uint32_t) (endpointState[endpoint].maxPacket - BYTES_REMAINING(ep[PHY_TO_LOG(endpoint)].out[bf]));
-
- // Copy data
- USBMemCopy(data, ct->out, *bytesRead);
- return EP_COMPLETED;
- }
-}
-
-void USBHAL::EP0getWriteResult(void) {
- // Complete an endpoint 0 write
-
- // Nothing required for this target
- return;
-}
-
-void USBHAL::EP0stall(void) {
- ep[0].in[0] = CMDSTS_S;
- ep[0].out[0] = CMDSTS_S;
-}
-
-void USBHAL::setAddress(uint8_t address) {
- devCmdStat &= ~DEV_ADDR_MASK;
- devCmdStat |= DEV_ADDR(address);
- LPC_USB->DEVCMDSTAT = devCmdStat;
-}
-
-EP_STATUS USBHAL::endpointWrite(uint8_t endpoint, uint8_t *data, uint32_t size) {
- uint32_t flags = 0;
- uint32_t bf;
-
- // Validate parameters
- if (data == NULL) {
- return EP_INVALID;
- }
-
- if (endpoint > LAST_PHYSICAL_ENDPOINT) {
- return EP_INVALID;
- }
-
- if ((endpoint==EP0IN) || (endpoint==EP0OUT)) {
- return EP_INVALID;
- }
-
- if (size > endpointState[endpoint].maxPacket) {
- return EP_INVALID;
- }
-
- if (LPC_USB->EPBUFCFG & EP(endpoint)) {
- // Double buffered
- if (LPC_USB->EPINUSE & EP(endpoint)) {
- bf = 1;
- } else {
- bf = 0;
- }
- } else {
- // Single buffered
- bf = 0;
- }
-
- // Check if already active
- if (ep[PHY_TO_LOG(endpoint)].in[bf] & CMDSTS_A) {
- return EP_INVALID;
- }
-
- // Check if stalled
- if (ep[PHY_TO_LOG(endpoint)].in[bf] & CMDSTS_S) {
- return EP_STALLED;
- }
-
- // Copy data to USB RAM
- USBMemCopy((uint8_t *)endpointState[endpoint].buffer[bf], data, size);
-
- // Add options
- if (endpointState[endpoint].options & RATE_FEEDBACK_MODE) {
- flags |= CMDSTS_RF;
- }
-
- if (endpointState[endpoint].options & ISOCHRONOUS) {
- flags |= CMDSTS_T;
- }
-
- // Add transfer
- ep[PHY_TO_LOG(endpoint)].in[bf] = CMDSTS_ADDRESS_OFFSET( \
- endpointState[endpoint].buffer[bf]) \
- | CMDSTS_NBYTES(size) | CMDSTS_A | flags;
-
- return EP_PENDING;
-}
-
-EP_STATUS USBHAL::endpointWriteResult(uint8_t endpoint) {
- uint32_t bf;
- // Validate parameters
-
- if (endpoint > LAST_PHYSICAL_ENDPOINT) {
- return EP_INVALID;
- }
-
- if (OUT_EP(endpoint)) {
- return EP_INVALID;
- }
-
- if (LPC_USB->EPBUFCFG & EP(endpoint)) {
- // Double buffered // TODO: FIX THIS
- if (LPC_USB->EPINUSE & EP(endpoint)) {
- bf = 1;
- } else {
- bf = 0;
- }
- } else {
- // Single buffered
- bf = 0;
- }
-
- // Check if endpoint still active
- if (ep[PHY_TO_LOG(endpoint)].in[bf] & CMDSTS_A) {
- return EP_PENDING;
- }
-
- // Check if stalled
- if (ep[PHY_TO_LOG(endpoint)].in[bf] & CMDSTS_S) {
- return EP_STALLED;
- }
-
- return EP_COMPLETED;
-}
-
-void USBHAL::stallEndpoint(uint8_t endpoint) {
-
- // TODO: should this clear active bit?
-
- if (IN_EP(endpoint)) {
- ep[PHY_TO_LOG(endpoint)].in[0] |= CMDSTS_S;
- ep[PHY_TO_LOG(endpoint)].in[1] |= CMDSTS_S;
- } else {
- ep[PHY_TO_LOG(endpoint)].out[0] |= CMDSTS_S;
- ep[PHY_TO_LOG(endpoint)].out[1] |= CMDSTS_S;
- }
-}
-
-void USBHAL::unstallEndpoint(uint8_t endpoint) {
- if (LPC_USB->EPBUFCFG & EP(endpoint)) {
- // Double buffered
- if (IN_EP(endpoint)) {
- ep[PHY_TO_LOG(endpoint)].in[0] = 0; // S = 0
- ep[PHY_TO_LOG(endpoint)].in[1] = 0; // S = 0
-
- if (LPC_USB->EPINUSE & EP(endpoint)) {
- ep[PHY_TO_LOG(endpoint)].in[1] = CMDSTS_TR; // S =0, TR=1, TV = 0
- } else {
- ep[PHY_TO_LOG(endpoint)].in[0] = CMDSTS_TR; // S =0, TR=1, TV = 0
- }
- } else {
- ep[PHY_TO_LOG(endpoint)].out[0] = 0; // S = 0
- ep[PHY_TO_LOG(endpoint)].out[1] = 0; // S = 0
-
- if (LPC_USB->EPINUSE & EP(endpoint)) {
- ep[PHY_TO_LOG(endpoint)].out[1] = CMDSTS_TR; // S =0, TR=1, TV = 0
- } else {
- ep[PHY_TO_LOG(endpoint)].out[0] = CMDSTS_TR; // S =0, TR=1, TV = 0
- }
- }
- } else {
- // Single buffered
- if (IN_EP(endpoint)) {
- ep[PHY_TO_LOG(endpoint)].in[0] = CMDSTS_TR; // S=0, TR=1, TV = 0
- } else {
- ep[PHY_TO_LOG(endpoint)].out[0] = CMDSTS_TR; // S=0, TR=1, TV = 0
- }
- }
-}
-
-bool USBHAL::getEndpointStallState(unsigned char endpoint) {
- if (IN_EP(endpoint)) {
- if (LPC_USB->EPINUSE & EP(endpoint)) {
- if (ep[PHY_TO_LOG(endpoint)].in[1] & CMDSTS_S) {
- return true;
- }
- } else {
- if (ep[PHY_TO_LOG(endpoint)].in[0] & CMDSTS_S) {
- return true;
- }
- }
- } else {
- if (LPC_USB->EPINUSE & EP(endpoint)) {
- if (ep[PHY_TO_LOG(endpoint)].out[1] & CMDSTS_S) {
- return true;
- }
- } else {
- if (ep[PHY_TO_LOG(endpoint)].out[0] & CMDSTS_S) {
- return true;
- }
- }
- }
-
- return false;
-}
-
-bool USBHAL::realiseEndpoint(uint8_t endpoint, uint32_t maxPacket, uint32_t options) {
- uint32_t tmpEpRamPtr;
-
- if (endpoint > LAST_PHYSICAL_ENDPOINT) {
- return false;
- }
-
- // Not applicable to the control endpoints
- if ((endpoint==EP0IN) || (endpoint==EP0OUT)) {
- return false;
- }
-
- // Allocate buffers in USB RAM
- tmpEpRamPtr = epRamPtr;
-
- // Must be 64 byte aligned
- tmpEpRamPtr = ROUND_UP_TO_MULTIPLE(tmpEpRamPtr, 64);
-
- if ((tmpEpRamPtr + maxPacket) > (USB_RAM_START + USB_RAM_SIZE)) {
- // Out of memory
- return false;
- }
-
- // Allocate first buffer
- endpointState[endpoint].buffer[0] = tmpEpRamPtr;
- tmpEpRamPtr += maxPacket;
-
- if (!(options & SINGLE_BUFFERED)) {
- // Must be 64 byte aligned
- tmpEpRamPtr = ROUND_UP_TO_MULTIPLE(tmpEpRamPtr, 64);
-
- if ((tmpEpRamPtr + maxPacket) > (USB_RAM_START + USB_RAM_SIZE)) {
- // Out of memory
- return false;
- }
-
- // Allocate second buffer
- endpointState[endpoint].buffer[1] = tmpEpRamPtr;
- tmpEpRamPtr += maxPacket;
- }
-
- // Commit to this USB RAM allocation
- epRamPtr = tmpEpRamPtr;
-
- // Remaining endpoint state values
- endpointState[endpoint].maxPacket = maxPacket;
- endpointState[endpoint].options = options;
-
- // Enable double buffering if required
- if (options & SINGLE_BUFFERED) {
- LPC_USB->EPBUFCFG &= ~EP(endpoint);
- } else {
- // Double buffered
- LPC_USB->EPBUFCFG |= EP(endpoint);
- }
-
- // Enable interrupt
- LPC_USB->INTEN |= EP(endpoint);
-
- // Enable endpoint
- unstallEndpoint(endpoint);
- return true;
-}
-
-void USBHAL::remoteWakeup(void) {
- // Clearing DSUS bit initiates a remote wakeup if the
- // device is currently enabled and suspended - otherwise
- // it has no effect.
- LPC_USB->DEVCMDSTAT = devCmdStat & ~DSUS;
-}
-
-
-static void disableEndpoints(void) {
- uint32_t logEp;
-
- // Ref. Table 158 "When a bus reset is received, software
- // must set the disable bit of all endpoints to 1".
-
- for (logEp = 1; logEp < NUMBER_OF_LOGICAL_ENDPOINTS; logEp++) {
- ep[logEp].out[0] = CMDSTS_D;
- ep[logEp].out[1] = CMDSTS_D;
- ep[logEp].in[0] = CMDSTS_D;
- ep[logEp].in[1] = CMDSTS_D;
- }
-
- // Start of USB RAM for endpoints > 0
- epRamPtr = usbRamPtr;
-}
-
-
-
-void USBHAL::_usbisr(void) {
- instance->usbisr();
-}
-
-
-void USBHAL::usbisr(void) {
- // Start of frame
- if (LPC_USB->INTSTAT & FRAME_INT) {
- // Clear SOF interrupt
- LPC_USB->INTSTAT = FRAME_INT;
-
- // SOF event, read frame number
- SOF(FRAME_NR(LPC_USB->INFO));
- }
-
- // Device state
- if (LPC_USB->INTSTAT & DEV_INT) {
- LPC_USB->INTSTAT = DEV_INT;
-
- if (LPC_USB->DEVCMDSTAT & DCON_C) {
- // Connect status changed
- LPC_USB->DEVCMDSTAT = devCmdStat | DCON_C;
-
- connectStateChanged((LPC_USB->DEVCMDSTAT & DCON) != 0);
- }
-
- if (LPC_USB->DEVCMDSTAT & DSUS_C) {
- // Suspend status changed
- LPC_USB->DEVCMDSTAT = devCmdStat | DSUS_C;
-
- suspendStateChanged((LPC_USB->DEVCMDSTAT & DSUS) != 0);
- }
-
- if (LPC_USB->DEVCMDSTAT & DRES_C) {
- // Bus reset
- LPC_USB->DEVCMDSTAT = devCmdStat | DRES_C;
-
- // Disable endpoints > 0
- disableEndpoints();
-
- // Bus reset event
- busReset();
- }
- }
-
- // Endpoint 0
- if (LPC_USB->INTSTAT & EP(EP0OUT)) {
- // Clear EP0OUT/SETUP interrupt
- LPC_USB->INTSTAT = EP(EP0OUT);
-
- // Check if SETUP
- if (LPC_USB->DEVCMDSTAT & SETUP) {
- // Clear Active and Stall bits for EP0
- // Documentation does not make it clear if we must use the
- // EPSKIP register to achieve this, Fig. 16 and NXP reference
- // code suggests we can just clear the Active bits - check with
- // NXP to be sure.
- ep[0].in[0] = 0;
- ep[0].out[0] = 0;
-
- // Clear EP0IN interrupt
- LPC_USB->INTSTAT = EP(EP0IN);
-
- // Clear SETUP (and INTONNAK_CI/O) in device status register
- LPC_USB->DEVCMDSTAT = devCmdStat | SETUP;
-
- // EP0 SETUP event (SETUP data received)
- EP0setupCallback();
- } else {
- // EP0OUT ACK event (OUT data received)
- EP0out();
- }
- }
-
- if (LPC_USB->INTSTAT & EP(EP0IN)) {
- // Clear EP0IN interrupt
- LPC_USB->INTSTAT = EP(EP0IN);
-
- // EP0IN ACK event (IN data sent)
- EP0in();
- }
-
- if (LPC_USB->INTSTAT & EP(EP1IN)) {
- // Clear EP1IN interrupt
- LPC_USB->INTSTAT = EP(EP1IN);
- epComplete |= EP(EP1IN);
- if(EP1_IN_callback())
- epComplete &= ~EP(EP1IN);
- }
-
- if (LPC_USB->INTSTAT & EP(EP1OUT)) {
- // Clear EP1OUT interrupt
- LPC_USB->INTSTAT = EP(EP1OUT);
- epComplete |= EP(EP1OUT);
- if(EP1_OUT_callback())
- epComplete &= ~EP(EP1OUT);
- }
-
- if (LPC_USB->INTSTAT & EP(EP2IN)) {
- // Clear EPBULK_IN interrupt
- LPC_USB->INTSTAT = EP(EP2IN);
- epComplete |= EP(EP2IN);
- if(EP2_IN_callback())
- epComplete &= ~EP(EP2IN);
- }
-
- if (LPC_USB->INTSTAT & EP(EP2OUT)) {
- // Clear EPBULK_OUT interrupt
- LPC_USB->INTSTAT = EP(EP2OUT);
- epComplete |= EP(EP2OUT);
- //Call callback function. If true, clear epComplete
- if(EP2_OUT_callback())
- epComplete &= ~EP(EP2OUT);
- }
-
- if (LPC_USB->INTSTAT & EP(EP3IN)) {
- // Clear EP3_IN interrupt
- LPC_USB->INTSTAT = EP(EP3IN);
- epComplete |= EP(EP3IN);
- if(EP3_IN_callback())
- epComplete &= ~EP(EP3IN);
- }
-
- if (LPC_USB->INTSTAT & EP(EP3OUT)) {
- // Clear EP3_OUT interrupt
- LPC_USB->INTSTAT = EP(EP3OUT);
- epComplete |= EP(EP3OUT);
- //Call callback function. If true, clear epComplete
- if(EP3_OUT_callback())
- epComplete &= ~EP(EP3OUT);
- }
-}
-
-#endif
\ No newline at end of file
--- a/USBDevice/USBDevice/USBBusInterface_LPC17_LPC23.cpp Mon Nov 14 10:00:07 2011 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,682 +0,0 @@
-// USBBusInterface_LPC17_LPC23.c
-// USB Bus Interface for NXP LPC1768 and LPC2368
-// Copyright (c) 2011 ARM Limited. All rights reserved.
-
-#ifdef TARGET_LPC1768
-
-#include "USBBusInterface.h"
-
-
-// Get endpoint direction
-#define IN_EP(endpoint) ((endpoint) & 1U ? true : false)
-#define OUT_EP(endpoint) ((endpoint) & 1U ? false : true)
-
-// Convert physical endpoint number to register bit
-#define EP(endpoint) (1UL<<endpoint)
-
-// Power Control for Peripherals register
-#define PCUSB (1UL<<31)
-
-// USB Clock Control register
-#define DEV_CLK_EN (1UL<<1)
-#define AHB_CLK_EN (1UL<<4)
-
-// USB Clock Status register
-#define DEV_CLK_ON (1UL<<1)
-#define AHB_CLK_ON (1UL<<4)
-
-// USB Device Interupt registers
-#define FRAME (1UL<<0)
-#define EP_FAST (1UL<<1)
-#define EP_SLOW (1UL<<2)
-#define DEV_STAT (1UL<<3)
-#define CCEMPTY (1UL<<4)
-#define CDFULL (1UL<<5)
-#define RxENDPKT (1UL<<6)
-#define TxENDPKT (1UL<<7)
-#define EP_RLZED (1UL<<8)
-#define ERR_INT (1UL<<9)
-
-// USB Control register
-#define RD_EN (1<<0)
-#define WR_EN (1<<1)
-#define LOG_ENDPOINT(endpoint) ((endpoint>>1)<<2)
-
-// USB Receive Packet Length register
-#define DV (1UL<<10)
-#define PKT_RDY (1UL<<11)
-#define PKT_LNGTH_MASK (0x3ff)
-
-// Serial Interface Engine (SIE)
-#define SIE_WRITE (0x01)
-#define SIE_READ (0x02)
-#define SIE_COMMAND (0x05)
-#define SIE_CMD_CODE(phase, data) ((phase<<8)|(data<<16))
-
-// SIE Command codes
-#define SIE_CMD_SET_ADDRESS (0xD0)
-#define SIE_CMD_CONFIGURE_DEVICE (0xD8)
-#define SIE_CMD_SET_MODE (0xF3)
-#define SIE_CMD_READ_FRAME_NUMBER (0xF5)
-#define SIE_CMD_READ_TEST_REGISTER (0xFD)
-#define SIE_CMD_SET_DEVICE_STATUS (0xFE)
-#define SIE_CMD_GET_DEVICE_STATUS (0xFE)
-#define SIE_CMD_GET_ERROR_CODE (0xFF)
-#define SIE_CMD_READ_ERROR_STATUS (0xFB)
-
-#define SIE_CMD_SELECT_ENDPOINT(endpoint) (0x00+endpoint)
-#define SIE_CMD_SELECT_ENDPOINT_CLEAR_INTERRUPT(endpoint) (0x40+endpoint)
-#define SIE_CMD_SET_ENDPOINT_STATUS(endpoint) (0x40+endpoint)
-
-#define SIE_CMD_CLEAR_BUFFER (0xF2)
-#define SIE_CMD_VALIDATE_BUFFER (0xFA)
-
-// SIE Device Status register
-#define SIE_DS_CON (1<<0)
-#define SIE_DS_CON_CH (1<<1)
-#define SIE_DS_SUS (1<<2)
-#define SIE_DS_SUS_CH (1<<3)
-#define SIE_DS_RST (1<<4)
-
-// SIE Device Set Address register
-#define SIE_DSA_DEV_EN (1<<7)
-
-// SIE Configue Device register
-#define SIE_CONF_DEVICE (1<<0)
-
-// Select Endpoint register
-#define SIE_SE_FE (1<<0)
-#define SIE_SE_ST (1<<1)
-#define SIE_SE_STP (1<<2)
-#define SIE_SE_PO (1<<3)
-#define SIE_SE_EPN (1<<4)
-#define SIE_SE_B_1_FULL (1<<5)
-#define SIE_SE_B_2_FULL (1<<6)
-
-// Set Endpoint Status command
-#define SIE_SES_ST (1<<0)
-#define SIE_SES_DA (1<<5)
-#define SIE_SES_RF_MO (1<<6)
-#define SIE_SES_CND_ST (1<<7)
-
-
-USBHAL * USBHAL::instance;
-
-volatile int epComplete;
-uint32_t endpointStallState;
-
-static void SIECommand(uint32_t command)
-{
- // The command phase of a SIE transaction
- LPC_USB->USBDevIntClr = CCEMPTY;
- LPC_USB->USBCmdCode = SIE_CMD_CODE(SIE_COMMAND, command);
- while (!(LPC_USB->USBDevIntSt & CCEMPTY));
-}
-
-static void SIEWriteData(uint8_t data)
-{
- // The data write phase of a SIE transaction
- LPC_USB->USBDevIntClr = CCEMPTY;
- LPC_USB->USBCmdCode = SIE_CMD_CODE(SIE_WRITE, data);
- while (!(LPC_USB->USBDevIntSt & CCEMPTY));
-}
-
-static uint8_t SIEReadData(uint32_t command)
-{
- // The data read phase of a SIE transaction
- LPC_USB->USBDevIntClr = CDFULL;
- LPC_USB->USBCmdCode = SIE_CMD_CODE(SIE_READ, command);
- while (!(LPC_USB->USBDevIntSt & CDFULL));
- return (uint8_t)LPC_USB->USBCmdData;
-}
-
-static void SIEsetDeviceStatus(uint8_t status)
-{
- // Write SIE device status register
- SIECommand(SIE_CMD_SET_DEVICE_STATUS);
- SIEWriteData(status);
-}
-
-static uint8_t SIEgetDeviceStatus(void)
-{
- // Read SIE device status register
- SIECommand(SIE_CMD_GET_DEVICE_STATUS);
- return SIEReadData(SIE_CMD_GET_DEVICE_STATUS);
-}
-
-void SIEsetAddress(uint8_t address)
-{
- // Write SIE device address register
- SIECommand(SIE_CMD_SET_ADDRESS);
- SIEWriteData((address & 0x7f) | SIE_DSA_DEV_EN);
-}
-
-static uint8_t SIEselectEndpoint(uint8_t endpoint)
-{
- // SIE select endpoint command
- SIECommand(SIE_CMD_SELECT_ENDPOINT(endpoint));
- return SIEReadData(SIE_CMD_SELECT_ENDPOINT(endpoint));
-}
-
-static uint8_t SIEclearBuffer(void)
-{
- // SIE clear buffer command
- SIECommand(SIE_CMD_CLEAR_BUFFER);
- return SIEReadData(SIE_CMD_CLEAR_BUFFER);
-}
-
-static void SIEvalidateBuffer(void)
-{
- // SIE validate buffer command
- SIECommand(SIE_CMD_VALIDATE_BUFFER);
-}
-
-static void SIEsetEndpointStatus(uint8_t endpoint, uint8_t status)
-{
- // SIE set endpoint status command
- SIECommand(SIE_CMD_SET_ENDPOINT_STATUS(endpoint));
- SIEWriteData(status);
-}
-
-static uint16_t SIEgetFrameNumber(void) __attribute__ ((unused));
-static uint16_t SIEgetFrameNumber(void)
-{
- // Read current frame number
- uint16_t lowByte;
- uint16_t highByte;
-
- SIECommand(SIE_CMD_READ_FRAME_NUMBER);
- lowByte = SIEReadData(SIE_CMD_READ_FRAME_NUMBER);
- highByte = SIEReadData(SIE_CMD_READ_FRAME_NUMBER);
-
- return (highByte << 8) | lowByte;
-}
-
-static void SIEconfigureDevice(void)
-{
- // SIE Configure device command
- SIECommand(SIE_CMD_CONFIGURE_DEVICE);
- SIEWriteData(SIE_CONF_DEVICE);
-}
-
-static void SIEunconfigureDevice(void)
-{
- // SIE Configure device command
- SIECommand(SIE_CMD_CONFIGURE_DEVICE);
- SIEWriteData(0);
-}
-
-static void SIEconnect(void)
-{
- // Connect USB device
- uint8_t status;
-
- status = SIEgetDeviceStatus();
- SIEsetDeviceStatus(status | SIE_DS_CON);
-}
-
-
-static void SIEdisconnect(void)
-{
- // Disconnect USB device
- uint8_t status;
-
- status = SIEgetDeviceStatus();
- SIEsetDeviceStatus(status & ~SIE_DS_CON);
-}
-
-
-static uint8_t selectEndpointClearInterrupt(uint8_t endpoint)
-{
- // Implemented using using EP_INT_CLR.
- LPC_USB->USBEpIntClr = EP(endpoint);
- while (!(LPC_USB->USBDevIntSt & CDFULL));
- return (uint8_t)LPC_USB->USBCmdData;
-}
-
-
-
-
-
-static void enableEndpointEvent(uint8_t endpoint)
-{
- // Enable an endpoint interrupt
- LPC_USB->USBEpIntEn |= EP(endpoint);
-}
-
-static void disableEndpointEvent(uint8_t endpoint) __attribute__ ((unused));
-static void disableEndpointEvent(uint8_t endpoint)
-{
- // Disable an endpoint interrupt
- LPC_USB->USBEpIntEn &= ~EP(endpoint);
-}
-
-static volatile uint32_t __attribute__((used)) dummyRead;
-
-
-static uint32_t endpointReadcore(uint8_t endpoint, uint8_t *buffer)
-{
- // Read from an OUT endpoint
- uint32_t size;
- uint32_t i;
- uint32_t data = 0;
- uint8_t offset;
-
- LPC_USB->USBCtrl = LOG_ENDPOINT(endpoint) | RD_EN;
- while (!(LPC_USB->USBRxPLen & PKT_RDY));
-
- size = LPC_USB->USBRxPLen & PKT_LNGTH_MASK;
-
- offset = 0;
-
- if (size > 0)
- {
- for (i=0; i<size; i++)
- {
- if (offset==0)
- {
- // Fetch up to four bytes of data as a word
- data = LPC_USB->USBRxData;
- }
-
- // extract a byte
- *buffer = (data>>offset) & 0xff;
- buffer++;
-
- // move on to the next byte
- offset = (offset + 8) % 32;
- }
- }
- else
- {
- dummyRead = LPC_USB->USBRxData;
- }
-
- SIEselectEndpoint(endpoint);
- SIEclearBuffer();
- return size;
-}
-
-static void endpointWritecore(uint8_t endpoint, uint8_t *buffer, uint32_t size)
-{
- // Write to an IN endpoint
- uint32_t temp, data;
- uint8_t offset;
-
- LPC_USB->USBCtrl = LOG_ENDPOINT(endpoint) | WR_EN;
-
- LPC_USB->USBTxPLen = size;
- offset = 0;
- data = 0;
-
- if (size>0)
- {
- do {
- // Fetch next data byte into a word-sized temporary variable
- temp = *buffer++;
-
- // Add to current data word
- temp = temp << offset;
- data = data | temp;
-
- // move on to the next byte
- offset = (offset + 8) % 32;
- size--;
-
- if ((offset==0) || (size==0))
- {
- // Write the word to the endpoint
- LPC_USB->USBTxData = data;
- data = 0;
- }
- } while (size>0);
- }
- else
- {
- LPC_USB->USBTxData = 0;
- }
-
- // Clear WR_EN to cover zero length packet case
- LPC_USB->USBCtrl=0;
-
- SIEselectEndpoint(endpoint);
- SIEvalidateBuffer();
-}
-
-
-
-
-
-
-
-USBHAL::USBHAL(void)
-{
- // Disable IRQ
- NVIC_DisableIRQ(USB_IRQn);
-
- // Enable power to USB device controller
- LPC_SC->PCONP |= PCUSB;
-
- // Enable USB clocks
- LPC_USB->USBClkCtrl |= DEV_CLK_EN | AHB_CLK_EN;
- while (LPC_USB->USBClkSt != (DEV_CLK_ON | AHB_CLK_ON));
-
- // Configure pins P0.29 and P0.30 to be USB D+ and USB D-
- LPC_PINCON->PINSEL1 &= 0xc3ffffff;
- LPC_PINCON->PINSEL1 |= 0x14000000;
-
- // Disconnect USB device
- SIEdisconnect();
-
- // Configure pin P2.9 to be Connect
- LPC_PINCON->PINSEL4 &= 0xfffcffff;
- LPC_PINCON->PINSEL4 |= 0x00040000;
-
- // Connect must be low for at least 2.5uS
- wait(0.3);
-
- // Set the maximum packet size for the control endpoints
- realiseEndpoint(EP0IN, MAX_PACKET_SIZE_EP0, 0);
- realiseEndpoint(EP0OUT, MAX_PACKET_SIZE_EP0, 0);
-
- // Attach IRQ
- instance = this;
- NVIC_SetVector(USB_IRQn, (uint32_t)&_usbisr);
- NVIC_EnableIRQ(USB_IRQn);
-
- // Enable interrupts for device events and EP0
- LPC_USB->USBDevIntEn = EP_SLOW | DEV_STAT;
- enableEndpointEvent(EP0IN);
- enableEndpointEvent(EP0OUT);
-}
-
-USBHAL::~USBHAL(void)
-{
- // Ensure device disconnected
- SIEdisconnect();
-
- // Disable USB interrupts
- NVIC_DisableIRQ(USB_IRQn);
-}
-
-void USBHAL::connect(void)
-{
- // Connect USB device
- SIEconnect();
-}
-
-void USBHAL::disconnect(void)
-{
- // Disconnect USB device
- SIEdisconnect();
-}
-
-void USBHAL::configureDevice(void)
-{
- SIEconfigureDevice();
-}
-
-void USBHAL::unconfigureDevice(void)
-{
- SIEunconfigureDevice();
-}
-
-void USBHAL::setAddress(uint8_t address)
-{
- SIEsetAddress(address);
-}
-
-void USBHAL::EP0setup(uint8_t *buffer)
-{
- endpointReadcore(EP0OUT, buffer);
-}
-
-void USBHAL::EP0read(void)
-{
- // Not required
-}
-
-uint32_t USBHAL::EP0getReadResult(uint8_t *buffer)
-{
- return endpointReadcore(EP0OUT, buffer);
-}
-
-void USBHAL::EP0write(uint8_t *buffer, uint32_t size)
-{
- endpointWritecore(EP0IN, buffer, size);
-}
-
-void USBHAL::EP0getWriteResult(void)
-{
- // Not required
-}
-
-void USBHAL::EP0stall(void)
-{
- // This will stall both control endpoints
- stallEndpoint(EP0OUT);
-}
-
-EP_STATUS USBHAL::endpointRead(uint8_t endpoint, uint32_t maximumSize)
-{
- return EP_PENDING;
-}
-
-EP_STATUS USBHAL::endpointReadResult(uint8_t endpoint, uint8_t * buffer, uint32_t *bytesRead)
-{
- if(!(epComplete & EP(endpoint)))
- return EP_PENDING;
- *bytesRead = endpointReadcore(endpoint, buffer);
- epComplete &= ~EP(endpoint);
- return EP_COMPLETED;
-}
-
-EP_STATUS USBHAL::endpointWrite(uint8_t endpoint, uint8_t *data, uint32_t size)
-{
- if (getEndpointStallState(endpoint))
- {
- return EP_STALLED;
- }
-
- epComplete &= ~EP(endpoint);
-
- endpointWritecore(endpoint, data, size);
- return EP_PENDING;
-}
-
-EP_STATUS USBHAL::endpointWriteResult(uint8_t endpoint)
-{
- if (epComplete & EP(endpoint))
- {
- epComplete &= ~EP(endpoint);
- return EP_COMPLETED;
- }
-
- return EP_PENDING;
-}
-
-bool USBHAL::realiseEndpoint(uint8_t endpoint, uint32_t maxPacket, uint32_t flags)
-{
- // Realise an endpoint
- LPC_USB->USBDevIntClr = EP_RLZED;
- LPC_USB->USBReEp |= EP(endpoint);
- LPC_USB->USBEpInd = endpoint;
- LPC_USB->USBMaxPSize = maxPacket;
-
- while (!(LPC_USB->USBDevIntSt & EP_RLZED));
- LPC_USB->USBDevIntClr = EP_RLZED;
-
- // Clear stall state
- endpointStallState &= ~EP(endpoint);
-
- enableEndpointEvent(endpoint);
- return true;
-}
-
-void USBHAL::stallEndpoint(uint8_t endpoint)
-{
- // Stall an endpoint
- if ( (endpoint==EP0IN) || (endpoint==EP0OUT) )
- {
- // Conditionally stall both control endpoints
- SIEsetEndpointStatus(EP0OUT, SIE_SES_CND_ST);
- }
- else
- {
- SIEsetEndpointStatus(endpoint, SIE_SES_ST);
-
- // Update stall state
- endpointStallState |= EP(endpoint);
- }
-}
-
-void USBHAL::unstallEndpoint(uint8_t endpoint)
-{
- // Unstall an endpoint. The endpoint will also be reinitialised
- SIEsetEndpointStatus(endpoint, 0);
-
- // Update stall state
- endpointStallState &= ~EP(endpoint);
-}
-
-bool USBHAL::getEndpointStallState(uint8_t endpoint)
-{
- // Returns true if endpoint stalled
- return endpointStallState & EP(endpoint);
-}
-
-void USBHAL::remoteWakeup(void)
-{
- // Remote wakeup
- uint8_t status;
-
- // Enable USB clocks
- LPC_USB->USBClkCtrl |= DEV_CLK_EN | AHB_CLK_EN;
- while (LPC_USB->USBClkSt != (DEV_CLK_ON | AHB_CLK_ON));
-
- status = SIEgetDeviceStatus();
- SIEsetDeviceStatus(status & ~SIE_DS_SUS);
-}
-
-
-
-
-
-void USBHAL::_usbisr(void)
-{
- instance->usbisr();
-}
-
-
-void USBHAL::usbisr(void)
-{
- uint8_t devStat;
-
- if (LPC_USB->USBDevIntSt & FRAME)
- {
- // Start of frame event
- SOF(SIEgetFrameNumber());
- // Clear interrupt status flag
- LPC_USB->USBDevIntClr = FRAME;
- }
-
- if (LPC_USB->USBDevIntSt & DEV_STAT)
- {
- // Device Status interrupt
- // Must clear the interrupt status flag before reading the device status from the SIE
- LPC_USB->USBDevIntClr = DEV_STAT;
-
- // Read device status from SIE
- devStat = SIEgetDeviceStatus();
-
- if (devStat & SIE_DS_RST)
- {
- // Bus reset
- busReset();
- }
- }
-
- if (LPC_USB->USBDevIntSt & EP_SLOW)
- {
- // (Slow) Endpoint Interrupt
-
- // Process each endpoint interrupt
- if (LPC_USB->USBEpIntSt & EP(EP0OUT))
- {
- if (selectEndpointClearInterrupt(EP0OUT) & SIE_SE_STP)
- {
- // this is a setup packet
- EP0setupCallback();
- }
- else
- {
- EP0out();
- }
- LPC_USB->USBDevIntClr = EP_SLOW;
- }
-
- if (LPC_USB->USBEpIntSt & EP(EP0IN))
- {
- selectEndpointClearInterrupt(EP0IN);
- LPC_USB->USBDevIntClr = EP_SLOW;
- EP0in();
- }
-
- // TODO: This should cover all endpoints, not just EP1,2,3:
- if (LPC_USB->USBEpIntSt & EP(EP1IN))
- {
- selectEndpointClearInterrupt(EP1IN);
- epComplete |= EP(EP1IN);
- LPC_USB->USBDevIntClr = EP_SLOW;
- if(EP1_IN_callback())
- epComplete &= ~EP(EP1IN);
- }
-
- if (LPC_USB->USBEpIntSt & EP(EP1OUT))
- {
- selectEndpointClearInterrupt(EP1OUT);
- epComplete |= EP(EP1OUT);
- LPC_USB->USBDevIntClr = EP_SLOW;
- if(EP1_OUT_callback())
- epComplete &= ~EP(EP1OUT);
- }
-
- if (LPC_USB->USBEpIntSt & EP(EP2IN))
- {
- selectEndpointClearInterrupt(EP2IN);
- epComplete |= EP(EP2IN);
- LPC_USB->USBDevIntClr = EP_SLOW;
- if(EP2_IN_callback())
- epComplete &= ~EP(EP2IN);
- }
-
- if (LPC_USB->USBEpIntSt & EP(EP2OUT))
- {
- selectEndpointClearInterrupt(EP2OUT);
- epComplete |= EP(EP2OUT);
- LPC_USB->USBDevIntClr = EP_SLOW;
- if(EP2_OUT_callback())
- epComplete &= ~EP(EP2OUT);
- }
-
- if (LPC_USB->USBEpIntSt & EP(EP3IN))
- {
- selectEndpointClearInterrupt(EP3IN);
- epComplete |= EP(EP3IN);
- LPC_USB->USBDevIntClr = EP_SLOW;
- if(EP3_IN_callback())
- epComplete &= ~EP(EP3IN);
- }
-
- if (LPC_USB->USBEpIntSt & EP(EP3OUT))
- {
- selectEndpointClearInterrupt(EP3OUT);
- epComplete |= EP(EP3OUT);
- LPC_USB->USBDevIntClr = EP_SLOW;
- if(EP3_OUT_callback())
- epComplete &= ~EP(EP3OUT);
- }
- }
-}
-
-#endif
--- a/USBDevice/USBDevice/USBDescriptor.h Mon Nov 14 10:00:07 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,60 +0,0 @@ -/* USBDescriptor.h */ -/* Definitions and macros for constructing USB descriptors */ -/* Copyright (c) 2011 ARM Limited. All rights reserved. */ - -/* Standard descriptor types */ -#define DEVICE_DESCRIPTOR (1) -#define CONFIGURATION_DESCRIPTOR (2) -#define STRING_DESCRIPTOR (3) -#define INTERFACE_DESCRIPTOR (4) -#define ENDPOINT_DESCRIPTOR (5) -#define QUALIFIER_DESCRIPTOR (6) - -/* Standard descriptor lengths */ -#define DEVICE_DESCRIPTOR_LENGTH (0x12) -#define CONFIGURATION_DESCRIPTOR_LENGTH (0x09) -#define INTERFACE_DESCRIPTOR_LENGTH (0x09) -#define ENDPOINT_DESCRIPTOR_LENGTH (0x07) - - -/*string offset*/ -#define STRING_OFFSET_LANGID (0) -#define STRING_OFFSET_IMANUFACTURER (1) -#define STRING_OFFSET_IPRODUCT (2) -#define STRING_OFFSET_ISERIAL (3) -#define STRING_OFFSET_ICONFIGURATION (4) -#define STRING_OFFSET_IINTERFACE (5) - -/* USB Specification Release Number */ -#define USB_VERSION_2_0 (0x0200) - -/* Least/Most significant byte of short integer */ -#define LSB(n) ((n)&0xff) -#define MSB(n) (((n)&0xff00)>>8) - -/* Convert physical endpoint number to descriptor endpoint number */ -#define PHY_TO_DESC(endpoint) (((endpoint)>>1) | (((endpoint) & 1) ? 0x80:0)) - -/* bmAttributes in configuration descriptor */ -/* C_RESERVED must always be set */ -#define C_RESERVED (1U<<7) -#define C_SELF_POWERED (1U<<6) -#define C_REMOTE_WAKEUP (1U<<5) - -/* bMaxPower in configuration descriptor */ -#define C_POWER(mA) ((mA)/2) - -/* bmAttributes in endpoint descriptor */ -#define E_CONTROL (0x00) -#define E_ISOCHRONOUS (0x01) -#define E_BULK (0x02) -#define E_INTERRUPT (0x03) - -/* For isochronous endpoints only: */ -#define E_NO_SYNCHRONIZATION (0x00) -#define E_ASYNCHRONOUS (0x04) -#define E_ADAPTIVE (0x08) -#define E_SYNCHRONOUS (0x0C) -#define E_DATA (0x00) -#define E_FEEDBACK (0x10) -#define E_IMPLICIT_FEEDBACK (0x20)
--- a/USBDevice/USBDevice/USBDevice.cpp Mon Nov 14 10:00:07 2011 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,912 +0,0 @@
-/* USBDevice.c */
-/* Generic USB device */
-/* Copyright (c) 2011 ARM Limited. All rights reserved. */
-
-/* Reference: */
-/* Universal Serial Bus Specification Revision 2.0, Chapter 9 "USB Device Framework" */
-
-#include "stdint.h"
-
-#include "USBEndpoints.h"
-#include "USBDevice.h"
-#include "USBDescriptor.h"
-#include "USBHID_Types.h"
-
-
-/* Device status */
-#define DEVICE_STATUS_SELF_POWERED (1U<<0)
-#define DEVICE_STATUS_REMOTE_WAKEUP (1U<<1)
-
-/* Endpoint status */
-#define ENDPOINT_STATUS_HALT (1U<<0)
-
-/* Standard feature selectors */
-#define DEVICE_REMOTE_WAKEUP (1)
-#define ENDPOINT_HALT (0)
-
-/* Macro to convert wIndex endpoint number to physical endpoint number */
-#define WINDEX_TO_PHYSICAL(endpoint) (((endpoint & 0x0f) << 1) + \
- ((endpoint & 0x80) ? 1 : 0))
-
-
-bool USBDevice::requestGetDescriptor(void)
-{
- bool success = false;
-
- switch (DESCRIPTOR_TYPE(transfer.setup.wValue))
- {
- case DEVICE_DESCRIPTOR:
- case QUALIFIER_DESCRIPTOR:
- if (deviceDesc() != NULL)
- {
- if ((deviceDesc()[0] == DEVICE_DESCRIPTOR_LENGTH) \
- && (deviceDesc()[1] == DEVICE_DESCRIPTOR))
- {
- transfer.remaining = DEVICE_DESCRIPTOR_LENGTH;
- transfer.ptr = deviceDesc();
- transfer.direction = DEVICE_TO_HOST;
- success = true;
- }
- }
- break;
- case CONFIGURATION_DESCRIPTOR:
- if (configurationDesc() != NULL)
- {
- if ((configurationDesc()[0] == CONFIGURATION_DESCRIPTOR_LENGTH) \
- && (configurationDesc()[1] == CONFIGURATION_DESCRIPTOR))
- {
- /* Get wTotalLength */
- transfer.remaining = configurationDesc()[2] \
- | (configurationDesc()[3] << 8);
-
- transfer.ptr = configurationDesc();
- transfer.direction = DEVICE_TO_HOST;
- success = true;
- }
- }
- break;
- case STRING_DESCRIPTOR:
- switch (DESCRIPTOR_INDEX(transfer.setup.wValue))
- {
- case STRING_OFFSET_LANGID:
- transfer.remaining = stringLangidDesc()[0];
- transfer.ptr = stringLangidDesc();
- transfer.direction = DEVICE_TO_HOST;
- success = true;
- break;
- case STRING_OFFSET_IMANUFACTURER:
- transfer.remaining = stringImanufacturerDesc()[0];
- transfer.ptr = stringImanufacturerDesc();
- transfer.direction = DEVICE_TO_HOST;
- success = true;
- break;
- case STRING_OFFSET_IPRODUCT:
- transfer.remaining = stringIproductDesc()[0];
- transfer.ptr = stringIproductDesc();
- transfer.direction = DEVICE_TO_HOST;
- success = true;
- break;
- case STRING_OFFSET_ISERIAL:
- transfer.remaining = stringIserialDesc()[0];
- transfer.ptr = stringIserialDesc();
- transfer.direction = DEVICE_TO_HOST;
- success = true;
- break;
- case STRING_OFFSET_ICONFIGURATION:
- transfer.remaining = stringIConfigurationDesc()[0];
- transfer.ptr = stringIConfigurationDesc();
- transfer.direction = DEVICE_TO_HOST;
- success = true;
- break;
- case STRING_OFFSET_IINTERFACE:
- transfer.remaining = stringIinterfaceDesc()[0];
- transfer.ptr = stringIinterfaceDesc();
- transfer.direction = DEVICE_TO_HOST;
- success = true;
- break;
- }
- break;
- case INTERFACE_DESCRIPTOR:
- case ENDPOINT_DESCRIPTOR:
- /* TODO: Support is optional, not implemented here */
- break;
- default:
- break;
- }
-
- return success;
-}
-
-void USBDevice::decodeSetupPacket(uint8_t *data, SETUP_PACKET *packet)
-{
- /* Fill in the elements of a SETUP_PACKET structure from raw data */
- packet->bmRequestType.dataTransferDirection = (data[0] & 0x80) >> 7;
- packet->bmRequestType.Type = (data[0] & 0x60) >> 5;
- packet->bmRequestType.Recipient = data[0] & 0x1f;
- packet->bRequest = data[1];
- packet->wValue = (data[2] | (uint16_t)data[3] << 8);
- packet->wIndex = (data[4] | (uint16_t)data[5] << 8);
- packet->wLength = (data[6] | (uint16_t)data[7] << 8);
-}
-
-
-bool USBDevice::controlOut(void)
-{
- /* Control transfer data OUT stage */
- uint8_t buffer[MAX_PACKET_SIZE_EP0];
- uint32_t packetSize;
-
- /* Check we should be transferring data OUT */
- if (transfer.direction != HOST_TO_DEVICE)
- {
- return false;
- }
-
- /* Read from endpoint */
- packetSize = EP0getReadResult(buffer);
-
- /* Check if transfer size is valid */
- if (packetSize > transfer.remaining)
- {
- /* Too big */
- return false;
- }
-
- /* Update transfer */
- transfer.ptr += packetSize;
- transfer.remaining -= packetSize;
-
- /* Check if transfer has completed */
- if (transfer.remaining == 0)
- {
- /* Transfer completed */
- if (transfer.notify)
- {
- /* Notify class layer. */
- USBCallback_requestCompleted();
- transfer.notify = false;
- }
- /* Status stage */
- EP0write(NULL, 0);
- }
- else
- {
- EP0read();
- }
-
- return true;
-}
-
-bool USBDevice::controlIn(void)
-{
- /* Control transfer data IN stage */
- uint32_t packetSize;
-
- /* Check if transfer has completed (status stage transactions */
- /* also have transfer.remaining == 0) */
- if (transfer.remaining == 0)
- {
- if (transfer.zlp)
- {
- /* Send zero length packet */
- EP0write(NULL, 0);
- transfer.zlp = false;
- }
-
- /* Transfer completed */
- if (transfer.notify)
- {
- /* Notify class layer. */
- USBCallback_requestCompleted();
- transfer.notify = false;
- }
-
- EP0read();
-
- /* Completed */
- return true;
- }
-
- /* Check we should be transferring data IN */
- if (transfer.direction != DEVICE_TO_HOST)
- {
- return false;
- }
-
- packetSize = transfer.remaining;
-
- if (packetSize > MAX_PACKET_SIZE_EP0)
- {
- packetSize = MAX_PACKET_SIZE_EP0;
- }
-
- /* Write to endpoint */
- EP0write(transfer.ptr, packetSize);
-
- /* Update transfer */
- transfer.ptr += packetSize;
- transfer.remaining -= packetSize;
-
- return true;
-}
-
-bool USBDevice::requestSetAddress(void)
-{
- /* Set the device address */
- setAddress(transfer.setup.wValue);
-
- if (transfer.setup.wValue == 0)
- {
- device.state = DEFAULT;
- }
- else
- {
- device.state = ADDRESS;
- }
-
- return true;
-}
-
-bool USBDevice::requestSetConfiguration(void)
-{
-
- device.configuration = transfer.setup.wValue;
- /* Set the device configuration */
- if (device.configuration == 0)
- {
- /* Not configured */
- unconfigureDevice();
- device.state = ADDRESS;
- }
- else
- {
- if (USBCallback_setConfiguration(device.configuration))
- {
- /* Valid configuration */
- configureDevice();
- device.state = CONFIGURED;
- }
- else
- {
- return false;
- }
- }
-
- return true;
-}
-
-bool USBDevice::requestGetConfiguration(void)
-{
- /* Send the device configuration */
- transfer.ptr = &device.configuration;
- transfer.remaining = sizeof(device.configuration);
- transfer.direction = DEVICE_TO_HOST;
- return true;
-}
-
-bool USBDevice::requestGetInterface(void)
-{
- static uint8_t alternateSetting;
-
- /* Return the selected alternate setting for an interface */
-
- if (device.state != CONFIGURED)
- {
- return false;
- }
-
- /* TODO: We currently do not support alternate settings */
- /* so always return zero */
- /* TODO: Should check that the interface number is valid */
- alternateSetting = 0;
-
- /* Send the alternate setting */
- transfer.ptr = &alternateSetting;
- transfer.remaining = sizeof(alternateSetting);
- transfer.direction = DEVICE_TO_HOST;
- return true;
-}
-
-bool USBDevice::requestSetInterface(void)
-{
- /* TODO: We currently do not support alternate settings, return false */
- return false;
-}
-
-bool USBDevice::requestSetFeature()
-{
- bool success = false;
-
- if (device.state != CONFIGURED)
- {
- /* Endpoint or interface must be zero */
- if (transfer.setup.wIndex != 0)
- {
- return false;
- }
- }
-
- switch (transfer.setup.bmRequestType.Recipient)
- {
- case DEVICE_RECIPIENT:
- /* TODO: Remote wakeup feature not supported */
- break;
- case ENDPOINT_RECIPIENT:
- if (transfer.setup.wValue == ENDPOINT_HALT)
- {
- /* TODO: We should check that the endpoint number is valid */
- stallEndpoint(
- WINDEX_TO_PHYSICAL(transfer.setup.wIndex));
- success = true;
- }
- break;
- default:
- break;
- }
-
- return success;
-}
-
-bool USBDevice::requestClearFeature()
-{
- bool success = false;
-
- if (device.state != CONFIGURED)
- {
- /* Endpoint or interface must be zero */
- if (transfer.setup.wIndex != 0)
- {
- return false;
- }
- }
-
- switch (transfer.setup.bmRequestType.Recipient)
- {
- case DEVICE_RECIPIENT:
- /* TODO: Remote wakeup feature not supported */
- break;
- case ENDPOINT_RECIPIENT:
- /* TODO: We should check that the endpoint number is valid */
- if (transfer.setup.wValue == ENDPOINT_HALT)
- {
- unstallEndpoint( WINDEX_TO_PHYSICAL(transfer.setup.wIndex));
- success = true;
- }
- break;
- default:
- break;
- }
-
- return success;
-}
-
-bool USBDevice::requestGetStatus(void)
-{
- static uint16_t status;
- bool success = false;
-
- if (device.state != CONFIGURED)
- {
- /* Endpoint or interface must be zero */
- if (transfer.setup.wIndex != 0)
- {
- return false;
- }
- }
-
- switch (transfer.setup.bmRequestType.Recipient)
- {
- case DEVICE_RECIPIENT:
- /* TODO: Currently only supports self powered devices */
- status = DEVICE_STATUS_SELF_POWERED;
- success = true;
- break;
- case INTERFACE_RECIPIENT:
- status = 0;
- success = true;
- break;
- case ENDPOINT_RECIPIENT:
- /* TODO: We should check that the endpoint number is valid */
- if (getEndpointStallState(
- WINDEX_TO_PHYSICAL(transfer.setup.wIndex)))
- {
- status = ENDPOINT_STATUS_HALT;
- }
- else
- {
- status = 0;
- }
- success = true;
- break;
- default:
- break;
- }
-
- if (success)
- {
- /* Send the status */
- transfer.ptr = (uint8_t *)&status; /* Assumes little endian */
- transfer.remaining = sizeof(status);
- transfer.direction = DEVICE_TO_HOST;
- }
-
- return success;
-}
-
-bool USBDevice::requestSetup(void)
-{
- bool success = false;
-
- /* Process standard requests */
- if ((transfer.setup.bmRequestType.Type == STANDARD_TYPE))
- {
- switch (transfer.setup.bRequest)
- {
- case GET_STATUS:
- success = requestGetStatus();
- break;
- case CLEAR_FEATURE:
- success = requestClearFeature();
- break;
- case SET_FEATURE:
- success = requestSetFeature();
- break;
- case SET_ADDRESS:
- success = requestSetAddress();
- break;
- case GET_DESCRIPTOR:
- success = requestGetDescriptor();
- break;
- case SET_DESCRIPTOR:
- /* TODO: Support is optional, not implemented here */
- success = false;
- break;
- case GET_CONFIGURATION:
- success = requestGetConfiguration();
- break;
- case SET_CONFIGURATION:
- success = requestSetConfiguration();
- break;
- case GET_INTERFACE:
- success = requestGetInterface();
- break;
- case SET_INTERFACE:
- success = requestSetInterface();
- break;
- default:
- break;
- }
- }
-
- return success;
-}
-
-bool USBDevice::controlSetup(void)
-{
- bool success = false;
-
- /* Control transfer setup stage */
- uint8_t buffer[MAX_PACKET_SIZE_EP0];
-
- EP0setup(buffer);
-
- /* Initialise control transfer state */
- decodeSetupPacket(buffer, &transfer.setup);
- transfer.ptr = NULL;
- transfer.remaining = 0;
- transfer.direction = 0;
- transfer.zlp = false;
- transfer.notify = false;
-
- /* Process request */
-
- /* Class / vendor specific */
- success = USBCallback_request();
-
- if (!success)
- {
- /* Standard requests */
- if (!requestSetup())
- {
- return false;
- }
- }
-
- /* Check transfer size and direction */
- if (transfer.setup.wLength>0)
- {
- if (transfer.setup.bmRequestType.dataTransferDirection \
- == DEVICE_TO_HOST)
- {
- /* IN data stage is required */
- if (transfer.direction != DEVICE_TO_HOST)
- {
- return false;
- }
-
- /* Transfer must be less than or equal to the size */
- /* requested by the host */
- if (transfer.remaining > transfer.setup.wLength)
- {
- transfer.remaining = transfer.setup.wLength;
- }
- }
- else
- {
-
- /* OUT data stage is required */
- if (transfer.direction != HOST_TO_DEVICE)
- {
- return false;
- }
-
- /* Transfer must be equal to the size requested by the host */
- if (transfer.remaining != transfer.setup.wLength)
- {
- return false;
- }
- }
- }
- else
- {
- /* No data stage; transfer size must be zero */
- if (transfer.remaining != 0)
- {
- return false;
- }
- }
-
- /* Data or status stage if applicable */
- if (transfer.setup.wLength>0)
- {
- if (transfer.setup.bmRequestType.dataTransferDirection \
- == DEVICE_TO_HOST)
- {
- /* Check if we'll need to send a zero length packet at */
- /* the end of this transfer */
- if (transfer.setup.wLength > transfer.remaining)
- {
- /* Device wishes to transfer less than host requested */
- if ((transfer.remaining % MAX_PACKET_SIZE_EP0) == 0)
- {
- /* Transfer is a multiple of EP0 max packet size */
- transfer.zlp = true;
- }
- }
-
- /* IN stage */
- controlIn();
- }
- else
- {
- /* OUT stage */
- EP0read();
- }
- }
- else
- {
- /* Status stage */
- EP0write(NULL, 0);
- }
-
- return true;
-}
-
-void USBDevice::busReset(void)
-{
- device.state = DEFAULT;
- device.configuration = 0;
- device.suspended = false;
-
- /* Call class / vendor specific busReset function */
- USBCallback_busReset();
-}
-
-void USBDevice::EP0setupCallback(void)
-{
- /* Endpoint 0 setup event */
- if (!controlSetup())
- {
- /* Protocol stall */
- EP0stall();
- }
-
- /* Return true if an OUT data stage is expected */
-}
-
-void USBDevice::EP0out(void)
-{
- /* Endpoint 0 OUT data event */
- if (!controlOut())
- {
- /* Protocol stall; this will stall both endpoints */
- EP0stall();
- }
-}
-
-void USBDevice::EP0in(void)
-{
- /* Endpoint 0 IN data event */
- if (!controlIn())
- {
- /* Protocol stall; this will stall both endpoints */
- EP0stall();
- }
-}
-
-bool USBDevice::configured(void)
-{
- /* Returns true if device is in the CONFIGURED state */
- return (device.state == CONFIGURED);
-}
-
-void USBDevice::connect(void)
-{
- /* Connect device */
- USBHAL::connect();
-}
-
-void USBDevice::disconnect(void)
-{
- /* Disconnect device */
- USBHAL::disconnect();
-}
-
-CONTROL_TRANSFER * USBDevice::getTransferPtr(void)
-{
- return &transfer;
-}
-
-bool USBDevice::addEndpoint(uint8_t endpoint, uint32_t maxPacket)
-{
- return realiseEndpoint(endpoint, maxPacket, 0);
-}
-
-bool USBDevice::addRateFeedbackEndpoint(uint8_t endpoint, uint32_t maxPacket)
-{
- /* For interrupt endpoints only */
- return realiseEndpoint(endpoint, maxPacket, RATE_FEEDBACK_MODE);
-}
-
-uint8_t * USBDevice::findDescriptor(uint8_t descriptorType)
-{
- /* Find a descriptor within the list of descriptors */
- /* following a configuration descriptor. */
- uint16_t wTotalLength;
- uint8_t *ptr;
-
- if (configurationDesc() == NULL)
- {
- return NULL;
- }
-
- /* Check this is a configuration descriptor */
- if ((configurationDesc()[0] != CONFIGURATION_DESCRIPTOR_LENGTH) \
- || (configurationDesc()[1] != CONFIGURATION_DESCRIPTOR))
- {
- return NULL;
- }
-
- wTotalLength = configurationDesc()[2] | (configurationDesc()[3] << 8);
-
- /* Check there are some more descriptors to follow */
- if (wTotalLength <= (CONFIGURATION_DESCRIPTOR_LENGTH+2))
- /* +2 is for bLength and bDescriptorType of next descriptor */
- {
- return false;
- }
-
- /* Start at first descriptor after the configuration descriptor */
- ptr = &(configurationDesc()[CONFIGURATION_DESCRIPTOR_LENGTH]);
-
- do {
- if (ptr[1] /* bDescriptorType */ == descriptorType)
- {
- /* Found */
- return ptr;
- }
-
- /* Skip to next descriptor */
- ptr += ptr[0]; /* bLength */
- } while (ptr < (configurationDesc() + wTotalLength));
-
- /* Reached end of the descriptors - not found */
- return NULL;
-}
-
-void USBDevice::SOF(int frameNumber)
-{
-}
-
-void USBDevice::connectStateChanged(unsigned int connected)
-{
-}
-
-void USBDevice::suspendStateChanged(unsigned int suspended)
-{
-}
-
-
-USBDevice::USBDevice(uint16_t vendor_id, uint16_t product_id, uint16_t product_release){
- VENDOR_ID = vendor_id;
- PRODUCT_ID = product_id;
- PRODUCT_RELEASE = product_release;
-
- /* Set initial device state */
- device.state = POWERED;
- device.configuration = 0;
- device.suspended = false;
-
- //connect();
-};
-
-
-bool USBDevice::readStart(uint8_t endpoint, uint16_t maxSize)
-{
- return endpointRead(endpoint, maxSize) == EP_PENDING;
-}
-
-
-bool USBDevice::write(uint8_t endpoint, uint8_t * buffer, uint16_t size, uint16_t maxSize)
-{
- EP_STATUS result;
-
- if (size > maxSize)
- {
- return false;
- }
-
- /* Block if not configured */
- while (!configured());
-
- /* Send report */
- result = endpointWrite(endpoint, buffer, size);
-
- if (result != EP_PENDING)
- {
- return false;
- }
-
- /* Wait for completion */
- do {
- result = endpointWriteResult(endpoint);
- } while ((result == EP_PENDING) && configured());
-
- return (result == EP_COMPLETED);
-}
-
-
-bool USBDevice::writeNB(uint8_t endpoint, uint8_t * buffer, uint16_t size, uint16_t maxSize)
-{
- EP_STATUS result;
-
- if (size > maxSize)
- {
- return false;
- }
-
- /* Block if not configured */
- while (!configured());
-
- /* Send report */
- result = endpointWrite(endpoint, buffer, size);
-
- if (result != EP_PENDING)
- {
- return false;
- }
-
- result = endpointWriteResult(endpoint);
-
- return (result == EP_COMPLETED);
-}
-
-
-
-bool USBDevice::read(uint8_t endpoint, uint8_t * buffer, uint16_t * size, uint16_t maxSize)
-{
- EP_STATUS result;
-
- /* Block if not configured */
- while (!configured());
-
- /* Wait for completion */
- do {
- result = endpointReadResult(endpoint, buffer, (uint32_t *)size);
- } while ((result == EP_PENDING) && configured());
-
- return (result == EP_COMPLETED);
-}
-
-
-bool USBDevice::readNB(uint8_t endpoint, uint8_t * buffer, uint16_t * size, uint16_t maxSize)
-{
- EP_STATUS result;
-
- /* Block if not configured */
- while (!configured());
-
- result = endpointReadResult(endpoint, buffer, (uint32_t *)size);
-
- return (result == EP_COMPLETED);
-}
-
-
-
-uint8_t * USBDevice::deviceDesc() {
- static uint8_t deviceDescriptor[] = {
- DEVICE_DESCRIPTOR_LENGTH, /* bLength */
- DEVICE_DESCRIPTOR, /* bDescriptorType */
- LSB(USB_VERSION_2_0), /* bcdUSB (LSB) */
- MSB(USB_VERSION_2_0), /* bcdUSB (MSB) */
- 0x00, /* bDeviceClass */
- 0x00, /* bDeviceSubClass */
- 0x00, /* bDeviceprotocol */
- MAX_PACKET_SIZE_EP0, /* bMaxPacketSize0 */
- LSB(VENDOR_ID), /* idVendor (LSB) */
- MSB(VENDOR_ID), /* idVendor (MSB) */
- LSB(PRODUCT_ID), /* idProduct (LSB) */
- MSB(PRODUCT_ID), /* idProduct (MSB) */
- LSB(PRODUCT_RELEASE), /* bcdDevice (LSB) */
- MSB(PRODUCT_RELEASE), /* bcdDevice (MSB) */
- STRING_OFFSET_IMANUFACTURER, /* iManufacturer */
- STRING_OFFSET_IPRODUCT, /* iProduct */
- STRING_OFFSET_ISERIAL, /* iSerialNumber */
- 0x01 /* bNumConfigurations */
- };
- return deviceDescriptor;
-}
-
-uint8_t * USBDevice::stringLangidDesc() {
- static uint8_t stringLangidDescriptor[] = {
- 0x04, /*bLength*/
- STRING_DESCRIPTOR, /*bDescriptorType 0x03*/
- 0x09,0x00, /*bString Lang ID - 0x009 - English*/
- };
- return stringLangidDescriptor;
-}
-
-uint8_t * USBDevice::stringImanufacturerDesc() {
- static uint8_t stringImanufacturerDescriptor[] = {
- 0x12, /*bLength*/
- STRING_DESCRIPTOR, /*bDescriptorType 0x03*/
- 'm',0,'b',0,'e',0,'d',0,'.',0,'o',0,'r',0,'g',0, /*bString iManufacturer - mbed.org*/
- };
- return stringImanufacturerDescriptor;
-}
-
-uint8_t * USBDevice::stringIserialDesc() {
- static uint8_t stringIserialDescriptor[] = {
- 0x16, /*bLength*/
- STRING_DESCRIPTOR, /*bDescriptorType 0x03*/
- '0',0,'1',0,'2',0,'3',0,'4',0,'5',0,'6',0,'7',0,'8',0,'9',0, /*bString iSerial - 0123456789*/
- };
- return stringIserialDescriptor;
-}
-
-uint8_t * USBDevice::stringIConfigurationDesc() {
- static uint8_t stringIconfigurationDescriptor[] = {
- 0x06, /*bLength*/
- STRING_DESCRIPTOR, /*bDescriptorType 0x03*/
- '0',0,'1',0, /*bString iConfiguration - 01*/
- };
- return stringIconfigurationDescriptor;
-}
-
-uint8_t * USBDevice::stringIinterfaceDesc() {
- static uint8_t stringIinterfaceDescriptor[] = {
- 0x08, /*bLength*/
- STRING_DESCRIPTOR, /*bDescriptorType 0x03*/
- 'U',0,'S',0,'B',0, /*bString iInterface - USB*/
- };
- return stringIinterfaceDescriptor;
-}
-
-uint8_t * USBDevice::stringIproductDesc() {
- static uint8_t stringIproductDescriptor[] = {
- 0x16, /*bLength*/
- STRING_DESCRIPTOR, /*bDescriptorType 0x03*/
- 'U',0,'S',0,'B',0,' ',0,'D',0,'E',0,'V',0,'I',0,'C',0,'E',0 /*bString iProduct - USB DEVICE*/
- };
- return stringIproductDescriptor;
-}
--- a/USBDevice/USBDevice/USBDevice.h Mon Nov 14 10:00:07 2011 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,231 +0,0 @@
-/* USBDevice.h */
-/* Generic USB device */
-/* Copyright (c) 2011 ARM Limited. All rights reserved. */
-
-#ifndef USBDEVICE_H
-#define USBDEVICE_H
-
-#include "mbed.h"
-#include "USBDevice_Types.h"
-#include "USBBusInterface.h"
-
-
-
-class USBDevice: public USBHAL
-{
-public:
- USBDevice(uint16_t vendor_id, uint16_t product_id, uint16_t product_release);
-
- /*
- * Check if the device is configured
- *
- * @returns true if configured, false otherwise
- */
- bool configured(void);
-
- /*
- * Connect a device
- */
- void connect(void);
-
- /*
- * Disconnect a device
- */
- void disconnect(void);
-
- /*
- * Add an endpoint
- *
- * @param endpoint endpoint which will be added
- * @param maxPacket Maximum size of a packet which can be sent for this endpoint
- * @returns true if successful, false otherwise
- */
- bool addEndpoint(uint8_t endpoint, uint32_t maxPacket);
-
- /*
- * Start a reading on a certain endpoint.
- * You can access the result of the reading by USBDevice_read
- *
- * @param endpoint endpoint which will be read
- * @param maxSize the maximum length that can be read
- * @return true if successful
- */
- bool readStart(uint8_t endpoint, uint16_t maxSize);
-
- /*
- * Read a certain endpoint. Before calling this function, USBUSBDevice_readStart
- * must be called.
- *
- * Warning: blocking
- *
- * @param endpoint endpoint which will be read
- * @param buffer buffer will be filled with the data received
- * @param size the number of bytes read will be stored in *size
- * @param maxSize the maximum length that can be read
- * @returns true if successful
- */
- bool read(uint8_t endpoint, uint8_t * buffer, uint16_t * size, uint16_t maxSize);
-
- /*
- * Read a certain endpoint.
- *
- * Warning: non blocking
- *
- * @param endpoint endpoint which will be read
- * @param buffer buffer will be filled with the data received (if data are available)
- * @param size the number of bytes read will be stored in *size
- * @param maxSize the maximum length that can be read
- * @returns true if successful
- */
- bool readNB(uint8_t endpoint, uint8_t * buffer, uint16_t * size, uint16_t maxSize);
-
- /*
- * Write a certain endpoint.
- *
- * Warning: blocking
- *
- * @param endpoint endpoint to write
- * @param buffer data contained in buffer will be write
- * @param size the number of bytes to write
- * @param maxSize the maximum length that can be written on this endpoint
- */
- bool write(uint8_t endpoint, uint8_t * buffer, uint16_t size, uint16_t maxSize);
- bool writeNB(uint8_t endpoint, uint8_t * buffer, uint16_t size, uint16_t maxSize);
-
-
- /*
- * Called by USBDevice layer on bus reset. Warning: Called in ISR context
- *
- * May be used to reset state
- */
- virtual void USBCallback_busReset(void) {};
-
- /*
- * Called by USBDevice on Endpoint0 request. Warning: Called in ISR context
- * This is used to handle extensions to standard requests
- * and class specific requests
- *
- * @returns true if class handles this request
- */
- virtual bool USBCallback_request() { return false; };
-
- /*
- * Called by USBDevice on Endpoint0 request completion
- * if the 'notify' flag has been set to true. Warning: Called in ISR context
- *
- * In this case it is used to indicate that a HID report has
- * been received from the host on endpoint 0
- */
- virtual void USBCallback_requestCompleted() {};
-
- /*
- * Called by USBDevice layer. Set configuration of the device.
- * For instance, you can add all endpoints that you need on this function.
- *
- * @param configuration Number of the configuration
- */
- virtual bool USBCallback_setConfiguration(uint8_t configuration) { return false; };
-
- /*
- * Get device descriptor. Warning: this method has to store the length of the report descriptor in reportLength.
- *
- * @returns pointer to the device descriptor
- */
- virtual uint8_t * deviceDesc();
-
- /*
- * Get configuration descriptor
- *
- * @returns pointer to the configuration descriptor
- */
- virtual uint8_t * configurationDesc(){return NULL;};
-
- /*
- * Get string lang id descriptor
- *
- * @return pointer to the string lang id descriptor
- */
- virtual uint8_t * stringLangidDesc();
-
- /*
- * Get string manufacturer descriptor
- *
- * @returns pointer to the string manufacturer descriptor
- */
- virtual uint8_t * stringImanufacturerDesc();
-
- /*
- * Get string product descriptor
- *
- * @returns pointer to the string product descriptor
- */
- virtual uint8_t * stringIproductDesc();
-
- /*
- * Get string serial descriptor
- *
- * @returns pointer to the string serial descriptor
- */
- virtual uint8_t * stringIserialDesc();
-
- /*
- * Get string configuration descriptor
- *
- * @returns pointer to the string configuration descriptor
- */
- virtual uint8_t * stringIConfigurationDesc();
-
- /*
- * Get string interface descriptor
- *
- * @returns pointer to the string interface descriptor
- */
- virtual uint8_t * stringIinterfaceDesc();
-
- /*
- * Get the length of the report descriptor
- *
- * @returns length of the report descriptor
- */
- virtual uint16_t reportDescLength() { return 0; };
-
-
-
-protected:
- virtual void busReset(void);
- virtual void EP0setupCallback(void);
- virtual void EP0out(void);
- virtual void EP0in(void);
- virtual void SOF(int frameNumber);
- virtual void connectStateChanged(unsigned int connected);
- virtual void suspendStateChanged(unsigned int suspended);
- uint8_t * findDescriptor(uint8_t descriptorType);
- CONTROL_TRANSFER * getTransferPtr(void);
-
- uint16_t VENDOR_ID;
- uint16_t PRODUCT_ID;
- uint16_t PRODUCT_RELEASE;
-
-private:
- bool addRateFeedbackEndpoint(uint8_t endpoint, uint32_t maxPacket);
- bool requestGetDescriptor(void);
- bool controlOut(void);
- bool controlIn(void);
- bool requestSetAddress(void);
- bool requestSetConfiguration(void);
- bool requestSetFeature(void);
- bool requestClearFeature(void);
- bool requestGetStatus(void);
- bool requestSetup(void);
- bool controlSetup(void);
- void decodeSetupPacket(uint8_t *data, SETUP_PACKET *packet);
- bool requestGetConfiguration(void);
- bool requestGetInterface(void);
- bool requestSetInterface(void);
-
- CONTROL_TRANSFER transfer;
- USB_DEVICE device;
-};
-
-
-#endif
--- a/USBDevice/USBDevice/USBDevice_Types.h Mon Nov 14 10:00:07 2011 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,69 +0,0 @@
-/* USBDevice_Types.h */
-/* USB Device type definitions, conversions and constants */
-/* Copyright (c) 2011 ARM Limited. All rights reserved. */
-
-#ifndef USBDEVICE_TYPES_H
-#define USBDEVICE_TYPES_H
-
-/* Standard requests */
-#define GET_STATUS (0)
-#define CLEAR_FEATURE (1)
-#define SET_FEATURE (3)
-#define SET_ADDRESS (5)
-#define GET_DESCRIPTOR (6)
-#define SET_DESCRIPTOR (7)
-#define GET_CONFIGURATION (8)
-#define SET_CONFIGURATION (9)
-#define GET_INTERFACE (10)
-#define SET_INTERFACE (11)
-
-/* bmRequestType.dataTransferDirection */
-#define HOST_TO_DEVICE (0)
-#define DEVICE_TO_HOST (1)
-
-/* bmRequestType.Type*/
-#define STANDARD_TYPE (0)
-#define CLASS_TYPE (1)
-#define VENDOR_TYPE (2)
-#define RESERVED_TYPE (3)
-
-/* bmRequestType.Recipient */
-#define DEVICE_RECIPIENT (0)
-#define INTERFACE_RECIPIENT (1)
-#define ENDPOINT_RECIPIENT (2)
-#define OTHER_RECIPIENT (3)
-
-/* Descriptors */
-#define DESCRIPTOR_TYPE(wValue) (wValue >> 8)
-#define DESCRIPTOR_INDEX(wValue) (wValue & 0xf)
-
-typedef struct {
- struct {
- uint8_t dataTransferDirection;
- uint8_t Type;
- uint8_t Recipient;
- } bmRequestType;
- uint8_t bRequest;
- uint16_t wValue;
- uint16_t wIndex;
- uint16_t wLength;
-} SETUP_PACKET;
-
-typedef struct {
- SETUP_PACKET setup;
- uint8_t *ptr;
- uint32_t remaining;
- uint8_t direction;
- bool zlp;
- bool notify;
-} CONTROL_TRANSFER;
-
-typedef enum {ATTACHED, POWERED, DEFAULT, ADDRESS, CONFIGURED} DEVICE_STATE;
-
-typedef struct {
- volatile DEVICE_STATE state;
- uint8_t configuration;
- bool suspended;
-} USB_DEVICE;
-
-#endif
--- a/USBDevice/USBDevice/USBEndpoints.h Mon Nov 14 10:00:07 2011 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-/* USBEndpoints.h */
-/* USB endpoint configuration */
-/* Copyright (c) 2011 ARM Limited. All rights reserved. */
-
-#ifndef USBENDPOINTS_H
-#define USBENDPOINTS_H
-
-/* SETUP packet size */
-#define SETUP_PACKET_SIZE (8)
-
-/* Options flags for configuring endpoints */
-#define DEFAULT_OPTIONS (0)
-#define SINGLE_BUFFERED (1U << 0)
-#define ISOCHRONOUS (1U << 1)
-#define RATE_FEEDBACK_MODE (1U << 2) /* Interrupt endpoints only */
-
-/* Endpoint transfer status, for endpoints > 0 */
-typedef enum {
- EP_COMPLETED, /* Transfer completed */
- EP_PENDING, /* Transfer in progress */
- EP_INVALID, /* Invalid parameter */
- EP_STALLED, /* Endpoint stalled */
-} EP_STATUS;
-
-/* Include configuration for specific target */
-#if defined(TARGET_LPC1768) || defined(TARGET_LPC2368)
-#include "USBEndpoints_LPC17_LPC23.h"
-#elif defined(TARGET_LPC11U24)
-#include "USBEndpoints_LPC11U.h"
-#else
-#error "Unknown target type"
-#endif
-
-#endif
--- a/USBDevice/USBDevice/USBEndpoints_LPC11U.h Mon Nov 14 10:00:07 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ -/* USBEndpoints_LPC11U.h */ -/* Endpoint configuration for LPC11U */ -/* Copyright (c) 2011 ARM Limited. All rights reserved. */ - -#define NUMBER_OF_LOGICAL_ENDPOINTS (5) -#define NUMBER_OF_PHYSICAL_ENDPOINTS (NUMBER_OF_LOGICAL_ENDPOINTS * 2) - -/* Define physical endpoint numbers */ - -/* Endpoint No. Type(s) MaxPacket DoubleBuffer */ -/* ---------------- ------------ ---------- --- */ -#define EP0OUT (0) /* Control 64 No */ -#define EP0IN (1) /* Control 64 No */ -#define EP1OUT (2) /* Int/Bulk/Iso 64/64/1023 Yes */ -#define EP1IN (3) /* Int/Bulk/Iso 64/64/1023 Yes */ -#define EP2OUT (4) /* Int/Bulk/Iso 64/64/1023 Yes */ -#define EP2IN (5) /* Int/Bulk/Iso 64/64/1023 Yes */ -#define EP3OUT (6) /* Int/Bulk/Iso 64/64/1023 Yes */ -#define EP3IN (7) /* Int/Bulk/Iso 64/64/1023 Yes */ -#define EP4OUT (8) /* Int/Bulk/Iso 64/64/1023 Yes */ -#define EP4IN (9) /* Int/Bulk/Iso 64/64/1023 Yes */ - -/* Maximum Packet sizes */ - -#define MAX_PACKET_SIZE_EP0 (64) -#define MAX_PACKET_SIZE_EP1 (64) /* Int/Bulk */ -#define MAX_PACKET_SIZE_EP2 (64) /* Int/Bulk */ -#define MAX_PACKET_SIZE_EP3 (64) /* Int/Bulk */ -#define MAX_PACKET_SIZE_EP4 (64) /* Int/Bulk */ - -#define MAX_PACKET_SIZE_EP1_ISO (1023) /* Isochronous */ -#define MAX_PACKET_SIZE_EP2_ISO (1023) /* Isochronous */ -#define MAX_PACKET_SIZE_EP3_ISO (1023) /* Isochronous */ -#define MAX_PACKET_SIZE_EP4_ISO (1023) /* Isochronous */ - -/* Generic endpoints - intended to be portable accross devices */ -/* and be suitable for simple USB devices. */ - -/* Bulk endpoint */ -#define EPBULK_OUT (EP2OUT) -#define EPBULK_IN (EP2IN) -/* Interrupt endpoint */ -#define EPINT_OUT (EP1OUT) -#define EPINT_IN (EP1IN) -/* Isochronous endpoint */ -#define EPISO_OUT (EP3OUT) -#define EPISO_IN (EP3IN) - -#define MAX_PACKET_SIZE_EPBULK (MAX_PACKET_SIZE_EP2) -#define MAX_PACKET_SIZE_EPINT (MAX_PACKET_SIZE_EP1) -#define MAX_PACKET_SIZE_EPISO (MAX_PACKET_SIZE_EP3_ISO)
--- a/USBDevice/USBDevice/USBEndpoints_LPC17_LPC23.h Mon Nov 14 10:00:07 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,79 +0,0 @@ -/* USBEndpoints_LPC17_LPC23.h */ -/* Endpoint configuration for LPC1768 and LPC2368 */ -/* Copyright (c) 2011 ARM Limited. All rights reserved. */ - -#define NUMBER_OF_LOGICAL_ENDPOINTS (16) -#define NUMBER_OF_PHYSICAL_ENDPOINTS (NUMBER_OF_LOGICAL_ENDPOINTS * 2) - -/* Define physical endpoint numbers */ - -/* Endpoint No. Type(s) MaxPacket DoubleBuffer */ -/* ---------------- ------------ ---------- --- */ -#define EP0OUT (0) /* Control 64 No */ -#define EP0IN (1) /* Control 64 No */ -#define EP1OUT (2) /* Interrupt 64 No */ -#define EP1IN (3) /* Interrupt 64 No */ -#define EP2OUT (4) /* Bulk 64 Yes */ -#define EP2IN (5) /* Bulk 64 Yes */ -#define EP3OUT (6) /* Isochronous 1023 Yes */ -#define EP3IN (7) /* Isochronous 1023 Yes */ -#define EP4OUT (8) /* Interrupt 64 No */ -#define EP4IN (9) /* Interrupt 64 No */ -#define EP5OUT (10) /* Bulk 64 Yes */ -#define EP5IN (11) /* Bulk 64 Yes */ -#define EP6OUT (12) /* Isochronous 1023 Yes */ -#define EP6IN (13) /* Isochronous 1023 Yes */ -#define EP7OUT (14) /* Interrupt 64 No */ -#define EP7IN (15) /* Interrupt 64 No */ -#define EP8OUT (16) /* Bulk 64 Yes */ -#define EP8IN (17) /* Bulk 64 Yes */ -#define EP9OUT (18) /* Isochronous 1023 Yes */ -#define EP9IN (19) /* Isochronous 1023 Yes */ -#define EP10OUT (20) /* Interrupt 64 No */ -#define EP10IN (21) /* Interrupt 64 No */ -#define EP11OUT (22) /* Bulk 64 Yes */ -#define EP11IN (23) /* Bulk 64 Yes */ -#define EP12OUT (24) /* Isochronous 1023 Yes */ -#define EP12IN (25) /* Isochronous 1023 Yes */ -#define EP13OUT (26) /* Interrupt 64 No */ -#define EP13IN (27) /* Interrupt 64 No */ -#define EP14OUT (28) /* Bulk 64 Yes */ -#define EP14IN (29) /* Bulk 64 Yes */ -#define EP15OUT (30) /* Bulk 64 Yes */ -#define EP15IN (31) /* Bulk 64 Yes */ - -/* Maximum Packet sizes */ - -#define MAX_PACKET_SIZE_EP0 (64) -#define MAX_PACKET_SIZE_EP1 (64) -#define MAX_PACKET_SIZE_EP2 (64) -#define MAX_PACKET_SIZE_EP3 (1023) -#define MAX_PACKET_SIZE_EP4 (64) -#define MAX_PACKET_SIZE_EP5 (64) -#define MAX_PACKET_SIZE_EP6 (1023) -#define MAX_PACKET_SIZE_EP7 (64) -#define MAX_PACKET_SIZE_EP8 (64) -#define MAX_PACKET_SIZE_EP9 (1023) -#define MAX_PACKET_SIZE_EP10 (64) -#define MAX_PACKET_SIZE_EP11 (64) -#define MAX_PACKET_SIZE_EP12 (1023) -#define MAX_PACKET_SIZE_EP13 (64) -#define MAX_PACKET_SIZE_EP14 (64) -#define MAX_PACKET_SIZE_EP15 (64) - -/* Generic endpoints - intended to be portable accross devices */ -/* and be suitable for simple USB devices. */ - -/* Bulk endpoints */ -#define EPBULK_OUT (EP2OUT) -#define EPBULK_IN (EP2IN) -/* Interrupt endpoints */ -#define EPINT_OUT (EP1OUT) -#define EPINT_IN (EP1IN) -/* Isochronous endpoints */ -#define EPISO_OUT (EP3OUT) -#define EPISO_IN (EP3IN) - -#define MAX_PACKET_SIZE_EPBULK (MAX_PACKET_SIZE_EP2) -#define MAX_PACKET_SIZE_EPINT (MAX_PACKET_SIZE_EP1) -#define MAX_PACKET_SIZE_EPISO (MAX_PACKET_SIZE_EP3)
--- a/USBDevice/USBHID/USBHID.cpp Mon Nov 14 10:00:07 2011 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,259 +0,0 @@
-// USBHID.c
-// Human Interface Device (HID) class
-// Copyright (c) 2011 ARM Limited. All rights reserved.
-
-#include "stdint.h"
-#include "USBBusInterface.h"
-#include "USBHID.h"
-
-
-USBHID::USBHID(uint8_t output_report_length, uint8_t input_report_length, uint16_t vendor_id, uint16_t product_id, uint16_t product_release): USBDevice(vendor_id, product_id, product_release)
-{
- output_length = output_report_length;
- input_length = input_report_length;
-}
-
-
-bool USBHID::send(HID_REPORT *report)
-{
- return write(EPINT_IN, report->data, report->length, MAX_HID_REPORT_SIZE);
-}
-
-
-bool USBHID::read(HID_REPORT *report)
-{
- uint16_t bytesRead = 0;
- bool result;
- result = USBDevice::read(EPINT_OUT, report->data, &bytesRead, MAX_HID_REPORT_SIZE);
- if(!readStart(EPINT_OUT, MAX_HID_REPORT_SIZE))
- return false;
- report->length = bytesRead;
- return result;
-}
-
-
-bool USBHID::readNB(HID_REPORT *report)
-{
- uint16_t bytesRead = 0;
- bool result;
- result = USBDevice::readNB(EPINT_OUT, report->data, &bytesRead, MAX_HID_REPORT_SIZE);
- report->length = bytesRead;
- if(!readStart(EPINT_OUT, MAX_HID_REPORT_SIZE))
- return false;
- return result;
-}
-
-
-uint16_t USBHID::reportDescLength() {
- reportDesc();
- return reportLength;
-}
-
-
-
-//
-// Route callbacks from lower layers to class(es)
-//
-
-
-// Called in ISR context
-// Called by USBDevice on Endpoint0 request
-// This is used to handle extensions to standard requests
-// and class specific requests
-// Return true if class handles this request
-bool USBHID::USBCallback_request() {
- bool success = false;
- CONTROL_TRANSFER * transfer = getTransferPtr();
- uint8_t *hidDescriptor;
-
- // Process additional standard requests
-
- if ((transfer->setup.bmRequestType.Type == STANDARD_TYPE))
- {
- switch (transfer->setup.bRequest)
- {
- case GET_DESCRIPTOR:
- switch (DESCRIPTOR_TYPE(transfer->setup.wValue))
- {
- case REPORT_DESCRIPTOR:
- if ((reportDesc() != NULL) \
- && (reportDescLength() != 0))
- {
- transfer->remaining = reportDescLength();
- transfer->ptr = reportDesc();
- transfer->direction = DEVICE_TO_HOST;
- success = true;
- }
- break;
- case HID_DESCRIPTOR:
- // Find the HID descriptor, after the configuration descriptor
- hidDescriptor = findDescriptor(HID_DESCRIPTOR);
- if (hidDescriptor != NULL)
- {
- transfer->remaining = HID_DESCRIPTOR_LENGTH;
- transfer->ptr = hidDescriptor;
- transfer->direction = DEVICE_TO_HOST;
- success = true;
- }
- break;
-
- default:
- break;
- }
- break;
- default:
- break;
- }
- }
-
- // Process class-specific requests
-
- if (transfer->setup.bmRequestType.Type == CLASS_TYPE)
- {
- switch (transfer->setup.bRequest)
- {
- case SET_REPORT:
- // First byte will be used for report ID
- outputReport.data[0] = transfer->setup.wValue & 0xff;
- outputReport.length = transfer->setup.wLength + 1;
-
- transfer->remaining = sizeof(outputReport.data) - 1;
- transfer->ptr = &outputReport.data[1];
- transfer->direction = HOST_TO_DEVICE;
- transfer->notify = true;
- success = true;
- default:
- break;
- }
- }
-
- return success;
-}
-
-
-// Called in ISR context
-// Called by USBDevice on Endpoint0 request completion
-// if the 'notify' flag has been set to true
-// In this case it is used to indicate that a HID report has
-// been received from the host on endpoint 0
-void USBHID::USBCallback_requestCompleted() {
- HID_callbackSetReport(&outputReport);
-}
-
-#define DEFAULT_CONFIGURATION (1)
-
-
-// Called in ISR context
-// Set configuration. Return false if the
-// configuration is not supported
-bool USBHID::USBCallback_setConfiguration(uint8_t configuration) {
- if (configuration != DEFAULT_CONFIGURATION) {
- return false;
- }
-
- // Configure endpoints > 0
- addEndpoint(EPINT_IN, MAX_PACKET_SIZE_EPINT);
- addEndpoint(EPINT_OUT, MAX_PACKET_SIZE_EPINT);
-
- // We activate the endpoint to be able to recceive data
- readStart(EPINT_OUT, MAX_PACKET_SIZE_EPINT);
- return true;
-}
-
-uint8_t * USBHID::stringIinterfaceDesc() {
- static uint8_t stringIinterfaceDescriptor[] = {
- 0x08, //bLength
- STRING_DESCRIPTOR, //bDescriptorType 0x03
- 'H',0,'I',0,'D',0, //bString iInterface - HID
- };
- return stringIinterfaceDescriptor;
-}
-
-uint8_t * USBHID::stringIproductDesc() {
- static uint8_t stringIproductDescriptor[] = {
- 0x16, //bLength
- STRING_DESCRIPTOR, //bDescriptorType 0x03
- 'H',0,'I',0,'D',0,' ',0,'D',0,'E',0,'V',0,'I',0,'C',0,'E',0 //bString iProduct - HID device
- };
- return stringIproductDescriptor;
-}
-
-
-
-uint8_t * USBHID::reportDesc() {
- static uint8_t reportDescriptor[] = {
- 0x06, LSB(0xFFAB), MSB(0xFFAB),
- 0x0A, LSB(0x0200), MSB(0x0200),
- 0xA1, 0x01, // Collection 0x01
- 0x75, 0x08, // report size = 8 bits
- 0x15, 0x00, // logical minimum = 0
- 0x26, 0xFF, 0x00, // logical maximum = 255
- 0x95, input_length, // report count
- 0x09, 0x01, // usage
- 0x81, 0x02, // Input (array)
- 0x95, output_length, // report count
- 0x09, 0x02, // usage
- 0x91, 0x02, // Output (array)
- 0xC0 // end collection
-
- };
- reportLength = sizeof(reportDescriptor);
- return reportDescriptor;
-}
-
-#define DEFAULT_CONFIGURATION (1)
-#define TOTAL_DESCRIPTOR_LENGTH ((1 * CONFIGURATION_DESCRIPTOR_LENGTH) \
- + (1 * INTERFACE_DESCRIPTOR_LENGTH) \
- + (1 * HID_DESCRIPTOR_LENGTH) \
- + (2 * ENDPOINT_DESCRIPTOR_LENGTH))
-
-uint8_t * USBHID::configurationDesc() {
- static uint8_t configurationDescriptor[] = {
- CONFIGURATION_DESCRIPTOR_LENGTH,// bLength
- CONFIGURATION_DESCRIPTOR, // bDescriptorType
- LSB(TOTAL_DESCRIPTOR_LENGTH), // wTotalLength (LSB)
- MSB(TOTAL_DESCRIPTOR_LENGTH), // wTotalLength (MSB)
- 0x01, // bNumInterfaces
- DEFAULT_CONFIGURATION, // bConfigurationValue
- 0x00, // iConfiguration
- C_RESERVED | C_SELF_POWERED, // bmAttributes
- C_POWER(0), // bMaxPower
-
- INTERFACE_DESCRIPTOR_LENGTH, // bLength
- INTERFACE_DESCRIPTOR, // bDescriptorType
- 0x00, // bInterfaceNumber
- 0x00, // bAlternateSetting
- 0x02, // bNumEndpoints
- HID_CLASS, // bInterfaceClass
- HID_SUBCLASS_NONE, // bInterfaceSubClass
- HID_PROTOCOL_NONE, // bInterfaceProtocol
- 0x00, // iInterface
-
- HID_DESCRIPTOR_LENGTH, // bLength
- HID_DESCRIPTOR, // bDescriptorType
- LSB(HID_VERSION_1_11), // bcdHID (LSB)
- MSB(HID_VERSION_1_11), // bcdHID (MSB)
- 0x00, // bCountryCode
- 0x01, // bNumDescriptors
- REPORT_DESCRIPTOR, // bDescriptorType
- LSB(this->reportDescLength()), // wDescriptorLength (LSB)
- MSB(this->reportDescLength()), // wDescriptorLength (MSB)
-
- ENDPOINT_DESCRIPTOR_LENGTH, // bLength
- ENDPOINT_DESCRIPTOR, // bDescriptorType
- PHY_TO_DESC(EPINT_IN), // bEndpointAddress
- E_INTERRUPT, // bmAttributes
- LSB(MAX_PACKET_SIZE_EPINT), // wMaxPacketSize (LSB)
- MSB(MAX_PACKET_SIZE_EPINT), // wMaxPacketSize (MSB)
- 10, // bInterval (milliseconds)
-
- ENDPOINT_DESCRIPTOR_LENGTH, // bLength
- ENDPOINT_DESCRIPTOR, // bDescriptorType
- PHY_TO_DESC(EPINT_OUT), // bEndpointAddress
- E_INTERRUPT, // bmAttributes
- LSB(MAX_PACKET_SIZE_EPINT), // wMaxPacketSize (LSB)
- MSB(MAX_PACKET_SIZE_EPINT), // wMaxPacketSize (MSB)
- 10, // bInterval (milliseconds)
- };
- return configurationDescriptor;
-}
--- a/USBDevice/USBHID/USBHID.h Mon Nov 14 10:00:07 2011 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,156 +0,0 @@
-/* USBHID.h */
-/* Human Interface Device (HID) class */
-/* Copyright (c) 2011 ARM Limited. All rights reserved. */
-
-#ifndef USB_HID_H
-#define USB_HID_H
-
-/* These headers are included for child class. */
-#include "USBEndpoints.h"
-#include "USBDescriptor.h"
-#include "USBDevice_Types.h"
-
-#include "USBHID_Types.h"
-#include "USBDevice.h"
-
-
-/**
- * USBHID example
- * @code
- * #include "mbed.h"
- * #include "USBHID.h"
- *
- * USBHID hid;
- * HID_REPORT recv;
- * BusOut leds(LED1,LED2,LED3,LED4);
- *
- * int main(void) {
- * while (1) {
- * hid.read(&recv);
- * leds = recv.data[0];
- * }
- * }
- * @endcode
- */
-
-class USBHID: public USBDevice {
-public:
-
- /**
- * Constructor
- *
- * @param output_report_length Maximum length of a sent report (up to 64 bytes) (default: 64 bytes)
- * @param input_report_length Maximum length of a received report (up to 64 bytes) (default: 64 bytes)
- * @param vendor_id Your vendor_id
- * @param product_id Your product_id
- * @param product_release Your preoduct_release
- */
- USBHID(uint8_t output_report_length = 64, uint8_t input_report_length = 64, uint16_t vendor_id = 0x1234, uint16_t product_id = 0x0006, uint16_t product_release = 0x0001);
-
-
- /**
- * Send a Report
- *
- * @param report Report which will be sent (a report is defined by all data and the length)
- * @returns true if successful
- */
- bool send(HID_REPORT *report);
-
- /**
- * Read a report: blocking
- *
- * @param report pointer to the report to fill
- * @returns true if successful
- */
- bool read(HID_REPORT * report);
-
- /**
- * Read a report: non blocking
- *
- * @param report pointer to the report to fill
- * @returns true if successful
- */
- bool readNB(HID_REPORT * report);
-
-protected:
- uint16_t reportLength;
-
- /*
- * Get the Report descriptor
- *
- * @returns pointer to the report descriptor
- */
- virtual uint8_t * reportDesc();
-
- /*
- * Get the length of the report descriptor
- *
- * @returns the length of the report descriptor
- */
- virtual uint16_t reportDescLength();
-
- /*
- * Get string product descriptor
- *
- * @returns pointer to the string product descriptor
- */
- virtual uint8_t * stringIproductDesc();
-
- /*
- * Get string interface descriptor
- *
- * @returns pointer to the string interface descriptor
- */
- virtual uint8_t * stringIinterfaceDesc();
-
- /*
- * Get configuration descriptor
- *
- * @returns pointer to the configuration descriptor
- */
- virtual uint8_t * configurationDesc();
-
-
- /*
- * HID Report received by SET_REPORT request. Warning: Called in ISR context
- * First byte of data will be the report ID
- *
- * @param report Data and length received
- */
- virtual void HID_callbackSetReport(HID_REPORT *report){};
-
-
- /*
- * Called by USBDevice on Endpoint0 request. Warning: Called in ISR context
- * This is used to handle extensions to standard requests
- * and class specific requests
- *
- * @returns true if class handles this request
- */
- virtual bool USBCallback_request();
-
- /*
- * Called by USBDevice on Endpoint0 request completion
- * if the 'notify' flag has been set to true. Warning: Called in ISR context
- *
- * In this case it is used to indicate that a HID report has
- * been received from the host on endpoint 0
- */
- virtual void USBCallback_requestCompleted();
-
- /*
- * Called by USBDevice layer. Set configuration of the device.
- * For instance, you can add all endpoints that you need on this function.
- *
- * @param configuration Number of the configuration
- * @returns true if class handles this request
- */
- virtual bool USBCallback_setConfiguration(uint8_t configuration);
-
-private:
- HID_REPORT outputReport;
- uint8_t output_length;
- uint8_t input_length;
-};
-
-#endif
--- a/USBDevice/USBHID/USBHID_Types.h Mon Nov 14 10:00:07 2011 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,77 +0,0 @@
-/* USBClass_HID_Types.h */
-/* USB HID class type definitions, conversions and constants */
-/* Copyright (c) 2011 ARM Limited. All rights reserved. */
-
-#ifndef USBCLASS_HID_TYPES
-#define USBCLASS_HID_TYPES
-
-#include <stdint.h>
-
-/* */
-#define HID_VERSION_1_11 (0x0111)
-
-/* HID Class */
-#define HID_CLASS (3)
-#define HID_SUBCLASS_NONE (0)
-#define HID_PROTOCOL_NONE (0)
-
-/* Descriptors */
-#define HID_DESCRIPTOR (33)
-#define HID_DESCRIPTOR_LENGTH (0x09)
-#define REPORT_DESCRIPTOR (34)
-
-/* Class requests */
-#define GET_REPORT (0x1)
-#define GET_IDLE (0x2)
-#define SET_REPORT (0x9)
-#define SET_IDLE (0xa)
-
-/* HID Class Report Descriptor */
-/* Short items: size is 0, 1, 2 or 3 specifying 0, 1, 2 or 4 (four) bytes */
-/* of data as per HID Class standard */
-
-/* Main items */
-#define INPUT(size) (0x80 | size)
-#define OUTPUT(size) (0x90 | size)
-#define FEATURE(size) (0xb0 | size)
-#define COLLECTION(size) (0xa0 | size)
-#define END_COLLECTION(size) (0xc0 | size)
-
-/* Global items */
-#define USAGE_PAGE(size) (0x04 | size)
-#define LOGICAL_MINIMUM(size) (0x14 | size)
-#define LOGICAL_MAXIMUM(size) (0x24 | size)
-#define PHYSICAL_MINIMUM(size) (0x34 | size)
-#define PHYSICAL_MAXIMUM(size) (0x44 | size)
-#define UNIT_EXPONENT(size) (0x54 | size)
-#define UNIT(size) (0x64 | size)
-#define REPORT_SIZE(size) (0x74 | size)
-#define REPORT_ID(size) (0x84 | size)
-#define REPORT_COUNT(size) (0x94 | size)
-#define PUSH(size) (0xa4 | size)
-#define POP(size) (0xb4 | size)
-
-/* Local items */
-#define USAGE(size) (0x08 | size)
-#define USAGE_MINIMUM(size) (0x18 | size)
-#define USAGE_MAXIMUM(size) (0x28 | size)
-#define DESIGNATOR_INDEX(size) (0x38 | size)
-#define DESIGNATOR_MINIMUM(size) (0x48 | size)
-#define DESIGNATOR_MAXIMUM(size) (0x58 | size)
-#define STRING_INDEX(size) (0x78 | size)
-#define STRING_MINIMUM(size) (0x88 | size)
-#define STRING_MAXIMUM(size) (0x98 | size)
-#define DELIMITER(size) (0xa8 | size)
-
-/* HID Report */
-/* Where report IDs are used the first byte of 'data' will be the */
-/* report ID and 'length' will include this report ID byte. */
-
-#define MAX_HID_REPORT_SIZE (64)
-
-typedef struct {
- uint32_t length;
- uint8_t data[MAX_HID_REPORT_SIZE];
-} HID_REPORT;
-
-#endif
--- a/USBDevice/USBHID/USBKeyboard.cpp Mon Nov 14 10:00:07 2011 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,472 +0,0 @@
-// USBKeyboard.c
-// USB device example: Standard keyboard
-// Copyright (c) 2011 ARM Limited. All rights reserved.
-
-#include "stdint.h"
-
-#include "USBKeyboard.h"
-
-#define REPORT_ID_KEYBOARD 1
-#define REPORT_ID_VOLUME 3
-
-
-typedef struct {
- unsigned char usage;
- unsigned char modifier;
-} KEYMAP;
-
-#ifdef US_KEYBOARD
-/* US keyboard (as HID standard) */
-#define KEYMAP_SIZE (148)
-const KEYMAP keymap[KEYMAP_SIZE] = {
- {0, 0}, /* NUL */
- {0, 0}, /* SOH */
- {0, 0}, /* STX */
- {0, 0}, /* ETX */
- {0, 0}, /* EOT */
- {0, 0}, /* ENQ */
- {0, 0}, /* ACK */
- {0, 0}, /* BEL */
- {0x2a, 0}, /* BS */ /* Keyboard Delete (Backspace) */
- {0x2b, 0}, /* TAB */ /* Keyboard Tab */
- {0x28, 0}, /* LF */ /* Keyboard Return (Enter) */
- {0, 0}, /* VT */
- {0, 0}, /* FF */
- {0, 0}, /* CR */
- {0, 0}, /* SO */
- {0, 0}, /* SI */
- {0, 0}, /* DEL */
- {0, 0}, /* DC1 */
- {0, 0}, /* DC2 */
- {0, 0}, /* DC3 */
- {0, 0}, /* DC4 */
- {0, 0}, /* NAK */
- {0, 0}, /* SYN */
- {0, 0}, /* ETB */
- {0, 0}, /* CAN */
- {0, 0}, /* EM */
- {0, 0}, /* SUB */
- {0, 0}, /* ESC */
- {0, 0}, /* FS */
- {0, 0}, /* GS */
- {0, 0}, /* RS */
- {0, 0}, /* US */
- {0x2c, 0}, /* */
- {0x1e, KEY_SHIFT}, /* ! */
- {0x34, KEY_SHIFT}, /* " */
- {0x20, KEY_SHIFT}, /* # */
- {0x21, KEY_SHIFT}, /* $ */
- {0x22, KEY_SHIFT}, /* % */
- {0x24, KEY_SHIFT}, /* & */
- {0x34, 0}, /* ' */
- {0x26, KEY_SHIFT}, /* ( */
- {0x27, KEY_SHIFT}, /* ) */
- {0x25, KEY_SHIFT}, /* * */
- {0x2e, KEY_SHIFT}, /* + */
- {0x36, 0}, /* , */
- {0x2d, 0}, /* - */
- {0x37, 0}, /* . */
- {0x38, 0}, /* / */
- {0x27, 0}, /* 0 */
- {0x1e, 0}, /* 1 */
- {0x1f, 0}, /* 2 */
- {0x20, 0}, /* 3 */
- {0x21, 0}, /* 4 */
- {0x22, 0}, /* 5 */
- {0x23, 0}, /* 6 */
- {0x24, 0}, /* 7 */
- {0x25, 0}, /* 8 */
- {0x26, 0}, /* 9 */
- {0x33, KEY_SHIFT}, /* : */
- {0x33, 0}, /* ; */
- {0x36, KEY_SHIFT}, /* < */
- {0x2e, 0}, /* = */
- {0x37, KEY_SHIFT}, /* > */
- {0x38, KEY_SHIFT}, /* ? */
- {0x1f, KEY_SHIFT}, /* @ */
- {0x04, KEY_SHIFT}, /* A */
- {0x05, KEY_SHIFT}, /* B */
- {0x06, KEY_SHIFT}, /* C */
- {0x07, KEY_SHIFT}, /* D */
- {0x08, KEY_SHIFT}, /* E */
- {0x09, KEY_SHIFT}, /* F */
- {0x0a, KEY_SHIFT}, /* G */
- {0x0b, KEY_SHIFT}, /* H */
- {0x0c, KEY_SHIFT}, /* I */
- {0x0d, KEY_SHIFT}, /* J */
- {0x0e, KEY_SHIFT}, /* K */
- {0x0f, KEY_SHIFT}, /* L */
- {0x10, KEY_SHIFT}, /* M */
- {0x11, KEY_SHIFT}, /* N */
- {0x12, KEY_SHIFT}, /* O */
- {0x13, KEY_SHIFT}, /* P */
- {0x14, KEY_SHIFT}, /* Q */
- {0x15, KEY_SHIFT}, /* R */
- {0x16, KEY_SHIFT}, /* S */
- {0x17, KEY_SHIFT}, /* T */
- {0x18, KEY_SHIFT}, /* U */
- {0x19, KEY_SHIFT}, /* V */
- {0x1a, KEY_SHIFT}, /* W */
- {0x1b, KEY_SHIFT}, /* X */
- {0x1c, KEY_SHIFT}, /* Y */
- {0x1d, KEY_SHIFT}, /* Z */
- {0x2f, 0}, /* [ */
- {0x31, 0}, /* \ */
- {0x30, 0}, /* ] */
- {0x23, KEY_SHIFT}, /* ^ */
- {0x2d, KEY_SHIFT}, /* _ */
- {0x35, 0}, /* ` */
- {0x04, 0}, /* a */
- {0x05, 0}, /* b */
- {0x06, 0}, /* c */
- {0x07, 0}, /* d */
- {0x08, 0}, /* e */
- {0x09, 0}, /* f */
- {0x0a, 0}, /* g */
- {0x0b, 0}, /* h */
- {0x0c, 0}, /* i */
- {0x0d, 0}, /* j */
- {0x0e, 0}, /* k */
- {0x0f, 0}, /* l */
- {0x10, 0}, /* m */
- {0x11, 0}, /* n */
- {0x12, 0}, /* o */
- {0x13, 0}, /* p */
- {0x14, 0}, /* q */
- {0x15, 0}, /* r */
- {0x16, 0}, /* s */
- {0x17, 0}, /* t */
- {0x18, 0}, /* u */
- {0x19, 0}, /* v */
- {0x1a, 0}, /* w */
- {0x1b, 0}, /* x */
- {0x1c, 0}, /* y */
- {0x1d, 0}, /* z */
- {0x2f, KEY_SHIFT}, /* { */
- {0x31, KEY_SHIFT}, /* | */
- {0x30, KEY_SHIFT}, /* } */
- {0x35, KEY_SHIFT}, /* ~ */
- {0,0}, /* DEL */
-
- {0x3a, 0}, /* F1 */
- {0x3b, 0}, /* F2 */
- {0x3c, 0}, /* F3 */
- {0x3d, 0}, /* F4 */
- {0x3e, 0}, /* F5 */
- {0x3f, 0}, /* F6 */
- {0x40, 0}, /* F7 */
- {0x41, 0}, /* F8 */
- {0x42, 0}, /* F9 */
- {0x43, 0}, /* F10 */
- {0x44, 0}, /* F11 */
- {0x45, 0}, /* F12 */
-
- {0x46, 0}, /* PRINT_SCREEN */
- {0x47, 0}, /* SCROLL_LOCK */
- {0x39, 0}, /* CAPS_LOCK */
- {0x53, 0}, /* NUM_LOCK */
- {0x49, 0}, /* INSERT */
- {0x4a, 0}, /* HOME */
- {0x4b, 0}, /* PAGE_UP */
- {0x4e, 0}, /* PAGE_DOWN */
-};
-
-#else
-/* UK keyboard */
-#define KEYMAP_SIZE (148)
-const KEYMAP keymap[KEYMAP_SIZE] = {
- {0, 0}, /* NUL */
- {0, 0}, /* SOH */
- {0, 0}, /* STX */
- {0, 0}, /* ETX */
- {0, 0}, /* EOT */
- {0, 0}, /* ENQ */
- {0, 0}, /* ACK */
- {0, 0}, /* BEL */
- {0x2a, 0}, /* BS */ /* Keyboard Delete (Backspace) */
- {0x2b, 0}, /* TAB */ /* Keyboard Tab */
- {0x28, 0}, /* LF */ /* Keyboard Return (Enter) */
- {0, 0}, /* VT */
- {0, 0}, /* FF */
- {0, 0}, /* CR */
- {0, 0}, /* SO */
- {0, 0}, /* SI */
- {0, 0}, /* DEL */
- {0, 0}, /* DC1 */
- {0, 0}, /* DC2 */
- {0, 0}, /* DC3 */
- {0, 0}, /* DC4 */
- {0, 0}, /* NAK */
- {0, 0}, /* SYN */
- {0, 0}, /* ETB */
- {0, 0}, /* CAN */
- {0, 0}, /* EM */
- {0, 0}, /* SUB */
- {0, 0}, /* ESC */
- {0, 0}, /* FS */
- {0, 0}, /* GS */
- {0, 0}, /* RS */
- {0, 0}, /* US */
- {0x2c, 0}, /* */
- {0x1e, KEY_SHIFT}, /* ! */
- {0x1f, KEY_SHIFT}, /* " */
- {0x32, 0}, /* # */
- {0x21, KEY_SHIFT}, /* $ */
- {0x22, KEY_SHIFT}, /* % */
- {0x24, KEY_SHIFT}, /* & */
- {0x34, 0}, /* ' */
- {0x26, KEY_SHIFT}, /* ( */
- {0x27, KEY_SHIFT}, /* ) */
- {0x25, KEY_SHIFT}, /* * */
- {0x2e, KEY_SHIFT}, /* + */
- {0x36, 0}, /* , */
- {0x2d, 0}, /* - */
- {0x37, 0}, /* . */
- {0x38, 0}, /* / */
- {0x27, 0}, /* 0 */
- {0x1e, 0}, /* 1 */
- {0x1f, 0}, /* 2 */
- {0x20, 0}, /* 3 */
- {0x21, 0}, /* 4 */
- {0x22, 0}, /* 5 */
- {0x23, 0}, /* 6 */
- {0x24, 0}, /* 7 */
- {0x25, 0}, /* 8 */
- {0x26, 0}, /* 9 */
- {0x33, KEY_SHIFT}, /* : */
- {0x33, 0}, /* ; */
- {0x36, KEY_SHIFT}, /* < */
- {0x2e, 0}, /* = */
- {0x37, KEY_SHIFT}, /* > */
- {0x38, KEY_SHIFT}, /* ? */
- {0x34, KEY_SHIFT}, /* @ */
- {0x04, KEY_SHIFT}, /* A */
- {0x05, KEY_SHIFT}, /* B */
- {0x06, KEY_SHIFT}, /* C */
- {0x07, KEY_SHIFT}, /* D */
- {0x08, KEY_SHIFT}, /* E */
- {0x09, KEY_SHIFT}, /* F */
- {0x0a, KEY_SHIFT}, /* G */
- {0x0b, KEY_SHIFT}, /* H */
- {0x0c, KEY_SHIFT}, /* I */
- {0x0d, KEY_SHIFT}, /* J */
- {0x0e, KEY_SHIFT}, /* K */
- {0x0f, KEY_SHIFT}, /* L */
- {0x10, KEY_SHIFT}, /* M */
- {0x11, KEY_SHIFT}, /* N */
- {0x12, KEY_SHIFT}, /* O */
- {0x13, KEY_SHIFT}, /* P */
- {0x14, KEY_SHIFT}, /* Q */
- {0x15, KEY_SHIFT}, /* R */
- {0x16, KEY_SHIFT}, /* S */
- {0x17, KEY_SHIFT}, /* T */
- {0x18, KEY_SHIFT}, /* U */
- {0x19, KEY_SHIFT}, /* V */
- {0x1a, KEY_SHIFT}, /* W */
- {0x1b, KEY_SHIFT}, /* X */
- {0x1c, KEY_SHIFT}, /* Y */
- {0x1d, KEY_SHIFT}, /* Z */
- {0x2f, 0}, /* [ */
- {0x64, 0}, /* \ */
- {0x30, 0}, /* ] */
- {0x23, KEY_SHIFT}, /* ^ */
- {0x2d, KEY_SHIFT}, /* _ */
- {0x35, 0}, /* ` */
- {0x04, 0}, /* a */
- {0x05, 0}, /* b */
- {0x06, 0}, /* c */
- {0x07, 0}, /* d */
- {0x08, 0}, /* e */
- {0x09, 0}, /* f */
- {0x0a, 0}, /* g */
- {0x0b, 0}, /* h */
- {0x0c, 0}, /* i */
- {0x0d, 0}, /* j */
- {0x0e, 0}, /* k */
- {0x0f, 0}, /* l */
- {0x10, 0}, /* m */
- {0x11, 0}, /* n */
- {0x12, 0}, /* o */
- {0x13, 0}, /* p */
- {0x14, 0}, /* q */
- {0x15, 0}, /* r */
- {0x16, 0}, /* s */
- {0x17, 0}, /* t */
- {0x18, 0}, /* u */
- {0x19, 0}, /* v */
- {0x1a, 0}, /* w */
- {0x1b, 0}, /* x */
- {0x1c, 0}, /* y */
- {0x1d, 0}, /* z */
- {0x2f, KEY_SHIFT}, /* { */
- {0x64, KEY_SHIFT}, /* | */
- {0x30, KEY_SHIFT}, /* } */
- {0x32, KEY_SHIFT}, /* ~ */
- {0,0}, /* DEL */
-
- {0x3a, 0}, /* F1 */
- {0x3b, 0}, /* F2 */
- {0x3c, 0}, /* F3 */
- {0x3d, 0}, /* F4 */
- {0x3e, 0}, /* F5 */
- {0x3f, 0}, /* F6 */
- {0x40, 0}, /* F7 */
- {0x41, 0}, /* F8 */
- {0x42, 0}, /* F9 */
- {0x43, 0}, /* F10 */
- {0x44, 0}, /* F11 */
- {0x45, 0}, /* F12 */
-
- {0x46, 0}, /* PRINT_SCREEN */
- {0x47, 0}, /* SCROLL_LOCK */
- {0x39, 0}, /* CAPS_LOCK */
- {0x53, 0}, /* NUM_LOCK */
- {0x49, 0}, /* INSERT */
- {0x4a, 0}, /* HOME */
- {0x4b, 0}, /* PAGE_UP */
- {0x4e, 0}, /* PAGE_DOWN */
-};
-#endif
-
-uint8_t * USBKeyboard::reportDesc() {
- static uint8_t reportDescriptor[] = {
- USAGE_PAGE(1), 0x01, // Generic Desktop
- USAGE(1), 0x06, // Keyboard
- COLLECTION(1), 0x01, // Application
- REPORT_ID(1), REPORT_ID_KEYBOARD,
-
- USAGE_PAGE(1), 0x07, // Key Codes
- USAGE_MINIMUM(1), 0xE0,
- USAGE_MAXIMUM(1), 0xE7,
- LOGICAL_MINIMUM(1), 0x00,
- LOGICAL_MAXIMUM(1), 0x01,
- REPORT_SIZE(1), 0x01,
- REPORT_COUNT(1), 0x08,
- INPUT(1), 0x02, // Data, Variable, Absolute
- REPORT_COUNT(1), 0x01,
- REPORT_SIZE(1), 0x08,
- INPUT(1), 0x01, // Constant
-
-
- REPORT_COUNT(1), 0x05,
- REPORT_SIZE(1), 0x01,
- USAGE_PAGE(1), 0x08, // LEDs
- USAGE_MINIMUM(1), 0x01,
- USAGE_MAXIMUM(1), 0x05,
- OUTPUT(1), 0x02, // Data, Variable, Absolute
- REPORT_COUNT(1), 0x01,
- REPORT_SIZE(1), 0x03,
- OUTPUT(1), 0x01, // Constant
-
-
- REPORT_COUNT(1), 0x06,
- REPORT_SIZE(1), 0x08,
- LOGICAL_MINIMUM(1), 0x00,
- LOGICAL_MAXIMUM(1), 0x65,
- USAGE_PAGE(1), 0x07, // Key Codes
- USAGE_MINIMUM(1), 0x00,
- USAGE_MAXIMUM(1), 0x65,
- INPUT(1), 0x00, // Data, Array
- END_COLLECTION(0),
-
- // Media Control
- USAGE_PAGE(1), 0x0C,
- USAGE(1), 0x01,
- COLLECTION(1), 0x01,
- REPORT_ID(1), REPORT_ID_VOLUME,
- USAGE_PAGE(1), 0x0C,
- LOGICAL_MINIMUM(1), 0x00,
- LOGICAL_MAXIMUM(1), 0x01,
- REPORT_SIZE(1), 0x01,
- REPORT_COUNT(1), 0x07,
- USAGE(1), 0xB5, // Next Track
- USAGE(1), 0xB6, // Previous Track
- USAGE(1), 0xB7, // Stop
- USAGE(1), 0xCD, // Play / Pause
- USAGE(1), 0xE2, // Mute
- USAGE(1), 0xE9, // Volume Up
- USAGE(1), 0xEA, // Volume Down
- INPUT(1), 0x02, // Input (Data, Variable, Absolute)
- REPORT_COUNT(1), 0x01,
- INPUT(1), 0x01,
- END_COLLECTION(0),
- };
- reportLength = sizeof(reportDescriptor);
- return reportDescriptor;
-}
-
-
-bool USBKeyboard::EP1_OUT_callback() {
- uint16_t bytesRead = 0;
- uint8_t led[65];
- USBDevice::read(EPINT_OUT, led, &bytesRead, MAX_HID_REPORT_SIZE);
- if (leds != NULL && led[0] == REPORT_ID_KEYBOARD) {
- // We take led[1] because led[0] is the report_id
- // led1: NUM_LOCK
- // led2: CAPS_LOCK
- // led3: SCROLL_LOCK
- *leds = (led[1]) & 0x7;
- }
- // We activate the endpoint to be able to recceive data
- if (!readStart(EPINT_OUT, MAX_HID_REPORT_SIZE))
- return false;
- return true;
-}
-
-
-int USBKeyboard::_putc(int c) {
- return keyCode(c, keymap[c].modifier);
-}
-
-bool USBKeyboard::keyCode(uint8_t key, uint8_t modifier) {
- // Send a simulated keyboard keypress. Returns true if successful.
- HID_REPORT report;
-
- report.data[0] = REPORT_ID_KEYBOARD;
- report.data[1] = modifier;
- report.data[2] = 0;
- report.data[3] = keymap[key].usage;
- report.data[4] = 0;
- report.data[5] = 0;
- report.data[6] = 0;
- report.data[7] = 0;
- report.data[8] = 0;
-
- report.length = 9;
-
- if (!send(&report)) {
- return false;
- }
-
- report.data[1] = 0;
- report.data[3] = 0;
-
- if (!send(&report)) {
- return false;
- }
-
- return true;
-
-}
-
-
-bool USBKeyboard::mediaControl(MEDIA_KEY key) {
- HID_REPORT report;
-
- report.data[0] = REPORT_ID_VOLUME;
- report.data[1] = (1 << key) & 0x7f;
-
- report.length = 2;
-
- if (!send(&report)) {
- return false;
- }
-
- report.data[0] = REPORT_ID_VOLUME;
- report.data[1] = 0;
-
- report.length = 2;
-
- return send(&report);
-}
-
--- a/USBDevice/USBHID/USBKeyboard.h Mon Nov 14 10:00:07 2011 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,147 +0,0 @@
-/* USBKeyboard.h */
-/* USB device example: Standard keyboard */
-/* Copyright (c) 2011 ARM Limited. All rights reserved. */
-
-#ifndef USBKEYBOARD_H
-#define USBKEYBOARD_H
-
-#include "USBHID.h"
-#include "Stream.h"
-
-/* Modifiers */
-enum MODIFIER_KEY
-{
- KEY_CTRL = 1,
- KEY_SHIFT = 2,
- KEY_ALT = 4,
-};
-
-
-enum MEDIA_KEY
-{
- KEY_NEXT_TRACK, /*!< next Track Button */
- KEY_PREVIOUS_TRACK, /*!< Previous track Button */
- KEY_STOP, /*!< Stop Button */
- KEY_PLAY_PAUSE, /*!< Play/Pause Button */
- KEY_MUTE, /*!< Mute Button */
- KEY_VOLUME_UP, /*!< Volume Up Button */
- KEY_VOLUME_DOWN, /*!< Volume Down Button */
-};
-
-enum FUNCTION_KEY
-{
- KEY_F1 = 128, /* F1 key */
- KEY_F2, /* F2 key */
- KEY_F3, /* F3 key */
- KEY_F4, /* F4 key */
- KEY_F5, /* F5 key */
- KEY_F6, /* F6 key */
- KEY_F7, /* F7 key */
- KEY_F8, /* F8 key */
- KEY_F9, /* F9 key */
- KEY_F10, /* F10 key */
- KEY_F11, /* F11 key */
- KEY_F12, /* F12 key */
- KEY_PRINT_SCREEN, /* Print Screen key */
- KEY_SCROLL_LOCK, /* Scroll lock */
- KEY_CAPS_LOCK, /* caps lock */
- KEY_NUM_LOCK, /* num lock */
- KEY_INSERT, /* Insert key */
- KEY_HOME, /* Home key */
- KEY_PAGE_UP, /* Page Up key */
- KEY_PAGE_DOWN, /* Page Down key */
-};
-
-/**
- * USBKeyboard example
- * @code
- *
- * #include "mbed.h"
- * #include "USBKeyboard.h"
- *
- * USBKeyboard key;
- *
- * int main(void)
- * {
- * while (1)
- * {
- * key.printf("Hello World\r\n");
- * wait(1);
- * }
- * }
- *
- * @endcode
- */
-class USBKeyboard: public USBHID, public Stream
-{
- public:
-
- /**
- * Constructor
- *
- *
- * @param leds Leds bus: first: NUM_LOCK, second: CAPS_LOCK, third: SCROLL_LOCK
- * @param vendor_id Your vendor_id (default: 0x1234)
- * @param product_id Your product_id (default: 0x0001)
- * @param product_release Your preoduct_release (default: 0x0001)
- *
- */
- USBKeyboard(BusOut * leds = NULL, uint16_t vendor_id = 0x1235, uint16_t product_id = 0x0010, uint16_t product_release = 0x0001):
- USBHID(0, 0, vendor_id, product_id, product_release){
- this->leds = leds;
- };
-
- /**
- * To send a character defined by a modifier(CTRL, SHIFT, ALT) and the key
- *
- * @code
- * //To send CTRL + s (save)
- * keyboard.keyCode('s', KEY_CTRL);
- * @endcode
- *
- * @param modifier bit 0: KEY_CTRL, bit 1: KEY_SHIFT, bit 2: KEY_ALT (default: 0)
- * @param key character to send
- * @returns true if there is no error, false otherwise
- */
- bool keyCode(uint8_t key, uint8_t modifier = 0);
-
- /**
- * Send a character
- *
- * @param c character to be sent
- * @returns true if there is no error, false otherwise
- */
- virtual int _putc(int c);
-
- /**
- * Control media keys
- *
- * @param key media key pressed (KEY_NEXT_TRACK, KEY_PREVIOUS_TRACK, KEY_STOP, KEY_PLAY_PAUSE, KEY_MUTE, KEY_VOLUME_UP, KEY_VOLUME_DOWN)
- * @returns true if there is no error, false otherwise
- */
- bool mediaControl(MEDIA_KEY key);
-
- /*
- * To define the report descriptor. Warning: this method has to store the length of the report descriptor in reportLength.
- *
- * @returns pointer to the report descriptor
- */
- virtual uint8_t * reportDesc();
-
- /*
- * Called when a data is received on the OUT endpoint. Useful to switch on LED of LOCK keys
- *
- * @returns if handle by subclass, return true
- */
- virtual bool EP1_OUT_callback();
-
- private:
- //dummy otherwise it doesn,t compile (we must define all methods of an abstract class)
- virtual int _getc() { return -1;};
-
- // Switch on leds (CAPS LOCK,...)
- BusOut * leds;
-};
-
-#endif
-
--- a/USBDevice/USBHID/USBMouse.cpp Mon Nov 14 10:00:07 2011 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,176 +0,0 @@
-// USBMouse.c
-// USB device example: Relative mouse
-// Copyright (c) 2011 ARM Limited. All rights reserved.
-
-#include "stdint.h"
-#include "USBMouse.h"
-
-bool USBMouse::update(int16_t x, int16_t y, uint8_t button, int8_t z) {
- switch (mouse_type) {
- case REL_MOUSE:
- while (x > 127) {
- if (!mouseSend(127, 0, button, z)) return false;
- x = x - 127;
- }
- while (x < -128) {
- if (!mouseSend(-128, 0, button, z)) return false;
- x = x + 128;
- }
- while (y > 127) {
- if (!mouseSend(0, 127, button, z)) return false;
- y = y - 127;
- }
- while (y < -128) {
- if (!mouseSend(0, -128, button, z)) return false;
- y = y + 128;
- }
- return mouseSend(x, y, button, z);
- case ABS_MOUSE:
- HID_REPORT report;
-
- report.data[0] = x & 0xff;
- report.data[1] = (x >> 8) & 0xff;
- report.data[2] = y & 0xff;
- report.data[3] = (y >> 8) & 0xff;
- report.data[4] = -z;
- report.data[5] = button & 0x07;
-
- report.length = 6;
-
- return send(&report);
- default:
- return false;
- }
-}
-
-bool USBMouse::mouseSend(int8_t x, int8_t y, uint8_t buttons, int8_t z) {
- HID_REPORT report;
- report.data[0] = buttons & 0x07;
- report.data[1] = x;
- report.data[2] = y;
- report.data[3] = -z; // >0 to scroll down, <0 to scroll up
-
- report.length = 4;
-
- return send(&report);
-}
-
-bool USBMouse::move(int16_t x, int16_t y) {
- return update(x, y, button, 0);
-}
-
-bool USBMouse::scroll(int8_t z) {
- return update(0, 0, button, z);
-}
-
-
-bool USBMouse::doubleClick() {
- if (!click(MOUSE_LEFT))
- return false;
- wait(0.1);
- return click(MOUSE_LEFT);
-}
-
-bool USBMouse::click(uint8_t button) {
- if (!update(0, 0, button, 0))
- return false;
- wait(0.01);
- return update(0, 0, 0, 0);
-}
-
-bool USBMouse::press(uint8_t button_) {
- button = button_ & 0x07;
- return update(0, 0, button, 0);
-}
-
-bool USBMouse::release(uint8_t button_) {
- button = (button & (~button_)) & 0x07;
- return update(0, 0, button, 0);
-}
-
-
-uint8_t * USBMouse::reportDesc() {
-
- if (mouse_type == REL_MOUSE) {
- static uint8_t reportDescriptor[] = {
- USAGE_PAGE(1), 0x01, // Genric Desktop
- USAGE(1), 0x02, // Mouse
- COLLECTION(1), 0x01, // Application
- USAGE(1), 0x01, // Pointer
- COLLECTION(1), 0x00, // Physical
-
- REPORT_COUNT(1), 0x03,
- REPORT_SIZE(1), 0x01,
- USAGE_PAGE(1), 0x09, // Buttons
- USAGE_MINIMUM(1), 0x1,
- USAGE_MAXIMUM(1), 0x3,
- LOGICAL_MINIMUM(1), 0x00,
- LOGICAL_MAXIMUM(1), 0x01,
- INPUT(1), 0x02,
- REPORT_COUNT(1), 0x01,
- REPORT_SIZE(1), 0x05,
- INPUT(1), 0x01,
-
- REPORT_COUNT(1), 0x03,
- REPORT_SIZE(1), 0x08,
- USAGE_PAGE(1), 0x01,
- USAGE(1), 0x30, // X
- USAGE(1), 0x31, // Y
- USAGE(1), 0x38, // scroll
- LOGICAL_MINIMUM(1), 0x81,
- LOGICAL_MAXIMUM(1), 0x7f,
- INPUT(1), 0x06, // Relative data
-
- END_COLLECTION(0),
- END_COLLECTION(0),
- };
- reportLength = sizeof(reportDescriptor);
- return reportDescriptor;
- } else if (mouse_type == ABS_MOUSE) {
- static uint8_t reportDescriptor[] = {
-
- USAGE_PAGE(1), 0x01, // Generic Desktop
- USAGE(1), 0x02, // Mouse
- COLLECTION(1), 0x01, // Application
- USAGE(1), 0x01, // Pointer
- COLLECTION(1), 0x00, // Physical
-
- USAGE_PAGE(1), 0x01, // Generic Desktop
- USAGE(1), 0x30, // X
- USAGE(1), 0x31, // Y
- LOGICAL_MINIMUM(1), 0x00, // 0
- LOGICAL_MAXIMUM(2), 0xff, 0x7f, // 32767
- REPORT_SIZE(1), 0x10,
- REPORT_COUNT(1), 0x02,
- INPUT(1), 0x02, // Data, Variable, Absolute
-
- USAGE_PAGE(1), 0x01, // Generic Desktop
- USAGE(1), 0x38, // scroll
- LOGICAL_MINIMUM(1), 0x81, // -127
- LOGICAL_MAXIMUM(1), 0x7f, // 127
- REPORT_SIZE(1), 0x08,
- REPORT_COUNT(1), 0x01,
- INPUT(1), 0x06, // Data, Variable, Relative
-
- USAGE_PAGE(1), 0x09, // Buttons
- USAGE_MINIMUM(1), 0x01,
- USAGE_MAXIMUM(1), 0x03,
- LOGICAL_MINIMUM(1), 0x00, // 0
- LOGICAL_MAXIMUM(1), 0x01, // 1
- REPORT_COUNT(1), 0x03,
- REPORT_SIZE(1), 0x01,
- INPUT(1), 0x02, // Data, Variable, Absolute
- REPORT_COUNT(1), 0x01,
- REPORT_SIZE(1), 0x05,
- INPUT(1), 0x01, // Constant
-
- END_COLLECTION(0),
- END_COLLECTION(0)
- };
- reportLength = sizeof(reportDescriptor);
- return reportDescriptor;
- }
- return NULL;
-}
-
-
--- a/USBDevice/USBHID/USBMouse.h Mon Nov 14 10:00:07 2011 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,186 +0,0 @@
-/* USBMouse.h */
-/* USB device example: relative mouse */
-/* Copyright (c) 2011 ARM Limited. All rights reserved. */
-
-#ifndef USBMOUSE_H
-#define USBMOUSE_H
-
-#include "USBHID.h"
-
-#define REPORT_ID_MOUSE 2
-
-/* Common usage */
-
-enum MOUSE_BUTTON
-{
- MOUSE_LEFT = 1,
- MOUSE_RIGHT = 2,
- MOUSE_MIDDLE = 4,
-};
-
-/* X and Y limits */
-/* These values do not directly map to screen pixels */
-/* Zero may be interpreted as meaning 'no movement' */
-#define X_MIN_ABS (1) /*!< Minimum value on x-axis */
-#define Y_MIN_ABS (1) /*!< Minimum value on y-axis */
-#define X_MAX_ABS (0x7fff) /*!< Maximum value on x-axis */
-#define Y_MAX_ABS (0x7fff) /*!< Maximum value on y-axis */
-
-#define X_MIN_REL (-127) /*!< The maximum value that we can move to the left on the x-axis */
-#define Y_MIN_REL (-127) /*!< The maximum value that we can move up on the y-axis */
-#define X_MAX_REL (127) /*!< The maximum value that we can move to the right on the x-axis */
-#define Y_MAX_REL (127) /*!< The maximum value that we can move down on the y-axis */
-
-enum MOUSE_TYPE
-{
- ABS_MOUSE,
- REL_MOUSE,
-};
-
-/**
- *
- * USBMouse example
- * @code
- * #include "mbed.h"
- * #include "USBMouse.h"
- *
- * USBMouse mouse;
- *
- * int main(void)
- * {
- * while (1)
- * {
- * mouse.move(20, 0);
- * wait(0.5);
- * }
- * }
- *
- * @endcode
- *
- *
- * @code
- * #include "mbed.h"
- * #include "USBMouse.h"
- * #include <math.h>
- *
- * USBMouse mouse(ABS_MOUSE);
- *
- * int main(void)
- * {
- * uint16_t x_center = (X_MAX_ABS - X_MIN_ABS)/2;
- * uint16_t y_center = (Y_MAX_ABS - Y_MIN_ABS)/2;
- * uint16_t x_screen = 0;
- * uint16_t y_screen = 0;
- *
- * uint32_t x_origin = x_center;
- * uint32_t y_origin = y_center;
- * uint32_t radius = 5000;
- * uint32_t angle = 0;
- *
- * while (1)
- * {
- * x_screen = x_origin + cos((double)angle*3.14/180.0)*radius;
- * y_screen = y_origin + sin((double)angle*3.14/180.0)*radius;
- *
- * mouse.move(x_screen, y_screen);
- * angle += 3;
- * wait(0.01);
- * }
- * }
- *
- * @endcode
- */
-class USBMouse: public USBHID
-{
- public:
-
- /**
- * Constructor
- *
- * @param mouse_type Mouse type: ABS_MOUSE (absolute mouse) or REL_MOUSE (relative mouse) (default: REL_MOUSE)
- * @param vendor_id Your vendor_id (default: 0x1234)
- * @param product_id Your product_id (default: 0x0001)
- * @param product_release Your preoduct_release (default: 0x0001)
- *
- */
- USBMouse(MOUSE_TYPE mouse_type = REL_MOUSE, uint16_t vendor_id = 0x1234, uint16_t product_id = 0x0001, uint16_t product_release = 0x0001):
- USBHID(0, 0, vendor_id, product_id, product_release)
- {
- button = 0;
- this->mouse_type = mouse_type;
- };
-
- /**
- * Write a state of the mouse
- *
- * @param x x-axis position
- * @param y y-axis position
- * @param buttons buttons state (first bit represents MOUSE_LEFT, second bit MOUSE_RIGHT and third bit MOUSE_MIDDLE)
- * @param z wheel state (>0 to scroll down, <0 to scroll up)
- * @returns true if there is no error, false otherwise
- */
- bool update(int16_t x, int16_t y, uint8_t buttons, int8_t z);
-
-
- /**
- * Move the cursor to (x, y)
- *
- * @param x-axis position
- * @param y-axis position
- * @returns true if there is no error, false otherwise
- */
- bool move(int16_t x, int16_t y);
-
- /**
- * Press one or several buttons
- *
- * @param button button state (ex: press(MOUSE_LEFT))
- * @returns true if there is no error, false otherwise
- */
- bool press(uint8_t button);
-
- /**
- * Release one or several buttons
- *
- * @param button button state (ex: release(MOUSE_LEFT))
- * @returns true if there is no error, false otherwise
- */
- bool release(uint8_t button);
-
- /**
- * Double click (MOUSE_LEFT)
- *
- * @returns true if there is no error, false otherwise
- */
- bool doubleClick();
-
- /**
- * Click
- *
- * @param button state of the buttons ( ex: clic(MOUSE_LEFT))
- * @returns true if there is no error, false otherwise
- */
- bool click(uint8_t button);
-
- /**
- * Scrolling
- *
- * @param z value of the wheel (>0 to go down, <0 to go up)
- * @returns true if there is no error, false otherwise
- */
- bool scroll(int8_t z);
-
- /*
- * To define the report descriptor. Warning: this method has to store the length of the report descriptor in reportLength.
- *
- * @returns pointer to the report descriptor
- */
- virtual uint8_t * reportDesc();
-
- private:
- MOUSE_TYPE mouse_type;
- uint8_t button;
- bool mouseSend(int8_t x, int8_t y, uint8_t buttons, int8_t z);
-};
-
-#endif
--- a/USBDevice/USBHID/USBMouseKeyboard.cpp Mon Nov 14 10:00:07 2011 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,681 +0,0 @@
-// Keyboard_RelMouse.c
-// USB device example: Keyboard and a relative mouse
-// Copyright (c) 2011 ARM Limited. All rights reserved.
-
-#include "stdint.h"
-#include "USBMouseKeyboard.h"
-
-typedef struct {
- unsigned char usage;
- unsigned char modifier;
-} KEYMAP;
-
-#ifdef US_KEYBOARD
-/* US keyboard (as HID standard) */
-#define KEYMAP_SIZE (148)
-const KEYMAP keymap[KEYMAP_SIZE] = {
- {0, 0}, /* NUL */
- {0, 0}, /* SOH */
- {0, 0}, /* STX */
- {0, 0}, /* ETX */
- {0, 0}, /* EOT */
- {0, 0}, /* ENQ */
- {0, 0}, /* ACK */
- {0, 0}, /* BEL */
- {0x2a, 0}, /* BS */ /* Keyboard Delete (Backspace) */
- {0x2b, 0}, /* TAB */ /* Keyboard Tab */
- {0x28, 0}, /* LF */ /* Keyboard Return (Enter) */
- {0, 0}, /* VT */
- {0, 0}, /* FF */
- {0, 0}, /* CR */
- {0, 0}, /* SO */
- {0, 0}, /* SI */
- {0, 0}, /* DEL */
- {0, 0}, /* DC1 */
- {0, 0}, /* DC2 */
- {0, 0}, /* DC3 */
- {0, 0}, /* DC4 */
- {0, 0}, /* NAK */
- {0, 0}, /* SYN */
- {0, 0}, /* ETB */
- {0, 0}, /* CAN */
- {0, 0}, /* EM */
- {0, 0}, /* SUB */
- {0, 0}, /* ESC */
- {0, 0}, /* FS */
- {0, 0}, /* GS */
- {0, 0}, /* RS */
- {0, 0}, /* US */
- {0x2c, 0}, /* */
- {0x1e, KEY_SHIFT}, /* ! */
- {0x34, KEY_SHIFT}, /* " */
- {0x20, KEY_SHIFT}, /* # */
- {0x21, KEY_SHIFT}, /* $ */
- {0x22, KEY_SHIFT}, /* % */
- {0x24, KEY_SHIFT}, /* & */
- {0x34, 0}, /* ' */
- {0x26, KEY_SHIFT}, /* ( */
- {0x27, KEY_SHIFT}, /* ) */
- {0x25, KEY_SHIFT}, /* * */
- {0x2e, KEY_SHIFT}, /* + */
- {0x36, 0}, /* , */
- {0x2d, 0}, /* - */
- {0x37, 0}, /* . */
- {0x38, 0}, /* / */
- {0x27, 0}, /* 0 */
- {0x1e, 0}, /* 1 */
- {0x1f, 0}, /* 2 */
- {0x20, 0}, /* 3 */
- {0x21, 0}, /* 4 */
- {0x22, 0}, /* 5 */
- {0x23, 0}, /* 6 */
- {0x24, 0}, /* 7 */
- {0x25, 0}, /* 8 */
- {0x26, 0}, /* 9 */
- {0x33, KEY_SHIFT}, /* : */
- {0x33, 0}, /* ; */
- {0x36, KEY_SHIFT}, /* < */
- {0x2e, 0}, /* = */
- {0x37, KEY_SHIFT}, /* > */
- {0x38, KEY_SHIFT}, /* ? */
- {0x1f, KEY_SHIFT}, /* @ */
- {0x04, KEY_SHIFT}, /* A */
- {0x05, KEY_SHIFT}, /* B */
- {0x06, KEY_SHIFT}, /* C */
- {0x07, KEY_SHIFT}, /* D */
- {0x08, KEY_SHIFT}, /* E */
- {0x09, KEY_SHIFT}, /* F */
- {0x0a, KEY_SHIFT}, /* G */
- {0x0b, KEY_SHIFT}, /* H */
- {0x0c, KEY_SHIFT}, /* I */
- {0x0d, KEY_SHIFT}, /* J */
- {0x0e, KEY_SHIFT}, /* K */
- {0x0f, KEY_SHIFT}, /* L */
- {0x10, KEY_SHIFT}, /* M */
- {0x11, KEY_SHIFT}, /* N */
- {0x12, KEY_SHIFT}, /* O */
- {0x13, KEY_SHIFT}, /* P */
- {0x14, KEY_SHIFT}, /* Q */
- {0x15, KEY_SHIFT}, /* R */
- {0x16, KEY_SHIFT}, /* S */
- {0x17, KEY_SHIFT}, /* T */
- {0x18, KEY_SHIFT}, /* U */
- {0x19, KEY_SHIFT}, /* V */
- {0x1a, KEY_SHIFT}, /* W */
- {0x1b, KEY_SHIFT}, /* X */
- {0x1c, KEY_SHIFT}, /* Y */
- {0x1d, KEY_SHIFT}, /* Z */
- {0x2f, 0}, /* [ */
- {0x31, 0}, /* \ */
- {0x30, 0}, /* ] */
- {0x23, KEY_SHIFT}, /* ^ */
- {0x2d, KEY_SHIFT}, /* _ */
- {0x35, 0}, /* ` */
- {0x04, 0}, /* a */
- {0x05, 0}, /* b */
- {0x06, 0}, /* c */
- {0x07, 0}, /* d */
- {0x08, 0}, /* e */
- {0x09, 0}, /* f */
- {0x0a, 0}, /* g */
- {0x0b, 0}, /* h */
- {0x0c, 0}, /* i */
- {0x0d, 0}, /* j */
- {0x0e, 0}, /* k */
- {0x0f, 0}, /* l */
- {0x10, 0}, /* m */
- {0x11, 0}, /* n */
- {0x12, 0}, /* o */
- {0x13, 0}, /* p */
- {0x14, 0}, /* q */
- {0x15, 0}, /* r */
- {0x16, 0}, /* s */
- {0x17, 0}, /* t */
- {0x18, 0}, /* u */
- {0x19, 0}, /* v */
- {0x1a, 0}, /* w */
- {0x1b, 0}, /* x */
- {0x1c, 0}, /* y */
- {0x1d, 0}, /* z */
- {0x2f, KEY_SHIFT}, /* { */
- {0x31, KEY_SHIFT}, /* | */
- {0x30, KEY_SHIFT}, /* } */
- {0x35, KEY_SHIFT}, /* ~ */
- {0,0}, /* DEL */
-
- {0x3a, 0}, /* F1 */
- {0x3b, 0}, /* F2 */
- {0x3c, 0}, /* F3 */
- {0x3d, 0}, /* F4 */
- {0x3e, 0}, /* F5 */
- {0x3f, 0}, /* F6 */
- {0x40, 0}, /* F7 */
- {0x41, 0}, /* F8 */
- {0x42, 0}, /* F9 */
- {0x43, 0}, /* F10 */
- {0x44, 0}, /* F11 */
- {0x45, 0}, /* F12 */
-
- {0x46, 0}, /* PRINT_SCREEN */
- {0x47, 0}, /* SCROLL_LOCK */
- {0x39, 0}, /* CAPS_LOCK */
- {0x53, 0}, /* NUM_LOCK */
- {0x49, 0}, /* INSERT */
- {0x4a, 0}, /* HOME */
- {0x4b, 0}, /* PAGE_UP */
- {0x4e, 0}, /* PAGE_DOWN */
-};
-
-#else
-/* UK keyboard */
-#define KEYMAP_SIZE (148)
-const KEYMAP keymap[KEYMAP_SIZE] = {
- {0, 0}, /* NUL */
- {0, 0}, /* SOH */
- {0, 0}, /* STX */
- {0, 0}, /* ETX */
- {0, 0}, /* EOT */
- {0, 0}, /* ENQ */
- {0, 0}, /* ACK */
- {0, 0}, /* BEL */
- {0x2a, 0}, /* BS */ /* Keyboard Delete (Backspace) */
- {0x2b, 0}, /* TAB */ /* Keyboard Tab */
- {0x28, 0}, /* LF */ /* Keyboard Return (Enter) */
- {0, 0}, /* VT */
- {0, 0}, /* FF */
- {0, 0}, /* CR */
- {0, 0}, /* SO */
- {0, 0}, /* SI */
- {0, 0}, /* DEL */
- {0, 0}, /* DC1 */
- {0, 0}, /* DC2 */
- {0, 0}, /* DC3 */
- {0, 0}, /* DC4 */
- {0, 0}, /* NAK */
- {0, 0}, /* SYN */
- {0, 0}, /* ETB */
- {0, 0}, /* CAN */
- {0, 0}, /* EM */
- {0, 0}, /* SUB */
- {0, 0}, /* ESC */
- {0, 0}, /* FS */
- {0, 0}, /* GS */
- {0, 0}, /* RS */
- {0, 0}, /* US */
- {0x2c, 0}, /* */
- {0x1e, KEY_SHIFT}, /* ! */
- {0x1f, KEY_SHIFT}, /* " */
- {0x32, 0}, /* # */
- {0x21, KEY_SHIFT}, /* $ */
- {0x22, KEY_SHIFT}, /* % */
- {0x24, KEY_SHIFT}, /* & */
- {0x34, 0}, /* ' */
- {0x26, KEY_SHIFT}, /* ( */
- {0x27, KEY_SHIFT}, /* ) */
- {0x25, KEY_SHIFT}, /* * */
- {0x2e, KEY_SHIFT}, /* + */
- {0x36, 0}, /* , */
- {0x2d, 0}, /* - */
- {0x37, 0}, /* . */
- {0x38, 0}, /* / */
- {0x27, 0}, /* 0 */
- {0x1e, 0}, /* 1 */
- {0x1f, 0}, /* 2 */
- {0x20, 0}, /* 3 */
- {0x21, 0}, /* 4 */
- {0x22, 0}, /* 5 */
- {0x23, 0}, /* 6 */
- {0x24, 0}, /* 7 */
- {0x25, 0}, /* 8 */
- {0x26, 0}, /* 9 */
- {0x33, KEY_SHIFT}, /* : */
- {0x33, 0}, /* ; */
- {0x36, KEY_SHIFT}, /* < */
- {0x2e, 0}, /* = */
- {0x37, KEY_SHIFT}, /* > */
- {0x38, KEY_SHIFT}, /* ? */
- {0x34, KEY_SHIFT}, /* @ */
- {0x04, KEY_SHIFT}, /* A */
- {0x05, KEY_SHIFT}, /* B */
- {0x06, KEY_SHIFT}, /* C */
- {0x07, KEY_SHIFT}, /* D */
- {0x08, KEY_SHIFT}, /* E */
- {0x09, KEY_SHIFT}, /* F */
- {0x0a, KEY_SHIFT}, /* G */
- {0x0b, KEY_SHIFT}, /* H */
- {0x0c, KEY_SHIFT}, /* I */
- {0x0d, KEY_SHIFT}, /* J */
- {0x0e, KEY_SHIFT}, /* K */
- {0x0f, KEY_SHIFT}, /* L */
- {0x10, KEY_SHIFT}, /* M */
- {0x11, KEY_SHIFT}, /* N */
- {0x12, KEY_SHIFT}, /* O */
- {0x13, KEY_SHIFT}, /* P */
- {0x14, KEY_SHIFT}, /* Q */
- {0x15, KEY_SHIFT}, /* R */
- {0x16, KEY_SHIFT}, /* S */
- {0x17, KEY_SHIFT}, /* T */
- {0x18, KEY_SHIFT}, /* U */
- {0x19, KEY_SHIFT}, /* V */
- {0x1a, KEY_SHIFT}, /* W */
- {0x1b, KEY_SHIFT}, /* X */
- {0x1c, KEY_SHIFT}, /* Y */
- {0x1d, KEY_SHIFT}, /* Z */
- {0x2f, 0}, /* [ */
- {0x64, 0}, /* \ */
- {0x30, 0}, /* ] */
- {0x23, KEY_SHIFT}, /* ^ */
- {0x2d, KEY_SHIFT}, /* _ */
- {0x35, 0}, /* ` */
- {0x04, 0}, /* a */
- {0x05, 0}, /* b */
- {0x06, 0}, /* c */
- {0x07, 0}, /* d */
- {0x08, 0}, /* e */
- {0x09, 0}, /* f */
- {0x0a, 0}, /* g */
- {0x0b, 0}, /* h */
- {0x0c, 0}, /* i */
- {0x0d, 0}, /* j */
- {0x0e, 0}, /* k */
- {0x0f, 0}, /* l */
- {0x10, 0}, /* m */
- {0x11, 0}, /* n */
- {0x12, 0}, /* o */
- {0x13, 0}, /* p */
- {0x14, 0}, /* q */
- {0x15, 0}, /* r */
- {0x16, 0}, /* s */
- {0x17, 0}, /* t */
- {0x18, 0}, /* u */
- {0x19, 0}, /* v */
- {0x1a, 0}, /* w */
- {0x1b, 0}, /* x */
- {0x1c, 0}, /* y */
- {0x1d, 0}, /* z */
- {0x2f, KEY_SHIFT}, /* { */
- {0x64, KEY_SHIFT}, /* | */
- {0x30, KEY_SHIFT}, /* } */
- {0x32, KEY_SHIFT}, /* ~ */
- {0,0}, /* DEL */
-
- {0x3a, 0}, /* F1 */
- {0x3b, 0}, /* F2 */
- {0x3c, 0}, /* F3 */
- {0x3d, 0}, /* F4 */
- {0x3e, 0}, /* F5 */
- {0x3f, 0}, /* F6 */
- {0x40, 0}, /* F7 */
- {0x41, 0}, /* F8 */
- {0x42, 0}, /* F9 */
- {0x43, 0}, /* F10 */
- {0x44, 0}, /* F11 */
- {0x45, 0}, /* F12 */
-
- {0x46, 0}, /* PRINT_SCREEN */
- {0x47, 0}, /* SCROLL_LOCK */
- {0x39, 0}, /* CAPS_LOCK */
- {0x53, 0}, /* NUM_LOCK */
- {0x49, 0}, /* INSERT */
- {0x4a, 0}, /* HOME */
- {0x4b, 0}, /* PAGE_UP */
- {0x4e, 0}, /* PAGE_DOWN */
-};
-#endif
-
-
-uint8_t * USBMouseKeyboard::reportDesc() {
- if (mouse_type == REL_MOUSE) {
- static uint8_t reportDescriptor[] = {
- // Keyboard
- USAGE_PAGE(1), 0x01,
- USAGE(1), 0x06,
- COLLECTION(1), 0x01,
- REPORT_ID(1), REPORT_ID_KEYBOARD,
- USAGE_PAGE(1), 0x07,
- USAGE_MINIMUM(1), 0xE0,
- USAGE_MAXIMUM(1), 0xE7,
- LOGICAL_MINIMUM(1), 0x00,
- LOGICAL_MAXIMUM(1), 0x01,
- REPORT_SIZE(1), 0x01,
- REPORT_COUNT(1), 0x08,
- INPUT(1), 0x02,
- REPORT_COUNT(1), 0x01,
- REPORT_SIZE(1), 0x08,
- INPUT(1), 0x01,
- REPORT_COUNT(1), 0x05,
- REPORT_SIZE(1), 0x01,
- USAGE_PAGE(1), 0x08,
- USAGE_MINIMUM(1), 0x01,
- USAGE_MAXIMUM(1), 0x05,
- OUTPUT(1), 0x02,
- REPORT_COUNT(1), 0x01,
- REPORT_SIZE(1), 0x03,
- OUTPUT(1), 0x01,
- REPORT_COUNT(1), 0x06,
- REPORT_SIZE(1), 0x08,
- LOGICAL_MINIMUM(1), 0x00,
- LOGICAL_MAXIMUM(2), 0xff, 0x00,
- USAGE_PAGE(1), 0x07,
- USAGE_MINIMUM(1), 0x00,
- USAGE_MAXIMUM(2), 0xff, 0x00,
- INPUT(1), 0x00,
- END_COLLECTION(0),
-
- // Mouse
- USAGE_PAGE(1), 0x01, // Generic Desktop
- USAGE(1), 0x02, // Mouse
- COLLECTION(1), 0x01, // Application
- USAGE(1), 0x01, // Pointer
- COLLECTION(1), 0x00, // Physical
- REPORT_ID(1), REPORT_ID_MOUSE,
- REPORT_COUNT(1), 0x03,
- REPORT_SIZE(1), 0x01,
- USAGE_PAGE(1), 0x09, // Buttons
- USAGE_MINIMUM(1), 0x1,
- USAGE_MAXIMUM(1), 0x3,
- LOGICAL_MINIMUM(1), 0x00,
- LOGICAL_MAXIMUM(1), 0x01,
- INPUT(1), 0x02,
- REPORT_COUNT(1), 0x01,
- REPORT_SIZE(1), 0x05,
- INPUT(1), 0x01,
- REPORT_COUNT(1), 0x03,
- REPORT_SIZE(1), 0x08,
- USAGE_PAGE(1), 0x01,
- USAGE(1), 0x30, // X
- USAGE(1), 0x31, // Y
- USAGE(1), 0x38, // scroll
- LOGICAL_MINIMUM(1), 0x81,
- LOGICAL_MAXIMUM(1), 0x7f,
- INPUT(1), 0x06,
- END_COLLECTION(0),
- END_COLLECTION(0),
-
-
- // Media Control
- USAGE_PAGE(1), 0x0C,
- USAGE(1), 0x01,
- COLLECTION(1), 0x01,
- REPORT_ID(1), REPORT_ID_VOLUME,
- USAGE_PAGE(1), 0x0C,
- LOGICAL_MINIMUM(1), 0x00,
- LOGICAL_MAXIMUM(1), 0x01,
- REPORT_SIZE(1), 0x01,
- REPORT_COUNT(1), 0x07,
- USAGE(1), 0xB5, // Next Track
- USAGE(1), 0xB6, // Previous Track
- USAGE(1), 0xB7, // Stop
- USAGE(1), 0xCD, // Play / Pause
- USAGE(1), 0xE2, // Mute
- USAGE(1), 0xE9, // Volume Up
- USAGE(1), 0xEA, // Volume Down
- INPUT(1), 0x02, // Input (Data, Variable, Absolute)
- REPORT_COUNT(1), 0x01,
- INPUT(1), 0x01,
- END_COLLECTION(0),
- };
- reportLength = sizeof(reportDescriptor);
- return reportDescriptor;
- } else if (mouse_type == ABS_MOUSE) {
- static uint8_t reportDescriptor[] = {
-
- // Keyboard
- USAGE_PAGE(1), 0x01,
- USAGE(1), 0x06,
- COLLECTION(1), 0x01,
- REPORT_ID(1), REPORT_ID_KEYBOARD,
- USAGE_PAGE(1), 0x07,
- USAGE_MINIMUM(1), 0xE0,
- USAGE_MAXIMUM(1), 0xE7,
- LOGICAL_MINIMUM(1), 0x00,
- LOGICAL_MAXIMUM(1), 0x01,
- REPORT_SIZE(1), 0x01,
- REPORT_COUNT(1), 0x08,
- INPUT(1), 0x02,
- REPORT_COUNT(1), 0x01,
- REPORT_SIZE(1), 0x08,
- INPUT(1), 0x01,
- REPORT_COUNT(1), 0x05,
- REPORT_SIZE(1), 0x01,
- USAGE_PAGE(1), 0x08,
- USAGE_MINIMUM(1), 0x01,
- USAGE_MAXIMUM(1), 0x05,
- OUTPUT(1), 0x02,
- REPORT_COUNT(1), 0x01,
- REPORT_SIZE(1), 0x03,
- OUTPUT(1), 0x01,
- REPORT_COUNT(1), 0x06,
- REPORT_SIZE(1), 0x08,
- LOGICAL_MINIMUM(1), 0x00,
- LOGICAL_MAXIMUM(2), 0xff, 0x00,
- USAGE_PAGE(1), 0x07,
- USAGE_MINIMUM(1), 0x00,
- USAGE_MAXIMUM(2), 0xff, 0x00,
- INPUT(1), 0x00,
- END_COLLECTION(0),
-
- // Mouse
- USAGE_PAGE(1), 0x01, // Generic Desktop
- USAGE(1), 0x02, // Mouse
- COLLECTION(1), 0x01, // Application
- USAGE(1), 0x01, // Pointer
- COLLECTION(1), 0x00, // Physical
- REPORT_ID(1), REPORT_ID_MOUSE,
-
- USAGE_PAGE(1), 0x01, // Generic Desktop
- USAGE(1), 0x30, // X
- USAGE(1), 0x31, // Y
- LOGICAL_MINIMUM(1), 0x00, // 0
- LOGICAL_MAXIMUM(2), 0xff, 0x7f, // 32767
- REPORT_SIZE(1), 0x10,
- REPORT_COUNT(1), 0x02,
- INPUT(1), 0x02, // Data, Variable, Absolute
-
- USAGE_PAGE(1), 0x01, // Generic Desktop
- USAGE(1), 0x38, // scroll
- LOGICAL_MINIMUM(1), 0x81, // -127
- LOGICAL_MAXIMUM(1), 0x7f, // 127
- REPORT_SIZE(1), 0x08,
- REPORT_COUNT(1), 0x01,
- INPUT(1), 0x06, // Data, Variable, Relative
-
- USAGE_PAGE(1), 0x09, // Buttons
- USAGE_MINIMUM(1), 0x01,
- USAGE_MAXIMUM(1), 0x03,
- LOGICAL_MINIMUM(1), 0x00, // 0
- LOGICAL_MAXIMUM(1), 0x01, // 1
- REPORT_COUNT(1), 0x03,
- REPORT_SIZE(1), 0x01,
- INPUT(1), 0x02, // Data, Variable, Absolute
- REPORT_COUNT(1), 0x01,
- REPORT_SIZE(1), 0x05,
- INPUT(1), 0x01, // Constant
-
- END_COLLECTION(0),
- END_COLLECTION(0),
-
- // Media Control
- USAGE_PAGE(1), 0x0C,
- USAGE(1), 0x01,
- COLLECTION(1), 0x01,
- REPORT_ID(1), REPORT_ID_VOLUME,
- USAGE_PAGE(1), 0x0C,
- LOGICAL_MINIMUM(1), 0x00,
- LOGICAL_MAXIMUM(1), 0x01,
- REPORT_SIZE(1), 0x01,
- REPORT_COUNT(1), 0x07,
- USAGE(1), 0xB5, // Next Track
- USAGE(1), 0xB6, // Previous Track
- USAGE(1), 0xB7, // Stop
- USAGE(1), 0xCD, // Play / Pause
- USAGE(1), 0xE2, // Mute
- USAGE(1), 0xE9, // Volume Up
- USAGE(1), 0xEA, // Volume Down
- INPUT(1), 0x02, // Input (Data, Variable, Absolute)
- REPORT_COUNT(1), 0x01,
- INPUT(1), 0x01,
- END_COLLECTION(0),
- };
- reportLength = sizeof(reportDescriptor);
- return reportDescriptor;
- }
-
- return NULL;
-}
-
-bool USBMouseKeyboard::EP1_OUT_callback() {
- uint16_t bytesRead = 0;
- uint8_t led[65];
- USBDevice::read(EPINT_OUT, led, &bytesRead, MAX_HID_REPORT_SIZE);
- if (leds != NULL && led[0] == REPORT_ID_KEYBOARD) {
- // We take led[1] because led[0] is the report_id
- // led1: NUM_LOCK
- // led2: CAPS_LOCK
- // led3: SCROLL_LOCK
- *leds = (led[1]) & 0x7;
- }
- // We activate the endpoint to be able to recceive data
- if (!readStart(EPINT_OUT, MAX_HID_REPORT_SIZE))
- return false;
- return true;
-}
-
-bool USBMouseKeyboard::update(int16_t x, int16_t y, uint8_t button, int8_t z) {
- switch (mouse_type) {
- case REL_MOUSE:
- while (x > 127) {
- if (!mouseSend(127, 0, button, z)) return false;
- x = x - 127;
- }
- while (x < -128) {
- if (!mouseSend(-128, 0, button, z)) return false;
- x = x + 128;
- }
- while (y > 127) {
- if (!mouseSend(0, 127, button, z)) return false;
- y = y - 127;
- }
- while (y < -128) {
- if (!mouseSend(0, -128, button, z)) return false;
- y = y + 128;
- }
- return mouseSend(x, y, button, z);
- case ABS_MOUSE:
- HID_REPORT report;
-
- report.data[0] = REPORT_ID_MOUSE;
- report.data[1] = x & 0xff;
- report.data[2] = (x >> 8) & 0xff;
- report.data[3] = y & 0xff;
- report.data[4] = (y >> 8) & 0xff;
- report.data[5] = -z;
- report.data[6] = button & 0x07;
-
- report.length = 7;
-
- return send(&report);
- default:
- return false;
- }
-}
-
-bool USBMouseKeyboard::mouseSend(int8_t x, int8_t y, uint8_t buttons, int8_t z) {
- HID_REPORT report;
- report.data[0] = REPORT_ID_MOUSE;
- report.data[1] = buttons & 0x07;
- report.data[2] = x;
- report.data[3] = y;
- report.data[4] = -z; // >0 to scroll down, <0 to scroll up
-
- report.length = 5;
-
- return send(&report);
-}
-
-bool USBMouseKeyboard::move(int16_t x, int16_t y) {
- return update(x, y, button, 0);
-}
-
-bool USBMouseKeyboard::scroll(int8_t z) {
- return update(0, 0, button, z);
-}
-
-bool USBMouseKeyboard::doubleClick() {
- if (!click(MOUSE_LEFT))
- return false;
- wait(0.1);
- return click(MOUSE_LEFT);
-}
-
-bool USBMouseKeyboard::click(uint8_t button) {
- if (!update(0, 0, button, 0))
- return false;
- wait(0.01);
- return update(0, 0, 0, 0);
-}
-
-bool USBMouseKeyboard::press(uint8_t button_) {
- button = button_ & 0x07;
- return update(0, 0, button, 0);
-}
-
-bool USBMouseKeyboard::release(uint8_t button_) {
- button = (button & (~button_)) & 0x07;
- return update(0, 0, button, 0);
-}
-
-int USBMouseKeyboard::_putc(int c) {
- return keyCode(c, keymap[c].modifier);
-}
-
-bool USBMouseKeyboard::keyCode(uint8_t key, uint8_t modifier) {
- // Send a simulated keyboard keypress. Returns true if successful.
-
- HID_REPORT report;
-
- report.data[0] = REPORT_ID_KEYBOARD;
- report.data[1] = modifier;
- report.data[2] = 0;
- report.data[3] = keymap[key].usage;
- report.data[4] = 0;
- report.data[5] = 0;
- report.data[6] = 0;
- report.data[7] = 0;
- report.data[8] = 0;
-
- report.length = 9;
-
- if (!send(&report)) {
- return false;
- }
-
- report.data[1] = 0;
- report.data[3] = 0;
-
- if (!send(&report)) {
- return false;
- }
-
- return true;
-
-}
-
-
-bool USBMouseKeyboard::mediaControl(MEDIA_KEY key) {
- HID_REPORT report;
-
- report.data[0] = REPORT_ID_VOLUME;
- report.data[1] = (1 << key) & 0x7f;
-
- report.length = 2;
-
- send(&report);
-
- report.data[0] = REPORT_ID_VOLUME;
- report.data[1] = 0;
-
- report.length = 2;
-
- return send(&report);
-}
--- a/USBDevice/USBHID/USBMouseKeyboard.h Mon Nov 14 10:00:07 2011 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,196 +0,0 @@
-/* USBMouseKeyboard.h */
-/* USB device example: Keyboard with a relative mouse */
-/* Copyright (c) 2011 ARM Limited. All rights reserved. */
-
-#ifndef USBMOUSEKEYBOARD_H
-#define USBMOUSEKEYBOARD_H
-
-#define REPORT_ID_KEYBOARD 1
-#define REPORT_ID_MOUSE 2
-#define REPORT_ID_VOLUME 3
-
-#include "USBMouse.h"
-#include "USBKeyboard.h"
-#include "Stream.h"
-#include "USBHID.h"
-
-/**
- * USBMouseKeyboard example
- * @code
- *
- * #include "mbed.h"
- * #include "USBMouseKeyboard.h"
- *
- * USBMouseKeyboard key_mouse;
- *
- * int main(void)
- * {
- * while(1)
- * {
- * key_mouse.move(20, 0);
- * key_mouse.printf("Hello From MBED\r\n");
- * wait(1);
- * }
- * }
- * @endcode
- *
- *
- * @code
- *
- * #include "mbed.h"
- * #include "USBMouseKeyboard.h"
- *
- * USBMouseKeyboard key_mouse(ABS_MOUSE);
- *
- * int main(void)
- * {
- * while(1)
- * {
- * key_mouse.move(X_MAX_ABS/2, Y_MAX_ABS/2);
- * key_mouse.printf("Hello from MBED\r\n");
- * wait(1);
- * }
- * }
- * @endcode
- */
-class USBMouseKeyboard: public USBHID, public Stream
-{
- public:
-
- /**
- * Constructor
- *
- * @param mouse_type Mouse type: ABS_MOUSE (absolute mouse) or REL_MOUSE (relative mouse) (default: REL_MOUSE)
- * @param leds Leds bus: first: NUM_LOCK, second: CAPS_LOCK, third: SCROLL_LOCK
- * @param vendor_id Your vendor_id (default: 0x1234)
- * @param product_id Your product_id (default: 0x0001)
- * @param product_release Your preoduct_release (default: 0x0001)
- *
- */
- USBMouseKeyboard(MOUSE_TYPE mouse_type = REL_MOUSE, BusOut * leds = NULL, uint16_t vendor_id = 0x0021, uint16_t product_id = 0x0011, uint16_t product_release = 0x0001):
- USBHID(0, 0, vendor_id, product_id, product_release)
- {
- this->leds = leds;
- button = 0;
- this->mouse_type = mouse_type;
- };
-
- /**
- * Write a state of the mouse
- *
- * @param x x-axis position
- * @param y y-axis position
- * @param buttons buttons state (first bit represents MOUSE_LEFT, second bit MOUSE_RIGHT and third bit MOUSE_MIDDLE)
- * @param z wheel state (>0 to scroll down, <0 to scroll up)
- * @returns true if there is no error, false otherwise
- */
- bool update(int16_t x, int16_t y, uint8_t buttons, int8_t z);
-
-
- /**
- * Move the cursor to (x, y)
- *
- * @param x x-axis position
- * @param y y-axis position
- * @returns true if there is no error, false otherwise
- */
- bool move(int16_t x, int16_t y);
-
- /**
- * Press one or several buttons
- *
- * @param button button state (ex: press(MOUSE_LEFT))
- * @returns true if there is no error, false otherwise
- */
- bool press(uint8_t button);
-
- /**
- * Release one or several buttons
- *
- * @param button button state (ex: release(MOUSE_LEFT))
- * @returns true if there is no error, false otherwise
- */
- bool release(uint8_t button);
-
- /**
- * Double click (MOUSE_LEFT)
- *
- * @returns true if there is no error, false otherwise
- */
- bool doubleClick();
-
- /**
- * Click
- *
- * @param button state of the buttons ( ex: clic(MOUSE_LEFT))
- * @returns true if there is no error, false otherwise
- */
- bool click(uint8_t button);
-
- /**
- * Scrolling
- *
- * @param z value of the wheel (>0 to go down, <0 to go up)
- * @returns true if there is no error, false otherwise
- */
- bool scroll(int8_t z);
-
- /**
- * To send a character defined by a modifier(CTRL, SHIFT, ALT) and the key
- *
- * @code
- * //To send CTRL + s (save)
- * keyboard.keyCode('s', KEY_CTRL);
- * @endcode
- *
- * @param modifier bit 0: KEY_CTRL, bit 1: KEY_SHIFT, bit 2: KEY_ALT (default: 0)
- * @param key character to send
- * @returns true if there is no error, false otherwise
- */
- bool keyCode(uint8_t key, uint8_t modifier = 0);
-
- /**
- * Send a character
- *
- * @param c character to be sent
- * @returns true if there is no error, false otherwise
- */
- virtual int _putc(int c);
-
- /**
- * Control media keys
- *
- * @param key media key pressed (KEY_NEXT_TRACK, KEY_PREVIOUS_TRACK, KEY_STOP, KEY_PLAY_PAUSE, KEY_MUTE, KEY_VOLUME_UP, KEY_VOLUME_DOWN)
- * @returns true if there is no error, false otherwise
- */
- bool mediaControl(MEDIA_KEY key);
-
- /*
- * To define the report descriptor. Warning: this method has to store the length of the report descriptor in reportLength.
- *
- * @returns pointer to the report descriptor
- */
- virtual uint8_t * reportDesc();
-
- /*
- * Called when a data is received on the OUT endpoint. Useful to switch on LED of LOCK keys
- *
- * @returns if handle by subclass, return true
- */
- virtual bool EP1_OUT_callback();
-
-
- private:
- bool mouseWrite(int8_t x, int8_t y, uint8_t buttons, int8_t z);
- MOUSE_TYPE mouse_type;
- uint8_t button;
- bool mouseSend(int8_t x, int8_t y, uint8_t buttons, int8_t z);
-
- // Switch on leds (CAPS LOCK,...)
- BusOut * leds;
-
- //dummy otherwise it doesn,t compile (we must define all methods of an abstract class)
- virtual int _getc() { return -1;}
-};
-
-#endif
--- a/USBDevice/USBMIDI/MIDIMessage.h Mon Nov 14 10:00:07 2011 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,254 +0,0 @@
-/* @license The MIT License
- * Copyright (c) 2011 mux, simon
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#ifndef MIDIMESSAGE_H
-#define MIDIMESSAGE_H
-
-#include "mbed.h"
-
-// MIDI Message Format
-//
-// [ msg(4) | channel(4) ] [ 0 | n(7) ] [ 0 | m(7) ]
-//
-// MIDI Data Messages (Channel Specific)
-//
-// Message msg n m
-// ---------------------------------------------
-// Note Off 0x8 Key Velocity
-// Note On 0x9 Key Velocity
-// Polyphonic Aftertouch 0xA Key Pressure
-// Control Change 0xB Controller Value
-// Program Change 0xC Program -
-// Channel Aftertouch 0xD Pressure -
-// Pitch Wheel 0xE LSB MSB
-
-#define CABLE_NUM (0<<4)
-
-/** A MIDI message container */
-class MIDIMessage {
-public:
- MIDIMessage() {}
-
- MIDIMessage(uint8_t *buf) {
- *((uint32_t *)data) = *((uint32_t *)buf);
- }
-
- // create messages
-
- /** Create a NoteOff message
- * @param key Key ID
- * @param velocity Key velocity (0-127, default = 127)
- * @param channel Key channel (0-15, default 0)
- * @returns A MIDIMessage
- */
- static MIDIMessage NoteOff(int key, int velocity = 127, int channel = 0) {
- MIDIMessage msg;
- msg.data[0] = CABLE_NUM | 0x08;
- msg.data[1] = 0x80 | (channel & 0x0F);
- msg.data[2] = key & 0x7F;
- msg.data[3] = velocity & 0x7F;
- return msg;
- }
-
- /** Create a NoteOn message
- * @param key Key ID
- * @param velocity Key velocity (0-127, default = 127)
- * @param channel Key channel (0-15, default 0)
- * @returns A MIDIMessage
- */
- static MIDIMessage NoteOn(int key, int velocity = 127, int channel = 0) {
- MIDIMessage msg;
- msg.data[0] = CABLE_NUM | 0x09;
- msg.data[1] = 0x90 | (channel & 0x0F);
- msg.data[2] = key & 0x7F;
- msg.data[3] = velocity & 0x7F;
- return msg;
- }
-
- /** Create a PolyPhonic Aftertouch message
- * @param key Key ID
- * @param pressure Aftertouch pressure (0-127)
- * @param channel Key channel (0-15, default 0)
- * @returns A MIDIMessage
- */
- static MIDIMessage PolyphonicAftertouch(int key, int pressure, int channel = 0) {
- MIDIMessage msg;
- msg.data[0] = CABLE_NUM | 0x0A;
- msg.data[1] = 0xA0 | (channel & 0x0F);
- msg.data[2] = key & 0x7F;
- msg.data[3] = pressure & 0x7F;
- return msg;
- }
-
- /** Create a Control Change message
- * @param control Controller ID
- * @param value Controller value (0-127)
- * @param channel Controller channel (0-15, default 0)
- * @returns A MIDIMessage
- */
- static MIDIMessage ControlChange(int control, int value, int channel = 0) {
- MIDIMessage msg;
- msg.data[0] = CABLE_NUM | 0x0B;
- msg.data[1] = 0xB0 | (channel & 0x0F);
- msg.data[2] = control & 0x7F;
- msg.data[3] = value & 0x7F;
- return msg;
- }
-
- /** Create a Program Change message
- * @param program Program ID
- * @param channel Channel (0-15, default 0)
- * @returns A MIDIMessage
- */
- static MIDIMessage ProgramChange(int program, int channel = 0) {
- MIDIMessage msg;
- msg.data[0] = CABLE_NUM | 0x0C;
- msg.data[1] = 0xC0 | (channel & 0x0F);
- msg.data[2] = program & 0x7F;
- msg.data[3] = 0x00;
- return msg;
- }
-
- /** Create a Channel Aftertouch message
- * @param pressure Pressure
- * @param channel Key channel (0-15, default 0)
- * @returns A MIDIMessage
- */
- static MIDIMessage ChannelAftertouch(int pressure, int channel = 0) {
- MIDIMessage msg;
- msg.data[0] = CABLE_NUM | 0x0D;
- msg.data[1] = 0xD0 | (channel & 0x0F);
- msg.data[2] = pressure & 0x7F;
- msg.data[3] = 0x00;
- return msg;
- }
-
- /** Create a Pitch Wheel message
- * @param pitch Pitch (-8192 - 8191, default = 0)
- * @param channel Channel (0-15, default 0)
- * @returns A MIDIMessage
- */
- static MIDIMessage PitchWheel(int pitch = 0, int channel = 0) {
- MIDIMessage msg;
- int p = pitch + 8192; // 0 - 16383, 8192 is center
- msg.data[0] = CABLE_NUM | 0x0E;
- msg.data[1] = 0xE0 | (channel & 0x0F);
- msg.data[2] = p & 0x7F;
- msg.data[3] = (p >> 7) & 0x7F;
- return msg;
- }
-
- /** Create an All Notes Off message
- * @param channel Channel (0-15, default 0)
- * @returns A MIDIMessage
- */
- static MIDIMessage AllNotesOff(int channel = 0) {
- return ControlChange(123, 0, channel);
- }
-
- // decode messages
-
- /** MIDI Message Types */
- enum MIDIMessageType {
- ErrorType,
- NoteOffType,
- NoteOnType,
- PolyphonicAftertouchType,
- ControlChangeType,
- ProgramChangeType,
- ChannelAftertouchType,
- PitchWheelType,
- AllNotesOffType
- };
-
- /** Read the message type
- * @returns MIDIMessageType
- */
- MIDIMessageType type() {
- switch((data[1] >> 4) & 0xF) {
- case 0x8: return NoteOffType;
- case 0x9: return NoteOnType;
- case 0xA: return PolyphonicAftertouchType;
- case 0xB:
- if(controller() < 120) { // standard controllers
- return ControlChangeType;
- } else if(controller() == 123) {
- return AllNotesOffType;
- } else {
- return ErrorType; // unsupported atm
- }
- case 0xC: return ProgramChangeType;
- case 0xD: return ChannelAftertouchType;
- case 0xE: return PitchWheelType;
- default: return ErrorType;
- }
- }
-
- /** Read the channel number */
- int channel() {
- return (data[1] & 0x0F);
- }
-
- /** Read the key ID */
- int key() {
- return (data[2] & 0x7F);
- }
-
- /** Read the velocity */
- int velocity() {
- return (data[3] & 0x7F);
- }
-
- /** Read the controller value */
- int value() {
- return (data[3] & 0x7F);
- }
-
- /** Read the aftertouch pressure */
- int pressure() {
- if(type() == PolyphonicAftertouchType) {
- return (data[3] & 0x7F);
- } else {
- return (data[2] & 0x7F);
- }
- }
-
- /** Read the controller number */
- int controller() {
- return (data[2] & 0x7F);
- }
-
- /** Read the program number */
- int program() {
- return (data[2] & 0x7F);
- }
-
- /** Read the pitch value */
- int pitch() {
- int p = ((data[3] & 0x7F) << 7) | (data[2] & 0x7F);
- return p - 8192; // 0 - 16383, 8192 is center
- }
-
- uint8_t data[4];
-};
-
-#endif
--- a/USBDevice/USBMIDI/USBMIDI.cpp Mon Nov 14 10:00:07 2011 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,107 +0,0 @@
-// USB_MIDI.cpp
-// MIDI edvice example
-// Copyright (c) 2011 ARM Limited. All rights reserved.
-
-#include "stdint.h"
-#include "USBMIDI.h"
-#include "USBBusInterface.h"
-
-
-USBMIDI::USBMIDI(uint16_t vendor_id, uint16_t product_id, uint16_t product_release): USBDevice(vendor_id, product_id, product_release) {
- midi_evt = NULL;
-}
-
-void USBMIDI::write(MIDIMessage m) {
- USBDevice::write(EPBULK_IN, m.data, 4, MAX_PACKET_SIZE_EPBULK);
-}
-
-
-void USBMIDI::attach(void (*fptr)(MIDIMessage)) {
- midi_evt = fptr;
-}
-
-
-bool USBMIDI::EP2_OUT_callback() {
- uint8_t buf[64];
- uint16_t len;
- read(EPBULK_OUT, buf, &len, 64);
-
- if (midi_evt != NULL) {
- for (int i=0; i<len; i+=4) {
- midi_evt(MIDIMessage(buf+i));
- }
- }
-
- // We reactivate the endpoint to receive next characters
- readStart(EPBULK_OUT, MAX_PACKET_SIZE_EPBULK);
- return true;
-}
-
-
-
-// Called in ISR context
-// Set configuration. Return false if the
-// configuration is not supported.
-bool USBMIDI::USBCallback_setConfiguration(uint8_t configuration) {
- if (configuration != DEFAULT_CONFIGURATION) {
- return false;
- }
-
- // Configure endpoints > 0
- addEndpoint(EPBULK_IN, MAX_PACKET_SIZE_EPBULK);
- addEndpoint(EPBULK_OUT, MAX_PACKET_SIZE_EPBULK);
-
- // We activate the endpoint to be able to receive data
- readStart(EPBULK_OUT, MAX_PACKET_SIZE_EPBULK);
- return true;
-}
-
-
-uint8_t * USBMIDI::stringIinterfaceDesc() {
- static uint8_t stringIinterfaceDescriptor[] = {
- 0x0c, //bLength
- STRING_DESCRIPTOR, //bDescriptorType 0x03
- 'A',0,'u',0,'d',0,'i',0,'o',0 //bString iInterface - Audio
- };
- return stringIinterfaceDescriptor;
-}
-
-uint8_t * USBMIDI::stringIproductDesc() {
- static uint8_t stringIproductDescriptor[] = {
- 0x16, //bLength
- STRING_DESCRIPTOR, //bDescriptorType 0x03
- 'M',0,'b',0,'e',0,'d',0,' ',0,'A',0,'u',0,'d',0,'i',0,'o',0 //bString iProduct - Mbed Audio
- };
- return stringIproductDescriptor;
-}
-
-
-uint8_t * USBMIDI::configurationDesc() {
- static uint8_t configDescriptor[] = {
- // configuration descriptor
- 0x09, 0x02, 0x65, 0x00, 0x02, 0x01, 0x00, 0xc0, 0x50,
-
- // The Audio Interface Collection
- 0x09, 0x04, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, // Standard AC Interface Descriptor
- 0x09, 0x24, 0x01, 0x00, 0x01, 0x09, 0x00, 0x01, 0x01, // Class-specific AC Interface Descriptor
- 0x09, 0x04, 0x01, 0x00, 0x02, 0x01, 0x03, 0x00, 0x00, // MIDIStreaming Interface Descriptors
- 0x07, 0x24, 0x01, 0x00, 0x01, 0x41, 0x00, // Class-Specific MS Interface Header Descriptor
-
- // MIDI IN JACKS
- 0x06, 0x24, 0x02, 0x01, 0x01, 0x00,
- 0x06, 0x24, 0x02, 0x02, 0x02, 0x00,
-
- // MIDI OUT JACKS
- 0x09, 0x24, 0x03, 0x01, 0x03, 0x01, 0x02, 0x01, 0x00,
- 0x09, 0x24, 0x03, 0x02, 0x06, 0x01, 0x01, 0x01, 0x00,
-
- // OUT endpoint descriptor
- 0x09, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00,
- 0x05, 0x25, 0x01, 0x01, 0x01,
-
- // IN endpoint descriptor
- 0x09, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00,
- 0x05, 0x25, 0x01, 0x01, 0x03,
- };
- return configDescriptor;
-}
--- a/USBDevice/USBMIDI/USBMIDI.h Mon Nov 14 10:00:07 2011 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,96 +0,0 @@
-/* USB_MIDI.h */
-/* MIDI device example */
-/* Copyright (c) 2011 ARM Limited. All rights reserved. */
-
-#ifndef USBMIDI_H
-#define USBMIDI_H
-
-/* These headers are included for child class. */
-#include "USBEndpoints.h"
-#include "USBDescriptor.h"
-#include "USBDevice_Types.h"
-
-#include "USBDevice.h"
-#include "MIDIMessage.h"
-
-#define DEFAULT_CONFIGURATION (1)
-
-/**
-* USBMIDI example
-*
-* @code
-* #include "mbed.h"
-* #include "USBMIDI.h"
-*
-* USBMIDI midi;
-*
-* int main() {
-* while (1) {
-* for(int i=48; i<83; i++) { // send some messages!
-* midi.write(MIDIMessage::NoteOn(i));
-* wait(0.25);
-* midi.write(MIDIMessage::NoteOff(i));
-* wait(0.5);
-* }
-* }
-* }
-* @endcode
-*/
-class USBMIDI: public USBDevice {
-public:
-
- /**
- * Constructor
- *
- * @param vendor_id Your vendor_id
- * @param product_id Your product_id
- * @param product_release Your preoduct_release
- */
- USBMIDI(uint16_t vendor_id = 0x0700, uint16_t product_id = 0x0101, uint16_t product_release = 0x0001);
-
- /**
- * Send a MIDIMessage
- *
- * @param m The MIDIMessage to send
- */
- void write(MIDIMessage m);
-
- /**
- * Attach a callback for when a MIDIEvent is received
- *
- * @param fptr function pointer
- */
- void attach(void (*fptr)(MIDIMessage));
-
-
-protected:
- virtual bool EP2_OUT_callback();
- virtual bool USBCallback_setConfiguration(uint8_t configuration);
- /*
- * Get string product descriptor
- *
- * @returns pointer to the string product descriptor
- */
- virtual uint8_t * stringIproductDesc();
-
- /*
- * Get string interface descriptor
- *
- * @returns pointer to the string interface descriptor
- */
- virtual uint8_t * stringIinterfaceDesc();
-
- /*
- * Get configuration descriptor
- *
- * @returns pointer to the configuration descriptor
- */
- virtual uint8_t * configurationDesc();
-
-private:
- void (*midi_evt)(MIDIMessage);
-
-};
-
-#endif
-
--- a/USBDevice/USBMSD/USBMSD.cpp Mon Nov 14 10:00:07 2011 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,617 +0,0 @@
-// USBMSD.cpp
-// USB mass storage device example
-// Copyright (c) 2011 ARM Limited. All rights reserved.
-
-#include "stdint.h"
-#include "USBMSD.h"
-#include "USBBusInterface.h"
-
-#define CBW_Signature 0x43425355
-#define CSW_Signature 0x53425355
-
-// SCSI Commands
-#define TEST_UNIT_READY 0x00
-#define REQUEST_SENSE 0x03
-#define FORMAT_UNIT 0x04
-#define INQUIRY 0x12
-#define MODE_SELECT6 0x15
-#define MODE_SENSE6 0x1A
-#define START_STOP_UNIT 0x1B
-#define MEDIA_REMOVAL 0x1E
-#define READ_FORMAT_CAPACITIES 0x23
-#define READ_CAPACITY 0x25
-#define READ10 0x28
-#define WRITE10 0x2A
-#define VERIFY10 0x2F
-#define READ12 0xA8
-#define WRITE12 0xAA
-#define MODE_SELECT10 0x55
-#define MODE_SENSE10 0x5A
-
-// MSC class specific requests
-#define MSC_REQUEST_RESET 0xFF
-#define MSC_REQUEST_GET_MAX_LUN 0xFE
-
-#define DEFAULT_CONFIGURATION (1)
-
-// Max In/Out Packet Size on the bulk endpoint */
-#define MAX_PACKET MAX_PACKET_SIZE_EPBULK
-
-// CSW Status
-enum Status {
- CSW_PASSED,
- CSW_FAILED,
- CSW_ERROR,
-};
-
-
-USBMSD::USBMSD(uint16_t vendor_id, uint16_t product_id, uint16_t product_release): USBDevice(vendor_id, product_id, product_release) {
-}
-
-
-DigitalOut l2(LED2);
-// Called in ISR context to process a class specific request
-bool USBMSD::USBCallback_request(void) {
-
- bool success = false;
- CONTROL_TRANSFER * transfer = getTransferPtr();
-
- if (transfer->setup.bmRequestType.Type == CLASS_TYPE) {
- switch (transfer->setup.bRequest) {
- case MSC_REQUEST_RESET:
- reset();
- success = true;
- break;
- case MSC_REQUEST_GET_MAX_LUN:
- transfer->remaining = 1;
- transfer->ptr = getMaxLUN();
- transfer->direction = DEVICE_TO_HOST;
- success = true;
- break;
- default:
- break;
- }
- }
-
- return success;
-}
-
-
-bool USBMSD::connect()
-{
-
- //disk initialization
- diskInit();
-
- // get block size
- BlockSize = blockSize();
- if(BlockSize != 0) {
- page = (uint8_t *)malloc(BlockSize * sizeof(uint8_t));
- if(page == NULL)
- return false;
- }
-
- //get memory size
- MemorySize = memorySize();
- if(!MemorySize) {
- return false;
- }
- BlockCount = MemorySize/BlockSize;
-
- //connect the device
- USBDevice::connect();
- return true;
-}
-
-
-void USBMSD::reset()
-{
- stage = READ_CBW;
-}
-
-uint8_t * USBMSD::getMaxLUN()
-{
- static uint8_t LUN[] = {0};
- return LUN;
-}
-
-// Called in ISR context called when a data is received
-bool USBMSD::EP2_OUT_callback() {
- uint16_t size = 0;
- uint8_t buf[MAX_PACKET_SIZE_EPBULK];
- read(EPBULK_OUT, buf, &size, MAX_PACKET_SIZE_EPBULK);
- switch (stage) {
- // the device has to decode the CBW received
- case READ_CBW:
- CBWDecode(buf, size);
- break;
-
- // the device has to receive data from the host
- case PROCESS_CBW:
- switch (cbw.CB[0]) {
- case WRITE10:
- case WRITE12:
- memoryWrite(buf, size);
- break;
- case VERIFY10:
- memoryVerify(buf, size);
- break;
- }
- break;
-
- // an error has occured: stall endpoint and send CSW
- default:
- stallEndpoint(EPBULK_OUT);
- csw.Status = CSW_ERROR;
- sendCSW();
- break;
- }
-
- //reactivate readings on the OUT bulk endpoint
- readStart(EPBULK_OUT, MAX_PACKET_SIZE_EPBULK);
- return true;
-}
-
-// Called in ISR context when a data has been transferred
-bool USBMSD::EP2_IN_callback() {
- switch (stage) {
-
- // the device has to send data to the host
- case PROCESS_CBW:
- switch (cbw.CB[0]) {
- case READ10:
- case READ12:
- memoryRead();
- break;
- }
- break;
-
- //the device has to send a CSW
- case SEND_CSW:
- sendCSW();
- break;
-
- // an error has occured
- case ERROR:
- stallEndpoint(EPBULK_IN);
- sendCSW();
- break;
-
- // the host has received the CSW -> we wait a CBW
- case WAIT_CSW:
- stage = READ_CBW;
- break;
- }
- return true;
-}
-
-
-void USBMSD::memoryWrite (uint8_t * buf, uint16_t size) {
-
- if ((addr + size) > MemorySize) {
- size = MemorySize - addr;
- stage = ERROR;
- stallEndpoint(EPBULK_OUT);
- }
-
- // we fill an array in RAM of 1 block before writing it in memory
- for (int i = 0; i < size; i++)
- page[addr%BlockSize + i] = buf[i];
-
- // if the array is filled, write it in memory
- if (!((addr + size)%BlockSize))
- blockWrite(page, addr/BlockSize);
-
- addr += size;
- length -= size;
- csw.DataResidue -= size;
-
- if ((!length) || (stage != PROCESS_CBW)) {
- csw.Status = (stage == ERROR) ? CSW_FAILED : CSW_PASSED;
- sendCSW();
- }
-}
-
-void USBMSD::memoryVerify (uint8_t * buf, uint16_t size) {
- uint32_t n;
-
- if ((addr + size) > MemorySize) {
- size = MemorySize - addr;
- stage = ERROR;
- stallEndpoint(EPBULK_OUT);
- }
-
- // beginning of a new block -> load a whole block in RAM
- if (!(addr%BlockSize))
- blockRead(page, addr/BlockSize);
-
- // info are in RAM -> no need to re-read memory
- for (n = 0; n < size; n++) {
- if (page[addr%BlockSize + n] != buf[n]) {
- memOK = false;
- break;
- }
- }
-
- addr += size;
- length -= size;
- csw.DataResidue -= size;
-
- if ( !length || (stage != PROCESS_CBW)) {
- csw.Status = (memOK && (stage == PROCESS_CBW)) ? CSW_PASSED : CSW_FAILED;
- sendCSW();
- }
-}
-
-
-bool USBMSD::inquiryRequest (void) {
- uint8_t inquiry[] = { 0x00, 0x80, 0x00, 0x01,
- 36 - 4, 0x80, 0x00, 0x00,
- 'M', 'B', 'E', 'D', '.', 'O', 'R', 'G',
- 'M', 'B', 'E', 'D', ' ', 'U', 'S', 'B', ' ', 'D', 'I', 'S', 'K', ' ', ' ', ' ',
- '1', '.', '0', ' ',
- };
- if (!write(inquiry, sizeof(inquiry))) {
- return false;
- }
- return true;
-}
-
-
-bool USBMSD::readFormatCapacity() {
- uint8_t capacity[] = { 0x00, 0x00, 0x00, 0x08,
- (BlockCount >> 24) & 0xff,
- (BlockCount >> 16) & 0xff,
- (BlockCount >> 8) & 0xff,
- (BlockCount >> 0) & 0xff,
-
- 0x02,
- (BlockSize >> 16) & 0xff,
- (BlockSize >> 8) & 0xff,
- (BlockSize >> 0) & 0xff,
- };
- if (!write(capacity, sizeof(capacity))) {
- return false;
- }
- return true;
-}
-
-
-bool USBMSD::readCapacity (void) {
- uint8_t capacity[] = {
- ((BlockCount - 1) >> 24) & 0xff,
- ((BlockCount - 1) >> 16) & 0xff,
- ((BlockCount - 1) >> 8) & 0xff,
- ((BlockCount - 1) >> 0) & 0xff,
-
- (BlockSize >> 24) & 0xff,
- (BlockSize >> 16) & 0xff,
- (BlockSize >> 8) & 0xff,
- (BlockSize >> 0) & 0xff,
- };
- if (!write(capacity, sizeof(capacity))) {
- return false;
- }
- return true;
-}
-
-bool USBMSD::write (uint8_t * buf, uint16_t size) {
-
- if (size >= cbw.DataLength) {
- size = cbw.DataLength;
- }
- stage = SEND_CSW;
-
- if (!writeNB(EPBULK_IN, buf, size, MAX_PACKET_SIZE_EPBULK)) {
- return false;
- }
-
- csw.DataResidue -= size;
- csw.Status = CSW_PASSED;
- return true;
-}
-
-
-bool USBMSD::modeSense6 (void) {
- uint8_t sense6[] = { 0x03, 0x00, 0x00, 0x00 };
- if (!write(sense6, sizeof(sense6))) {
- return false;
- }
- return true;
-}
-
-void USBMSD::sendCSW() {
- csw.Signature = CSW_Signature;
- writeNB(EPBULK_IN, (uint8_t *)&csw, sizeof(CSW), MAX_PACKET_SIZE_EPBULK);
- stage = WAIT_CSW;
-}
-
-bool USBMSD::requestSense (void) {
- uint8_t request_sense[] = {
- 0x70, // Response Code
- 0x00,
- 0x05, // Sense Key: illegal request
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x0A, // Additional Length
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x30, // ASC
- 0x01, // ASCQ
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- };
-
- if (!write(request_sense, sizeof(request_sense))) {
- return false;
- }
-
- return true;
-}
-
-void USBMSD::fail() {
- csw.Status = CSW_FAILED;
- sendCSW();
-}
-
-DigitalOut l1(LED1);
-void USBMSD::CBWDecode(uint8_t * buf, uint16_t size) {
- if (size == sizeof(cbw)) {
- memcpy((uint8_t *)&cbw, buf, size);
- if (cbw.Signature == CBW_Signature) {
- csw.Tag = cbw.Tag;
- csw.DataResidue = cbw.DataLength;
- if ((cbw.CBLength < 1) || (cbw.CBLength > 16) ) {
- fail();
- } else {
- switch (cbw.CB[0]) {
- case TEST_UNIT_READY:
- testUnitReady();
- break;
- case REQUEST_SENSE:
- requestSense();
- break;
- case INQUIRY:
- inquiryRequest();
- break;
- case MODE_SENSE6:
- modeSense6();
- break;
- case READ_FORMAT_CAPACITIES:
- readFormatCapacity();
- break;
- case READ_CAPACITY:
- readCapacity();
- break;
- case READ10:
- case READ12:
- if (infoTransfer()) {
- if ((cbw.Flags & 0x80)) {
- stage = PROCESS_CBW;
- memoryRead();
- } else {
- stallEndpoint(EPBULK_OUT);
- csw.Status = CSW_ERROR;
- sendCSW();
- }
- }
- break;
- case WRITE10:
- case WRITE12:
- if (infoTransfer()) {
- if (!(cbw.Flags & 0x80)) {
- stage = PROCESS_CBW;
- } else {
- stallEndpoint(EPBULK_IN);
- csw.Status = CSW_ERROR;
- sendCSW();
- }
- }
- break;
- case VERIFY10:
- if (!(cbw.CB[1] & 0x02)) {
- csw.Status = CSW_PASSED;
- sendCSW();
- break;
- }
- if (infoTransfer()) {
- if (!(cbw.Flags & 0x80)) {
- stage = PROCESS_CBW;
- memOK = true;
- } else {
- stallEndpoint(EPBULK_IN);
- csw.Status = CSW_ERROR;
- sendCSW();
- }
- }
- break;
- default:
- fail();
- break;
- }
- }
- }
- }
-}
-
-void USBMSD::testUnitReady (void) {
-
- if (cbw.DataLength != 0) {
- if ((cbw.Flags & 0x80) != 0) {
- stallEndpoint(EPBULK_IN);
- } else {
- stallEndpoint(EPBULK_OUT);
- }
- }
-
- csw.Status = CSW_PASSED;
- sendCSW();
-}
-
-
-void USBMSD::memoryRead (void) {
- uint32_t n;
-
- n = (length > MAX_PACKET) ? MAX_PACKET : length;
-
- if ((addr + n) > MemorySize) {
- n = MemorySize - addr;
- stage = ERROR;
- }
-
- // we read an entire block
- if (!(addr%BlockSize))
- blockRead(page, addr/BlockSize);
-
- // write data which are in RAM
- writeNB(EPBULK_IN, &page[addr%BlockSize], n, MAX_PACKET_SIZE_EPBULK);
-
- addr += n;
- length -= n;
-
- csw.DataResidue -= n;
-
- if ( !length || (stage != PROCESS_CBW)) {
- csw.Status = (stage == PROCESS_CBW) ? CSW_PASSED : CSW_FAILED;
- sendCSW();
- }
-}
-
-
-bool USBMSD::infoTransfer (void) {
- uint32_t n;
-
- // Logical Block Address of First Block
- n = (cbw.CB[2] << 24) | (cbw.CB[3] << 16) | (cbw.CB[4] << 8) | (cbw.CB[5] << 0);
-
- addr = n * BlockSize;
-
- // Number of Blocks to transfer
- switch (cbw.CB[0]) {
- case READ10:
- case WRITE10:
- case VERIFY10:
- n = (cbw.CB[7] << 8) | (cbw.CB[8] << 0);
- break;
-
- case READ12:
- case WRITE12:
- n = (cbw.CB[6] << 24) | (cbw.CB[7] << 16) | (cbw.CB[8] << 8) | (cbw.CB[9] << 0);
- break;
- }
-
- length = n * BlockSize;
-
- if (!cbw.DataLength) { // host requests no data
- csw.Status = CSW_FAILED;
- sendCSW();
- return false;
- }
-
- if (cbw.DataLength != length) {
- if ((cbw.Flags & 0x80) != 0) {
- stallEndpoint(EPBULK_IN);
- } else {
- stallEndpoint(EPBULK_OUT);
- }
-
- csw.Status = CSW_FAILED;
- sendCSW();
- return false;
- }
-
- return true;
-}
-
-
-
-
-
-// Called in ISR context
-// Set configuration. Return false if the
-// configuration is not supported.
-bool USBMSD::USBCallback_setConfiguration(uint8_t configuration) {
- if (configuration != DEFAULT_CONFIGURATION) {
- return false;
- }
-
- // Configure endpoints > 0
- addEndpoint(EPBULK_IN, MAX_PACKET_SIZE_EPBULK);
- addEndpoint(EPBULK_OUT, MAX_PACKET_SIZE_EPBULK);
-
- //activate readings
- readStart(EPBULK_OUT, MAX_PACKET_SIZE_EPBULK);
- return true;
-}
-
-
-uint8_t * USBMSD::stringIinterfaceDesc() {
- static uint8_t stringIinterfaceDescriptor[] = {
- 0x08, //bLength
- STRING_DESCRIPTOR, //bDescriptorType 0x03
- 'M',0,'S',0,'D',0 //bString iInterface - MSD
- };
- return stringIinterfaceDescriptor;
-}
-
-uint8_t * USBMSD::stringIproductDesc() {
- static uint8_t stringIproductDescriptor[] = {
- 0x12, //bLength
- STRING_DESCRIPTOR, //bDescriptorType 0x03
- 'M',0,'b',0,'e',0,'d',0,' ',0,'M',0,'S',0,'D',0 //bString iProduct - Mbed Audio
- };
- return stringIproductDescriptor;
-}
-
-
-uint8_t * USBMSD::configurationDesc() {
- static uint8_t configDescriptor[] = {
-
- // Configuration 1
- 9, // bLength
- 2, // bDescriptorType
- LSB(9 + 9 + 7 + 7), // wTotalLength
- MSB(9 + 9 + 7 + 7),
- 0x01, // bNumInterfaces
- 0x01, // bConfigurationValue: 0x01 is used to select this configuration
- 0x00, // iConfiguration: no string to describe this configuration
- 0xC0, // bmAttributes
- 100, // bMaxPower, device power consumption is 100 mA
-
- // Interface 0, Alternate Setting 0, MSC Class
- 9, // bLength
- 4, // bDescriptorType
- 0x00, // bInterfaceNumber
- 0x00, // bAlternateSetting
- 0x02, // bNumEndpoints
- 0x08, // bInterfaceClass
- 0x06, // bInterfaceSubClass
- 0x50, // bInterfaceProtocol
- 0x04, // iInterface
-
- // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
- 7, // bLength
- 5, // bDescriptorType
- PHY_TO_DESC(EPBULK_IN), // bEndpointAddress
- 0x02, // bmAttributes (0x02=bulk)
- LSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (LSB)
- MSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (MSB)
- 0, // bInterval
-
- // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
- 7, // bLength
- 5, // bDescriptorType
- PHY_TO_DESC(EPBULK_OUT), // bEndpointAddress
- 0x02, // bmAttributes (0x02=bulk)
- LSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (LSB)
- MSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (MSB)
- 0 // bInterval
- };
- return configDescriptor;
-}
--- a/USBDevice/USBMSD/USBMSD.h Mon Nov 14 10:00:07 2011 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,204 +0,0 @@
-/* USBMSD.h */
-/* USB mass storage device example */
-/* Copyright (c) 2011 ARM Limited. All rights reserved. */
-
-/*
-* Guide to adapt this class to your storage chip:
-*
-*/
-
-#ifndef USBMSD_H
-#define USBMSD_H
-
-/* These headers are included for child class. */
-#include "USBEndpoints.h"
-#include "USBDescriptor.h"
-#include "USBDevice_Types.h"
-
-#include "USBDevice.h"
-
-#define DEFAULT_CONFIGURATION (1)
-
-
-// MSC Bulk-only Stage
-enum Stage {
- READ_CBW, // wait a CBW
- ERROR, // error
- PROCESS_CBW, // process a CBW request
- SEND_CSW, // send a CSW
- WAIT_CSW, // wait that a CSW has been effectively sent
-};
-
-// Bulk-only CBW
-typedef __packed struct {
- uint32_t Signature;
- uint32_t Tag;
- uint32_t DataLength;
- uint8_t Flags;
- uint8_t LUN;
- uint8_t CBLength;
- uint8_t CB[16];
-} CBW;
-
-// Bulk-only CSW
-typedef __packed struct {
- uint32_t Signature;
- uint32_t Tag;
- uint32_t DataResidue;
- uint8_t Status;
-} CSW;
-
-
-class USBMSD: public USBDevice {
-public:
-
- /**
- * Constructor
- *
- * @param vendor_id Your vendor_id
- * @param product_id Your product_id
- * @param product_release Your preoduct_release
- */
- USBMSD(uint16_t vendor_id = 0x0703, uint16_t product_id = 0x0104, uint16_t product_release = 0x0001);
-
- /*
- * read a block on a storage chip
- *
- * @param data pointer where will be stored read data
- * @param block block number
- * @returns 0 if successful
- */
- virtual int blockRead(uint8_t * data, uint16_t block){return 1;};
-
- /*
- * write a block on a storage chip
- *
- * @param data data to write
- * @param block block number
- * @returns 0 if successful
- */
- virtual int blockWrite(uint8_t * data, uint16_t block){return 1;};
-
- /*
- * Disk initilization
- */
- virtual int diskInit(){return -1;};
-
- /*
- * Return block size
- *
- * @returns size of a block
- */
- virtual uint16_t blockSize(){return 0;};
-
- /*
- * Return memory size
- *
- * @returns memory size
- */
- virtual uint32_t memorySize(){return 0;};
-
- /*
- * Connect the USB MSD device. Establish disk initialization before really connect the device.
- *
- * @returns
- */
- bool connect();
-
-
-protected:
-
-
- /*
- * Get number of logical unit - 1 (here 0)
- *
- * @returns Pointer containing the number of logical unit - 1
- */
- uint8_t * getMaxLUN();
-
- /*
- * Get string product descriptor
- *
- * @returns pointer to the string product descriptor
- */
- virtual uint8_t * stringIproductDesc();
-
- /*
- * Get string interface descriptor
- *
- * @returns pointer to the string interface descriptor
- */
- virtual uint8_t * stringIinterfaceDesc();
-
- /*
- * Get configuration descriptor
- *
- * @returns pointer to the configuration descriptor
- */
- virtual uint8_t * configurationDesc();
-
- /*
- * Callback called when a packet is received
- */
- virtual bool EP2_OUT_callback();
-
- /*
- * Callback called when a packet has been sent
- */
- virtual bool EP2_IN_callback();
-
- /*
- * Set configuration of device. Add endpoints
- */
- virtual bool USBCallback_setConfiguration(uint8_t configuration);
-
- /*
- * Callback called to process class specific requests
- */
- virtual bool USBCallback_request();
-
-
-private:
- //state of the bulk-only state machine
- Stage stage;
-
- // current CBW
- CBW cbw;
-
- // CSW which will be sent
- CSW csw;
-
- // addr where will be read or written data
- uint32_t addr;
-
- // length of a reading or writing
- uint32_t length;
-
- // memory OK (after a memoryVerify)
- bool memOK;
-
- // cache in RAM before writing in memory. Useful also to read a block.
- uint8_t * page;
-
- uint16_t BlockSize;
- uint32_t MemorySize;
- uint16_t BlockCount;
-
- void CBWDecode(uint8_t * buf, uint16_t size);
- void sendCSW (void);
- bool inquiryRequest (void);
- bool write (uint8_t * buf, uint16_t size);
- bool readFormatCapacity();
- bool readCapacity (void);
- bool infoTransfer (void);
- void memoryRead (void);
- bool modeSense6 (void);
- void testUnitReady (void);
- bool requestSense (void);
- void memoryVerify (uint8_t * buf, uint16_t size);
- void memoryWrite (uint8_t * buf, uint16_t size);
- void reset();
- void fail();
-};
-
-#endif
--- a/USBDevice/USBMSD/USB_SDcard.cpp Mon Nov 14 10:00:07 2011 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,374 +0,0 @@
-/* mbed USB_SDcard Library, for accessing SD cards
- * Copyright (c) 2008-2010, sford
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "USB_SDcard.h"
-
-#define SD_COMMAND_TIMEOUT 5000
-
-USB_SDcard::USB_SDcard(PinName mosi, PinName miso, PinName sclk, PinName cs):
- _spi(mosi, miso, sclk), _cs(cs) {
- _cs = 1;
- USBMSD::connect();
-}
-
-#define R1_IDLE_STATE (1 << 0)
-#define R1_ERASE_RESET (1 << 1)
-#define R1_ILLEGAL_COMMAND (1 << 2)
-#define R1_COM_CRC_ERROR (1 << 3)
-#define R1_ERASE_SEQUENCE_ERROR (1 << 4)
-#define R1_ADDRESS_ERROR (1 << 5)
-#define R1_PARAMETER_ERROR (1 << 6)
-
-// Types
-// - v1.x Standard Capacity
-// - v2.x Standard Capacity
-// - v2.x High Capacity
-// - Not recognised as an SD Card
-
-#define SDCARD_FAIL 0
-#define SDCARD_V1 1
-#define SDCARD_V2 2
-#define SDCARD_V2HC 3
-
-int USB_SDcard::initialise_card() {
- // Set to 100kHz for initialisation, and clock card with cs = 1
- _spi.frequency(100000);
- _cs = 1;
- for(int i=0; i<16; i++) {
- _spi.write(0xFF);
- }
-
- // send CMD0, should return with all zeros except IDLE STATE set (bit 0)
- if(_cmd(0, 0) != R1_IDLE_STATE) {
- fprintf(stderr, "No disk, or could not put SD card in to SPI idle state\n");
- return SDCARD_FAIL;
- }
-
- // send CMD8 to determine whther it is ver 2.x
- int r = _cmd8();
- if(r == R1_IDLE_STATE) {
- return initialise_card_v2();
- } else if(r == (R1_IDLE_STATE | R1_ILLEGAL_COMMAND)) {
- return initialise_card_v1();
- } else {
- fprintf(stderr, "Not in idle state after sending CMD8 (not an SD card?)\n");
- return SDCARD_FAIL;
- }
-}
-
-int USB_SDcard::initialise_card_v1() {
- for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
- _cmd(55, 0);
- if(_cmd(41, 0) == 0) {
- return SDCARD_V1;
- }
- }
-
- fprintf(stderr, "Timeout waiting for v1.x card\n");
- return SDCARD_FAIL;
-}
-
-int USB_SDcard::initialise_card_v2() {
-
- for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
- _cmd(55, 0);
- if(_cmd(41, 0) == 0) {
- _cmd58();
- return SDCARD_V2;
- }
- }
-
- fprintf(stderr, "Timeout waiting for v2.x card\n");
- return SDCARD_FAIL;
-}
-
-uint32_t USB_SDcard::memorySize()
-{
- return (uint32_t)capacity;
-}
-
-uint16_t USB_SDcard::blockSize()
-{
- return (uint16_t)block_len;
-}
-
-int USB_SDcard::diskInit() {
-
- int i = initialise_card();
-// printf("init card = %d\n", i);
-// printf("OK\n");
-
- _sectors = _sd_sectors();
-
- // Set block length to 512 (CMD16)
- if(_cmd(16, 512) != 0) {
- fprintf(stderr, "Set 512-byte block timed out\n");
- return 1;
- }
-
- _spi.frequency(1000000); // Set to 1MHz for data transfer
- return 0;
-}
-
-int USB_SDcard::blockWrite(uint8_t * buffer, uint16_t block_number) {
- // set write address for single block (CMD24)
- if(_cmd(24, block_number * 512) != 0) {
- return 1;
- }
-
- // send the data block
- _write((const char *)buffer, 512);
- return 0;
-}
-
-int USB_SDcard::blockRead(uint8_t * buffer, uint16_t block_number) {
- // set read address for single block (CMD17)
- if(_cmd(17, block_number * 512) != 0) {
- return 1;
- }
-
- // receive the data
- _read((char *)buffer, 512);
- return 0;
-}
-
-int USB_SDcard::disk_status() { return 0; }
-int USB_SDcard::disk_sync() { return 0; }
-int USB_SDcard::disk_sectors() { return _sectors; }
-
-// PRIVATE FUNCTIONS
-
-int USB_SDcard::_cmd(int cmd, int arg) {
- _cs = 0;
-
- // send a command
- _spi.write(0x40 | cmd);
- _spi.write(arg >> 24);
- _spi.write(arg >> 16);
- _spi.write(arg >> 8);
- _spi.write(arg >> 0);
- _spi.write(0x95);
-
- // wait for the repsonse (response[7] == 0)
- for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
- int response = _spi.write(0xFF);
- if(!(response & 0x80)) {
- _cs = 1;
- _spi.write(0xFF);
- return response;
- }
- }
- _cs = 1;
- _spi.write(0xFF);
- return -1; // timeout
-}
-int USB_SDcard::_cmdx(int cmd, int arg) {
- _cs = 0;
-
- // send a command
- _spi.write(0x40 | cmd);
- _spi.write(arg >> 24);
- _spi.write(arg >> 16);
- _spi.write(arg >> 8);
- _spi.write(arg >> 0);
- _spi.write(0x95);
-
- // wait for the repsonse (response[7] == 0)
- for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
- int response = _spi.write(0xFF);
- if(!(response & 0x80)) {
- return response;
- }
- }
- _cs = 1;
- _spi.write(0xFF);
- return -1; // timeout
-}
-
-
-int USB_SDcard::_cmd58() {
- _cs = 0;
- int arg = 0;
-
- // send a command
- _spi.write(0x40 | 58);
- _spi.write(arg >> 24);
- _spi.write(arg >> 16);
- _spi.write(arg >> 8);
- _spi.write(arg >> 0);
- _spi.write(0x95);
-
- // wait for the repsonse (response[7] == 0)
- for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
- int response = _spi.write(0xFF);
- if(!(response & 0x80)) {
- int ocr = _spi.write(0xFF) << 24;
- ocr |= _spi.write(0xFF) << 16;
- ocr |= _spi.write(0xFF) << 8;
- ocr |= _spi.write(0xFF) << 0;
-// printf("OCR = 0x%08X\n", ocr);
- _cs = 1;
- _spi.write(0xFF);
- return response;
- }
- }
- _cs = 1;
- _spi.write(0xFF);
- return -1; // timeout
-}
-
-int USB_SDcard::_cmd8() {
- _cs = 0;
-
- // send a command
- _spi.write(0x40 | 8); // CMD8
- _spi.write(0x00); // reserved
- _spi.write(0x00); // reserved
- _spi.write(0x01); // 3.3v
- _spi.write(0xAA); // check pattern
- _spi.write(0x87); // crc
-
- // wait for the repsonse (response[7] == 0)
- for(int i=0; i<SD_COMMAND_TIMEOUT * 1000; i++) {
- char response[5];
- response[0] = _spi.write(0xFF);
- if(!(response[0] & 0x80)) {
- for(int j=1; j<5; j++) {
- response[i] = _spi.write(0xFF);
- }
- _cs = 1;
- _spi.write(0xFF);
- return response[0];
- }
- }
- _cs = 1;
- _spi.write(0xFF);
- return -1; // timeout
-}
-
-int USB_SDcard::_read(char *buffer, int length) {
- _cs = 0;
-
- // read until start byte (0xFF)
- while(_spi.write(0xFF) != 0xFE);
-
- // read data
- for(int i=0; i<length; i++) {
- buffer[i] = _spi.write(0xFF);
- }
- _spi.write(0xFF); // checksum
- _spi.write(0xFF);
-
- _cs = 1;
- _spi.write(0xFF);
- return 0;
-}
-
-int USB_SDcard::_write(const char *buffer, int length) {
- _cs = 0;
-
- // indicate start of block
- _spi.write(0xFE);
-
- // write the data
- for(int i=0; i<length; i++) {
- _spi.write(buffer[i]);
- }
-
- // write the checksum
- _spi.write(0xFF);
- _spi.write(0xFF);
-
- // check the repsonse token
- if((_spi.write(0xFF) & 0x1F) != 0x05) {
- _cs = 1;
- _spi.write(0xFF);
- return 1;
- }
-
- // wait for write to finish
- while(_spi.write(0xFF) == 0);
-
- _cs = 1;
- _spi.write(0xFF);
- return 0;
-}
-
-static int ext_bits(char *data, int msb, int lsb) {
- int bits = 0;
- int size = 1 + msb - lsb;
- for(int i=0; i<size; i++) {
- int position = lsb + i;
- int byte = 15 - (position >> 3);
- int bit = position & 0x7;
- int value = (data[byte] >> bit) & 1;
- bits |= value << i;
- }
- return bits;
-}
-
-int USB_SDcard::_sd_sectors() {
-
- // CMD9, Response R2 (R1 byte + 16-byte block read)
- if(_cmdx(9, 0) != 0) {
- fprintf(stderr, "Didn't get a response from the disk\n");
- return 0;
- }
-
- char csd[16];
- if(_read(csd, 16) != 0) {
- fprintf(stderr, "Couldn't read csd response from disk\n");
- return 0;
- }
-
- // csd_structure : csd[127:126]
- // c_size : csd[73:62]
- // c_size_mult : csd[49:47]
- // read_bl_len : csd[83:80] - the *maximum* read block length
-
- int csd_structure = ext_bits(csd, 127, 126);
- int c_size = ext_bits(csd, 73, 62);
- int c_size_mult = ext_bits(csd, 49, 47);
- int read_bl_len = ext_bits(csd, 83, 80);
-
-// printf("CSD_STRUCT = %d\n", csd_structure);
-
- if(csd_structure != 0) {
- fprintf(stderr, "This disk tastes funny! I only know about type 0 CSD structures\n");
- return 0;
- }
-
- // memory capacity = BLOCKNR * BLOCK_LEN
- // where
- // BLOCKNR = (C_SIZE+1) * MULT
- // MULT = 2^(C_SIZE_MULT+2) (C_SIZE_MULT < 8)
- // BLOCK_LEN = 2^READ_BL_LEN, (READ_BL_LEN < 12)
-
- block_len = 1 << read_bl_len;
- int mult = 1 << (c_size_mult + 2);
- int blocknr = (c_size + 1) * mult;
- capacity = blocknr * block_len;
-
- int blocks = capacity / 512;
-
- return blocks;
-}
--- a/USBDevice/USBMSD/USB_SDcard.h Mon Nov 14 10:00:07 2011 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,87 +0,0 @@
-/* mbed USB_SDcard Library, for accessing SD cards
- * Copyright (c) 2008-2010, sford
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#ifndef USB_SDCARD_H
-#define USB_SDCARD_H
-
-#include "mbed.h"
-#include "USBMSD.h"
-
-class USB_SDcard : public USBMSD {
-public:
-
- /** Create the File System for accessing an SD Card using SPI
- *
- * @param mosi SPI mosi pin connected to SD Card
- * @param miso SPI miso pin conencted to SD Card
- * @param sclk SPI sclk pin connected to SD Card
- * @param cs DigitalOut pin used as SD Card chip select
- */
- USB_SDcard(PinName mosi = p5, PinName miso = p6, PinName sclk = p7, PinName cs = p8);
-
- /*
- * read a block on a storage chip
- *
- * @param data pointer where will be stored read data
- * @param block block number
- * @returns 0 if successful
- */
- virtual int blockRead(uint8_t * data, uint16_t block);
-
- /*
- * write a block on a storage chip
- *
- * @param data data to write
- * @param block block number
- * @returns 0 if successful
- */
- virtual int blockWrite(uint8_t * data, uint16_t block);
-
- virtual int diskInit();
- virtual uint16_t blockSize();
- virtual uint32_t memorySize();
-
-protected:
-
- int disk_status();
- int disk_sync();
- int disk_sectors();
- int _cmd(int cmd, int arg);
- int _cmdx(int cmd, int arg);
- int _cmd8();
- int _cmd58();
- int initialise_card();
- int initialise_card_v1();
- int initialise_card_v2();
-
- int _read(char *buffer, int length);
- int _write(const char *buffer, int length);
- int _sd_sectors();
- int _sectors;
- int capacity;
- int block_len;
-
- SPI _spi;
- DigitalOut _cs;
-};
-
-#endif
--- a/USBDevice/USBSERIAL/CBuffer.h Mon Nov 14 10:00:07 2011 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-#ifndef CBUFFER_H
-#define CBUFFER_H
-
-#define MAX_BUF 128
-
-class CBuffer {
-public:
- CBuffer() {
- write = 0;
- read = 0;
- size = MAX_BUF + 1;
- };
-
- bool isFull() {
- return ((write + 1) % size == read);
- };
-
- bool isEmpty() {
- return (read == write);
- };
-
- void queue(uint8_t k) {
- if (isFull()) {
- read++;
- read %= size;
- }
- buf[write++] = k;
- write %= size;
- }
-
- uint16_t available() {
- return (write >= read) ? write - read : size - read + write;
- };
-
- bool dequeue(uint8_t * c) {
- if (!isEmpty()) {
- *c = buf[read++];
- read %= size;
- }
- return(isEmpty());
- };
-
-
-private:
- volatile uint16_t write;
- volatile uint16_t read;
- uint16_t size;
- uint8_t buf[MAX_BUF + 1];
-};
-
-#endif
\ No newline at end of file
--- a/USBDevice/USBSERIAL/USBCDC.cpp Mon Nov 14 10:00:07 2011 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,225 +0,0 @@
-/* USBCDC.c */
-/* CDC class */
-/* Copyright (c) 2011 ARM Limited. All rights reserved. */
-
-#include "stdint.h"
-#include "USBCDC.h"
-#include "USBBusInterface.h"
-
-static uint8_t cdc_line_coding[7]= {0x80, 0x25, 0x00, 0x00, 0x00, 0x00, 0x08};
-
-#define DEFAULT_CONFIGURATION (1)
-
-#define CDC_SET_LINE_CODING 0x20
-#define CDC_GET_LINE_CODING 0x21
-#define CDC_SET_CONTROL_LINE_STATE 0x22
-
-#define MAX_CDC_REPORT_SIZE MAX_PACKET_SIZE_EPBULK
-
-USBCDC::USBCDC(uint16_t vendor_id, uint16_t product_id, uint16_t product_release):
- USBDevice(vendor_id, product_id, product_release) { }
-
-bool USBCDC::USBCallback_request(void) {
- /* Called in ISR context */
-
- bool success = false;
- CONTROL_TRANSFER * transfer = getTransferPtr();
-
- /* Process class-specific requests */
-
- if (transfer->setup.bmRequestType.Type == CLASS_TYPE) {
- switch (transfer->setup.bRequest) {
- case CDC_GET_LINE_CODING:
- transfer->remaining = 7;
- transfer->ptr = cdc_line_coding;
- transfer->direction = DEVICE_TO_HOST;
- success = true;
- break;
- case CDC_SET_LINE_CODING:
- transfer->remaining = 7;
- success = true;
- break;
- case CDC_SET_CONTROL_LINE_STATE:
- success = true;
- break;
- default:
- break;
- }
- }
-
- return success;
-}
-
-
-// Called in ISR context
-// Set configuration. Return false if the
-// configuration is not supported.
-bool USBCDC::USBCallback_setConfiguration(uint8_t configuration) {
- if (configuration != DEFAULT_CONFIGURATION) {
- return false;
- }
-
- // Configure endpoints > 0
- addEndpoint(EPINT_IN, MAX_PACKET_SIZE_EPINT);
- addEndpoint(EPBULK_IN, MAX_PACKET_SIZE_EPBULK);
- addEndpoint(EPBULK_OUT, MAX_PACKET_SIZE_EPBULK);
-
- // We activate the endpoint to be able to recceive data
- readStart(EPBULK_OUT, MAX_PACKET_SIZE_EPBULK);
- return true;
-}
-
-bool USBCDC::send(uint8_t endpoint, uint8_t * buffer, uint16_t size) {
- return write(endpoint, buffer, size, MAX_CDC_REPORT_SIZE);
-}
-
-bool USBCDC::read(uint8_t endpoint, uint8_t * buffer, uint16_t * size, uint16_t maxSize) {
- if (!USBDevice::read(endpoint, buffer, size, maxSize))
- return false;
- if (!readStart(endpoint, maxSize))
- return false;
- return true;
-}
-
-bool USBCDC::readNB(uint8_t endpoint, uint8_t * buffer, uint16_t * size, uint16_t maxSize) {
- if (!USBDevice::readNB(endpoint, buffer, size, MAX_CDC_REPORT_SIZE))
- return false;
- if (!readStart(endpoint, MAX_CDC_REPORT_SIZE))
- return false;
- return true;
-}
-
-
-uint8_t * USBCDC::deviceDesc() {
- static uint8_t deviceDescriptor[] = {
- 18, // bLength
- 1, // bDescriptorType
- 0x10, 0x01, // bcdUSB
- 2, // bDeviceClass
- 0, // bDeviceSubClass
- 0, // bDeviceProtocol
- MAX_PACKET_SIZE_EP0, // bMaxPacketSize0
- LSB(VENDOR_ID), MSB(VENDOR_ID), // idVendor
- LSB(PRODUCT_ID), MSB(PRODUCT_ID),// idProduct
- 0x00, 0x01, // bcdDevice
- 1, // iManufacturer
- 2, // iProduct
- 3, // iSerialNumber
- 1 // bNumConfigurations
- };
- return deviceDescriptor;
-}
-
-uint8_t * USBCDC::stringIinterfaceDesc() {
- static uint8_t stringIinterfaceDescriptor[] = {
- 0x08,
- STRING_DESCRIPTOR,
- 'C',0,'D',0,'C',0,
- };
- return stringIinterfaceDescriptor;
-}
-
-uint8_t * USBCDC::stringIproductDesc() {
- static uint8_t stringIproductDescriptor[] = {
- 0x16,
- STRING_DESCRIPTOR,
- 'C',0,'D',0,'C',0,' ',0,'D',0,'E',0,'V',0,'I',0,'C',0,'E',0
- };
- return stringIproductDescriptor;
-}
-
-
-#define CONFIG1_DESC_SIZE (9+9+5+5+4+5+7+9+7+7)
-
-uint8_t * USBCDC::configurationDesc() {
- static uint8_t configDescriptor[] = {
- 9, // bLength;
- 2, // bDescriptorType;
- LSB(CONFIG1_DESC_SIZE), // wTotalLength
- MSB(CONFIG1_DESC_SIZE),
- 2, // bNumInterfaces
- 1, // bConfigurationValue
- 0, // iConfiguration
- 0x80, // bmAttributes
- 50, // bMaxPower
-
- // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
- 9, // bLength
- 4, // bDescriptorType
- 0, // bInterfaceNumber
- 0, // bAlternateSetting
- 1, // bNumEndpoints
- 0x02, // bInterfaceClass
- 0x02, // bInterfaceSubClass
- 0x01, // bInterfaceProtocol
- 0, // iInterface
-
- // CDC Header Functional Descriptor, CDC Spec 5.2.3.1, Table 26
- 5, // bFunctionLength
- 0x24, // bDescriptorType
- 0x00, // bDescriptorSubtype
- 0x10, 0x01, // bcdCDC
-
- // Call Management Functional Descriptor, CDC Spec 5.2.3.2, Table 27
- 5, // bFunctionLength
- 0x24, // bDescriptorType
- 0x01, // bDescriptorSubtype
- 0x03, // bmCapabilities
- 1, // bDataInterface
-
- // Abstract Control Management Functional Descriptor, CDC Spec 5.2.3.3, Table 28
- 4, // bFunctionLength
- 0x24, // bDescriptorType
- 0x02, // bDescriptorSubtype
- 0x06, // bmCapabilities
-
- // Union Functional Descriptor, CDC Spec 5.2.3.8, Table 33
- 5, // bFunctionLength
- 0x24, // bDescriptorType
- 0x06, // bDescriptorSubtype
- 0, // bMasterInterface
- 1, // bSlaveInterface0
-
- // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
- ENDPOINT_DESCRIPTOR_LENGTH, // bLength
- ENDPOINT_DESCRIPTOR, // bDescriptorType
- PHY_TO_DESC(EPINT_IN), // bEndpointAddress
- E_INTERRUPT, // bmAttributes (0x03=intr)
- LSB(MAX_PACKET_SIZE_EPINT), // wMaxPacketSize (LSB)
- MSB(MAX_PACKET_SIZE_EPINT), // wMaxPacketSize (MSB)
- 16, // bInterval
-
-
-
-
- // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
- 9, // bLength
- 4, // bDescriptorType
- 1, // bInterfaceNumber
- 0, // bAlternateSetting
- 2, // bNumEndpoints
- 0x0A, // bInterfaceClass
- 0x00, // bInterfaceSubClass
- 0x00, // bInterfaceProtocol
- 0, // iInterface
-
- // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
- 7, // bLength
- 5, // bDescriptorType
- PHY_TO_DESC(EPBULK_IN), // bEndpointAddress
- 0x02, // bmAttributes (0x02=bulk)
- LSB(MAX_PACKET_SIZE_EPBULK), // wMaxPacketSize (LSB)
- MSB(MAX_PACKET_SIZE_EPBULK), // wMaxPacketSize (MSB)
- 0, // bInterval
-
- // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
- 7, // bLength
- 5, // bDescriptorType
- PHY_TO_DESC(EPBULK_OUT),// bEndpointAddress
- 0x02, // bmAttributes (0x02=bulk)
- LSB(MAX_PACKET_SIZE_EPBULK), // wMaxPacketSize (LSB)
- MSB(MAX_PACKET_SIZE_EPBULK), // wMaxPacketSize (MSB)
- 0 // bInterval
- };
- return configDescriptor;
-}
--- a/USBDevice/USBSERIAL/USBCDC.h Mon Nov 14 10:00:07 2011 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,95 +0,0 @@
-/* USBCDC.h */
-/* CDC class */
-/* Copyright (c) 2011 ARM Limited. All rights reserved. */
-
-#ifndef USBCDC_H
-#define USBCDC_H
-
-/* These headers are included for child class. */
-#include "USBEndpoints.h"
-#include "USBDescriptor.h"
-#include "USBDevice_Types.h"
-
-#include "USBDevice.h"
-
-
-
-class USBCDC: public USBDevice {
-public:
-
- /*
- * Constructor
- *
- * @param vendor_id Your vendor_id
- * @param product_id Your product_id
- * @param product_release Your preoduct_release
- */
- USBCDC(uint16_t vendor_id, uint16_t product_id, uint16_t product_release);
-
-
- /*
- * Get device descriptor. Warning: this method has to store the length of the report descriptor in reportLength.
- *
- * @returns pointer to the device descriptor
- */
- virtual uint8_t * deviceDesc();
-
- /*
- * Get string product descriptor
- *
- * @returns pointer to the string product descriptor
- */
- virtual uint8_t * stringIproductDesc();
-
- /*
- * Get string interface descriptor
- *
- * @returns pointer to the string interface descriptor
- */
- virtual uint8_t * stringIinterfaceDesc();
-
- /*
- * Get configuration descriptor
- *
- * @returns pointer to the configuration descriptor
- */
- virtual uint8_t * configurationDesc();
-
- /*
- * Send a buffer to a certain endpoint
- *
- * @param endpoint endpoint which will be sent the buffer
- * @param buffer buffer to be sent
- * @param size length of the buffer
- * @returns true if successful
- */
- bool send(uint8_t endpoint, uint8_t * buffer, uint16_t size);
-
- /*
- * Read a buffer from a certain endpoint. Warning: blocking
- *
- * @param endpoint endpoint to read
- * @param buffer buffer where will be stored bytes
- * @param size the number of bytes read will be stored in *size
- * @param maxSize the maximum length that can be read
- * @returns true if successful
- */
- bool read(uint8_t endpoint, uint8_t * buffer, uint16_t * size, uint16_t maxSize);
-
- /*
- * Read a buffer from a certain endpoint. Warning: non blocking
- *
- * @param endpoint endpoint to read
- * @param buffer buffer where will be stored bytes
- * @param size the number of bytes read will be stored in *size
- * @param maxSize the maximum length that can be read
- * @returns true if successful
- */
- bool readNB(uint8_t endpoint, uint8_t * buffer, uint16_t * size, uint16_t maxSize);
-
- virtual bool USBCallback_request();
- virtual bool USBCallback_setConfiguration(uint8_t configuration);
-
-};
-
-#endif
--- a/USBDevice/USBSERIAL/USBSerial.cpp Mon Nov 14 10:00:07 2011 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-// USBSerial.c
-// USB device example: virtual serial port
-// Copyright (c) 2011 ARM Limited. All rights reserved
-
-#include "stdint.h"
-#include "USBSerial.h"
-#include "USBBusInterface.h"
-
-
-int USBSerial::_putc(int c) {
- send(EPBULK_IN, (uint8_t *)&c, 1);
- return 1;
-}
-
-int USBSerial::_getc() {
- uint8_t c;
- while (buf.isEmpty());
- buf.dequeue(&c);
- return c;
-}
-
-void USBSerial::attach(void (*ptr)(void)) {
- handler = true;
- proc = true;
- fn = ptr;
-}
-
-
-bool USBSerial::EP2_OUT_callback() {
- uint8_t c[65];
- uint16_t size = 0;
-
- //we read the packet received and put it on the circular buffer
- USBCDC::read(EPBULK_OUT, c, &size, MAX_PACKET_SIZE_EPBULK);
- for (int i = 0; i < size; i++) {
- buf.queue(c[i]);
- }
-
- //call a potential handler
- if (handler) {
- if (proc) {
- (*fn)();
- } else {
- rx.call();
- }
- }
-
- // We reactivate the endpoint to receive next characters
- readStart(EPBULK_OUT, MAX_PACKET_SIZE_EPBULK);
- return true;
-}
-
-uint8_t USBSerial::available() {
- return buf.available();
-}
--- a/USBDevice/USBSERIAL/USBSerial.h Mon Nov 14 10:00:07 2011 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,106 +0,0 @@
-/* USBSerial.h */
-/* USB device example: virtual serial port */
-/* Copyright (c) 2011 ARM Limited. All rights reserved. */
-
-#ifndef USBSERIAL_H
-#define USBSERIAL_H
-
-#include "USBCDC.h"
-#include "Stream.h"
-#include "CBuffer.h"
-
-
-/**
-* USBSerial example
-*
-* @code
-* #include "mbed.h"
-* #include "USBSerial.h"
-*
-* //Virtual serial port over USB
-* USBSerial serial;
-*
-* int main(void) {
-*
-* while(1)
-* {
-* serial.printf("I am a virtual serial port\n");
-* wait(1);
-* }
-* }
-* @endcode
-*/
-class USBSerial: public USBCDC, public Stream {
-public:
-
- /**
- * Constructor
- *
- * @param vendor_id Your vendor_id (default: 0x1f00)
- * @param product_id Your product_id (default: 0x2012)
- * @param product_release Your preoduct_release (default: 0x0001)
- *
- */
- USBSerial(uint16_t vendor_id = 0x1f00, uint16_t product_id = 0x2012, uint16_t product_release = 0x0001): USBCDC(vendor_id, product_id, product_release){
- handler = false;
- proc = false;
- };
-
-
- /**
- * Send a character. You can use puts, printf.
- *
- * @param c character to be sent
- * @returns true if there is no error, false otherwise
- */
- virtual int _putc(int c);
-
- /**
- * Read a character: blocking
- *
- * @returns character read
- */
- virtual int _getc();
-
- /**
- * Check the number of bytes available.
- *
- * @returns the number of bytes available
- */
- uint8_t available();
-
- /**
- * Attach a member function to call when a packet is received.
- *
- * @param tptr pointer to the object to call the member function on
- * @param mptr pointer to the member function to be called
- */
- template<typename T>
- void attach(T* tptr, void (T::*mptr)(void)) {
- if((mptr != NULL) && (tptr != NULL)) {
- proc = false;
- handler = true;
- rx.attach(tptr, mptr);
- }
- }
-
- /**
- * Attach a callback for when a packet is received
- *
- * @param fptr function pointer
- */
- void attach(void (*fn)(void));
-
-
-protected:
- virtual bool EP2_OUT_callback();
-
-private:
- FunctionPointer rx;
- CBuffer buf;
- void (*fn)(void);
- bool handler;
- bool proc;
-};
-
-#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBMSD/USBMSD.cpp Mon Nov 14 12:08:32 2011 +0000
@@ -0,0 +1,614 @@
+// USBMSD.cpp
+// USB mass storage device example
+// Copyright (c) 2011 ARM Limited. All rights reserved.
+
+#include "stdint.h"
+#include "USBMSD.h"
+#include "USBBusInterface.h"
+
+#define CBW_Signature 0x43425355
+#define CSW_Signature 0x53425355
+
+// SCSI Commands
+#define TEST_UNIT_READY 0x00
+#define REQUEST_SENSE 0x03
+#define FORMAT_UNIT 0x04
+#define INQUIRY 0x12
+#define MODE_SELECT6 0x15
+#define MODE_SENSE6 0x1A
+#define START_STOP_UNIT 0x1B
+#define MEDIA_REMOVAL 0x1E
+#define READ_FORMAT_CAPACITIES 0x23
+#define READ_CAPACITY 0x25
+#define READ10 0x28
+#define WRITE10 0x2A
+#define VERIFY10 0x2F
+#define READ12 0xA8
+#define WRITE12 0xAA
+#define MODE_SELECT10 0x55
+#define MODE_SENSE10 0x5A
+
+// MSC class specific requests
+#define MSC_REQUEST_RESET 0xFF
+#define MSC_REQUEST_GET_MAX_LUN 0xFE
+
+#define DEFAULT_CONFIGURATION (1)
+
+// Max In/Out Packet Size on the bulk endpoint */
+#define MAX_PACKET MAX_PACKET_SIZE_EPBULK
+
+// CSW Status
+enum Status {
+ CSW_PASSED,
+ CSW_FAILED,
+ CSW_ERROR,
+};
+
+
+USBMSD::USBMSD(uint16_t vendor_id, uint16_t product_id, uint16_t product_release): USBDevice(vendor_id, product_id, product_release) {
+}
+
+
+DigitalOut l2(LED2);
+// Called in ISR context to process a class specific request
+bool USBMSD::USBCallback_request(void) {
+
+ bool success = false;
+ CONTROL_TRANSFER * transfer = getTransferPtr();
+
+ if (transfer->setup.bmRequestType.Type == CLASS_TYPE) {
+ switch (transfer->setup.bRequest) {
+ case MSC_REQUEST_RESET:
+ reset();
+ success = true;
+ break;
+ case MSC_REQUEST_GET_MAX_LUN:
+ transfer->remaining = 1;
+ transfer->ptr = getMaxLUN();
+ transfer->direction = DEVICE_TO_HOST;
+ success = true;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return success;
+}
+
+
+bool USBMSD::connect() {
+
+ //disk initialization
+ diskInit();
+
+ // get block size
+ BlockSize = blockSize();
+ if (BlockSize != 0) {
+ page = (uint8_t *)malloc(BlockSize * sizeof(uint8_t));
+ if (page == NULL)
+ return false;
+ }
+
+ //get memory size
+ MemorySize = memorySize();
+ if (!MemorySize) {
+ return false;
+ }
+ BlockCount = MemorySize/BlockSize;
+
+ //connect the device
+ USBDevice::connect();
+ return true;
+}
+
+
+void USBMSD::reset() {
+ stage = READ_CBW;
+}
+
+uint8_t * USBMSD::getMaxLUN() {
+ static uint8_t LUN[] = {0};
+ return LUN;
+}
+
+// Called in ISR context called when a data is received
+bool USBMSD::EP2_OUT_callback() {
+ uint16_t size = 0;
+ uint8_t buf[MAX_PACKET_SIZE_EPBULK];
+ read(EPBULK_OUT, buf, &size, MAX_PACKET_SIZE_EPBULK);
+ switch (stage) {
+ // the device has to decode the CBW received
+ case READ_CBW:
+ CBWDecode(buf, size);
+ break;
+
+ // the device has to receive data from the host
+ case PROCESS_CBW:
+ switch (cbw.CB[0]) {
+ case WRITE10:
+ case WRITE12:
+ memoryWrite(buf, size);
+ break;
+ case VERIFY10:
+ memoryVerify(buf, size);
+ break;
+ }
+ break;
+
+ // an error has occured: stall endpoint and send CSW
+ default:
+ stallEndpoint(EPBULK_OUT);
+ csw.Status = CSW_ERROR;
+ sendCSW();
+ break;
+ }
+
+ //reactivate readings on the OUT bulk endpoint
+ readStart(EPBULK_OUT, MAX_PACKET_SIZE_EPBULK);
+ return true;
+}
+
+// Called in ISR context when a data has been transferred
+bool USBMSD::EP2_IN_callback() {
+ switch (stage) {
+
+ // the device has to send data to the host
+ case PROCESS_CBW:
+ switch (cbw.CB[0]) {
+ case READ10:
+ case READ12:
+ memoryRead();
+ break;
+ }
+ break;
+
+ //the device has to send a CSW
+ case SEND_CSW:
+ sendCSW();
+ break;
+
+ // an error has occured
+ case ERROR:
+ stallEndpoint(EPBULK_IN);
+ sendCSW();
+ break;
+
+ // the host has received the CSW -> we wait a CBW
+ case WAIT_CSW:
+ stage = READ_CBW;
+ break;
+ }
+ return true;
+}
+
+
+void USBMSD::memoryWrite (uint8_t * buf, uint16_t size) {
+
+ if ((addr + size) > MemorySize) {
+ size = MemorySize - addr;
+ stage = ERROR;
+ stallEndpoint(EPBULK_OUT);
+ }
+
+ // we fill an array in RAM of 1 block before writing it in memory
+ for (int i = 0; i < size; i++)
+ page[addr%BlockSize + i] = buf[i];
+
+ // if the array is filled, write it in memory
+ if (!((addr + size)%BlockSize))
+ blockWrite(page, addr/BlockSize);
+
+ addr += size;
+ length -= size;
+ csw.DataResidue -= size;
+
+ if ((!length) || (stage != PROCESS_CBW)) {
+ csw.Status = (stage == ERROR) ? CSW_FAILED : CSW_PASSED;
+ sendCSW();
+ }
+}
+
+void USBMSD::memoryVerify (uint8_t * buf, uint16_t size) {
+ uint32_t n;
+
+ if ((addr + size) > MemorySize) {
+ size = MemorySize - addr;
+ stage = ERROR;
+ stallEndpoint(EPBULK_OUT);
+ }
+
+ // beginning of a new block -> load a whole block in RAM
+ if (!(addr%BlockSize))
+ blockRead(page, addr/BlockSize);
+
+ // info are in RAM -> no need to re-read memory
+ for (n = 0; n < size; n++) {
+ if (page[addr%BlockSize + n] != buf[n]) {
+ memOK = false;
+ break;
+ }
+ }
+
+ addr += size;
+ length -= size;
+ csw.DataResidue -= size;
+
+ if ( !length || (stage != PROCESS_CBW)) {
+ csw.Status = (memOK && (stage == PROCESS_CBW)) ? CSW_PASSED : CSW_FAILED;
+ sendCSW();
+ }
+}
+
+
+bool USBMSD::inquiryRequest (void) {
+ uint8_t inquiry[] = { 0x00, 0x80, 0x00, 0x01,
+ 36 - 4, 0x80, 0x00, 0x00,
+ 'M', 'B', 'E', 'D', '.', 'O', 'R', 'G',
+ 'M', 'B', 'E', 'D', ' ', 'U', 'S', 'B', ' ', 'D', 'I', 'S', 'K', ' ', ' ', ' ',
+ '1', '.', '0', ' ',
+ };
+ if (!write(inquiry, sizeof(inquiry))) {
+ return false;
+ }
+ return true;
+}
+
+
+bool USBMSD::readFormatCapacity() {
+ uint8_t capacity[] = { 0x00, 0x00, 0x00, 0x08,
+ (BlockCount >> 24) & 0xff,
+ (BlockCount >> 16) & 0xff,
+ (BlockCount >> 8) & 0xff,
+ (BlockCount >> 0) & 0xff,
+
+ 0x02,
+ (BlockSize >> 16) & 0xff,
+ (BlockSize >> 8) & 0xff,
+ (BlockSize >> 0) & 0xff,
+ };
+ if (!write(capacity, sizeof(capacity))) {
+ return false;
+ }
+ return true;
+}
+
+
+bool USBMSD::readCapacity (void) {
+ uint8_t capacity[] = {
+ ((BlockCount - 1) >> 24) & 0xff,
+ ((BlockCount - 1) >> 16) & 0xff,
+ ((BlockCount - 1) >> 8) & 0xff,
+ ((BlockCount - 1) >> 0) & 0xff,
+
+ (BlockSize >> 24) & 0xff,
+ (BlockSize >> 16) & 0xff,
+ (BlockSize >> 8) & 0xff,
+ (BlockSize >> 0) & 0xff,
+ };
+ if (!write(capacity, sizeof(capacity))) {
+ return false;
+ }
+ return true;
+}
+
+bool USBMSD::write (uint8_t * buf, uint16_t size) {
+
+ if (size >= cbw.DataLength) {
+ size = cbw.DataLength;
+ }
+ stage = SEND_CSW;
+
+ if (!writeNB(EPBULK_IN, buf, size, MAX_PACKET_SIZE_EPBULK)) {
+ return false;
+ }
+
+ csw.DataResidue -= size;
+ csw.Status = CSW_PASSED;
+ return true;
+}
+
+
+bool USBMSD::modeSense6 (void) {
+ uint8_t sense6[] = { 0x03, 0x00, 0x00, 0x00 };
+ if (!write(sense6, sizeof(sense6))) {
+ return false;
+ }
+ return true;
+}
+
+void USBMSD::sendCSW() {
+ csw.Signature = CSW_Signature;
+ writeNB(EPBULK_IN, (uint8_t *)&csw, sizeof(CSW), MAX_PACKET_SIZE_EPBULK);
+ stage = WAIT_CSW;
+}
+
+bool USBMSD::requestSense (void) {
+ uint8_t request_sense[] = {
+ 0x70, // Response Code
+ 0x00,
+ 0x05, // Sense Key: illegal request
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x0A, // Additional Length
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x30, // ASC
+ 0x01, // ASCQ
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ };
+
+ if (!write(request_sense, sizeof(request_sense))) {
+ return false;
+ }
+
+ return true;
+}
+
+void USBMSD::fail() {
+ csw.Status = CSW_FAILED;
+ sendCSW();
+}
+
+DigitalOut l1(LED1);
+void USBMSD::CBWDecode(uint8_t * buf, uint16_t size) {
+ if (size == sizeof(cbw)) {
+ memcpy((uint8_t *)&cbw, buf, size);
+ if (cbw.Signature == CBW_Signature) {
+ csw.Tag = cbw.Tag;
+ csw.DataResidue = cbw.DataLength;
+ if ((cbw.CBLength < 1) || (cbw.CBLength > 16) ) {
+ fail();
+ } else {
+ switch (cbw.CB[0]) {
+ case TEST_UNIT_READY:
+ testUnitReady();
+ break;
+ case REQUEST_SENSE:
+ requestSense();
+ break;
+ case INQUIRY:
+ inquiryRequest();
+ break;
+ case MODE_SENSE6:
+ modeSense6();
+ break;
+ case READ_FORMAT_CAPACITIES:
+ readFormatCapacity();
+ break;
+ case READ_CAPACITY:
+ readCapacity();
+ break;
+ case READ10:
+ case READ12:
+ if (infoTransfer()) {
+ if ((cbw.Flags & 0x80)) {
+ stage = PROCESS_CBW;
+ memoryRead();
+ } else {
+ stallEndpoint(EPBULK_OUT);
+ csw.Status = CSW_ERROR;
+ sendCSW();
+ }
+ }
+ break;
+ case WRITE10:
+ case WRITE12:
+ if (infoTransfer()) {
+ if (!(cbw.Flags & 0x80)) {
+ stage = PROCESS_CBW;
+ } else {
+ stallEndpoint(EPBULK_IN);
+ csw.Status = CSW_ERROR;
+ sendCSW();
+ }
+ }
+ break;
+ case VERIFY10:
+ if (!(cbw.CB[1] & 0x02)) {
+ csw.Status = CSW_PASSED;
+ sendCSW();
+ break;
+ }
+ if (infoTransfer()) {
+ if (!(cbw.Flags & 0x80)) {
+ stage = PROCESS_CBW;
+ memOK = true;
+ } else {
+ stallEndpoint(EPBULK_IN);
+ csw.Status = CSW_ERROR;
+ sendCSW();
+ }
+ }
+ break;
+ default:
+ fail();
+ break;
+ }
+ }
+ }
+ }
+}
+
+void USBMSD::testUnitReady (void) {
+
+ if (cbw.DataLength != 0) {
+ if ((cbw.Flags & 0x80) != 0) {
+ stallEndpoint(EPBULK_IN);
+ } else {
+ stallEndpoint(EPBULK_OUT);
+ }
+ }
+
+ csw.Status = CSW_PASSED;
+ sendCSW();
+}
+
+
+void USBMSD::memoryRead (void) {
+ uint32_t n;
+
+ n = (length > MAX_PACKET) ? MAX_PACKET : length;
+
+ if ((addr + n) > MemorySize) {
+ n = MemorySize - addr;
+ stage = ERROR;
+ }
+
+ // we read an entire block
+ if (!(addr%BlockSize))
+ blockRead(page, addr/BlockSize);
+
+ // write data which are in RAM
+ writeNB(EPBULK_IN, &page[addr%BlockSize], n, MAX_PACKET_SIZE_EPBULK);
+
+ addr += n;
+ length -= n;
+
+ csw.DataResidue -= n;
+
+ if ( !length || (stage != PROCESS_CBW)) {
+ csw.Status = (stage == PROCESS_CBW) ? CSW_PASSED : CSW_FAILED;
+ sendCSW();
+ }
+}
+
+
+bool USBMSD::infoTransfer (void) {
+ uint32_t n;
+
+ // Logical Block Address of First Block
+ n = (cbw.CB[2] << 24) | (cbw.CB[3] << 16) | (cbw.CB[4] << 8) | (cbw.CB[5] << 0);
+
+ addr = n * BlockSize;
+
+ // Number of Blocks to transfer
+ switch (cbw.CB[0]) {
+ case READ10:
+ case WRITE10:
+ case VERIFY10:
+ n = (cbw.CB[7] << 8) | (cbw.CB[8] << 0);
+ break;
+
+ case READ12:
+ case WRITE12:
+ n = (cbw.CB[6] << 24) | (cbw.CB[7] << 16) | (cbw.CB[8] << 8) | (cbw.CB[9] << 0);
+ break;
+ }
+
+ length = n * BlockSize;
+
+ if (!cbw.DataLength) { // host requests no data
+ csw.Status = CSW_FAILED;
+ sendCSW();
+ return false;
+ }
+
+ if (cbw.DataLength != length) {
+ if ((cbw.Flags & 0x80) != 0) {
+ stallEndpoint(EPBULK_IN);
+ } else {
+ stallEndpoint(EPBULK_OUT);
+ }
+
+ csw.Status = CSW_FAILED;
+ sendCSW();
+ return false;
+ }
+
+ return true;
+}
+
+
+
+
+
+// Called in ISR context
+// Set configuration. Return false if the
+// configuration is not supported.
+bool USBMSD::USBCallback_setConfiguration(uint8_t configuration) {
+ if (configuration != DEFAULT_CONFIGURATION) {
+ return false;
+ }
+
+ // Configure endpoints > 0
+ addEndpoint(EPBULK_IN, MAX_PACKET_SIZE_EPBULK);
+ addEndpoint(EPBULK_OUT, MAX_PACKET_SIZE_EPBULK);
+
+ //activate readings
+ readStart(EPBULK_OUT, MAX_PACKET_SIZE_EPBULK);
+ return true;
+}
+
+
+uint8_t * USBMSD::stringIinterfaceDesc() {
+ static uint8_t stringIinterfaceDescriptor[] = {
+ 0x08, //bLength
+ STRING_DESCRIPTOR, //bDescriptorType 0x03
+ 'M',0,'S',0,'D',0 //bString iInterface - MSD
+ };
+ return stringIinterfaceDescriptor;
+}
+
+uint8_t * USBMSD::stringIproductDesc() {
+ static uint8_t stringIproductDescriptor[] = {
+ 0x12, //bLength
+ STRING_DESCRIPTOR, //bDescriptorType 0x03
+ 'M',0,'b',0,'e',0,'d',0,' ',0,'M',0,'S',0,'D',0 //bString iProduct - Mbed Audio
+ };
+ return stringIproductDescriptor;
+}
+
+
+uint8_t * USBMSD::configurationDesc() {
+ static uint8_t configDescriptor[] = {
+
+ // Configuration 1
+ 9, // bLength
+ 2, // bDescriptorType
+ LSB(9 + 9 + 7 + 7), // wTotalLength
+ MSB(9 + 9 + 7 + 7),
+ 0x01, // bNumInterfaces
+ 0x01, // bConfigurationValue: 0x01 is used to select this configuration
+ 0x00, // iConfiguration: no string to describe this configuration
+ 0xC0, // bmAttributes
+ 100, // bMaxPower, device power consumption is 100 mA
+
+ // Interface 0, Alternate Setting 0, MSC Class
+ 9, // bLength
+ 4, // bDescriptorType
+ 0x00, // bInterfaceNumber
+ 0x00, // bAlternateSetting
+ 0x02, // bNumEndpoints
+ 0x08, // bInterfaceClass
+ 0x06, // bInterfaceSubClass
+ 0x50, // bInterfaceProtocol
+ 0x04, // iInterface
+
+ // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
+ 7, // bLength
+ 5, // bDescriptorType
+ PHY_TO_DESC(EPBULK_IN), // bEndpointAddress
+ 0x02, // bmAttributes (0x02=bulk)
+ LSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (LSB)
+ MSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (MSB)
+ 0, // bInterval
+
+ // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
+ 7, // bLength
+ 5, // bDescriptorType
+ PHY_TO_DESC(EPBULK_OUT), // bEndpointAddress
+ 0x02, // bmAttributes (0x02=bulk)
+ LSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (LSB)
+ MSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (MSB)
+ 0 // bInterval
+ };
+ return configDescriptor;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBMSD/USBMSD.h Mon Nov 14 12:08:32 2011 +0000
@@ -0,0 +1,204 @@
+/* USBMSD.h */
+/* USB mass storage device example */
+/* Copyright (c) 2011 ARM Limited. All rights reserved. */
+
+/*
+* Guide to adapt this class to your storage chip:
+*
+*/
+
+#ifndef USBMSD_H
+#define USBMSD_H
+
+/* These headers are included for child class. */
+#include "USBEndpoints.h"
+#include "USBDescriptor.h"
+#include "USBDevice_Types.h"
+
+#include "USBDevice.h"
+
+#define DEFAULT_CONFIGURATION (1)
+
+
+// MSC Bulk-only Stage
+enum Stage {
+ READ_CBW, // wait a CBW
+ ERROR, // error
+ PROCESS_CBW, // process a CBW request
+ SEND_CSW, // send a CSW
+ WAIT_CSW, // wait that a CSW has been effectively sent
+};
+
+// Bulk-only CBW
+typedef __packed struct {
+ uint32_t Signature;
+ uint32_t Tag;
+ uint32_t DataLength;
+ uint8_t Flags;
+ uint8_t LUN;
+ uint8_t CBLength;
+ uint8_t CB[16];
+} CBW;
+
+// Bulk-only CSW
+typedef __packed struct {
+ uint32_t Signature;
+ uint32_t Tag;
+ uint32_t DataResidue;
+ uint8_t Status;
+} CSW;
+
+
+class USBMSD: public USBDevice {
+public:
+
+ /**
+ * Constructor
+ *
+ * @param vendor_id Your vendor_id
+ * @param product_id Your product_id
+ * @param product_release Your preoduct_release
+ */
+ USBMSD(uint16_t vendor_id = 0x0703, uint16_t product_id = 0x0104, uint16_t product_release = 0x0001);
+
+ /*
+ * read a block on a storage chip
+ *
+ * @param data pointer where will be stored read data
+ * @param block block number
+ * @returns 0 if successful
+ */
+ virtual int blockRead(uint8_t * data, uint16_t block){return 1;};
+
+ /*
+ * write a block on a storage chip
+ *
+ * @param data data to write
+ * @param block block number
+ * @returns 0 if successful
+ */
+ virtual int blockWrite(uint8_t * data, uint16_t block){return 1;};
+
+ /*
+ * Disk initilization
+ */
+ virtual int diskInit(){return -1;};
+
+ /*
+ * Return block size
+ *
+ * @returns size of a block
+ */
+ virtual uint16_t blockSize(){return 0;};
+
+ /*
+ * Return memory size
+ *
+ * @returns memory size
+ */
+ virtual uint32_t memorySize(){return 0;};
+
+ /*
+ * Connect the USB MSD device. Establish disk initialization before really connect the device.
+ *
+ * @returns
+ */
+ bool connect();
+
+
+protected:
+
+
+ /*
+ * Get number of logical unit - 1 (here 0)
+ *
+ * @returns Pointer containing the number of logical unit - 1
+ */
+ uint8_t * getMaxLUN();
+
+ /*
+ * Get string product descriptor
+ *
+ * @returns pointer to the string product descriptor
+ */
+ virtual uint8_t * stringIproductDesc();
+
+ /*
+ * Get string interface descriptor
+ *
+ * @returns pointer to the string interface descriptor
+ */
+ virtual uint8_t * stringIinterfaceDesc();
+
+ /*
+ * Get configuration descriptor
+ *
+ * @returns pointer to the configuration descriptor
+ */
+ virtual uint8_t * configurationDesc();
+
+ /*
+ * Callback called when a packet is received
+ */
+ virtual bool EP2_OUT_callback();
+
+ /*
+ * Callback called when a packet has been sent
+ */
+ virtual bool EP2_IN_callback();
+
+ /*
+ * Set configuration of device. Add endpoints
+ */
+ virtual bool USBCallback_setConfiguration(uint8_t configuration);
+
+ /*
+ * Callback called to process class specific requests
+ */
+ virtual bool USBCallback_request();
+
+
+private:
+ //state of the bulk-only state machine
+ Stage stage;
+
+ // current CBW
+ CBW cbw;
+
+ // CSW which will be sent
+ CSW csw;
+
+ // addr where will be read or written data
+ uint32_t addr;
+
+ // length of a reading or writing
+ uint32_t length;
+
+ // memory OK (after a memoryVerify)
+ bool memOK;
+
+ // cache in RAM before writing in memory. Useful also to read a block.
+ uint8_t * page;
+
+ uint16_t BlockSize;
+ uint32_t MemorySize;
+ uint16_t BlockCount;
+
+ void CBWDecode(uint8_t * buf, uint16_t size);
+ void sendCSW (void);
+ bool inquiryRequest (void);
+ bool write (uint8_t * buf, uint16_t size);
+ bool readFormatCapacity();
+ bool readCapacity (void);
+ bool infoTransfer (void);
+ void memoryRead (void);
+ bool modeSense6 (void);
+ void testUnitReady (void);
+ bool requestSense (void);
+ void memoryVerify (uint8_t * buf, uint16_t size);
+ void memoryWrite (uint8_t * buf, uint16_t size);
+ void reset();
+ void fail();
+};
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBMSD/USB_SDcard.cpp Mon Nov 14 12:08:32 2011 +0000
@@ -0,0 +1,374 @@
+/* mbed USB_SDcard Library, for accessing SD cards
+ * Copyright (c) 2008-2010, sford
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "USB_SDcard.h"
+
+#define SD_COMMAND_TIMEOUT 5000
+
+USB_SDcard::USB_SDcard(PinName mosi, PinName miso, PinName sclk, PinName cs):
+ _spi(mosi, miso, sclk), _cs(cs) {
+ _cs = 1;
+ USBMSD::connect();
+}
+
+#define R1_IDLE_STATE (1 << 0)
+#define R1_ERASE_RESET (1 << 1)
+#define R1_ILLEGAL_COMMAND (1 << 2)
+#define R1_COM_CRC_ERROR (1 << 3)
+#define R1_ERASE_SEQUENCE_ERROR (1 << 4)
+#define R1_ADDRESS_ERROR (1 << 5)
+#define R1_PARAMETER_ERROR (1 << 6)
+
+// Types
+// - v1.x Standard Capacity
+// - v2.x Standard Capacity
+// - v2.x High Capacity
+// - Not recognised as an SD Card
+
+#define SDCARD_FAIL 0
+#define SDCARD_V1 1
+#define SDCARD_V2 2
+#define SDCARD_V2HC 3
+
+int USB_SDcard::initialise_card() {
+ // Set to 100kHz for initialisation, and clock card with cs = 1
+ _spi.frequency(100000);
+ _cs = 1;
+ for(int i=0; i<16; i++) {
+ _spi.write(0xFF);
+ }
+
+ // send CMD0, should return with all zeros except IDLE STATE set (bit 0)
+ if(_cmd(0, 0) != R1_IDLE_STATE) {
+ fprintf(stderr, "No disk, or could not put SD card in to SPI idle state\n");
+ return SDCARD_FAIL;
+ }
+
+ // send CMD8 to determine whther it is ver 2.x
+ int r = _cmd8();
+ if(r == R1_IDLE_STATE) {
+ return initialise_card_v2();
+ } else if(r == (R1_IDLE_STATE | R1_ILLEGAL_COMMAND)) {
+ return initialise_card_v1();
+ } else {
+ fprintf(stderr, "Not in idle state after sending CMD8 (not an SD card?)\n");
+ return SDCARD_FAIL;
+ }
+}
+
+int USB_SDcard::initialise_card_v1() {
+ for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
+ _cmd(55, 0);
+ if(_cmd(41, 0) == 0) {
+ return SDCARD_V1;
+ }
+ }
+
+ fprintf(stderr, "Timeout waiting for v1.x card\n");
+ return SDCARD_FAIL;
+}
+
+int USB_SDcard::initialise_card_v2() {
+
+ for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
+ _cmd(55, 0);
+ if(_cmd(41, 0) == 0) {
+ _cmd58();
+ return SDCARD_V2;
+ }
+ }
+
+ fprintf(stderr, "Timeout waiting for v2.x card\n");
+ return SDCARD_FAIL;
+}
+
+uint32_t USB_SDcard::memorySize()
+{
+ return (uint32_t)capacity;
+}
+
+uint16_t USB_SDcard::blockSize()
+{
+ return (uint16_t)block_len;
+}
+
+int USB_SDcard::diskInit() {
+
+ int i = initialise_card();
+// printf("init card = %d\n", i);
+// printf("OK\n");
+
+ _sectors = _sd_sectors();
+
+ // Set block length to 512 (CMD16)
+ if(_cmd(16, 512) != 0) {
+ fprintf(stderr, "Set 512-byte block timed out\n");
+ return 1;
+ }
+
+ _spi.frequency(1000000); // Set to 1MHz for data transfer
+ return 0;
+}
+
+int USB_SDcard::blockWrite(uint8_t * buffer, uint16_t block_number) {
+ // set write address for single block (CMD24)
+ if(_cmd(24, block_number * 512) != 0) {
+ return 1;
+ }
+
+ // send the data block
+ _write((const char *)buffer, 512);
+ return 0;
+}
+
+int USB_SDcard::blockRead(uint8_t * buffer, uint16_t block_number) {
+ // set read address for single block (CMD17)
+ if(_cmd(17, block_number * 512) != 0) {
+ return 1;
+ }
+
+ // receive the data
+ _read((char *)buffer, 512);
+ return 0;
+}
+
+int USB_SDcard::disk_status() { return 0; }
+int USB_SDcard::disk_sync() { return 0; }
+int USB_SDcard::disk_sectors() { return _sectors; }
+
+// PRIVATE FUNCTIONS
+
+int USB_SDcard::_cmd(int cmd, int arg) {
+ _cs = 0;
+
+ // send a command
+ _spi.write(0x40 | cmd);
+ _spi.write(arg >> 24);
+ _spi.write(arg >> 16);
+ _spi.write(arg >> 8);
+ _spi.write(arg >> 0);
+ _spi.write(0x95);
+
+ // wait for the repsonse (response[7] == 0)
+ for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
+ int response = _spi.write(0xFF);
+ if(!(response & 0x80)) {
+ _cs = 1;
+ _spi.write(0xFF);
+ return response;
+ }
+ }
+ _cs = 1;
+ _spi.write(0xFF);
+ return -1; // timeout
+}
+int USB_SDcard::_cmdx(int cmd, int arg) {
+ _cs = 0;
+
+ // send a command
+ _spi.write(0x40 | cmd);
+ _spi.write(arg >> 24);
+ _spi.write(arg >> 16);
+ _spi.write(arg >> 8);
+ _spi.write(arg >> 0);
+ _spi.write(0x95);
+
+ // wait for the repsonse (response[7] == 0)
+ for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
+ int response = _spi.write(0xFF);
+ if(!(response & 0x80)) {
+ return response;
+ }
+ }
+ _cs = 1;
+ _spi.write(0xFF);
+ return -1; // timeout
+}
+
+
+int USB_SDcard::_cmd58() {
+ _cs = 0;
+ int arg = 0;
+
+ // send a command
+ _spi.write(0x40 | 58);
+ _spi.write(arg >> 24);
+ _spi.write(arg >> 16);
+ _spi.write(arg >> 8);
+ _spi.write(arg >> 0);
+ _spi.write(0x95);
+
+ // wait for the repsonse (response[7] == 0)
+ for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
+ int response = _spi.write(0xFF);
+ if(!(response & 0x80)) {
+ int ocr = _spi.write(0xFF) << 24;
+ ocr |= _spi.write(0xFF) << 16;
+ ocr |= _spi.write(0xFF) << 8;
+ ocr |= _spi.write(0xFF) << 0;
+// printf("OCR = 0x%08X\n", ocr);
+ _cs = 1;
+ _spi.write(0xFF);
+ return response;
+ }
+ }
+ _cs = 1;
+ _spi.write(0xFF);
+ return -1; // timeout
+}
+
+int USB_SDcard::_cmd8() {
+ _cs = 0;
+
+ // send a command
+ _spi.write(0x40 | 8); // CMD8
+ _spi.write(0x00); // reserved
+ _spi.write(0x00); // reserved
+ _spi.write(0x01); // 3.3v
+ _spi.write(0xAA); // check pattern
+ _spi.write(0x87); // crc
+
+ // wait for the repsonse (response[7] == 0)
+ for(int i=0; i<SD_COMMAND_TIMEOUT * 1000; i++) {
+ char response[5];
+ response[0] = _spi.write(0xFF);
+ if(!(response[0] & 0x80)) {
+ for(int j=1; j<5; j++) {
+ response[i] = _spi.write(0xFF);
+ }
+ _cs = 1;
+ _spi.write(0xFF);
+ return response[0];
+ }
+ }
+ _cs = 1;
+ _spi.write(0xFF);
+ return -1; // timeout
+}
+
+int USB_SDcard::_read(char *buffer, int length) {
+ _cs = 0;
+
+ // read until start byte (0xFF)
+ while(_spi.write(0xFF) != 0xFE);
+
+ // read data
+ for(int i=0; i<length; i++) {
+ buffer[i] = _spi.write(0xFF);
+ }
+ _spi.write(0xFF); // checksum
+ _spi.write(0xFF);
+
+ _cs = 1;
+ _spi.write(0xFF);
+ return 0;
+}
+
+int USB_SDcard::_write(const char *buffer, int length) {
+ _cs = 0;
+
+ // indicate start of block
+ _spi.write(0xFE);
+
+ // write the data
+ for(int i=0; i<length; i++) {
+ _spi.write(buffer[i]);
+ }
+
+ // write the checksum
+ _spi.write(0xFF);
+ _spi.write(0xFF);
+
+ // check the repsonse token
+ if((_spi.write(0xFF) & 0x1F) != 0x05) {
+ _cs = 1;
+ _spi.write(0xFF);
+ return 1;
+ }
+
+ // wait for write to finish
+ while(_spi.write(0xFF) == 0);
+
+ _cs = 1;
+ _spi.write(0xFF);
+ return 0;
+}
+
+static int ext_bits(char *data, int msb, int lsb) {
+ int bits = 0;
+ int size = 1 + msb - lsb;
+ for(int i=0; i<size; i++) {
+ int position = lsb + i;
+ int byte = 15 - (position >> 3);
+ int bit = position & 0x7;
+ int value = (data[byte] >> bit) & 1;
+ bits |= value << i;
+ }
+ return bits;
+}
+
+int USB_SDcard::_sd_sectors() {
+
+ // CMD9, Response R2 (R1 byte + 16-byte block read)
+ if(_cmdx(9, 0) != 0) {
+ fprintf(stderr, "Didn't get a response from the disk\n");
+ return 0;
+ }
+
+ char csd[16];
+ if(_read(csd, 16) != 0) {
+ fprintf(stderr, "Couldn't read csd response from disk\n");
+ return 0;
+ }
+
+ // csd_structure : csd[127:126]
+ // c_size : csd[73:62]
+ // c_size_mult : csd[49:47]
+ // read_bl_len : csd[83:80] - the *maximum* read block length
+
+ int csd_structure = ext_bits(csd, 127, 126);
+ int c_size = ext_bits(csd, 73, 62);
+ int c_size_mult = ext_bits(csd, 49, 47);
+ int read_bl_len = ext_bits(csd, 83, 80);
+
+// printf("CSD_STRUCT = %d\n", csd_structure);
+
+ if(csd_structure != 0) {
+ fprintf(stderr, "This disk tastes funny! I only know about type 0 CSD structures\n");
+ return 0;
+ }
+
+ // memory capacity = BLOCKNR * BLOCK_LEN
+ // where
+ // BLOCKNR = (C_SIZE+1) * MULT
+ // MULT = 2^(C_SIZE_MULT+2) (C_SIZE_MULT < 8)
+ // BLOCK_LEN = 2^READ_BL_LEN, (READ_BL_LEN < 12)
+
+ block_len = 1 << read_bl_len;
+ int mult = 1 << (c_size_mult + 2);
+ int blocknr = (c_size + 1) * mult;
+ capacity = blocknr * block_len;
+
+ int blocks = capacity / 512;
+
+ return blocks;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBMSD/USB_SDcard.h Mon Nov 14 12:08:32 2011 +0000
@@ -0,0 +1,87 @@
+/* mbed USB_SDcard Library, for accessing SD cards
+ * Copyright (c) 2008-2010, sford
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef USB_SDCARD_H
+#define USB_SDCARD_H
+
+#include "mbed.h"
+#include "USBMSD.h"
+
+class USB_SDcard : public USBMSD {
+public:
+
+ /** Create the File System for accessing an SD Card using SPI
+ *
+ * @param mosi SPI mosi pin connected to SD Card
+ * @param miso SPI miso pin conencted to SD Card
+ * @param sclk SPI sclk pin connected to SD Card
+ * @param cs DigitalOut pin used as SD Card chip select
+ */
+ USB_SDcard(PinName mosi = p5, PinName miso = p6, PinName sclk = p7, PinName cs = p8);
+
+ /*
+ * read a block on a storage chip
+ *
+ * @param data pointer where will be stored read data
+ * @param block block number
+ * @returns 0 if successful
+ */
+ virtual int blockRead(uint8_t * data, uint16_t block);
+
+ /*
+ * write a block on a storage chip
+ *
+ * @param data data to write
+ * @param block block number
+ * @returns 0 if successful
+ */
+ virtual int blockWrite(uint8_t * data, uint16_t block);
+
+ virtual int diskInit();
+ virtual uint16_t blockSize();
+ virtual uint32_t memorySize();
+
+protected:
+
+ int disk_status();
+ int disk_sync();
+ int disk_sectors();
+ int _cmd(int cmd, int arg);
+ int _cmdx(int cmd, int arg);
+ int _cmd8();
+ int _cmd58();
+ int initialise_card();
+ int initialise_card_v1();
+ int initialise_card_v2();
+
+ int _read(char *buffer, int length);
+ int _write(const char *buffer, int length);
+ int _sd_sectors();
+ int _sectors;
+ int capacity;
+ int block_len;
+
+ SPI _spi;
+ DigitalOut _cs;
+};
+
+#endif
--- a/main.cpp Mon Nov 14 10:00:07 2011 +0000
+++ b/main.cpp Mon Nov 14 12:08:32 2011 +0000
@@ -1,8 +1,19 @@
#include "mbed.h"
#include "USB_SDcard.h"
+#include "SDFileSystem.h"
USB_SDcard sd;
+SDFileSystem sd1(p5, p6, p7, p8, "sd");
int main() {
+ mkdir("/sd/mydir", 0777);
+
+ FILE *fp = fopen("/sd/mydir/sdtest.txt", "w");
+ if(fp == NULL) {
+ error("Could not open file for write\n");
+ }
+ fprintf(fp, "Hello fun SD Card World!");
+ fclose(fp);
+
while(1);
}
Samuel Mokrani