| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293 | // Copyright (c) 2022 Rabbit Hole Computing™// Copyright (c) 2023 Eric Helgeson#include "BlueSCSI_log.h"#include "BlueSCSI_config.h"#include "BlueSCSI_platform.h"const char *g_log_firmwareversion = BLUESCSI_FW_VERSION " " __DATE__ " " __TIME__;bool g_log_debug = false;uint8_t g_scsi_log_mask = 0;bool g_test_mode = false;// This memory buffer can be read by debugger and is also saved to log.txt#define LOGBUFMASK (LOGBUFSIZE - 1)// The log buffer is in special uninitialized RAM section so that it is not reset// when soft rebooting or jumping from bootloader.uint32_t g_log_magic;char g_logbuffer[LOGBUFSIZE + 1];uint32_t g_logpos;void log_raw(const char *str){    // Keep log from reboot / bootloader if magic matches expected value    if (g_log_magic != 0xAA55AA55)    {        g_log_magic = 0xAA55AA55;        g_logpos = 0;    }    const char *p = str;    while (*p)    {        g_logbuffer[g_logpos & LOGBUFMASK] = *p++;        g_logpos++;    }    // Keep buffer null-terminated    g_logbuffer[g_logpos & LOGBUFMASK] = '\0';    platform_log(str);}// Log byte as hexvoid log_raw(uint8_t value){    const char *nibble = "0123456789ABCDEF";    char hexbuf[5] = {        '0', 'x',        nibble[(value >>  4) & 0xF], nibble[(value >>  0) & 0xF],        0    };    log_raw(hexbuf);}// Log integer as hexvoid log_raw(uint32_t value){    const char *nibble = "0123456789ABCDEF";    char hexbuf[11] = {        '0', 'x',        nibble[(value >> 28) & 0xF], nibble[(value >> 24) & 0xF],        nibble[(value >> 20) & 0xF], nibble[(value >> 16) & 0xF],        nibble[(value >> 12) & 0xF], nibble[(value >>  8) & 0xF],        nibble[(value >>  4) & 0xF], nibble[(value >>  0) & 0xF],        0    };    log_raw(hexbuf);}// Log integer as hexvoid log_raw(uint64_t value){    const char *nibble = "0123456789ABCDEF";    char hexbuf[19] = {        '0', 'x',        nibble[(value >> 60) & 0xF], nibble[(value >> 56) & 0xF],        nibble[(value >> 52) & 0xF], nibble[(value >> 48) & 0xF],        nibble[(value >> 44) & 0xF], nibble[(value >> 40) & 0xF],        nibble[(value >> 36) & 0xF], nibble[(value >> 32) & 0xF],        nibble[(value >> 28) & 0xF], nibble[(value >> 24) & 0xF],        nibble[(value >> 20) & 0xF], nibble[(value >> 16) & 0xF],        nibble[(value >> 12) & 0xF], nibble[(value >>  8) & 0xF],        nibble[(value >>  4) & 0xF], nibble[(value >>  0) & 0xF],        0    };    log_raw(hexbuf);}// Log integer as decimalvoid log_raw(int value){    char decbuf[16] = {0};    char *p = &decbuf[14];    int remainder = (value < 0) ? -value : value;    do    {        *--p = '0' + (remainder % 10);        remainder /= 10;    } while (remainder > 0);    if (value < 0)    {        *--p = '-';    }    log_raw(p);}void log_raw(bytearray array){    for (size_t i = 0; i < array.len; i++)    {        log_raw(array.data[i]);        log_raw(" ");        if (i > 32)        {            log_raw("... (total ", (int)array.len, ")");            break;        }    }}void log_raw(double value){    char buffer[6];    snprintf(buffer, sizeof buffer, "%0.3f", value);    log_raw(buffer);}void log_raw(bool value){    if(value) log_raw("true");    else log_raw("false");}void log_f(const char *format, ...){    static char out[2048];    va_list ap;    va_start(ap, format);    vsnprintf(out, sizeof(out), format, ap);    va_end(ap);    log(out);}void log_buf(const unsigned char *buf, unsigned long size){    static char tmp[1500 * 3];    static char hex[] = "0123456789abcdef";    int o = 0;    for (int j = 0; j < size; j++) {        if (o + 3 >= sizeof(tmp))            break;        if (j != 0)            tmp[o++] = ' ';        tmp[o++] = hex[(buf[j] >> 4) & 0xf];        tmp[o++] = hex[buf[j] & 0xf];        tmp[o] = 0;    }    log_f("%s", tmp);}uint32_t log_get_buffer_len(){    return g_logpos;}const char *log_get_buffer(uint32_t *startpos, uint32_t *available){    uint32_t default_pos = 0;    if (startpos == NULL)    {        startpos = &default_pos;    }    // Check oldest data available in buffer    uint32_t lag = (g_logpos - *startpos);    if (lag >= LOGBUFSIZE)    {        // If we lose data, skip 512 bytes forward to give us time to transmit        // pending data before new log messages arrive. Also skip to next line        // break to keep formatting consistent.        uint32_t oldest = g_logpos - LOGBUFSIZE + 512;        while (oldest < g_logpos)        {            char c = g_logbuffer[oldest & LOGBUFMASK];            if (c == '\r' || c == '\n') break;            oldest++;        }        if (oldest > g_logpos)        {            oldest = g_logpos;        }        *startpos = oldest;    }    const char *result = &g_logbuffer[*startpos & LOGBUFMASK];    // Calculate number of bytes available    uint32_t len;    if ((g_logpos & LOGBUFMASK) >= (*startpos & LOGBUFMASK))    {        // Can read directly to g_logpos        len = g_logpos - *startpos;    }    else    {        // Buffer wraps, read to end of buffer now and start from beginning on next call.        len = LOGBUFSIZE - (*startpos & LOGBUFMASK);    }    if (available) { *available = len; }    *startpos += len;    return result;}// TODO write directly global log buffer to save some memorystatic char shared_log_buf[1500 * 3];// core method for variadic printf like loggingstatic void log_va(bool debug, const char *format, va_list ap){    vsnprintf(shared_log_buf, sizeof(shared_log_buf), format, ap);    if (debug)    {        debuglog(shared_log_buf);    }    else    {        log(shared_log_buf);    }}void logmsg_f(const char *format, ...){    va_list ap;    va_start(ap, format);    log_va(false, format, ap);    va_end(ap);}void dbgmsg_f(const char *format, ...){    if (!g_log_debug)        return;    va_list ap;    va_start(ap, format);    log_va(true, format, ap);    va_end(ap);}// core method for logging a data buffer into a hex stringvoid log_hex_buf(const unsigned char *buf, unsigned long size, bool debug){    static char hex[] = "0123456789abcdef";    int o = 0;    for (int j = 0; j < size; j++) {        if (o + 3 >= sizeof(shared_log_buf))            break;        if (j != 0)            shared_log_buf[o++] = ' ';        shared_log_buf[o++] = hex[(buf[j] >> 4) & 0xf];        shared_log_buf[o++] = hex[buf[j] & 0xf];        shared_log_buf[o] = 0;    }    if (debug)        debuglog(shared_log_buf);    else        log(shared_log_buf);}void logmsg_buf(const unsigned char *buf, unsigned long size){    log_hex_buf(buf, size, false);}void dbgmsg_buf(const unsigned char *buf, unsigned long size){    if (!g_log_debug)        return;    log_hex_buf(buf, size, true);}
 |