123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302 |
- /* mbed Microcontroller Library
- * Copyright (c) 2006-2013 ARM Limited
- *
- * 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.
- */
- #include "platform/LocalFileSystem.h"
- #if DEVICE_LOCALFILESYSTEM
- #include "platform/mbed_semihost_api.h"
- #include <string.h>
- #include <stdio.h>
- #include <errno.h>
- namespace mbed {
- /* Extension to FINFO type defined in RTL.h (in Keil RL) - adds 'create time'. */
- typedef struct {
- unsigned char hr; /* Hours [0..23] */
- unsigned char min; /* Minutes [0..59] */
- unsigned char sec; /* Seconds [0..59] */
- unsigned char day; /* Day [1..31] */
- unsigned char mon; /* Month [1..12] */
- unsigned short year; /* Year [1980..2107] */
- } FTIME;
- typedef struct { /* File Search info record */
- char name[32]; /* File name */
- long size; /* File size in bytes */
- int fileID; /* System File Identification */
- FTIME create_time; /* Date & time file was created */
- FTIME write_time; /* Date & time of last write */
- } XFINFO;
- #define RESERVED_FOR_USER_APPLICATIONS (0x100) /* 0x100 - 0x1ff */
- #define USR_XFFIND (RESERVED_FOR_USER_APPLICATIONS + 0)
- static int xffind(const char *pattern, XFINFO *info)
- {
- unsigned param[4];
- param[0] = (unsigned long)pattern;
- param[1] = (unsigned long)strlen(pattern);
- param[2] = (unsigned long)info;
- param[3] = (unsigned long)sizeof(XFINFO);
- return __semihost(USR_XFFIND, param);
- }
- #define OPEN_R 0
- #define OPEN_B 1
- #define OPEN_PLUS 2
- #define OPEN_W 4
- #define OPEN_A 8
- #define OPEN_INVALID -1
- int posix_to_semihost_open_flags(int flags)
- {
- /* POSIX flags -> semihosting open mode */
- int openmode;
- if (flags & O_RDWR) {
- /* a plus mode */
- openmode = OPEN_PLUS;
- if (flags & O_APPEND) {
- openmode |= OPEN_A;
- } else if (flags & O_TRUNC) {
- openmode |= OPEN_W;
- } else {
- openmode |= OPEN_R;
- }
- } else if (flags & O_WRONLY) {
- /* write or append */
- if (flags & O_APPEND) {
- openmode = OPEN_A;
- } else {
- openmode = OPEN_W;
- }
- } else if (flags == O_RDONLY) {
- /* read mode */
- openmode = OPEN_R;
- } else {
- /* invalid flags */
- openmode = OPEN_INVALID;
- }
- return openmode;
- }
- FILEHANDLE local_file_open(const char *name, int flags)
- {
- int openmode = posix_to_semihost_open_flags(flags);
- if (openmode == OPEN_INVALID) {
- return (FILEHANDLE)NULL;
- }
- FILEHANDLE fh = semihost_open(name, openmode);
- if (fh == -1) {
- return (FILEHANDLE)NULL;
- }
- return fh;
- }
- LocalFileHandle::LocalFileHandle(FILEHANDLE fh) : _fh(fh), pos(0)
- {
- // No lock needed in constructor
- }
- int LocalFileHandle::close()
- {
- int retval = semihost_close(_fh);
- delete this;
- return retval;
- }
- ssize_t LocalFileHandle::write(const void *buffer, size_t length)
- {
- lock();
- ssize_t n = semihost_write(_fh, (const unsigned char *)buffer, length, 0); // number of characters not written
- n = length - n; // number of characters written
- pos += n;
- unlock();
- return n;
- }
- ssize_t LocalFileHandle::read(void *buffer, size_t length)
- {
- lock();
- ssize_t n = semihost_read(_fh, (unsigned char *)buffer, length, 0); // number of characters not read
- n = length - n; // number of characters read
- pos += n;
- unlock();
- return n;
- }
- int LocalFileHandle::isatty()
- {
- lock();
- int ret = semihost_istty(_fh);
- unlock();
- return ret;
- }
- off_t LocalFileHandle::seek(off_t position, int whence)
- {
- lock();
- if (whence == SEEK_CUR) {
- position += pos;
- } else if (whence == SEEK_END) {
- position += semihost_flen(_fh);
- } /* otherwise SEEK_SET, so position is fine */
- /* Always seems to return -1, so just ignore for now. */
- semihost_seek(_fh, position);
- pos = position;
- unlock();
- return position;
- }
- int LocalFileHandle::sync()
- {
- lock();
- int ret = semihost_ensure(_fh);
- unlock();
- return ret;
- }
- off_t LocalFileHandle::size()
- {
- lock();
- off_t off = semihost_flen(_fh);
- unlock();
- return off;
- }
- void LocalFileHandle::lock()
- {
- _mutex.lock();
- }
- void LocalFileHandle::unlock()
- {
- _mutex.unlock();
- }
- class LocalDirHandle : public DirHandle {
- public:
- XFINFO info;
- LocalDirHandle() : info()
- {
- }
- virtual int close()
- {
- // No lock can be used in destructor
- delete this;
- return 0;
- }
- virtual int read(struct dirent *ent)
- {
- lock();
- if (xffind("*", &info) != 0) {
- unlock();
- return 0;
- }
- memcpy(ent->d_name, info.name, sizeof(info.name));
- unlock();
- return 1;
- }
- virtual void rewind()
- {
- lock();
- info.fileID = 0;
- unlock();
- }
- virtual off_t tell()
- {
- lock();
- int fileId = info.fileID;
- unlock();
- return fileId;
- }
- virtual void seek(off_t offset)
- {
- lock();
- info.fileID = offset;
- unlock();
- }
- protected:
- PlatformMutex _mutex;
- virtual void lock()
- {
- _mutex.lock();
- }
- virtual void unlock()
- {
- _mutex.unlock();
- }
- };
- int LocalFileSystem::open(FileHandle **file, const char *name, int flags)
- {
- // No global state modified so function is thread safe
- /* reject filenames with / in them */
- for (const char *tmp = name; *tmp; tmp++) {
- if (*tmp == '/') {
- return -EINVAL;
- }
- }
- int openmode = posix_to_semihost_open_flags(flags);
- if (openmode == OPEN_INVALID) {
- return -EINVAL;
- }
- FILEHANDLE fh = semihost_open(name, openmode);
- if (fh == -1) {
- return -EIO;
- }
- *file = new LocalFileHandle(fh);
- return 0;
- }
- int LocalFileSystem::remove(const char *filename)
- {
- // No global state modified so function is thread safe
- return semihost_remove(filename);
- }
- int LocalFileSystem::open(DirHandle **dir, const char *name)
- {
- // No global state modified so function is thread safe
- *dir = new LocalDirHandle();
- return 0;
- }
- } // namespace mbed
- #endif
|