#include "debugrep.h"

#include "swis.h"
#include "kernel.h"

#include <stdarg.h>
#include <stdio.h>
#include <string.h>

#define DEBUG_MAX_LINE_LENGTH 256

// Reporter's SWI number, kept once found (it may load after this module).
static int report_swi = 0;


uint32_t debug_now_cs(void)
{
        uint32_t t = 0;
        _swix(OS_ReadMonotonicTime, _OUT(0), &t);
        return t;
}


static int report_available(void)
{
        if (report_swi == 0 &&
            _swix(OS_SWINumberFromString, _IN(1) | _OUT(0), "Report_Text0", &report_swi) != NULL)
                report_swi = 0;

        return report_swi != 0;
}


int debug_printf(char *cntrl_string, ...)
{
        char            s[DEBUG_MAX_LINE_LENGTH];
        int             ret;
        va_list         ap;

        /* Reporter (a debug tool) provides Report_Text0;
           If it isn't loaded, the look-up fails and we silently do nothing. */
        if (!report_available())
                return 0;

        /* uptime in centiseconds: exact differences between lines */
        uint32_t now = debug_now_cs();
        int pre = sprintf(s, DEBUG_PREFIX "[%u.%02u] ", now / 100, now % 100);

        va_start(ap, cntrl_string);
        ret = vsnprintf(s+pre, DEBUG_MAX_LINE_LENGTH-pre, cntrl_string, ap);
        va_end(ap);
        s[DEBUG_MAX_LINE_LENGTH - 1] = '\0';

        /* Reporter has quit: look the SWI up afresh next time */
        if (_swix(report_swi, _IN(0), s) != NULL)
                report_swi = 0;

        return ret;
}


void debug_anchor(const char *why)
{
        char text[32] = { 0 };
        char *end;

        if (_swix(OS_Word, _INR(0,1), 14, text) != NULL)
                strcpy(text, "clock unreadable");
        text[sizeof(text) - 1] = '\0';
        end = strchr(text, 13);
        if (end != NULL)
                *end = '\0';

        debug_printf("clock: %s: %s\n", why, text);
}


void debug_hexdump(const char *what, const uint8_t *data, uint32_t len)
{
        char line[3 * DEBUG_HEX_PER_LINE + 1];

        debug_printf("%s: %u bytes\n", what, len);

        for (uint32_t off = 0; off < len; off += DEBUG_HEX_PER_LINE) {
                uint32_t n = len - off;
                int pos = 0;

                if (n > DEBUG_HEX_PER_LINE)
                        n = DEBUG_HEX_PER_LINE;
                for (uint32_t i = 0; i < n; i++)
                        pos += sprintf(line + pos, "%02x ", data[off + i]);
                line[pos - 1] = '\0';

                debug_printf("%s: %04x: %s\n", what, off, line);
        }
}
