diff --git a/.cyignore b/.cyignore new file mode 100644 index 000000000..9b44d22ee --- /dev/null +++ b/.cyignore @@ -0,0 +1,27 @@ +cmake +examples +makefile +ports/atmel +ports/dialog +ports/emlib +ports/esp8266_sdk +ports/esp_idf +ports/mynewt +ports/nrf5_sdk +ports/nxp +ports/particle +ports/qp +ports/s32sdk +ports/stm32cube +ports/templates +ports/zephyr +scripts +tests +$(SEARCH_memfault-firmware-sdk)/components/include/memfault/core +$(SEARCH_memfault-firmware-sdk)/components/include/memfault/demo +$(SEARCH_memfault-firmware-sdk)/components/include/memfault/http +$(SEARCH_memfault-firmware-sdk)/components/include/memfault/metrics +$(SEARCH_memfault-firmware-sdk)/components/include/memfault/panics +$(SEARCH_memfault-firmware-sdk)/components/include/memfault/util +$(SEARCH_memfault-firmware-sdk)/ports/include/memfault/ports/ble +$(SEARCH_memfault-firmware-sdk)/ports/include/memfault/ports/stm32cube diff --git a/CHANGES.md b/CHANGES.md index 45f4f46cb..ace716069 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,21 @@ +### Changes between Memfault SDK 0.31.0 and SDK 0.30.5 - June 6, 2022 + +#### :chart_with_upwards_trend: Improvements + +- Added reference port for [CAT1A (PSoC:tm: 6)](https://github.com/Infineon/mtb-pdl-cat1) based + MCUs using the + [ModusToolbox:tm: Software](https://www.infineon.com/cms/en/design-support/tools/sdk/modustoolbox-software/) + stack. For more details see [ports/cypress/psoc6](ports/cypress/psoc6) directory. +- - Added a convenience utility function for posting chunks using the Memfault http client. See + [`memfault_http_client_post_chunk`](components/include/memfault/http/http_client.h#L101) + for more details! + +#### :house: Internal + +- Fixed compiler error in + [nRF91 sample test app](examples/nrf-connect-sdk/nrf9160/memfault_demo_app) + when compiling with the nRF Connect SDK 1.8 release + ### Changes between Memfault SDK 0.30.5 and SDK 0.30.4 - May 24, 2022 #### :rocket: New Features diff --git a/VERSION b/VERSION index eb3330cdd..8323867af 100644 --- a/VERSION +++ b/VERSION @@ -1,2 +1,2 @@ -BUILD ID: 447316 -GIT COMMIT: 77b7799c5 +BUILD ID: 451641 +GIT COMMIT: 963211879 diff --git a/components/demo/src/http/memfault_demo_http.c b/components/demo/src/http/memfault_demo_http.c index 11c5642a6..68669a923 100644 --- a/components/demo/src/http/memfault_demo_http.c +++ b/components/demo/src/http/memfault_demo_http.c @@ -27,20 +27,5 @@ const char *memfault_demo_get_api_project_key(void) { int memfault_demo_cli_cmd_post_core(MEMFAULT_UNUSED int argc, MEMFAULT_UNUSED char *argv[]) { MEMFAULT_LOG_INFO("Posting Memfault Data..."); - sMfltHttpClient *http_client = memfault_http_client_create(); - if (!http_client) { - MEMFAULT_LOG_ERROR("Failed to create HTTP client"); - return MemfaultInternalReturnCode_Error; - } - - const int rv = memfault_http_client_post_data(http_client); - if ((eMfltPostDataStatus)rv == kMfltPostDataStatus_NoDataFound) { - MEMFAULT_LOG_INFO("No new data found"); - } else { - MEMFAULT_LOG_INFO("Result: %d", rv); - } - const uint32_t timeout_ms = 30 * 1000; - memfault_http_client_wait_until_requests_completed(http_client, timeout_ms); - memfault_http_client_destroy(http_client); - return rv; + return memfault_http_client_post_chunk(); } diff --git a/components/http/src/memfault_http_client_post_chunk.c b/components/http/src/memfault_http_client_post_chunk.c new file mode 100644 index 000000000..4a6d363e2 --- /dev/null +++ b/components/http/src/memfault_http_client_post_chunk.c @@ -0,0 +1,38 @@ +//! @file +//! +//! Copyright (c) Memfault, Inc. +//! See License.txt for details +//! +//! @brief +//! Implements conveninece API for posting a single chunk of Memfault data + +#include "memfault/http/http_client.h" + +#include "memfault/core/debug_log.h" +#include "memfault/core/errors.h" +#include "memfault/core/data_packetizer.h" + +int memfault_http_client_post_chunk(void) { + // A pre-flight check before we attempt to setup an HTTP client + // If there's no data to send, just early return + bool more_data = memfault_packetizer_data_available(); + if (!more_data) { + // no new data to post + return kMfltPostDataStatus_NoDataFound; + } + + sMfltHttpClient *http_client = memfault_http_client_create(); + if (!http_client) { + MEMFAULT_LOG_ERROR("Failed to create HTTP client"); + return MemfaultInternalReturnCode_Error; + } + + const int rv = memfault_http_client_post_data(http_client); + if ((eMfltPostDataStatus)rv != kMfltPostDataStatus_Success) { + MEMFAULT_LOG_ERROR("Failed to post chunk: rv=%d", rv); + } + const uint32_t timeout_ms = 30 * 1000; + memfault_http_client_wait_until_requests_completed(http_client, timeout_ms); + memfault_http_client_destroy(http_client); + return rv; +} diff --git a/components/include/memfault/http/http_client.h b/components/include/memfault/http/http_client.h index ee6bf774e..b31b5f506 100644 --- a/components/include/memfault/http/http_client.h +++ b/components/include/memfault/http/http_client.h @@ -98,6 +98,12 @@ typedef enum { //! if no data was found or else an error code. int memfault_http_client_post_data(sMfltHttpClient *client); +//! Create a http client, post a chunk of data and then teardown the connection +//! +//! @return kMfltPostDataStatus_Success on success, kMfltPostDataStatus_NoDataFound +//! if no data was found or else an error code. +int memfault_http_client_post_chunk(void); + //! Waits until pending requests have been completed. //! @param client The http client. //! @return 0 on success, else error code diff --git a/components/include/memfault/version.h b/components/include/memfault/version.h index 8cbf09dd5..70b1ccc4b 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 = 30, .patch = 5 } +#define MEMFAULT_SDK_VERSION { .major = 0, .minor = 31, .patch = 0 } #ifdef __cplusplus } diff --git a/examples/nrf-connect-sdk/nrf9160/memfault_demo_app/CMakeLists.txt b/examples/nrf-connect-sdk/nrf9160/memfault_demo_app/CMakeLists.txt index 7ab2016b5..0cceeef88 100644 --- a/examples/nrf-connect-sdk/nrf9160/memfault_demo_app/CMakeLists.txt +++ b/examples/nrf-connect-sdk/nrf9160/memfault_demo_app/CMakeLists.txt @@ -38,8 +38,10 @@ if (NCS_VERSION_MAJOR) set(CONFIG_NEWLIB_LIBC y CACHE INTERNAL "") endif() - # These were removed in NCS 1.9, but are needed prior to that. - if (${NCS_VERSION_MAJOR} LESS_EQUAL 1 AND ${NCS_VERSION_MINOR} LESS 9 AND ${NCS_VERSION_PATCH} LESS 99) + # These were removed in NCS 1.8.0, but are needed prior to that. Enable them + # if NCS version <1.7.99 (.99 patch version is used for the next revision's + # development series) + if (${NCS_VERSION_MAJOR}.${NCS_VERSION_MINOR}.${NCS_VERSION_PATCH} VERSION_LESS 1.7.99) set(CONFIG_BSD_LIBRARY y CACHE INTERNAL "") set(CONFIG_BSD_LIBRARY_SYS_INIT n CACHE INTERNAL "") # ^ Note: CONFIG_BSD_ were renamed to _NRF_MODEM_ in diff --git a/examples/wiced/libraries/memfault/http/http.mk b/examples/wiced/libraries/memfault/http/http.mk index 7d159c35d..7bc7999cd 100644 --- a/examples/wiced/libraries/memfault/http/http.mk +++ b/examples/wiced/libraries/memfault/http/http.mk @@ -1,31 +1,34 @@ NAME := MemfaultHttp -$(NAME)_SOURCES := src/memfault_http_client.c \ +$(NAME)_SOURCES := \ + src/memfault_http_client.c \ + src/memfault_http_client_post_chunk.c -$(NAME)_COMPONENTS := libraries/memfault/core \ - libraries/memfault/panics \ - protocols/HTTP_client \ - +$(NAME)_COMPONENTS := \ + libraries/memfault/core \ + libraries/memfault/panics \ + protocols/HTTP_client $(NAME)_INCLUDES += include GLOBAL_INCLUDES += include VALID_OSNS_COMBOS := ThreadX-NetX_Duo FreeRTOS-LwIP -VALID_PLATFORMS := BCM943362WCD4 \ - BCM943362WCD6 \ - BCM943362WCD8 \ - BCM943364WCD1 \ - CYW94343WWCD1_EVB \ - BCM943438WCD1 \ - BCM94343WWCD2 \ - CY8CKIT_062 \ - NEB1DX* \ - CYW9MCU7X9N364 \ - CYW943907AEVAL1F \ - CYW954907AEVAL1F \ - CYW9WCD2REFAD2* \ - CYW9WCD760PINSDAD2 \ - CYW943455EVB* \ - CYW943012EVB* +VALID_PLATFORMS := \ + BCM943362WCD4 \ + BCM943362WCD6 \ + BCM943362WCD8 \ + BCM943364WCD1 \ + CYW94343WWCD1_EVB \ + BCM943438WCD1 \ + BCM94343WWCD2 \ + CY8CKIT_062 \ + NEB1DX* \ + CYW9MCU7X9N364 \ + CYW943907AEVAL1F \ + CYW954907AEVAL1F \ + CYW9WCD2REFAD2* \ + CYW9WCD760PINSDAD2 \ + CYW943455EVB* \ + CYW943012EVB* diff --git a/ports/cypress/psoc6/README.md b/ports/cypress/psoc6/README.md new file mode 100644 index 000000000..889de4c35 --- /dev/null +++ b/ports/cypress/psoc6/README.md @@ -0,0 +1,4 @@ +# Memfault Library for ModusToolbox:tm: + +To get started with the Memfault ModusToolbox:tm: port see the integration guide +available [here](https://mflt.io/mtb-integration-guide). diff --git a/ports/cypress/psoc6/memfault_bss.ld b/ports/cypress/psoc6/memfault_bss.ld new file mode 100644 index 000000000..2bf33a6da --- /dev/null +++ b/ports/cypress/psoc6/memfault_bss.ld @@ -0,0 +1,16 @@ +/* + Custom section to be included in the linker command file to support recovery of all FreeRTOS tasks when + a coredump is collected. +*/ + +SECTIONS +{ + .mflt_bss (NOLOAD) : + { + __memfault_capture_bss_start = .; + *tasks.o(.bss COMMON .bss*) + *timers*.o(.bss COMMON .bss*) + __memfault_capture_bss_end = .; + } +} +INSERT BEFORE .bss; diff --git a/ports/cypress/psoc6/memfault_platform_core.c b/ports/cypress/psoc6/memfault_platform_core.c new file mode 100644 index 000000000..efcaf1545 --- /dev/null +++ b/ports/cypress/psoc6/memfault_platform_core.c @@ -0,0 +1,65 @@ +//! @file +//! +//! Copyright (c) Memfault, Inc. +//! See License.txt for details +//! +//! @brief +//! Implementation of core dependencies and setup for PSOC6 based products that are using the +//! ModusToolbox SDK + +#include "memfault/components.h" +#include "memfault/ports/reboot_reason.h" +#include "memfault/ports/freertos.h" + +#ifndef MEMFAULT_EVENT_STORAGE_RAM_SIZE +#define MEMFAULT_EVENT_STORAGE_RAM_SIZE 1024 +#endif + +MEMFAULT_WEAK +void memfault_platform_reboot(void) { + NVIC_SystemReset(); + while (1) { } // unreachable +} + +size_t memfault_platform_sanitize_address_range(void *start_addr, size_t desired_size) { + static const struct { + uint32_t start_addr; + size_t length; + } s_mcu_mem_regions[] = { + {.start_addr = CY_SRAM_BASE, .length = CY_SRAM_SIZE}, + }; + + for (size_t i = 0; i < MEMFAULT_ARRAY_SIZE(s_mcu_mem_regions); i++) { + const uint32_t lower_addr = s_mcu_mem_regions[i].start_addr; + const uint32_t upper_addr = lower_addr + s_mcu_mem_regions[i].length; + if ((uint32_t)start_addr >= lower_addr && ((uint32_t)start_addr < upper_addr)) { + return MEMFAULT_MIN(desired_size, upper_addr - (uint32_t)start_addr); + } + } + + return 0; +} + +int memfault_platform_boot(void) { + memfault_build_info_dump(); + memfault_device_info_dump(); + + memfault_freertos_port_boot(); + memfault_platform_reboot_tracking_boot(); + + static uint8_t s_event_storage[MEMFAULT_EVENT_STORAGE_RAM_SIZE]; + const sMemfaultEventStorageImpl *evt_storage = + memfault_events_storage_boot(s_event_storage, sizeof(s_event_storage)); + memfault_trace_event_boot(evt_storage); + + memfault_reboot_tracking_collect_reset_info(evt_storage); + + sMemfaultMetricBootInfo boot_info = { + .unexpected_reboot_count = memfault_reboot_tracking_get_crash_count(), + }; + memfault_metrics_boot(evt_storage, &boot_info); + + MEMFAULT_LOG_INFO("Memfault Initialized!"); + + return 0; +} diff --git a/ports/cypress/psoc6/memfault_platform_coredump_regions.c b/ports/cypress/psoc6/memfault_platform_coredump_regions.c new file mode 100644 index 000000000..2f1239895 --- /dev/null +++ b/ports/cypress/psoc6/memfault_platform_coredump_regions.c @@ -0,0 +1,87 @@ +//! @file +//! +//! Copyright (c) Memfault, Inc. +//! See License.txt for details +//! +//! @brief +//! A coredump port which scoops up all the FreeRTOS state in the system at the time of crash +//! To override and provide a custom port, simply add this file to the .cyignore for your project +//! so it is not included in the build: +//! (i.e $(SEARCH_memfault-firmware-sdk)/ports/cypress/psoc6/memfault_platform_coredump_regions.c) + +#include +#include + +#include "memfault/components.h" +#include "memfault/panics/arch/arm/cortex_m.h" +#include "memfault/ports/freertos_coredump.h" + +#include "cy_syslib.h" +#include "cy_device_headers.h" + +#define MEMFAULT_COREDUMP_MAX_TASK_REGIONS ((MEMFAULT_PLATFORM_MAX_TRACKED_TASKS) * 2) + +static sMfltCoredumpRegion s_coredump_regions[ + MEMFAULT_COREDUMP_MAX_TASK_REGIONS + + 2 /* active stack(s) */ + + 1 /* _kernel variable */ + + 1 /* __memfault_capture_start */ +]; + +//! Note: If you get a linker error because these symbols are missing, your forgot to add the Memfault ld file +//! to you LDFLAGS: +//! LDFLAGS += -T$(SEARCH_memfault-firmware-sdk)/ports/cypress/psoc6/memfault_bss.ld +extern uint32_t __memfault_capture_bss_end; +extern uint32_t __memfault_capture_bss_start; + +//! Note: This function is called early on boot before the C runtime is loaded +//! We hook into this function in order to scrub the +void Cy_OnResetUser(void) { + const size_t memfault_region_size = (uint32_t)&__memfault_capture_bss_end - + (uint32_t)&__memfault_capture_bss_start; + memset((uint32_t*)&__memfault_capture_bss_start, 0x0, memfault_region_size); +} + +const sMfltCoredumpRegion *memfault_platform_coredump_get_regions( + const sCoredumpCrashInfo *crash_info, size_t *num_regions) { + int region_idx = 0; + const size_t active_stack_size_to_collect = 512; + + // first, capture the active stack (and ISR if applicable) + const bool msp_was_active = (crash_info->exception_reg_state->exc_return & (1 << 2)) == 0; + + size_t stack_size_to_collect = memfault_platform_sanitize_address_range( + crash_info->stack_address, MEMFAULT_PLATFORM_ACTIVE_STACK_SIZE_TO_COLLECT); + + s_coredump_regions[region_idx] = MEMFAULT_COREDUMP_MEMORY_REGION_INIT( + crash_info->stack_address, stack_size_to_collect); + region_idx++; + + if (msp_was_active) { + // System crashed in an ISR but the running task state is on PSP so grab that too + void *psp = (void *)(uintptr_t)__get_PSP(); + + // Collect a little bit more stack for the PSP since there is an + // exception frame that will have been stacked on it as well + const uint32_t extra_stack_bytes = 128; + stack_size_to_collect = memfault_platform_sanitize_address_range( + psp, active_stack_size_to_collect + extra_stack_bytes); + s_coredump_regions[region_idx] = MEMFAULT_COREDUMP_MEMORY_REGION_INIT( + psp, stack_size_to_collect); + region_idx++; + } + + // Scoop up memory regions necessary to perform unwinds of the FreeRTOS tasks + const size_t memfault_region_size = (uint32_t)&__memfault_capture_bss_end - + (uint32_t)&__memfault_capture_bss_start; + + s_coredump_regions[region_idx] = MEMFAULT_COREDUMP_MEMORY_REGION_INIT( + &__memfault_capture_bss_start, memfault_region_size); + region_idx++; + + region_idx += memfault_freertos_get_task_regions(&s_coredump_regions[region_idx], + MEMFAULT_ARRAY_SIZE(s_coredump_regions) - region_idx); + + *num_regions = region_idx; + return &s_coredump_regions[0]; +} diff --git a/ports/cypress/psoc6/memfault_platform_http.c b/ports/cypress/psoc6/memfault_platform_http.c new file mode 100644 index 000000000..c8ddc1457 --- /dev/null +++ b/ports/cypress/psoc6/memfault_platform_http.c @@ -0,0 +1,238 @@ +//! @file +//! +//! Copyright (c) Memfault, Inc. +//! See License.txt for details +//! +//! @brief +//! Implements dependency functions required to utilize Memfault's http client +//! for posting data collected via HTTPS + +#include + +#include "memfault/components.h" + +#include "cy_secure_sockets.h" +#include "cy_tls.h" + +struct MfltHttpClient { + bool active; + cy_socket_t handle; + cy_socket_sockaddr_t sock_addr; +}; + +typedef struct MfltHttpResponse { + uint32_t status_code; +} sMfltHttpResponse; + +static sMfltHttpClient s_client; + +static cy_rslt_t prv_teardown_connection(sMfltHttpClient *client) { + cy_rslt_t result = cy_socket_disconnect(client->handle, 0); + if (result != CY_RSLT_SUCCESS) { + MEMFAULT_LOG_ERROR("cy_socket_disconnect failed: rv=0x%x", (int)result); + } + + cy_socket_delete(client->handle); + client->active = false; + return 0; +} + +static cy_rslt_t prv_disconnect_handler(cy_socket_t socket_handle, void *arg) { + MEMFAULT_LOG_DEBUG("Memfault Socket Disconnected dropped"); + prv_teardown_connection(&s_client); + return 0; +} + +static cy_rslt_t prv_open_socket(sMfltHttpClient *client) { + cy_rslt_t result = cy_socket_create(CY_SOCKET_DOMAIN_AF_INET, CY_SOCKET_TYPE_STREAM, + CY_SOCKET_IPPROTO_TLS, &client->handle); + + if (result != CY_RSLT_SUCCESS) { + MEMFAULT_LOG_ERROR("cy_socket_create failed, rv=0x%x", (int)result); + return result; + } + + cy_socket_opt_callback_t disconnect_listener = { + .callback = prv_disconnect_handler, .arg = NULL}; + + result = cy_socket_setsockopt( + client->handle, CY_SOCKET_SOL_SOCKET, CY_SOCKET_SO_DISCONNECT_CALLBACK, + &disconnect_listener, sizeof(cy_socket_opt_callback_t)); + if (result != CY_RSLT_SUCCESS) { + MEMFAULT_LOG_ERROR( + "cy_socket_setsockopt CY_SOCKET_SO_DISCONNECT_CALLBACK failed, rv=0x%x", (int)result); + return result; + } + + cy_socket_tls_auth_mode_t tls_auth_mode = CY_SOCKET_TLS_VERIFY_REQUIRED; + result = cy_socket_setsockopt(client->handle, CY_SOCKET_SOL_TLS, + CY_SOCKET_SO_TLS_AUTH_MODE, &tls_auth_mode, + sizeof(cy_socket_tls_auth_mode_t)); + if (result != CY_RSLT_SUCCESS) { + MEMFAULT_LOG_ERROR("cy_socket_setsockopt CY_SOCKET_SO_TLS_AUTH_MODE failed, rv=0x%x", + (int)result); + } + + result = cy_socket_connect(client->handle, &client->sock_addr, + sizeof(cy_socket_sockaddr_t)); + if (result != CY_RSLT_SUCCESS) { + MEMFAULT_LOG_ERROR("cy_socket_connect failed, 0x%x", (int)result); + } + + return result; +} + +sMfltHttpClient *memfault_platform_http_client_create(void) { + if (s_client.active) { + MEMFAULT_LOG_ERROR("Memfault HTTP client already in use"); + return NULL; + } + + s_client = (sMfltHttpClient) { + .sock_addr = { + .port = MEMFAULT_HTTP_GET_CHUNKS_API_PORT(), + }, + }; + + cy_rslt_t result = cy_socket_gethostbyname( + MEMFAULT_HTTP_CHUNKS_API_HOST, CY_SOCKET_IP_VER_V4, &s_client.sock_addr.ip_address); + if (result != CY_RSLT_SUCCESS) { + MEMFAULT_LOG_ERROR("DNS lookup failed: 0x%x", (int)result); + return NULL; + } + + result = prv_open_socket(&s_client); + if (result != CY_RSLT_SUCCESS) { + return NULL; + } + + s_client.active = true; + return &s_client; +} + + +static bool prv_try_send(sMfltHttpClient *client, const uint8_t *buf, size_t buf_len) { + cy_rslt_t idx = 0; + while (idx != buf_len) { + uint32_t bytes_sent = 0; + int rv = cy_socket_send(client->handle, &buf[idx], buf_len - idx, CY_SOCKET_FLAGS_NONE, &bytes_sent); + if (rv == CY_RSLT_SUCCESS && bytes_sent > 0) { + idx += bytes_sent; + continue; + } + + MEMFAULT_LOG_ERROR("Data Send Error: bytes_sent=%d, cy_rslt=0x%x", (int)bytes_sent, rv); + return false; + + } + return true; +} + +static bool prv_send_data(const void *data, size_t data_len, void *ctx) { + sMfltHttpClient *client = (sMfltHttpClient *)ctx; + return prv_try_send(client, data, data_len); +} + +static bool prv_read_socket_data(sMfltHttpClient *client, void *buf, size_t *buf_len) { + uint32_t buf_len_out; + cy_rslt_t result = cy_socket_recv(client->handle, buf, *buf_len, CY_SOCKET_FLAGS_NONE, &buf_len_out); + *buf_len = (size_t)buf_len_out; + return result == CY_RSLT_SUCCESS; +} + +int memfault_platform_http_response_get_status(const sMfltHttpResponse *response, uint32_t *status_out) { + MEMFAULT_SDK_ASSERT(response != NULL); + + *status_out = response->status_code; + return 0; +} + +static int prv_wait_for_http_response(sMfltHttpClient *client) { + sMemfaultHttpResponseContext ctx = { 0 }; + while (1) { + // We don't expect any response that needs to be parsed so + // just use an arbitrarily small receive buffer + char buf[32]; + size_t bytes_read = sizeof(buf); + if (!prv_read_socket_data(client, buf, &bytes_read)) { + return -1; + } + + bool done = memfault_http_parse_response(&ctx, buf, bytes_read); + if (done) { + MEMFAULT_LOG_DEBUG("Response Complete: Parse Status %d HTTP Status %d!", + (int)ctx.parse_error, ctx.http_status_code); + MEMFAULT_LOG_DEBUG("Body: %s", ctx.http_body); + return ctx.http_status_code; + } + } +} + +int memfault_platform_http_client_post_data( + sMfltHttpClient *client, MemfaultHttpClientResponseCallback callback, void *ctx) { + if (!client->active) { + return -1; + } + + const sPacketizerConfig cfg = { + // let a single msg span many "memfault_packetizer_get_next" calls + .enable_multi_packet_chunk = true, + }; + + // will be populated with size of entire message queued for sending + sPacketizerMetadata metadata; + const bool data_available = memfault_packetizer_begin(&cfg, &metadata); + if (!data_available) { + MEMFAULT_LOG_DEBUG("No more data to send"); + return kMfltPostDataStatus_NoDataFound; + } + + memfault_http_start_chunk_post(prv_send_data, client, metadata.single_chunk_message_length); + + // Drain all the data that is available to be sent + while (1) { + // Arbitrarily sized send buffer. + uint8_t buf[128]; + size_t buf_len = sizeof(buf); + eMemfaultPacketizerStatus status = memfault_packetizer_get_next(buf, &buf_len); + if (status == kMemfaultPacketizerStatus_NoMoreData) { + break; + } + + if (!prv_try_send(client, buf, buf_len)) { + // unexpected failure, abort in-flight transaction + memfault_packetizer_abort(); + return false; + } + + if (status == kMemfaultPacketizerStatus_EndOfChunk) { + break; + } + } + + // we've sent a chunk, drain status + sMfltHttpResponse response = { + .status_code = prv_wait_for_http_response(client), + }; + + if (callback) { + callback(&response, ctx); + } + + return 0; +} + +int memfault_platform_http_client_destroy(sMfltHttpClient *client) { + if (!client->active) { + return -1; + } + + prv_teardown_connection(client); + return 0; +} + +int memfault_platform_http_client_wait_until_requests_completed( + sMfltHttpClient *client, uint32_t timeout_ms) { + // No-op because memfault_platform_http_client_post_data() is synchronous + return 0; +} diff --git a/ports/cypress/psoc6/res_cause_reboot_tracking.c b/ports/cypress/psoc6/res_cause_reboot_tracking.c new file mode 100644 index 000000000..afcc15f30 --- /dev/null +++ b/ports/cypress/psoc6/res_cause_reboot_tracking.c @@ -0,0 +1,123 @@ +//! @file +//! +//! Copyright (c) Memfault, Inc. +//! See License.txt for details +//! +//! A port for recovering reset reason information by reading the Reset +//! Reason using the PSOC6 Peripheral HAL: https://github.com/Infineon/mtb-pdl-cat1 + +#include "memfault/components.h" +#include "memfault/ports/reboot_reason.h" + +#include "cy_syslib.h" + +//! Note: The default PSOC62 linker scripts have a KEEP(*(.noinit)) that we can use +MEMFAULT_PUT_IN_SECTION(".mflt_reboot_tracking.noinit") +static uint8_t s_reboot_tracking[MEMFAULT_REBOOT_TRACKING_REGION_SIZE]; + +#if MEMFAULT_ENABLE_REBOOT_DIAG_DUMP +#define MEMFAULT_PRINT_RESET_INFO(...) MEMFAULT_LOG_INFO(__VA_ARGS__) +#else +#define MEMFAULT_PRINT_RESET_INFO(...) +#endif + +void memfault_reboot_reason_get(sResetBootupInfo *info) { + MEMFAULT_SDK_ASSERT(info != NULL); + + eMemfaultRebootReason reset_reason = kMfltRebootReason_Unknown; + + const uint32_t reset_cause = Cy_SysLib_GetResetReason(); + + MEMFAULT_LOG_INFO("Reset Reason, Cy_SysLib_GetResetReason=0x%" PRIx32, reset_cause); + MEMFAULT_PRINT_RESET_INFO("Reset Cause: "); + + switch (reset_cause) { + case CY_SYSLIB_RESET_HWWDT: + MEMFAULT_PRINT_RESET_INFO(" HW WDT"); + reset_reason = kMfltRebootReason_HardwareWatchdog; + break; + case CY_SYSLIB_RESET_ACT_FAULT: + // unauthorized protection violations + MEMFAULT_PRINT_RESET_INFO(" ACT Fault"); + reset_reason = kMfltRebootReason_UnknownError; + break; + case CY_SYSLIB_RESET_DPSLP_FAULT: + // failed to enter deep sleep + MEMFAULT_PRINT_RESET_INFO(" DPSLP Fault"); + reset_reason = kMfltRebootReason_UnknownError; + break; + +#if defined (CY_IP_M33SYSCPUSS) || defined (CY_IP_M7CPUSS) + case CY_SYSLIB_RESET_TC_DBGRESET: + MEMFAULT_PRINT_RESET_INFO(" TC DBGRESET"); + reset_reason = kMfltRebootReason_Assert; + break; +#endif + + case CY_SYSLIB_RESET_SOFT: + MEMFAULT_PRINT_RESET_INFO(" Software Reset"); + reset_reason = kMfltRebootReason_SoftwareReset; + break; + + case CY_SYSLIB_RESET_SWWDT0: + case CY_SYSLIB_RESET_SWWDT1: + case CY_SYSLIB_RESET_SWWDT2: + case CY_SYSLIB_RESET_SWWDT3: + MEMFAULT_PRINT_RESET_INFO(" Software Watchdog"); + reset_reason = kMfltRebootReason_SoftwareWatchdog; + break; + + case CY_SYSLIB_RESET_CSV_LOSS_WAKEUP: + case CY_SYSLIB_RESET_CSV_ERROR_WAKEUP: + MEMFAULT_PRINT_RESET_INFO(" Clock-Supervision Logic Reset"); + reset_reason = kMfltRebootReason_ClockFailure; + break; + + case CY_SYSLIB_RESET_HIB_WAKEUP: + MEMFAULT_PRINT_RESET_INFO(" Hibernation Wakeup"); + reset_reason = kMfltRebootReason_LowPower; + break; + +#ifdef CY_IP_M7CPUSS + case CY_SYSLIB_RESET_XRES: + case CY_SYSLIB_RESET_BODVDDD: + case CY_SYSLIB_RESET_BODVDDA: + case CY_SYSLIB_RESET_BODVCCD: + MEMFAULT_PRINT_RESET_INFO(" Brown Out"); + reset_reason = kMfltRebootReason_BrownOutReset; + break; + + case CY_SYSLIB_RESET_OVDVDDD: + case CY_SYSLIB_RESET_OVDVDDA: + case CY_SYSLIB_RESET_OVDVCCD: + case CY_SYSLIB_RESET_OCD_ACT_LINREG: + case CY_SYSLIB_RESET_OCD_DPSLP_LINREG: + case CY_SYSLIB_RESET_OCD_REGHC: + case CY_SYSLIB_RESET_PMIC: + case CY_SYSLIB_RESET_PXRES: + case CY_SYSLIB_RESET_STRUCT_XRES: + reset_reason = kMfltRebootReason_UnknownError; + break; + case CY_SYSLIB_RESET_PORVDDD: + MEMFAULT_PRINT_RESET_INFO(" Power on Reset"); + reset_reason = kMfltRebootReason_PowerOnReset; + break; +#endif + default: + reset_reason = kMfltRebootReason_Unknown; + MEMFAULT_PRINT_RESET_INFO(" Unknown"); + break; + + } + + *info = (sResetBootupInfo){ + .reset_reason_reg = reset_cause, + .reset_reason = reset_reason, + }; +} + +void memfault_platform_reboot_tracking_boot(void) { + sResetBootupInfo reset_info = { 0 }; + memfault_reboot_reason_get(&reset_info); + memfault_reboot_tracking_boot(s_reboot_tracking, &reset_info); +} diff --git a/ports/cypress/psoc6/templates/README b/ports/cypress/psoc6/templates/README new file mode 100644 index 000000000..0332633c1 --- /dev/null +++ b/ports/cypress/psoc6/templates/README @@ -0,0 +1,16 @@ +# templates + +This folder contains default configuration files for ports using Modus Toolbox. + +If you would like to tune the configuration simply exclude the entire directory or select files +in your projects .cyignore file + +``` +$(SEARCH_memfault-firmware-sdk)/ports/cypress/psoc6/templates/memfault_metrics_heartbeat_config.def +``` + +or + +``` +$(SEARCH_memfault-firmware-sdk)/ports/cypress/psoc6/templates +``` diff --git a/ports/cypress/psoc6/templates/memfault_metrics_heartbeat_config.def b/ports/cypress/psoc6/templates/memfault_metrics_heartbeat_config.def new file mode 100644 index 000000000..e69de29bb diff --git a/ports/cypress/psoc6/templates/memfault_platform_config.h b/ports/cypress/psoc6/templates/memfault_platform_config.h new file mode 100644 index 000000000..833b32976 --- /dev/null +++ b/ports/cypress/psoc6/templates/memfault_platform_config.h @@ -0,0 +1,23 @@ +//! @file +//! +//! Copyright (c) Memfault, Inc. +//! See License.txt for details +//! +//! Default PSOC6 configuration + +#ifdef __cplusplus +extern "C" { +#endif + +//! Pick up logging macros from memfault_platform_log_config.h +#define MEMFAULT_PLATFORM_HAS_LOG_CONFIG 1 + +//! Change the name of the coredump noinit section to align with default +//! PSOC6 .ld of KEEP(*(.noinit)) +#define MEMFAULT_PLATFORM_COREDUMP_NOINIT_SECTION_NAME ".mflt_coredump.noinit" + +#define MEMFAULT_PLATFORM_COREDUMP_STORAGE_RAM_SIZE 8192 + +#ifdef __cplusplus +} +#endif diff --git a/ports/cypress/psoc6/templates/memfault_platform_log_config.h b/ports/cypress/psoc6/templates/memfault_platform_log_config.h new file mode 100644 index 000000000..320478639 --- /dev/null +++ b/ports/cypress/psoc6/templates/memfault_platform_log_config.h @@ -0,0 +1,25 @@ +//! @file +//! +//! Copyright (c) Memfault, Inc. +//! See License.txt for details +//! +//! Copyright (c) Memfault, Inc. +//! See License.txt for details +// Logging depends on how your configuration does logging. See +// https://docs.memfault.com/docs/mcu/self-serve/#logging-dependency + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define MEMFAULT_LOG_DEBUG(fmt, ...) printf( "[D] " fmt "\n", ## __VA_ARGS__) +#define MEMFAULT_LOG_INFO(fmt, ...) printf( "[I] " fmt "\n", ## __VA_ARGS__) +#define MEMFAULT_LOG_WARN(fmt, ...) printf( "[W] " fmt "\n", ## __VA_ARGS__) +#define MEMFAULT_LOG_ERROR(fmt, ...) printf( "[E] " fmt "\n", ## __VA_ARGS__) +#define MEMFAULT_LOG_RAW(fmt, ...) printf( fmt "\n", ## __VA_ARGS__) + +#ifdef __cplusplus +} +#endif diff --git a/ports/cypress/psoc6/templates/memfault_trace_reason_user_config.def b/ports/cypress/psoc6/templates/memfault_trace_reason_user_config.def new file mode 100644 index 000000000..e69de29bb diff --git a/ports/freertos/src/memfault_freertos_ram_regions.c b/ports/freertos/src/memfault_freertos_ram_regions.c index 552121c86..6f793457b 100644 --- a/ports/freertos/src/memfault_freertos_ram_regions.c +++ b/ports/freertos/src/memfault_freertos_ram_regions.c @@ -15,10 +15,10 @@ //! { //! _sbss = . ; //! __bss_start__ = _sbss; -//! __memfault_capture_start = .; +//! __memfault_capture_bss_start = .; //! *tasks.o(.bss COMMON .bss*) //! *timers*.o(.bss COMMON .bss*) -//! __memfault_capture_end = .; +//! __memfault_capture_bss_end = .; //! //! 2) Add this file to your build and update FreeRTOSConfig.h to //! include "memfault/ports/freertos_trace.h" @@ -57,17 +57,21 @@ //! active_stack_size_to_collect)); //! region_idx++; //! -//! extern uint32_t __memfault_capture_start; -//! extern uint32_t __memfault_capture_end; -//! const size_t memfault_region_size = (uint32_t)&__memfault_capture_end - -//! (uint32_t)&__memfault_capture_start; +//! extern uint32_t __memfault_capture_bss_start; +//! extern uint32_t __memfault_capture_bss_end; +//! const size_t memfault_region_size = (uint32_t)&__memfault_capture_bss_end - +//! (uint32_t)&__memfault_capture_bss_start; //! //! s_coredump_regions[region_idx] = MEMFAULT_COREDUMP_MEMORY_REGION_INIT( -//! &__memfault_capture_start, memfault_region_size); +//! &__memfault_capture_bss_start, memfault_region_size); //! region_idx++; //! //! region_idx += memfault_freertos_get_task_regions(&s_coredump_regions[region_idx], //! MEMFAULT_ARRAY_SIZE(s_coredump_regions) - region_idx); +//! +//! *num_regions = region_idx; +//! return &s_coredump_regions[0]; +//! } #include "memfault/ports/freertos_coredump.h" diff --git a/tests/src/test_memfault_demo_cli.cpp b/tests/src/test_memfault_demo_cli.cpp index e1647ccc3..bf4acc741 100644 --- a/tests/src/test_memfault_demo_cli.cpp +++ b/tests/src/test_memfault_demo_cli.cpp @@ -3,16 +3,18 @@ #include "CppUTest/TestHarness.h" #include "CppUTestExt/MockSupport.h" -extern "C" { - #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" +#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 = {