1/*
2 Copyright (c) 2013 Arduino LLC. All right reserved.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17*/
18
19#include <FileIO.h>
20
21namespace BridgeLib {
22
23File::File(BridgeClass &b) : bridge(b), mode(255) {
24 // Empty
25}
26
27File::File(const char *_filename, uint8_t _mode, BridgeClass &b) : bridge(b), mode(_mode) {
28 filename = _filename;
29 uint8_t modes[] = {'r', 'w', 'a'};
30 uint8_t cmd[] = {'F', modes[mode]};
31 uint8_t res[2];
32 dirPosition = 1;
33 bridge.transfer(cmd, 2, (uint8_t*)filename.c_str(), filename.length(), res, 2);
34 if (res[0] != 0) { // res[0] contains error code
35 mode = 255; // In case of error keep the file closed
36 return;
37 }
38 handle = res[1];
39 buffered = 0;
40}
41
42File::operator bool() {
43 return (mode != 255);
44}
45
46File::~File() {
47 close();
48}
49
50size_t File::write(uint8_t c) {
51 return write(&c, 1);
52}
53
54size_t File::write(const uint8_t *buf, size_t size) {
55 if (mode == 255)
56 return -1;
57 uint8_t cmd[] = {'g', handle};
58 uint8_t res[1];
59 bridge.transfer(cmd, 2, buf, size, res, 1);
60 if (res[0] != 0) // res[0] contains error code
61 return -res[0];
62 return size;
63}
64
65int File::read() {
66 doBuffer();
67 if (buffered == 0)
68 return -1; // no chars available
69 else {
70 buffered--;
71 return buffer[readPos++];
72 }
73}
74
75int File::peek() {
76 doBuffer();
77 if (buffered == 0)
78 return -1; // no chars available
79 else
80 return buffer[readPos];
81}
82
83boolean File::seek(uint32_t position) {
84 uint8_t cmd[] = {
85 's',
86 handle,
87 static_cast<uint8_t>(position >> 24),
88 static_cast<uint8_t>(position >> 16),
89 static_cast<uint8_t>(position >> 8),
90 static_cast<uint8_t>(position)
91 };
92 uint8_t res[1];
93 bridge.transfer(cmd, 6, res, 1);
94 if (res[0] == 0) {
95 // If seek succeed then flush buffers
96 buffered = 0;
97 return true;
98 }
99 return false;
100}
101
102uint32_t File::position() {
103 uint8_t cmd[] = {'S', handle};
104 uint8_t res[5];
105 bridge.transfer(cmd, 2, res, 5);
106 //err = res[0]; // res[0] contains error code
107 uint32_t pos;
108 pos = static_cast<uint32_t>(res[1]) << 24;
109 pos += static_cast<uint32_t>(res[2]) << 16;
110 pos += static_cast<uint32_t>(res[3]) << 8;
111 pos += static_cast<uint32_t>(res[4]);
112 return pos - buffered;
113}
114
115void File::doBuffer() {
116 // If there are already char in buffer exit
117 if (buffered > 0)
118 return;
119
120 // Try to buffer up to BUFFER_SIZE characters
121 readPos = 0;
122 uint8_t cmd[] = {'G', handle, BUFFER_SIZE - 1};
123 uint16_t readed = bridge.transfer(cmd, 3, buffer, BUFFER_SIZE);
124 //err = buff[0]; // First byte is error code
125 if (readed == BridgeClass::TRANSFER_TIMEOUT || readed == 0) {
126 // transfer failed to retrieve any data
127 buffered = 0;
128 } else {
129 // transfer retrieved at least one byte of data so skip the error code character
130 readPos++;
131 buffered = readed - 1;
132 }
133}
134
135int File::available() {
136 // Look if there is new data available
137 doBuffer();
138 return buffered;
139}
140
141void File::flush() {
142}
143
144int File::read(void *buff, uint16_t nbyte) {
145 uint16_t n = 0;
146 uint8_t *p = reinterpret_cast<uint8_t *>(buff);
147 while (n < nbyte) {
148 if (buffered == 0) {
149 doBuffer();
150 if (buffered == 0)
151 break;
152 }
153 *p++ = buffer[readPos++];
154 buffered--;
155 n++;
156 }
157 return n;
158}
159
160uint32_t File::size() {
161 if (bridge.getBridgeVersion() < 101)
162 return 0;
163 uint8_t cmd[] = {'t', handle};
164 uint8_t buff[5];
165 bridge.transfer(cmd, 2, buff, 5);
166 //err = res[0]; // First byte is error code
167 uint32_t res;
168 res = ((uint32_t)buff[1]) << 24;
169 res |= ((uint32_t)buff[2]) << 16;
170 res |= ((uint32_t)buff[3]) << 8;
171 res |= ((uint32_t)buff[4]);
172 return res;
173}
174
175void File::close() {
176 if (mode == 255)
177 return;
178 uint8_t cmd[] = {'f', handle};
179 uint8_t ret[1];
180 bridge.transfer(cmd, 2, ret, 1);
181 mode = 255;
182}
183
184const char *File::name() {
185 return filename.c_str();
186}
187
188
189boolean File::isDirectory() {
190 uint8_t res[1];
191 uint8_t cmd[] = {'i'};
192 if (mode != 255)
193 return 0;
194
195 bridge.transfer(cmd, 1, (uint8_t *)filename.c_str(), filename.length(), res, 1);
196 return res[0];
197}
198
199
200File File::openNextFile(uint8_t mode) {
201 Process awk;
202 char tmp;
203 String command;
204 String filepath;
205 if (dirPosition == 0xFFFF) return File();
206
207 command = "ls ";
208 command += filename;
209 command += " | awk 'NR==";
210 command += dirPosition;
211 command += "'";
212
213 awk.runShellCommand(command);
214
215 while (awk.running());
216
217 command = "";
218
219 while (awk.available()) {
220 tmp = awk.read();
221 if (tmp != '\n') command += tmp;
222 }
223 if (command.length() == 0)
224 return File();
225 dirPosition++;
226 filepath = filename + "/" + command;
227 return File(filepath.c_str(), mode);
228
229}
230
231void File::rewindDirectory(void) {
232 dirPosition = 1;
233}
234
235
236
237
238
239
240boolean FileSystemClass::begin() {
241 return true;
242}
243
244File FileSystemClass::open(const char *filename, uint8_t mode) {
245 return File(filename, mode);
246}
247
248boolean FileSystemClass::exists(const char *filepath) {
249 Process ls;
250 ls.begin("ls");
251 ls.addParameter(filepath);
252 int res = ls.run();
253 return (res == 0);
254}
255
256boolean FileSystemClass::mkdir(const char *filepath) {
257 Process mk;
258 mk.begin("mkdir");
259 mk.addParameter("-p");
260 mk.addParameter(filepath);
261 int res = mk.run();
262 return (res == 0);
263}
264
265boolean FileSystemClass::remove(const char *filepath) {
266 Process rm;
267 rm.begin("rm");
268 rm.addParameter(filepath);
269 int res = rm.run();
270 return (res == 0);
271}
272
273boolean FileSystemClass::rmdir(const char *filepath) {
274 Process rm;
275 rm.begin("rmdir");
276 rm.addParameter(filepath);
277 int res = rm.run();
278 return (res == 0);
279}
280
281FileSystemClass FileSystem;
282
283}