Web server based weather station using Sparkfun Weather Meters.
Dependencies: FatFileSystem mbed WeatherMeters SDFileSystem
Revision 1:c7958aa34fa1, committed 2012-02-25
- Comitter:
- AdamGreen
- Date:
- Sat Feb 25 03:28:05 2012 +0000
- Parent:
- 0:616601bde9fb
- Commit message:
- Use published libraries where possible.
Changed in this revision
--- a/Anemometer.cpp Thu Feb 23 21:38:39 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,60 +0,0 @@ -/* Copyright 2012 Adam Green (http://mbed.org/users/AdamGreen/) - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ -/* Implementation of class to interface for anemometer sensor with Sparkfun Weather Meters: - http://www.sparkfun.com/products/8942 -*/ -#include <mbed.h> -#include "Anemometer.h" - - -#define REV_PER_SECOND_TO_KMPH 2.4f - - -CAnemometer::CAnemometer(PinName AnemometerPin, unsigned int IgnoreTimeForDebounceInMicroSeconds) - : CDebouncedFallingEdgeCounter(AnemometerPin, IgnoreTimeForDebounceInMicroSeconds) -{ - m_CurrentWindSpeed = 0.0f; - ResetMaximumWindSpeed(); - m_OneSecondTicker.attach_us<CAnemometer>(this, &CAnemometer::OneSecondTickerISR, 1000000); -} - - -void CAnemometer::ResetMaximumWindSpeed() -{ - m_MaximumWindSpeed = m_CurrentWindSpeed; -} - - -void CAnemometer::OneSecondTickerISR() -{ - unsigned int GetCurrentCount = GetCountAndZero(); - - m_CurrentWindSpeed = (float)GetCurrentCount * REV_PER_SECOND_TO_KMPH; - if (m_CurrentWindSpeed > m_MaximumWindSpeed) - { - m_MaximumWindSpeed = m_CurrentWindSpeed; - } -} - -float CAnemometer::GetCurrentWindSpeed() -{ - return m_CurrentWindSpeed; -} - - -float CAnemometer::GetMaximumWindSpeed() -{ - return m_MaximumWindSpeed; -}
--- a/Anemometer.h Thu Feb 23 21:38:39 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +0,0 @@ -/* Copyright 2012 Adam Green (http://mbed.org/users/AdamGreen/) - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ -/* Header file for class to interface with anemometer sensor of Sparkfun Weather Meters: - http://www.sparkfun.com/products/8942 -*/ -#ifndef _ANEMOMETER_H_ -#define _ANEMOMETER_H_ - -#include "DebouncedFallingEdgeCounter.h" - - -namespace AFP -{ - -class CAnemometer : protected CDebouncedFallingEdgeCounter -{ -protected: - Ticker m_OneSecondTicker; - float m_CurrentWindSpeed; - float m_MaximumWindSpeed; - -public: - CAnemometer(PinName AnemometerPin, unsigned int IgnoreTimeForDebounceInMicroSeconds = 1000); - - float GetCurrentWindSpeed(); - float GetMaximumWindSpeed(); - void ResetMaximumWindSpeed(); - -protected: - void OneSecondTickerISR(); -}; - -} // namespace AFP -using namespace AFP; - -#endif // _ANEMOMETER_H_
--- a/DebouncedFallingEdgeCounter.cpp Thu Feb 23 21:38:39 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,100 +0,0 @@ -/* Copyright 2012 Adam Green (http://mbed.org/users/AdamGreen/) - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ -/* Implementation for wrapper class of InterruptIn used for counting falling edge - events with specified hold off time for the purpose of debouncing. -*/ -#include <mbed.h> -#include "DebouncedFallingEdgeCounter.h" - - -CDebouncedFallingEdgeCounter::CDebouncedFallingEdgeCounter(PinName InterruptInPin, unsigned int IgnoreTimeForDebounceInMicroSeconds) - : m_FallingEdgeInterruptIn(InterruptInPin) -{ - m_Timer.start(); - m_IgnoreTimeForDebounce = IgnoreTimeForDebounceInMicroSeconds; - InitLastFallingEdgeTime(); - - ZeroCount(); - - m_FallingEdgeInterruptIn.mode(PullUp); - m_FallingEdgeInterruptIn.fall<CDebouncedFallingEdgeCounter>(this, &CDebouncedFallingEdgeCounter::FallingEdgeISR); -} - - -void CDebouncedFallingEdgeCounter::InitLastFallingEdgeTime() -{ - InitLastFallingEdgeTime((unsigned int)m_Timer.read_us()); -} - - -void CDebouncedFallingEdgeCounter::InitLastFallingEdgeTime(unsigned int CurrentTime) -{ - m_LastFallingEdgeTime = CurrentTime - m_IgnoreTimeForDebounce; -} - - -void CDebouncedFallingEdgeCounter::FallingEdgeISR() -{ - // UNDONE: Can I just use whatever timer the m_Timer uses under the covers? - unsigned int CurrentTime = (unsigned int)m_Timer.read_us(); - - if (TimeSinceLastFallingEdge(CurrentTime) >= m_IgnoreTimeForDebounce) - { - m_FallingEdgeCount++; - m_LastFallingEdgeTime = CurrentTime; - } -} - - -unsigned int CDebouncedFallingEdgeCounter::TimeSinceLastFallingEdge(unsigned int CurrentTime) -{ - return CurrentTime - m_LastFallingEdgeTime; -} - - -unsigned int CDebouncedFallingEdgeCounter::GetCountAndZero() -{ - unsigned int CurrentCount; - - CurrentCount = GetCount(); - ZeroCount(); - return CurrentCount; -} - - -unsigned int CDebouncedFallingEdgeCounter::GetCount() -{ - RefreshTimers(); - - return m_FallingEdgeCount; -} - - -void CDebouncedFallingEdgeCounter::ZeroCount() -{ - m_FallingEdgeCount = 0; -} - - -void CDebouncedFallingEdgeCounter::RefreshTimers() -{ - unsigned int CurrentTime = (unsigned int)m_Timer.read_us(); - - if (TimeSinceLastFallingEdge(CurrentTime) > m_IgnoreTimeForDebounce) - { - // Protect from timer overflow. - InitLastFallingEdgeTime(CurrentTime); - } -}
--- a/DebouncedFallingEdgeCounter.h Thu Feb 23 21:38:39 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -/* Copyright 2012 Adam Green (http://mbed.org/users/AdamGreen/) - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ -/* Header file for wrapper class of InterruptIn used for counting falling edge - events with specified hold off time for the purpose of debouncing. -*/ -#ifndef _DEBOUNCED_FALLING_EDGE_COUNT_H_ -#define _DEBOUNCED_FALLING_EDGE_COUNT_H_ - -namespace AFP -{ - -class CDebouncedFallingEdgeCounter -{ -protected: - InterruptIn m_FallingEdgeInterruptIn; - // UNDONE: Run for over 30 minutes and make sure that this rolls over as expected. - Timer m_Timer; - unsigned int m_IgnoreTimeForDebounce; - unsigned int m_LastFallingEdgeTime; - unsigned int m_FallingEdgeCount; - -public: - CDebouncedFallingEdgeCounter(PinName InterruptInPin, unsigned int IgnoreTimeForDebounceInMicroSeconds); - - unsigned int GetCountAndZero(); - void ZeroCount(); - unsigned int GetCount(); - -protected: - void InitLastFallingEdgeTime(); - void InitLastFallingEdgeTime(unsigned int CurrentTime); - void FallingEdgeISR(); - void RefreshTimers(); - unsigned int TimeSinceLastFallingEdge(unsigned int CurrentTime); -}; - -} // namespace AFP -using namespace AFP; - -#endif // _DEBOUNCED_FALLING_EDGE_COUNT_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/FatFileSystem.lib Sat Feb 25 03:28:05 2012 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/AdamGreen/code/FatFileSystem/#6ceefe1c53e4
--- a/FatFileSystem/FATDirHandle.cpp Thu Feb 23 21:38:39 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +0,0 @@ -/* 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 FATFS_DIR &the_dir) { - dir = the_dir; -} - -int FATDirHandle::closedir() { - delete this; - return 0; -} - -struct dirent *FATDirHandle::readdir() { - FILINFO finfo; - -#if _USE_LFN - finfo.lfname = cur_entry.d_name; - finfo.lfsize = sizeof(cur_entry.d_name); -#endif // _USE_LFN - - FRESULT res = f_readdir(&dir, &finfo); - -#if _USE_LFN - if(res != 0 || finfo.fname[0]==0) { - return NULL; - } else { - if(cur_entry.d_name[0]==0) { - // No long filename so use short filename. - memcpy(cur_entry.d_name, finfo.fname, sizeof(finfo.fname)); - } - return &cur_entry; - } -#else - if(res != 0 || finfo.fname[0]==0) { - return NULL; - } else { - memcpy(cur_entry.d_name, finfo.fname, sizeof(finfo.fname)); - return &cur_entry; - } -#endif /* _USE_LFN */ -} - -void FATDirHandle::rewinddir() { - dir.index = 0; -} - -off_t FATDirHandle::telldir() { - return dir.index; -} - -void FATDirHandle::seekdir(off_t location) { - dir.index = location; -} - -} -
--- a/FatFileSystem/FATDirHandle.h Thu Feb 23 21:38:39 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +0,0 @@ -/* 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 FATFS_DIR &the_dir); - virtual int closedir(); - virtual struct dirent *readdir(); - virtual void rewinddir(); - virtual off_t telldir(); - virtual void seekdir(off_t location); - - private: - FATFS_DIR dir; - struct dirent cur_entry; - -}; - -} - -#endif
--- a/FatFileSystem/FATFileHandle.cpp Thu Feb 23 21:38:39 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,102 +0,0 @@ -/* 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 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
--- a/FatFileSystem/FATFileHandle.h Thu Feb 23 21:38:39 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -/* 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 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 _fh; - -}; - -} - -#endif
--- a/FatFileSystem/FATFileSystem.cpp Thu Feb 23 21:38:39 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,134 +0,0 @@ -/* 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[_VOLUMES] = {0}; - -FATFileSystem::FATFileSystem(const char* n) : FileSystemLike(n) { - FFSDEBUG("FATFileSystem(%s)\n", n); - for(int i=0; i<_VOLUMES; 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<_VOLUMES; 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 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) { - FATFS_DIR 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
--- a/FatFileSystem/FATFileSystem.h Thu Feb 23 21:38:39 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -/* 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[_VOLUMES]; // 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
--- a/FatFileSystem/MemFileSystem.h Thu Feb 23 21:38:39 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,75 +0,0 @@ -/* mbed Microcontroller Library - MemFileSystem - * Copyright (c) 2008, sford - */ - - -#ifndef MBED_MEMFILESYSTEM_H -#define MBED_MEMFILESYSTEM_H - -#include "FATFileSystem.h" - -namespace mbed { - -class MemFileSystem : public FATFileSystem { -public: - - // 2000 sectors, each 512 bytes (malloced as required) - char *sectors[2000]; - - MemFileSystem(const char* name) : FATFileSystem(name) { - memset(sectors, 0, sizeof(sectors)); - } - - virtual ~MemFileSystem() { - for(int i = 0; i < 2000; i++) { - if(sectors[i]) { - free(sectors[i]); - } - } - } - - // read a sector in to the buffer, return 0 if ok - virtual int disk_read(char *buffer, int sector) { - if(sectors[sector] == 0) { - // nothing allocated means sector is empty - memset(buffer, 0, 512); - } else { - memcpy(buffer, sectors[sector], 512); - } - return 0; - } - - // write a sector from the buffer, return 0 if ok - virtual int disk_write(const char *buffer, int sector) { - // if buffer is zero deallocate sector - char zero[512]; - memset(zero, 0, 512); - if(memcmp(zero, buffer, 512)==0) { - if(sectors[sector] != 0) { - free(sectors[sector]); - sectors[sector] = 0; - } - return 0; - } - // else allocate a sector if needed, and write - if(sectors[sector] == 0) { - char *sec = (char*)malloc(512); - if(sec==0) { - return 1; // out of memory - } - sectors[sector] = sec; - } - memcpy(sectors[sector], buffer, 512); - return 0; - } - - // return the number of sectors - virtual int disk_sectors() { - return sizeof(sectors)/sizeof(sectors[0]); - } - -}; - -} - -#endif
--- a/FatFileSystem/diskio.c Thu Feb 23 21:38:39 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,105 +0,0 @@ -/*-----------------------------------------------------------------------*/ -/* 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(DWORD 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(DWORD s=sector; s<sector+count; s++) { - FFSDEBUG(" disk_write(sector %d)\n", s); - int res = FATFileSystem::_ffs[drv]->disk_write((char*)buff, s); - 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; -} -
--- a/FatFileSystem/diskio.h Thu Feb 23 21:38:39 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,78 +0,0 @@ -/*----------------------------------------------------------------------- -/ 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*); - - - -/* 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
--- a/FatFileSystem/ff.c Thu Feb 23 21:38:39 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4077 +0,0 @@ -/*----------------------------------------------------------------------------/ -/ FatFs - FAT file system module R0.09 (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. -/ -/ Sep 06,'11 R0.09 f_mkfs() supports multiple partition to finish the multiple partition feature. -/ Added f_fdisk(). (_MULTI_PARTITION = 2) -/---------------------------------------------------------------------------*/ - -#include "ff.h" /* FatFs configurations and declarations */ -#include "diskio.h" /* Declarations of low level disk I/O functions */ - - -/*-------------------------------------------------------------------------- - - Module Private Definitions - ----------------------------------------------------------------------------*/ - -#if _FATFS != 6502 /* Revision ID */ -#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) /* Variable 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 */ - - -/*------------------------------------------------------------*/ -/* Module private work area */ -/*------------------------------------------------------------*/ -/* Note that uninitialized variables with static duration are -/ zeroed/nulled at start-up. If not, the compiler or start-up -/ routine is out of ANSI-C standard. -*/ - -#if _VOLUMES -static -FATFS *FatFs[_VOLUMES]; /* Pointer to the file system objects (logical drives) */ -#else -#error Number of volumes 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 feature */ -#define DEF_NAMEBUF BYTE sfn[12] -#define INIT_BUF(dobj) (dobj).fn = sfn -#define FREE_BUF() - -#elif _USE_LFN == 1 /* LFN feature with static 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 feature with dynamic 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 feature with dynamic 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 - ----------------------------------------------------------------------------*/ - - -/*-----------------------------------------------------------------------*/ -/* 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 */ - FATFS_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 (void) /* Check if an entry is available for a new file */ -{ - 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) */ - FATFS_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, 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 ( - FATFS_DIR *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 */ - FATFS_DIR *dj, /* Pointer to directory object */ - int stretch /* 0: Do not stretch table, 1: Stretch table if needed */ -) -{ - DWORD clst; - WORD i; - - - stretch = stretch; /* To suppress warning on read-only cfg. */ - 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 ( - FATFS_DIR *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 ( - FATFS_DIR *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 */ - FATFS_DIR *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 */ - FATFS_DIR *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 ( - FATFS_DIR *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 */ - FATFS_DIR *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 */ - FATFS_DIR *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 a sector and check if it is an FAT Volume Boot Record */ -/*-----------------------------------------------------------------------*/ - -static -BYTE check_fs ( /* 0:FAT-VBR, 1:Valid BR but not 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, pi, *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 file system object 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 && chk_wp && (stat & STA_PROTECT)) /* Check write protection if needed */ - return FR_WRITE_PROTECTED; - return FR_OK; /* The file system object is valid */ - } - } - - /* The file system object is not valid. */ - /* Following code attempts to mount the volume. (analyze BPB and initialize the fs object) */ - - fs->fs_type = 0; /* Clear the file system object */ - fs->drv = 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 (!_FS_READONLY && chk_wp && (stat & STA_PROTECT)) /* Check disk write protection if needed */ - return FR_WRITE_PROTECTED; -#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 - /* Search FAT partition on the drive. Supports only generic partitionings, FDISK and SFD. */ - fmt = check_fs(fs, bsect = 0); /* Load sector 0 and check if it is an FAT-VBR (in SFD) */ - if (LD2PT(vol) && !fmt) fmt = 1; /* Force non-SFD if the volume is forced partition */ - if (fmt == 1) { /* Not an FAT-VBR, the physical drive can be partitioned */ - /* Check the partition listed in the partition table */ - pi = LD2PT(vol); - if (pi) pi--; - tbl = &fs->win[MBR_Table + pi * 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 */ - - /* An 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+FATFS_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 *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; - FATFS_DIR 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() ? 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 FATFS_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 *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 *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 = (const 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 *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 *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; - FATFS_DIR 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; - FATFS_DIR 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 *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 ( - FATFS_DIR *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 ( - FATFS_DIR *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; - FATFS_DIR 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 *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; - FATFS_DIR 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(FATFS_DIR)); /* 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; - FATFS_DIR 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; - FATFS_DIR 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; - FATFS_DIR 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; - FATFS_DIR 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(FATFS_DIR)); /* 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 *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, sys, *tbl, pdrv, part; - DWORD n_clst, vs, n, wsect; - UINT i; - DWORD b_vol, b_fat, b_dir, b_data; /* 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; - if (sfd > 1) return FR_INVALID_PARAMETER; - if (au & (au - 1)) return FR_INVALID_PARAMETER; - fs = FatFs[drv]; - if (!fs) return FR_NOT_ENABLED; - fs->fs_type = 0; - pdrv = LD2PD(drv); /* Physical drive */ - part = LD2PT(drv); /* Partition (0:auto detect, 1-4:get from partition table)*/ - - /* Get disk statics */ - stat = disk_initialize(pdrv); - 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(pdrv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK || SS(fs) > _MAX_SS) - return FR_DISK_ERR; -#endif - if (_MULTI_PARTITION && part) { - /* Get partition information from partition table in the MBR */ - if (disk_read(pdrv, fs->win, 0, 1) != RES_OK) return FR_DISK_ERR; - if (LD_WORD(fs->win+BS_55AA) != 0xAA55) return FR_MKFS_ABORTED; - tbl = &fs->win[MBR_Table + (part - 1) * SZ_PTE]; - if (!tbl[4]) return FR_MKFS_ABORTED; /* No partition? */ - b_vol = LD_DWORD(tbl+8); /* Volume start sector */ - n_vol = LD_DWORD(tbl+12); /* Volume size */ - } else { - /* Create a partition in this function */ - if (disk_ioctl(pdrv, 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; /* Volume 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 - b_vol) return FR_MKFS_ABORTED; /* Too small volume */ - - /* Align data start sector to erase block boundary (for flash memory media) */ - if (disk_ioctl(pdrv, 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; - - switch (fmt) { /* Determine system ID for partition table */ - case FS_FAT12: sys = 0x01; break; - case FS_FAT16: sys = (n_vol < 0x10000) ? 0x04 : 0x06; break; - default: sys = 0x0C; - } - - if (_MULTI_PARTITION && part) { - /* Update system ID in the partition table */ - tbl = &fs->win[MBR_Table + (part - 1) * SZ_PTE]; - tbl[4] = sys; - if (disk_write(pdrv, fs->win, 0, 1) != RES_OK) return FR_DISK_ERR; - md = 0xF8; - } else { - if (sfd) { /* No patition table (SFD) */ - md = 0xF0; - } else { /* Create partition table (FDISK) */ - mem_set(fs->win, 0, SS(fs)); - tbl = fs->win+MBR_Table; /* Create partiton table for single partition in the drive */ - tbl[1] = 1; /* Partition start head */ - tbl[2] = 1; /* Partition start sector */ - tbl[3] = 0; /* Partition start cylinder */ - tbl[4] = sys; /* System type */ - tbl[5] = 254; /* Partition end head */ - n = (b_vol + n_vol) / 63 / 255; - tbl[6] = (BYTE)((n >> 2) | 63); /* Partiiton end sector */ - tbl[7] = (BYTE)n; /* End cylinder */ - 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(pdrv, fs->win, 0, 1) != RES_OK) /* Write it to the MBR sector */ - return FR_DISK_ERR; - md = 0xF8; - } - } - - /* Create BPB in the VBR */ - 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(pdrv, tbl, b_vol, 1) != RES_OK) /* Write it to the VBR sector */ - return FR_DISK_ERR; - if (fmt == FS_FAT32) /* Write backup VBR if needed (VBR+6) */ - disk_write(pdrv, 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(pdrv, 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(pdrv, tbl, wsect++, 1) != RES_OK) - return FR_DISK_ERR; - } - } - - /* Initialize root directory */ - i = (fmt == FS_FAT32) ? au : n_dir; - do { - if (disk_write(pdrv, 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(pdrv, 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(pdrv, tbl, b_vol + 1, 1); /* Write original (VBR+1) */ - disk_write(pdrv, tbl, b_vol + 7, 1); /* Write backup (VBR+7) */ - } - - return (disk_ioctl(pdrv, CTRL_SYNC, 0) == RES_OK) ? FR_OK : FR_DISK_ERR; -} - - -#if _MULTI_PARTITION == 2 -/*-----------------------------------------------------------------------*/ -/* Divide Physical Drive */ -/*-----------------------------------------------------------------------*/ - -FRESULT f_fdisk ( - BYTE pdrv, /* Physical drive number */ - const DWORD szt[], /* Pointer to the size table for each partitions */ - void* work /* Pointer to the working buffer */ -) -{ - UINT i, n, sz_cyl, tot_cyl, b_cyl, e_cyl, p_cyl; - BYTE s_hd, e_hd, *p, *buf = (BYTE*)work; - DSTATUS stat; - DWORD sz_disk, sz_part, s_part; - - - stat = disk_initialize(pdrv); - if (stat & STA_NOINIT) return FR_NOT_READY; - if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; - if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_disk)) return FR_DISK_ERR; - - /* Determine CHS in the table regardless of the drive geometry */ - for (n = 16; n < 256 && sz_disk / n / 63 > 1024; n *= 2) ; - if (n == 256) n--; - e_hd = n - 1; - sz_cyl = 63 * n; - tot_cyl = sz_disk / sz_cyl; - - /* Create partition table */ - mem_set(buf, 0, _MAX_SS); - p = buf + MBR_Table; b_cyl = 0; - for (i = 0; i < 4; i++, p += SZ_PTE) { - p_cyl = (szt[i] <= 100) ? (DWORD)tot_cyl * szt[i] / 100 : szt[i] / sz_cyl; - if (!p_cyl) continue; - s_part = (DWORD)sz_cyl * b_cyl; - sz_part = (DWORD)sz_cyl * p_cyl; - if (i == 0) { /* Exclude first track of cylinder 0 */ - s_hd = 1; - s_part += 63; sz_part -= 63; - } else { - s_hd = 0; - } - e_cyl = b_cyl + p_cyl - 1; - if (e_cyl >= tot_cyl) return FR_INVALID_PARAMETER; - - /* Set partition table */ - p[1] = s_hd; /* Start head */ - p[2] = (BYTE)((b_cyl >> 2) + 1); /* Start sector */ - p[3] = (BYTE)b_cyl; /* Start cylinder */ - p[4] = 0x06; /* System type (temporary setting) */ - p[5] = e_hd; /* End head */ - p[6] = (BYTE)((e_cyl >> 2) + 63); /* End sector */ - p[7] = (BYTE)e_cyl; /* End cylinder */ - ST_DWORD(p + 8, s_part); /* Start sector in LBA */ - ST_DWORD(p + 12, sz_part); /* Partition size */ - - /* Next partition */ - b_cyl += p_cyl; - } - ST_WORD(p, 0xAA55); - - /* Write it to the MBR */ - return (disk_write(pdrv, buf, 0, 1) || disk_ioctl(pdrv, CTRL_SYNC, 0)) ? FR_DISK_ERR : FR_OK; -} - - -#endif /* _MULTI_PARTITION == 2 */ -#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* 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* 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* 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* 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, chc, 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++) ; - chc = 0; - if (!(f & 2)) { - while (j++ < w) chc += (cc = f_putc(' ', fil)); - } - chc += (cc = f_puts(p, fil)); - while (j++ < w) chc += (cc = f_putc(' ', fil)); - if (cc != EOF) cc = chc; - 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) ? (ULONG)va_arg(arp, long) : ((d == 'D') ? (ULONG)(long)va_arg(arp, int) : (ULONG)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 */
--- a/FatFileSystem/ff.h Thu Feb 23 21:38:39 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,337 +0,0 @@ -/*---------------------------------------------------------------------------/ -/ FatFs - FAT file system module include file R0.09 (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 6502 /* Revision ID */ - -#ifdef __cplusplus -extern "C" { -#endif - -#include "integer.h" /* Basic integer types */ -#include "ffconf.h" /* FatFs configuration options */ - -#if _FATFS != _FFCONF -#error Wrong configuration file (ffconf.h). -#endif - - - -/* Definitions of volume management */ - -#if _MULTI_PARTITION /* Multiple partition configuration */ -typedef struct { - BYTE pd; /* Physical drive number */ - BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */ -} PARTITION; -extern PARTITION VolToPart[]; /* Volume - Partition resolution table */ -#define LD2PD(vol) (VolToPart[vol].pd) /* Get physical drive number */ -#define LD2PT(vol) (VolToPart[vol].pt) /* Get partition index */ - -#else /* Single partition configuration */ -#define LD2PD(vol) (vol) /* Each logical drive is bound to the same physical drive number */ -#define LD2PT(vol) 0 /* Always mounts the 1st partition or in SFD */ - -#endif - - - -/* Type of path name strings on FatFs API */ - -#if _LFN_UNICODE /* Unicode string */ -#if !_USE_LFN -#error _LFN_UNICODE must be 0 in non-LFN cfg. -#endif -#ifndef _INC_TCHAR -typedef WCHAR TCHAR; -#define _T(x) L ## x -#define _TEXT(x) L ## x -#endif - -#else /* ANSI/OEM string */ -#ifndef _INC_TCHAR -typedef char TCHAR; -#define _T(x) x -#define _TEXT(x) x -#endif - -#endif - - - -/* File system object structure (FATFS) */ - -typedef struct { - BYTE fs_type; /* FAT sub-type (0:Not mounted) */ - BYTE drv; /* Physical drive number */ - BYTE csize; /* Sectors per cluster (1,2,4...128) */ - BYTE n_fats; /* Number of FAT copies (1,2) */ - BYTE wflag; /* win[] dirty flag (1:must be written back) */ - BYTE fsi_flag; /* fsinfo dirty flag (1:must be written back) */ - WORD id; /* File system mount ID */ - WORD n_rootdir; /* Number of root directory entries (FAT12/16) */ -#if _MAX_SS != 512 - WORD ssize; /* Bytes per sector (512, 1024, 2048 or 4096) */ -#endif -#if _FS_REENTRANT - _SYNC_t sobj; /* Identifier of sync object */ -#endif -#if !_FS_READONLY - DWORD last_clust; /* Last allocated cluster */ - DWORD free_clust; /* Number of free clusters */ - DWORD fsi_sector; /* fsinfo sector (FAT32) */ -#endif -#if _FS_RPATH - DWORD cdir; /* Current directory start cluster (0:root) */ -#endif - DWORD n_fatent; /* Number of FAT entries (= number of clusters + 2) */ - DWORD fsize; /* Sectors per FAT */ - DWORD fatbase; /* FAT start sector */ - DWORD dirbase; /* Root directory start sector (FAT32:Cluster#) */ - DWORD database; /* Data start sector */ - DWORD winsect; /* Current sector appearing in the win[] */ - BYTE win[_MAX_SS]; /* Disk access window for Directory, FAT (and Data on tiny cfg) */ -} FATFS; - - - -/* File object structure (FIL) */ - -typedef struct { - FATFS* fs; /* Pointer to the 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; - - - -/* Directory object structure (FATFS_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 -} FATFS_DIR; - - - -/* File status structure (FILINFO) */ - -typedef struct { - DWORD fsize; /* File size */ - WORD fdate; /* Last modified date */ - WORD ftime; /* Last modified time */ - BYTE fattrib; /* Attribute */ - TCHAR fname[13]; /* Short file name (8.3 format) */ -#if _USE_LFN - TCHAR* lfname; /* Pointer to the LFN buffer */ - UINT lfsize; /* Size of LFN buffer in TCHAR */ -#endif -} FILINFO; - - - -/* File function return code (FRESULT) */ - -typedef enum { - FR_OK = 0, /* (0) Succeeded */ - FR_DISK_ERR, /* (1) A hard error 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 */ - 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 */ - FR_INVALID_PARAMETER /* (19) Given parameter is invalid */ -} FRESULT; - - - -/*--------------------------------------------------------------*/ -/* FatFs module application interface */ - -FRESULT f_mount (BYTE, FATFS*); /* Mount/Unmount a logical drive */ -FRESULT f_open (FIL*, const TCHAR*, BYTE); /* Open or create a file */ -FRESULT f_read (FIL*, void*, UINT, UINT*); /* Read data from a file */ -FRESULT f_lseek (FIL*, DWORD); /* Move file pointer of a file object */ -FRESULT f_close (FIL*); /* Close an open file object */ -FRESULT f_opendir (FATFS_DIR*, const TCHAR*); /* Open an existing directory */ -FRESULT f_readdir (FATFS_DIR*, FILINFO*); /* Read a directory item */ -FRESULT f_stat (const TCHAR*, FILINFO*); /* Get file status */ -FRESULT f_write (FIL*, const void*, UINT, UINT*); /* Write data to a file */ -FRESULT f_getfree (const TCHAR*, DWORD*, FATFS**); /* Get number of free clusters on the drive */ -FRESULT f_truncate (FIL*); /* Truncate file */ -FRESULT f_sync (FIL*); /* Flush cached data of a writing file */ -FRESULT f_unlink (const TCHAR*); /* Delete an existing file or directory */ -FRESULT f_mkdir (const TCHAR*); /* Create a new directory */ -FRESULT f_chmod (const TCHAR*, BYTE, BYTE); /* Change 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_chdrive (BYTE); /* Change current drive */ -FRESULT f_chdir (const TCHAR*); /* Change current directory */ -FRESULT f_getcwd (TCHAR*, UINT); /* Get current directory */ -FRESULT f_forward (FIL*, UINT(*)(const BYTE*,UINT), UINT, UINT*); /* Forward data to the stream */ -FRESULT f_mkfs (BYTE, BYTE, UINT); /* Create a file system on the drive */ -FRESULT f_fdisk (BYTE, const DWORD[], void*); /* Divide a physical drive into some partitions */ -int f_putc (TCHAR, FIL*); /* Put a character to the file */ -int f_puts (const TCHAR*, FIL*); /* Put a string to the file */ -int f_printf (FIL*, const TCHAR*, ...); /* Put a formatted string to the file */ -TCHAR* f_gets (TCHAR*, int, FIL*); /* Get a string from the file */ - -#define f_eof(fp) (((fp)->fptr == (fp)->fsize) ? 1 : 0) -#define f_error(fp) (((fp)->flag & FA__ERROR) ? 1 : 0) -#define f_tell(fp) ((fp)->fptr) -#define f_size(fp) ((fp)->fsize) - -#ifndef EOF -#define EOF (-1) -#endif - - - - -/*--------------------------------------------------------------*/ -/* Additional user defined functions */ - -/* RTC function */ -#if !_FS_READONLY -DWORD get_fattime (void); -#endif - -/* Unicode support functions */ -#if _USE_LFN /* Unicode - OEM code conversion */ -WCHAR ff_convert (WCHAR, UINT); /* OEM-Unicode bidirectional conversion */ -WCHAR ff_wtoupper (WCHAR); /* Unicode upper-case conversion */ -#if _USE_LFN == 3 /* Memory functions */ -void* ff_memalloc (UINT); /* Allocate memory block */ -void ff_memfree (void*); /* Free memory block */ -#endif -#endif - -/* Sync functions */ -#if _FS_REENTRANT -int ff_cre_syncobj (BYTE, _SYNC_t*);/* Create a sync object */ -int ff_req_grant (_SYNC_t); /* Lock sync object */ -void ff_rel_grant (_SYNC_t); /* Unlock sync object */ -int ff_del_syncobj (_SYNC_t); /* Delete a sync object */ -#endif - - - - -/*--------------------------------------------------------------*/ -/* Flags and offset address */ - - -/* File access control and file status flags (FIL.flag) */ - -#define FA_READ 0x01 -#define FA_OPEN_EXISTING 0x00 -#define FA__ERROR 0x80 - -#if !_FS_READONLY -#define FA_WRITE 0x02 -#define FA_CREATE_NEW 0x04 -#define FA_CREATE_ALWAYS 0x08 -#define FA_OPEN_ALWAYS 0x10 -#define FA__WRITTEN 0x20 -#define FA__DIRTY 0x40 -#endif - - -/* FAT sub type (FATFS.fs_type) */ - -#define FS_FAT12 1 -#define FS_FAT16 2 -#define FS_FAT32 3 - - -/* File attribute bits for directory entry */ - -#define AM_RDO 0x01 /* Read only */ -#define AM_HID 0x02 /* Hidden */ -#define AM_SYS 0x04 /* System */ -#define AM_VOL 0x08 /* Volume label */ -#define AM_LFN 0x0F /* LFN entry */ -#define AM_DIR 0x10 /* Directory */ -#define AM_ARC 0x20 /* Archive */ -#define AM_MASK 0x3F /* Mask of defined bits */ - - -/* Fast seek feature */ -#define CREATE_LINKMAP 0xFFFFFFFF - - - -/*--------------------------------*/ -/* Multi-byte word access macros */ - -#if _WORD_ACCESS == 1 /* Enable word access to the FAT structure */ -#define LD_WORD(ptr) (WORD)(*(WORD*)(BYTE*)(ptr)) -#define LD_DWORD(ptr) (DWORD)(*(DWORD*)(BYTE*)(ptr)) -#define ST_WORD(ptr,val) *(WORD*)(BYTE*)(ptr)=(WORD)(val) -#define ST_DWORD(ptr,val) *(DWORD*)(BYTE*)(ptr)=(DWORD)(val) -#else /* Use byte-by-byte access to the FAT structure */ -#define LD_WORD(ptr) (WORD)(((WORD)*((BYTE*)(ptr)+1)<<8)|(WORD)*(BYTE*)(ptr)) -#define LD_DWORD(ptr) (DWORD)(((DWORD)*((BYTE*)(ptr)+3)<<24)|((DWORD)*((BYTE*)(ptr)+2)<<16)|((WORD)*((BYTE*)(ptr)+1)<<8)|*(BYTE*)(ptr)) -#define ST_WORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8) -#define ST_DWORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8); *((BYTE*)(ptr)+2)=(BYTE)((DWORD)(val)>>16); *((BYTE*)(ptr)+3)=(BYTE)((DWORD)(val)>>24) -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* _FATFS */
--- a/FatFileSystem/ffconf.h Thu Feb 23 21:38:39 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,190 +0,0 @@ -/*---------------------------------------------------------------------------/ -/ FatFs - FAT file system module configuration file R0.09 (C)ChaN, 2011 -/----------------------------------------------------------------------------/ -/ -/ CAUTION! Do not forget to make clean the project after any changes to -/ the configuration options. -/ -/----------------------------------------------------------------------------*/ -#ifndef _FFCONF -#define _FFCONF 6502 /* Revision ID */ - - -/*---------------------------------------------------------------------------/ -/ Functions 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 0 /* 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 858 -/* 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 4 -/* Number of volumes (logical drives) to be used. */ - - -#define _MAX_SS 512 /* 512, 1024, 2048 or 4096 */ -/* Maximum sector size to be handled. -/ Always set 512 for memory card and hard disk but a larger value may be -/ required for on-board flash memory, floppy disk and optical disk. -/ When _MAX_SS is larger than 512, it configures FatFs to variable sector size -/ and GET_SECTOR_SIZE command must be implememted to the disk_ioctl function. */ - - -#define _MULTI_PARTITION 0 /* 0:Single partition, 1/2:Enable multiple partition */ -/* When set to 0, each volume is bound to the same physical drive number and -/ it can mount only first primaly partition. When it is set to 1, each volume -/ is tied to the partitions listed in VolToPart[]. */ - - -#define _USE_ERASE 0 /* 0:Disable or 1:Enable */ -/* To enable sector erase feature, set _USE_ERASE to 1. CTRL_ERASE_SECTOR command -/ should be added to the disk_ioctl functio. */ - - - -/*---------------------------------------------------------------------------/ -/ System Configurations -/----------------------------------------------------------------------------*/ - -#define _WORD_ACCESS 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 */
--- a/FatFileSystem/integer.h Thu Feb 23 21:38:39 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,37 +0,0 @@ -/*-------------------------------------------*/ -/* 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
--- a/FatFileSystem/option/ccsbcs.c Thu Feb 23 21:38:39 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,540 +0,0 @@ -/*------------------------------------------------------------------------*/ -/* 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; -}
--- a/RainGauge.h Thu Feb 23 21:38:39 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -/* Copyright 2012 Adam Green (http://mbed.org/users/AdamGreen/) - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ -/* Header file for class to interface with the rain gauge sensor of the Sparkfun Weather Meters: - http://www.sparkfun.com/products/8942 -*/ -#ifndef _RAIN_GAUGE_H_ -#define _RAIN_GAUGE_H_ - -#include "DebouncedFallingEdgeCounter.h" - - -#define MILLIMETERS_OF_RAIN_PER_COUNT 0.2794f - - -namespace AFP -{ - -class CRainGauge : protected CDebouncedFallingEdgeCounter -{ -public: - CRainGauge(PinName RainGaugePin, unsigned int IgnoreTimeForDebounceInMicroSeconds = 1000) - : CDebouncedFallingEdgeCounter(RainGaugePin, IgnoreTimeForDebounceInMicroSeconds) - { - } - - void Reset() - { - ZeroCount(); - } - - float GetRainfall() - { - return (float)GetCount() * MILLIMETERS_OF_RAIN_PER_COUNT; - } -}; - -} // namespace AFP -using namespace AFP; - -#endif // _RAIN_GAUGE_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SDFileSystem.lib Sat Feb 25 03:28:05 2012 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/simon/code/SDFileSystem/#b1ddfc9a9b25
--- a/SDFileSystem/SDFileSystem.cpp Thu Feb 23 21:38:39 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,457 +0,0 @@ -/* 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* pName) : - FATFileSystem(pName), _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() { - - 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; -}
--- a/SDFileSystem/SDFileSystem.h Thu Feb 23 21:38:39 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,81 +0,0 @@ -/* 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
--- a/WeatherMeters.cpp Thu Feb 23 21:38:39 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -/* Copyright 2012 Adam Green (http://mbed.org/users/AdamGreen/) - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ -/* Implementation of class to interface with Sparkfun Weather Meters: - http://www.sparkfun.com/products/8942 -*/ -#include <mbed.h> -#include "WeatherMeters.h" - - -CWeatherMeters::CWeatherMeters(PinName AnemometerPin, - PinName RainGaugePin, - PinName WindVanePin, - float WindVaneSeriesResistance) : m_Anemometer(AnemometerPin), - m_RainGauge(RainGaugePin), - m_WindVane(WindVanePin, WindVaneSeriesResistance) -{ -} - - -void CWeatherMeters::GetMeasurements(SMeasurements* pMeasurements) -{ - pMeasurements->WindDirectionString = m_WindVane.GetWindDirectionAsString(); - pMeasurements->WindDirectionAngle = m_WindVane.GetWindDirectionAsAngle(); - pMeasurements->WindSpeed = m_Anemometer.GetCurrentWindSpeed(); - pMeasurements->MaximumWindSpeed = m_Anemometer.GetMaximumWindSpeed(); - pMeasurements->Rainfall = m_RainGauge.GetRainfall(); -} - - -void CWeatherMeters::Reset() -{ - ResetRainfall(); - ResetMaximumWindSpeed(); -} - - -void CWeatherMeters::ResetRainfall() -{ - m_RainGauge.Reset(); -} - - -void CWeatherMeters::ResetMaximumWindSpeed() -{ - m_Anemometer.ResetMaximumWindSpeed(); -} -
--- a/WeatherMeters.h Thu Feb 23 21:38:39 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,130 +0,0 @@ -/* Copyright 2012 Adam Green (http://mbed.org/users/AdamGreen/) - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ -/* Header file for class to interface with Sparkfun Weather Meters: - http://www.sparkfun.com/products/8942 -*/ -#ifndef _WEATHER_METERS_H_ -#define _WEATHER_METERS_H_ - -#include "WindVane.h" -#include "RainGauge.h" -#include "Anemometer.h" - - -namespace AFP -{ - -/** A class to interface with the Sparkfun Weather Meters. - http://www.sparkfun.com/products/8942 - - This set of weather meters from Sparkfun includes anemometer (wind speed), - wind vane, and rain gauge. All of the sensors use reed switches so that - the electronics can detect motion/location in the sensor hardware via - magnets placed in the sensors without actually exposing the electonic - switches themselves to the elements. A reed switch closes as the - anemometer spins and the rain gauge empties. The wind vane includes - 8 reed switches, each with a different valued resistor attached so that - the voltage will vary depending on where the magnet in the vane is - located. - * Example: - * @code -#include <mbed.h> -#include "WeatherMeters.h" - -int main() -{ - CWeatherMeters WeatherMeters(p9, p10, p15); - for (;;) - { - CWeatherMeters::SMeasurements Measurements; - - WeatherMeters.GetMeasurements(&Measurements); - - printf("Direction: %s\n", Measurements.WindDirectionString); - printf("Depth: %f\n",Measurements.Rainfall); - printf("Current speed: %f\n", Measurements.WindSpeed); - printf("Maximum speed: %f\n", Measurements.MaximumWindSpeed); - - wait(1.0f); - } -} - * @endcode - */ -class CWeatherMeters -{ -protected: - CAnemometer m_Anemometer; - CRainGauge m_RainGauge; - CWindVane m_WindVane; - -public: - /** A structure in which the current measurements registered by the weather - meters are returned from the GetMeasurements() method. - */ - struct SMeasurements - { - const char* WindDirectionString; /**< String representing current wind direction. Example: "North" */ - float WindDirectionAngle; /**< Wind direction in degrees from north. */ - float WindSpeed; /**< Current wind speed in km/hour. */ - float MaximumWindSpeed; /**< Maximum wind speed measured since last reset. Measured in km/hour. */ - float Rainfall; /**< Amount of rainfall since last reset. Measured in mm. */ - }; - - /** Create a CWeatherMeters object, binds it to the specified input pins, - and initializes the required interrupt handlers. - - @param AnemometerPin The mbed pin which is connected to the anemometer - sensor. Must be a pin on which the mbed supports InterruptIn. - @param RainGauagePin The mbed pin which is connected to the rain gauge - sensor. Must be a pin on which the mbed supports InterruptIn. - @param WindVanePin The mbed pin which is connected to the wind vane - sensor. Must be a pin on which the mbed supports AnalogIn. - @param WindVaneSeriesResistance The value of the resistance which is - in series with the wind vane sensor and along with the - varying resistance of the wind vane sensor itself, acts as a - voltage divider. - */ - CWeatherMeters(PinName AnemometerPin, - PinName RainGaugePin, - PinName WindVanePin, - float WindVaneSeriesResistance = 10000.0f); - - /** Gets current weather meter measurements. - - NOTE: Should call this method on a regular basis (every 15 minutes or - less) to keep internal timers from overflowing. - - @param pMeasurements points to the measurement structure to be filled in - with the current measurement from the sensors. The historical - values in this structure such as rainfall and maximum wind - speed can be reset by calls to ResetRainfall(), - ResetMaximumWindSpeed(), and Reset(). - */ - void GetMeasurements(SMeasurements* pMeasurements); - - /** Resets all historical measurements: rainfall and maximum wind speed. */ - void Reset(); - - /** Resets the cumulative rainfall measurement. */ - void ResetRainfall(); - - /** Resets the maximum wind speed measurement. */ - void ResetMaximumWindSpeed(); -}; - -} // namespace AFP -using namespace AFP; - -#endif // _WEATHER_METERS_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WeatherMeters.lib Sat Feb 25 03:28:05 2012 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/AdamGreen/code/WeatherMeters/#457832d52954
--- a/WindVane.cpp Thu Feb 23 21:38:39 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,96 +0,0 @@ -/* Copyright 2012 Adam Green (http://mbed.org/users/AdamGreen/) - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ -/* Declaration of class to interface with wind vane sensor Sparkfun Weather Meters: - http://www.sparkfun.com/products/8942 -*/ -#include <mbed.h> -#include "WindVane.h" - - -#define REV_PER_SECOND_TO_KMPH 2.4f -#define PARALLEL_R(R1, R2) (((R1) * (R2)) / ((R1) + (R2))) -#define ARRAY_SIZE(X) (sizeof(X)/sizeof(X[0])) - -struct SDescription -{ - const char* DirectionString; - float DirectionAngle; - float SensorResistance; -}; - - -static SDescription g_WindVaneDescriptionTable[16] = { - { "North", 0.0f, 33.0f * 1000.0f }, - { "North North East", 22.5f, PARALLEL_R(33.0f * 1000.0f, 8.2f * 1000.0f) }, - { "North East", 45.0f, 8.2f * 1000.0f }, - { "East North East", 67.5f, PARALLEL_R(8.2f * 1000.0f, 1000.0f) }, - { "East", 90.0f, 1000.0f }, - { "East South East", 112.5f, PARALLEL_R(1000.0f, 2.2f * 1000.0f) }, - { "South East", 135.0f, 2.2f * 1000.0f }, - { "South South East", 157.5f, PARALLEL_R(2.2f * 1000.0f, 3.9f * 1000.0f) }, - { "South", 180.0f, 3.9f * 1000.0f }, - { "South South West", 202.5f, PARALLEL_R(3.9f * 1000.0f, 16.0f * 1000.0f) }, - { "South West", 225.0f, 16.0f * 1000.0f }, - { "West South West", 247.5f, PARALLEL_R(16.0f * 1000.0f, 120.0f * 1000.0f) }, - { "West", 270.0f, 120.0f * 1000.0f }, - { "West North West", 292.5f, PARALLEL_R(120.0f * 1000.0f, 64.9f * 1000.0f) }, - { "North West", 315.0f, 64.9f * 1000.0f }, - { "North North West", 337.5f, PARALLEL_R(64.9f * 1000.0f, 33.0f * 1000.0f) } -}; - - -CWindVane::CWindVane(PinName WindVanePin, float WindVaneSeriesResistance) - : m_WindVaneAnalogIn(WindVanePin) -{ - for (size_t i = 0 ; i < ARRAY_SIZE(g_WindVaneDescriptionTable) ; i++) - { - SDescription* pDescription = &g_WindVaneDescriptionTable[i]; - - m_WindVaneVoltageTable[i] = pDescription->SensorResistance / - (pDescription->SensorResistance + WindVaneSeriesResistance); - } -} - -const char* CWindVane::GetWindDirectionAsString() -{ - return g_WindVaneDescriptionTable[DetermineWindDirectionIndex()].DirectionString; -} - -float CWindVane::GetWindDirectionAsAngle() -{ - return g_WindVaneDescriptionTable[DetermineWindDirectionIndex()].DirectionAngle; -} - -size_t CWindVane::DetermineWindDirectionIndex() -{ - float WindVaneSensorVoltage = m_WindVaneAnalogIn.read(); - - // Default to the first entry being closest. - size_t ClosestIndex = 0; - float ClosestDelta = fabs(m_WindVaneVoltageTable[0] - WindVaneSensorVoltage); - - // Walk the rest of the entries to see if there is another which is closer. - for (size_t i = 1 ; i < ARRAY_SIZE(m_WindVaneVoltageTable) ; i++) - { - float Delta = fabs(m_WindVaneVoltageTable[i] - WindVaneSensorVoltage); - if (Delta < ClosestDelta) - { - ClosestDelta = Delta; - ClosestIndex = i; - } - } - - return ClosestIndex; -}
--- a/WindVane.h Thu Feb 23 21:38:39 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +0,0 @@ -/* Copyright 2012 Adam Green (http://mbed.org/users/AdamGreen/) - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ -/* Implementation of class to interface with wind vane sensor Sparkfun Weather Meters: - http://www.sparkfun.com/products/8942 -*/ -#ifndef _WIND_VANE_H_ -#define _WIND_VANE_H_ - -namespace AFP -{ - -class CWindVane -{ -protected: - AnalogIn m_WindVaneAnalogIn; - float m_WindVaneVoltageTable[16]; - -public: - CWindVane(PinName WindVanePin, float WindVaneSeriesResistance = 10000.0f); - - const char* GetWindDirectionAsString(); - float GetWindDirectionAsAngle(); - -protected: - size_t DetermineWindDirectionIndex(); -}; - -} // namespace AFP -using namespace AFP; - -#endif // _WIND_VANE_H_