this is using the mbed os version 5-13-1

Dependencies:   mbed-http

Revision:
92:ec9550034276
Child:
103:7b566b522427
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/mbed_memory_status.cpp	Sat Apr 13 14:17:29 2019 +0000
@@ -0,0 +1,488 @@
+/*
+    mbed Memory Status Helper
+    Copyright (c) 2017 Max Vilimpoc
+
+    Permission is hereby granted, free of charge, to any person obtaining a copy
+    of this software and associated documentation files (the "Software"), to deal
+    in the Software without restriction, including without limitation the rights
+    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+    copies of the Software, and to permit persons to whom the Software is
+    furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice shall be included in
+    all copies or substantial portions of the Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+    THE SOFTWARE.
+*/
+
+/**
+ * Purpose: Print out thread info and other useful details using
+ *          only raw serial access.
+ *
+ * Based on mbed_board.c's error printing functionality, minus
+ * pulling in all the printf() code.
+ */
+
+// Not great having to pull in all of mbed.h just to get the MBED_VERSION macro,
+// but it's the only way to do it for both pre- and post-5.4 releases
+//
+// If you're only supporting something newer than 5.4, you could use this alone:
+// #include "platform/mbed_version.h"
+//
+// platform/mbed_version.h says:
+// 999999 is default value for development version (master branch)
+
+#include "mbed.h"
+
+// Critical sections header file renamed in mbed OS 5.4 release
+// See: https://github.com/ARMmbed/mbed-os/commit/aff49d8d1e3b5d4dc18286b0510336c36ae9603c
+
+#ifndef MBED_VERSION
+#warning "You're probably using an unsupported version of mbed older than 5.2."
+#endif
+
+#if   MBED_VERSION >= 50400
+#include "platform/mbed_critical.h"
+#elif MBED_VERSION >= 50200
+#include "platform/critical.h"
+#endif
+
+#include "platform/mbed_stats.h"
+
+#if !MBED_STACK_STATS_ENABLED
+#warning MBED_STACK_STATS_ENABLED != 1, so there will be no stack usage measurements.
+#endif
+
+#ifndef DEBUG_ISR_STACK_USAGE
+#define DEBUG_ISR_STACK_USAGE  0
+#endif
+
+#ifndef DEBUG_MEMORY_CONTENTS
+#define DEBUG_MEMORY_CONTENTS  0
+#endif
+
+#define OUTPUT_SERIAL          1
+#define OUTPUT_RTT             0
+#define OUTPUT_SWO             0
+
+#if DEBUG_ISR_STACK_USAGE
+#include "compiler_abstraction.h"
+
+// Value is sprayed into all of the ISR stack at boot time.
+static const uint32_t ISR_STACK_CANARY = 0xAFFEC7ED; // AFFECTED
+
+// Refers to linker script defined symbol, may not be available
+// on all platforms.
+extern uint32_t __StackLimit;
+extern uint32_t __StackTop;
+
+void fill_isr_stack_with_canary(void)
+{
+    uint32_t * bottom = &__StackLimit;
+    uint32_t * top    = (uint32_t *) GET_SP();
+
+    for (; bottom < top; bottom++)
+    {
+        *bottom = ISR_STACK_CANARY;
+    }
+}
+#endif // DEBUG_ISR_STACK_USAGE
+
+#if OUTPUT_SERIAL && DEVICE_SERIAL
+#include "hal/serial_api.h"
+
+extern int      stdio_uart_inited;
+extern serial_t stdio_uart;
+
+static void output_serial_init(void)
+{
+    if (!stdio_uart_inited)
+    {
+        serial_init(&stdio_uart, STDIO_UART_TX, STDIO_UART_RX);
+        serial_baud(&stdio_uart, 115200); // This is hard coded.
+    }
+}
+
+static void output_serial_print_label(const char * label)
+{
+#if MBED_VERSION < 50902
+    // After mbed OS 5.9.2, this locks up the system.
+    core_util_critical_section_enter();
+#endif
+
+    output_serial_init();
+
+    while (*label) serial_putc(&stdio_uart, *label++);
+
+#if MBED_VERSION < 50902
+    core_util_critical_section_exit();
+#endif
+}
+#endif // OUTPUT_SERIAL && DEVICE_SERIAL
+
+#if OUTPUT_RTT
+#include "RTT/SEGGER_RTT.h"
+
+enum
+{
+    DEFAULT_RTT_UP_BUFFER = 0
+};
+
+static void output_rtt_init(void)
+{
+    static int initialized = 0;
+
+    if (!initialized)
+    {
+        SEGGER_RTT_ConfigUpBuffer(DEFAULT_RTT_UP_BUFFER, NULL, NULL, 0, SEGGER_RTT_MODE_NO_BLOCK_TRIM);
+
+        initialized = 1;
+    }
+}
+
+static void output_rtt_print_label(const char * label)
+{
+    output_rtt_init();
+    SEGGER_RTT_WriteString(DEFAULT_RTT_UP_BUFFER, label);
+}
+#endif // OUTPUT_RTT
+
+#if OUTPUT_SWO
+#if defined (NRF52) && !defined (ENABLE_SWO)
+  #error "You need to enable SWO using `-D ENABLE_SWO` on the mbed compile command line."
+#endif
+
+#ifdef NRF52
+#include "nrf.h"
+#endif
+
+static void output_swo_init(void)
+{
+    static int initialized = 0;
+
+    if (!initialized)
+    {
+        NRF_CLOCK->TRACECONFIG = (NRF_CLOCK->TRACECONFIG & ~CLOCK_TRACECONFIG_TRACEPORTSPEED_Msk) |
+            (CLOCK_TRACECONFIG_TRACEPORTSPEED_4MHz << CLOCK_TRACECONFIG_TRACEPORTSPEED_Pos);
+
+        ITM->TCR |= 1;
+        ITM->TER |= 1;
+
+        initialized = 1;
+    }
+}
+
+static void output_swo_print_label(const char * label)
+{
+    output_swo_init();
+    while (*label) ITM_SendChar(*label++);
+}
+#endif // OUTPUT_SWO
+
+static void nway_print_label(const char * label)
+{
+#if OUTPUT_SERIAL
+    output_serial_print_label(label);
+#endif
+
+#if OUTPUT_RTT
+    output_rtt_print_label(label);
+#endif
+
+#if OUTPUT_SWO
+    output_swo_print_label(label);
+#endif
+}
+
+static const char HEX[] = "0123456789ABCDEF";
+
+static void debug_print_u32(uint32_t u32)
+{
+    char output[9] = {0};
+
+    // Always printed as big endian.
+    output[0] = HEX[(((uint32_t) u32 & 0xf0000000) >> 28)];
+    output[1] = HEX[(((uint32_t) u32 & 0x0f000000) >> 24)];
+    output[2] = HEX[(((uint32_t) u32 & 0x00f00000) >> 20)];
+    output[3] = HEX[(((uint32_t) u32 & 0x000f0000) >> 16)];
+    output[4] = HEX[(((uint32_t) u32 & 0x0000f000) >> 12)];
+    output[5] = HEX[(((uint32_t) u32 & 0x00000f00) >>  8)];
+    output[6] = HEX[(((uint32_t) u32 & 0x000000f0) >>  4)];
+    output[7] = HEX[(((uint32_t) u32 & 0x0000000f) >>  0)];
+
+    nway_print_label(output);
+}
+
+static void debug_print_pointer(const void * pointer)
+{
+    debug_print_u32((uint32_t) pointer);
+}
+
+#define DPL(X) nway_print_label((X))
+
+#if (defined (MBED_CONF_RTOS_PRESENT) && (MBED_CONF_RTOS_PRESENT != 0))
+#include "cmsis_os.h"
+
+// cmsis_os.h provides some useful defines:
+//
+// For mbed OS 5.4 and lower,  osCMSIS == 0x10002U (see: rtos/rtx/TARGET_CORTEX_M)
+// For mbed OS 5.5 and higher, osCMSIS == 0x20001U (see: rtos/TARGET_CORTEX/rtx{4|5})
+//
+// Starting in mbed OS 5.5, a new RTOS layer was introduced with a different API.
+
+#if (osCMSIS < 0x20000U)
+    // Temporarily #undef NULL or the compiler complains about previous def.
+    #undef NULL
+    #include "rt_TypeDef.h"
+#else
+    #include "rtx_lib.h"
+    // #include <stdlib.h>  // Include if you need malloc() / free() below. (probably better for non-C99 compilers)
+#endif
+
+#if (osCMSIS < 0x20000U)
+
+// No public forward declaration for this.
+extern "C" P_TCB rt_tid2ptcb (osThreadId thread_id);
+
+static void print_thread_info(osThreadId threadId)
+{
+    if (!threadId) return;
+
+    osEvent event;
+
+    P_TCB tcb = rt_tid2ptcb(threadId);
+
+    DPL("    stack ( start: ");
+    debug_print_pointer(tcb->stack);
+
+    event = _osThreadGetInfo(threadId, osThreadInfoStackSize);
+
+    DPL(" end: ");
+    debug_print_pointer(((uint8_t *) tcb->stack + event.value.v)); // (tcb->priv_stack)));
+
+    DPL(" size: ");
+    debug_print_u32(event.value.v);
+
+    event = _osThreadGetInfo(threadId, osThreadInfoStackMax);
+    DPL(" used: ");
+    debug_print_u32(event.value.v);
+
+
+    DPL(" ) ");
+
+    DPL("thread ( id: ");
+    debug_print_pointer(threadId);
+
+    event = _osThreadGetInfo(threadId, osThreadInfoEntry);
+    DPL(" entry: ");
+    debug_print_pointer(event.value.p);
+
+    DPL(" )\r\n");
+}
+
+void print_all_thread_info(void)
+{
+    osThreadEnumId enumId   = _osThreadsEnumStart();
+    osThreadId     threadId = (osThreadId) NULL; // Can't use nullptr yet because mbed doesn't support C++11.
+
+    while ((threadId = _osThreadEnumNext(enumId)))
+    {
+        print_thread_info(threadId);
+    }
+
+    _osThreadEnumFree(enumId);
+}
+
+#else
+
+static void print_thread_info(osThreadId threadId)
+{
+    // Refs: rtx_lib.h - #define os_thread_t osRtxThread_t
+    //       rtx_os.h  - typedef struct osRtxThread_s { } osRtxThread_t
+
+    if (!threadId) return;
+
+    os_thread_t * tcb = (os_thread_t *) threadId;
+
+    uint32_t stackSize = osThreadGetStackSize(threadId);
+    uint32_t stackUsed = osThreadGetStackSpace(threadId);
+
+    DPL("    stack ( start: ");
+    debug_print_pointer(tcb->stack_mem);
+
+    DPL(" end: ");
+    debug_print_pointer((uint8_t *) tcb->stack_mem + stackSize);
+
+    DPL(" size: ");
+    debug_print_u32(stackSize);
+
+    DPL(" used: ");
+    debug_print_u32(stackSize - stackUsed);
+
+    DPL(" ) ");
+
+    DPL("thread ( id: ");
+    debug_print_pointer(threadId);
+
+    DPL(" entry: ");
+    debug_print_u32(tcb->thread_addr);
+
+    DPL(" name: ");
+    DPL(osThreadGetName(threadId) ? osThreadGetName(threadId) : "unknown");
+
+    DPL(" )\r\n");
+}
+
+void print_all_thread_info(void)
+{
+    // Refs: mbed_stats.c - mbed_stats_stack_get_each()
+
+    uint32_t     threadCount = osThreadGetCount();
+    osThreadId_t threads[threadCount]; // g++ will throw a -Wvla on this, but it is likely ok.
+
+    // osThreadId_t * threads = malloc(sizeof(osThreadId_t) * threadCount);
+    // MBED_ASSERT(NULL != threads);
+
+    memset(threads, 0, threadCount * sizeof(osThreadId_t));
+
+    // This will probably only work if the number of threads remains constant
+    // (i.e. the number of thread control blocks remains constant)
+    //
+    // This is probably the case on a deterministic realtime embedded system
+    // with limited SRAM.
+
+    osKernelLock();
+
+    threadCount = osThreadEnumerate(threads, threadCount);
+
+    for (uint32_t i = 0; i < threadCount; i++)
+    {
+        // There seems to be a Heisenbug when calling print_thread_info()
+        // inside of osKernelLock()!
+
+        // This error may appear on the serial console:
+        // mbed assertation failed: os_timer->get_tick() == svcRtxKernelGetTickCount(), file: .\mbed-os\rtos\TARGET_CORTEX\mbed_rtx_idle.c
+
+        // The RTOS seems to be asserting an idle constraint violation due
+        // to the slowness of sending data through the serial port, but it
+        // does not happen consistently.
+        print_thread_info(threads[i]);
+    }
+
+    osKernelUnlock();
+
+    // free(threads);
+}
+
+#endif
+
+void print_current_thread_id(void)
+{
+    DPL("Current thread: ");
+    debug_print_pointer(osThreadGetId());
+    DPL("\r\n");
+}
+#endif // MBED_CONF_RTOS_PRESENT
+
+#if DEBUG_MEMORY_CONTENTS
+static void print_memory_contents(const uint32_t * start, const uint32_t * end)
+{
+    uint8_t line = 0;
+
+    for (; start < end; start++)
+    {
+        if (0 == line)
+        {
+            debug_print_pointer(start);
+            DPL(": ");
+        }
+
+        debug_print_u32(*start);
+
+        line++;
+
+        if (16 == line)
+        {
+            DPL("\r\n");
+            line = 0;
+        }
+    }
+}
+#endif
+
+extern uint32_t mbed_stack_isr_size;
+
+#if DEBUG_ISR_STACK_USAGE
+uint32_t calculate_isr_stack_usage(void)
+{
+    for (const uint32_t * stack = &__StackLimit; stack < &__StackTop; stack++)
+    {
+        if (*stack != ISR_STACK_CANARY)
+        {
+            return (uint32_t) &__StackTop - (uint32_t) stack;
+        }
+    }
+
+    return mbed_stack_isr_size;
+}
+#endif
+
+void print_heap_and_isr_stack_info(void)
+{
+    extern unsigned char * mbed_heap_start;
+    extern uint32_t        mbed_heap_size;
+
+    extern unsigned char * mbed_stack_isr_start;
+
+    mbed_stats_heap_t      heap_stats;
+
+    mbed_stats_heap_get(&heap_stats);
+
+    DPL("     heap ( start: ");
+    debug_print_pointer(mbed_heap_start);
+
+    DPL(" end: ");
+    debug_print_pointer(mbed_heap_start + mbed_heap_size);
+
+    DPL(" size: ");
+    debug_print_u32(mbed_heap_size);
+
+    DPL(" used: ");
+    debug_print_u32(heap_stats.max_size);
+
+    DPL(" )  alloc ( ok: ");
+    debug_print_u32(heap_stats.alloc_cnt);
+
+    DPL("  fail: ");
+    debug_print_u32(heap_stats.alloc_fail_cnt);
+
+    DPL(" )\r\n");
+
+    DPL("isr_stack ( start: ");
+    debug_print_pointer(mbed_stack_isr_start);
+
+    DPL(" end: ");
+    debug_print_pointer(mbed_stack_isr_start + mbed_stack_isr_size);
+
+    DPL(" size: ");
+    debug_print_u32(mbed_stack_isr_size);
+
+#if DEBUG_ISR_STACK_USAGE
+    DPL(" used: ");
+    debug_print_u32(calculate_isr_stack_usage());
+#endif
+
+    DPL(" )\r\n");
+
+#if DEBUG_MEMORY_CONTENTS
+    // Print ISR stack contents.
+    print_memory_contents(&__StackLimit, &__StackTop);
+#endif
+}
+