224 lines
6.7 KiB
C
224 lines
6.7 KiB
C
/* my_debug.c
|
|
Copyright 2021 Carl John Kugler III
|
|
|
|
Licensed under the Apache License, Version 2.0 (the License); you may not use
|
|
this file except in compliance with the License. You may obtain a copy of the
|
|
License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
Unless required by applicable law or agreed to in writing, software distributed
|
|
under the License is distributed on an AS IS BASIS, WITHOUT WARRANTIES OR
|
|
CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
|
specific language governing permissions and limitations under the License.
|
|
*/
|
|
|
|
#include <stdarg.h>
|
|
#include <stddef.h>
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
//
|
|
#include "pico/stdlib.h"
|
|
#include "hardware/sync.h"
|
|
//
|
|
#include "crash.h"
|
|
//
|
|
#include "my_debug.h"
|
|
|
|
/* Function Attribute ((weak))
|
|
The weak attribute causes a declaration of an external symbol to be emitted as a weak symbol
|
|
rather than a global. This is primarily useful in defining library functions that can be
|
|
overridden in user code, though it can also be used with non-function declarations. The
|
|
overriding symbol must have the same type as the weak symbol.
|
|
https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html
|
|
|
|
You can override these functions in your application to redirect "stdout"-type messages.
|
|
*/
|
|
|
|
/* Single string output callbacks */
|
|
|
|
void __attribute__((weak)) put_out_error_message(const char *s) { (void)s; }
|
|
void __attribute__((weak)) put_out_info_message(const char *s) { (void)s; }
|
|
void __attribute__((weak)) put_out_debug_message(const char *s) { (void)s; }
|
|
|
|
/* "printf"-style output callbacks */
|
|
|
|
#if defined(USE_PRINTF) && USE_PRINTF
|
|
|
|
int __attribute__((weak))
|
|
error_message_printf(const char *func, int line,
|
|
const char *fmt, ...)
|
|
{
|
|
printf("%s:%d: ", func, line);
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
int cw = vprintf(fmt, args);
|
|
va_end(args);
|
|
stdio_flush();
|
|
return cw;
|
|
}
|
|
int __attribute__((weak)) error_message_printf_plain(const char *fmt, ...) {
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
int cw = vprintf(fmt, args);
|
|
va_end(args);
|
|
stdio_flush();
|
|
return cw;
|
|
}
|
|
int __attribute__((weak)) info_message_printf(const char *fmt, ...) {
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
int cw = vprintf(fmt, args);
|
|
va_end(args);
|
|
return cw;
|
|
}
|
|
int __attribute__((weak))
|
|
debug_message_printf(const char *func, int line,
|
|
const char *fmt, ...)
|
|
{
|
|
(void) func;
|
|
(void) line;
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
int cw = vprintf(fmt, args);
|
|
va_end(args);
|
|
stdio_flush();
|
|
return cw;
|
|
}
|
|
|
|
#else
|
|
|
|
/* These will truncate at 256 bytes. You can tell by checking the return code. */
|
|
|
|
int __attribute__((weak))
|
|
error_message_printf(const char *func, int line,
|
|
const char *fmt, ...)
|
|
{
|
|
(void) func;
|
|
(void) line;
|
|
char buf[256] = {0};
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
int cw = vsnprintf(buf, sizeof(buf), fmt, args);
|
|
put_out_error_message(buf);
|
|
va_end(args);
|
|
return cw;
|
|
}
|
|
int __attribute__((weak)) error_message_printf_plain(const char *fmt, ...) {
|
|
char buf[256] = {0};
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
int cw = vsnprintf(buf, sizeof(buf), fmt, args);
|
|
put_out_info_message(buf);
|
|
va_end(args);
|
|
return cw;
|
|
}
|
|
int __attribute__((weak)) info_message_printf(const char *fmt, ...) {
|
|
char buf[256] = {0};
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
int cw = vsnprintf(buf, sizeof(buf), fmt, args);
|
|
put_out_info_message(buf);
|
|
va_end(args);
|
|
return cw;
|
|
}
|
|
int __attribute__((weak))
|
|
debug_message_printf(const char *func, int line,
|
|
const char *fmt, ...)
|
|
{
|
|
(void) func;
|
|
(void) line;
|
|
char buf[256] = {0};
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
int cw = vsnprintf(buf, sizeof(buf), fmt, args);
|
|
put_out_debug_message(buf);
|
|
va_end(args);
|
|
return cw;
|
|
}
|
|
|
|
#endif
|
|
|
|
void __attribute__((weak)) my_assert_func(const char *file, int line, const char *func,
|
|
const char *pred) {
|
|
error_message_printf_plain("assertion \"%s\" failed: file \"%s\", line %d, function: %s\n",
|
|
pred, file, line, func);
|
|
(void)save_and_disable_interrupts(); /* Disable global interrupts. */
|
|
capture_assert(file, line, func, pred);
|
|
}
|
|
|
|
void assert_case_not_func(const char *file, int line, const char *func, int v) {
|
|
char pred[128];
|
|
snprintf(pred, sizeof pred, "case not %d", v);
|
|
my_assert_func(file, line, func, pred);
|
|
}
|
|
|
|
void assert_case_is(const char *file, int line, const char *func, int v, int expected) {
|
|
char pred[128];
|
|
snprintf(pred, sizeof pred, "%d is %d", v, expected);
|
|
my_assert_func(file, line, func, pred);
|
|
}
|
|
|
|
void dump8buf(char *buf, size_t buf_sz, uint8_t *pbytes, size_t nbytes) {
|
|
int n = 0;
|
|
for (size_t byte_ix = 0; byte_ix < nbytes; ++byte_ix) {
|
|
for (size_t col = 0; col < 32 && byte_ix < nbytes; ++col, ++byte_ix) {
|
|
n += snprintf(buf + n, buf_sz - n, "%02hhx ", pbytes[byte_ix]);
|
|
myASSERT(0 < n && n < (int)buf_sz);
|
|
}
|
|
n += snprintf(buf + n, buf_sz - n, "\n");
|
|
myASSERT(0 < n && n < (int)buf_sz);
|
|
}
|
|
}
|
|
void hexdump_8(const char *s, const uint8_t *pbytes, size_t nbytes) {
|
|
IMSG_PRINTF("\n%s(%s, 0x%p, %zu)\n", __FUNCTION__, s, pbytes, nbytes);
|
|
stdio_flush();
|
|
size_t col = 0;
|
|
for (size_t byte_ix = 0; byte_ix < nbytes; ++byte_ix) {
|
|
IMSG_PRINTF("%02hhx ", pbytes[byte_ix]);
|
|
if (++col > 31) {
|
|
IMSG_PRINTF("\n");
|
|
col = 0;
|
|
}
|
|
stdio_flush();
|
|
}
|
|
}
|
|
// nwords is size in WORDS!
|
|
void hexdump_32(const char *s, const uint32_t *pwords, size_t nwords) {
|
|
IMSG_PRINTF("\n%s(%s, 0x%p, %zu)\n", __FUNCTION__, s, pwords, nwords);
|
|
stdio_flush();
|
|
size_t col = 0;
|
|
for (size_t word_ix = 0; word_ix < nwords; ++word_ix) {
|
|
IMSG_PRINTF("%08lx ", pwords[word_ix]);
|
|
if (++col > 7) {
|
|
IMSG_PRINTF("\n");
|
|
col = 0;
|
|
}
|
|
stdio_flush();
|
|
}
|
|
}
|
|
// nwords is size in bytes
|
|
bool compare_buffers_8(const char *s0, const uint8_t *pbytes0, const char *s1,
|
|
const uint8_t *pbytes1, const size_t nbytes) {
|
|
/* Verify the data. */
|
|
if (0 != memcmp(pbytes0, pbytes1, nbytes)) {
|
|
hexdump_8(s0, pbytes0, nbytes);
|
|
hexdump_8(s1, pbytes1, nbytes);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
// nwords is size in WORDS!
|
|
bool compare_buffers_32(const char *s0, const uint32_t *pwords0, const char *s1,
|
|
const uint32_t *pwords1, const size_t nwords) {
|
|
/* Verify the data. */
|
|
if (0 != memcmp(pwords0, pwords1, nwords * sizeof(uint32_t))) {
|
|
hexdump_32(s0, pwords0, nwords);
|
|
hexdump_32(s1, pwords1, nwords);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
/* [] END OF FILE */
|