Ben Katz / mbed-dev_spine

Dependents:   SPIne CH_Communicatuin_Test CH_Communicatuin_Test2 MCP_SPIne ... more

Fork of mbed-dev-f303 by Ben Katz

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