diff --git a/CHANGES.md b/CHANGES.md index 93c115403..3cc3b654b 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,37 @@ +### Changes between Memfault SDK 0.31.4 and SDK 0.31.3 - July 19, 2022 + +#### :chart_with_upwards_trend: Improvements + +- ESP32 port: add new Kconfig option, `CONFIG_MEMFAULT_AUTOMATIC_INIT`, that can + be explicitly set to `n` to skip automatically initializing the Memfault SDK + on boot. This can be useful if Memfault SDK initialization needs to be + deferred to application start. + +- Zephyr port: add Kconfig options, + `CONFIG_MEMFAULT_INIT_PRIORITY`/`CONFIG_MEMFAULT_INIT_LEVEL_POST_KERNEL` for + controlling the Memfault SDK initialization level and priority. This can be + useful when needing Memfault to initialize earlier in the system startup + sequence, for example for diagnosing crashes in an early driver + initialization. + +- Partial support, still in progress, for NRF Connect SDK + Zephyr v3.1: + - Remove reference to the now-removed Kconfig symbol, + `NET_SOCKETS_OFFLOAD_TLS` to enable building without warnings. **NOTE:** if + mbedtls is enabled (`CONFIG_MBEDTLS=y`), but is _not_ being used for HTTP + transfers (eg, mbedtls is used for security functions, but the device does + not use HTTP for transferring data), it may be necessary to explicitly set + `CONFIG_MEMFAULT_HTTP_USES_MBEDTLS=n`. + +#### :house: Internal + +- Zephyr port: remove an unused header file, + `ports/zephyr/common/memfault_zephyr_http.h` + +- Remove `memfault_demo_cli_cmd_print_chunk()` demo function. + `memfault_data_export_dump_chunks()` can be used instead, which is intended to + be used with the "Chunks Debug" UI in the Memfault web application- see + [here](https://mflt.io/chunk-data-export) for more details + ### Changes between Memfault SDK 0.31.3 and SDK 0.31.2 - July 8, 2022 #### :chart_with_upwards_trend: Improvements diff --git a/VERSION b/VERSION index 55a8f4df3..c6652dbe3 100644 --- a/VERSION +++ b/VERSION @@ -1,2 +1,2 @@ -BUILD ID: 474047 -GIT COMMIT: 74c12c38c +BUILD ID: 478452 +GIT COMMIT: 56592ceef diff --git a/components/demo/src/memfault_demo_cli_print_chunk.c b/components/demo/src/memfault_demo_cli_print_chunk.c deleted file mode 100644 index 9d226eba8..000000000 --- a/components/demo/src/memfault_demo_cli_print_chunk.c +++ /dev/null @@ -1,149 +0,0 @@ -//! @file -//! -//! Copyright (c) Memfault, Inc. -//! See License.txt for details -//! -//! @brief -//! CLI command that dumps the coredump saved out over the console in such a way that the output -//! can be copy & pasted to a terminal and posted to the Memfault cloud Service - -#include "memfault/demo/cli.h" - -#include -#include -#include - -#include "memfault/core/compiler.h" -#include "memfault/core/data_packetizer.h" -#include "memfault/core/debug_log.h" -#include "memfault/core/math.h" -#include "memfault/demo/util.h" - -// -// Weak function implementations for when the "http" component is not enabled. This way we can -// still dump a CLI command that shows how to post a chunk using curl. -// - -MEMFAULT_WEAK -const char *memfault_demo_get_chunks_url(void) { - return "https://chunks.memfault.com/api/v0/chunks/DEMOSERIAL"; -} - -MEMFAULT_WEAK -const char *memfault_demo_get_api_project_key(void) { - return ""; -} - -static void prv_write_curl_epilogue(void) { - MEMFAULT_LOG_RAW("| xxd -p -r | curl -X POST %s\\", memfault_demo_get_chunks_url()); - MEMFAULT_LOG_RAW(" -H 'Memfault-Project-Key:%s'\\", memfault_demo_get_api_project_key()); - MEMFAULT_LOG_RAW(" -H 'Content-Type:application/octet-stream' --data-binary @- -i"); - MEMFAULT_LOG_RAW("\nprint_chunk done"); -} - -typedef struct MemfaultPrintImpl { - const char *prologue; - const char *line_end; - void (*write_epilogue)(void); -} sMemfaultPrintImpl; - -static void prv_write_chunk_data(const sMemfaultPrintImpl *print_impl, uint8_t *packet_buffer, - size_t packet_size) { - char hex_buffer[MEMFAULT_CLI_LOG_BUFFER_MAX_SIZE_BYTES]; - for (uint32_t j = 0; j < packet_size; ++j) { - sprintf(&hex_buffer[j * 2], "%02x", packet_buffer[j]); - } - strncpy(&hex_buffer[packet_size * 2], print_impl->line_end, - MEMFAULT_CLI_LOG_BUFFER_MAX_SIZE_BYTES - (packet_size * 2)); - MEMFAULT_LOG_RAW("%s", hex_buffer); -} - -static int prv_send_memfault_data_multi_packet_chunk( - const sMemfaultPrintImpl *print_impl, void *packet_buffer, size_t packet_buffer_max_size) { - const sPacketizerConfig cfg = { - // Enable multi packet chunking. This means a chunk may span multiple calls to - // memfault_packetizer_get_next(). - .enable_multi_packet_chunk = true, - }; - - sPacketizerMetadata metadata; - bool data_available = memfault_packetizer_begin(&cfg, &metadata); - if (!data_available) { - return 0; - } - - while (1) { - size_t read_size = packet_buffer_max_size; - eMemfaultPacketizerStatus packetizer_status = - memfault_packetizer_get_next(packet_buffer, &read_size); - if (packetizer_status == kMemfaultPacketizerStatus_NoMoreData) { - // We know data is available from the memfault_packetizer_begin() call above - // so _NoMoreData is an unexpected result - MEMFAULT_LOG_ERROR("Unexpected packetizer status: %d", (int)packetizer_status); - return -1; - } - - prv_write_chunk_data(print_impl, packet_buffer, read_size); - if (packetizer_status == kMemfaultPacketizerStatus_EndOfChunk) { - break; - } - } - return 0; -} - -static int prv_send_memfault_data_single_packet_chunk( - const sMemfaultPrintImpl *print_impl, void *packet_buffer, size_t packet_buffer_size) { - bool data_available = memfault_packetizer_get_chunk(packet_buffer, &packet_buffer_size); - if (!data_available) { - return 0; - } - - prv_write_chunk_data(print_impl, packet_buffer, packet_buffer_size); - return 0; -} - -int memfault_demo_cli_cmd_print_chunk(int argc, char *argv[]) { - // by default, we will use curl - bool use_curl = (argc <= 1) || (strcmp(argv[1], "curl") == 0); - bool use_hex = !use_curl && (strcmp(argv[1], "hex") == 0); - if (!use_curl && !use_hex) { - MEMFAULT_LOG_ERROR("Usage: \"print_chunk\" or \"print_chunk \""); - return -1; - } - - // by default, we will dump the entire message in a single chunk - size_t chunk_size = (argc <= 2) ? 0 : (size_t)atoi(argv[2]); - - char packet_buffer[MEMFAULT_CLI_LOG_BUFFER_MAX_SIZE_BYTES / 2]; - if (chunk_size > sizeof(packet_buffer)) { - MEMFAULT_LOG_ERROR("Usage: chunk_size must be <= %d bytes", (int)sizeof(packet_buffer)); - return -1; - } - - bool more_data = memfault_packetizer_data_available(); - if (!more_data) { // there are no more chunks to send - MEMFAULT_LOG_INFO("All data has been sent!"); - return 0; - } - - const sMemfaultPrintImpl print_impl = { - .prologue = use_curl ? "echo \\" : NULL, - .line_end = use_curl ? "\\" : "", - .write_epilogue = use_curl ? prv_write_curl_epilogue: NULL, - }; - - if (print_impl.prologue) { - MEMFAULT_LOG_RAW("%s", print_impl.prologue); - } - - const size_t max_read_size = sizeof(packet_buffer) - strlen(print_impl.line_end) - 1; - - int rv = (chunk_size == 0) ? - prv_send_memfault_data_multi_packet_chunk(&print_impl, packet_buffer, max_read_size) : - prv_send_memfault_data_single_packet_chunk(&print_impl, packet_buffer, max_read_size); - - if (print_impl.write_epilogue) { - print_impl.write_epilogue(); - } - return rv; -} diff --git a/components/include/memfault/demo/cli.h b/components/include/memfault/demo/cli.h index feeb625c3..b3eb82499 100644 --- a/components/include/memfault/demo/cli.h +++ b/components/include/memfault/demo/cli.h @@ -46,12 +46,6 @@ int memfault_demo_cli_cmd_get_core(int argc, char *argv[]); //! It takes no arguments. int memfault_demo_cli_cmd_post_core(int argc, char *argv[]); -//! Command to print out the next Memfault data to send and print as a curl command. -//! It takes zero or one string argument, which can be: -//! - curl : (default) prints a shell command to post the next data chunk to Memfault's API (using echo, xxd and curl) -//! - hex : hexdumps the data -int memfault_demo_cli_cmd_print_chunk(int argc, char *argv[]); - //! Command to clear a coredump. //! It takes no arguments. int memfault_demo_cli_cmd_clear_core(int argc, char *argv[]); diff --git a/components/include/memfault/version.h b/components/include/memfault/version.h index 1aa77b73f..929c2d70a 100644 --- a/components/include/memfault/version.h +++ b/components/include/memfault/version.h @@ -19,7 +19,7 @@ typedef struct { uint8_t patch; } sMfltSdkVersion; -#define MEMFAULT_SDK_VERSION { .major = 0, .minor = 31, .patch = 3 } +#define MEMFAULT_SDK_VERSION { .major = 0, .minor = 31, .patch = 4 } #ifdef __cplusplus } diff --git a/examples/esp32/apps/memfault_demo_app/main/console_example_main.c b/examples/esp32/apps/memfault_demo_app/main/console_example_main.c index 82ee2a01b..370d4cde4 100644 --- a/examples/esp32/apps/memfault_demo_app/main/console_example_main.c +++ b/examples/esp32/apps/memfault_demo_app/main/console_example_main.c @@ -214,6 +214,9 @@ static void prv_initialize_task_watchdog(void) { // This task started by cpu_start.c::start_cpu0_default(). void app_main() { +#if !CONFIG_MEMFAULT_AUTOMATIC_INIT + memfault_boot(); +#endif extern void memfault_platform_device_info_boot(void); memfault_platform_device_info_boot(); g_unaligned_buffer = &s_my_buf[1]; diff --git a/examples/wiced/apps/memfault_demo_app/memfault_demo_app.c b/examples/wiced/apps/memfault_demo_app/memfault_demo_app.c index 906c4a481..bc5a94850 100644 --- a/examples/wiced/apps/memfault_demo_app/memfault_demo_app.c +++ b/examples/wiced/apps/memfault_demo_app/memfault_demo_app.c @@ -49,7 +49,6 @@ static const command_t commands[] = { {"get_core", memfault_demo_cli_cmd_get_core, 0, NULL, NULL, NULL, "Get coredump info"}, {"clear_core", memfault_demo_cli_cmd_clear_core, 0, NULL, NULL, NULL, "Clear an existing coredump"}, {"post_core", memfault_demo_cli_cmd_post_core, 0, NULL, NULL, NULL, "Post coredump to Memfault"}, - {"print_chunk", memfault_demo_cli_cmd_print_chunk, 0, NULL, NULL, "[curl|hex]", "Get next Memfault data chunk to send and print as a curl command"}, {"crash", memfault_demo_cli_cmd_crash, 1, NULL, NULL, ""ESCAPE_SPACE_PROMPT, "Trigger a crash"}, {"get_core_region", prv_get_core_region, 0, NULL, NULL, NULL, "Get coredump SPI region info"}, diff --git a/examples/wiced/libraries/memfault/demo/demo.mk b/examples/wiced/libraries/memfault/demo/demo.mk index 4f1ef532c..e7eba16f5 100644 --- a/examples/wiced/libraries/memfault/demo/demo.mk +++ b/examples/wiced/libraries/memfault/demo/demo.mk @@ -2,7 +2,6 @@ NAME := MemfaultDemo $(NAME)_SOURCES := \ src/http/memfault_demo_http.c \ - src/memfault_demo_cli_print_chunk.c \ src/memfault_demo_core.c \ src/panics/memfault_demo_cli_aux.c \ src/panics/memfault_demo_panics.c diff --git a/ports/esp_idf/memfault/Kconfig b/ports/esp_idf/memfault/Kconfig index 592a2f5dd..10791ec61 100644 --- a/ports/esp_idf/memfault/Kconfig +++ b/ports/esp_idf/memfault/Kconfig @@ -26,4 +26,12 @@ menu "Memfault" defined in a partitions*.csv file. If the device has already been shipped and the partition table cannot be modified, an OTA slot can be used instead. + + config MEMFAULT_AUTOMATIC_INIT + bool "Automatically initialize the SDK when the system is booted" + default y + help + By default, Memfault will automatically initialize the SDK + when the system is booted. This can be disabled if the user + wants to initialize the SDK manually. endmenu diff --git a/ports/esp_idf/memfault/common/memfault_platform_core.c b/ports/esp_idf/memfault/common/memfault_platform_core.c index 7f6c4f0bf..bbda68b80 100644 --- a/ports/esp_idf/memfault/common/memfault_platform_core.c +++ b/ports/esp_idf/memfault/common/memfault_platform_core.c @@ -147,8 +147,7 @@ static int prv_memfault_log_wrapper(const char *fmt, va_list args) { return vprintf(fmt, args); } -// register an initialization routine that will be run from do_global_ctors() -static void __attribute__((constructor)) prv_memfault_boot(void) { +void memfault_boot(void) { s_memfault_lock = xSemaphoreCreateRecursiveMutex(); // set up log collection so recent logs can be viewed in coredump @@ -172,3 +171,10 @@ static void __attribute__((constructor)) prv_memfault_boot(void) { memfault_register_cli(); #endif } + +#if CONFIG_MEMFAULT_AUTOMATIC_INIT +// register an initialization routine that will be run from do_global_ctors() +static void __attribute__((constructor)) prv_memfault_boot(void) { + memfault_boot(); +} +#endif diff --git a/ports/esp_idf/memfault/common/memfault_platform_demo_cli_cmds.c b/ports/esp_idf/memfault/common/memfault_platform_demo_cli_cmds.c index dc19d5779..51bc9860d 100644 --- a/ports/esp_idf/memfault/common/memfault_platform_demo_cli_cmds.c +++ b/ports/esp_idf/memfault/common/memfault_platform_demo_cli_cmds.c @@ -251,12 +251,6 @@ void memfault_register_cli(void) { .func = memfault_demo_cli_cmd_get_device_info, })); - ESP_ERROR_CHECK( esp_console_cmd_register(&(esp_console_cmd_t) { - .command = "print_chunk", - .help = "Get next Memfault data chunk to send and print as a curl command", - .hint = "curl | hex", - .func = memfault_demo_cli_cmd_print_chunk, - })); ESP_ERROR_CHECK( esp_console_cmd_register(&(esp_console_cmd_t) { .command = "export", .help = "Can be used to dump chunks to console or post via GDB", diff --git a/ports/esp_idf/memfault/include/memfault/esp_port/core.h b/ports/esp_idf/memfault/include/memfault/esp_port/core.h index 9d39d840b..d971c0062 100644 --- a/ports/esp_idf/memfault/include/memfault/esp_port/core.h +++ b/ports/esp_idf/memfault/include/memfault/esp_port/core.h @@ -40,6 +40,15 @@ bool memfault_esp_port_data_available(void); //! @return true if the buffer was filled, false otherwise bool memfault_esp_port_get_chunk(void *buf, size_t *buf_len); +//! Intializes the Memfault system, and should be called one time at boot. +//! +//! Note: by default this is called from the system initialization sequence- +//! it's placed into the global constructor table during compilation, and +//! executed by the esp-idf initialization code. Optionally it can instead be +//! explictly called during application startup by setting +//! 'CONFIG_MEMFAULT_AUTOMATIC_INIT=n' in the project Kconfig options. +void memfault_boot(void); + #ifdef __cplusplus } #endif diff --git a/ports/zephyr/Kconfig b/ports/zephyr/Kconfig index bf6b3b16c..a5eab6ce1 100644 --- a/ports/zephyr/Kconfig +++ b/ports/zephyr/Kconfig @@ -184,10 +184,13 @@ config MEMFAULT_HTTP_PERIODIC_UPLOAD_INTERVAL_SECS config MEMFAULT_HTTP_USES_MBEDTLS bool "Use mbedTLS for HTTP transport" - default y if !NET_SOCKETS_OFFLOAD_TLS && MBEDTLS + default y if MBEDTLS help Configure Memfault HTTP for using mbedTLS- perform some sanity checks - at compile time that it is configured correctly. + at compile time that it is configured correctly. Note that if MbedTLS + is used for purposes other than securing the TCP/IP sockets, i.e. if + TLS is offloaded to the underlying socket, this check is invalid, and + should be explicitly set to 'n'. endif # MEMFAULT_HTTP_ENABLE @@ -274,6 +277,18 @@ config MEMFAULT_SOFTWARE_WATCHDOG_TIMEOUT_SECS int "The time, in seconds, to configure the software watchdog expiration for" default 15 +config MEMFAULT_INIT_PRIORITY + int "The priority of Memfault initialization on system start" + default KERNEL_INIT_PRIORITY_DEFAULT + help + The SYS_INIT relative priority for Memfault initialization. + +config MEMFAULT_INIT_LEVEL_POST_KERNEL + bool "Use POST_KERNEL init level for Memfault initialization" + default n + help + Set the Memfault initialization SYS_INIT priority level to + "POST_KERNEL". Default is "APPLICATION". rsource "ncs/Kconfig" diff --git a/ports/zephyr/common/memfault_platform_core.c b/ports/zephyr/common/memfault_platform_core.c index 4776fe04b..c7379e601 100644 --- a/ports/zephyr/common/memfault_platform_core.c +++ b/ports/zephyr/common/memfault_platform_core.c @@ -100,4 +100,10 @@ static int prv_init_and_log_reboot() { return 0; } -SYS_INIT(prv_init_and_log_reboot, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +SYS_INIT(prv_init_and_log_reboot, +#if CONFIG_MEMFAULT_INIT_LEVEL_POST_KERNEL + POST_KERNEL, +#else + APPLICATION, +#endif + CONFIG_MEMFAULT_INIT_PRIORITY); diff --git a/ports/zephyr/common/memfault_zephyr_http.h b/ports/zephyr/common/memfault_zephyr_http.h deleted file mode 100644 index 4fb004377..000000000 --- a/ports/zephyr/common/memfault_zephyr_http.h +++ /dev/null @@ -1,71 +0,0 @@ -#pragma once - -//! @file -//! -//! Copyright (c) Memfault, Inc. -//! See License.txt for details -//! -//! @brief -//! Zephyr-port specific http utility for interfacing with http - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -//! Sends diagnostic data to the Memfault cloud chunks endpoint -//! -//! @note This function is blocking and will return once posting of chunk data has completed. -//! -//! For more info see https://mflt.io/data-to-cloud -int memfault_zephyr_port_post_data(void); - - -typedef struct MemfaultOtaInfo { - // The size, in bytes, of the OTA payload. - size_t size; -} sMemfaultOtaInfo; - -typedef struct { - //! Caller provided buffer to be used for the duration of the OTA lifecycle - void *buf; - size_t buf_len; - - //! Optional: Context for use by the caller - void *user_ctx; - - //! Called if a new ota update is available - //! @return true to continue, false to abort the OTA download - bool (*handle_update_available)(const sMemfaultOtaInfo *info, void *user_ctx); - - //! Invoked as bytes are downloaded for the OTA update - //! - //! @return true to continue, false to abort the OTA download - bool (*handle_data)(void *buf, size_t buf_len, void *user_ctx); - - //! Called once the entire ota payload has been downloaded - bool (*handle_download_complete)(void *user_ctx); -} sMemfaultOtaUpdateHandler; - - -//! Handler which can be used to run OTA update using Memfault's Release Mgmt Infra -//! For more details see: -//! https://mflt.io/release-mgmt -//! -//! @param handler Context with info necessary to perform an OTA. See struct -//! definition for more details. -//! -//! @note This function is blocking. 'handler' callbacks will be invoked prior to the function -//! returning. -//! -//! @return -//! < 0 Error while trying to figure out if an update was available -//! 0 Check completed successfully - No new update available -//! 1 New update is available and handlers were invoked -int memfault_zephyr_port_ota_update(const sMemfaultOtaUpdateHandler *handler); - -#ifdef __cplusplus -} -#endif diff --git a/scripts/mflt-build-id/tests_mflt_build_id/test_fw_build_id.py b/scripts/mflt-build-id/tests_mflt_build_id/test_fw_build_id.py index b2a65769c..84a385917 100644 --- a/scripts/mflt-build-id/tests_mflt_build_id/test_fw_build_id.py +++ b/scripts/mflt-build-id/tests_mflt_build_id/test_fw_build_id.py @@ -3,12 +3,10 @@ # See License.txt for details # -import contextlib import filecmp import os import shutil import sys -import tempfile import pytest @@ -22,26 +20,25 @@ from mflt_build_id import BuildIdInspectorAndPatcher, MemfaultBuildIdTypes # noqa isort:skip -@contextlib.contextmanager -def open_copy(file_to_copy, *args, **kwargs): - f = tempfile.NamedTemporaryFile(delete=False) - try: - tmp_name = f.name - f.close() +@pytest.fixture() +def copy_file(tmp_path): + """Copies a file into the tests tmp path""" + idx = [0] - if file_to_copy is not None: - shutil.copy2(file_to_copy, tmp_name) + def _copy_file(src): + # NB: Python 2.7 does not support `nonlocal` + tmp_name = str(tmp_path / "file_{}.bin".format(idx[0])) + idx[0] += 1 + shutil.copy2(src, tmp_name) + return tmp_name - with open(tmp_name, *args, **kwargs) as file: - yield file - finally: - os.unlink(tmp_name) + return _copy_file -def test_gnu_build_id_in_use(capsys, snapshot): +def test_gnu_build_id_in_use(capsys, snapshot, copy_file): elf_fixture_filename = os.path.join(ELF_FIXTURES_DIR, "gnu_id_present_and_used.elf") - with open_copy(elf_fixture_filename, mode="rb") as elf_copy_file: + with open(copy_file(elf_fixture_filename), mode="rb") as elf_copy_file: b = BuildIdInspectorAndPatcher(elf_copy_file) b.check_or_update_build_id() @@ -52,11 +49,11 @@ def test_gnu_build_id_in_use(capsys, snapshot): snapshot.assert_match(lines) -def test_gnu_build_id_present_but_not_used(capsys, snapshot): +def test_gnu_build_id_present_but_not_used(capsys, snapshot, copy_file): elf_fixture_filename = os.path.join(ELF_FIXTURES_DIR, "gnu_id_present_and_not_used.elf") result_fixture_filename = os.path.join(ELF_FIXTURES_DIR, "memfault_id_used_gnu_id_present.elf") - with open_copy(elf_fixture_filename, mode="rb") as elf_copy_file: + with open(copy_file(elf_fixture_filename), mode="rb") as elf_copy_file: b = BuildIdInspectorAndPatcher(elf_copy_file) b.check_or_update_build_id() @@ -67,7 +64,7 @@ def test_gnu_build_id_present_but_not_used(capsys, snapshot): snapshot.assert_match(lines) -def test_memfault_id_unpopulated(capsys, snapshot): +def test_memfault_id_unpopulated(capsys, snapshot, copy_file): elf_fixture_filename = os.path.join( ELF_FIXTURES_DIR, "memfault_build_id_present_and_unpopulated.elf" ) @@ -75,7 +72,7 @@ def test_memfault_id_unpopulated(capsys, snapshot): ELF_FIXTURES_DIR, "memfault_build_id_present_and_populated.elf" ) - with open_copy(elf_fixture_filename, mode="rb") as elf_copy_file: + with open(copy_file(elf_fixture_filename), mode="rb") as elf_copy_file: b = BuildIdInspectorAndPatcher(elf_copy_file) b.check_or_update_build_id() @@ -86,12 +83,12 @@ def test_memfault_id_unpopulated(capsys, snapshot): snapshot.assert_match(lines) -def test_memfault_id_populated(capsys, snapshot): +def test_memfault_id_populated(capsys, snapshot, copy_file): elf_fixture_filename = os.path.join( ELF_FIXTURES_DIR, "memfault_build_id_present_and_populated.elf" ) - with open_copy(elf_fixture_filename, mode="rb") as elf_copy_file: + with open(copy_file(elf_fixture_filename), mode="rb") as elf_copy_file: b = BuildIdInspectorAndPatcher(elf_copy_file) b.check_or_update_build_id() @@ -122,11 +119,11 @@ def test_no_build_id_on_dump(): b.dump_build_info(num_chars=1) -def test_build_id_dump(capsys, snapshot): +def test_build_id_dump(capsys, snapshot, copy_file): elf_fixture_filename = os.path.join( ELF_FIXTURES_DIR, "memfault_build_id_present_and_populated.elf" ) - with open_copy(elf_fixture_filename, mode="rb") as elf_copy_file: + with open(copy_file(elf_fixture_filename), mode="rb") as elf_copy_file: b = BuildIdInspectorAndPatcher(elf_copy_file) b.dump_build_info(num_chars=1) b.dump_build_info(num_chars=2) @@ -189,20 +186,20 @@ def test_build_id_dump(capsys, snapshot): ), ], ) -def test_get_build_info(fixture, expected_result): +def test_get_build_info(fixture, expected_result, copy_file): elf_fixture_filename = os.path.join(ELF_FIXTURES_DIR, fixture) - with open_copy(elf_fixture_filename, mode="rb") as elf_copy_file: + with open(copy_file(elf_fixture_filename), mode="rb") as elf_copy_file: b = BuildIdInspectorAndPatcher(elf_copy_file) assert b.get_build_info() == expected_result assert filecmp.cmp(elf_copy_file.name, elf_fixture_filename) -def test_crc_build_id_unpopulated(capsys, snapshot): +def test_crc_build_id_unpopulated(capsys, snapshot, copy_file): elf_fixture_filename = os.path.join(ELF_FIXTURES_DIR, "crc32_build_id_unpopulated.elf") result_fixture_filename = os.path.join(ELF_FIXTURES_DIR, "crc32_build_id_populated.elf") - with open_copy(elf_fixture_filename, mode="rb") as elf_copy_file: + with open(copy_file(elf_fixture_filename), mode="rb") as elf_copy_file: b = BuildIdInspectorAndPatcher(elf_copy_file) b.check_or_update_crc_build_id("g_example_crc32_build_id") @@ -213,10 +210,10 @@ def test_crc_build_id_unpopulated(capsys, snapshot): snapshot.assert_match(lines) -def test_crc_build_id_unpopulated_dump_only(capsys, snapshot): +def test_crc_build_id_unpopulated_dump_only(capsys, snapshot, copy_file): elf_fixture_filename = os.path.join(ELF_FIXTURES_DIR, "crc32_build_id_unpopulated.elf") - with open_copy(elf_fixture_filename, mode="rb") as elf_copy_file: + with open(copy_file(elf_fixture_filename), mode="rb") as elf_copy_file: b = BuildIdInspectorAndPatcher(elf_copy_file) b.check_or_update_crc_build_id("g_example_crc32_build_id", dump_only=True) @@ -228,10 +225,10 @@ def test_crc_build_id_unpopulated_dump_only(capsys, snapshot): snapshot.assert_match(lines) -def test_crc_build_id_populated(capsys, snapshot): +def test_crc_build_id_populated(capsys, snapshot, copy_file): elf_fixture_filename = os.path.join(ELF_FIXTURES_DIR, "crc32_build_id_populated.elf") - with open_copy(elf_fixture_filename, mode="rb") as elf_copy_file: + with open(copy_file(elf_fixture_filename), mode="rb") as elf_copy_file: b = BuildIdInspectorAndPatcher(elf_copy_file) b.check_or_update_crc_build_id("g_example_crc32_build_id") diff --git a/tasks/__init__.py b/tasks/__init__.py index 57fdff3f6..af27a7486 100644 --- a/tasks/__init__.py +++ b/tasks/__init__.py @@ -4,6 +4,7 @@ # import os +import pathlib from invoke import Collection, task @@ -11,6 +12,7 @@ from .macos_ftdi import is_macos SDK_FW_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +SDK_FW_TASKS_DIR = pathlib.Path(os.path.join(SDK_FW_ROOT, "tasks")) SDK_FW_TESTS_ROOT = os.path.join(SDK_FW_ROOT, "tests") @@ -60,12 +62,17 @@ def fw_sdk_unit_test(ctx, coverage=False, rule="", test_filter=None, test_dir=SD ns.add_collection(nrf) ns.add_collection(wiced) ns.add_collection(esp32) - if os.environ.get("STM32_ENABLED"): from . import stm32 ns.add_collection(stm32) +# Internal tasks are only included if they exist in the SDK +if (SDK_FW_TASKS_DIR / "internal.py").exists(): + from . import internal + + ns.add_collection(internal) + @task( pre=[ diff --git a/tasks/nrf.py b/tasks/nrf.py index 4dfbe8cf0..2297caa87 100644 --- a/tasks/nrf.py +++ b/tasks/nrf.py @@ -15,6 +15,7 @@ TASKS_DIR = os.path.dirname(__file__) MEMFAULT_SDK_ROOT = os.path.dirname(TASKS_DIR) NRF_ROOT = os.path.join(MEMFAULT_SDK_ROOT, "examples", "nrf5") +NRF_SDK_ROOT = os.path.join(NRF_ROOT, "nrf5_sdk") NRF_DEMO_APP_ROOT = os.path.join(NRF_ROOT, "apps", "memfault_demo_app") NRF_DEMO_APP_ELF = os.path.join(NRF_DEMO_APP_ROOT, "build", "memfault_demo_app_nrf52840_s140.out") diff --git a/tests/makefiles/Makefile_memfault_demo_cli.mk b/tests/makefiles/Makefile_memfault_demo_cli.mk deleted file mode 100644 index 8aa637ed6..000000000 --- a/tests/makefiles/Makefile_memfault_demo_cli.mk +++ /dev/null @@ -1,26 +0,0 @@ -COMPONENT_NAME=memfault_demo_cli - -SRC_FILES = \ - $(MFLT_COMPONENTS_DIR)/demo/src/memfault_demo_cli_print_chunk.c \ - $(MFLT_COMPONENTS_DIR)/http/src/memfault_http_client.c - -MOCK_AND_FAKE_SRC_FILES += \ - $(MFLT_COMPONENTS_DIR)/core/src/memfault_data_packetizer.c \ - $(MFLT_COMPONENTS_DIR)/util/src/memfault_chunk_transport.c \ - $(MFLT_COMPONENTS_DIR)/util/src/memfault_crc16_ccitt.c \ - $(MFLT_COMPONENTS_DIR)/util/src/memfault_varint.c \ - $(MFLT_COMPONENTS_DIR)/demo/src/http/memfault_demo_http.c \ - $(MFLT_TEST_FAKE_DIR)/fake_memfault_platform_get_device_info.c \ - $(MFLT_TEST_FAKE_DIR)/fake_memfault_platform_http_client.c \ - $(MFLT_TEST_MOCK_DIR)/mock_memfault_coredump.cpp \ - $(MFLT_TEST_MOCK_DIR)/mock_memfault_platform_debug_log.cpp \ - $(MFLT_TEST_STUB_DIR)/stub_memfault_log_save.c \ - -TEST_SRC_FILES = \ - $(MFLT_TEST_SRC_DIR)/test_memfault_demo_cli.cpp \ - $(MOCK_AND_FAKE_SRC_FILES) - -# Allow cast from (const char **) to (char **) -CPPUTEST_CPPFLAGS += -Wno-c++11-compat-deprecated-writable-strings -Wno-write-strings - -include $(CPPUTEST_MAKFILE_INFRA) diff --git a/tests/src/test_memfault_demo_cli.cpp b/tests/src/test_memfault_demo_cli.cpp deleted file mode 100644 index bf4acc741..000000000 --- a/tests/src/test_memfault_demo_cli.cpp +++ /dev/null @@ -1,176 +0,0 @@ -#include "CppUTest/MemoryLeakDetectorMallocMacros.h" -#include "CppUTest/MemoryLeakDetectorNewMacros.h" -#include "CppUTest/TestHarness.h" -#include "CppUTestExt/MockSupport.h" - -#include -#include - -#include "memfault/core/math.h" -#include "memfault/core/platform/debug_log.h" -#include "memfault/demo/cli.h" -#include "memfault/http/http_client.h" -#include "memfault/panics/platform/coredump.h" -#include "mocks/mock_memfault_coredump.h" - -int memfault_http_client_post_chunk(void) { - return 0; -} - -sMfltHttpClientConfig g_mflt_http_client_config = { - .api_key = "a1e284881e60450c957a5fbaae4e11de", -}; - -bool memfault_coredump_read(uint32_t offset, void *buf, size_t buf_len) { - return (memfault_platform_coredump_storage_read(offset, buf, buf_len) != 0); -} - -TEST_GROUP(MfltDemoCliTestGroup) { - void setup() { - // Set a size that will result in a more than a single line of output: - g_mock_memfault_coredump_total_size = 140; - } - - void teardown() { - mock().checkExpectations(); - mock().clear(); - } -}; - -static void prv_setup_test_print_chunk_expectations(const char *const lines[], size_t num_lines) { - mock().expectNCalls(2, "memfault_coredump_has_valid_coredump") - .andReturnValue(true) - .ignoreOtherParameters(); - mock().expectNCalls(4, "memfault_platform_coredump_storage_read").ignoreOtherParameters(); - for (unsigned int i = 0; i < num_lines; ++i) { - mock().expectOneCall("memfault_platform_log_raw").withStringParameter("output", lines[i]); - } - // coredump should be cleared after it has been drained - mock().expectOneCall("memfault_platform_coredump_storage_clear"); -} - -static void prv_setup_test_print_chunk_single_packet_expectations(const char *const lines[], size_t num_lines) { - mock().expectNCalls(2, "memfault_coredump_has_valid_coredump") - .andReturnValue(true) - .ignoreOtherParameters(); - mock().expectNCalls(4, "memfault_platform_coredump_storage_read").ignoreOtherParameters(); - for (unsigned int i = 0; i < num_lines; ++i) { - mock().expectOneCall("memfault_platform_log_raw").withStringParameter("output", lines[i]); - } - // coredump should be cleared after it has been drained - mock().expectOneCall("memfault_platform_coredump_storage_clear"); -} - -static void prv_test_print_chunk_curl(int argc, char *argv[]) { - const char *lines[] = { - "echo \\", - "0801ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\\", - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\\", - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\\", - "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffc2c\\", - "| xxd -p -r | curl -X POST https://chunks.memfault.com/api/v0/chunks/DAABBCCDD\\", - " -H 'Memfault-Project-Key:a1e284881e60450c957a5fbaae4e11de'\\", - " -H 'Content-Type:application/octet-stream' --data-binary @- -i", - "\nprint_chunk done", - }; - prv_setup_test_print_chunk_expectations(lines, MEMFAULT_ARRAY_SIZE(lines)); - - int retval = memfault_demo_cli_cmd_print_chunk(argc, (char **)argv); - LONGS_EQUAL(0, retval); -} - -TEST(MfltDemoCliTestGroup, Test_MfltDemoCliPrintCmdNoFormatUsesCurl) { - char *argv[] = {"print_chunk"}; - prv_test_print_chunk_curl(MEMFAULT_ARRAY_SIZE(argv), (char **)argv); -} - -TEST(MfltDemoCliTestGroup, Test_MfltDemoCliPrintCmdCurl) { - char *argv[] = {"print_chunk", "curl"}; - prv_test_print_chunk_curl(MEMFAULT_ARRAY_SIZE(argv), (char **)argv); -} - -TEST(MfltDemoCliTestGroup, Test_MfltDemoCliPrintCmdCurlSinglePacketChunk) { - char *argv[] = {"print_chunk", "curl", "40"}; - - const char *lines[] = { - "echo \\", - "488d0101ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\\", - "| xxd -p -r | curl -X POST https://chunks.memfault.com/api/v0/chunks/DAABBCCDD\\", - " -H 'Memfault-Project-Key:a1e284881e60450c957a5fbaae4e11de'\\", - " -H 'Content-Type:application/octet-stream' --data-binary @- -i", - "\nprint_chunk done", - "echo \\", - "c023ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\\", - "| xxd -p -r | curl -X POST https://chunks.memfault.com/api/v0/chunks/DAABBCCDD\\", - " -H 'Memfault-Project-Key:a1e284881e60450c957a5fbaae4e11de'\\", - " -H 'Content-Type:application/octet-stream' --data-binary @- -i", - "\nprint_chunk done", - "echo \\", - "c047ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\\", - "| xxd -p -r | curl -X POST https://chunks.memfault.com/api/v0/chunks/DAABBCCDD\\", - " -H 'Memfault-Project-Key:a1e284881e60450c957a5fbaae4e11de'\\", - " -H 'Content-Type:application/octet-stream' --data-binary @- -i", - "\nprint_chunk done", - "echo \\", - "806bfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc2c\\", - "| xxd -p -r | curl -X POST https://chunks.memfault.com/api/v0/chunks/DAABBCCDD\\", - " -H 'Memfault-Project-Key:a1e284881e60450c957a5fbaae4e11de'\\", - " -H 'Content-Type:application/octet-stream' --data-binary @- -i", - "\nprint_chunk done", - }; - prv_setup_test_print_chunk_single_packet_expectations(lines, MEMFAULT_ARRAY_SIZE(lines)); - - const size_t num_calls_needed = 4; - for (size_t i = 0; i < num_calls_needed; i++) { - int retval = memfault_demo_cli_cmd_print_chunk(MEMFAULT_ARRAY_SIZE(argv), (char **)argv); - LONGS_EQUAL(0, retval); - } -} - -TEST(MfltDemoCliTestGroup, Test_MfltDemoCliPrintCmdHex) { - const char *const lines[] = { - "0801ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "fffffffffffffffffffffffffffffffffffffffffffffffffffc2c", - }; - prv_setup_test_print_chunk_expectations(lines, MEMFAULT_ARRAY_SIZE(lines)); - - char *argv[] = {"print_chunk", "hex"}; - int retval = memfault_demo_cli_cmd_print_chunk(MEMFAULT_ARRAY_SIZE(argv), (char **)argv); - LONGS_EQUAL(0, retval); -} - -TEST(MfltDemoCliTestGroup, Test_MfltDemoCliPrintCmdInvalidFormat) { - mock().expectOneCall("memfault_platform_log"). - withIntParameter("level", kMemfaultPlatformLogLevel_Error). - withStringParameter("output", "Usage: \"print_chunk\" or \"print_chunk \""); - - char *argv[] = {"print_chunk", "invalid"}; - int retval = memfault_demo_cli_cmd_print_chunk(MEMFAULT_ARRAY_SIZE(argv), (char **)argv); - LONGS_EQUAL(-1, retval); -} - - -TEST(MfltDemoCliTestGroup, Test_MfltDemoCliPrintCmdNoData) { - mock().expectOneCall("memfault_coredump_has_valid_coredump") - .andReturnValue(false) - .ignoreOtherParameters(); - mock().expectOneCall("memfault_platform_log"). - withIntParameter("level", kMemfaultPlatformLogLevel_Info). - withStringParameter("output", "All data has been sent!"); - - char *argv[] = {"print_chunk" }; - int retval = memfault_demo_cli_cmd_print_chunk(MEMFAULT_ARRAY_SIZE(argv), (char **)argv); - LONGS_EQUAL(0, retval); -} - -TEST(MfltDemoCliTestGroup, Test_MfltDemoCliInvalidChunkSize) { - mock().expectOneCall("memfault_platform_log"). - withIntParameter("level", kMemfaultPlatformLogLevel_Error). - withStringParameter("output", "Usage: chunk_size must be <= 40 bytes"); - - char *argv[] = {"print_chunk", "curl", "41" }; - int retval = memfault_demo_cli_cmd_print_chunk(MEMFAULT_ARRAY_SIZE(argv), (char **)argv); - LONGS_EQUAL(-1, retval); -} diff --git a/tests/src/test_memfault_heartbeat_metrics.cpp b/tests/src/test_memfault_heartbeat_metrics.cpp index eb8afe843..3bea3c1d9 100644 --- a/tests/src/test_memfault_heartbeat_metrics.cpp +++ b/tests/src/test_memfault_heartbeat_metrics.cpp @@ -313,7 +313,7 @@ TEST(MemfaultHeartbeatMetrics, Test_String) { int rv = memfault_metrics_heartbeat_set_string(key, SAMPLE_STRING); LONGS_EQUAL(0, rv); - char sample_string[strlen(SAMPLE_STRING) + 1]; + char sample_string[sizeof(SAMPLE_STRING) + 1]; memset(sample_string, 0, sizeof(sample_string)); rv = memfault_metrics_heartbeat_read_string(key, sample_string, sizeof(sample_string)); @@ -326,7 +326,7 @@ TEST(MemfaultHeartbeatMetrics, Test_String) { int rv = memfault_metrics_heartbeat_set_string(key, SAMPLE_STRING "1"); LONGS_EQUAL(0, rv); - char sample_string[strlen(SAMPLE_STRING) + 1]; + char sample_string[sizeof(SAMPLE_STRING) + 1]; memset(sample_string, 0, sizeof(sample_string)); rv = memfault_metrics_heartbeat_read_string(key, sample_string, sizeof(sample_string)); @@ -348,7 +348,7 @@ TEST(MemfaultHeartbeatMetrics, Test_String) { rv = memfault_metrics_heartbeat_set_string(key, SHORT_TEST_STRING); LONGS_EQUAL(0, rv); - char sample_string[strlen(SHORT_TEST_STRING) + 1]; + char sample_string[sizeof(SHORT_TEST_STRING)]; memset(sample_string, 0, sizeof(sample_string)); rv = memfault_metrics_heartbeat_read_string(key, sample_string, sizeof(sample_string)); @@ -361,7 +361,7 @@ TEST(MemfaultHeartbeatMetrics, Test_String) { int rv = memfault_metrics_heartbeat_set_string(key, SAMPLE_STRING); LONGS_EQUAL(0, rv); - char sample_string[strlen(SAMPLE_STRING)]; + char sample_string[sizeof(SAMPLE_STRING) - 1]; memset(sample_string, 'a', sizeof(sample_string)); rv = memfault_metrics_heartbeat_read_string(key, sample_string, sizeof(sample_string));