mbed library sources. Supersedes mbed-src.

Dependents:   SPIne CH_Communicatuin_Test CH_Communicatuin_Test2 MCP_SPIne ... more

Fork of mbed-dev-f303 by Ben Katz

Revision:
167:e84263d55307
Parent:
163:74e0ce7f98e8
Child:
168:9672193075cf
diff -r c97ed07ec1a8 -r e84263d55307 platform/mbed_retarget.cpp
--- a/platform/mbed_retarget.cpp	Thu Jun 08 15:02:37 2017 +0100
+++ b/platform/mbed_retarget.cpp	Wed Jun 21 17:46:44 2017 +0100
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 #include "platform/platform.h"
-#include "drivers/FilePath.h"
+#include "platform/FilePath.h"
 #include "hal/serial_api.h"
 #include "platform/mbed_toolchain.h"
 #include "platform/mbed_semihost_api.h"
@@ -23,20 +23,16 @@
 #include "platform/PlatformMutex.h"
 #include "platform/mbed_error.h"
 #include "platform/mbed_stats.h"
-#if MBED_CONF_FILESYSTEM_PRESENT
-#include "filesystem/FileSystem.h"
-#include "filesystem/File.h"
-#include "filesystem/Dir.h"
-#endif
+#include "platform/mbed_critical.h"
 #include <stdlib.h>
 #include <string.h>
+#include <limits.h>
 #if DEVICE_STDIO_MESSAGES
 #include <stdio.h>
 #endif
 #include <errno.h>
 #include "platform/mbed_retarget.h"
 
-
 #if defined(__ARMCC_VERSION)
 #   include <rt_sys.h>
 #   define PREFIX(x)    _sys##x
@@ -76,7 +72,6 @@
 extern const char __stderr_name[] = "/stderr";
 #endif
 
-// Heap limits - only used if set
 unsigned char *mbed_heap_start = 0;
 uint32_t mbed_heap_size = 0;
 
@@ -85,11 +80,11 @@
  * put it in a filehandles array and return the index into that array
  * (or rather index+3, as filehandles 0-2 are stdin/out/err).
  */
-static FileLike *filehandles[OPEN_MAX];
+static FileHandle *filehandles[OPEN_MAX];
 static SingletonPtr<PlatformMutex> filehandle_mutex;
 
 namespace mbed {
-void remove_filehandle(FileLike *file) {
+void remove_filehandle(FileHandle *file) {
     filehandle_mutex->lock();
     /* Remove all open filehandles for this */
     for (unsigned int fh_i = 0; fh_i < sizeof(filehandles)/sizeof(*filehandles); fh_i++) {
@@ -120,7 +115,20 @@
 #endif
 }
 
-#if MBED_CONF_FILESYSTEM_PRESENT
+/**
+ * Sets errno when file opening fails.
+ * Wipes out the filehandle too.
+ *
+ * @param error is a negative error code returned from an mbed function and
+ *              will be negated to store a positive error code in errno
+ */
+static int handle_open_errors(int error, unsigned filehandle_idx) {
+    errno = -error;
+    // Free file handle
+    filehandles[filehandle_idx] = NULL;
+    return -1;
+}
+
 static inline int openmode_to_posix(int openmode) {
     int posix = openmode;
 #ifdef __ARMCC_VERSION
@@ -155,32 +163,6 @@
 #endif
     return posix;
 }
-#endif
-
-extern "C" WEAK void mbed_sdk_init(void);
-extern "C" WEAK void mbed_sdk_init(void) {
-}
-
-#if MBED_CONF_FILESYSTEM_PRESENT
-// Internally used file objects with managed memory on close
-class ManagedFile : public File {
-public:
-    virtual int close() {
-        int err = File::close();
-        delete this;
-        return err;
-    }
-};
-
-class ManagedDir : public Dir {
-public:
-     virtual int close() {
-        int err = Dir::close();
-        delete this;
-        return err;
-    }
-};
-#endif
 
 /* @brief 	standard c library fopen() retargeting function.
  *
@@ -189,7 +171,7 @@
  * @return
  *  On success, a valid FILEHANDLE is returned.
  *  On failure, -1 is returned and errno is set to an appropriate value e.g.
- *   EBADF		a bad file descriptor was found (default errno setting)
+ *   ENOENT	    file not found (default errno setting)
  *	 EMFILE		the maximum number of open files was exceeded.
  *
  * */
@@ -198,11 +180,6 @@
     // Before version 5.03, we were using a patched version of microlib with proper names
     // This is the workaround that the microlib author suggested us
     static int n = 0;
-    static int mbed_sdk_inited = 0;
-    if (!mbed_sdk_inited) {
-        mbed_sdk_inited = 1;
-        mbed_sdk_init();
-    }
     if (!std::strcmp(name, ":tt")) return n++;
     #else
     /* Use the posix convention that stdin,out,err are filehandles 0,1,2.
@@ -219,9 +196,6 @@
     }
     #endif
 
-    /* if something goes wrong and errno is not explicly set, errno will be set to EBADF */
-    errno = EBADF;
-
     // find the first empty slot in filehandles
     filehandle_mutex->lock();
     unsigned int fh_i;
@@ -235,16 +209,16 @@
         filehandle_mutex->unlock();
         return -1;
     }
-    filehandles[fh_i] = (FileLike*)FILE_HANDLE_RESERVED;
+    filehandles[fh_i] = (FileHandle*)FILE_HANDLE_RESERVED;
     filehandle_mutex->unlock();
 
-    FileLike *res = NULL;
+    FileHandle *res = NULL;
 
-    /* FILENAME: ":0x12345678" describes a FileLike* */
+    /* FILENAME: ":0x12345678" describes a FileHandle* */
     if (name[0] == ':') {
         void *p;
-        sscanf(name, ":%p", &p);
-        res = (FileLike*)p;
+        std::sscanf(name, ":%p", &p);
+        res = (FileHandle*)p;
 
     /* FILENAME: "/file_system/file_name" */
     } else {
@@ -253,41 +227,25 @@
         if (!path.exists()) {
             /* The first part of the filename (between first 2 '/') is not a
              * registered mount point in the namespace.
-             * Free file handle.
              */
-            filehandles[fh_i] = NULL;
-            errno = ENOENT;
-            return -1;
-        } else if (path.isFile()) {
+            return handle_open_errors(-ENOENT, fh_i);
+        }
+
+        if (path.isFile()) {
             res = path.file();
-#if MBED_CONF_FILESYSTEM_PRESENT
         } else {
-            FileSystem *fs = path.fileSystem();
+            FileSystemHandle *fs = path.fileSystem();
             if (fs == NULL) {
-                /* The filesystem instance managing the namespace under the mount point
-                 * has not been found. Free file handle */
-                errno = ENOENT;
-                filehandles[fh_i] = NULL;
-                return -1;
+                return handle_open_errors(-ENOENT, fh_i);
             }
             int posix_mode = openmode_to_posix(openmode);
-            File *file = new ManagedFile;
-            int err = file->open(fs, path.fileName(), posix_mode);
-            if (err < 0) {
-                errno = -err;
-                delete file;
-            } else {
-                res = file;
+            int err = fs->open(&res, path.fileName(), posix_mode);
+            if (err) {
+                return handle_open_errors(err, fh_i);
             }
-#endif
         }
     }
 
-    if (res == NULL) {
-        // Free file handle
-        filehandles[fh_i] = NULL;
-        return -1;
-    }
     filehandles[fh_i] = res;
 
     return fh_i + 3; // +3 as filehandles 0-2 are stdin/out/err
@@ -296,10 +254,12 @@
 extern "C" int PREFIX(_close)(FILEHANDLE fh) {
     if (fh < 3) return 0;
 
-    errno = EBADF;
-    FileLike* fhc = filehandles[fh-3];
+    FileHandle* fhc = filehandles[fh-3];
     filehandles[fh-3] = NULL;
-    if (fhc == NULL) return -1;
+    if (fhc == NULL) {
+        errno = EBADF;
+        return -1;
+    }
 
     int err = fhc->close();
     if (err < 0) {
@@ -317,7 +277,12 @@
 #endif
     int n; // n is the number of bytes written
 
-    errno = EBADF;
+#if defined(MBED_TRAP_ERRORS_ENABLED) && MBED_TRAP_ERRORS_ENABLED && defined(MBED_CONF_RTOS_PRESENT)
+    if (core_util_is_isr_active() || !core_util_are_interrupts_enabled()) {
+        error("Error - writing to a file in an ISR or critical section\r\n");
+    }
+#endif
+
     if (fh < 3) {
 #if DEVICE_SERIAL
         if (!stdio_uart_inited) init_serial();
@@ -337,8 +302,11 @@
 #endif
         n = length;
     } else {
-        FileLike* fhc = filehandles[fh-3];
-        if (fhc == NULL) return -1;
+        FileHandle* fhc = filehandles[fh-3];
+        if (fhc == NULL) {
+            errno = EBADF;
+            return -1;
+        }
 
         n = fhc->write(buffer, length);
         if (n < 0) {
@@ -359,7 +327,12 @@
 #endif
     int n; // n is the number of bytes read
 
-    errno = EBADF;
+#if defined(MBED_TRAP_ERRORS_ENABLED) && MBED_TRAP_ERRORS_ENABLED && defined(MBED_CONF_RTOS_PRESENT)
+    if (core_util_is_isr_active() || !core_util_are_interrupts_enabled()) {
+        error("Error - reading from a file in an ISR or critical section\r\n");
+    }
+#endif
+
     if (fh < 3) {
         // only read a character at a time from stdin
 #if DEVICE_SERIAL
@@ -389,8 +362,11 @@
 #endif
         n = 1;
     } else {
-        FileLike* fhc = filehandles[fh-3];
-        if (fhc == NULL) return -1;
+        FileHandle* fhc = filehandles[fh-3];
+        if (fhc == NULL) {
+            errno = EBADF;
+            return -1;
+        }
 
         n = fhc->read(buffer, length);
         if (n < 0) {
@@ -404,57 +380,76 @@
 #endif
 }
 
+
 #ifdef __ARMCC_VERSION
 extern "C" int PREFIX(_istty)(FILEHANDLE fh)
 #else
 extern "C" int _isatty(FILEHANDLE fh)
 #endif
 {
-    errno = EBADF;
     /* stdin, stdout and stderr should be tty */
     if (fh < 3) return 1;
 
-    FileLike* fhc = filehandles[fh-3];
-    if (fhc == NULL) return -1;
+    FileHandle* fhc = filehandles[fh-3];
+    if (fhc == NULL) {
+        errno = EBADF;
+        return 0;
+    }
 
-    int err = fhc->isatty();
-    if (err < 0) {
-        errno = -err;
-        return -1;
+    int tty = fhc->isatty();
+    if (tty < 0) {
+        errno = -tty;
+        return 0;
     } else {
-        return 0;
+        return tty;
     }
 }
 
 extern "C"
 #if defined(__ARMCC_VERSION)
-int _sys_seek(FILEHANDLE fh, long position)
+int _sys_seek(FILEHANDLE fh, long offset)
 #elif defined(__ICCARM__)
 long __lseek(int fh, long offset, int whence)
 #else
 int _lseek(FILEHANDLE fh, int offset, int whence)
 #endif
 {
-    errno = EBADF;
-    if (fh < 3) return 0;
-
-    FileLike* fhc = filehandles[fh-3];
-    if (fhc == NULL) return -1;
+#if defined(__ARMCC_VERSION)
+    int whence = SEEK_SET;
+#endif
+    if (fh < 3) {
+        errno = ESPIPE;
+        return -1;
+    }
 
-#if defined(__ARMCC_VERSION)
-    return fhc->seek(position, SEEK_SET);
-#else
-    return fhc->seek(offset, whence);
-#endif
+    FileHandle* fhc = filehandles[fh-3];
+    if (fhc == NULL) {
+        errno = EBADF;
+        return -1;
+    }
+
+    off_t off = fhc->seek(offset, whence);
+    if (off < 0) {
+        errno = -off;
+        return -1;
+    }
+    // Assuming INT_MAX = LONG_MAX, so we don't care about prototype difference
+    if (off > INT_MAX) {
+        errno = EOVERFLOW;
+        return -1;
+    }
+    return off;
 }
 
 #ifdef __ARMCC_VERSION
 extern "C" int PREFIX(_ensure)(FILEHANDLE fh) {
-    errno = EBADF;
     if (fh < 3) return 0;
 
-    FileLike* fhc = filehandles[fh-3];
-    if (fhc == NULL) return -1;
+    FileHandle* fhc = filehandles[fh-3];
+    if (fhc == NULL) {
+        errno = EBADF;
+        return -1;
+    }
 
     int err = fhc->sync();
     if (err < 0) {
@@ -466,13 +461,27 @@
 }
 
 extern "C" long PREFIX(_flen)(FILEHANDLE fh) {
-    errno = EBADF;
-    if (fh < 3) return 0;
+    if (fh < 3) {
+        errno = EINVAL;
+        return -1;
+    }
+
+    FileHandle* fhc = filehandles[fh-3];
+    if (fhc == NULL) {
+        errno = EBADF;
+        return -1;
+    }
 
-    FileLike* fhc = filehandles[fh-3];
-    if (fhc == NULL) return -1;
-
-    return fhc->size();
+    off_t size = fhc->size();
+    if (size < 0) {
+        errno = -size;
+        return -1;
+    }
+    if (size > LONG_MAX) {
+        errno = EOVERFLOW;
+        return -1;
+    }
+    return size;
 }
 #endif
 
@@ -490,11 +499,12 @@
 
 namespace std {
 extern "C" int remove(const char *path) {
-#if MBED_CONF_FILESYSTEM_PRESENT
-    errno = EBADF;
     FilePath fp(path);
-    FileSystem *fs = fp.fileSystem();
-    if (fs == NULL) return -1;
+    FileSystemHandle *fs = fp.fileSystem();
+    if (fs == NULL) {
+        errno = ENOENT;
+        return -1;
+    }
 
     int err = fs->remove(fp.fileName());
     if (err < 0) {
@@ -503,22 +513,24 @@
     } else {
         return 0;
     }
-#else
-    errno = ENOSYS;
-    return -1;
-#endif
 }
 
 extern "C" int rename(const char *oldname, const char *newname) {
-#if MBED_CONF_FILESYSTEM_PRESENT
-    errno = EBADF;
     FilePath fpOld(oldname);
     FilePath fpNew(newname);
-    FileSystem *fsOld = fpOld.fileSystem();
-    FileSystem *fsNew = fpNew.fileSystem();
+    FileSystemHandle *fsOld = fpOld.fileSystem();
+    FileSystemHandle *fsNew = fpNew.fileSystem();
+
+    if (fsOld == NULL) {
+        errno = ENOENT;
+        return -1;
+    }
 
     /* rename only if both files are on the same FS */
-    if (fsOld != fsNew || fsOld == NULL) return -1;
+    if (fsOld != fsNew) {
+        errno = EXDEV;
+        return -1;
+    }
 
     int err = fsOld->rename(fpOld.fileName(), fpNew.fileName());
     if (err < 0) {
@@ -527,10 +539,6 @@
     } else {
         return 0;
     }
-#else
-    errno = ENOSYS;
-    return -1;
-#endif
 }
 
 extern "C" char *tmpnam(char *s) {
@@ -551,30 +559,24 @@
 #endif
 
 extern "C" DIR *opendir(const char *path) {
-#if MBED_CONF_FILESYSTEM_PRESENT
-    errno = EBADF;
+    FilePath fp(path);
+    FileSystemHandle* fs = fp.fileSystem();
+    if (fs == NULL) {
+        errno = ENOENT;
+        return NULL;
+    }
 
-    FilePath fp(path);
-    FileSystem* fs = fp.fileSystem();
-    if (fs == NULL) return NULL;
-
-    Dir *dir = new ManagedDir;
-    int err = dir->open(fs, fp.fileName());
+    DirHandle *dir;
+    int err = fs->open(&dir, fp.fileName());
     if (err < 0) {
         errno = -err;
-        delete dir;
-        dir = NULL;
+        return NULL;
     }
 
     return dir;
-#else
-    errno = ENOSYS;
-    return 0;
-#endif
 }
 
 extern "C" struct dirent *readdir(DIR *dir) {
-#if MBED_CONF_FILESYSTEM_PRESENT
     static struct dirent ent;
     int err = dir->read(&ent);
     if (err < 1) {
@@ -585,14 +587,9 @@
     }
 
     return &ent;
-#else
-    errno = ENOSYS;
-    return 0;
-#endif
 }
 
 extern "C" int closedir(DIR *dir) {
-#if MBED_CONF_FILESYSTEM_PRESENT
     int err = dir->close();
     if (err < 0) {
         errno = -err;
@@ -600,41 +597,23 @@
     } else {
         return 0;
     }
-#else
-    errno = ENOSYS;
-    return -1;
-#endif
 }
 
 extern "C" void rewinddir(DIR *dir) {
-#if MBED_CONF_FILESYSTEM_PRESENT
     dir->rewind();
-#else
-    errno = ENOSYS;
-#endif
 }
 
 extern "C" off_t telldir(DIR *dir) {
-#if MBED_CONF_FILESYSTEM_PRESENT
     return dir->tell();
-#else
-    errno = ENOSYS;
-    return 0;
-#endif
 }
 
 extern "C" void seekdir(DIR *dir, off_t off) {
-#if MBED_CONF_FILESYSTEM_PRESENT
     dir->seek(off);
-#else
-    errno = ENOSYS;
-#endif
 }
 
 extern "C" int mkdir(const char *path, mode_t mode) {
-#if MBED_CONF_FILESYSTEM_PRESENT
     FilePath fp(path);
-    FileSystem *fs = fp.fileSystem();
+    FileSystemHandle *fs = fp.fileSystem();
     if (fs == NULL) return -1;
 
     int err = fs->mkdir(fp.fileName(), mode);
@@ -644,16 +623,11 @@
     } else {
         return 0;
     }
-#else
-    errno = ENOSYS;
-    return -1;
-#endif
 }
 
 extern "C" int stat(const char *path, struct stat *st) {
-#if MBED_CONF_FILESYSTEM_PRESENT
     FilePath fp(path);
-    FileSystem *fs = fp.fileSystem();
+    FileSystemHandle *fs = fp.fileSystem();
     if (fs == NULL) return -1;
 
     int err = fs->stat(fp.fileName(), st);
@@ -663,10 +637,6 @@
     } else {
         return 0;
     }
-#else
-    errno = ENOSYS;
-    return -1;
-#endif
 }
 
 #if defined(TOOLCHAIN_GCC)
@@ -684,79 +654,10 @@
 
 #endif
 
-#if defined(TOOLCHAIN_GCC)
-
-#ifdef  FEATURE_UVISOR
-#include "uvisor-lib/uvisor-lib.h"
-#endif/* FEATURE_UVISOR */
-
-
-extern "C" WEAK void software_init_hook_rtos(void)
-{
-    // Do nothing by default.
-}
-
-extern "C" void software_init_hook(void)
-{
-#ifdef   FEATURE_UVISOR
-    int return_code;
-
-    return_code = uvisor_lib_init();
-    if (return_code) {
-        mbed_die();
-    }
-#endif/* FEATURE_UVISOR */
-    mbed_sdk_init();
-    software_init_hook_rtos();
-}
-#endif
-
-// ****************************************************************************
-// mbed_main is a function that is called before main()
-// mbed_sdk_init() is also a function that is called before main(), but unlike
-// mbed_main(), it is not meant for user code, but for the SDK itself to perform
-// initializations before main() is called.
-
-extern "C" WEAK void mbed_main(void);
-extern "C" WEAK void mbed_main(void) {
-}
-
-#if defined(TOOLCHAIN_ARM)
-extern "C" int $Super$$main(void);
-
-extern "C" int $Sub$$main(void) {
-    mbed_main();
-    return $Super$$main();
-}
-
-extern "C" void _platform_post_stackheap_init (void) {
-    mbed_sdk_init();
-}
-
-#elif defined(TOOLCHAIN_GCC)
-extern "C" int __real_main(void);
-
-extern "C" int __wrap_main(void) {
-    mbed_main();
-    return __real_main();
-}
-#elif defined(TOOLCHAIN_IAR)
-// IAR doesn't have the $Super/$Sub mechanism of armcc, nor something equivalent
-// to ld's --wrap. It does have a --redirect, but that doesn't help, since redirecting
-// 'main' to another symbol looses the original 'main' symbol. However, its startup
-// code will call a function to setup argc and argv (__iar_argc_argv) if it is defined.
-// Since mbed doesn't use argc/argv, we use this function to call our mbed_main.
-extern "C" void __iar_argc_argv() {
-    mbed_main();
-}
-#endif
-
 // Provide implementation of _sbrk (low-level dynamic memory allocation
 // routine) for GCC_ARM which compares new heap pointer with MSP instead of
 // SP.  This make it compatible with RTX RTOS thread stacks.
 #if defined(TOOLCHAIN_GCC_ARM) || defined(TOOLCHAIN_GCC_CR)
-// Linker defined symbol used by _sbrk to indicate where heap should start.
-extern "C" int __end__;
 
 #if defined(TARGET_CORTEX_A)
 extern "C" uint32_t  __HeapLimit;
@@ -766,9 +667,6 @@
 #undef errno
 extern "C" int errno;
 
-// For ARM7 only
-register unsigned char * stack_ptr __asm ("sp");
-
 // Dynamic memory allocation related syscall.
 #if defined(TARGET_NUMAKER_PFM_NUC472) || defined(TARGET_NUMAKER_PFM_M453)
 // Overwrite _sbrk() to support two region model (heap and stack are two distinct regions).
@@ -780,14 +678,14 @@
     return (caddr_t) __wrap__sbrk(incr);
 }
 #else
+// Linker defined symbol used by _sbrk to indicate where heap should start.
+extern "C" uint32_t __end__;
 extern "C" caddr_t _sbrk(int incr) {
     static unsigned char* heap = (unsigned char*)&__end__;
     unsigned char*        prev_heap = heap;
     unsigned char*        new_heap = heap + incr;
 
-#if defined(TARGET_ARM7)
-    if (new_heap >= stack_ptr) {
-#elif defined(TARGET_CORTEX_A)
+#if defined(TARGET_CORTEX_A)
     if (new_heap >= (unsigned char*)&__HeapLimit) {     /* __HeapLimit is end of heap section */
 #else
     if (new_heap >= (unsigned char*)__get_MSP()) {
@@ -899,16 +797,34 @@
 
 namespace mbed {
 
-void mbed_set_unbuffered_stream(FILE *_file) {
+void mbed_set_unbuffered_stream(std::FILE *_file) {
 #if defined (__ICCARM__)
     char buf[2];
-    std::setvbuf(_file,buf,_IONBF,NULL);    
+    std::setvbuf(_file,buf,_IONBF,NULL);
 #else
     setbuf(_file, NULL);
 #endif
 }
 
-int mbed_getc(FILE *_file){
+/* Applications are expected to use fdopen()
+ * not this function directly. This code had to live here because FILE and FileHandle
+ * processes are all linked together here.
+ */
+std::FILE *mbed_fdopen(FileHandle *fh, const char *mode)
+{
+    char buf[12]; /* :0x12345678 + null byte */
+    std::sprintf(buf, ":%p", fh);
+    std::FILE *stream = std::fopen(buf, mode);
+    /* newlib-nano doesn't appear to ever call _isatty itself, so
+     * happily fully buffers an interactive stream. Deal with that here.
+     */
+    if (stream && fh->isatty()) {
+        mbed_set_unbuffered_stream(stream);
+    }
+    return stream;
+}
+
+int mbed_getc(std::FILE *_file){
 #if defined (__ICCARM__)
     /*This is only valid for unbuffered streams*/
     int res = std::fgetc(_file);
@@ -916,14 +832,14 @@
         _file->_Mode = (unsigned short)(_file->_Mode & ~ 0x1000);/* Unset read mode */
         _file->_Rend = _file->_Wend;
         _file->_Next = _file->_Wend;
-    }    
+    }
     return res;
-#else    
+#else
     return std::fgetc(_file);
-#endif   
+#endif
 }
 
-char* mbed_gets(char*s, int size, FILE *_file){
+char* mbed_gets(char*s, int size, std::FILE *_file){
 #if defined (__ICCARM__)
     /*This is only valid for unbuffered streams*/
     char *str = fgets(s,size,_file);
@@ -933,7 +849,7 @@
         _file->_Next = _file->_Wend;
     }
     return str;
-#else    
+#else
     return std::fgets(s,size,_file);
 #endif
 }
@@ -1048,3 +964,72 @@
         free(ptr);
     }
 }
+
+#if defined(MBED_CONF_RTOS_PRESENT) && defined(MBED_TRAP_ERRORS_ENABLED) && MBED_TRAP_ERRORS_ENABLED
+
+static const char* error_msg(int32_t status)
+{
+    switch (status) {
+    case osError:
+        return "Unspecified RTOS error";
+    case osErrorTimeout:
+        return "Operation not completed within the timeout period";
+    case osErrorResource:
+        return "Resource not available";
+    case osErrorParameter:
+        return "Parameter error";
+    case osErrorNoMemory:
+        return "System is out of memory";
+    case osErrorISR:
+        return "Not allowed in ISR context";
+    default:
+        return "Unknown";
+    }
+}
+
+extern "C" void EvrRtxKernelError (int32_t status)
+{
+    error("Kernel error %i: %s\r\n", status, error_msg(status));
+}
+
+extern "C" void EvrRtxThreadError (osThreadId_t thread_id, int32_t status)
+{
+    error("Thread %p error %i: %s\r\n", thread_id, status, error_msg(status));
+}
+
+extern "C" void EvrRtxTimerError (osTimerId_t timer_id, int32_t status)
+{
+    error("Timer %p error %i: %s\r\n", timer_id, status, error_msg(status));
+}
+
+extern "C" void EvrRtxEventFlagsError (osEventFlagsId_t ef_id, int32_t status)
+{
+    error("Event %p error %i: %s\r\n", ef_id, status, error_msg(status));
+}
+
+extern "C" void EvrRtxMutexError (osMutexId_t mutex_id, int32_t status)
+{
+    error("Mutex %p error %i: %s\r\n", mutex_id, status, error_msg(status));
+}
+
+extern "C" void EvrRtxSemaphoreError (osSemaphoreId_t semaphore_id, int32_t status)
+{
+    // Ignore semaphore overflow, the count will saturate with a returned error
+    if (status == osRtxErrorSemaphoreCountLimit) {
+        return;
+    }
+
+    error("Semaphore %p error %i\r\n", semaphore_id, status);
+}
+
+extern "C" void EvrRtxMemoryPoolError (osMemoryPoolId_t mp_id, int32_t status)
+{
+    error("Memory Pool %p error %i\r\n", mp_id, status);
+}
+
+extern "C" void EvrRtxMessageQueueError (osMessageQueueId_t mq_id, int32_t status)
+{
+    error("Message Queue %p error %i\r\n", mq_id, status);
+}
+
+#endif