Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
retarget.cpp
00001 /* mbed Microcontroller Library 00002 * Copyright (c) 2006-2013 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 "platform.h" 00017 #include "FileHandle.h" 00018 #include "FileSystemLike.h" 00019 #include "FilePath.h" 00020 #include "serial_api.h" 00021 #include "toolchain.h" 00022 #include <errno.h> 00023 00024 #if defined(__ARMCC_VERSION) 00025 # include <rt_sys.h> 00026 # define PREFIX(x) _sys##x 00027 # define OPEN_MAX _SYS_OPEN 00028 # ifdef __MICROLIB 00029 # pragma import(__use_full_stdio) 00030 # endif 00031 00032 #elif defined(__ICCARM__) 00033 # include <yfuns.h> 00034 # define PREFIX(x) _##x 00035 # define OPEN_MAX 16 00036 00037 # define STDIN_FILENO 0 00038 # define STDOUT_FILENO 1 00039 # define STDERR_FILENO 2 00040 00041 #else 00042 # include <sys/stat.h> 00043 # include <sys/unistd.h> 00044 # include <sys/syslimits.h> 00045 # define PREFIX(x) x 00046 #endif 00047 00048 using namespace mbed; 00049 00050 #if defined(__MICROLIB) && (__ARMCC_VERSION>5030000) 00051 // Before version 5.03, we were using a patched version of microlib with proper names 00052 extern const char __stdin_name[] = ":tt"; 00053 extern const char __stdout_name[] = ":tt"; 00054 extern const char __stderr_name[] = ":tt"; 00055 00056 #else 00057 extern const char __stdin_name[] = "/stdin"; 00058 extern const char __stdout_name[] = "/stdout"; 00059 extern const char __stderr_name[] = "/stderr"; 00060 #endif 00061 00062 /* newlib has the filehandle field in the FILE struct as a short, so 00063 * we can't just return a Filehandle* from _open and instead have to 00064 * put it in a filehandles array and return the index into that array 00065 * (or rather index+3, as filehandles 0-2 are stdin/out/err). 00066 */ 00067 static FileHandle *filehandles[OPEN_MAX]; 00068 00069 FileHandle::~FileHandle() { 00070 /* Remove all open filehandles for this */ 00071 for (unsigned int fh_i = 0; fh_i < sizeof(filehandles)/sizeof(*filehandles); fh_i++) { 00072 if (filehandles[fh_i] == this) { 00073 filehandles[fh_i] = NULL; 00074 } 00075 } 00076 } 00077 00078 #if DEVICE_SERIAL 00079 extern int stdio_uart_inited; 00080 extern serial_t stdio_uart; 00081 #endif 00082 00083 static void init_serial() { 00084 #if DEVICE_SERIAL 00085 if (stdio_uart_inited) return; 00086 serial_init(&stdio_uart, STDIO_UART_TX, STDIO_UART_RX); 00087 #endif 00088 } 00089 00090 static inline int openmode_to_posix(int openmode) { 00091 int posix = openmode; 00092 #ifdef __ARMCC_VERSION 00093 if (openmode & OPEN_PLUS) { 00094 posix = O_RDWR; 00095 } else if(openmode & OPEN_W) { 00096 posix = O_WRONLY; 00097 } else if(openmode & OPEN_A) { 00098 posix = O_WRONLY|O_APPEND; 00099 } else { 00100 posix = O_RDONLY; 00101 } 00102 /* a, w, a+, w+ all create if file does not already exist */ 00103 if (openmode & (OPEN_A|OPEN_W)) { 00104 posix |= O_CREAT; 00105 } 00106 /* w and w+ truncate */ 00107 if (openmode & OPEN_W) { 00108 posix |= O_TRUNC; 00109 } 00110 #elif defined(__ICCARM__) 00111 switch (openmode & _LLIO_RDWRMASK) { 00112 case _LLIO_RDONLY: posix = O_RDONLY; break; 00113 case _LLIO_WRONLY: posix = O_WRONLY; break; 00114 case _LLIO_RDWR : posix = O_RDWR ; break; 00115 } 00116 if (openmode & _LLIO_CREAT ) posix |= O_CREAT; 00117 if (openmode & _LLIO_APPEND) posix |= O_APPEND; 00118 if (openmode & _LLIO_TRUNC ) posix |= O_TRUNC; 00119 #endif 00120 return posix; 00121 } 00122 00123 extern "C" FILEHANDLE PREFIX(_open)(const char* name, int openmode) { 00124 #if defined(__MICROLIB) && (__ARMCC_VERSION>5030000) 00125 // Before version 5.03, we were using a patched version of microlib with proper names 00126 // This is the workaround that the microlib author suggested us 00127 static int n = 0; 00128 if (!std::strcmp(name, ":tt")) return n++; 00129 00130 #else 00131 /* Use the posix convention that stdin,out,err are filehandles 0,1,2. 00132 */ 00133 if (std::strcmp(name, __stdin_name) == 0) { 00134 init_serial(); 00135 return 0; 00136 } else if (std::strcmp(name, __stdout_name) == 0) { 00137 init_serial(); 00138 return 1; 00139 } else if (std::strcmp(name, __stderr_name) == 0) { 00140 init_serial(); 00141 return 2; 00142 } 00143 #endif 00144 00145 // find the first empty slot in filehandles 00146 unsigned int fh_i; 00147 for (fh_i = 0; fh_i < sizeof(filehandles)/sizeof(*filehandles); fh_i++) { 00148 if (filehandles[fh_i] == NULL) break; 00149 } 00150 if (fh_i >= sizeof(filehandles)/sizeof(*filehandles)) { 00151 return -1; 00152 } 00153 00154 FileHandle *res; 00155 00156 /* FILENAME: ":0x12345678" describes a FileLike* */ 00157 if (name[0] == ':') { 00158 void *p; 00159 sscanf(name, ":%p", &p); 00160 res = (FileHandle*)p; 00161 00162 /* FILENAME: "/file_system/file_name" */ 00163 } else { 00164 FilePath path(name); 00165 00166 if (!path.exists()) 00167 return -1; 00168 else if (path.isFile()) { 00169 res = path.file(); 00170 } else { 00171 FileSystemLike *fs = path.fileSystem(); 00172 if (fs == NULL) return -1; 00173 int posix_mode = openmode_to_posix(openmode); 00174 res = fs->open(path.fileName(), posix_mode); /* NULL if fails */ 00175 } 00176 } 00177 00178 if (res == NULL) return -1; 00179 filehandles[fh_i] = res; 00180 00181 return fh_i + 3; // +3 as filehandles 0-2 are stdin/out/err 00182 } 00183 00184 extern "C" int PREFIX(_close)(FILEHANDLE fh) { 00185 if (fh < 3) return 0; 00186 00187 FileHandle* fhc = filehandles[fh-3]; 00188 filehandles[fh-3] = NULL; 00189 if (fhc == NULL) return -1; 00190 00191 return fhc->close(); 00192 } 00193 00194 #if defined(__ICCARM__) 00195 extern "C" size_t __write (int fh, const unsigned char *buffer, size_t length) { 00196 #else 00197 extern "C" int PREFIX(_write)(FILEHANDLE fh, const unsigned char *buffer, unsigned int length, int mode) { 00198 #endif 00199 int n; // n is the number of bytes written 00200 if (fh < 3) { 00201 #if DEVICE_SERIAL 00202 if (!stdio_uart_inited) init_serial(); 00203 for (unsigned int i = 0; i < length; i++) { 00204 serial_putc(&stdio_uart, buffer[i]); 00205 } 00206 #endif 00207 n = length; 00208 } else { 00209 FileHandle* fhc = filehandles[fh-3]; 00210 if (fhc == NULL) return -1; 00211 00212 n = fhc->write(buffer, length); 00213 } 00214 #ifdef __ARMCC_VERSION 00215 return length-n; 00216 #else 00217 return n; 00218 #endif 00219 } 00220 00221 #if defined(__ICCARM__) 00222 extern "C" size_t __read (int fh, unsigned char *buffer, size_t length) { 00223 #else 00224 extern "C" int PREFIX(_read)(FILEHANDLE fh, unsigned char *buffer, unsigned int length, int mode) { 00225 #endif 00226 int n; // n is the number of bytes read 00227 if (fh < 3) { 00228 // only read a character at a time from stdin 00229 #if DEVICE_SERIAL 00230 if (!stdio_uart_inited) init_serial(); 00231 *buffer = serial_getc(&stdio_uart); 00232 #endif 00233 n = 1; 00234 } else { 00235 FileHandle* fhc = filehandles[fh-3]; 00236 if (fhc == NULL) return -1; 00237 00238 n = fhc->read(buffer, length); 00239 } 00240 #ifdef __ARMCC_VERSION 00241 return length-n; 00242 #else 00243 return n; 00244 #endif 00245 } 00246 00247 #ifdef __ARMCC_VERSION 00248 extern "C" int PREFIX(_istty)(FILEHANDLE fh) 00249 #else 00250 extern "C" int _isatty(FILEHANDLE fh) 00251 #endif 00252 { 00253 /* stdin, stdout and stderr should be tty */ 00254 if (fh < 3) return 1; 00255 00256 FileHandle* fhc = filehandles[fh-3]; 00257 if (fhc == NULL) return -1; 00258 00259 return fhc->isatty(); 00260 } 00261 00262 extern "C" 00263 #if defined(__ARMCC_VERSION) 00264 int _sys_seek(FILEHANDLE fh, long position) 00265 #elif defined(__ICCARM__) 00266 long __lseek(int fh, long offset, int whence) 00267 #else 00268 int _lseek(FILEHANDLE fh, int offset, int whence) 00269 #endif 00270 { 00271 if (fh < 3) return 0; 00272 00273 FileHandle* fhc = filehandles[fh-3]; 00274 if (fhc == NULL) return -1; 00275 00276 #if defined(__ARMCC_VERSION) 00277 return fhc->lseek(position, SEEK_SET); 00278 #else 00279 return fhc->lseek(offset, whence); 00280 #endif 00281 } 00282 00283 #ifdef __ARMCC_VERSION 00284 extern "C" int PREFIX(_ensure)(FILEHANDLE fh) { 00285 if (fh < 3) return 0; 00286 00287 FileHandle* fhc = filehandles[fh-3]; 00288 if (fhc == NULL) return -1; 00289 00290 return fhc->fsync(); 00291 } 00292 00293 extern "C" long PREFIX(_flen)(FILEHANDLE fh) { 00294 if (fh < 3) return 0; 00295 00296 FileHandle* fhc = filehandles[fh-3]; 00297 if (fhc == NULL) return -1; 00298 00299 return fhc->flen(); 00300 } 00301 #endif 00302 00303 00304 #if !defined(__ARMCC_VERSION) && !defined(__ICCARM__) 00305 extern "C" int _fstat(int fd, struct stat *st) { 00306 if ((STDOUT_FILENO == fd) || (STDERR_FILENO == fd) || (STDIN_FILENO == fd)) { 00307 st->st_mode = S_IFCHR; 00308 return 0; 00309 } 00310 00311 errno = EBADF; 00312 return -1; 00313 } 00314 #endif 00315 00316 namespace std { 00317 extern "C" int remove(const char *path) { 00318 FilePath fp(path); 00319 FileSystemLike *fs = fp.fileSystem(); 00320 if (fs == NULL) return -1; 00321 00322 return fs->remove(fp.fileName()); 00323 } 00324 00325 extern "C" int rename(const char *oldname, const char *newname) { 00326 FilePath fpOld(oldname); 00327 FilePath fpNew(newname); 00328 FileSystemLike *fsOld = fpOld.fileSystem(); 00329 FileSystemLike *fsNew = fpNew.fileSystem(); 00330 00331 /* rename only if both files are on the same FS */ 00332 if (fsOld != fsNew || fsOld == NULL) return -1; 00333 00334 return fsOld->rename(fpOld.fileName(), fpNew.fileName()); 00335 } 00336 00337 extern "C" char *tmpnam(char *s) { 00338 return NULL; 00339 } 00340 00341 extern "C" FILE *tmpfile() { 00342 return NULL; 00343 } 00344 } // namespace std 00345 00346 #ifdef __ARMCC_VERSION 00347 extern "C" char *_sys_command_string(char *cmd, int len) { 00348 return NULL; 00349 } 00350 #endif 00351 00352 extern "C" DIR *opendir(const char *path) { 00353 /* root dir is FileSystemLike */ 00354 if (path[0] == '/' && path[1] == 0) { 00355 return FileSystemLike::opendir(); 00356 } 00357 00358 FilePath fp(path); 00359 FileSystemLike* fs = fp.fileSystem(); 00360 if (fs == NULL) return NULL; 00361 00362 return fs->opendir(fp.fileName()); 00363 } 00364 00365 extern "C" struct dirent *readdir(DIR *dir) { 00366 return dir->readdir(); 00367 } 00368 00369 extern "C" int closedir(DIR *dir) { 00370 return dir->closedir(); 00371 } 00372 00373 extern "C" void rewinddir(DIR *dir) { 00374 dir->rewinddir(); 00375 } 00376 00377 extern "C" off_t telldir(DIR *dir) { 00378 return dir->telldir(); 00379 } 00380 00381 extern "C" void seekdir(DIR *dir, off_t off) { 00382 dir->seekdir(off); 00383 } 00384 00385 extern "C" int mkdir(const char *path, mode_t mode) { 00386 FilePath fp(path); 00387 FileSystemLike *fs = fp.fileSystem(); 00388 if (fs == NULL) return -1; 00389 00390 return fs->mkdir(fp.fileName(), mode); 00391 } 00392 00393 #if defined(TOOLCHAIN_GCC) 00394 /* prevents the exception handling name demangling code getting pulled in */ 00395 #include "mbed_error.h" 00396 namespace __gnu_cxx { 00397 void __verbose_terminate_handler() { 00398 error("Exception"); 00399 } 00400 } 00401 extern "C" WEAK void __cxa_pure_virtual(void); 00402 extern "C" WEAK void __cxa_pure_virtual(void) { 00403 exit(1); 00404 } 00405 00406 #endif 00407 00408 // **************************************************************************** 00409 // mbed_main is a function that is called before main() 00410 // mbed_sdk_init() is also a function that is called before main(), but unlike 00411 // mbed_main(), it is not meant for user code, but for the SDK itself to perform 00412 // initializations before main() is called. 00413 00414 extern "C" WEAK void mbed_main(void); 00415 extern "C" WEAK void mbed_main(void) { 00416 } 00417 00418 extern "C" WEAK void mbed_sdk_init(void); 00419 extern "C" WEAK void mbed_sdk_init(void) { 00420 } 00421 00422 #if defined(TOOLCHAIN_ARM) 00423 extern "C" int $Super$$main(void); 00424 00425 extern "C" int $Sub$$main(void) { 00426 mbed_sdk_init(); 00427 mbed_main(); 00428 return $Super$$main(); 00429 } 00430 #elif defined(TOOLCHAIN_GCC) 00431 extern "C" int __real_main(void); 00432 00433 extern "C" int __wrap_main(void) { 00434 mbed_sdk_init(); 00435 mbed_main(); 00436 return __real_main(); 00437 } 00438 #elif defined(TOOLCHAIN_IAR) 00439 // IAR doesn't have the $Super/$Sub mechanism of armcc, nor something equivalent 00440 // to ld's --wrap. It does have a --redirect, but that doesn't help, since redirecting 00441 // 'main' to another symbol looses the original 'main' symbol. However, its startup 00442 // code will call a function to setup argc and argv (__iar_argc_argv) if it is defined. 00443 // Since mbed doesn't use argc/argv, we use this function to call our mbed_main. 00444 extern "C" void __iar_argc_argv() { 00445 mbed_sdk_init(); 00446 mbed_main(); 00447 } 00448 #endif 00449 00450 // Provide implementation of _sbrk (low-level dynamic memory allocation 00451 // routine) for GCC_ARM which compares new heap pointer with MSP instead of 00452 // SP. This make it compatible with RTX RTOS thread stacks. 00453 #if defined(TOOLCHAIN_GCC_ARM) 00454 // Linker defined symbol used by _sbrk to indicate where heap should start. 00455 extern "C" int __end__; 00456 00457 // Turn off the errno macro and use actual global variable instead. 00458 #undef errno 00459 extern "C" int errno; 00460 00461 // For ARM7 only 00462 register unsigned char * stack_ptr __asm ("sp"); 00463 00464 // Dynamic memory allocation related syscall. 00465 extern "C" caddr_t _sbrk(int incr) { 00466 static unsigned char* heap = (unsigned char*)&__end__; 00467 unsigned char* prev_heap = heap; 00468 unsigned char* new_heap = heap + incr; 00469 00470 #if defined(TARGET_ARM7) 00471 if (new_heap >= stack_ptr) { 00472 #else 00473 if (new_heap >= (unsigned char*)__get_MSP()) { 00474 #endif 00475 errno = ENOMEM; 00476 return (caddr_t)-1; 00477 } 00478 00479 heap = new_heap; 00480 return (caddr_t) prev_heap; 00481 } 00482 #endif 00483 00484 00485 namespace mbed { 00486 00487 void mbed_set_unbuffered_stream(FILE *_file) { 00488 #if defined (__ICCARM__) 00489 char buf[2]; 00490 std::setvbuf(_file,buf,_IONBF,NULL); 00491 #else 00492 setbuf(_file, NULL); 00493 #endif 00494 } 00495 00496 int mbed_getc(FILE *_file){ 00497 #if defined (__ICCARM__) 00498 /*This is only valid for unbuffered streams*/ 00499 int res = std::fgetc(_file); 00500 if (res>=0){ 00501 _file->_Mode = (unsigned short)(_file->_Mode & ~ 0x1000);/* Unset read mode */ 00502 _file->_Rend = _file->_Wend; 00503 _file->_Next = _file->_Wend; 00504 } 00505 return res; 00506 #else 00507 return std::fgetc(_file); 00508 #endif 00509 } 00510 00511 char* mbed_gets(char*s, int size, FILE *_file){ 00512 #if defined (__ICCARM__) 00513 /*This is only valid for unbuffered streams*/ 00514 char *str = fgets(s,size,_file); 00515 if (str!=NULL){ 00516 _file->_Mode = (unsigned short)(_file->_Mode & ~ 0x1000);/* Unset read mode */ 00517 _file->_Rend = _file->_Wend; 00518 _file->_Next = _file->_Wend; 00519 } 00520 return str; 00521 #else 00522 return std::fgets(s,size,_file); 00523 #endif 00524 } 00525 00526 } // namespace mbed 00527 00528 00529 00530 00531 00532 00533 00534
Generated on Tue Jul 12 2022 19:07:09 by
