diff --git a/TESTS/mbed_drivers/c_strings/main.cpp b/TESTS/mbed_drivers/c_strings/main.cpp index 9b79f2bd9ee..f1e9868fad8 100644 --- a/TESTS/mbed_drivers/c_strings/main.cpp +++ b/TESTS/mbed_drivers/c_strings/main.cpp @@ -116,14 +116,15 @@ Case cases[] = { Case("C strings: %u %d integer formatting", test_case_c_string_u_d, greentea_failure_handler), Case("C strings: %x %E integer formatting", test_case_c_string_x_X, greentea_failure_handler), #if !defined(__NEWLIB_NANO) - //In build tools, GCC with Newlib-nano linker option "-u _printf_float" is not configured - //to enable printf floating format. So disabling floating format test case. + // Newlib-nano linker option "-u _printf_float" is not set to enable floating point support. +#if (defined(MBED_MINIMAL_PRINTF) && MBED_CONF_PLATFORM_MINIMAL_PRINTF_ENABLE_FLOATING_POINT) || !defined(MBED_MINIMAL_PRINTF) Case("C strings: %f %f float formatting", test_case_c_string_f_f, greentea_failure_handler), +#endif #ifndef MBED_MINIMAL_PRINTF Case("C strings: %e %E float formatting", test_case_c_string_e_E, greentea_failure_handler), Case("C strings: %g %g float formatting", test_case_c_string_g_g, greentea_failure_handler), -#endif -#endif +#endif // MBED_MINIMAL_PRINTF +#endif // !defined(__NEWLIB_NANO) }; utest::v1::status_t greentea_test_setup(const size_t number_of_cases) diff --git a/TESTS/mbed_drivers/reset_reason/main.cpp b/TESTS/mbed_drivers/reset_reason/main.cpp index 73d41ab8d21..768d85b0125 100644 --- a/TESTS/mbed_drivers/reset_reason/main.cpp +++ b/TESTS/mbed_drivers/reset_reason/main.cpp @@ -75,7 +75,7 @@ static cmd_status_t handle_command(const char *key, const char *value) int raw_reason_hex_str_len = snprintf(raw_reason_hex_str, sizeof raw_reason_hex_str, "%08lx", raw_reason); - if (raw_reason_hex_str_len != (sizeof raw_reason_hex_str) - 1) { + if (raw_reason_hex_str_len < 0) { TEST_ASSERT_MESSAGE(0, "Failed to compose raw reset reason hex string."); return CMD_STATUS_ERROR; } @@ -134,7 +134,7 @@ void test_reset_reason() hal_reset_reason_get_capabilities(&rrcap); char msg_value[11]; int str_len = snprintf(msg_value, sizeof msg_value, "%08lx,%01x", rrcap.reasons, MSG_VALUE_WATCHDOG_STATUS); - if (str_len != (sizeof msg_value) - 1) { + if (str_len < 0) { printf("Failed to compose a value string to be sent to host."); GREENTEA_TESTSUITE_RESULT(0); return; diff --git a/TESTS/mbed_drivers/watchdog_reset/main.cpp b/TESTS/mbed_drivers/watchdog_reset/main.cpp index 5f32b3b5446..a8311a6f0ae 100644 --- a/TESTS/mbed_drivers/watchdog_reset/main.cpp +++ b/TESTS/mbed_drivers/watchdog_reset/main.cpp @@ -92,7 +92,7 @@ bool send_reset_notification(testcase_data *tcdata, uint32_t delay_ms) { char msg_value[12]; int str_len = snprintf(msg_value, sizeof msg_value, "%02x,%08lx", tcdata->start_index + tcdata->index, delay_ms); - if (str_len != (sizeof msg_value) - 1) { + if (str_len < 0) { utest_printf("Failed to compose a value string to be sent to host."); return false; } diff --git a/TESTS/mbed_hal/reset_reason/main.cpp b/TESTS/mbed_hal/reset_reason/main.cpp index 8efbdf43a87..4f51fa007e0 100644 --- a/TESTS/mbed_hal/reset_reason/main.cpp +++ b/TESTS/mbed_hal/reset_reason/main.cpp @@ -75,7 +75,7 @@ static cmd_status_t handle_command(const char *key, const char *value) int raw_reason_hex_str_len = snprintf(raw_reason_hex_str, sizeof raw_reason_hex_str, "%08lx", raw_reason); - if (raw_reason_hex_str_len != (sizeof raw_reason_hex_str) - 1) { + if (raw_reason_hex_str_len < 0) { TEST_ASSERT_MESSAGE(0, "Failed to compose raw reset reason hex string."); return CMD_STATUS_ERROR; } @@ -129,7 +129,7 @@ void test_reset_reason() hal_reset_reason_get_capabilities(&rrcap); char msg_value[11]; int str_len = snprintf(msg_value, sizeof msg_value, "%08lx,%01x", rrcap.reasons, MSG_VALUE_WATCHDOG_STATUS); - if (str_len != (sizeof msg_value) - 1) { + if (str_len < 0) { printf("Failed to compose a value string to be sent to host."); GREENTEA_TESTSUITE_RESULT(0); return; diff --git a/TESTS/mbed_hal/watchdog_reset/main.cpp b/TESTS/mbed_hal/watchdog_reset/main.cpp index 6f3fa9704d4..4d9b7948159 100644 --- a/TESTS/mbed_hal/watchdog_reset/main.cpp +++ b/TESTS/mbed_hal/watchdog_reset/main.cpp @@ -90,7 +90,7 @@ bool send_reset_notification(testcase_data *tcdata, uint32_t delay_ms) { char msg_value[12]; int str_len = snprintf(msg_value, sizeof msg_value, "%02x,%08lx", tcdata->start_index + tcdata->index, delay_ms); - if (str_len != (sizeof msg_value) - 1) { + if (str_len < 0) { utest_printf("Failed to compose a value string to be sent to host."); return false; } diff --git a/TESTS/mbed_hal/watchdog_timing/main.cpp b/TESTS/mbed_hal/watchdog_timing/main.cpp index 9f0e75bc425..23d5993283b 100644 --- a/TESTS/mbed_hal/watchdog_timing/main.cpp +++ b/TESTS/mbed_hal/watchdog_timing/main.cpp @@ -59,7 +59,7 @@ bool send_reset_notification(testcase_data *tcdata, uint32_t delay_ms) { char msg_value[12]; int str_len = snprintf(msg_value, sizeof msg_value, "%02x,%08lx", tcdata->start_index + tcdata->index, delay_ms); - if (str_len != (sizeof msg_value) - 1) { + if (str_len < 0) { utest_printf("Failed to compose a value string to be sent to host."); return false; } @@ -110,7 +110,7 @@ void test_timing() int str_len = snprintf(msg_value, sizeof msg_value, "%02x,%08lx", current_case.start_index + current_case.index, (uint32_t) current_ts); - if (str_len != (sizeof msg_value) - 1) { + if (str_len < 0) { utest_printf("Failed to compose a value string to be sent to host."); return; } diff --git a/TESTS/mbed_timing_fpga_ci_test_shield/watchdog/main.cpp b/TESTS/mbed_timing_fpga_ci_test_shield/watchdog/main.cpp index c11aef21506..afde8d941cf 100644 --- a/TESTS/mbed_timing_fpga_ci_test_shield/watchdog/main.cpp +++ b/TESTS/mbed_timing_fpga_ci_test_shield/watchdog/main.cpp @@ -119,7 +119,7 @@ bool send_reset_notification(testcase_data *tcdata, uint32_t delay_ms) { char msg_value[12]; int str_len = snprintf(msg_value, sizeof msg_value, "%02x,%08lx", tcdata->start_index + tcdata->index, delay_ms); - if (str_len != (sizeof msg_value) - 1) { + if (str_len < 0) { utest_printf("Failed to compose a value string to be sent to host."); return false; } diff --git a/platform/mbed_lib.json b/platform/mbed_lib.json index 2da4dbea2d5..fcc61737b08 100644 --- a/platform/mbed_lib.json +++ b/platform/mbed_lib.json @@ -140,15 +140,15 @@ "value": true }, "minimal-printf-enable-64-bit": { - "help": "Enable printing 64 bit integers when using mprintf profile", + "help": "Enable printing 64 bit integers when using minimal printf library", "value": true }, "minimal-printf-enable-floating-point": { - "help": "Enable floating point printing when using mprintf profile", + "help": "Enable floating point printing when using minimal printf library", "value": false }, "minimal-printf-set-floating-point-max-decimals": { - "help": "Maximum number of decimals to be printed", + "help": "Maximum number of decimals to be printed when using minimal printf library", "value": 6 } }, diff --git a/platform/source/minimal-printf/README.md b/platform/source/minimal-printf/README.md index 3c5bc464daa..d99fe3c124b 100644 --- a/platform/source/minimal-printf/README.md +++ b/platform/source/minimal-printf/README.md @@ -1,7 +1,7 @@ # Minimal printf and snprintf -Library supports both printf and snprintf in 1252 bytes of flash. +Library supports both printf and snprintf in around 1300 bytes of flash. Prints directly to stdio/UART without using malloc. All flags and precision modifiers are ignored. There is no error handling if a writing error occurs. @@ -20,6 +20,10 @@ Supports: * %s: string. * %p: pointer (e.g. 0x00123456). +Note that support for: +* 64b modifiers is only present when `minimal-printf-enable-64-bit` config is set to `true` (default). +* Floating point parameters is only present when `minimal-printf-enable-floating-point` config is set to `true` (disabled by default). + Unrecognized format specifiers are treated as ordinary characters. Floating point limitations: @@ -28,8 +32,7 @@ Floating point limitations: ## Usage - -To replace the standard implementation of the printf functions with the ones in this library: +As of Mbed OS 6.0 this is enabled by default. To replace the standard implementation of the printf functions with the ones in this library for older versions of Mbed: Modify your application configuration file to override the parameter `target.printf_lib` with the value `minimal-printf` as shown below: @@ -43,6 +46,17 @@ Modify your application configuration file to override the parameter `target.pri } ``` +If your application requires more advanced functionality, you'll need to revert to using standard version of printf/snprintf. Please note that it will result in significant ROM usage increase. In case you are using minimal version of standard C library advanced functionality may not be present. + +Modify your application configuration in `mbed_app.json` file to override the parameter `target.printf_lib` with the value `std` as shown below: + +```json + "target_overrides": { + "*": { + "target.printf_lib": "std" + } + } +``` ## Configuration @@ -54,27 +68,24 @@ Minimal printf is configured by the following parameters defined in `platform/mb "name": "platform", "config": { "minimal-printf-enable-64-bit": { - "help": "Enable printing 64 bit integers when using minimal-printf profile", + "help": "Enable printing 64 bit integers when using minimal printf library", "value": true }, "minimal-printf-enable-floating-point": { - "help": "Enable floating point printing when using minimal-printf profile", + "help": "Enable floating point printing when using minimal printf library", "value": false }, "minimal-printf-set-floating-point-max-decimals": { - "help": "Maximum number of decimals to be printed", + "help": "Maximum number of decimals to be printed when using minimal printf library", "value": 6 } - } + } } ``` -By default, 64 bit integers support is enabled. - -If your target does not require some options then you can override the default configuration in your application `mbed_app.json` and achieve further memory optimisation (see next section for size comparison numbers). - -In mbed_app.json: +By default, 64 bit integers support is enabled, but floating point support is disabled to increase memory savings. +If your application needs to override the default configuration add following section to your `mbed_app.json`: ```json "target_overrides": { "*": { diff --git a/platform/source/minimal-printf/mbed_printf_implementation.c b/platform/source/minimal-printf/mbed_printf_implementation.c index 428ef3bbd4f..53dca36c7ef 100644 --- a/platform/source/minimal-printf/mbed_printf_implementation.c +++ b/platform/source/minimal-printf/mbed_printf_implementation.c @@ -1,5 +1,5 @@ /* mbed Microcontroller Library - * Copyright (c) 2017 ARM Limited + * Copyright (c) 2017-2020 ARM Limited * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -122,17 +122,22 @@ static void mbed_minimal_putchar(char *buffer, size_t length, int *result, char { /* only continue if 'result' doesn't overflow */ if ((*result >= 0) && (*result <= INT_MAX - 1)) { - /* write data only if there's enough space */ - if ((size_t)*result < length) { - if (buffer) { + if (buffer) { + /* write data only if there's enough space */ + if ((size_t)*result < length) { buffer[*result] = data; + } + + /* increment 'result' even if data was not written. This ensures that + 'mbed_minimal_formatted_string' returns the correct value. */ + *result += 1; + } else { + if (fputc(data, stream) == EOF) { + *result = EOF; } else { - fputc(data, stream); + *result += 1; } } - /* increment 'result' even if data was not written. This ensures that - 'mbed_minimal_formatted_string' returns the correct value. */ - *result += 1; } } @@ -503,6 +508,16 @@ int mbed_minimal_formatted_string(char *buffer, size_t length, const char *forma /* use 64 bit storage type for readout */ value = va_arg(arguments, MBED_SIGNED_STORAGE); } else +#else + /* If 64 bit is not enabled, print %ll[di] rather than truncated value */ + if (length_modifier == LENGTH_LL) { + mbed_minimal_formatted_string_character(buffer, length, &result, '%', stream); + if (next == '%') { + // Continue printing loop after `%` + index = next_index; + } + continue; + } #endif { /* use native storage type (which can be 32 or 64 bit) */ @@ -552,6 +567,16 @@ int mbed_minimal_formatted_string(char *buffer, size_t length, const char *forma /* use 64 bit storage type for readout */ value = va_arg(arguments, MBED_UNSIGNED_STORAGE); } else +#else + /* If 64 bit is not enabled, print %ll[uxX] rather than truncated value */ + if (length_modifier == LENGTH_LL) { + mbed_minimal_formatted_string_character(buffer, length, &result, '%', stream); + if (next == '%') { + // Continue printing loop after `%` + index = next_index; + } + continue; + } #endif { /* use native storage type (which can be 32 or 64 bit) */ diff --git a/targets/targets.json b/targets/targets.json index 7e692a57aac..504d2b57b76 100644 --- a/targets/targets.json +++ b/targets/targets.json @@ -19,7 +19,7 @@ "c_lib": "std", "bootloader_supported": false, "static_memory_defines": true, - "printf_lib": "std", + "printf_lib": "minimal-printf", "supported_c_libs": { "arm": [ "std"