Semihosted file handles for targets without DEVICE_SEMIHOST or DEVICE_LOCALFILESYSTEM
Revision 0:d5e731da01f0, committed 2017-10-11
- Comitter:
- devanlai
- Date:
- Wed Oct 11 23:14:14 2017 +0000
- Commit message:
- Initial Semihosting file I/O shim for devices without DEVICE_SEMIHOST and DEVICE_LOCALFILESYSTEM
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/SemihostedFileSystem.cpp Wed Oct 11 23:14:14 2017 +0000
@@ -0,0 +1,179 @@
+/* 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 "SemihostedFileSystem.h"
+#include "mbed_semihost_api_shim.h"
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <cstdarg>
+
+#define STRING_STACK_LIMIT 120
+
+#define OPEN_R 0
+#define OPEN_B 1
+#define OPEN_PLUS 2
+#define OPEN_W 4
+#define OPEN_A 8
+#define OPEN_INVALID -1
+
+static 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 semihosted_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;
+}
+
+SemihostedFileHandle::SemihostedFileHandle(FILEHANDLE fh) : _fh(fh), pos(0) {
+ // No lock needed in constructor
+}
+
+SemihostedFileHandle::SemihostedFileHandle(const char* name, int flags)
+ : _fh(semihosted_file_open(name, flags)), pos(0) {
+ // No lock needed in constructor
+}
+
+int SemihostedFileHandle::close() {
+ int retval = semihost_close(_fh);
+ delete this;
+ return retval;
+}
+
+ssize_t SemihostedFileHandle::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 SemihostedFileHandle::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 SemihostedFileHandle::isatty() {
+ lock();
+ int ret = semihost_istty(_fh);
+ unlock();
+ return ret;
+}
+
+off_t SemihostedFileHandle::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 SemihostedFileHandle::sync() {
+ lock();
+ int ret = semihost_ensure(_fh);
+ unlock();
+ return ret;
+}
+
+off_t SemihostedFileHandle::size() {
+ lock();
+ off_t off = semihost_flen(_fh);
+ unlock();
+ return off;
+}
+
+void SemihostedFileHandle::lock() {
+ _mutex.lock();
+}
+
+void SemihostedFileHandle::unlock() {
+ _mutex.unlock();
+}
+
+// Experimental support for printf in RawSerial. No Stream inheritance
+// means we can't call printf() directly, so we use sprintf() instead.
+// We only call malloc() for the sprintf() buffer if the buffer
+// length is above a certain threshold, otherwise we use just the stack.
+int SemihostedFileHandle::printf(const char *format, ...) {
+ lock();
+ std::va_list arg;
+ va_start(arg, format);
+ // ARMCC microlib does not properly handle a size of 0.
+ // As a workaround supply a dummy buffer with a size of 1.
+ char dummy_buf[1];
+ int len = vsnprintf(dummy_buf, sizeof(dummy_buf), format, arg);
+ if (len < STRING_STACK_LIMIT) {
+ char temp[STRING_STACK_LIMIT];
+ vsprintf(temp, format, arg);
+ write(temp, len);
+ } else {
+ char *temp = new char[len + 1];
+ vsprintf(temp, format, arg);
+ write(temp, len);
+ delete[] temp;
+ }
+ va_end(arg);
+ unlock();
+ return len;
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/SemihostedFileSystem.h Wed Oct 11 23:14:14 2017 +0000
@@ -0,0 +1,65 @@
+/* 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.
+ */
+#ifndef SEMIHOSTEDFILESYSTEM_H
+#define SEMIHOSTEDFILESYSTEM_H
+
+#include "platform/platform.h"
+
+#include "platform/FileSystemLike.h"
+#include "platform/PlatformMutex.h"
+#include "platform/NonCopyable.h"
+
+/** \addtogroup platform */
+/** @{*/
+
+FILEHANDLE semihosted_file_open(const char* name, int flags);
+/** @}*/
+
+/**
+ * @class SemihostedFileHandle
+ * @ingroup platform
+ */
+class SemihostedFileHandle : public mbed::FileHandle, private mbed::NonCopyable<SemihostedFileHandle> {
+
+public:
+ SemihostedFileHandle(FILEHANDLE fh);
+ SemihostedFileHandle(const char* name, int flags);
+
+ virtual int close();
+
+ virtual ssize_t write(const void *buffer, size_t length);
+
+ virtual ssize_t read(void *buffer, size_t length);
+
+ virtual int isatty();
+
+ virtual off_t seek(off_t position, int whence);
+
+ virtual int sync();
+
+ virtual off_t size();
+
+ int printf(const char *format, ...);
+
+protected:
+ virtual void lock();
+ virtual void unlock();
+ FILEHANDLE _fh;
+ int pos;
+ PlatformMutex _mutex;
+};
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed_semihost_api_shim.c Wed Oct 11 23:14:14 2017 +0000
@@ -0,0 +1,101 @@
+/* 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 "cmsis.h"
+#include "mbed_semihost_api_shim.h"
+
+#include <stdint.h>
+#include <string.h>
+
+// ARM Semihosting Commands
+#define SYS_OPEN (0x1)
+#define SYS_CLOSE (0x2)
+#define SYS_WRITE (0x5)
+#define SYS_READ (0x6)
+#define SYS_ISTTY (0x9)
+#define SYS_SEEK (0xa)
+#define SYS_ENSURE (0xb)
+#define SYS_FLEN (0xc)
+#define SYS_REMOVE (0xe)
+#define SYS_RENAME (0xf)
+#define SYS_EXIT (0x18)
+
+#if !DEVICE_LOCALFILESYSTEM
+FILEHANDLE semihost_open(const char* name, int openmode) {
+ uint32_t args[3];
+ args[0] = (uint32_t)name;
+ args[1] = (uint32_t)openmode;
+ args[2] = (uint32_t)strlen(name);
+ return __semihost(SYS_OPEN, args);
+}
+
+int semihost_close(FILEHANDLE fh) {
+ return __semihost(SYS_CLOSE, &fh);
+}
+
+int semihost_write(FILEHANDLE fh, const unsigned char* buffer, unsigned int length, int mode) {
+ if (length == 0) return 0;
+
+ uint32_t args[3];
+ args[0] = (uint32_t)fh;
+ args[1] = (uint32_t)buffer;
+ args[2] = (uint32_t)length;
+ return __semihost(SYS_WRITE, args);
+}
+
+int semihost_read(FILEHANDLE fh, unsigned char* buffer, unsigned int length, int mode) {
+ uint32_t args[3];
+ args[0] = (uint32_t)fh;
+ args[1] = (uint32_t)buffer;
+ args[2] = (uint32_t)length;
+ return __semihost(SYS_READ, args);
+}
+
+int semihost_istty(FILEHANDLE fh) {
+ return __semihost(SYS_ISTTY, &fh);
+}
+
+int semihost_seek(FILEHANDLE fh, long position) {
+ uint32_t args[2];
+ args[0] = (uint32_t)fh;
+ args[1] = (uint32_t)position;
+ return __semihost(SYS_SEEK, args);
+}
+
+int semihost_ensure(FILEHANDLE fh) {
+ return __semihost(SYS_ENSURE, &fh);
+}
+
+long semihost_flen(FILEHANDLE fh) {
+ return __semihost(SYS_FLEN, &fh);
+}
+
+int semihost_remove(const char *name) {
+ uint32_t args[2];
+ args[0] = (uint32_t)name;
+ args[1] = (uint32_t)strlen(name);
+ return __semihost(SYS_REMOVE, args);
+}
+
+int semihost_rename(const char *old_name, const char *new_name) {
+ uint32_t args[4];
+ args[0] = (uint32_t)old_name;
+ args[1] = (uint32_t)strlen(old_name);
+ args[0] = (uint32_t)new_name;
+ args[1] = (uint32_t)strlen(new_name);
+ return __semihost(SYS_RENAME, args);
+}
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed_semihost_api_shim.h Wed Oct 11 23:14:14 2017 +0000
@@ -0,0 +1,51 @@
+
+/** \addtogroup platform */
+/** @{*/
+/* 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.
+ */
+#ifndef MBED_SEMIHOST_SHIM_H
+#define MBED_SEMIHOST_SHIM_H
+
+#include "device.h"
+#include "platform/mbed_toolchain.h"
+
+#include "platform/mbed_semihost_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if !DEVICE_LOCALFILESYSTEM
+FILEHANDLE semihost_open(const char* name, int openmode);
+int semihost_close (FILEHANDLE fh);
+int semihost_read (FILEHANDLE fh, unsigned char* buffer, unsigned int length, int mode);
+int semihost_write (FILEHANDLE fh, const unsigned char* buffer, unsigned int length, int mode);
+int semihost_ensure(FILEHANDLE fh);
+long semihost_flen (FILEHANDLE fh);
+int semihost_seek (FILEHANDLE fh, long position);
+int semihost_istty (FILEHANDLE fh);
+
+int semihost_remove(const char *name);
+int semihost_rename(const char *old_name, const char *new_name);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/** @}*/
\ No newline at end of file