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.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
mbed_retarget.cpp
00001 /* mbed Microcontroller Library 00002 * Copyright (c) 2006-2019 ARM Limited 00003 * SPDX-License-Identifier: Apache-2.0 00004 * 00005 * Licensed under the Apache License, Version 2.0 (the "License"); 00006 * you may not use this file except in compliance with the License. 00007 * You may obtain a copy of the License at 00008 * 00009 * http://www.apache.org/licenses/LICENSE-2.0 00010 * 00011 * Unless required by applicable law or agreed to in writing, software 00012 * distributed under the License is distributed on an "AS IS" BASIS, 00013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00014 * See the License for the specific language governing permissions and 00015 * limitations under the License. 00016 */ 00017 00018 #include <mstd_mutex> 00019 #include <time.h> 00020 #include "platform/platform.h" 00021 #include "platform/FilePath.h" 00022 #include "hal/serial_api.h" 00023 #include "hal/us_ticker_api.h" 00024 #include "platform/mbed_toolchain.h" 00025 #include "platform/mbed_semihost_api.h" 00026 #include "platform/mbed_interface.h" 00027 #include "platform/SingletonPtr.h" 00028 #include "platform/PlatformMutex.h" 00029 #include "platform/mbed_error.h" 00030 #include "platform/mbed_atomic.h" 00031 #include "platform/mbed_critical.h" 00032 #include "platform/mbed_poll.h" 00033 #include "drivers/UARTSerial.h" 00034 #include "hal/us_ticker_api.h" 00035 #include "hal/lp_ticker_api.h" 00036 #include "hal/static_pinmap.h" 00037 #include <stdlib.h> 00038 #include <string.h> 00039 #include <limits.h> 00040 #ifndef SSIZE_MAX 00041 #define SSIZE_MAX INT_MAX 00042 #endif 00043 #include <stdio.h> 00044 #include <errno.h> 00045 #include "platform/mbed_retarget.h" 00046 00047 static SingletonPtr<PlatformMutex> _mutex; 00048 00049 #if defined(__ARMCC_VERSION) 00050 # if __ARMCC_VERSION >= 6010050 00051 # include <arm_compat.h> 00052 # endif 00053 # include <rt_sys.h> 00054 # include <rt_misc.h> 00055 # include <stdint.h> 00056 # define PREFIX(x) _sys##x 00057 # define OPEN_MAX _SYS_OPEN 00058 # ifdef __MICROLIB 00059 # if __ARMCC_VERSION >= 6010050 00060 asm(" .global __use_full_stdio\n"); 00061 # else 00062 # pragma import(__use_full_stdio) 00063 # endif 00064 # endif 00065 00066 #elif defined(__ICCARM__) 00067 # include <yfuns.h> 00068 # define PREFIX(x) _##x 00069 # define OPEN_MAX 16 00070 00071 # define STDIN_FILENO 0 00072 # define STDOUT_FILENO 1 00073 # define STDERR_FILENO 2 00074 00075 #else 00076 # include <sys/syslimits.h> 00077 # define PREFIX(x) x 00078 #endif 00079 00080 #if !MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY 00081 # define RETARGET_OPEN_MAX OPEN_MAX 00082 #else 00083 # define RETARGET_OPEN_MAX 3 00084 #endif // MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY 00085 00086 #define FILE_HANDLE_RESERVED ((FileHandle*)0xFFFFFFFF) 00087 00088 /** 00089 * Macros for setting console flow control. 00090 */ 00091 #define CONSOLE_FLOWCONTROL_RTS 1 00092 #define CONSOLE_FLOWCONTROL_CTS 2 00093 #define CONSOLE_FLOWCONTROL_RTSCTS 3 00094 #define mbed_console_concat_(x) CONSOLE_FLOWCONTROL_##x 00095 #define mbed_console_concat(x) mbed_console_concat_(x) 00096 #define CONSOLE_FLOWCONTROL mbed_console_concat(MBED_CONF_TARGET_CONSOLE_UART_FLOW_CONTROL) 00097 00098 using namespace mbed; 00099 00100 #if defined(__MICROLIB) && (__ARMCC_VERSION>5030000) 00101 // Before version 5.03, we were using a patched version of microlib with proper names 00102 extern const char __stdin_name[] = ":tt"; 00103 extern const char __stdout_name[] = ":tt"; 00104 extern const char __stderr_name[] = ":tt"; 00105 00106 #else 00107 extern const char __stdin_name[] = "/stdin"; 00108 extern const char __stdout_name[] = "/stdout"; 00109 extern const char __stderr_name[] = "/stderr"; 00110 #endif 00111 00112 unsigned char *mbed_heap_start = 0; 00113 uint32_t mbed_heap_size = 0; 00114 00115 #if !MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY 00116 00117 /* newlib has the filehandle field in the FILE struct as a short, so 00118 * we can't just return a Filehandle* from _open and instead have to 00119 * put it in a filehandles array and return the index into that array 00120 */ 00121 static FileHandle *filehandles[RETARGET_OPEN_MAX] = { FILE_HANDLE_RESERVED, FILE_HANDLE_RESERVED, FILE_HANDLE_RESERVED }; 00122 static SingletonPtr<PlatformMutex> filehandle_mutex; 00123 #endif // !MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY 00124 00125 static char stdio_in_prev[RETARGET_OPEN_MAX]; 00126 static char stdio_out_prev[RETARGET_OPEN_MAX]; 00127 00128 namespace mbed { 00129 void mbed_set_unbuffered_stream(std::FILE *_file); 00130 00131 void remove_filehandle(FileHandle *file) 00132 { 00133 #if !MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY 00134 filehandle_mutex->lock(); 00135 /* Remove all open filehandles for this */ 00136 for (unsigned int fh_i = 0; fh_i < sizeof(filehandles) / sizeof(*filehandles); fh_i++) { 00137 if (filehandles[fh_i] == file) { 00138 filehandles[fh_i] = NULL; 00139 } 00140 } 00141 filehandle_mutex->unlock(); 00142 #endif // !MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY 00143 } 00144 } 00145 00146 #if DEVICE_SERIAL 00147 extern int stdio_uart_inited; 00148 extern serial_t stdio_uart; 00149 00150 /* Private FileHandle to implement backwards-compatible functionality of 00151 * direct HAL serial access for default stdin/stdout/stderr. 00152 * This is not a particularly well-behaved FileHandle for a stream, which 00153 * is why it's not public. People should be using UARTSerial. 00154 */ 00155 class DirectSerial : public FileHandle { 00156 public: 00157 DirectSerial(PinName tx, PinName rx, int baud); 00158 DirectSerial(const serial_pinmap_t &static_pinmap, int baud); 00159 virtual ssize_t write(const void *buffer, size_t size); 00160 virtual ssize_t read(void *buffer, size_t size); 00161 virtual off_t seek(off_t offset, int whence = SEEK_SET) 00162 { 00163 return -ESPIPE; 00164 } 00165 virtual off_t size() 00166 { 00167 return -EINVAL; 00168 } 00169 virtual int isatty() 00170 { 00171 return true; 00172 } 00173 virtual int close() 00174 { 00175 return 0; 00176 } 00177 virtual short poll(short events) const; 00178 }; 00179 00180 DirectSerial::DirectSerial(PinName tx, PinName rx, int baud) 00181 { 00182 if (stdio_uart_inited) { 00183 return; 00184 } 00185 static const serial_pinmap_t console_pinmap = get_uart_pinmap(STDIO_UART_TX, STDIO_UART_RX); 00186 serial_init_direct(&stdio_uart, &console_pinmap); 00187 serial_baud(&stdio_uart, baud); 00188 00189 #if CONSOLE_FLOWCONTROL == CONSOLE_FLOWCONTROL_RTS 00190 static const serial_fc_pinmap_t fc_pinmap = get_uart_fc_pinmap(STDIO_UART_RTS, NC); 00191 serial_set_flow_control_direct(&stdio_uart, FlowControlRTS, &fc_pinmap); 00192 #elif CONSOLE_FLOWCONTROL == CONSOLE_FLOWCONTROL_CTS 00193 static const serial_fc_pinmap_t fc_pinmap = get_uart_fc_pinmap(NC, STDIO_UART_CTS); 00194 serial_set_flow_control_direct(&stdio_uart, FlowControlCTS, &fc_pinmap); 00195 #elif CONSOLE_FLOWCONTROL == CONSOLE_FLOWCONTROL_RTSCTS 00196 static const serial_fc_pinmap_t fc_pinmap = get_uart_fc_pinmap(STDIO_UART_RTS, STDIO_UART_CTS); 00197 serial_set_flow_control_direct(&stdio_uart, FlowControlRTSCTS, &fc_pinmap); 00198 #endif 00199 } 00200 00201 DirectSerial::DirectSerial(const serial_pinmap_t &static_pinmap, int baud) 00202 { 00203 if (stdio_uart_inited) { 00204 return; 00205 } 00206 serial_init_direct(&stdio_uart, &static_pinmap); 00207 serial_baud(&stdio_uart, baud); 00208 00209 #if CONSOLE_FLOWCONTROL == CONSOLE_FLOWCONTROL_RTS 00210 static const serial_fc_pinmap_t fc_pinmap = get_uart_fc_pinmap(STDIO_UART_RTS, NC); 00211 serial_set_flow_control_direct(&stdio_uart, FlowControlRTS, &fc_pinmap); 00212 #elif CONSOLE_FLOWCONTROL == CONSOLE_FLOWCONTROL_CTS 00213 static const serial_fc_pinmap_t fc_pinmap = get_uart_fc_pinmap(NC, STDIO_UART_CTS); 00214 serial_set_flow_control_direct(&stdio_uart, FlowControlCTS, &fc_pinmap); 00215 #elif CONSOLE_FLOWCONTROL == CONSOLE_FLOWCONTROL_RTSCTS 00216 static const serial_fc_pinmap_t fc_pinmap = get_uart_fc_pinmap(STDIO_UART_RTS, STDIO_UART_CTS); 00217 serial_set_flow_control_direct(&stdio_uart, FlowControlRTSCTS, &fc_pinmap); 00218 #endif 00219 } 00220 00221 ssize_t DirectSerial::write(const void *buffer, size_t size) 00222 { 00223 const unsigned char *buf = static_cast<const unsigned char *>(buffer); 00224 for (size_t i = 0; i < size; i++) { 00225 serial_putc(&stdio_uart, buf[i]); 00226 } 00227 return size; 00228 } 00229 00230 ssize_t DirectSerial::read(void *buffer, size_t size) 00231 { 00232 unsigned char *buf = static_cast<unsigned char *>(buffer); 00233 if (size == 0) { 00234 return 0; 00235 } 00236 buf[0] = serial_getc(&stdio_uart); 00237 return 1; 00238 } 00239 00240 short DirectSerial::poll(short events) const 00241 { 00242 short revents = 0; 00243 if ((events & POLLIN) && serial_readable(&stdio_uart)) { 00244 revents |= POLLIN; 00245 } 00246 if ((events & POLLOUT) && serial_writable(&stdio_uart)) { 00247 revents |= POLLOUT; 00248 } 00249 return revents; 00250 } 00251 #if MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY 00252 # if MBED_CONF_TARGET_CONSOLE_UART 00253 00254 static void do_serial_init() 00255 { 00256 if (stdio_uart_inited) { 00257 return; 00258 } 00259 00260 static const serial_pinmap_t console_pinmap = get_uart_pinmap(STDIO_UART_TX, STDIO_UART_RX); 00261 serial_init_direct(&stdio_uart, &console_pinmap); 00262 serial_baud(&stdio_uart, MBED_CONF_PLATFORM_STDIO_BAUD_RATE); 00263 #if CONSOLE_FLOWCONTROL == CONSOLE_FLOWCONTROL_RTS 00264 static const serial_fc_pinmap_t fc_pinmap = get_uart_fc_pinmap(STDIO_UART_RTS, NC); 00265 serial_set_flow_control_direct(&stdio_uart, FlowControlRTS, &fc_pinmap); 00266 #elif CONSOLE_FLOWCONTROL == CONSOLE_FLOWCONTROL_CTS 00267 static const serial_fc_pinmap_t fc_pinmap = get_uart_fc_pinmap(NC, STDIO_UART_CTS); 00268 serial_set_flow_control_direct(&stdio_uart, FlowControlCTS, &fc_pinmap); 00269 #elif CONSOLE_FLOWCONTROL == CONSOLE_FLOWCONTROL_RTSCTS 00270 static const serial_fc_pinmap_t fc_pinmap = get_uart_fc_pinmap(STDIO_UART_RTS, STDIO_UART_CTS); 00271 serial_set_flow_control_direct(&stdio_uart, FlowControlRTSCTS, &fc_pinmap); 00272 #endif 00273 } 00274 00275 static void do_serial_init_once() 00276 { 00277 static mstd::once_flag once; 00278 mstd::call_once(once, do_serial_init); 00279 } 00280 00281 #endif // MBED_CONF_TARGET_CONSOLE_UART 00282 #endif // MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY 00283 00284 #endif // DEVICE_SERIAL 00285 00286 class Sink : public FileHandle { 00287 public: 00288 virtual ssize_t write(const void *buffer, size_t size); 00289 virtual ssize_t read(void *buffer, size_t size); 00290 virtual off_t seek(off_t offset, int whence = SEEK_SET) 00291 { 00292 return ESPIPE; 00293 } 00294 virtual off_t size() 00295 { 00296 return -EINVAL; 00297 } 00298 virtual int isatty() 00299 { 00300 return true; 00301 } 00302 virtual int close() 00303 { 00304 return 0; 00305 } 00306 }; 00307 00308 ssize_t Sink::write(const void *buffer, size_t size) 00309 { 00310 // Just swallow the data - this is historical non-DEVICE_SERIAL behaviour 00311 return size; 00312 } 00313 00314 ssize_t Sink::read(void *buffer, size_t size) 00315 { 00316 // Produce 1 zero byte - historical behaviour returned 1 without touching 00317 // the buffer 00318 unsigned char *buf = static_cast<unsigned char *>(buffer); 00319 buf[0] = 0; 00320 return 1; 00321 } 00322 00323 #if !MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY 00324 MBED_WEAK FileHandle *mbed::mbed_target_override_console(int fd) 00325 { 00326 return NULL; 00327 } 00328 00329 MBED_WEAK FileHandle *mbed::mbed_override_console(int fd) 00330 { 00331 return NULL; 00332 } 00333 00334 static FileHandle *default_console() 00335 { 00336 #if MBED_CONF_TARGET_CONSOLE_UART && DEVICE_SERIAL 00337 00338 # if MBED_CONF_PLATFORM_STDIO_BUFFERED_SERIAL 00339 static const serial_pinmap_t console_pinmap = get_uart_pinmap(STDIO_UART_TX, STDIO_UART_RX); 00340 static UARTSerial console(console_pinmap, MBED_CONF_PLATFORM_STDIO_BAUD_RATE); 00341 # if CONSOLE_FLOWCONTROL == CONSOLE_FLOWCONTROL_RTS 00342 static const serial_fc_pinmap_t fc_pinmap = get_uart_fc_pinmap(STDIO_UART_RTS, NC); 00343 console.serial_set_flow_control(SerialBase::RTS, fc_pinmap); 00344 # elif CONSOLE_FLOWCONTROL == CONSOLE_FLOWCONTROL_CTS 00345 static const serial_fc_pinmap_t fc_pinmap = get_uart_fc_pinmap(NC, STDIO_UART_CTS); 00346 console.serial_set_flow_control(SerialBase::CTS, fc_pinmap); 00347 # elif CONSOLE_FLOWCONTROL == CONSOLE_FLOWCONTROL_RTSCTS 00348 static const serial_fc_pinmap_t fc_pinmap = get_uart_fc_pinmap(STDIO_UART_RTS, STDIO_UART_CTS); 00349 console.serial_set_flow_control(SerialBase::RTSCTS, fc_pinmap); 00350 # endif 00351 # else 00352 static const serial_pinmap_t console_pinmap = get_uart_pinmap(STDIO_UART_TX, STDIO_UART_RX); 00353 static DirectSerial console(console_pinmap, MBED_CONF_PLATFORM_STDIO_BAUD_RATE); 00354 # endif 00355 #else // MBED_CONF_TARGET_CONSOLE_UART && DEVICE_SERIAL 00356 static Sink console; 00357 #endif 00358 return &console; 00359 } 00360 00361 /* Locate the default console for stdout, stdin, stderr */ 00362 static FileHandle *get_console(int fd) 00363 { 00364 FileHandle *fh = mbed_override_console(fd); 00365 if (fh) { 00366 return fh; 00367 } 00368 fh = mbed_target_override_console(fd); 00369 if (fh) { 00370 return fh; 00371 } 00372 return default_console(); 00373 } 00374 #endif // !MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY 00375 00376 namespace mbed { 00377 /* Deal with the fact C library may not _open descriptors 0, 1, 2 - auto bind */ 00378 FileHandle *mbed_file_handle(int fd) 00379 { 00380 #if !MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY 00381 if (fd >= RETARGET_OPEN_MAX) { 00382 return NULL; 00383 } 00384 FileHandle *fh = filehandles[fd]; 00385 if (fh == FILE_HANDLE_RESERVED && fd < 3) { 00386 filehandles[fd] = fh = get_console(fd); 00387 } 00388 return fh; 00389 #else 00390 return nullptr; 00391 #endif // !MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY 00392 } 00393 } 00394 00395 00396 #if !MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY 00397 /** 00398 * Sets errno when file opening fails. 00399 * Wipes out the filehandle too. 00400 * 00401 * @param error is a negative error code returned from an mbed function and 00402 * will be negated to store a positive error code in errno 00403 */ 00404 static int handle_open_errors(int error, unsigned filehandle_idx) 00405 { 00406 errno = -error; 00407 // Free file handle 00408 filehandles[filehandle_idx] = NULL; 00409 return -1; 00410 } 00411 00412 static inline int openflags_to_posix(int openflags) 00413 { 00414 int posix = openflags; 00415 #ifdef __ARMCC_VERSION 00416 if (openflags & OPEN_PLUS) { 00417 posix = O_RDWR; 00418 } else if (openflags & OPEN_W) { 00419 posix = O_WRONLY; 00420 } else if (openflags & OPEN_A) { 00421 posix = O_WRONLY | O_APPEND; 00422 } else { 00423 posix = O_RDONLY; 00424 } 00425 /* a, w, a+, w+ all create if file does not already exist */ 00426 if (openflags & (OPEN_A | OPEN_W)) { 00427 posix |= O_CREAT; 00428 } 00429 /* w and w+ truncate */ 00430 if (openflags & OPEN_W) { 00431 posix |= O_TRUNC; 00432 } 00433 #elif defined(__ICCARM__) 00434 switch (openflags & _LLIO_RDWRMASK) { 00435 case _LLIO_RDONLY: 00436 posix = O_RDONLY; 00437 break; 00438 case _LLIO_WRONLY: 00439 posix = O_WRONLY; 00440 break; 00441 case _LLIO_RDWR : 00442 posix = O_RDWR ; 00443 break; 00444 } 00445 if (openflags & _LLIO_CREAT) { 00446 posix |= O_CREAT; 00447 } 00448 if (openflags & _LLIO_APPEND) { 00449 posix |= O_APPEND; 00450 } 00451 if (openflags & _LLIO_TRUNC) { 00452 posix |= O_TRUNC; 00453 } 00454 #elif defined(TOOLCHAIN_GCC) 00455 posix &= ~O_BINARY; 00456 #endif 00457 return posix; 00458 } 00459 00460 static int reserve_filehandle() 00461 { 00462 // find the first empty slot in filehandles, after the slots reserved for stdin/stdout/stderr 00463 filehandle_mutex->lock(); 00464 int fh_i; 00465 for (fh_i = 3; fh_i < RETARGET_OPEN_MAX; fh_i++) { 00466 /* Take a next free filehandle slot available. */ 00467 if (filehandles[fh_i] == NULL) { 00468 break; 00469 } 00470 } 00471 if (fh_i >= RETARGET_OPEN_MAX) { 00472 /* Too many file handles have been opened */ 00473 errno = EMFILE; 00474 filehandle_mutex->unlock(); 00475 return -1; 00476 } 00477 filehandles[fh_i] = FILE_HANDLE_RESERVED; 00478 filehandle_mutex->unlock(); 00479 00480 return fh_i; 00481 } 00482 00483 00484 int mbed::bind_to_fd(FileHandle *fh) 00485 { 00486 int fildes = reserve_filehandle(); 00487 if (fildes < 0) { 00488 return fildes; 00489 } 00490 00491 filehandles[fildes] = fh; 00492 stdio_in_prev[fildes] = 0; 00493 stdio_out_prev[fildes] = 0; 00494 00495 return fildes; 00496 } 00497 00498 static int unbind_from_fd(int fd, FileHandle *fh) 00499 { 00500 if (filehandles[fd] == fh) { 00501 filehandles[fd] = NULL; 00502 return 0; 00503 } else { 00504 errno = EBADF; 00505 return -1; 00506 } 00507 } 00508 00509 #ifndef __IAR_SYSTEMS_ICC__ 00510 /* IAR provides fdopen itself */ 00511 extern "C" std::FILE *fdopen(int fildes, const char *mode) 00512 { 00513 // This is to avoid scanf and the bloat it brings. 00514 char buf[1 + sizeof fildes]; /* @(integer) */ 00515 MBED_STATIC_ASSERT(sizeof buf == 5, "Integers should be 4 bytes."); 00516 buf[0] = '@'; 00517 memcpy(buf + 1, &fildes, sizeof fildes); 00518 00519 std::FILE *stream = std::fopen(buf, mode); 00520 /* newlib-nano doesn't appear to ever call _isatty itself, so 00521 * happily fully buffers an interactive stream. Deal with that here. 00522 */ 00523 if (stream && isatty(fildes)) { 00524 mbed_set_unbuffered_stream(stream); 00525 } 00526 return stream; 00527 } 00528 #endif 00529 00530 namespace mbed { 00531 std::FILE *fdopen(FileHandle *fh, const char *mode) 00532 { 00533 // First reserve the integer file descriptor 00534 int fd = bind_to_fd(fh); 00535 if (fd < 0) { 00536 return NULL; 00537 } 00538 // Then bind that to the C stream. If successful, C library 00539 // takes ownership and responsibility to close. 00540 std::FILE *stream = ::fdopen(fd, mode); 00541 if (!stream) { 00542 unbind_from_fd(fd, fh); 00543 } 00544 return stream; 00545 } 00546 } 00547 #endif // !MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY 00548 00549 00550 /* @brief standard c library fopen() retargeting function. 00551 * 00552 * This function is invoked by the standard c library retargeting to handle fopen() 00553 * 00554 * @return 00555 * On success, a valid FILEHANDLE is returned. 00556 * On failure, -1 is returned and errno is set to an appropriate value e.g. 00557 * ENOENT file not found (default errno setting) 00558 * EMFILE the maximum number of open files was exceeded. 00559 * 00560 * */ 00561 extern "C" FILEHANDLE PREFIX(_open)(const char *name, int openflags) 00562 { 00563 #if defined(__MICROLIB) && (__ARMCC_VERSION>5030000) 00564 #if !defined(MBED_CONF_RTOS_PRESENT) 00565 // valid only for mbed 2 00566 // for ulib, this is invoked after RAM init, prior c++ 00567 // used as hook, as post stack/heap is not active there 00568 extern void mbed_copy_nvic(void); 00569 extern void mbed_sdk_init(void); 00570 00571 static int mbed_sdk_inited = 0; 00572 if (!mbed_sdk_inited) { 00573 mbed_copy_nvic(); 00574 mbed_sdk_init(); 00575 #if DEVICE_USTICKER && MBED_CONF_TARGET_INIT_US_TICKER_AT_BOOT 00576 us_ticker_init(); 00577 #endif 00578 mbed_sdk_inited = 1; 00579 } 00580 #endif 00581 // Before version 5.03, we were using a patched version of microlib with proper names 00582 // This is the workaround that the microlib author suggested us 00583 static int n = 0; 00584 if (std::strcmp(name, ":tt") == 0 && n < 3) { 00585 return n++; 00586 } 00587 #else 00588 /* Use the posix convention that stdin,out,err are filehandles 0,1,2. 00589 */ 00590 if (std::strcmp(name, __stdin_name) == 0) { 00591 mbed_file_handle(STDIN_FILENO); 00592 return STDIN_FILENO; 00593 } else if (std::strcmp(name, __stdout_name) == 0) { 00594 mbed_file_handle(STDOUT_FILENO); 00595 return STDOUT_FILENO; 00596 } else if (std::strcmp(name, __stderr_name) == 0) { 00597 mbed_file_handle(STDERR_FILENO); 00598 return STDERR_FILENO; 00599 } 00600 #endif 00601 #ifndef __IAR_SYSTEMS_ICC__ 00602 #if !MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY 00603 /* FILENAME: "@(integer)" gives an already-allocated descriptor */ 00604 if (name[0] == '@') { 00605 int fd; 00606 memcpy(&fd, name + 1, sizeof fd); 00607 return fd; 00608 } 00609 #endif // !MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY 00610 #endif 00611 #if !MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY 00612 return open(name, openflags_to_posix(openflags)); 00613 #else 00614 return -1; 00615 #endif // !MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY 00616 } 00617 00618 #if !MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY 00619 extern "C" int open(const char *name, int oflag, ...) 00620 { 00621 int fildes = reserve_filehandle(); 00622 if (fildes < 0) { 00623 return fildes; 00624 } 00625 00626 FileHandle *res = NULL; 00627 FilePath path(name); 00628 00629 if (!path.exists()) { 00630 /* The first part of the filename (between first 2 '/') is not a 00631 * registered mount point in the namespace. 00632 */ 00633 return handle_open_errors(-ENODEV, fildes); 00634 } 00635 00636 if (path.isFile()) { 00637 res = path.file(); 00638 } else { 00639 FileSystemHandle *fs = path.fileSystem(); 00640 if (fs == NULL) { 00641 return handle_open_errors(-ENODEV, fildes); 00642 } 00643 int err = fs->open(&res, path.fileName(), oflag); 00644 if (err) { 00645 return handle_open_errors(err, fildes); 00646 } 00647 } 00648 00649 filehandles[fildes] = res; 00650 stdio_in_prev[fildes] = 0; 00651 stdio_out_prev[fildes] = 0; 00652 00653 return fildes; 00654 } 00655 #endif // !MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY 00656 00657 extern "C" int PREFIX(_close)(FILEHANDLE fh) 00658 { 00659 #if !MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY 00660 return close(fh); 00661 #else 00662 return 0; 00663 #endif // !MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY 00664 } 00665 00666 #if !MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY 00667 extern "C" int close(int fildes) 00668 { 00669 FileHandle *fhc = mbed_file_handle(fildes); 00670 filehandles[fildes] = NULL; 00671 if (fhc == NULL) { 00672 errno = EBADF; 00673 return -1; 00674 } 00675 00676 int err = fhc->close(); 00677 if (err < 0) { 00678 errno = -err; 00679 return -1; 00680 } else { 00681 return 0; 00682 } 00683 } 00684 #endif // !MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY 00685 00686 static bool convert_crlf(int fd) 00687 { 00688 #if MBED_CONF_PLATFORM_STDIO_CONVERT_TTY_NEWLINES 00689 return isatty(fd); 00690 #elif MBED_CONF_PLATFORM_STDIO_CONVERT_NEWLINES 00691 return fd < 3 && isatty(fd); 00692 #else 00693 return false; 00694 #endif 00695 } 00696 00697 #if defined(__ICCARM__) 00698 extern "C" size_t __write(int fh, const unsigned char *buffer, size_t length) 00699 { 00700 #else 00701 extern "C" int PREFIX(_write)(FILEHANDLE fh, const unsigned char *buffer, unsigned int length, int mode) 00702 { 00703 #endif 00704 00705 #if defined(MBED_TRAP_ERRORS_ENABLED) && MBED_TRAP_ERRORS_ENABLED && defined(MBED_CONF_RTOS_PRESENT) 00706 if (core_util_is_isr_active() || !core_util_are_interrupts_enabled()) { 00707 MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_PROHIBITED_IN_ISR_CONTEXT), "Error - writing to a file in an ISR or critical section\r\n", fh); 00708 } 00709 #endif 00710 00711 if (length > SSIZE_MAX) { 00712 errno = EINVAL; 00713 return -1; 00714 } 00715 00716 ssize_t slength = length; 00717 ssize_t written = 0; 00718 00719 if (convert_crlf(fh)) { 00720 // local prev is previous in buffer during seek 00721 // stdio_out_prev[fh] is last thing actually written 00722 char prev = stdio_out_prev[fh]; 00723 // Seek for '\n' without preceding '\r'; if found flush 00724 // preceding and insert '\r'. Continue until end of input. 00725 for (ssize_t cur = 0; cur < slength; cur++) { 00726 if (buffer[cur] == '\n' && prev != '\r') { 00727 ssize_t r; 00728 // flush stuff preceding the \n 00729 if (cur > written) { 00730 r = write(fh, buffer + written, cur - written); 00731 if (r < 0) { 00732 return -1; 00733 } 00734 written += r; 00735 if (written < cur) { 00736 // For some reason, didn't write all - give up now 00737 goto finish; 00738 } 00739 stdio_out_prev[fh] = prev; 00740 } 00741 // insert a \r now, leaving the \n still to be written 00742 r = write(fh, "\r", 1); 00743 if (r < 0) { 00744 return -1; 00745 } 00746 if (r < 1) { 00747 goto finish; 00748 } 00749 stdio_out_prev[fh] = '\r'; 00750 } 00751 prev = buffer[cur]; 00752 } 00753 } 00754 00755 // Flush remaining from conversion, or the whole thing if no conversion 00756 if (written < slength) { 00757 ssize_t r = write(fh, buffer + written, slength - written); 00758 if (r < 0) { 00759 return -1; 00760 } 00761 written += r; 00762 if (written > 0) { 00763 stdio_out_prev[fh] = buffer[written - 1]; 00764 } 00765 } 00766 00767 finish: 00768 #ifdef __ARMCC_VERSION 00769 if (written >= 0) { 00770 return slength - written; 00771 } else { 00772 return written; 00773 } 00774 #else 00775 return written; 00776 #endif 00777 } 00778 00779 extern "C" ssize_t write(int fildes, const void *buf, size_t length) 00780 { 00781 #if MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY 00782 if (fildes != STDOUT_FILENO && fildes != STDERR_FILENO) { 00783 errno = EBADF; 00784 return -1; 00785 } 00786 00787 const unsigned char *buffer = static_cast<const unsigned char *>(buf); 00788 00789 for (size_t i = 0; i < length; i++) { 00790 mbed::minimal_console_putc(buffer[i]); 00791 } 00792 00793 ssize_t ret = length; 00794 #else 00795 FileHandle *fhc = mbed_file_handle(fildes); 00796 if (fhc == NULL) { 00797 errno = EBADF; 00798 return -1; 00799 } 00800 00801 ssize_t ret = fhc->write(buf, length); 00802 #endif // MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY 00803 if (ret < 0) { 00804 errno = -ret; 00805 return -1; 00806 } else { 00807 return ret; 00808 } 00809 } 00810 00811 #if MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY 00812 /* Write one character to a serial interface */ 00813 MBED_WEAK int mbed::minimal_console_putc(int c) 00814 { 00815 #if MBED_CONF_TARGET_CONSOLE_UART && DEVICE_SERIAL 00816 do_serial_init_once(); 00817 serial_putc(&stdio_uart, c); 00818 #endif // MBED_CONF_TARGET_CONSOLE_UART && DEVICE_SERIAL 00819 return c; 00820 } 00821 #endif // MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY 00822 00823 #if defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) 00824 extern "C" void PREFIX(_exit)(int return_code) 00825 { 00826 while (1) {} 00827 } 00828 00829 extern "C" void _ttywrch(int ch) 00830 { 00831 char c = ch; 00832 write(STDOUT_FILENO, &c, 1); 00833 } 00834 #endif 00835 00836 #if defined(__ICCARM__) 00837 extern "C" size_t __read(int fh, unsigned char *buffer, size_t length) 00838 { 00839 #else 00840 extern "C" int PREFIX(_read)(FILEHANDLE fh, unsigned char *buffer, unsigned int length, int mode) 00841 { 00842 #endif 00843 00844 #if defined(MBED_TRAP_ERRORS_ENABLED) && MBED_TRAP_ERRORS_ENABLED && defined(MBED_CONF_RTOS_PRESENT) 00845 if (core_util_is_isr_active() || !core_util_are_interrupts_enabled()) { 00846 MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_PROHIBITED_IN_ISR_CONTEXT), "Error - reading from a file in an ISR or critical section\r\n", fh); 00847 } 00848 #endif 00849 00850 if (length > SSIZE_MAX) { 00851 errno = EINVAL; 00852 return -1; 00853 } 00854 00855 ssize_t bytes_read = 0; 00856 00857 if (convert_crlf(fh)) { 00858 while (true) { 00859 char c; 00860 ssize_t r = read(fh, &c, 1); 00861 if (r < 0) { 00862 return -1; 00863 } 00864 if (r == 0) { 00865 return bytes_read; 00866 } 00867 if ((c == '\r' && stdio_in_prev[fh] != '\n') || 00868 (c == '\n' && stdio_in_prev[fh] != '\r')) { 00869 stdio_in_prev[fh] = c; 00870 *buffer = '\n'; 00871 break; 00872 } else if ((c == '\r' && stdio_in_prev[fh] == '\n') || 00873 (c == '\n' && stdio_in_prev[fh] == '\r')) { 00874 stdio_in_prev[fh] = c; 00875 continue; 00876 } else { 00877 stdio_in_prev[fh] = c; 00878 *buffer = c; 00879 break; 00880 } 00881 } 00882 bytes_read = 1; 00883 } else { 00884 bytes_read = read(fh, buffer, length); 00885 } 00886 00887 #ifdef __ARMCC_VERSION 00888 if (bytes_read < 0) { 00889 return -1; 00890 } else if (bytes_read == 0) { 00891 return 0x80000000 | length; // weird EOF indication 00892 } else { 00893 return (ssize_t)length - bytes_read; 00894 } 00895 #else 00896 return bytes_read; 00897 #endif 00898 } 00899 00900 extern "C" ssize_t read(int fildes, void *buf, size_t length) 00901 { 00902 #if MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY 00903 if (fildes != STDIN_FILENO && fildes != STDERR_FILENO) { 00904 errno = EBADF; 00905 return -1; 00906 } 00907 00908 if (length == 0) { 00909 return 0; 00910 } 00911 00912 unsigned char *buffer = static_cast<unsigned char *>(buf); 00913 00914 buffer[0] = minimal_console_getc(); 00915 00916 ssize_t ret = 1; 00917 00918 #else 00919 FileHandle *fhc = mbed_file_handle(fildes); 00920 if (fhc == NULL) { 00921 errno = EBADF; 00922 return -1; 00923 } 00924 00925 ssize_t ret = fhc->read(buf, length); 00926 #endif // MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY 00927 if (ret < 0) { 00928 errno = -ret; 00929 return -1; 00930 } else { 00931 return ret; 00932 } 00933 } 00934 00935 #if MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY 00936 /* Read a character from the serial interface */ 00937 MBED_WEAK int mbed::minimal_console_getc() 00938 { 00939 #if MBED_CONF_TARGET_CONSOLE_UART && DEVICE_SERIAL 00940 do_serial_init_once(); 00941 return serial_getc(&stdio_uart); 00942 #else 00943 return 0; 00944 #endif // MBED_CONF_TARGET_CONSOLE_UART && DEVICE_SERIAL 00945 } 00946 #endif // MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY 00947 00948 00949 #ifdef __ARMCC_VERSION 00950 extern "C" int PREFIX(_istty)(FILEHANDLE fh) 00951 #else 00952 extern "C" int _isatty(FILEHANDLE fh) 00953 #endif 00954 { 00955 return isatty(fh); 00956 } 00957 00958 00959 extern "C" int isatty(int fildes) 00960 { 00961 #if !MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY 00962 FileHandle *fhc = mbed_file_handle(fildes); 00963 if (fhc == NULL) { 00964 errno = EBADF; 00965 return 0; 00966 } 00967 00968 int tty = fhc->isatty(); 00969 if (tty < 0) { 00970 errno = -tty; 00971 return 0; 00972 } else { 00973 return tty; 00974 } 00975 #else 00976 // Is attached to an interactive device 00977 return 1; 00978 #endif // !MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY 00979 } 00980 00981 extern "C" 00982 #if defined(__ARMCC_VERSION) 00983 int _sys_seek(FILEHANDLE fh, long offset) 00984 #elif defined(__ICCARM__) 00985 long __lseek(int fh, long offset, int whence) 00986 #else 00987 int _lseek(FILEHANDLE fh, int offset, int whence) 00988 #endif 00989 { 00990 #if !MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY 00991 #if defined(__ARMCC_VERSION) 00992 int whence = SEEK_SET; 00993 #endif 00994 00995 off_t off = lseek(fh, offset, whence); 00996 // Assuming INT_MAX = LONG_MAX, so we don't care about prototype difference 00997 // coverity[result_independent_of_operands] 00998 if (off > INT_MAX) { 00999 // Be cautious in case off_t is 64-bit 01000 errno = EOVERFLOW; 01001 return -1; 01002 } 01003 return off; 01004 #else 01005 // Not supported 01006 return -1; 01007 #endif // !MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY 01008 } 01009 01010 #if !MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY 01011 extern "C" off_t lseek(int fildes, off_t offset, int whence) 01012 { 01013 FileHandle *fhc = mbed_file_handle(fildes); 01014 if (fhc == NULL) { 01015 errno = EBADF; 01016 return -1; 01017 } 01018 01019 off_t off = fhc->seek(offset, whence); 01020 if (off < 0) { 01021 errno = -off; 01022 return -1; 01023 } 01024 return off; 01025 } 01026 01027 extern "C" int ftruncate(int fildes, off_t length) 01028 { 01029 FileHandle *fhc = mbed_file_handle(fildes); 01030 if (fhc == NULL) { 01031 errno = EBADF; 01032 return -1; 01033 } 01034 01035 int err = fhc->truncate(length); 01036 if (err < 0) { 01037 errno = -err; 01038 return -1; 01039 } else { 01040 return 0; 01041 } 01042 } 01043 01044 #ifdef __ARMCC_VERSION 01045 extern "C" int PREFIX(_ensure)(FILEHANDLE fh) 01046 { 01047 return fsync(fh); 01048 } 01049 #endif 01050 #endif // !MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY 01051 01052 extern "C" int fsync(int fildes) 01053 { 01054 #if !MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY 01055 FileHandle *fhc = mbed_file_handle(fildes); 01056 if (fhc == NULL) { 01057 errno = EBADF; 01058 return -1; 01059 } 01060 01061 int err = fhc->sync(); 01062 if (err < 0) { 01063 errno = -err; 01064 return -1; 01065 } else { 01066 return 0; 01067 } 01068 #else 01069 return -1; 01070 #endif // !MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY 01071 } 01072 01073 01074 #ifdef __ARMCC_VERSION 01075 extern "C" long PREFIX(_flen)(FILEHANDLE fh) 01076 { 01077 #if !MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY 01078 FileHandle *fhc = mbed_file_handle(fh); 01079 if (fhc == NULL) { 01080 errno = EBADF; 01081 return -1; 01082 } 01083 01084 off_t size = fhc->size(); 01085 if (size < 0) { 01086 errno = -size; 01087 return -1; 01088 } 01089 if (size > LONG_MAX) { 01090 errno = EOVERFLOW; 01091 return -1; 01092 } 01093 return size; 01094 #else 01095 // Not supported 01096 return -1; 01097 #endif // !MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY 01098 } 01099 01100 // Do not compile this code for TFM secure target 01101 #if !defined(COMPONENT_SPE) || !defined(TARGET_TFM) 01102 01103 #if !defined(__MICROLIB) 01104 #if defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) 01105 __asm(".global __use_two_region_memory\n\t"); 01106 __asm(".global __use_no_semihosting\n\t"); 01107 #else 01108 #pragma import(__use_two_region_memory) 01109 #endif 01110 #endif 01111 01112 // Through weak-reference, we can check if ARM_LIB_HEAP is defined at run-time. 01113 // If ARM_LIB_HEAP is defined, we can fix heap allocation. 01114 extern MBED_WEAK uint32_t Image$$ARM_LIB_HEAP$$ZI$$Base[]; 01115 extern MBED_WEAK uint32_t Image$$ARM_LIB_HEAP$$ZI$$Limit[]; 01116 01117 // Heap here is considered starting after ZI ends to Stack start 01118 extern uint32_t Image$$ARM_LIB_STACK$$ZI$$Base[]; 01119 extern uint32_t Image$$RW_IRAM1$$ZI$$Limit[]; 01120 01121 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) 01122 { 01123 // Define heap by assuming one-region 01124 uint32_t heap_base = (uint32_t)Image$$RW_IRAM1$$ZI$$Limit; 01125 uint32_t heap_limit = (uint32_t)Image$$ARM_LIB_STACK$$ZI$$Base; 01126 struct __initial_stackheap r; 01127 01128 // Fix heap if ARM_LIB_HEAP is defined 01129 if (Image$$ARM_LIB_HEAP$$ZI$$Base != Image$$ARM_LIB_HEAP$$ZI$$Limit) { 01130 heap_base = (uint32_t) Image$$ARM_LIB_HEAP$$ZI$$Base; 01131 heap_limit = (uint32_t) Image$$ARM_LIB_HEAP$$ZI$$Limit; 01132 } 01133 01134 // Ensure heap_base is 8-byte aligned 01135 heap_base = (heap_base + 7) & ~0x7; 01136 r.heap_base = heap_base; 01137 r.heap_limit = heap_limit; 01138 01139 return r; 01140 } 01141 01142 #if !defined(__MICROLIB) 01143 extern "C" __value_in_regs struct __argc_argv $Super$$__rt_lib_init(unsigned heapbase, unsigned heaptop); 01144 01145 extern "C" __value_in_regs struct __argc_argv $Sub$$__rt_lib_init(unsigned heapbase, unsigned heaptop) 01146 { 01147 // Define heap by assuming one-region 01148 uint32_t heap_base = (uint32_t)Image$$RW_IRAM1$$ZI$$Limit; 01149 uint32_t heap_limit = (uint32_t)Image$$ARM_LIB_STACK$$ZI$$Base; 01150 01151 // Fix heap if ARM_LIB_HEAP is defined 01152 if (Image$$ARM_LIB_HEAP$$ZI$$Base != Image$$ARM_LIB_HEAP$$ZI$$Limit) { 01153 heap_base = (uint32_t) Image$$ARM_LIB_HEAP$$ZI$$Base; 01154 heap_limit = (uint32_t) Image$$ARM_LIB_HEAP$$ZI$$Limit; 01155 } 01156 01157 return $Super$$__rt_lib_init((unsigned)heap_base, (unsigned)heap_limit); 01158 } 01159 #endif 01160 01161 extern "C" __value_in_regs struct __initial_stackheap __user_setup_stackheap(uint32_t R0, uint32_t R1, uint32_t R2, uint32_t R3) 01162 { 01163 return _mbed_user_setup_stackheap(R0, R1, R2, R3); 01164 } 01165 01166 #endif // !defined(COMPONENT_SPE) || !defined(TARGET_TFM) 01167 01168 #endif 01169 01170 #if !MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY 01171 #if !defined(__ARMCC_VERSION) && !defined(__ICCARM__) 01172 extern "C" int _fstat(int fh, struct stat *st) 01173 { 01174 return fstat(fh, st); 01175 } 01176 #endif 01177 01178 extern "C" int fstat(int fildes, struct stat *st) 01179 { 01180 FileHandle *fhc = mbed_file_handle(fildes); 01181 if (fhc == NULL) { 01182 errno = EBADF; 01183 return -1; 01184 } 01185 01186 st->st_mode = fhc->isatty() ? S_IFCHR : S_IFREG; 01187 st->st_size = fhc->size(); 01188 return 0; 01189 } 01190 01191 extern "C" int fcntl(int fildes, int cmd, ...) 01192 { 01193 FileHandle *fhc = mbed_file_handle(fildes); 01194 if (fhc == NULL) { 01195 errno = EBADF; 01196 return -1; 01197 } 01198 01199 switch (cmd) { 01200 case F_GETFL: { 01201 int flags = 0; 01202 if (fhc->is_blocking()) { 01203 flags |= O_NONBLOCK; 01204 } 01205 return flags; 01206 } 01207 case F_SETFL: { 01208 va_list ap; 01209 va_start(ap, cmd); 01210 int flags = va_arg(ap, int); 01211 va_end(ap); 01212 int ret = fhc->set_blocking(flags & O_NONBLOCK); 01213 if (ret < 0) { 01214 errno = -ret; 01215 return -1; 01216 } 01217 return 0; 01218 } 01219 01220 default: { 01221 errno = EINVAL; 01222 return -1; 01223 } 01224 } 01225 } 01226 01227 extern "C" int poll(struct pollfd fds[], nfds_t nfds, int timeout) 01228 { 01229 if (nfds > RETARGET_OPEN_MAX) { 01230 errno = EINVAL; 01231 return -1; 01232 } 01233 01234 struct mbed::pollfh fhs[RETARGET_OPEN_MAX]; 01235 for (nfds_t n = 0; n < nfds; n++) { 01236 // Underlying FileHandle poll returns POLLNVAL if given NULL, so 01237 // we don't need to take special action. 01238 fhs[n].fh = mbed_file_handle(fds[n].fd); 01239 fhs[n].events = fds[n].events; 01240 } 01241 int ret = poll(fhs, nfds, timeout); 01242 for (nfds_t n = 0; n < nfds; n++) { 01243 fds[n].revents = fhs[n].revents; 01244 } 01245 return ret; 01246 } 01247 #endif // !MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY 01248 01249 namespace std { 01250 extern "C" int remove(const char *path) 01251 { 01252 FilePath fp(path); 01253 FileSystemHandle *fs = fp.fileSystem(); 01254 if (fs == NULL) { 01255 errno = ENODEV; 01256 return -1; 01257 } 01258 01259 int err = fs->remove(fp.fileName()); 01260 if (err < 0) { 01261 errno = -err; 01262 return -1; 01263 } else { 01264 return 0; 01265 } 01266 } 01267 01268 extern "C" int rename(const char *oldname, const char *newname) 01269 { 01270 FilePath fpOld(oldname); 01271 FilePath fpNew(newname); 01272 FileSystemHandle *fsOld = fpOld.fileSystem(); 01273 FileSystemHandle *fsNew = fpNew.fileSystem(); 01274 01275 if (fsOld == NULL) { 01276 errno = ENODEV; 01277 return -1; 01278 } 01279 01280 /* rename only if both files are on the same FS */ 01281 if (fsOld != fsNew) { 01282 errno = EXDEV; 01283 return -1; 01284 } 01285 01286 int err = fsOld->rename(fpOld.fileName(), fpNew.fileName()); 01287 if (err < 0) { 01288 errno = -err; 01289 return -1; 01290 } else { 01291 return 0; 01292 } 01293 } 01294 01295 extern "C" char *tmpnam(char *s) 01296 { 01297 errno = EBADF; 01298 return NULL; 01299 } 01300 01301 extern "C" FILE *tmpfile() 01302 { 01303 errno = EBADF; 01304 return NULL; 01305 } 01306 } // namespace std 01307 01308 #ifdef __ARMCC_VERSION 01309 extern "C" char *_sys_command_string(char *cmd, int len) 01310 { 01311 return NULL; 01312 } 01313 #endif 01314 01315 #if !MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY 01316 extern "C" DIR *opendir(const char *path) 01317 { 01318 FilePath fp(path); 01319 FileSystemHandle *fs = fp.fileSystem(); 01320 if (fs == NULL) { 01321 errno = ENODEV; 01322 return NULL; 01323 } 01324 01325 DirHandle *dir; 01326 int err = fs->open(&dir, fp.fileName()); 01327 if (err < 0) { 01328 errno = -err; 01329 return NULL; 01330 } 01331 01332 return dir; 01333 } 01334 01335 extern "C" struct dirent *readdir(DIR *dir) 01336 { 01337 static struct dirent ent; 01338 int err = dir->read(&ent); 01339 if (err < 1) { 01340 if (err < 0) { 01341 errno = -err; 01342 } 01343 return NULL; 01344 } 01345 01346 return &ent; 01347 } 01348 01349 extern "C" int closedir(DIR *dir) 01350 { 01351 int err = dir->close(); 01352 if (err < 0) { 01353 errno = -err; 01354 return -1; 01355 } else { 01356 return 0; 01357 } 01358 } 01359 01360 extern "C" void rewinddir(DIR *dir) 01361 { 01362 dir->rewind(); 01363 } 01364 01365 extern "C" off_t telldir(DIR *dir) 01366 { 01367 return dir->tell(); 01368 } 01369 01370 extern "C" void seekdir(DIR *dir, off_t off) 01371 { 01372 dir->seek(off); 01373 } 01374 01375 extern "C" int mkdir(const char *path, mode_t mode) 01376 { 01377 FilePath fp(path); 01378 FileSystemHandle *fs = fp.fileSystem(); 01379 if (fs == NULL) { 01380 errno = ENODEV; 01381 return -1; 01382 } 01383 01384 int err = fs->mkdir(fp.fileName(), mode); 01385 if (err < 0) { 01386 errno = -err; 01387 return -1; 01388 } else { 01389 return 0; 01390 } 01391 } 01392 01393 extern "C" int stat(const char *path, struct stat *st) 01394 { 01395 FilePath fp(path); 01396 FileSystemHandle *fs = fp.fileSystem(); 01397 if (fs == NULL) { 01398 errno = ENODEV; 01399 return -1; 01400 } 01401 01402 int err = fs->stat(fp.fileName(), st); 01403 if (err < 0) { 01404 errno = -err; 01405 return -1; 01406 } else { 01407 return 0; 01408 } 01409 } 01410 01411 extern "C" int statvfs(const char *path, struct statvfs *buf) 01412 { 01413 FilePath fp(path); 01414 FileSystemHandle *fs = fp.fileSystem(); 01415 if (fs == NULL) { 01416 errno = ENODEV; 01417 return -1; 01418 } 01419 01420 int err = fs->statvfs(fp.fileName(), buf); 01421 if (err < 0) { 01422 errno = -err; 01423 return -1; 01424 } else { 01425 return 0; 01426 } 01427 } 01428 #endif // !MBED_CONF_PLATFORM_STDIO_MINIMAL_CONSOLE_ONLY 01429 01430 #if defined(TOOLCHAIN_GCC) 01431 /* prevents the exception handling name demangling code getting pulled in */ 01432 #include "mbed_error.h" 01433 namespace __gnu_cxx { 01434 void __verbose_terminate_handler() 01435 { 01436 MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_CLIB_EXCEPTION), "Exception", 0); 01437 } 01438 } 01439 extern "C" WEAK void __cxa_pure_virtual(void); 01440 extern "C" WEAK void __cxa_pure_virtual(void) 01441 { 01442 exit(1); 01443 } 01444 01445 #endif 01446 01447 // Provide implementation of _sbrk (low-level dynamic memory allocation 01448 // routine) for GCC_ARM which compares new heap pointer with MSP instead of 01449 // SP. This make it compatible with RTX RTOS thread stacks. 01450 #if defined(TOOLCHAIN_GCC_ARM) 01451 01452 #if defined(MBED_SPLIT_HEAP) 01453 01454 // Default RAM memory used for heap 01455 extern uint32_t __mbed_sbrk_start; 01456 extern uint32_t __mbed_krbs_start; 01457 /* Additional RAM memory used for heap - please note this 01458 * address must be lower address then the previous default address 01459 */ 01460 extern uint32_t __mbed_sbrk_start_0; 01461 extern uint32_t __mbed_krbs_start_0; 01462 01463 extern "C" WEAK caddr_t _sbrk(int incr) 01464 { 01465 static uint32_t heap = (uint32_t) &__mbed_sbrk_start_0; 01466 uint32_t prev_heap = heap; 01467 uint32_t new_heap = heap + incr; 01468 01469 /** 01470 * If we exceed the first region, start allocating from the second region. 01471 */ 01472 if (prev_heap <= (uint32_t) &__mbed_krbs_start_0 && new_heap > (uint32_t) &__mbed_krbs_start_0) { 01473 prev_heap = (uint32_t) &__mbed_sbrk_start; 01474 new_heap = prev_heap + incr; 01475 } 01476 01477 if (new_heap > (uint32_t) &__mbed_krbs_start) { 01478 /** 01479 * If the new address is outside the second region, return out-of-memory. 01480 */ 01481 errno = ENOMEM; 01482 return (caddr_t) - 1; 01483 } 01484 01485 heap = new_heap; 01486 return (caddr_t) prev_heap; 01487 } 01488 01489 #else 01490 01491 extern "C" uint32_t __end__; 01492 extern "C" uint32_t __HeapLimit; 01493 01494 // Turn off the errno macro and use actual global variable instead. 01495 #undef errno 01496 extern "C" int errno; 01497 01498 // Weak attribute allows user to override, e.g. to use external RAM for dynamic memory. 01499 extern "C" WEAK caddr_t _sbrk(int incr) 01500 { 01501 static uint32_t heap = (uint32_t) &__end__; 01502 uint32_t prev_heap = heap; 01503 uint32_t new_heap = heap + incr; 01504 01505 /* __HeapLimit is end of heap section */ 01506 if (new_heap > (uint32_t) &__HeapLimit) { 01507 errno = ENOMEM; 01508 return (caddr_t) - 1; 01509 } 01510 01511 heap = new_heap; 01512 return (caddr_t) prev_heap; 01513 } 01514 #endif 01515 #endif 01516 01517 #if defined(TOOLCHAIN_GCC_ARM) 01518 extern "C" void _exit(int return_code) 01519 { 01520 #else 01521 namespace std { 01522 extern "C" void exit(int return_code) 01523 { 01524 #endif 01525 01526 #if DEVICE_STDIO_MESSAGES 01527 #if MBED_CONF_PLATFORM_STDIO_FLUSH_AT_EXIT 01528 fflush(stdout); 01529 fflush(stderr); 01530 fsync(STDOUT_FILENO); 01531 fsync(STDERR_FILENO); 01532 #endif 01533 #endif 01534 01535 #if DEVICE_SEMIHOST 01536 if (mbed_interface_connected()) { 01537 semihost_exit(); 01538 } 01539 #endif 01540 if (return_code) { 01541 mbed_die(); 01542 } 01543 01544 while (1); 01545 } 01546 01547 #if !defined(TOOLCHAIN_GCC_ARM) 01548 } //namespace std 01549 #endif 01550 01551 #if defined(TOOLCHAIN_ARM) || defined(TOOLCHAIN_GCC) 01552 01553 // This series of function disable the registration of global destructors 01554 // in a dynamic table which will be called when the application exit. 01555 // In mbed, program never exit properly, it dies. 01556 // More informations about this topic for ARMCC here: 01557 // http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/6449.html 01558 extern "C" { 01559 int __aeabi_atexit(void *object, void (*dtor)(void * /*this*/), void *handle) 01560 { 01561 return 1; 01562 } 01563 01564 int __cxa_atexit(void (*dtor)(void * /*this*/), void *object, void *handle) 01565 { 01566 return 1; 01567 } 01568 01569 void __cxa_finalize(void *handle) 01570 { 01571 } 01572 01573 } // end of extern "C" 01574 01575 #endif 01576 01577 01578 #if defined(TOOLCHAIN_GCC) 01579 01580 /* 01581 * Depending on how newlib is configured, it is often not enough to define 01582 * __aeabi_atexit, __cxa_atexit and __cxa_finalize in order to override the 01583 * behavior regarding the registration of handlers with atexit. 01584 * 01585 * To overcome this limitation, exit and atexit are overriden here. 01586 */ 01587 extern "C" { 01588 01589 /** 01590 * @brief Retarget of exit for GCC. 01591 * @details Unlike the standard version, this function doesn't call any function 01592 * registered with atexit before calling _exit. 01593 */ 01594 void __wrap_exit(int return_code) 01595 { 01596 _exit(return_code); 01597 } 01598 01599 /** 01600 * @brief Retarget atexit from GCC. 01601 * @details This function will always fail and never register any handler to be 01602 * called at exit. 01603 */ 01604 int __wrap_atexit(void (*func)()) 01605 { 01606 return 1; 01607 } 01608 01609 } 01610 01611 #endif 01612 01613 01614 01615 namespace mbed { 01616 01617 void mbed_set_unbuffered_stream(std::FILE *_file) 01618 { 01619 #if defined (__ICCARM__) 01620 char buf[2]; 01621 std::setvbuf(_file, buf, _IONBF, NULL); 01622 #else 01623 setbuf(_file, NULL); 01624 #endif 01625 } 01626 01627 } // namespace mbed 01628 01629 #if defined (__ICCARM__) 01630 // Stub out locks when an rtos is not present 01631 extern "C" WEAK void __iar_system_Mtxinit(__iar_Rmtx *mutex) {} 01632 extern "C" WEAK void __iar_system_Mtxdst(__iar_Rmtx *mutex) {} 01633 extern "C" WEAK void __iar_system_Mtxlock(__iar_Rmtx *mutex) {} 01634 extern "C" WEAK void __iar_system_Mtxunlock(__iar_Rmtx *mutex) {} 01635 extern "C" WEAK void __iar_file_Mtxinit(__iar_Rmtx *mutex) {} 01636 extern "C" WEAK void __iar_file_Mtxdst(__iar_Rmtx *mutex) {} 01637 extern "C" WEAK void __iar_file_Mtxlock(__iar_Rmtx *mutex) {} 01638 extern "C" WEAK void __iar_file_Mtxunlock(__iar_Rmtx *mutex) {} 01639 #if defined(__IAR_SYSTEMS_ICC__ ) && (__VER__ >= 8000000) 01640 #pragma section="__iar_tls$$DATA" 01641 extern "C" WEAK void *__aeabi_read_tp(void) 01642 { 01643 // Thread Local storage is not supported, using main thread memory for errno 01644 return __section_begin("__iar_tls$$DATA"); 01645 } 01646 #endif 01647 #elif defined(__CC_ARM) 01648 // Do nothing 01649 #elif defined (__GNUC__) 01650 struct _reent; 01651 // Stub out locks when an rtos is not present 01652 extern "C" WEAK void __rtos_malloc_lock(struct _reent *_r) {} 01653 extern "C" WEAK void __rtos_malloc_unlock(struct _reent *_r) {} 01654 extern "C" WEAK void __rtos_env_lock(struct _reent *_r) {} 01655 extern "C" WEAK void __rtos_env_unlock(struct _reent *_r) {} 01656 01657 extern "C" void __malloc_lock(struct _reent *_r) 01658 { 01659 __rtos_malloc_lock(_r); 01660 } 01661 01662 extern "C" void __malloc_unlock(struct _reent *_r) 01663 { 01664 __rtos_malloc_unlock(_r); 01665 } 01666 01667 extern "C" void __env_lock(struct _reent *_r) 01668 { 01669 __rtos_env_lock(_r); 01670 } 01671 01672 extern "C" void __env_unlock(struct _reent *_r) 01673 { 01674 __rtos_env_unlock(_r); 01675 } 01676 01677 #endif 01678 01679 #if defined (__GNUC__) || defined (__ARMCC_VERSION) 01680 01681 #define CXA_GUARD_INIT_DONE (1 << 0) 01682 #define CXA_GUARD_INIT_IN_PROGRESS (1 << 1) 01683 #define CXA_GUARD_MASK (CXA_GUARD_INIT_DONE | CXA_GUARD_INIT_IN_PROGRESS) 01684 01685 extern "C" int __cxa_guard_acquire(int *guard_object_p) 01686 { 01687 uint8_t *guard_object = (uint8_t *)guard_object_p; 01688 if ((core_util_atomic_load_u8(guard_object) & CXA_GUARD_MASK) == CXA_GUARD_INIT_DONE) { 01689 return 0; 01690 } 01691 singleton_lock(); 01692 uint8_t guard = *guard_object; 01693 if ((guard & CXA_GUARD_MASK) == CXA_GUARD_INIT_DONE) { 01694 singleton_unlock(); 01695 return 0; 01696 } 01697 MBED_ASSERT((guard & CXA_GUARD_MASK) == 0); 01698 core_util_atomic_store_u8(guard_object, guard | CXA_GUARD_INIT_IN_PROGRESS); 01699 return 1; 01700 } 01701 01702 extern "C" void __cxa_guard_release(int *guard_object_p) 01703 { 01704 uint8_t *guard_object = (uint8_t *)guard_object_p; 01705 uint8_t guard = *guard_object; 01706 MBED_ASSERT((guard & CXA_GUARD_MASK) == CXA_GUARD_INIT_IN_PROGRESS); 01707 core_util_atomic_store_u8(guard_object, (guard & ~CXA_GUARD_MASK) | CXA_GUARD_INIT_DONE); 01708 singleton_unlock(); 01709 } 01710 01711 extern "C" void __cxa_guard_abort(int *guard_object_p) 01712 { 01713 uint8_t *guard_object = (uint8_t *)guard_object_p; 01714 uint8_t guard = *guard_object; 01715 MBED_ASSERT((guard & CXA_GUARD_MASK) == CXA_GUARD_INIT_IN_PROGRESS); 01716 core_util_atomic_store_u8(guard_object, guard & ~CXA_GUARD_INIT_IN_PROGRESS); 01717 singleton_unlock(); 01718 } 01719 01720 #endif 01721 01722 #if defined(MBED_MEM_TRACING_ENABLED) && (defined(__ARMCC_VERSION) || defined(__ICCARM__)) 01723 01724 // If the memory tracing is enabled, the wrappers in mbed_alloc_wrappers.cpp 01725 // provide the implementation for these. Note: this needs to use the wrappers 01726 // instead of malloc()/free() as the caller address would point to wrappers, 01727 // not the caller of "new" or "delete". 01728 extern "C" void *malloc_wrapper(size_t size, const void *caller); 01729 extern "C" void free_wrapper(void *ptr, const void *caller); 01730 01731 void *operator new (std::size_t count) 01732 { 01733 void *buffer = malloc_wrapper(count, MBED_CALLER_ADDR()); 01734 if (NULL == buffer) { 01735 MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_OUT_OF_MEMORY), "Operator new out of memory\r\n", count); 01736 } 01737 return buffer; 01738 } 01739 01740 void *operator new[](std::size_t count) 01741 { 01742 void *buffer = malloc_wrapper(count, MBED_CALLER_ADDR()); 01743 if (NULL == buffer) { 01744 error("Operator new[] out of memory\r\n"); 01745 } 01746 return buffer; 01747 } 01748 01749 void *operator new (std::size_t count, const std::nothrow_t &tag) 01750 { 01751 return malloc_wrapper(count, MBED_CALLER_ADDR()); 01752 } 01753 01754 void *operator new[](std::size_t count, const std::nothrow_t &tag) 01755 { 01756 return malloc_wrapper(count, MBED_CALLER_ADDR()); 01757 } 01758 01759 void operator delete (void *ptr) 01760 { 01761 free_wrapper(ptr, MBED_CALLER_ADDR()); 01762 } 01763 01764 void operator delete (void *ptr, std::size_t) 01765 { 01766 free_wrapper(ptr, MBED_CALLER_ADDR()); 01767 } 01768 01769 void operator delete[](void *ptr) 01770 { 01771 free_wrapper(ptr, MBED_CALLER_ADDR()); 01772 } 01773 01774 void operator delete[](void *ptr, std::size_t) 01775 { 01776 free_wrapper(ptr, MBED_CALLER_ADDR()); 01777 } 01778 01779 #elif defined(MBED_MEM_TRACING_ENABLED) && defined(__GNUC__) 01780 01781 #include <reent.h> 01782 01783 extern "C" void *malloc_wrapper(struct _reent *r, size_t size, void *caller); 01784 extern "C" void free_wrapper(struct _reent *r, void *ptr, void *caller); 01785 01786 void *operator new (std::size_t count) 01787 { 01788 void *buffer = malloc_wrapper(_REENT, count, MBED_CALLER_ADDR()); 01789 if (NULL == buffer) { 01790 MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_OUT_OF_MEMORY), "Operator new out of memory\r\n", count); 01791 } 01792 return buffer; 01793 } 01794 01795 void *operator new[](std::size_t count) 01796 { 01797 void *buffer = malloc_wrapper(_REENT, count, MBED_CALLER_ADDR()); 01798 if (NULL == buffer) { 01799 MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_OUT_OF_MEMORY), "Operator new out of memory\r\n", count); 01800 } 01801 return buffer; 01802 } 01803 01804 void *operator new (std::size_t count, const std::nothrow_t &tag) 01805 { 01806 return malloc_wrapper(_REENT, count, MBED_CALLER_ADDR()); 01807 } 01808 01809 void *operator new[](std::size_t count, const std::nothrow_t &tag) 01810 { 01811 return malloc_wrapper(_REENT, count, MBED_CALLER_ADDR()); 01812 } 01813 01814 void operator delete (void *ptr) 01815 { 01816 free_wrapper(_REENT, ptr, MBED_CALLER_ADDR()); 01817 } 01818 01819 void operator delete (void *ptr, std::size_t) 01820 { 01821 free_wrapper(_REENT, ptr, MBED_CALLER_ADDR()); 01822 } 01823 01824 void operator delete[](void *ptr) 01825 { 01826 free_wrapper(_REENT, ptr, MBED_CALLER_ADDR()); 01827 } 01828 01829 void operator delete[](void *ptr, std::size_t) 01830 { 01831 free_wrapper(_REENT, ptr, MBED_CALLER_ADDR()); 01832 } 01833 01834 #else 01835 01836 void *operator new (std::size_t count) 01837 { 01838 void *buffer = malloc(count); 01839 if (NULL == buffer) { 01840 MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_OUT_OF_MEMORY), "Operator new out of memory\r\n", count); 01841 } 01842 return buffer; 01843 } 01844 01845 void *operator new[](std::size_t count) 01846 { 01847 void *buffer = malloc(count); 01848 if (NULL == buffer) { 01849 MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_OUT_OF_MEMORY), "Operator new[] out of memory\r\n", count); 01850 } 01851 return buffer; 01852 } 01853 01854 void *operator new (std::size_t count, const std::nothrow_t &tag) 01855 { 01856 return malloc(count); 01857 } 01858 01859 void *operator new[](std::size_t count, const std::nothrow_t &tag) 01860 { 01861 return malloc(count); 01862 } 01863 01864 void operator delete (void *ptr) 01865 { 01866 free(ptr); 01867 } 01868 01869 void operator delete (void *ptr, std::size_t) 01870 { 01871 free(ptr); 01872 } 01873 01874 void operator delete[](void *ptr) 01875 { 01876 free(ptr); 01877 } 01878 01879 void operator delete[](void *ptr, std::size_t) 01880 { 01881 free(ptr); 01882 } 01883 01884 #endif 01885 01886 /* @brief standard c library clock() function. 01887 * 01888 * This function returns the number of clock ticks elapsed since the start of the program. 01889 * 01890 * @note Synchronization level: Thread safe 01891 * 01892 * @return 01893 * the number of clock ticks elapsed since the start of the program. 01894 * 01895 * */ 01896 extern "C" clock_t clock() 01897 { 01898 _mutex->lock(); 01899 clock_t t = ticker_read(get_us_ticker_data()); 01900 t /= 1000000 / CLOCKS_PER_SEC; // convert to processor time 01901 _mutex->unlock(); 01902 return t; 01903 } 01904 01905 // temporary - Default to 1MHz at 32 bits if target does not have us_ticker_get_info 01906 MBED_WEAK const ticker_info_t *us_ticker_get_info() 01907 { 01908 static const ticker_info_t info = { 01909 1000000, 01910 32 01911 }; 01912 return &info; 01913 } 01914 01915 // temporary - Default to 1MHz at 32 bits if target does not have lp_ticker_get_info 01916 MBED_WEAK const ticker_info_t *lp_ticker_get_info() 01917 { 01918 static const ticker_info_t info = { 01919 1000000, 01920 32 01921 }; 01922 return &info; 01923 } 01924 01925 01926 // The below resolves the linker error generated by a bug in Arm Compiler 6 01927 // The compiler inadvertently introduces the 01928 // _scanf_mbtowc symbol to the build. The code below provides a weak reference 01929 // for the missing symbol. 01930 // Arm Compiler 6 version 6.12 and earlier versions are affected. 01931 typedef int ScanfReadRec; 01932 extern "C" MBED_WEAK long int _scanf_mbtowc( 01933 int ignored, 01934 FILE *p, 01935 ScanfReadRec *sr, 01936 int *charmap, 01937 int exact 01938 ) 01939 { 01940 return 0; 01941 }
Generated on Tue Jul 12 2022 13:54:33 by
