Rtos API example

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers mbed_retarget.cpp Source File

mbed_retarget.cpp

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2006-2015 ARM Limited
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 #include <time.h>
00017 #include "platform/platform.h"
00018 #include "platform/FilePath.h"
00019 #include "hal/serial_api.h"
00020 #include "hal/us_ticker_api.h"
00021 #include "platform/mbed_toolchain.h"
00022 #include "platform/mbed_semihost_api.h"
00023 #include "platform/mbed_interface.h"
00024 #include "platform/SingletonPtr.h"
00025 #include "platform/PlatformMutex.h"
00026 #include "platform/mbed_error.h"
00027 #include "platform/mbed_stats.h"
00028 #include "platform/mbed_critical.h"
00029 #include "platform/PlatformMutex.h"
00030 #include "us_ticker_api.h"
00031 #include "lp_ticker_api.h"
00032 #include <stdlib.h>
00033 #include <string.h>
00034 #include <limits.h>
00035 #if DEVICE_STDIO_MESSAGES
00036 #include <stdio.h>
00037 #endif
00038 #include <errno.h>
00039 #include "platform/mbed_retarget.h"
00040 
00041 static SingletonPtr<PlatformMutex>  _mutex;
00042 
00043 #if defined(__ARMCC_VERSION)
00044 #   if __ARMCC_VERSION >= 6010050
00045 #      include <arm_compat.h>
00046 #   endif
00047 #   include <rt_sys.h>
00048 #   include <rt_misc.h>
00049 #   include <stdint.h>
00050 #   define PREFIX(x)    _sys##x
00051 #   define OPEN_MAX     _SYS_OPEN
00052 #   ifdef __MICROLIB
00053 #       pragma import(__use_full_stdio)
00054 #   endif
00055 
00056 #elif defined(__ICCARM__)
00057 #   include <yfuns.h>
00058 #   define PREFIX(x)        _##x
00059 #   define OPEN_MAX         16
00060 
00061 #   define STDIN_FILENO     0
00062 #   define STDOUT_FILENO    1
00063 #   define STDERR_FILENO    2
00064 
00065 #else
00066 #   include <sys/syslimits.h>
00067 #   define PREFIX(x)    x
00068 #endif
00069 
00070 #define FILE_HANDLE_RESERVED    0xFFFFFFFF
00071 
00072 using namespace mbed;
00073 
00074 #if defined(__MICROLIB) && (__ARMCC_VERSION>5030000)
00075 // Before version 5.03, we were using a patched version of microlib with proper names
00076 extern const char __stdin_name[]  = ":tt";
00077 extern const char __stdout_name[] = ":tt";
00078 extern const char __stderr_name[] = ":tt";
00079 
00080 #else
00081 extern const char __stdin_name[]  = "/stdin";
00082 extern const char __stdout_name[] = "/stdout";
00083 extern const char __stderr_name[] = "/stderr";
00084 #endif
00085 
00086 unsigned char *mbed_heap_start = 0;
00087 uint32_t mbed_heap_size = 0;
00088 
00089 /* newlib has the filehandle field in the FILE struct as a short, so
00090  * we can't just return a Filehandle* from _open and instead have to
00091  * put it in a filehandles array and return the index into that array
00092  * (or rather index+3, as filehandles 0-2 are stdin/out/err).
00093  */
00094 static FileHandle *filehandles[OPEN_MAX];
00095 static SingletonPtr<PlatformMutex>  filehandle_mutex;
00096 
00097 namespace mbed {
00098 void remove_filehandle(FileHandle *file) {
00099     filehandle_mutex->lock();
00100     /* Remove all open filehandles for this */
00101     for (unsigned int fh_i = 0; fh_i < sizeof(filehandles)/sizeof(*filehandles); fh_i++) {
00102         if (filehandles[fh_i] == file) {
00103             filehandles[fh_i] = NULL;
00104         }
00105     }
00106     filehandle_mutex->unlock();
00107 }
00108 }
00109 
00110 #if DEVICE_SERIAL
00111 extern int stdio_uart_inited;
00112 extern serial_t stdio_uart;
00113 #if MBED_CONF_PLATFORM_STDIO_CONVERT_NEWLINES
00114 static char stdio_in_prev;
00115 static char stdio_out_prev;
00116 #endif
00117 #endif
00118 
00119 static void init_serial() {
00120 #if DEVICE_SERIAL
00121     if (stdio_uart_inited) return;
00122     serial_init(&stdio_uart, STDIO_UART_TX, STDIO_UART_RX);
00123 #if MBED_CONF_PLATFORM_STDIO_BAUD_RATE
00124     serial_baud(&stdio_uart, MBED_CONF_PLATFORM_STDIO_BAUD_RATE);
00125 #endif
00126 #endif
00127 }
00128 
00129 /**
00130  * Sets errno when file opening fails.
00131  * Wipes out the filehandle too.
00132  *
00133  * @param error is a negative error code returned from an mbed function and
00134  *              will be negated to store a positive error code in errno
00135  */
00136 static int handle_open_errors(int error, unsigned filehandle_idx) {
00137     errno = -error;
00138     // Free file handle
00139     filehandles[filehandle_idx] = NULL;
00140     return -1;
00141 }
00142 
00143 static inline int openmode_to_posix(int openmode) {
00144     int posix = openmode;
00145 #ifdef __ARMCC_VERSION
00146     if (openmode & OPEN_PLUS) {
00147         posix = O_RDWR;
00148     } else if(openmode & OPEN_W) {
00149         posix = O_WRONLY;
00150     } else if(openmode & OPEN_A) {
00151         posix = O_WRONLY|O_APPEND;
00152     } else {
00153         posix = O_RDONLY;
00154     }
00155     /* a, w, a+, w+ all create if file does not already exist */
00156     if (openmode & (OPEN_A|OPEN_W)) {
00157         posix |= O_CREAT;
00158     }
00159     /* w and w+ truncate */
00160     if (openmode & OPEN_W) {
00161         posix |= O_TRUNC;
00162     }
00163 #elif defined(__ICCARM__)
00164     switch (openmode & _LLIO_RDWRMASK) {
00165         case _LLIO_RDONLY: posix = O_RDONLY; break;
00166         case _LLIO_WRONLY: posix = O_WRONLY; break;
00167         case _LLIO_RDWR  : posix = O_RDWR  ; break;
00168     }
00169     if (openmode & _LLIO_CREAT ) posix |= O_CREAT;
00170     if (openmode & _LLIO_APPEND) posix |= O_APPEND;
00171     if (openmode & _LLIO_TRUNC ) posix |= O_TRUNC;
00172 #elif defined(TOOLCHAIN_GCC)
00173     posix &= ~O_BINARY;
00174 #endif
00175     return posix;
00176 }
00177 
00178 /* @brief   standard c library fopen() retargeting function.
00179  *
00180  * This function is invoked by the standard c library retargeting to handle fopen()
00181  *
00182  * @return
00183  *  On success, a valid FILEHANDLE is returned.
00184  *  On failure, -1 is returned and errno is set to an appropriate value e.g.
00185  *   ENOENT     file not found (default errno setting)
00186  *   EMFILE     the maximum number of open files was exceeded.
00187  *
00188  * */
00189 extern "C" FILEHANDLE PREFIX(_open)(const char* name, int openmode) {
00190     #if defined(__MICROLIB) && (__ARMCC_VERSION>5030000)
00191 #if !defined(MBED_CONF_RTOS_PRESENT)
00192     // valid only for mbed 2
00193     // for ulib, this is invoked after RAM init, prior c++
00194     // used as hook, as post stack/heap is not active there
00195     extern void mbed_copy_nvic(void);
00196     extern void mbed_sdk_init(void);
00197 
00198     static int mbed_sdk_inited = 0;
00199     if (!mbed_sdk_inited) {
00200         mbed_copy_nvic();
00201         mbed_sdk_init();
00202         mbed_sdk_inited = 1;
00203     }
00204 #endif
00205     // Before version 5.03, we were using a patched version of microlib with proper names
00206     // This is the workaround that the microlib author suggested us
00207     static int n = 0;
00208     if (!std::strcmp(name, ":tt")) return n++;
00209     #else
00210     /* Use the posix convention that stdin,out,err are filehandles 0,1,2.
00211      */
00212     if (std::strcmp(name, __stdin_name) == 0) {
00213         init_serial();
00214         return 0;
00215     } else if (std::strcmp(name, __stdout_name) == 0) {
00216         init_serial();
00217         return 1;
00218     } else if (std::strcmp(name, __stderr_name) == 0) {
00219         init_serial();
00220         return 2;
00221     }
00222     #endif
00223 
00224     // find the first empty slot in filehandles
00225     filehandle_mutex->lock();
00226     unsigned int fh_i;
00227     for (fh_i = 0; fh_i < sizeof(filehandles)/sizeof(*filehandles); fh_i++) {
00228         /* Take a next free filehandle slot available. */
00229         if (filehandles[fh_i] == NULL) break;
00230     }
00231     if (fh_i >= sizeof(filehandles)/sizeof(*filehandles)) {
00232         /* Too many file handles have been opened */
00233         errno = EMFILE;
00234         filehandle_mutex->unlock();
00235         return -1;
00236     }
00237     filehandles[fh_i] = (FileHandle*)FILE_HANDLE_RESERVED;
00238     filehandle_mutex->unlock();
00239 
00240     FileHandle *res = NULL;
00241 
00242     /* FILENAME: ":(pointer)" describes a FileHandle* */
00243     if (name[0] == ':') {
00244         void *p;
00245         memcpy(&p, name + 1, sizeof(p));
00246         res = (FileHandle*)p;
00247 
00248     /* FILENAME: "/file_system/file_name" */
00249     } else {
00250         FilePath path(name);
00251 
00252         if (!path.exists()) {
00253             /* The first part of the filename (between first 2 '/') is not a
00254              * registered mount point in the namespace.
00255              */
00256             return handle_open_errors(-ENODEV, fh_i);
00257         }
00258 
00259         if (path.isFile()) {
00260             res = path.file();
00261         } else {
00262             FileSystemHandle *fs = path.fileSystem();
00263             if (fs == NULL) {
00264                 return handle_open_errors(-ENODEV, fh_i);
00265             }
00266             int posix_mode = openmode_to_posix(openmode);
00267             int err = fs->open(&res, path.fileName(), posix_mode);
00268             if (err) {
00269                 return handle_open_errors(err, fh_i);
00270             }
00271         }
00272     }
00273 
00274     filehandles[fh_i] = res;
00275 
00276     return fh_i + 3; // +3 as filehandles 0-2 are stdin/out/err
00277 }
00278 
00279 extern "C" int PREFIX(_close)(FILEHANDLE fh) {
00280     if (fh < 3) return 0;
00281 
00282     FileHandle* fhc = filehandles[fh-3];
00283     filehandles[fh-3] = NULL;
00284     if (fhc == NULL) {
00285         errno = EBADF;
00286         return -1;
00287     }
00288 
00289     int err = fhc->close();
00290     if (err < 0) {
00291         errno = -err;
00292         return -1;
00293     } else {
00294         return 0;
00295     }
00296 }
00297 
00298 #if defined(__ICCARM__)
00299 extern "C" size_t    __write (int        fh, const unsigned char *buffer, size_t length) {
00300 #else
00301 extern "C" int PREFIX(_write)(FILEHANDLE fh, const unsigned char *buffer, unsigned int length, int mode) {
00302 #endif
00303     int n; // n is the number of bytes written
00304 
00305 #if defined(MBED_TRAP_ERRORS_ENABLED) && MBED_TRAP_ERRORS_ENABLED && defined(MBED_CONF_RTOS_PRESENT)
00306     if (core_util_is_isr_active() || !core_util_are_interrupts_enabled()) {
00307         error("Error - writing to a file in an ISR or critical section\r\n");
00308     }
00309 #endif
00310 
00311     if (fh < 3) {
00312 #if DEVICE_SERIAL
00313         if (!stdio_uart_inited) init_serial();
00314 #if MBED_CONF_PLATFORM_STDIO_CONVERT_NEWLINES
00315         for (unsigned int i = 0; i < length; i++) {
00316             if (buffer[i] == '\n' && stdio_out_prev != '\r') {
00317                  serial_putc(&stdio_uart, '\r');
00318             }
00319             serial_putc(&stdio_uart, buffer[i]);
00320             stdio_out_prev = buffer[i];
00321         }
00322 #else
00323         for (unsigned int i = 0; i < length; i++) {
00324             serial_putc(&stdio_uart, buffer[i]);
00325         }
00326 #endif
00327 #endif
00328         n = length;
00329     } else {
00330         FileHandle* fhc = filehandles[fh-3];
00331         if (fhc == NULL) {
00332             errno = EBADF;
00333             return -1;
00334         }
00335 
00336         n = fhc->write(buffer, length);
00337         if (n < 0) {
00338             errno = -n;
00339         }
00340     }
00341 #ifdef __ARMCC_VERSION
00342     return length-n;
00343 #else
00344     return n;
00345 #endif
00346 }
00347 
00348 #if defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
00349 extern "C" void PREFIX(_exit)(int return_code) {
00350     while(1) {}
00351 }
00352 
00353 extern "C" void _ttywrch(int ch) {
00354     serial_putc(&stdio_uart, ch);
00355 }
00356 #endif
00357 
00358 #if defined(__ICCARM__)
00359 extern "C" size_t    __read (int        fh, unsigned char *buffer, size_t       length) {
00360 #else
00361 extern "C" int PREFIX(_read)(FILEHANDLE fh, unsigned char *buffer, unsigned int length, int mode) {
00362 #endif
00363     int n; // n is the number of bytes read
00364 
00365 #if defined(MBED_TRAP_ERRORS_ENABLED) && MBED_TRAP_ERRORS_ENABLED && defined(MBED_CONF_RTOS_PRESENT)
00366     if (core_util_is_isr_active() || !core_util_are_interrupts_enabled()) {
00367         error("Error - reading from a file in an ISR or critical section\r\n");
00368     }
00369 #endif
00370 
00371     if (fh < 3) {
00372         // only read a character at a time from stdin
00373 #if DEVICE_SERIAL
00374         if (!stdio_uart_inited) init_serial();
00375 #if MBED_CONF_PLATFORM_STDIO_CONVERT_NEWLINES
00376         while (true) {
00377             char c = serial_getc(&stdio_uart);
00378             if ((c == '\r' && stdio_in_prev != '\n') ||
00379                 (c == '\n' && stdio_in_prev != '\r')) {
00380                 stdio_in_prev = c;
00381                 *buffer = '\n';
00382                 break;
00383             } else if ((c == '\r' && stdio_in_prev == '\n') ||
00384                        (c == '\n' && stdio_in_prev == '\r')) {
00385                 stdio_in_prev = c;
00386                 // onto next character
00387                 continue;
00388             } else {
00389                 stdio_in_prev = c;
00390                 *buffer = c;
00391                 break;
00392             }
00393         }
00394 #else
00395         *buffer = serial_getc(&stdio_uart);
00396 #endif
00397 #endif
00398         n = 1;
00399     } else {
00400         FileHandle* fhc = filehandles[fh-3];
00401         if (fhc == NULL) {
00402             errno = EBADF;
00403             return -1;
00404         }
00405 
00406         n = fhc->read(buffer, length);
00407         if (n < 0) {
00408             errno = -n;
00409         }
00410     }
00411 #ifdef __ARMCC_VERSION
00412     return length-n;
00413 #else
00414     return n;
00415 #endif
00416 }
00417 
00418 
00419 #ifdef __ARMCC_VERSION
00420 extern "C" int PREFIX(_istty)(FILEHANDLE fh)
00421 #else
00422 extern "C" int _isatty(FILEHANDLE fh)
00423 #endif
00424 {
00425     /* stdin, stdout and stderr should be tty */
00426     if (fh < 3) return 1;
00427 
00428     FileHandle* fhc = filehandles[fh-3];
00429     if (fhc == NULL) {
00430         errno = EBADF;
00431         return 0;
00432     }
00433 
00434     int tty = fhc->isatty();
00435     if (tty < 0) {
00436         errno = -tty;
00437         return 0;
00438     } else {
00439         return tty;
00440     }
00441 }
00442 
00443 extern "C"
00444 #if defined(__ARMCC_VERSION)
00445 int _sys_seek(FILEHANDLE fh, long offset)
00446 #elif defined(__ICCARM__)
00447 long __lseek(int fh, long offset, int whence)
00448 #else
00449 int _lseek(FILEHANDLE fh, int offset, int whence)
00450 #endif
00451 {
00452 #if defined(__ARMCC_VERSION)
00453     int whence = SEEK_SET;
00454 #endif
00455 
00456     if (fh < 3) {
00457         errno = ESPIPE;
00458         return -1;
00459     }
00460 
00461     FileHandle* fhc = filehandles[fh-3];
00462     if (fhc == NULL) {
00463         errno = EBADF;
00464         return -1;
00465     }
00466 
00467     off_t off = fhc->seek(offset, whence);
00468     if (off < 0) {
00469         errno = -off;
00470         return -1;
00471     }
00472     // Assuming INT_MAX = LONG_MAX, so we don't care about prototype difference
00473     if (off > INT_MAX) {
00474         errno = EOVERFLOW;
00475         return -1;
00476     }
00477     return off;
00478 }
00479 
00480 #ifdef __ARMCC_VERSION
00481 extern "C" int PREFIX(_ensure)(FILEHANDLE fh) {
00482     if (fh < 3) return 0;
00483 
00484     FileHandle* fhc = filehandles[fh-3];
00485     if (fhc == NULL) {
00486         errno = EBADF;
00487         return -1;
00488     }
00489 
00490     int err = fhc->sync();
00491     if (err < 0) {
00492         errno = -err;
00493         return -1;
00494     } else {
00495         return 0;
00496     }
00497 }
00498 
00499 extern "C" long PREFIX(_flen)(FILEHANDLE fh) {
00500     if (fh < 3) {
00501         errno = EINVAL;
00502         return -1;
00503     }
00504 
00505     FileHandle* fhc = filehandles[fh-3];
00506     if (fhc == NULL) {
00507         errno = EBADF;
00508         return -1;
00509     }
00510 
00511     off_t size = fhc->size();
00512     if (size < 0) {
00513         errno = -size;
00514         return -1;
00515     }
00516     if (size > LONG_MAX) {
00517         errno = EOVERFLOW;
00518         return -1;
00519     }
00520     return size;
00521 }
00522 
00523 extern "C" char Image$$RW_IRAM1$$ZI$$Limit[];
00524 
00525 extern "C" MBED_WEAK __value_in_regs struct __initial_stackheap _mbed_user_setup_stackheap(uint32_t R0, uint32_t R1, uint32_t R2, uint32_t R3)
00526 {
00527     uint32_t zi_limit = (uint32_t)Image$$RW_IRAM1$$ZI$$Limit;
00528     uint32_t sp_limit = __current_sp();
00529 
00530     zi_limit = (zi_limit + 7) & ~0x7;    // ensure zi_limit is 8-byte aligned
00531 
00532     struct __initial_stackheap r;
00533     r.heap_base = zi_limit;
00534     r.heap_limit = sp_limit;
00535     return r;
00536 }
00537 
00538 extern "C" __value_in_regs struct __initial_stackheap __user_setup_stackheap(uint32_t R0, uint32_t R1, uint32_t R2, uint32_t R3) {
00539     return _mbed_user_setup_stackheap(R0, R1, R2, R3);
00540 }
00541 
00542 #endif
00543 
00544 
00545 #if !defined(__ARMCC_VERSION) && !defined(__ICCARM__)
00546 extern "C" int _fstat(int fh, struct stat *st) {
00547     if (fh < 3) {
00548         st->st_mode = S_IFCHR;
00549         return  0;
00550     }
00551 
00552     FileHandle* fhc = filehandles[fh-3];
00553     if (fhc == NULL) {
00554         errno = EBADF;
00555         return -1;
00556     }
00557 
00558     st->st_mode = fhc->isatty() ? S_IFCHR : S_IFREG;
00559     st->st_size = fhc->size();
00560     return 0;
00561 }
00562 #endif
00563 
00564 namespace std {
00565 extern "C" int remove(const char *path) {
00566     FilePath fp(path);
00567     FileSystemHandle *fs = fp.fileSystem();
00568     if (fs == NULL) {
00569         errno = ENODEV;
00570         return -1;
00571     }
00572 
00573     int err = fs->remove(fp.fileName());
00574     if (err < 0) {
00575         errno = -err;
00576         return -1;
00577     } else {
00578         return 0;
00579     }
00580 }
00581 
00582 extern "C" int rename(const char *oldname, const char *newname) {
00583     FilePath fpOld(oldname);
00584     FilePath fpNew(newname);
00585     FileSystemHandle *fsOld = fpOld.fileSystem();
00586     FileSystemHandle *fsNew = fpNew.fileSystem();
00587 
00588     if (fsOld == NULL) {
00589         errno = ENODEV;
00590         return -1;
00591     }
00592 
00593     /* rename only if both files are on the same FS */
00594     if (fsOld != fsNew) {
00595         errno = EXDEV;
00596         return -1;
00597     }
00598 
00599     int err = fsOld->rename(fpOld.fileName(), fpNew.fileName());
00600     if (err < 0) {
00601         errno = -err;
00602         return -1;
00603     } else {
00604         return 0;
00605     }
00606 }
00607 
00608 extern "C" char *tmpnam(char *s) {
00609     errno = EBADF;
00610     return NULL;
00611 }
00612 
00613 extern "C" FILE *tmpfile() {
00614     errno = EBADF;
00615     return NULL;
00616 }
00617 } // namespace std
00618 
00619 #ifdef __ARMCC_VERSION
00620 extern "C" char *_sys_command_string(char *cmd, int len) {
00621     return NULL;
00622 }
00623 #endif
00624 
00625 extern "C" DIR *opendir(const char *path) {
00626     FilePath fp(path);
00627     FileSystemHandle* fs = fp.fileSystem();
00628     if (fs == NULL) {
00629         errno = ENODEV;
00630         return NULL;
00631     }
00632 
00633     DirHandle *dir;
00634     int err = fs->open(&dir, fp.fileName());
00635     if (err < 0) {
00636         errno = -err;
00637         return NULL;
00638     }
00639 
00640     return dir;
00641 }
00642 
00643 extern "C" struct dirent *readdir(DIR *dir) {
00644     static struct dirent ent;
00645     int err = dir->read(&ent);
00646     if (err < 1) {
00647         if (err < 0) {
00648             errno = -err;
00649         }
00650         return NULL;
00651     }
00652 
00653     return &ent;
00654 }
00655 
00656 extern "C" int closedir(DIR *dir) {
00657     int err = dir->close();
00658     if (err < 0) {
00659         errno = -err;
00660         return -1;
00661     } else {
00662         return 0;
00663     }
00664 }
00665 
00666 extern "C" void rewinddir(DIR *dir) {
00667     dir->rewind();
00668 }
00669 
00670 extern "C" off_t telldir(DIR *dir) {
00671     return dir->tell();
00672 }
00673 
00674 extern "C" void seekdir(DIR *dir, off_t off) {
00675     dir->seek(off);
00676 }
00677 
00678 extern "C" int mkdir(const char *path, mode_t mode) {
00679     FilePath fp(path);
00680     FileSystemHandle *fs = fp.fileSystem();
00681     if (fs == NULL) {
00682         errno = ENODEV;
00683         return -1;
00684     }
00685 
00686     int err = fs->mkdir(fp.fileName(), mode);
00687     if (err < 0) {
00688         errno = -err;
00689         return -1;
00690     } else {
00691         return 0;
00692     }
00693 }
00694 
00695 extern "C" int stat(const char *path, struct stat *st) {
00696     FilePath fp(path);
00697     FileSystemHandle *fs = fp.fileSystem();
00698     if (fs == NULL) {
00699         errno = ENODEV;
00700         return -1;
00701     }
00702 
00703     int err = fs->stat(fp.fileName(), st);
00704     if (err < 0) {
00705         errno = -err;
00706         return -1;
00707     } else {
00708         return 0;
00709     }
00710 }
00711 
00712 #if defined(TOOLCHAIN_GCC)
00713 /* prevents the exception handling name demangling code getting pulled in */
00714 #include "mbed_error.h"
00715 namespace __gnu_cxx {
00716     void __verbose_terminate_handler() {
00717         error("Exception");
00718     }
00719 }
00720 extern "C" WEAK void __cxa_pure_virtual(void);
00721 extern "C" WEAK void __cxa_pure_virtual(void) {
00722     exit(1);
00723 }
00724 
00725 #endif
00726 
00727 // Provide implementation of _sbrk (low-level dynamic memory allocation
00728 // routine) for GCC_ARM which compares new heap pointer with MSP instead of
00729 // SP.  This make it compatible with RTX RTOS thread stacks.
00730 #if defined(TOOLCHAIN_GCC_ARM) || defined(TOOLCHAIN_GCC_CR)
00731 
00732 #if defined(TARGET_CORTEX_A)
00733 extern "C" uint32_t  __HeapLimit;
00734 #endif
00735 
00736 // Turn off the errno macro and use actual global variable instead.
00737 #undef errno
00738 extern "C" int errno;
00739 
00740 // Dynamic memory allocation related syscall.
00741 #if defined(TARGET_NUVOTON)
00742 // Overwrite _sbrk() to support two region model (heap and stack are two distinct regions).
00743 // __wrap__sbrk() is implemented in:
00744 // TARGET_NUMAKER_PFM_NUC472    targets/TARGET_NUVOTON/TARGET_NUC472/TARGET_NUMAKER_PFM_NUC472/TOOLCHAIN_GCC_ARM/nuc472_retarget.c
00745 // TARGET_NUMAKER_PFM_M453      targets/TARGET_NUVOTON/TARGET_M451/TARGET_NUMAKER_PFM_M453/TOOLCHAIN_GCC_ARM/m451_retarget.c
00746 extern "C" void *__wrap__sbrk(int incr);
00747 extern "C" caddr_t _sbrk(int incr) {
00748     return (caddr_t) __wrap__sbrk(incr);
00749 }
00750 #else
00751 // Linker defined symbol used by _sbrk to indicate where heap should start.
00752 extern "C" uint32_t __end__;
00753 extern "C" caddr_t _sbrk(int incr) {
00754     static unsigned char* heap = (unsigned char*)&__end__;
00755     unsigned char*        prev_heap = heap;
00756     unsigned char*        new_heap = heap + incr;
00757 
00758 #if defined(TARGET_CORTEX_A)
00759     if (new_heap >= (unsigned char*)&__HeapLimit) {     /* __HeapLimit is end of heap section */
00760 #else
00761     if (new_heap >= (unsigned char*)__get_MSP()) {
00762 #endif
00763         errno = ENOMEM;
00764         return (caddr_t)-1;
00765     }
00766 
00767     // Additional heap checking if set
00768     if (mbed_heap_size && (new_heap >= mbed_heap_start + mbed_heap_size)) {
00769         errno = ENOMEM;
00770         return (caddr_t)-1;
00771     }
00772 
00773     heap = new_heap;
00774     return (caddr_t) prev_heap;
00775 }
00776 #endif
00777 #endif
00778 
00779 #if defined(TOOLCHAIN_GCC_ARM) || defined(TOOLCHAIN_GCC_CR)
00780 extern "C" void _exit(int return_code) {
00781 #else
00782 namespace std {
00783 extern "C" void exit(int return_code) {
00784 #endif
00785 
00786 #if DEVICE_STDIO_MESSAGES
00787 #if MBED_CONF_PLATFORM_STDIO_FLUSH_AT_EXIT
00788     fflush(stdout);
00789     fflush(stderr);
00790 #endif
00791 #endif
00792 
00793 #if DEVICE_SEMIHOST
00794     if (mbed_interface_connected()) {
00795         semihost_exit();
00796     }
00797 #endif
00798     if (return_code) {
00799         mbed_die();
00800     }
00801 
00802     while (1);
00803 }
00804 
00805 #if !defined(TOOLCHAIN_GCC_ARM) && !defined(TOOLCHAIN_GCC_CR)
00806 } //namespace std
00807 #endif
00808 
00809 #if defined(TOOLCHAIN_ARM) || defined(TOOLCHAIN_GCC)
00810 
00811 // This series of function disable the registration of global destructors
00812 // in a dynamic table which will be called when the application exit.
00813 // In mbed, program never exit properly, it dies.
00814 // More informations about this topic for ARMCC here:
00815 // http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/6449.html
00816 extern "C" {
00817 int __aeabi_atexit(void *object, void (*dtor)(void* /*this*/), void *handle) {
00818     return 1;
00819 }
00820 
00821 int __cxa_atexit(void (*dtor)(void* /*this*/), void *object, void *handle) {
00822     return 1;
00823 }
00824 
00825 void __cxa_finalize(void *handle) {
00826 }
00827 
00828 } // end of extern "C"
00829 
00830 #endif
00831 
00832 
00833 #if defined(TOOLCHAIN_GCC)
00834 
00835 /*
00836  * Depending on how newlib is  configured, it is often not enough to define
00837  * __aeabi_atexit, __cxa_atexit and __cxa_finalize in order to override the
00838  * behavior regarding the registration of handlers with atexit.
00839  *
00840  * To overcome this limitation, exit and atexit are overriden here.
00841  */
00842 extern "C"{
00843 
00844 /**
00845  * @brief Retarget of exit for GCC.
00846  * @details Unlike the standard version, this function doesn't call any function
00847  * registered with atexit before calling _exit.
00848  */
00849 void __wrap_exit(int return_code) {
00850     _exit(return_code);
00851 }
00852 
00853 /**
00854  * @brief Retarget atexit from GCC.
00855  * @details This function will always fail and never register any handler to be
00856  * called at exit.
00857  */
00858 int __wrap_atexit(void (*func)()) {
00859     return 1;
00860 }
00861 
00862 }
00863 
00864 #endif
00865 
00866 
00867 
00868 namespace mbed {
00869 
00870 void mbed_set_unbuffered_stream(std::FILE *_file) {
00871 #if defined (__ICCARM__)
00872     char buf[2];
00873     std::setvbuf(_file,buf,_IONBF,NULL);
00874 #else
00875     setbuf(_file, NULL);
00876 #endif
00877 }
00878 
00879 /* Applications are expected to use fdopen()
00880  * not this function directly. This code had to live here because FILE and FileHandle
00881  * processes are all linked together here.
00882  */
00883 std::FILE *mbed_fdopen(FileHandle *fh, const char *mode)
00884 {
00885     // This is to avoid scanf(buf, ":%.4s", fh) and the bloat it brings.
00886     char buf[1 + sizeof(fh)]; /* :(pointer) */
00887     MBED_STATIC_ASSERT(sizeof(buf) == 5, "Pointers should be 4 bytes.");
00888     buf[0] = ':';
00889     memcpy(buf + 1, &fh, sizeof(fh));
00890 
00891     std::FILE *stream = std::fopen(buf, mode);
00892     /* newlib-nano doesn't appear to ever call _isatty itself, so
00893      * happily fully buffers an interactive stream. Deal with that here.
00894      */
00895     if (stream && fh->isatty()) {
00896         mbed_set_unbuffered_stream(stream);
00897     }
00898     return stream;
00899 }
00900 
00901 int mbed_getc(std::FILE *_file){
00902 #if defined(__IAR_SYSTEMS_ICC__ ) && (__VER__ < 8000000)
00903     /*This is only valid for unbuffered streams*/
00904     int res = std::fgetc(_file);
00905     if (res>=0){
00906         _file->_Mode = (unsigned short)(_file->_Mode & ~ 0x1000);/* Unset read mode */
00907         _file->_Rend = _file->_Wend;
00908         _file->_Next = _file->_Wend;
00909     }
00910     return res;
00911 #else
00912     return std::fgetc(_file);
00913 #endif
00914 }
00915 
00916 char* mbed_gets(char*s, int size, std::FILE *_file){
00917 #if defined(__IAR_SYSTEMS_ICC__ ) && (__VER__ < 8000000)
00918     /*This is only valid for unbuffered streams*/
00919     char *str = fgets(s,size,_file);
00920     if (str!=NULL){
00921         _file->_Mode = (unsigned short)(_file->_Mode & ~ 0x1000);/* Unset read mode */
00922         _file->_Rend = _file->_Wend;
00923         _file->_Next = _file->_Wend;
00924     }
00925     return str;
00926 #else
00927     return std::fgets(s,size,_file);
00928 #endif
00929 }
00930 
00931 } // namespace mbed
00932 
00933 #if defined (__ICCARM__)
00934 // Stub out locks when an rtos is not present
00935 extern "C" WEAK void __iar_system_Mtxinit(__iar_Rmtx *mutex) {}
00936 extern "C" WEAK void __iar_system_Mtxdst(__iar_Rmtx *mutex) {}
00937 extern "C" WEAK void __iar_system_Mtxlock(__iar_Rmtx *mutex) {}
00938 extern "C" WEAK void __iar_system_Mtxunlock(__iar_Rmtx *mutex) {}
00939 extern "C" WEAK void __iar_file_Mtxinit(__iar_Rmtx *mutex) {}
00940 extern "C" WEAK void __iar_file_Mtxdst(__iar_Rmtx *mutex) {}
00941 extern "C" WEAK void __iar_file_Mtxlock(__iar_Rmtx *mutex) {}
00942 extern "C" WEAK void __iar_file_Mtxunlock(__iar_Rmtx *mutex) {}
00943 #if defined(__IAR_SYSTEMS_ICC__ ) && (__VER__ >= 8000000)
00944 #pragma section="__iar_tls$$DATA"
00945 extern "C" WEAK void *__aeabi_read_tp (void) {
00946   // Thread Local storage is not supported, using main thread memory for errno
00947   return __section_begin("__iar_tls$$DATA");
00948 }
00949 #endif
00950 #elif defined(__CC_ARM)
00951 // Do nothing
00952 #elif defined (__GNUC__)
00953 struct _reent;
00954 // Stub out locks when an rtos is not present
00955 extern "C" WEAK void __rtos_malloc_lock( struct _reent *_r ) {}
00956 extern "C" WEAK void __rtos_malloc_unlock( struct _reent *_r ) {}
00957 extern "C" WEAK void __rtos_env_lock( struct _reent *_r ) {}
00958 extern "C" WEAK void __rtos_env_unlock( struct _reent *_r ) {}
00959 
00960 extern "C" void __malloc_lock( struct _reent *_r )
00961 {
00962     __rtos_malloc_lock(_r);
00963 }
00964 
00965 extern "C" void __malloc_unlock( struct _reent *_r )
00966 {
00967     __rtos_malloc_unlock(_r);
00968 }
00969 
00970 extern "C" void __env_lock( struct _reent *_r )
00971 {
00972     __rtos_env_lock(_r);
00973 }
00974 
00975 extern "C" void __env_unlock( struct _reent *_r )
00976 {
00977     __rtos_env_unlock(_r);
00978 }
00979 
00980 #define CXA_GUARD_INIT_DONE             (1 << 0)
00981 #define CXA_GUARD_INIT_IN_PROGRESS      (1 << 1)
00982 #define CXA_GUARD_MASK                  (CXA_GUARD_INIT_DONE | CXA_GUARD_INIT_IN_PROGRESS)
00983 
00984 extern "C" int __cxa_guard_acquire(int *guard_object_p)
00985 {
00986     uint8_t *guard_object = (uint8_t *)guard_object_p;
00987     if (CXA_GUARD_INIT_DONE == (*guard_object & CXA_GUARD_MASK)) {
00988         return 0;
00989     }
00990     singleton_lock();
00991     if (CXA_GUARD_INIT_DONE == (*guard_object & CXA_GUARD_MASK)) {
00992         singleton_unlock();
00993         return 0;
00994     }
00995     MBED_ASSERT(0 == (*guard_object & CXA_GUARD_MASK));
00996     *guard_object = *guard_object | CXA_GUARD_INIT_IN_PROGRESS;
00997     return 1;
00998 }
00999 
01000 extern "C" void __cxa_guard_release(int *guard_object_p)
01001 {
01002     uint8_t *guard_object = (uint8_t *)guard_object_p;
01003     MBED_ASSERT(CXA_GUARD_INIT_IN_PROGRESS == (*guard_object & CXA_GUARD_MASK));
01004     *guard_object = (*guard_object & ~CXA_GUARD_MASK) | CXA_GUARD_INIT_DONE;
01005     singleton_unlock();
01006 }
01007 
01008 extern "C" void __cxa_guard_abort(int *guard_object_p)
01009 {
01010     uint8_t *guard_object = (uint8_t *)guard_object_p;
01011     MBED_ASSERT(CXA_GUARD_INIT_IN_PROGRESS == (*guard_object & CXA_GUARD_MASK));
01012     *guard_object = *guard_object & ~CXA_GUARD_INIT_IN_PROGRESS;
01013     singleton_unlock();
01014 }
01015 
01016 #endif
01017 
01018 void *operator new(std::size_t count)
01019 {
01020     void *buffer = malloc(count);
01021     if (NULL == buffer) {
01022         error("Operator new out of memory\r\n");
01023     }
01024     return buffer;
01025 }
01026 
01027 void *operator new[](std::size_t count)
01028 {
01029     void *buffer = malloc(count);
01030     if (NULL == buffer) {
01031         error("Operator new[] out of memory\r\n");
01032     }
01033     return buffer;
01034 }
01035 
01036 void *operator new(std::size_t count, const std::nothrow_t& tag)
01037 {
01038     return malloc(count);
01039 }
01040 
01041 void *operator new[](std::size_t count, const std::nothrow_t& tag)
01042 {
01043     return malloc(count);
01044 }
01045 
01046 void operator delete(void *ptr)
01047 {
01048     if (ptr != NULL) {
01049         free(ptr);
01050     }
01051 }
01052 void operator delete[](void *ptr)
01053 {
01054     if (ptr != NULL) {
01055         free(ptr);
01056     }
01057 }
01058 
01059 /* @brief   standard c library clock() function.
01060  *
01061  * This function returns the number of clock ticks elapsed since the start of the program.
01062  *
01063  * @note Synchronization level: Thread safe
01064  *
01065  * @return
01066  *  the number of clock ticks elapsed since the start of the program.
01067  *
01068  * */
01069 extern "C" clock_t clock()
01070 {
01071     _mutex->lock();
01072     clock_t t = ticker_read(get_us_ticker_data());
01073     t /= 1000000 / CLOCKS_PER_SEC; // convert to processor time
01074     _mutex->unlock();
01075     return t;
01076 }
01077 
01078 // temporary - Default to 1MHz at 32 bits if target does not have us_ticker_get_info
01079 MBED_WEAK const ticker_info_t* us_ticker_get_info()
01080 {
01081     static const ticker_info_t info = {
01082         1000000,
01083         32
01084     };
01085     return &info;
01086 }
01087 
01088 // temporary - Default to 1MHz at 32 bits if target does not have lp_ticker_get_info
01089 MBED_WEAK const ticker_info_t* lp_ticker_get_info()
01090 {
01091     static const ticker_info_t info = {
01092         1000000,
01093         32
01094     };
01095     return &info;
01096 }