Semihosted file handles for targets without DEVICE_SEMIHOST or DEVICE_LOCALFILESYSTEM

Dependents:   SemihostingTest

Committer:
devanlai
Date:
Wed Oct 11 23:14:14 2017 +0000
Revision:
0:d5e731da01f0
Initial Semihosting file I/O shim for devices without DEVICE_SEMIHOST and DEVICE_LOCALFILESYSTEM

Who changed what in which revision?

UserRevisionLine numberNew contents of line
devanlai 0:d5e731da01f0 1 /* mbed Microcontroller Library
devanlai 0:d5e731da01f0 2 * Copyright (c) 2006-2013 ARM Limited
devanlai 0:d5e731da01f0 3 *
devanlai 0:d5e731da01f0 4 * Licensed under the Apache License, Version 2.0 (the "License");
devanlai 0:d5e731da01f0 5 * you may not use this file except in compliance with the License.
devanlai 0:d5e731da01f0 6 * You may obtain a copy of the License at
devanlai 0:d5e731da01f0 7 *
devanlai 0:d5e731da01f0 8 * http://www.apache.org/licenses/LICENSE-2.0
devanlai 0:d5e731da01f0 9 *
devanlai 0:d5e731da01f0 10 * Unless required by applicable law or agreed to in writing, software
devanlai 0:d5e731da01f0 11 * distributed under the License is distributed on an "AS IS" BASIS,
devanlai 0:d5e731da01f0 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
devanlai 0:d5e731da01f0 13 * See the License for the specific language governing permissions and
devanlai 0:d5e731da01f0 14 * limitations under the License.
devanlai 0:d5e731da01f0 15 */
devanlai 0:d5e731da01f0 16 #include "SemihostedFileSystem.h"
devanlai 0:d5e731da01f0 17 #include "mbed_semihost_api_shim.h"
devanlai 0:d5e731da01f0 18 #include <string.h>
devanlai 0:d5e731da01f0 19 #include <stdio.h>
devanlai 0:d5e731da01f0 20 #include <errno.h>
devanlai 0:d5e731da01f0 21 #include <cstdarg>
devanlai 0:d5e731da01f0 22
devanlai 0:d5e731da01f0 23 #define STRING_STACK_LIMIT 120
devanlai 0:d5e731da01f0 24
devanlai 0:d5e731da01f0 25 #define OPEN_R 0
devanlai 0:d5e731da01f0 26 #define OPEN_B 1
devanlai 0:d5e731da01f0 27 #define OPEN_PLUS 2
devanlai 0:d5e731da01f0 28 #define OPEN_W 4
devanlai 0:d5e731da01f0 29 #define OPEN_A 8
devanlai 0:d5e731da01f0 30 #define OPEN_INVALID -1
devanlai 0:d5e731da01f0 31
devanlai 0:d5e731da01f0 32 static int posix_to_semihost_open_flags(int flags) {
devanlai 0:d5e731da01f0 33 /* POSIX flags -> semihosting open mode */
devanlai 0:d5e731da01f0 34 int openmode;
devanlai 0:d5e731da01f0 35 if (flags & O_RDWR) {
devanlai 0:d5e731da01f0 36 /* a plus mode */
devanlai 0:d5e731da01f0 37 openmode = OPEN_PLUS;
devanlai 0:d5e731da01f0 38 if (flags & O_APPEND) {
devanlai 0:d5e731da01f0 39 openmode |= OPEN_A;
devanlai 0:d5e731da01f0 40 } else if (flags & O_TRUNC) {
devanlai 0:d5e731da01f0 41 openmode |= OPEN_W;
devanlai 0:d5e731da01f0 42 } else {
devanlai 0:d5e731da01f0 43 openmode |= OPEN_R;
devanlai 0:d5e731da01f0 44 }
devanlai 0:d5e731da01f0 45 } else if (flags & O_WRONLY) {
devanlai 0:d5e731da01f0 46 /* write or append */
devanlai 0:d5e731da01f0 47 if (flags & O_APPEND) {
devanlai 0:d5e731da01f0 48 openmode = OPEN_A;
devanlai 0:d5e731da01f0 49 } else {
devanlai 0:d5e731da01f0 50 openmode = OPEN_W;
devanlai 0:d5e731da01f0 51 }
devanlai 0:d5e731da01f0 52 } else if (flags == O_RDONLY) {
devanlai 0:d5e731da01f0 53 /* read mode */
devanlai 0:d5e731da01f0 54 openmode = OPEN_R;
devanlai 0:d5e731da01f0 55 } else {
devanlai 0:d5e731da01f0 56 /* invalid flags */
devanlai 0:d5e731da01f0 57 openmode = OPEN_INVALID;
devanlai 0:d5e731da01f0 58 }
devanlai 0:d5e731da01f0 59
devanlai 0:d5e731da01f0 60 return openmode;
devanlai 0:d5e731da01f0 61 }
devanlai 0:d5e731da01f0 62
devanlai 0:d5e731da01f0 63 FILEHANDLE semihosted_file_open(const char* name, int flags) {
devanlai 0:d5e731da01f0 64 int openmode = posix_to_semihost_open_flags(flags);
devanlai 0:d5e731da01f0 65 if (openmode == OPEN_INVALID) {
devanlai 0:d5e731da01f0 66 return (FILEHANDLE)NULL;
devanlai 0:d5e731da01f0 67 }
devanlai 0:d5e731da01f0 68
devanlai 0:d5e731da01f0 69 FILEHANDLE fh = semihost_open(name, openmode);
devanlai 0:d5e731da01f0 70 if (fh == -1) {
devanlai 0:d5e731da01f0 71 return (FILEHANDLE)NULL;
devanlai 0:d5e731da01f0 72 }
devanlai 0:d5e731da01f0 73
devanlai 0:d5e731da01f0 74 return fh;
devanlai 0:d5e731da01f0 75 }
devanlai 0:d5e731da01f0 76
devanlai 0:d5e731da01f0 77 SemihostedFileHandle::SemihostedFileHandle(FILEHANDLE fh) : _fh(fh), pos(0) {
devanlai 0:d5e731da01f0 78 // No lock needed in constructor
devanlai 0:d5e731da01f0 79 }
devanlai 0:d5e731da01f0 80
devanlai 0:d5e731da01f0 81 SemihostedFileHandle::SemihostedFileHandle(const char* name, int flags)
devanlai 0:d5e731da01f0 82 : _fh(semihosted_file_open(name, flags)), pos(0) {
devanlai 0:d5e731da01f0 83 // No lock needed in constructor
devanlai 0:d5e731da01f0 84 }
devanlai 0:d5e731da01f0 85
devanlai 0:d5e731da01f0 86 int SemihostedFileHandle::close() {
devanlai 0:d5e731da01f0 87 int retval = semihost_close(_fh);
devanlai 0:d5e731da01f0 88 delete this;
devanlai 0:d5e731da01f0 89 return retval;
devanlai 0:d5e731da01f0 90 }
devanlai 0:d5e731da01f0 91
devanlai 0:d5e731da01f0 92 ssize_t SemihostedFileHandle::write(const void *buffer, size_t length) {
devanlai 0:d5e731da01f0 93 lock();
devanlai 0:d5e731da01f0 94 ssize_t n = semihost_write(_fh, (const unsigned char*)buffer, length, 0); // number of characters not written
devanlai 0:d5e731da01f0 95 n = length - n; // number of characters written
devanlai 0:d5e731da01f0 96 pos += n;
devanlai 0:d5e731da01f0 97 unlock();
devanlai 0:d5e731da01f0 98 return n;
devanlai 0:d5e731da01f0 99 }
devanlai 0:d5e731da01f0 100
devanlai 0:d5e731da01f0 101 ssize_t SemihostedFileHandle::read(void *buffer, size_t length) {
devanlai 0:d5e731da01f0 102 lock();
devanlai 0:d5e731da01f0 103 ssize_t n = semihost_read(_fh, (unsigned char*)buffer, length, 0); // number of characters not read
devanlai 0:d5e731da01f0 104 n = length - n; // number of characters read
devanlai 0:d5e731da01f0 105 pos += n;
devanlai 0:d5e731da01f0 106 unlock();
devanlai 0:d5e731da01f0 107 return n;
devanlai 0:d5e731da01f0 108 }
devanlai 0:d5e731da01f0 109
devanlai 0:d5e731da01f0 110 int SemihostedFileHandle::isatty() {
devanlai 0:d5e731da01f0 111 lock();
devanlai 0:d5e731da01f0 112 int ret = semihost_istty(_fh);
devanlai 0:d5e731da01f0 113 unlock();
devanlai 0:d5e731da01f0 114 return ret;
devanlai 0:d5e731da01f0 115 }
devanlai 0:d5e731da01f0 116
devanlai 0:d5e731da01f0 117 off_t SemihostedFileHandle::seek(off_t position, int whence) {
devanlai 0:d5e731da01f0 118 lock();
devanlai 0:d5e731da01f0 119 if (whence == SEEK_CUR) {
devanlai 0:d5e731da01f0 120 position += pos;
devanlai 0:d5e731da01f0 121 } else if (whence == SEEK_END) {
devanlai 0:d5e731da01f0 122 position += semihost_flen(_fh);
devanlai 0:d5e731da01f0 123 } /* otherwise SEEK_SET, so position is fine */
devanlai 0:d5e731da01f0 124
devanlai 0:d5e731da01f0 125 /* Always seems to return -1, so just ignore for now. */
devanlai 0:d5e731da01f0 126 semihost_seek(_fh, position);
devanlai 0:d5e731da01f0 127 pos = position;
devanlai 0:d5e731da01f0 128 unlock();
devanlai 0:d5e731da01f0 129 return position;
devanlai 0:d5e731da01f0 130 }
devanlai 0:d5e731da01f0 131
devanlai 0:d5e731da01f0 132 int SemihostedFileHandle::sync() {
devanlai 0:d5e731da01f0 133 lock();
devanlai 0:d5e731da01f0 134 int ret = semihost_ensure(_fh);
devanlai 0:d5e731da01f0 135 unlock();
devanlai 0:d5e731da01f0 136 return ret;
devanlai 0:d5e731da01f0 137 }
devanlai 0:d5e731da01f0 138
devanlai 0:d5e731da01f0 139 off_t SemihostedFileHandle::size() {
devanlai 0:d5e731da01f0 140 lock();
devanlai 0:d5e731da01f0 141 off_t off = semihost_flen(_fh);
devanlai 0:d5e731da01f0 142 unlock();
devanlai 0:d5e731da01f0 143 return off;
devanlai 0:d5e731da01f0 144 }
devanlai 0:d5e731da01f0 145
devanlai 0:d5e731da01f0 146 void SemihostedFileHandle::lock() {
devanlai 0:d5e731da01f0 147 _mutex.lock();
devanlai 0:d5e731da01f0 148 }
devanlai 0:d5e731da01f0 149
devanlai 0:d5e731da01f0 150 void SemihostedFileHandle::unlock() {
devanlai 0:d5e731da01f0 151 _mutex.unlock();
devanlai 0:d5e731da01f0 152 }
devanlai 0:d5e731da01f0 153
devanlai 0:d5e731da01f0 154 // Experimental support for printf in RawSerial. No Stream inheritance
devanlai 0:d5e731da01f0 155 // means we can't call printf() directly, so we use sprintf() instead.
devanlai 0:d5e731da01f0 156 // We only call malloc() for the sprintf() buffer if the buffer
devanlai 0:d5e731da01f0 157 // length is above a certain threshold, otherwise we use just the stack.
devanlai 0:d5e731da01f0 158 int SemihostedFileHandle::printf(const char *format, ...) {
devanlai 0:d5e731da01f0 159 lock();
devanlai 0:d5e731da01f0 160 std::va_list arg;
devanlai 0:d5e731da01f0 161 va_start(arg, format);
devanlai 0:d5e731da01f0 162 // ARMCC microlib does not properly handle a size of 0.
devanlai 0:d5e731da01f0 163 // As a workaround supply a dummy buffer with a size of 1.
devanlai 0:d5e731da01f0 164 char dummy_buf[1];
devanlai 0:d5e731da01f0 165 int len = vsnprintf(dummy_buf, sizeof(dummy_buf), format, arg);
devanlai 0:d5e731da01f0 166 if (len < STRING_STACK_LIMIT) {
devanlai 0:d5e731da01f0 167 char temp[STRING_STACK_LIMIT];
devanlai 0:d5e731da01f0 168 vsprintf(temp, format, arg);
devanlai 0:d5e731da01f0 169 write(temp, len);
devanlai 0:d5e731da01f0 170 } else {
devanlai 0:d5e731da01f0 171 char *temp = new char[len + 1];
devanlai 0:d5e731da01f0 172 vsprintf(temp, format, arg);
devanlai 0:d5e731da01f0 173 write(temp, len);
devanlai 0:d5e731da01f0 174 delete[] temp;
devanlai 0:d5e731da01f0 175 }
devanlai 0:d5e731da01f0 176 va_end(arg);
devanlai 0:d5e731da01f0 177 unlock();
devanlai 0:d5e731da01f0 178 return len;
devanlai 0:d5e731da01f0 179 }