Minor code cleanups
[libjaylink.git] / libjaylink / fileio.c
blob28d20bd563e58bc07fd237c38e41add0edd18dd6
1 /*
2 * This file is part of the libjaylink project.
4 * Copyright (C) 2015 Marc Schink <jaylink-dev@marcschink.de>
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include <stddef.h>
21 #include <string.h>
22 #include <stdint.h>
23 #include <stdbool.h>
25 #include "libjaylink.h"
26 #include "libjaylink-internal.h"
28 /**
29 * @file
31 * File I/O functions.
34 /** @cond PRIVATE */
35 #define CMD_FILE_IO 0x1e
37 #define FILE_IO_CMD_READ 0x64
38 #define FILE_IO_CMD_WRITE 0x65
39 #define FILE_IO_CMD_GET_SIZE 0x66
40 #define FILE_IO_CMD_DELETE 0x67
42 #define FILE_IO_PARAM_FILENAME 0x01
43 #define FILE_IO_PARAM_OFFSET 0x02
44 #define FILE_IO_PARAM_LENGTH 0x03
46 #define FILE_IO_ERR 0x80000000
47 /** @endcond */
49 /**
50 * Read from a file.
52 * The maximum amount of data that can be read from a file at once is
53 * #JAYLINK_FILE_MAX_TRANSFER_SIZE bytes. Multiple reads in conjunction with
54 * the @p offset parameter are needed for larger files.
56 * @note This function must only be used if the device has the
57 * #JAYLINK_DEV_CAP_FILE_IO capability.
59 * @param[in,out] devh Device handle.
60 * @param[in] filename Name of the file to read from. The length of the name
61 * must not exceed #JAYLINK_FILE_NAME_MAX_LENGTH bytes.
62 * @param[out] buffer Buffer to store read data.
63 * @param[in] offset Offset in bytes relative to the beginning of the file from
64 * where to start reading.
65 * @param[in,out] length Number of bytes to read. On success, the value gets
66 * updated with the actual number of bytes read. The
67 * value is undefined on failure.
68 * @retval JAYLINK_OK Success.
69 * @retval JAYLINK_ERR_ARG Invalid arguments.
70 * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
71 * @retval JAYLINK_ERR_DEV Unspecified device error, or the file was not found.
72 * @retval JAYLINK_ERR Other error conditions.
74 * @since 0.1.0
76 JAYLINK_API int jaylink_file_read(struct jaylink_device_handle *devh,
77 const char *filename, uint8_t *buffer, uint32_t offset,
78 uint32_t *length)
80 int ret;
81 struct jaylink_context *ctx;
82 uint8_t buf[18 + JAYLINK_FILE_NAME_MAX_LENGTH];
83 size_t filename_length;
84 uint32_t tmp;
86 if (!devh || !filename || !buffer || !length)
87 return JAYLINK_ERR_ARG;
89 if (!*length)
90 return JAYLINK_ERR_ARG;
92 if (*length > JAYLINK_FILE_MAX_TRANSFER_SIZE)
93 return JAYLINK_ERR_ARG;
95 filename_length = strlen(filename);
97 if (!filename_length)
98 return JAYLINK_ERR_ARG;
100 if (filename_length > JAYLINK_FILE_NAME_MAX_LENGTH)
101 return JAYLINK_ERR_ARG;
103 ctx = devh->dev->ctx;
104 ret = transport_start_write(devh, 18 + filename_length, true);
106 if (ret != JAYLINK_OK) {
107 log_err(ctx, "transport_start_write() failed: %i.", ret);
108 return ret;
111 buf[0] = CMD_FILE_IO;
112 buf[1] = FILE_IO_CMD_READ;
113 buf[2] = 0x00;
115 buf[3] = filename_length;
116 buf[4] = FILE_IO_PARAM_FILENAME;
117 memcpy(buf + 5, filename, filename_length);
119 buf[filename_length + 5] = 0x04;
120 buf[filename_length + 6] = FILE_IO_PARAM_OFFSET;
121 buffer_set_u32(buf, offset, filename_length + 7);
123 buf[filename_length + 11] = 0x04;
124 buf[filename_length + 12] = FILE_IO_PARAM_LENGTH;
125 buffer_set_u32(buf, *length, filename_length + 13);
127 buf[filename_length + 17] = 0x00;
129 ret = transport_write(devh, buf, 18 + filename_length);
131 if (ret != JAYLINK_OK) {
132 log_err(ctx, "transport_write() failed: %i.", ret);
133 return ret;
136 ret = transport_start_read(devh, *length);
138 if (ret != JAYLINK_OK) {
139 log_err(ctx, "transport_start_read() failed: %i.", ret);
140 return ret;
143 ret = transport_read(devh, buffer, *length);
145 if (ret != JAYLINK_OK) {
146 log_err(ctx, "transport_read() failed: %i.", ret);
147 return ret;
150 ret = transport_start_read(devh, 4);
152 if (ret != JAYLINK_OK) {
153 log_err(ctx, "transport_start_read() failed: %i.", ret);
154 return ret;
157 ret = transport_read(devh, buf, 4);
159 if (ret != JAYLINK_OK) {
160 log_err(ctx, "transport_read() failed: %i.", ret);
161 return ret;
164 tmp = buffer_get_u32(buf, 0);
166 if (tmp & FILE_IO_ERR)
167 return JAYLINK_ERR_DEV;
169 *length = tmp;
171 return JAYLINK_OK;
175 * Write to a file.
177 * If a file does not exist, a new file is created.
179 * The maximum amount of data that can be written to a file at once is
180 * #JAYLINK_FILE_MAX_TRANSFER_SIZE bytes. Multiple writes in conjunction with
181 * the @p offset parameter are needed for larger files.
183 * @note This function must only be used if the device has the
184 * #JAYLINK_DEV_CAP_FILE_IO capability.
186 * @param[in,out] devh Device handle.
187 * @param[in] filename Name of the file to write to. The length of the name
188 * must not exceed #JAYLINK_FILE_NAME_MAX_LENGTH bytes.
189 * @param[in] buffer Buffer to write data from.
190 * @param[in] offset Offset in bytes relative to the beginning of the file from
191 * where to start writing.
192 * @param[in,out] length Number of bytes to write. On success, the value gets
193 * updated with the actual number of bytes written. The
194 * value is undefined on failure.
196 * @retval JAYLINK_OK Success.
197 * @retval JAYLINK_ERR_ARG Invalid arguments.
198 * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
199 * @retval JAYLINK_ERR_DEV Unspecified device error, or the file was not found.
200 * @retval JAYLINK_ERR Other error conditions.
202 * @since 0.1.0
204 JAYLINK_API int jaylink_file_write(struct jaylink_device_handle *devh,
205 const char *filename, const uint8_t *buffer, uint32_t offset,
206 uint32_t *length)
208 int ret;
209 struct jaylink_context *ctx;
210 uint8_t buf[18 + JAYLINK_FILE_NAME_MAX_LENGTH];
211 size_t filename_length;
212 uint32_t tmp;
214 if (!devh || !filename || !buffer || !length)
215 return JAYLINK_ERR_ARG;
217 if (!*length)
218 return JAYLINK_ERR_ARG;
220 if (*length > JAYLINK_FILE_MAX_TRANSFER_SIZE)
221 return JAYLINK_ERR_ARG;
223 filename_length = strlen(filename);
225 if (!filename_length)
226 return JAYLINK_ERR_ARG;
228 if (filename_length > JAYLINK_FILE_NAME_MAX_LENGTH)
229 return JAYLINK_ERR_ARG;
231 ctx = devh->dev->ctx;
232 ret = transport_start_write(devh, 18 + filename_length, true);
234 if (ret != JAYLINK_OK) {
235 log_err(ctx, "transport_start_write() failed: %i.", ret);
236 return ret;
239 buf[0] = CMD_FILE_IO;
240 buf[1] = FILE_IO_CMD_WRITE;
241 buf[2] = 0x00;
243 buf[3] = filename_length;
244 buf[4] = FILE_IO_PARAM_FILENAME;
245 memcpy(buf + 5, filename, filename_length);
247 buf[filename_length + 5] = 0x04;
248 buf[filename_length + 6] = FILE_IO_PARAM_OFFSET;
249 buffer_set_u32(buf, offset, filename_length + 7);
251 buf[filename_length + 11] = 0x04;
252 buf[filename_length + 12] = FILE_IO_PARAM_LENGTH;
253 buffer_set_u32(buf, *length, filename_length + 13);
255 buf[filename_length + 17] = 0x00;
257 ret = transport_write(devh, buf, 18 + filename_length);
259 if (ret != JAYLINK_OK) {
260 log_err(ctx, "transport_write() failed: %i.", ret);
261 return ret;
264 ret = transport_start_write(devh, *length, true);
266 if (ret != JAYLINK_OK) {
267 log_err(ctx, "transport_start_write() failed: %i.", ret);
268 return ret;
271 ret = transport_write(devh, buffer, *length);
273 if (ret != JAYLINK_OK) {
274 log_err(ctx, "transport_write() failed: %i.", ret);
275 return ret;
278 ret = transport_start_read(devh, 4);
280 if (ret != JAYLINK_OK) {
281 log_err(ctx, "transport_start_read() failed: %i.", ret);
282 return ret;
285 ret = transport_read(devh, buf, 4);
287 if (ret != JAYLINK_OK) {
288 log_err(ctx, "transport_read() failed: %i.", ret);
289 return ret;
292 tmp = buffer_get_u32(buf, 0);
294 if (tmp & FILE_IO_ERR)
295 return JAYLINK_ERR_DEV;
297 *length = tmp;
299 return JAYLINK_OK;
303 * Retrieve the size of a file.
305 * @note This function must only be used if the device has the
306 * #JAYLINK_DEV_CAP_FILE_IO capability.
308 * @param[in,out] devh Device handle.
309 * @param[in] filename Name of the file to retrieve the size of. The length
310 * of the name must not exceed
311 * #JAYLINK_FILE_NAME_MAX_LENGTH bytes.
312 * @param[out] size Size of the file in bytes on success, and undefined on
313 * failure.
315 * @retval JAYLINK_OK Success.
316 * @retval JAYLINK_ERR_ARG Invalid arguments.
317 * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
318 * @retval JAYLINK_ERR_DEV Unspecified device error, or the file was not found.
319 * @retval JAYLINK_ERR Other error conditions.
321 * @since 0.1.0
323 JAYLINK_API int jaylink_file_get_size(struct jaylink_device_handle *devh,
324 const char *filename, uint32_t *size)
326 int ret;
327 struct jaylink_context *ctx;
328 uint8_t buf[6 + JAYLINK_FILE_NAME_MAX_LENGTH];
329 size_t length;
330 uint32_t tmp;
332 if (!devh || !filename || !size)
333 return JAYLINK_ERR_ARG;
335 length = strlen(filename);
337 if (!length)
338 return JAYLINK_ERR_ARG;
340 if (length > JAYLINK_FILE_NAME_MAX_LENGTH)
341 return JAYLINK_ERR_ARG;
343 ctx = devh->dev->ctx;
344 ret = transport_start_write(devh, 6 + length, true);
346 if (ret != JAYLINK_OK) {
347 log_err(ctx, "transport_start_write() failed: %i.", ret);
348 return ret;
351 buf[0] = CMD_FILE_IO;
352 buf[1] = FILE_IO_CMD_GET_SIZE;
353 buf[2] = 0x00;
355 buf[3] = length;
356 buf[4] = FILE_IO_PARAM_FILENAME;
357 memcpy(buf + 5, filename, length);
359 buf[length + 5] = 0x00;
361 ret = transport_write(devh, buf, 6 + length);
363 if (ret != JAYLINK_OK) {
364 log_err(ctx, "transport_write() failed: %i.", ret);
365 return ret;
368 ret = transport_start_read(devh, 4);
370 if (ret != JAYLINK_OK) {
371 log_err(ctx, "transport_start_read() failed: %i.", ret);
372 return ret;
375 ret = transport_read(devh, buf, 4);
377 if (ret != JAYLINK_OK) {
378 log_err(ctx, "transport_read() failed: %i.", ret);
379 return ret;
382 tmp = buffer_get_u32(buf, 0);
384 if (tmp & FILE_IO_ERR)
385 return JAYLINK_ERR_DEV;
387 *size = tmp;
389 return JAYLINK_OK;
393 * Delete a file.
395 * @note This function must only be used if the device has the
396 * #JAYLINK_DEV_CAP_FILE_IO capability.
398 * @param[in,out] devh Device handle.
399 * @param[in] filename Name of the file to delete. The length of the name
400 * must not exceed #JAYLINK_FILE_NAME_MAX_LENGTH bytes.
402 * @retval JAYLINK_OK Success.
403 * @retval JAYLINK_ERR_ARG Invalid arguments.
404 * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
405 * @retval JAYLINK_ERR_DEV Unspecified device error, or the file was not found.
406 * @retval JAYLINK_ERR Other error conditions.
408 * @since 0.1.0
410 JAYLINK_API int jaylink_file_delete(struct jaylink_device_handle *devh,
411 const char *filename)
413 int ret;
414 struct jaylink_context *ctx;
415 uint8_t buf[6 + JAYLINK_FILE_NAME_MAX_LENGTH];
416 size_t length;
417 uint32_t tmp;
419 if (!devh || !filename)
420 return JAYLINK_ERR_ARG;
422 length = strlen(filename);
424 if (!length)
425 return JAYLINK_ERR_ARG;
427 if (length > JAYLINK_FILE_NAME_MAX_LENGTH)
428 return JAYLINK_ERR_ARG;
430 ctx = devh->dev->ctx;
431 ret = transport_start_write(devh, 6 + length, true);
433 if (ret != JAYLINK_OK) {
434 log_err(ctx, "transport_start_write() failed: %i.", ret);
435 return ret;
438 buf[0] = CMD_FILE_IO;
439 buf[1] = FILE_IO_CMD_DELETE;
440 buf[2] = 0x00;
442 buf[3] = length;
443 buf[4] = FILE_IO_PARAM_FILENAME;
444 memcpy(buf + 5, filename, length);
446 buf[length + 5] = 0x00;
448 ret = transport_write(devh, buf, 6 + length);
450 if (ret != JAYLINK_OK) {
451 log_err(ctx, "transport_write() failed: %i.", ret);
452 return ret;
455 ret = transport_start_read(devh, 4);
457 if (ret != JAYLINK_OK) {
458 log_err(ctx, "transport_start_read() failed: %i.", ret);
459 return ret;
462 ret = transport_read(devh, buf, 4);
464 if (ret != JAYLINK_OK) {
465 log_err(ctx, "transport_read() failed: %i.", ret);
466 return ret;
469 tmp = buffer_get_u32(buf, 0);
471 if (tmp & FILE_IO_ERR)
472 return JAYLINK_ERR_DEV;
474 return JAYLINK_OK;