]> git.donarmstrong.com Git - qmk_firmware.git/blob - tool/mbed/mbed-sdk/libraries/mbed/common/LocalFileSystem.cpp
Squashed 'tmk_core/' changes from 7967731..b9e0ea0
[qmk_firmware.git] / tool / mbed / mbed-sdk / libraries / mbed / common / LocalFileSystem.cpp
1 /* mbed Microcontroller Library
2  * Copyright (c) 2006-2013 ARM Limited
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include "LocalFileSystem.h"
17
18 #if DEVICE_LOCALFILESYSTEM
19
20 #include "semihost_api.h"
21 #include <string.h>
22 #include <stdio.h>
23
24 namespace mbed {
25
26 /* Extension to FINFO type defined in RTL.h (in Keil RL) - adds 'create time'. */
27 typedef struct {
28     unsigned char  hr;   /* Hours    [0..23]                  */
29     unsigned char  min;  /* Minutes  [0..59]                  */
30     unsigned char  sec;  /* Seconds  [0..59]                  */
31     unsigned char  day;  /* Day      [1..31]                  */
32     unsigned char  mon;  /* Month    [1..12]                  */
33     unsigned short year; /* Year     [1980..2107]             */
34 } FTIME;
35
36 typedef struct {         /* File Search info record           */
37     char  name[32];      /* File name                         */
38     long  size;          /* File size in bytes                */
39     int   fileID;        /* System File Identification        */
40     FTIME create_time;   /* Date & time file was created      */
41     FTIME write_time;    /* Date & time of last write         */
42 } XFINFO;
43
44 #define RESERVED_FOR_USER_APPLICATIONS (0x100) /* 0x100 - 0x1ff */
45 #define USR_XFFIND (RESERVED_FOR_USER_APPLICATIONS + 0)
46
47 static int xffind (const char *pattern, XFINFO *info) {
48     unsigned param[4];
49
50     param[0] = (unsigned long)pattern;
51     param[1] = (unsigned long)strlen(pattern);
52     param[2] = (unsigned long)info;
53     param[3] = (unsigned long)sizeof(XFINFO);
54
55     return __semihost(USR_XFFIND, param);
56 }
57
58 #define OPEN_R          0
59 #define OPEN_B          1
60 #define OPEN_PLUS       2
61 #define OPEN_W          4
62 #define OPEN_A          8
63 #define OPEN_INVALID   -1
64
65 int posix_to_semihost_open_flags(int flags) {
66     /* POSIX flags -> semihosting open mode */
67     int openmode;
68     if (flags & O_RDWR) {
69         /* a plus mode */
70         openmode = OPEN_PLUS;
71         if (flags & O_APPEND) {
72             openmode |= OPEN_A;
73         } else if (flags & O_TRUNC) {
74             openmode |= OPEN_W;
75         } else {
76             openmode |= OPEN_R;
77         }
78     } else if (flags & O_WRONLY) {
79         /* write or append */
80         if (flags & O_APPEND) {
81             openmode = OPEN_A;
82         } else {
83             openmode = OPEN_W;
84         }
85     } else if (flags == O_RDONLY) {
86         /* read mode */
87         openmode = OPEN_R;
88     } else {
89         /* invalid flags */
90         openmode = OPEN_INVALID;
91     }
92
93     return openmode;
94 }
95
96 FILEHANDLE local_file_open(const char* name, int flags) {
97     int openmode = posix_to_semihost_open_flags(flags);
98     if (openmode == OPEN_INVALID) {
99         return (FILEHANDLE)NULL;
100     }
101
102     FILEHANDLE fh = semihost_open(name, openmode);
103     if (fh == -1) {
104         return (FILEHANDLE)NULL;
105     }
106
107     return fh;
108 }
109
110 LocalFileHandle::LocalFileHandle(FILEHANDLE fh) : _fh(fh), pos(0) {
111 }
112
113 int LocalFileHandle::close() {
114     int retval = semihost_close(_fh);
115     delete this;
116     return retval;
117 }
118
119 ssize_t LocalFileHandle::write(const void *buffer, size_t length) {
120     ssize_t n = semihost_write(_fh, (const unsigned char*)buffer, length, 0); // number of characters not written
121     n = length - n; // number of characters written
122     pos += n;
123     return n;
124 }
125
126 ssize_t LocalFileHandle::read(void *buffer, size_t length) {
127     ssize_t n = semihost_read(_fh, (unsigned char*)buffer, length, 0); // number of characters not read
128     n = length - n; // number of characters read
129     pos += n;
130     return n;
131 }
132
133 int LocalFileHandle::isatty() {
134     return semihost_istty(_fh);
135 }
136
137 off_t LocalFileHandle::lseek(off_t position, int whence) {
138     if (whence == SEEK_CUR) {
139         position += pos;
140     } else if (whence == SEEK_END) {
141         position += semihost_flen(_fh);
142     } /* otherwise SEEK_SET, so position is fine */
143
144     /* Always seems to return -1, so just ignore for now. */
145     semihost_seek(_fh, position);
146     pos = position;
147     return position;
148 }
149
150 int LocalFileHandle::fsync() {
151     return semihost_ensure(_fh);
152 }
153
154 off_t LocalFileHandle::flen() {
155     return semihost_flen(_fh);
156 }
157
158 class LocalDirHandle : public DirHandle {
159
160 public:
161     struct dirent cur_entry;
162     XFINFO info;
163
164     LocalDirHandle() : cur_entry(), info() {
165     }
166
167     virtual int closedir() {
168         delete this;
169         return 0;
170     }
171
172     virtual struct dirent *readdir() {
173         if (xffind("*", &info)!=0) {
174             return NULL;
175         }
176         memcpy(cur_entry.d_name, info.name, sizeof(info.name));
177         return &cur_entry;
178     }
179
180     virtual void rewinddir() {
181         info.fileID = 0;
182     }
183
184     virtual off_t telldir() {
185         return info.fileID;
186     }
187
188     virtual void seekdir(off_t offset) {
189         info.fileID = offset;
190     }
191 };
192
193 FileHandle *LocalFileSystem::open(const char* name, int flags) {
194     /* reject filenames with / in them */
195     for (const char *tmp = name; *tmp; tmp++) {
196         if (*tmp == '/') {
197             return NULL;
198         }
199     }
200
201     int openmode = posix_to_semihost_open_flags(flags);
202     if (openmode == OPEN_INVALID) {
203         return NULL;
204     }
205
206     FILEHANDLE fh = semihost_open(name, openmode);
207     if (fh == -1) {
208         return NULL;
209     }
210     return new LocalFileHandle(fh);
211 }
212
213 int LocalFileSystem::remove(const char *filename) {
214     return semihost_remove(filename);
215 }
216
217 DirHandle *LocalFileSystem::opendir(const char *name) {
218     return new LocalDirHandle();
219 }
220
221 } // namespace mbed
222
223 #endif