-
-
Save Ziul/3956699 to your computer and use it in GitHub Desktop.
msp430 Petit FatFile System sample
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*----------------------------------------------------------------------- | |
/ PFF - Low level disk interface modlue include file (C)ChaN, 2009 | |
/-----------------------------------------------------------------------*/ | |
#ifndef _DISKIO | |
#include "integer.h" | |
/* Status of Disk Functions */ | |
typedef BYTE DSTATUS; | |
/* Results of Disk Functions */ | |
typedef enum { | |
RES_OK = 0, /* 0: Function succeeded */ | |
RES_ERROR, /* 1: Disk error */ | |
RES_NOTRDY, /* 2: Not ready */ | |
RES_PARERR /* 3: Invalid parameter */ | |
} DRESULT; | |
/*---------------------------------------*/ | |
/* Prototypes for disk control functions */ | |
DRESULT disk_initialize(void); | |
DRESULT disk_readp(BYTE*, DWORD, WORD, WORD); | |
DRESULT disk_writep(const BYTE*, DWORD); | |
#define STA_NOINIT 0x01 /* Drive not initialized */ | |
#define STA_NODISK 0x02 /* No medium in the drive */ | |
/* Card type flags (CardType) */ | |
#define CT_MMC 0x01 /* MMC ver 3 */ | |
#define CT_SD1 0x02 /* SD ver 1 */ | |
#define CT_SD2 0x04 /* SD ver 2 */ | |
#define CT_SDC (CT_SD1|CT_SD2) /* SD */ | |
#define CT_BLOCK 0x08 /* Block addressing */ | |
#define _DISKIO | |
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*-------------------------------------------*/ | |
/* 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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*---------------------------------------------------------------*/ | |
/* Petit FAT file system module test program R0.02 (C)ChaN, 2009 */ | |
/*---------------------------------------------------------------*/ | |
/*--------------------------------------------------------------- | |
* 04-06-2012 rkimball - Initial msp430g2553 implementation done | |
* for msp430-gcc using USCI UART(USCA0) and SPI(USCB0) | |
*--------------------------------------------------------------- | |
*/ | |
#include <msp430.h> | |
#include <stdio.h> | |
#include <stdint.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include "spi.h" | |
#include "diskio.h" | |
#include "pff.h" | |
#include "serial.h" | |
const unsigned long SMCLK_FREQ = 16000000; | |
const unsigned long BAUD_RATE = 9600; | |
/*---------------------------------------------------------------*/ | |
/* Work Area */ | |
/*---------------------------------------------------------------*/ | |
char Line[128]; | |
static | |
void put_rc(FRESULT rc) { | |
const char *p; | |
static const char str[] = | |
"OK\0" "DISK_ERR\0" "NOT_READY\0" "NO_FILE\0" "NO_PATH\0" | |
"NOT_OPENED\0" "NOT_ENABLED\0" "NO_FILE_SYSTEM\0"; | |
FRESULT i; | |
for (p = str, i = 0; i != rc && *p; i++) { | |
while (*p++) | |
; | |
} | |
printf("rc=%lu FR_%s\n", (long int) rc, p); | |
} | |
static | |
void put_drc(long int res) { | |
printf("rc=%lu\n", res); | |
} | |
static | |
void get_line(char *buff, BYTE len) { | |
BYTE c, i; | |
i = 0; | |
for (;;) { | |
c = getchar(); | |
if (c == '\r') | |
break; | |
if ((c == '\b') && i) | |
i--; | |
if ((c >= ' ') && (i < len - 1)) | |
buff[i++] = c; | |
} | |
buff[i] = 0; | |
putchar('\n'); | |
} | |
#if _USE_READ | |
static | |
void put_dump(const BYTE* buff, /* Pointer to the byte array to be dumped */ | |
DWORD addr, /* Heading address value */ | |
WORD len /* Number of bytes to be dumped */ | |
) { | |
int n; | |
printf("%08lX ", addr); /* address */ | |
for (n = 0; n < len; n++) { /* data (hexdecimal) */ | |
printf(" %02X", buff[n]); | |
} | |
printf(" "); | |
for (n = 0; n < len; n++) { /* data (ascii) */ | |
putchar(((buff[n] < 0x20) || (buff[n] >= 0x7F)) ? '.' : buff[n]); | |
; | |
} | |
putchar('\n'); | |
} | |
#endif | |
/** | |
* setup() - configure DCO clock system, UART and SPI. | |
*/ | |
void setup() { | |
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer | |
DCOCTL = 0x00; // Set DCOCLK to 16MHz | |
BCSCTL1 = CALBC1_16MHZ; | |
DCOCTL = CALDCO_16MHZ; | |
//DCOCTL += 6; // the default calibrated clock on my MCU is a little slow | |
P1DIR |= BIT4; | |
P1SEL |= BIT4; // output SMCLK for measurement on P1.4 | |
/* | |
* Configure USCI serial TX on P1.2, RX on P1.1. You need to change | |
* turn your Launchpad TX/RX jumpers 90 degrees from the factory settings. | |
*/ | |
serial_initialize((SMCLK_FREQ + (BAUD_RATE >> 1)) / BAUD_RATE); | |
/* | |
* configure USCI SPI B | |
*/ | |
spi_initialize(); | |
} | |
int main(void) { | |
char *ptr; | |
FRESULT res; | |
#if _USE_READ | |
WORD s1, s2; | |
DWORD ofs; | |
#endif | |
#if _USE_DIR | |
DIR dir; /* Directory object */ | |
FILINFO fno; /* File information */ | |
#endif | |
#if _USE_WRITE | |
WORD bw; | |
WORD n = 0; | |
#endif | |
#if _USE_LSEEK | |
DWORD p1; | |
#endif | |
FATFS fs; /* File system object */ | |
setup(); | |
__enable_interrupt(); // don't really need this we do blocking reads | |
printf("\nPFF test monitor\n"); | |
for (;;) { | |
printf("> "); | |
get_line(Line, sizeof(Line)); | |
ptr = Line; | |
switch (*ptr++) { | |
case 'd': | |
switch (*ptr++) { | |
case 'i': /* di - Initialize physical drive */ | |
printf("Disk Initialize...\n"); | |
res = disk_initialize(); | |
put_drc(res); | |
break; | |
} | |
break; | |
case 'f': | |
switch (*ptr++) { | |
case 'i': /* fi - Mount the volume */ | |
put_rc(pf_mount(&fs)); | |
break; | |
case 'o': /* fo <file> - Open a file */ | |
while (*ptr == ' ') | |
ptr++; | |
put_rc(pf_open(ptr)); | |
break; | |
#if _USE_READ | |
case 'd': /* fd - Read the file 128 bytes and dump it */ | |
ofs = fs.fptr; | |
res = pf_read(Line, sizeof(Line), &s1); | |
if (res != FR_OK) { | |
put_rc(res); | |
break; | |
} | |
ptr = Line; | |
while (s1) { | |
s2 = (s1 >= 16) ? 16 : s1; | |
s1 -= s2; | |
put_dump((BYTE*) ptr, ofs, s2); | |
ptr += 16; | |
ofs += 16; | |
} | |
break; | |
case 't': /* ft - Type the file data via dreadp function */ | |
do { | |
res = pf_read(0, 32768, &s1); | |
if (res != FR_OK) { | |
put_rc(res); | |
break; | |
} | |
} while (s1 == 32768); | |
break; | |
#endif | |
#if _USE_LSEEK | |
case 'e': /* fe - Move file pointer of the file */ | |
p1 = atol(ptr); | |
res = pf_lseek(p1); | |
put_rc(res); | |
if (res == FR_OK) { | |
printf("fptr = %lu(0x%lX)\n", fs.fptr, fs.fptr); | |
} | |
break; | |
#endif | |
#if _USE_DIR | |
case 'l': /* fl [<path>] - Directory listing */ | |
while (*ptr == ' ') | |
ptr++; | |
res = pf_opendir(&dir, ptr); | |
if (res) { | |
put_rc(res); | |
break; | |
} | |
s1 = 0; | |
for (;;) { | |
res = pf_readdir(&dir, &fno); | |
if (res != FR_OK) { | |
put_rc(res); | |
break; | |
} | |
if (!fno.fname[0]) | |
break; | |
if (fno.fattrib & AM_DIR) | |
printf(" <DIR> %s\n", fno.fname); | |
else | |
printf("%9lu %s\n", fno.fsize, fno.fname); | |
s1++; | |
} | |
printf("%u item(s)\n", s1); | |
break; | |
#endif | |
#if _USE_WRITE | |
case 'p': /* fp - Write console input to the file */ | |
printf( | |
"Enter lines to write. A blank line finalize the write operation.\n"); | |
for (;;) { | |
get_line(Line, sizeof(Line)); | |
if (!Line[0]) | |
break; | |
strcat(Line, "\r\n"); | |
res = pf_write(Line, strlen(Line), &bw); /* Write a line to the file */ | |
if (res) | |
break; | |
} | |
res = pf_write(0, 0, &bw); /* Finalize the write process */ | |
put_rc(res); | |
break; | |
case 'w': /* fw - write into write.txt, see write limitation in Petit FatFS documentation */ | |
printf( | |
"\nTrying to open an existing file for writing (write.txt)...\n"); | |
res = pf_open("WRITE.TXT"); | |
if (res != FR_OK) { | |
put_rc(res); | |
} else { | |
printf("Writing 100 lines of text data\n"); | |
do { | |
ltoa(++n, Line, 10); | |
strcat(Line, | |
" The quick brown fox jumps over the lazy dog. 1234567890\r\n"); | |
res = pf_write(Line, strlen(Line), &bw); | |
if (res != FR_OK) { | |
put_rc(res); | |
break; | |
} | |
if (n & 0x10) { | |
printf("."); | |
} | |
} while (n < 100); | |
if (res == FR_OK) { | |
printf("\nFinalizing the file write process.\n"); | |
res = pf_write(0, 0, &bw); | |
if (res != FR_OK) | |
put_rc(res); | |
} | |
} | |
break; | |
#endif | |
} | |
break; | |
} /* end switch */ | |
} /* end for */ | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*-----------------------------------------------------------------------*/ | |
/* Low level disk I/O module skeleton for Petit FatFs (C)ChaN, 2009 */ | |
/*-----------------------------------------------------------------------*/ | |
/*-----------------------------------------------------------------------*/ | |
/* msp430 USCI support routines */ | |
/*-----------------------------------------------------------------------*/ | |
#include <msp430.h> | |
#include <stdint.h> | |
#include <stdio.h> | |
#include "diskio.h" | |
#include "pff.h" | |
#include "spi.h" | |
#define DELAY_100US() __delay_cycles(1600) /* ( 100us/(1/16Mhz) ) = 1600 ticks */ | |
#define SELECT() P2OUT &= ~BIT0 /* CS = L */ | |
#define DESELECT() P2OUT |= BIT0 /* CS = H */ | |
#define MMC_SEL !(P2OUT & BIT0) /* CS status (true:CS == L) */ | |
#define FORWARD(d) putchar(d) /* Data forwarding function (Console out in this example) */ | |
/* Definitions for MMC/SDC command */ | |
#define CMD0 (0x40+0) /* GO_IDLE_STATE */ | |
#define CMD1 (0x40+1) /* SEND_OP_COND (MMC) */ | |
#define ACMD41 (0xC0+41) /* SEND_OP_COND (SDC) */ | |
#define CMD8 (0x40+8) /* SEND_IF_COND */ | |
#define CMD16 (0x40+16) /* SET_BLOCKLEN */ | |
#define CMD17 (0x40+17) /* READ_SINGLE_BLOCK */ | |
#define CMD24 (0x40+24) /* WRITE_BLOCK */ | |
#define CMD55 (0x40+55) /* APP_CMD */ | |
#define CMD58 (0x40+58) /* READ_OCR */ | |
/* Card type flags (CardType) */ | |
#define CT_MMC 0x01 /* MMC ver 3 */ | |
#define CT_SD1 0x02 /* SD ver 1 */ | |
#define CT_SD2 0x04 /* SD ver 2 */ | |
#define CT_BLOCK 0x08 /* Block addressing */ | |
static BYTE CardType; | |
/*-----------------------------------------------------------------------*/ | |
/* Send a command packet to MMC */ | |
/*-----------------------------------------------------------------------*/ | |
static BYTE send_cmd(BYTE cmd, /* 1st byte (Start + Index) */ | |
DWORD arg /* Argument (32 bits) */ | |
) { | |
BYTE n, res; | |
if (cmd & 0x80) { /* ACMD<n> is the command sequense of CMD55-CMD<n> */ | |
cmd &= 0x7F; | |
res = send_cmd(CMD55, 0); | |
if (res > 1) | |
return res; | |
} | |
/* Select the card */DESELECT(); | |
spi_receive(); | |
SELECT(); | |
spi_receive(); | |
/* Send a command packet */ | |
spi_send((BYTE) cmd); /* Start + Command index */ | |
spi_send((BYTE) (arg >> 24)); /* Argument[31..24] */ | |
spi_send((BYTE) (arg >> 16)); /* Argument[23..16] */ | |
spi_send((BYTE) (arg >> 8)); /* Argument[15..8] */ | |
spi_send((BYTE) arg); /* Argument[7..0] */ | |
n = 0x01; /* Dummy CRC + Stop */ | |
if (cmd == CMD0) | |
n = 0x95; /* Valid CRC for CMD0(0) */ | |
if (cmd == CMD8) | |
n = 0x87; /* Valid CRC for CMD8(0x1AA) */ | |
spi_send(n); | |
/* Receive a command response */ | |
n = 10; /* Wait for a valid response in timeout of 10 attempts */ | |
do { | |
res = spi_receive(); | |
} while ((res & 0x80) && --n); | |
return res; /* Return with the response value */ | |
} | |
/*-----------------------------------------------------------------------*/ | |
/* Initialize Disk Drive */ | |
/*-----------------------------------------------------------------------*/ | |
DRESULT disk_initialize(void) { | |
BYTE n, cmd, ty, ocr[4]; | |
UINT tmr; | |
#if _USE_WRITE | |
if (CardType && MMC_SEL) | |
disk_writep(0, 0); /* Finalize write process if it is in progress */ | |
#endif | |
spi_set_divisor(SPI_250kHz); | |
DESELECT(); | |
for (n = 10; n; n--) | |
spi_receive(); /* 80 dummy clocks with CS=H */ | |
ty = 0; | |
if (send_cmd(CMD0, 0) == 1) { /* Enter Idle state */ | |
if (send_cmd(CMD8, 0x1AA) == 1) { /* SDv2 */ | |
for (n = 0; n < 4; n++) | |
ocr[n] = spi_receive(); /* Get trailing return value of R7 resp */ | |
if (ocr[2] == 0x01 && ocr[3] == 0xAA) { /* The card can work at vdd range of 2.7-3.6V */ | |
for (tmr = 10000; tmr && send_cmd(ACMD41, 1UL << 30); tmr--) | |
DELAY_100US(); /* Wait for leaving idle state (ACMD41 with HCS bit) */ | |
if (tmr && send_cmd(CMD58, 0) == 0) { /* Check CCS bit in the OCR */ | |
for (n = 0; n < 4; n++) | |
ocr[n] = spi_receive(); | |
ty = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2; /* SDv2 (HC or SC) */ | |
} | |
} | |
} else { /* SDv1 or MMCv3 */ | |
if (send_cmd(ACMD41, 0) <= 1) { | |
ty = CT_SD1; | |
cmd = ACMD41; /* SDv1 */ | |
} else { | |
ty = CT_MMC; | |
cmd = CMD1; /* MMCv3 */ | |
} | |
for (tmr = 10000; tmr && send_cmd(cmd, 0); tmr--) | |
DELAY_100US(); /* Wait for leaving idle state */ | |
if (!tmr || send_cmd(CMD16, 512) != 0) /* Set R/W block length to 512 */ | |
ty = 0; | |
} | |
} | |
CardType = ty; | |
spi_set_divisor(SPI_DEFAULT_SPEED); | |
DESELECT(); | |
spi_receive(); | |
return ty ? 0 : STA_NOINIT; | |
} | |
/*-----------------------------------------------------------------------*/ | |
/* Read partial sector */ | |
/*-----------------------------------------------------------------------*/ | |
DRESULT disk_readp(BYTE *buff, /* Pointer to the read buffer (NULL:Read bytes are forwarded to the stream) */ | |
DWORD lba, /* Sector number (LBA) */ | |
WORD ofs, /* Byte offset to read from (0..511) */ | |
WORD cnt /* Number of bytes to read (ofs + cnt mus be <= 512) */ | |
) { | |
DRESULT res; | |
BYTE rc; | |
WORD bc; | |
if (!(CardType & CT_BLOCK)) | |
lba *= 512; /* Convert to byte address if needed */ | |
res = RES_ERROR; | |
if (send_cmd(CMD17, lba) == 0) { /* READ_SINGLE_BLOCK */ | |
bc = 40000; | |
do { /* Wait for data packet */ | |
rc = spi_receive(); | |
} while (rc == 0xFF && --bc); | |
if (rc == 0xFE) { /* A data packet arrived */ | |
bc = 514 - ofs - cnt; | |
/* Skip leading bytes */ | |
if (ofs) { | |
do | |
spi_receive(); | |
while (--ofs); | |
} | |
/* Receive a part of the sector */ | |
if (buff) { /* Store data to the memory */ | |
do { | |
*buff++ = spi_receive(); | |
} while (--cnt); | |
} else { /* Forward data to the outgoing stream (depends on the project) */ | |
do { | |
FORWARD(spi_receive()); | |
} while (--cnt); | |
} | |
/* Skip trailing bytes and CRC */ | |
do | |
spi_receive(); | |
while (--bc); | |
res = RES_OK; | |
} | |
} | |
DESELECT(); | |
spi_receive(); | |
return res; | |
} | |
/*-----------------------------------------------------------------------*/ | |
/* Write partial sector */ | |
/*-----------------------------------------------------------------------*/ | |
#if _USE_WRITE | |
DRESULT disk_writep(const BYTE *buff, /* Pointer to the bytes to be written (NULL:Initiate/Finalize sector write) */ | |
DWORD sa /* Number of bytes to send, Sector number (LBA) or zero */ | |
) { | |
DRESULT res; | |
WORD bc; | |
static WORD wc; | |
res = RES_ERROR; | |
if (buff) { /* Send data bytes */ | |
bc = (WORD) sa; | |
while (bc && wc) { /* Send data bytes to the card */ | |
spi_send(*buff++); | |
wc--; | |
bc--; | |
} | |
res = RES_OK; | |
} else { | |
if (sa) { /* Initiate sector write process */ | |
if (!(CardType & CT_BLOCK)) | |
sa *= 512; /* Convert to byte address if needed */ | |
if (send_cmd(CMD24, sa) == 0) { /* WRITE_SINGLE_BLOCK */ | |
spi_send(0xFF); | |
spi_send(0xFE); /* Data block header */ | |
wc = 512; /* Set byte counter */ | |
res = RES_OK; | |
} | |
} else { /* Finalize sector write process */ | |
bc = wc + 2; | |
while (bc--) | |
spi_send(0); /* Fill left bytes and CRC with zeros */ | |
if ((spi_receive() & 0x1F) == 0x05) { /* Receive data resp and wait for end of write process in timeout of 500ms */ | |
for (bc = 5000; spi_receive() != 0xFF && bc; bc--) | |
DELAY_100US(); /* Wait ready */ | |
if (bc) | |
res = RES_OK; | |
} | |
DESELECT(); | |
spi_receive(); | |
} | |
} | |
return res; | |
} | |
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*----------------------------------------------------------------------------/ | |
/ Petit FatFs - FAT file system module R0.02a (C)ChaN, 2010 | |
/-----------------------------------------------------------------------------/ | |
/ Petit FatFs module is an open source software to implement FAT file system to | |
/ small embedded systems. This is a free software and is opened for education, | |
/ research and commercial developments under license policy of following trems. | |
/ | |
/ Copyright (C) 2010, ChaN, all right reserved. | |
/ | |
/ * The Petit FatFs module is a free software and there is NO WARRANTY. | |
/ * No restriction on use. You can use, modify and redistribute it for | |
/ personal, non-profit or commercial use UNDER YOUR RESPONSIBILITY. | |
/ * Redistributions of source code must retain the above copyright notice. | |
/ | |
/-----------------------------------------------------------------------------/ | |
/ Jun 15,'09 R0.01a First release. (Branched from FatFs R0.07b.) | |
/ | |
/ Dec 14,'09 R0.02 Added multiple code page support. | |
/ Added write funciton. | |
/ Changed stream read mode interface. | |
/ Dec 07,'10 R0.02a Added some configuration options. | |
/ Fixed fails to open objects with DBCS character. | |
/----------------------------------------------------------------------------*/ | |
#include "pff.h" /* Petit FatFs configurations and declarations */ | |
#include "diskio.h" /* Declarations of low level disk I/O functions */ | |
/*-------------------------------------------------------------------------- | |
Module Private Definitions | |
---------------------------------------------------------------------------*/ | |
#if _FS_FAT32 | |
#define LD_CLUST(dir) (((DWORD)LD_WORD(dir+DIR_FstClusHI)<<16) | LD_WORD(dir+DIR_FstClusLO)) | |
#else | |
#define LD_CLUST(dir) LD_WORD(dir+DIR_FstClusLO) | |
#endif | |
/*--------------------------------------------------------*/ | |
/* 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) */ | |
#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')) | |
#if _DF1S /* DBCS configuration */ | |
#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 /* SBCS configuration */ | |
#define IsDBCS1(c) 0 | |
#define IsDBCS2(c) 0 | |
#endif /* _DF1S */ | |
/* FatFs refers the members in the FAT structures with byte offset instead | |
/ of structure member because there are incompatibility of the packing option | |
/ between various compilers. */ | |
#define BS_jmpBoot 0 | |
#define BS_OEMName 3 | |
#define BPB_BytsPerSec 11 | |
#define BPB_SecPerClus 13 | |
#define BPB_RsvdSecCnt 14 | |
#define BPB_NumFATs 16 | |
#define BPB_RootEntCnt 17 | |
#define BPB_TotSec16 19 | |
#define BPB_Media 21 | |
#define BPB_FATSz16 22 | |
#define BPB_SecPerTrk 24 | |
#define BPB_NumHeads 26 | |
#define BPB_HiddSec 28 | |
#define BPB_TotSec32 32 | |
#define BS_55AA 510 | |
#define BS_DrvNum 36 | |
#define BS_BootSig 38 | |
#define BS_VolID 39 | |
#define BS_VolLab 43 | |
#define BS_FilSysType 54 | |
#define BPB_FATSz32 36 | |
#define BPB_ExtFlags 40 | |
#define BPB_FSVer 42 | |
#define BPB_RootClus 44 | |
#define BPB_FSInfo 48 | |
#define BPB_BkBootSec 50 | |
#define BS_DrvNum32 64 | |
#define BS_BootSig32 66 | |
#define BS_VolID32 67 | |
#define BS_VolLab32 71 | |
#define BS_FilSysType32 82 | |
#define MBR_Table 446 | |
#define DIR_Name 0 | |
#define DIR_Attr 11 | |
#define DIR_NTres 12 | |
#define DIR_CrtTime 14 | |
#define DIR_CrtDate 16 | |
#define DIR_FstClusHI 20 | |
#define DIR_WrtTime 22 | |
#define DIR_WrtDate 24 | |
#define DIR_FstClusLO 26 | |
#define DIR_FileSize 28 | |
/*-------------------------------------------------------------------------- | |
Private Functions | |
---------------------------------------------------------------------------*/ | |
static | |
FATFS *FatFs; /* Pointer to the file system object (logical drive) */ | |
/* Fill memory */ | |
static | |
void mem_set (void* dst, int val, int cnt) { | |
char *d = (char*)dst; | |
while (cnt--) *d++ = (char)val; | |
} | |
/* Compare memory to memory */ | |
static | |
int mem_cmp (const void* dst, const void* src, int cnt) { | |
const char *d = (const char *)dst, *s = (const char *)src; | |
int r = 0; | |
while (cnt-- && (r = *d++ - *s++) == 0) ; | |
return r; | |
} | |
/*-----------------------------------------------------------------------*/ | |
/* FAT access - Read value of a FAT entry */ | |
/*-----------------------------------------------------------------------*/ | |
static | |
CLUST get_fat ( /* 1:IO error, Else:Cluster status */ | |
CLUST clst /* Cluster# to get the link information */ | |
) | |
{ | |
#if _FS_FAT12 | |
WORD wc, bc, ofs; | |
#endif | |
BYTE buf[4]; | |
FATFS *fs = FatFs; | |
if (clst < 2 || clst >= fs->n_fatent) /* Range check */ | |
return 1; | |
switch (fs->fs_type) { | |
#if _FS_FAT12 | |
case FS_FAT12 : | |
bc = (WORD)clst; bc += bc / 2; | |
ofs = bc % 512; bc /= 512; | |
if (ofs != 511) { | |
if (disk_readp(buf, fs->fatbase + bc, ofs, 2)) break; | |
} else { | |
if (disk_readp(buf, fs->fatbase + bc, 511, 1)) break; | |
if (disk_readp(buf+1, fs->fatbase + bc + 1, 0, 1)) break; | |
} | |
wc = LD_WORD(buf); | |
return (clst & 1) ? (wc >> 4) : (wc & 0xFFF); | |
#endif | |
case FS_FAT16 : | |
if (disk_readp(buf, fs->fatbase + clst / 256, (WORD)(((WORD)clst % 256) * 2), 2)) break; | |
return LD_WORD(buf); | |
#if _FS_FAT32 | |
case FS_FAT32 : | |
if (disk_readp(buf, fs->fatbase + clst / 128, (WORD)(((WORD)clst % 128) * 4), 4)) break; | |
return LD_DWORD(buf) & 0x0FFFFFFF; | |
#endif | |
} | |
return 1; /* An error occured at the disk I/O layer */ | |
} | |
/*-----------------------------------------------------------------------*/ | |
/* Get sector# from cluster# */ | |
/*-----------------------------------------------------------------------*/ | |
static | |
DWORD clust2sect ( /* !=0: Sector number, 0: Failed - invalid cluster# */ | |
CLUST clst /* Cluster# to be converted */ | |
) | |
{ | |
FATFS *fs = FatFs; | |
clst -= 2; | |
if (clst >= (fs->n_fatent - 2)) return 0; /* Invalid cluster# */ | |
return (DWORD)clst * fs->csize + fs->database; | |
} | |
/*-----------------------------------------------------------------------*/ | |
/* Directory handling - Rewind directory index */ | |
/*-----------------------------------------------------------------------*/ | |
static | |
FRESULT dir_rewind ( | |
DIR *dj /* Pointer to directory object */ | |
) | |
{ | |
CLUST clst; | |
FATFS *fs = FatFs; | |
dj->index = 0; | |
clst = dj->sclust; | |
if (clst == 1 || clst >= fs->n_fatent) /* Check start cluster range */ | |
return FR_DISK_ERR; | |
if (_FS_FAT32 && !clst && fs->fs_type == FS_FAT32) /* Replace cluster# 0 with root cluster# if in FAT32 */ | |
clst = (CLUST)fs->dirbase; | |
dj->clust = clst; /* Current cluster */ | |
dj->sect = clst ? clust2sect(clst) : fs->dirbase; /* Current sector */ | |
return FR_OK; /* Seek succeeded */ | |
} | |
/*-----------------------------------------------------------------------*/ | |
/* Directory handling - Move directory index next */ | |
/*-----------------------------------------------------------------------*/ | |
static | |
FRESULT dir_next ( /* FR_OK:Succeeded, FR_NO_FILE:End of table */ | |
DIR *dj /* Pointer to directory object */ | |
) | |
{ | |
CLUST clst; | |
WORD i; | |
FATFS *fs = FatFs; | |
i = dj->index + 1; | |
if (!i || !dj->sect) /* Report EOT when index has reached 65535 */ | |
return FR_NO_FILE; | |
if (!(i % 16)) { /* Sector changed? */ | |
dj->sect++; /* Next sector */ | |
if (dj->clust == 0) { /* Static table */ | |
if (i >= fs->n_rootdir) /* Report EOT when end of table */ | |
return FR_NO_FILE; | |
} | |
else { /* Dynamic table */ | |
if (((i / 16) & (fs->csize-1)) == 0) { /* Cluster changed? */ | |
clst = get_fat(dj->clust); /* Get next cluster */ | |
if (clst <= 1) return FR_DISK_ERR; | |
if (clst >= fs->n_fatent) /* When it reached end of dynamic table */ | |
return FR_NO_FILE; /* Report EOT */ | |
dj->clust = clst; /* Initialize data for new cluster */ | |
dj->sect = clust2sect(clst); | |
} | |
} | |
} | |
dj->index = i; | |
return FR_OK; | |
} | |
/*-----------------------------------------------------------------------*/ | |
/* Directory handling - Find an object in the directory */ | |
/*-----------------------------------------------------------------------*/ | |
static | |
FRESULT dir_find ( | |
DIR *dj, /* Pointer to the directory object linked to the file name */ | |
BYTE *dir /* 32-byte working buffer */ | |
) | |
{ | |
FRESULT res; | |
BYTE c; | |
res = dir_rewind(dj); /* Rewind directory object */ | |
if (res != FR_OK) return res; | |
do { | |
res = disk_readp(dir, dj->sect, (WORD)((dj->index % 16) * 32), 32) /* Read an entry */ | |
? FR_DISK_ERR : FR_OK; | |
if (res != FR_OK) break; | |
c = dir[DIR_Name]; /* First character */ | |
if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */ | |
if (!(dir[DIR_Attr] & AM_VOL) && !mem_cmp(dir, dj->fn, 11)) /* Is it a valid entry? */ | |
break; | |
res = dir_next(dj); /* Next entry */ | |
} while (res == FR_OK); | |
return res; | |
} | |
/*-----------------------------------------------------------------------*/ | |
/* Read an object from the directory */ | |
/*-----------------------------------------------------------------------*/ | |
#if _USE_DIR | |
static | |
FRESULT dir_read ( | |
DIR *dj, /* Pointer to the directory object to store read object name */ | |
BYTE *dir /* 32-byte working buffer */ | |
) | |
{ | |
FRESULT res; | |
BYTE a, c; | |
res = FR_NO_FILE; | |
while (dj->sect) { | |
res = disk_readp(dir, dj->sect, (WORD)((dj->index % 16) * 32), 32) /* Read an entry */ | |
? FR_DISK_ERR : FR_OK; | |
if (res != FR_OK) break; | |
c = dir[DIR_Name]; | |
if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */ | |
a = dir[DIR_Attr] & AM_MASK; | |
if (c != 0xE5 && c != '.' && !(a & AM_VOL)) /* Is it a valid entry? */ | |
break; | |
res = dir_next(dj); /* Next entry */ | |
if (res != FR_OK) break; | |
} | |
if (res != FR_OK) dj->sect = 0; | |
return res; | |
} | |
#endif | |
/*-----------------------------------------------------------------------*/ | |
/* Pick a segment and create the object name in directory form */ | |
/*-----------------------------------------------------------------------*/ | |
#ifdef _EXCVT | |
static const BYTE cvt[] = _EXCVT; | |
#endif | |
static | |
FRESULT create_name ( | |
DIR *dj, /* Pointer to the directory object */ | |
const char **path /* Pointer to pointer to the segment in the path string */ | |
) | |
{ | |
BYTE c, d, ni, si, i, *sfn; | |
const char *p; | |
/* Create file name in directory form */ | |
sfn = dj->fn; | |
mem_set(sfn, ' ', 11); | |
si = i = 0; ni = 8; | |
p = *path; | |
for (;;) { | |
c = p[si++]; | |
if (c <= ' ' || c == '/') break; /* Break on end of segment */ | |
if (c == '.' || i >= ni) { | |
if (ni != 8 || c != '.') break; | |
i = 8; ni = 11; | |
continue; | |
} | |
#ifdef _EXCVT | |
if (c >= 0x80) /* To upper extended char (SBCS) */ | |
c = cvt[c - 0x80]; | |
#endif | |
if (IsDBCS1(c) && i < ni - 1) { /* DBC 1st byte? */ | |
d = p[si++]; /* Get 2nd byte */ | |
sfn[i++] = c; | |
sfn[i++] = d; | |
} else { /* Single byte code */ | |
if (IsLower(c)) c -= 0x20; /* toupper */ | |
sfn[i++] = c; | |
} | |
} | |
*path = &p[si]; /* Rerurn pointer to the next segment */ | |
sfn[11] = (c <= ' ') ? 1 : 0; /* Set last segment flag if end of path */ | |
return FR_OK; | |
} | |
/*-----------------------------------------------------------------------*/ | |
/* Get file information from directory entry */ | |
/*-----------------------------------------------------------------------*/ | |
#if _USE_DIR | |
static | |
void get_fileinfo ( /* No return code */ | |
DIR *dj, /* Pointer to the directory object */ | |
BYTE *dir, /* 32-byte working buffer */ | |
FILINFO *fno /* Pointer to store the file information */ | |
) | |
{ | |
BYTE i, c; | |
char *p; | |
p = fno->fname; | |
if (dj->sect) { | |
for (i = 0; i < 8; i++) { /* Copy file name body */ | |
c = dir[i]; | |
if (c == ' ') break; | |
if (c == 0x05) c = 0xE5; | |
*p++ = c; | |
} | |
if (dir[8] != ' ') { /* Copy file name extension */ | |
*p++ = '.'; | |
for (i = 8; i < 11; i++) { | |
c = dir[i]; | |
if (c == ' ') break; | |
*p++ = c; | |
} | |
} | |
fno->fattrib = dir[DIR_Attr]; /* Attribute */ | |
fno->fsize = LD_DWORD(dir+DIR_FileSize); /* Size */ | |
fno->fdate = LD_WORD(dir+DIR_WrtDate); /* Date */ | |
fno->ftime = LD_WORD(dir+DIR_WrtTime); /* Time */ | |
} | |
*p = 0; | |
} | |
#endif /* _USE_DIR */ | |
/*-----------------------------------------------------------------------*/ | |
/* Follow a file path */ | |
/*-----------------------------------------------------------------------*/ | |
static | |
FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ | |
DIR *dj, /* Directory object to return last directory and found object */ | |
BYTE *dir, /* 32-byte working buffer */ | |
const char *path /* Full-path string to find a file or directory */ | |
) | |
{ | |
FRESULT res; | |
while (*path == ' ') path++; /* Skip leading spaces */ | |
if (*path == '/') path++; /* Strip heading separator */ | |
dj->sclust = 0; /* Set start directory (always root dir) */ | |
if ((BYTE)*path <= ' ') { /* Null path means the root directory */ | |
res = dir_rewind(dj); | |
dir[0] = 0; | |
} else { /* Follow path */ | |
for (;;) { | |
res = create_name(dj, &path); /* Get a segment */ | |
if (res != FR_OK) break; | |
res = dir_find(dj, dir); /* Find it */ | |
if (res != FR_OK) { /* Could not find the object */ | |
if (res == FR_NO_FILE && !*(dj->fn+11)) | |
res = FR_NO_PATH; | |
break; | |
} | |
if (*(dj->fn+11)) break; /* Last segment match. Function completed. */ | |
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; | |
} | |
/*-----------------------------------------------------------------------*/ | |
/* Check a sector if it is an FAT boot record */ | |
/*-----------------------------------------------------------------------*/ | |
static | |
BYTE check_fs ( /* 0:The FAT boot record, 1:Valid boot record but not an FAT, 2:Not a boot record, 3:Error */ | |
BYTE *buf, /* Working buffer */ | |
DWORD sect /* Sector# (lba) to check if it is an FAT boot record or not */ | |
) | |
{ | |
if (disk_readp(buf, sect, 510, 2)) /* Read the boot sector */ | |
return 3; | |
if (LD_WORD(buf) != 0xAA55) /* Check record signature */ | |
return 2; | |
if (!disk_readp(buf, sect, BS_FilSysType, 2) && LD_WORD(buf) == 0x4146) /* Check FAT12/16 */ | |
return 0; | |
if (_FS_FAT32 && !disk_readp(buf, sect, BS_FilSysType32, 2) && LD_WORD(buf) == 0x4146) /* Check FAT32 */ | |
return 0; | |
return 1; | |
} | |
/*-------------------------------------------------------------------------- | |
Public Functions | |
--------------------------------------------------------------------------*/ | |
/*-----------------------------------------------------------------------*/ | |
/* Mount/Unmount a Locical Drive */ | |
/*-----------------------------------------------------------------------*/ | |
FRESULT pf_mount ( | |
FATFS *fs /* Pointer to new file system object (NULL: Unmount) */ | |
) | |
{ | |
BYTE fmt, buf[36]; | |
DWORD bsect, fsize, tsect, mclst; | |
FatFs = 0; | |
if (!fs) return FR_OK; /* Unregister fs object */ | |
if (disk_initialize() & STA_NOINIT) /* Check if the drive is ready or not */ | |
return FR_NOT_READY; | |
/* Search FAT partition on the drive */ | |
bsect = 0; | |
fmt = check_fs(buf, bsect); /* Check sector 0 as an SFD format */ | |
if (fmt == 1) { /* Not an FAT boot record, it may be FDISK format */ | |
/* Check a partition listed in top of the partition table */ | |
if (disk_readp(buf, bsect, MBR_Table, 16)) { /* 1st partition entry */ | |
fmt = 3; | |
} else { | |
if (buf[4]) { /* Is the partition existing? */ | |
bsect = LD_DWORD(&buf[8]); /* Partition offset in LBA */ | |
fmt = check_fs(buf, bsect); /* Check the partition */ | |
} | |
} | |
} | |
if (fmt == 3) return FR_DISK_ERR; | |
if (fmt) return FR_NO_FILESYSTEM; /* No valid FAT patition is found */ | |
/* Initialize the file system object */ | |
if (disk_readp(buf, bsect, 13, sizeof(buf))) return FR_DISK_ERR; | |
fsize = LD_WORD(buf+BPB_FATSz16-13); /* Number of sectors per FAT */ | |
if (!fsize) fsize = LD_DWORD(buf+BPB_FATSz32-13); | |
fsize *= buf[BPB_NumFATs-13]; /* Number of sectors in FAT area */ | |
fs->fatbase = bsect + LD_WORD(buf+BPB_RsvdSecCnt-13); /* FAT start sector (lba) */ | |
fs->csize = buf[BPB_SecPerClus-13]; /* Number of sectors per cluster */ | |
fs->n_rootdir = LD_WORD(buf+BPB_RootEntCnt-13); /* Nmuber of root directory entries */ | |
tsect = LD_WORD(buf+BPB_TotSec16-13); /* Number of sectors on the file system */ | |
if (!tsect) tsect = LD_DWORD(buf+BPB_TotSec32-13); | |
mclst = (tsect /* Last cluster# + 1 */ | |
- LD_WORD(buf+BPB_RsvdSecCnt-13) - fsize - fs->n_rootdir / 16 | |
) / fs->csize + 2; | |
fs->n_fatent = (CLUST)mclst; | |
fmt = FS_FAT16; /* Determine the FAT sub type */ | |
if (mclst < 0xFF7) /* Number of clusters < 0xFF5 */ | |
#if _FS_FAT12 | |
fmt = FS_FAT12; | |
#else | |
return FR_NO_FILESYSTEM; | |
#endif | |
if (mclst >= 0xFFF7) /* Number of clusters >= 0xFFF5 */ | |
#if _FS_FAT32 | |
fmt = FS_FAT32; | |
#else | |
return FR_NO_FILESYSTEM; | |
#endif | |
fs->fs_type = fmt; /* FAT sub-type */ | |
if (_FS_FAT32 && fmt == FS_FAT32) | |
fs->dirbase = LD_DWORD(buf+(BPB_RootClus-13)); /* Root directory start cluster */ | |
else | |
fs->dirbase = fs->fatbase + fsize; /* Root directory start sector (lba) */ | |
fs->database = fs->fatbase + fsize + fs->n_rootdir / 16; /* Data start sector (lba) */ | |
fs->flag = 0; | |
FatFs = fs; | |
return FR_OK; | |
} | |
/*-----------------------------------------------------------------------*/ | |
/* Open or Create a File */ | |
/*-----------------------------------------------------------------------*/ | |
FRESULT pf_open ( | |
const char *path /* Pointer to the file name */ | |
) | |
{ | |
FRESULT res; | |
DIR dj; | |
BYTE sp[12], dir[32]; | |
FATFS *fs = FatFs; | |
if (!fs) /* Check file system */ | |
return FR_NOT_ENABLED; | |
fs->flag = 0; | |
dj.fn = sp; | |
res = follow_path(&dj, dir, path); /* Follow the file path */ | |
if (res != FR_OK) return res; /* Follow failed */ | |
if (!dir[0] || (dir[DIR_Attr] & AM_DIR)) /* It is a directory */ | |
return FR_NO_FILE; | |
fs->org_clust = LD_CLUST(dir); /* File start cluster */ | |
fs->fsize = LD_DWORD(dir+DIR_FileSize); /* File size */ | |
fs->fptr = 0; /* File pointer */ | |
fs->flag = FA_OPENED; | |
return FR_OK; | |
} | |
/*-----------------------------------------------------------------------*/ | |
/* Read File */ | |
/*-----------------------------------------------------------------------*/ | |
#if _USE_READ | |
FRESULT pf_read ( | |
void* buff, /* Pointer to the read buffer (NULL:Forward data to the stream)*/ | |
WORD btr, /* Number of bytes to read */ | |
WORD* br /* Pointer to number of bytes read */ | |
) | |
{ | |
DRESULT dr; | |
CLUST clst; | |
DWORD sect, remain; | |
WORD rcnt; | |
BYTE cs, *rbuff = buff; | |
FATFS *fs = FatFs; | |
*br = 0; | |
if (!fs) return FR_NOT_ENABLED; /* Check file system */ | |
if (!(fs->flag & FA_OPENED)) /* Check if opened */ | |
return FR_NOT_OPENED; | |
remain = fs->fsize - fs->fptr; | |
if (btr > remain) btr = (WORD)remain; /* Truncate btr by remaining bytes */ | |
while (btr) { /* Repeat until all data transferred */ | |
if ((fs->fptr % 512) == 0) { /* On the sector boundary? */ | |
cs = (BYTE)(fs->fptr / 512 & (fs->csize - 1)); /* Sector offset in the cluster */ | |
if (!cs) { /* On the cluster boundary? */ | |
clst = (fs->fptr == 0) ? /* On the top of the file? */ | |
fs->org_clust : get_fat(fs->curr_clust); | |
if (clst <= 1) goto fr_abort; | |
fs->curr_clust = clst; /* Update current cluster */ | |
} | |
sect = clust2sect(fs->curr_clust); /* Get current sector */ | |
if (!sect) goto fr_abort; | |
fs->dsect = sect + cs; | |
} | |
rcnt = (WORD)(512 - (fs->fptr % 512)); /* Get partial sector data from sector buffer */ | |
if (rcnt > btr) rcnt = btr; | |
dr = disk_readp(!buff ? 0 : rbuff, fs->dsect, (WORD)(fs->fptr % 512), rcnt); | |
if (dr) goto fr_abort; | |
fs->fptr += rcnt; rbuff += rcnt; /* Update pointers and counters */ | |
btr -= rcnt; *br += rcnt; | |
} | |
return FR_OK; | |
fr_abort: | |
fs->flag = 0; | |
return FR_DISK_ERR; | |
} | |
#endif | |
/*-----------------------------------------------------------------------*/ | |
/* Write File */ | |
/*-----------------------------------------------------------------------*/ | |
#if _USE_WRITE | |
FRESULT pf_write ( | |
const void* buff, /* Pointer to the data to be written */ | |
WORD btw, /* Number of bytes to write (0:Finalize the current write operation) */ | |
WORD* bw /* Pointer to number of bytes written */ | |
) | |
{ | |
CLUST clst; | |
DWORD sect, remain; | |
const BYTE *p = buff; | |
BYTE cs; | |
WORD wcnt; | |
FATFS *fs = FatFs; | |
*bw = 0; | |
if (!fs) return FR_NOT_ENABLED; /* Check file system */ | |
if (!(fs->flag & FA_OPENED)) /* Check if opened */ | |
return FR_NOT_OPENED; | |
if (!btw) { /* Finalize request */ | |
if ((fs->flag & FA__WIP) && disk_writep(0, 0)) goto fw_abort; | |
fs->flag &= ~FA__WIP; | |
return FR_OK; | |
} else { /* Write data request */ | |
if (!(fs->flag & FA__WIP)) /* Round-down fptr to the sector boundary */ | |
fs->fptr &= 0xFFFFFE00; | |
} | |
remain = fs->fsize - fs->fptr; | |
if (btw > remain) btw = (WORD)remain; /* Truncate btw by remaining bytes */ | |
while (btw) { /* Repeat until all data transferred */ | |
if (((WORD)fs->fptr % 512) == 0) { /* On the sector boundary? */ | |
cs = (BYTE)(fs->fptr / 512 & (fs->csize - 1)); /* Sector offset in the cluster */ | |
if (!cs) { /* On the cluster boundary? */ | |
clst = (fs->fptr == 0) ? /* On the top of the file? */ | |
fs->org_clust : get_fat(fs->curr_clust); | |
if (clst <= 1) goto fw_abort; | |
fs->curr_clust = clst; /* Update current cluster */ | |
} | |
sect = clust2sect(fs->curr_clust); /* Get current sector */ | |
if (!sect) goto fw_abort; | |
fs->dsect = sect + cs; | |
if (disk_writep(0, fs->dsect)) goto fw_abort; /* Initiate a sector write operation */ | |
fs->flag |= FA__WIP; | |
} | |
wcnt = 512 - ((WORD)fs->fptr % 512); /* Number of bytes to write to the sector */ | |
if (wcnt > btw) wcnt = btw; | |
if (disk_writep(p, wcnt)) goto fw_abort; /* Send data to the sector */ | |
fs->fptr += wcnt; p += wcnt; /* Update pointers and counters */ | |
btw -= wcnt; *bw += wcnt; | |
if (((WORD)fs->fptr % 512) == 0) { | |
if (disk_writep(0, 0)) goto fw_abort; /* Finalize the currtent secter write operation */ | |
fs->flag &= ~FA__WIP; | |
} | |
} | |
return FR_OK; | |
fw_abort: | |
fs->flag = 0; | |
return FR_DISK_ERR; | |
} | |
#endif | |
/*-----------------------------------------------------------------------*/ | |
/* Seek File R/W Pointer */ | |
/*-----------------------------------------------------------------------*/ | |
#if _USE_LSEEK | |
FRESULT pf_lseek ( | |
DWORD ofs /* File pointer from top of file */ | |
) | |
{ | |
CLUST clst; | |
DWORD bcs, sect, ifptr; | |
FATFS *fs = FatFs; | |
if (!fs) return FR_NOT_ENABLED; /* Check file system */ | |
if (!(fs->flag & FA_OPENED)) /* Check if opened */ | |
return FR_NOT_OPENED; | |
if (ofs > fs->fsize) ofs = fs->fsize; /* Clip offset with the file size */ | |
ifptr = fs->fptr; | |
fs->fptr = 0; | |
if (ofs > 0) { | |
bcs = (DWORD)fs->csize * 512; /* Cluster size (byte) */ | |
if (ifptr > 0 && | |
(ofs - 1) / bcs >= (ifptr - 1) / bcs) { /* When seek to same or following cluster, */ | |
fs->fptr = (ifptr - 1) & ~(bcs - 1); /* start from the current cluster */ | |
ofs -= fs->fptr; | |
clst = fs->curr_clust; | |
} else { /* When seek to back cluster, */ | |
clst = fs->org_clust; /* start from the first cluster */ | |
fs->curr_clust = clst; | |
} | |
while (ofs > bcs) { /* Cluster following loop */ | |
clst = get_fat(clst); /* Follow cluster chain */ | |
if (clst <= 1 || clst >= fs->n_fatent) goto fe_abort; | |
fs->curr_clust = clst; | |
fs->fptr += bcs; | |
ofs -= bcs; | |
} | |
fs->fptr += ofs; | |
sect = clust2sect(clst); /* Current sector */ | |
if (!sect) goto fe_abort; | |
fs->dsect = sect + (fs->fptr / 512 & (fs->csize - 1)); | |
} | |
return FR_OK; | |
fe_abort: | |
fs->flag = 0; | |
return FR_DISK_ERR; | |
} | |
#endif | |
/*-----------------------------------------------------------------------*/ | |
/* Create a Directroy Object */ | |
/*-----------------------------------------------------------------------*/ | |
#if _USE_DIR | |
FRESULT pf_opendir ( | |
DIR *dj, /* Pointer to directory object to create */ | |
const char *path /* Pointer to the directory path */ | |
) | |
{ | |
FRESULT res; | |
BYTE sp[12], dir[32]; | |
FATFS *fs = FatFs; | |
if (!fs) { /* Check file system */ | |
res = FR_NOT_ENABLED; | |
} else { | |
dj->fn = sp; | |
res = follow_path(dj, dir, path); /* Follow the path to the directory */ | |
if (res == FR_OK) { /* Follow completed */ | |
if (dir[0]) { /* It is not the root dir */ | |
if (dir[DIR_Attr] & AM_DIR) /* The object is a directory */ | |
dj->sclust = LD_CLUST(dir); | |
else /* The object is not a directory */ | |
res = FR_NO_PATH; | |
} | |
if (res == FR_OK) | |
res = dir_rewind(dj); /* Rewind dir */ | |
} | |
if (res == FR_NO_FILE) res = FR_NO_PATH; | |
} | |
return res; | |
} | |
/*-----------------------------------------------------------------------*/ | |
/* Read Directory Entry in Sequense */ | |
/*-----------------------------------------------------------------------*/ | |
FRESULT pf_readdir ( | |
DIR *dj, /* Pointer to the open directory object */ | |
FILINFO *fno /* Pointer to file information to return */ | |
) | |
{ | |
FRESULT res; | |
BYTE sp[12], dir[32]; | |
FATFS *fs = FatFs; | |
if (!fs) { /* Check file system */ | |
res = FR_NOT_ENABLED; | |
} else { | |
dj->fn = sp; | |
if (!fno) { | |
res = dir_rewind(dj); | |
} else { | |
res = dir_read(dj, dir); | |
if (res == FR_NO_FILE) { | |
dj->sect = 0; | |
res = FR_OK; | |
} | |
if (res == FR_OK) { /* A valid entry is found */ | |
get_fileinfo(dj, dir, fno); /* Get the object information */ | |
res = dir_next(dj); /* Increment index for next */ | |
if (res == FR_NO_FILE) { | |
dj->sect = 0; | |
res = FR_OK; | |
} | |
} | |
} | |
} | |
return res; | |
} | |
#endif /* _USE_DIR */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*---------------------------------------------------------------------------/ | |
/ Petit FatFs - FAT file system module include file R0.02a (C)ChaN, 2010 | |
/----------------------------------------------------------------------------/ | |
/ Petit FatFs module is an open source software to implement FAT file system to | |
/ small embedded systems. This is a free software and is opened for education, | |
/ research and commercial developments under license policy of following trems. | |
/ | |
/ Copyright (C) 2010, ChaN, all right reserved. | |
/ | |
/ * The Petit FatFs module is a free software and there is NO WARRANTY. | |
/ * No restriction on use. You can use, modify and redistribute it for | |
/ personal, non-profit or commercial use UNDER YOUR RESPONSIBILITY. | |
/ * Redistributions of source code must retain the above copyright notice. | |
/ | |
/----------------------------------------------------------------------------*/ | |
#include "integer.h" | |
/*---------------------------------------------------------------------------/ | |
/ Petit FatFs Configuration Options | |
/ | |
/ CAUTION! Do not forget to make clean the project after any changes to | |
/ the configuration options. | |
/ | |
/----------------------------------------------------------------------------*/ | |
#ifndef _FATFS | |
#define _FATFS | |
#define _USE_READ 1 /* 1:Enable pf_read() */ | |
#define _USE_DIR 1 /* 1:Enable pf_opendir() and pf_readdir() */ | |
#define _USE_LSEEK 1 /* 1:Enable pf_lseek() */ | |
#define _USE_WRITE 1 /* 1:Enable pf_write() */ | |
#define _FS_FAT12 0 /* 1:Enable FAT12 support */ | |
#define _FS_FAT32 1 /* 1:Enable FAT32 support */ | |
#define _CODE_PAGE 1 | |
/* Defines which code page is used for path name. Supported code pages are: | |
/ 932, 936, 949, 950, 437, 720, 737, 775, 850, 852, 855, 857, 858, 862, 866, | |
/ 874, 1250, 1251, 1252, 1253, 1254, 1255, 1257, 1258 and 1 (ASCII only). | |
/ SBCS code pages except for 1 requiers a case conversion table. This | |
/ might occupy 128 bytes on the RAM on some platforms, e.g. avr-gcc. */ | |
#define _WORD_ACCESS 0 | |
/* The _WORD_ACCESS option defines which access method is used to the word | |
/ data in the FAT structure. | |
/ | |
/ 0: Byte-by-byte access. Always compatible with all platforms. | |
/ 1: Word access. Do not choose this unless following condition is met. | |
/ | |
/ When the byte order on the memory is big-endian or address miss-aligned | |
/ word access results incorrect behavior, the _WORD_ACCESS must be set to 0. | |
/ If it is not the case, the value can also be set to 1 to improve the | |
/ performance and code efficiency. */ | |
/* End of configuration options. Do not change followings without care. */ | |
/*--------------------------------------------------------------------------*/ | |
#if _FS_FAT32 | |
#define CLUST DWORD | |
#else | |
#define CLUST WORD | |
#endif | |
/* File system object structure */ | |
typedef struct { | |
BYTE fs_type; /* FAT sub type */ | |
BYTE flag; /* File status flags */ | |
BYTE csize; /* Number of sectors per cluster */ | |
BYTE pad1; | |
WORD n_rootdir; /* Number of root directory entries (0 on FAT32) */ | |
CLUST n_fatent; /* Number of FAT entries (= number of clusters + 2) */ | |
DWORD fatbase; /* FAT start sector */ | |
DWORD dirbase; /* Root directory start sector (Cluster# on FAT32) */ | |
DWORD database; /* Data start sector */ | |
DWORD fptr; /* File R/W pointer */ | |
DWORD fsize; /* File size */ | |
CLUST org_clust; /* File start cluster */ | |
CLUST curr_clust; /* File current cluster */ | |
DWORD dsect; /* File current data sector */ | |
} FATFS; | |
/* Directory object structure */ | |
typedef struct { | |
WORD index; /* Current read/write index number */ | |
BYTE* fn; /* Pointer to the SFN (in/out) {file[8],ext[3],status[1]} */ | |
CLUST sclust; /* Table start cluster (0:Static table) */ | |
CLUST clust; /* Current cluster */ | |
DWORD sect; /* Current sector */ | |
} DIR; | |
/* File status structure */ | |
typedef struct { | |
DWORD fsize; /* File size */ | |
WORD fdate; /* Last modified date */ | |
WORD ftime; /* Last modified time */ | |
BYTE fattrib; /* Attribute */ | |
char fname[13]; /* File name */ | |
} FILINFO; | |
/* File function return code (FRESULT) */ | |
typedef enum { | |
FR_OK = 0, /* 0 */ | |
FR_DISK_ERR, /* 1 */ | |
FR_NOT_READY, /* 2 */ | |
FR_NO_FILE, /* 3 */ | |
FR_NO_PATH, /* 4 */ | |
FR_NOT_OPENED, /* 5 */ | |
FR_NOT_ENABLED, /* 6 */ | |
FR_NO_FILESYSTEM /* 7 */ | |
} FRESULT; | |
/*--------------------------------------------------------------*/ | |
/* Petit FatFs module application interface */ | |
FRESULT pf_mount (FATFS*); /* Mount/Unmount a logical drive */ | |
FRESULT pf_open (const char*); /* Open a file */ | |
FRESULT pf_read (void*, WORD, WORD*); /* Read data from the open file */ | |
FRESULT pf_write (const void*, WORD, WORD*); /* Write data to the open file */ | |
FRESULT pf_lseek (DWORD); /* Move file pointer of the open file */ | |
FRESULT pf_opendir (DIR*, const char*); /* Open a directory */ | |
FRESULT pf_readdir (DIR*, FILINFO*); /* Read a directory item from the open directory */ | |
/*--------------------------------------------------------------*/ | |
/* Flags and offset address */ | |
/* File status flag (FATFS.flag) */ | |
#define FA_OPENED 0x01 | |
#define FA_WPRT 0x02 | |
#define FA__WIP 0x40 | |
/* 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 */ | |
/*--------------------------------*/ | |
/* Multi-byte word access macros */ | |
#if _WORD_ACCESS == 1 /* Enable word access to the FAT structure */ | |
#define LD_WORD(ptr) (WORD)(*(WORD*)(BYTE*)(ptr)) | |
#define LD_DWORD(ptr) (DWORD)(*(DWORD*)(BYTE*)(ptr)) | |
#define ST_WORD(ptr,val) *(WORD*)(BYTE*)(ptr)=(WORD)(val) | |
#define ST_DWORD(ptr,val) *(DWORD*)(BYTE*)(ptr)=(DWORD)(val) | |
#else /* Use byte-by-byte access to the FAT structure */ | |
#define LD_WORD(ptr) (WORD)(((WORD)*((BYTE*)(ptr)+1)<<8)|(WORD)*(BYTE*)(ptr)) | |
#define LD_DWORD(ptr) (DWORD)(((DWORD)*((BYTE*)(ptr)+3)<<24)|((DWORD)*((BYTE*)(ptr)+2)<<16)|((WORD)*((BYTE*)(ptr)+1)<<8)|*(BYTE*)(ptr)) | |
#define ST_WORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8) | |
#define ST_DWORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8); *((BYTE*)(ptr)+2)=(BYTE)((DWORD)(val)>>16); *((BYTE*)(ptr)+3)=(BYTE)((DWORD)(val)>>24) | |
#endif | |
#endif /* _FATFS */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//----------------------------------------------------------------------------- | |
// serial.h - common function declarations for different serial implementations | |
//----------------------------------------------------------------------------- | |
#ifndef SERIAL_H_ | |
#define SERIAL_H_ | |
#ifdef __cplusplus | |
extern "C" { | |
#endif | |
static const int VER = 0x0101; | |
void serial_initialize(const uint32_t baud_rate_divisor); | |
int getchar(void); | |
int putchar(int); | |
#ifdef __cplusplus | |
} /* extern "C" */ | |
#endif | |
#endif /* SERIAL_H_ */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//----------------------------------------------------------------------------- | |
// spi.h - common function declarations for different SPI implementations | |
//----------------------------------------------------------------------------- | |
#ifndef SPI_H_ | |
#define SPI_H_ | |
/** | |
* SMCLK divider arguments for spi_set_divisor | |
* assumes 16MHz SMCLK. You need to change if you | |
* use a different frequency | |
*/ | |
#define SPI_250kHz 64 /* 16MHz/250000 */ | |
#define SPI_400kHz 40 /* 16MHz/400000 */ | |
#define SPI_1MHz 16 /* 16MHz/1MHz */ | |
#define SPI_2MHz 8 /* 16MHz/2MHz */ | |
#define SPI_4MHz 4 /* 16MHz/4MHz */ | |
#define SPI_8MHz 2 /* 16MHz/8MHz */ | |
#define SPI_16MHz 1 /* 16MHz/16Mhz */ | |
#define SPI_DEFAULT_SPEED SPI_8MHz | |
void spi_initialize(void); | |
uint8_t spi_send(const uint8_t); | |
uint8_t spi_receive(void); | |
uint16_t spi_set_divisor(const uint16_t clkdivider); | |
#endif /*SPI_H_*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* usci_serial.c - USCI implementations of serial_initialize(), getchar(), putchar() and puts() | |
* | |
* Created on: Oct 30, 2011 | |
* Author: kimballr - [email protected] | |
* | |
* 04-06-2012 - switched to oPossum style bps setting. | |
*/ | |
#include <msp430.h> | |
#include <stdint.h> | |
#include "serial.h" | |
/** | |
* Really simple use of the hardware UART so that it will be | |
* compatible with our equally simple software ones. We setup the | |
* hardware UART using the pins and bit duration provided. | |
* | |
* This code doesn't use any interrupts. Just simple polling | |
* to decide when to receive or transmit. | |
*/ | |
/** | |
* serial_initialize(bitclk_divisor) - configure USCI UCA0 as async serial port | |
* uses SMCLK as bitclock source and fractional divisor with over sampling mode. | |
* | |
* @params: | |
* uint32_t bitclk_divisor - should be (SMCLK_FREQ + (BPS >> 1)) / BPS | |
* | |
* Thanks to Kevin for original code from 43oh.com: | |
* @see http://www.43oh.com/forum/viewtopic.php?f=10&t=2493 | |
* | |
* P1.1 - RX | |
* P1.2 - TX | |
* | |
*/ | |
void serial_initialize(const uint32_t bitclk_divisor) { | |
UCA0CTL1 = UCSWRST; // Hold USCI in reset to allow configuration | |
UCA0CTL0 = 0; // No parity, LSB first, 8 bits, one stop bit, UART (async) | |
UCA0BR1 = (bitclk_divisor >> 12) & 0xFF; // High byte of whole divisor | |
UCA0BR0 = (bitclk_divisor >> 4) & 0xFF; // Low byte of whole divisor | |
UCA0MCTL = ((bitclk_divisor << 4) & 0xF0) | UCOS16; // Fractional divisor, over sampling mode | |
UCA0CTL1 = UCSSEL_2; // Use SMCLK for bit rate generator, release reset | |
P1SEL = BIT1 | BIT2; // P1.1=RXD, P1.2=TXD | |
P1SEL2 = BIT1 | BIT2; // P1.1=RXD, P1.2=TXD | |
} | |
/** | |
* int getchar() - read next char from serial port rx pin | |
* | |
* | |
*/ | |
int getchar(void) { | |
// sit and spin waiting for baudot heh I make myself laugh | |
while (!(IFG2 & UCA0RXIFG)) { | |
; // busywait until UCA0 RX buffer is ready | |
} | |
return UCA0RXBUF; // return RXed character | |
} | |
/** | |
* putchar(int c) - write char to serial port | |
* | |
*/ | |
int putchar(int c) { | |
// make sure previous character has been sent | |
// before trying to send another character | |
while (!(IFG2 & UCA0TXIFG)) { | |
; // busywait until UCA0 TX buffer is ready | |
} | |
UCA0TXBUF = (uint8_t) c; // TX character | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* File: usci_spi.c - msp430 USCI SPI implementation | |
* | |
*/ | |
#include <msp430.h> | |
#include <stdint.h> | |
#include "spi.h" | |
#ifndef __MSP430_HAS_USCI__ | |
#error "Error! This MCU doesn't have a USCI peripheral" | |
#endif | |
/** | |
* USCI flags for various the SPI MODEs | |
* | |
* Note: The msp430 UCCKPL tracks the CPOL value. However, | |
* the UCCKPH flag is inverted when compared to the CPHA | |
* value described in Motorola documentation. | |
*/ | |
#define SPI_MODE_0 (UCMSB | UCMST | UCSYNC | UCCKPH) /* CPOL=0 CPHA=0 */ | |
#define SPI_MODE_1 (UCMSB | UCMST | UCSYNC) /* CPOL=0 CPHA=1 */ | |
#define SPI_MODE_2 (UCMSB | UCMST | UCSYNC | UCCKPL | UCCKPH) /* CPOL=1 CPHA=0 */ | |
#define SPI_MODE_3 (UCMSB | UCMST | UCSYNC | UCCKPL) /* CPOL=1 CPHA=1 */ | |
/** | |
* utility macros for extracting hi/lo byte data from a word value | |
*/ | |
#ifndef LOBYTE | |
#define LOBYTE(w) ((w)&0xFF) | |
#define HIBYTE(w) ((w)>>8) | |
#endif | |
/** | |
* spi_initialize() - Configure USCI UCB0 for SPI mode | |
* | |
* P2.0 - CS (active low) | |
* P1.5 - SCLK | |
* P1.6 - SIMO/MOSI | |
* P1.7 - SOMI/MISO | |
*/ | |
void spi_initialize(void) { | |
UCB0CTL1 = UCSWRST | UCSSEL_2; // Put USCI in reset mode, source USCI clock from SMCLK | |
UCB0CTL0 = SPI_MODE_0; // Use SPI MODE 0 - CPOL=0 CPHA=0 | |
P1SEL |= BIT5 | BIT6 | BIT7; // configure P1.5, P1.6, P1.7 for USCI | |
P1SEL2 |= BIT5 | BIT6 | BIT7; | |
UCB0BR0 = LOBYTE(SPI_400kHz); // set initial speed to 400kHz (16MHz/400000) | |
UCB0BR1 = HIBYTE(SPI_400kHz); | |
P2OUT |= BIT0; // CS on P2.0. start out disabled | |
P2DIR |= BIT0; // CS configured as output | |
UCB0CTL1 &= ~UCSWRST; // release USCI for operation | |
} | |
/** | |
* spi_send() - send a byte and recv response | |
*/ | |
uint8_t spi_send(const uint8_t c) { | |
while (!(IFG2 & UCB0TXIFG)) | |
; // wait for previous tx to complete | |
UCB0TXBUF = c; // setting TXBUF clears the TXIFG flag | |
while (!(IFG2 & UCB0RXIFG)) | |
; // wait for an rx character? | |
return UCB0RXBUF; // reading clears RXIFG flag | |
} | |
/** | |
* spi_receive() - send dummy btye then recv response | |
*/ | |
uint8_t spi_receive(void) { | |
while (!(IFG2 & UCB0TXIFG)) | |
; // wait for any previous xmits to complete | |
UCB0TXBUF = 0xFF; // Send dummy packet to get data back. | |
while (!(IFG2 & UCB0RXIFG)) | |
; // wait to recv a character? | |
return UCB0RXBUF; // reading clears RXIFG flag | |
} | |
/** | |
* spi_set_divisor() - set new clock divider for USCI | |
* | |
* USCI speed is based on the SMCLK divided by BR0 and BR1 | |
* initially we start slow (400kHz) to conform to SDCard | |
* specifications then we speed up once initialized (SPI_DEFAULT_SPEED) | |
* | |
* returns the previous setting | |
*/ | |
uint16_t spi_set_divisor(const uint16_t clkdiv) { | |
uint16_t prev_clkdiv = UCB0BR1 << 8 | UCB0BR0; | |
UCB0CTL1 |= UCSWRST; // go into reset state | |
UCB0BR0 = LOBYTE(clkdiv); | |
UCB0BR1 = HIBYTE(clkdiv); | |
UCB0CTL1 &= ~UCSWRST; // release for operation | |
return prev_clkdiv; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment