14#include "sw/device/lib/base/status.h"
20#include "spi_device_regs.h"
33 kUnsignedHexLow =
'x',
34 kUnsignedHexHigh =
'X',
52OT_NONSTRING static const char kDigitsLow[16] =
"0123456789abcdef";
53OT_NONSTRING static const char kDigitsHigh[16] =
"0123456789ABCDEF";
55OT_NONSTRING static const char kErrorNul[17] =
"%<unexpected nul>";
56OT_NONSTRING static const char kUnknownSpec[15] =
"%<unknown spec>";
57OT_NONSTRING static const char kErrorTooWide[12] =
"%<bad width>";
59static size_t base_dev_null(
void *data,
const char *buf,
size_t len) {
74 if (out.sink == NULL) {
75 out.sink = &base_dev_null;
80static const size_t kSpiDeviceReadBufferSizeBytes =
81 SPI_DEVICE_PARAM_SRAM_READ_BUFFER_DEPTH *
sizeof(uint32_t);
82static const size_t kSpiDeviceFrameHeaderSizeBytes = 12;
83static const size_t kSpiDeviceBufferPreservedSizeBytes =
84 kSpiDeviceFrameHeaderSizeBytes;
85static const size_t kSpiDeviceMaxFramePayloadSizeBytes =
86 kSpiDeviceReadBufferSizeBytes - kSpiDeviceFrameHeaderSizeBytes -
87 kSpiDeviceBufferPreservedSizeBytes - 4;
88static const uint32_t kSpiDeviceFrameMagicNumber = 0xa5a5beef;
89static uint32_t spi_device_frame_num = 0;
92 const uint8_t *buf,
size_t len,
98 size_t space_to_end_of_buffer = kSpiDeviceReadBufferSizeBytes - address;
99 size_t first_part_size =
100 space_to_end_of_buffer < len ? space_to_end_of_buffer : len;
102 TRY(dif_spi_device_write_flash_buffer(spi_device,
104 address, first_part_size, buf));
107 if (first_part_size < len) {
108 size_t second_part_size = len - first_part_size;
109 TRY(dif_spi_device_write_flash_buffer(
111 (uint8_t *)(buf + first_part_size)));
136static size_t spi_device_send_frame(
void *data,
const char *buf,
size_t len) {
138 const size_t data_packet_size_bytes = ((len + 3u) & ~3u);
139 const size_t frame_size_bytes =
140 kSpiDeviceFrameHeaderSizeBytes + data_packet_size_bytes;
141 uint8_t frame_header_bytes[kSpiDeviceFrameHeaderSizeBytes];
143 static uint32_t next_write_address = 0;
145 if (frame_size_bytes >= kSpiDeviceReadBufferSizeBytes) {
150 for (
size_t i = 0; i < 4; ++i) {
151 frame_header_bytes[i] = (kSpiDeviceFrameMagicNumber >> (i * 8)) & 0xff;
154 for (
size_t i = 0; i < 4; ++i) {
155 frame_header_bytes[i + 4] = (spi_device_frame_num >> (i * 8)) & 0xff;
158 for (
size_t i = 0; i < 4; ++i) {
159 frame_header_bytes[i + 8] = (len >> (i * 8)) & 0xff;
164 if (spi_console_gpio == NULL) {
165 uint32_t available_buffer_size = 0;
166 uint32_t last_read_address = 0;
168 if (dif_spi_device_get_last_read_address(spi_device,
169 &last_read_address) !=
kDifOk) {
193 uint32_t adjusted_last_read_address =
194 (kSpiDeviceReadBufferSizeBytes + last_read_address -
195 kSpiDeviceFrameHeaderSizeBytes) %
196 kSpiDeviceReadBufferSizeBytes;
200 uint32_t next_read_address = ((adjusted_last_read_address + 1) & ~3u) %
201 kSpiDeviceReadBufferSizeBytes;
204 if (next_read_address > next_write_address) {
205 available_buffer_size = next_read_address - next_write_address - 1;
207 available_buffer_size =
209 (kSpiDeviceReadBufferSizeBytes - next_write_address) - 1;
211 }
while ((frame_size_bytes + kSpiDeviceBufferPreservedSizeBytes) >
212 available_buffer_size);
216 size_t data_write_address =
217 (next_write_address + kSpiDeviceFrameHeaderSizeBytes) %
218 kSpiDeviceReadBufferSizeBytes;
219 size_t aligned_data_len = len & (~3u);
220 if (!status_ok(spi_device_send_data(spi_device, (uint8_t *)buf,
221 aligned_data_len, data_write_address))) {
226 if (len != aligned_data_len) {
227 uint8_t pad_bytes[4] = {0xff, 0xff, 0xff, 0xff};
228 size_t pad_write_address =
229 (data_write_address + aligned_data_len) % kSpiDeviceReadBufferSizeBytes;
231 for (
size_t i = 0; i + aligned_data_len < len; i++) {
232 pad_bytes[i] = buf[aligned_data_len + i];
234 if (!status_ok(spi_device_send_data(spi_device, pad_bytes, 4,
235 pad_write_address))) {
241 if (!status_ok(spi_device_send_data(spi_device, frame_header_bytes,
242 kSpiDeviceFrameHeaderSizeBytes,
243 next_write_address))) {
249 (next_write_address + frame_size_bytes) % kSpiDeviceReadBufferSizeBytes;
250 spi_device_frame_num++;
255 if (spi_console_gpio != NULL) {
257 dif_gpio_write(spi_console_gpio, spi_console_tx_ready_gpio,
true));
258 bool cs_state =
true;
259 bool target_cs_state =
false;
266 for (
size_t i = 0; i < 4; ++i) {
268 if (dif_spi_device_get_csb_status(spi_device, &cs_state) !=
kDifOk) {
271 }
while (cs_state != target_cs_state);
274 dif_gpio_write(spi_console_gpio, spi_console_tx_ready_gpio,
false));
276 target_cs_state = !target_cs_state;
278 next_write_address = 0;
284static size_t base_dev_spi_device(
void *data,
const char *buf,
size_t len) {
285 size_t write_data_len = 0;
287 while (write_data_len < len) {
288 size_t payload_len = len - write_data_len;
289 if (payload_len > kSpiDeviceMaxFramePayloadSizeBytes) {
290 payload_len = kSpiDeviceMaxFramePayloadSizeBytes;
292 if (spi_device_send_frame(data, buf + write_data_len, payload_len) ==
294 write_data_len += payload_len;
298 return write_data_len;
303static size_t base_dev_uart(
void *data,
const char *buf,
size_t len) {
305 for (
size_t i = 0; i < len; ++i) {
306 if (dif_uart_byte_send_polled(uart, (uint8_t)buf[i]) !=
kDifOk) {
317 spi_console_gpio = gpio;
318 spi_console_tx_ready_gpio = tx_indicator_pin;
323 spi_device_frame_num = 0;
325 .sink = &base_dev_spi_device});
330 (
buffer_sink_t){.data = (
void *)uart, .sink = &base_dev_uart});
333size_t base_printf(
const char *format, ...) {
335 va_start(args, format);
336 size_t bytes_left = base_vprintf(format, args);
341size_t base_vprintf(
const char *format, va_list args) {
342 return base_vfprintf(base_stdout, format, args);
350static size_t snprintf_sink(
void *data,
const char *buf,
size_t len) {
352 if (captures->bytes_left == 0) {
356 if (len > captures->bytes_left) {
357 len = captures->bytes_left;
359 memcpy(captures->buf, buf, len);
360 captures->buf += len;
361 captures->bytes_left -= len;
365size_t base_snprintf(
char *buf,
size_t len,
const char *format, ...) {
367 va_start(args, format);
375 .sink = &snprintf_sink,
377 size_t bytes_left = base_vfprintf(out, format, args);
384 va_start(args, format);
385 size_t bytes_left = base_vfprintf(out, format, args);
399static bool consume_until_percent(
buffer_sink_t out,
const char **format,
400 size_t *bytes_written) {
403 char c = (*format)[text_len];
404 if (c ==
'\0' || c == kPercent) {
406 *bytes_written += out.sink(out.data, *format, text_len);
434static bool consume_format_specifier(
buffer_sink_t out,
const char **format,
435 size_t *bytes_written,
436 format_specifier_t *spec) {
437 *spec = (format_specifier_t){0};
444 if ((*format)[0] ==
'!') {
445 spec->is_nonstd =
true;
457 char c = (*format)[spec_len];
459 *bytes_written += out.sink(out.data, kErrorNul,
sizeof(kErrorNul));
462 if (c <
'0' || c >
'9') {
465 if (spec->padding == 0) {
474 spec->width += (c -
'0');
478 if ((spec->width == 0 && spec->padding != 0) || spec->width > 32) {
479 *bytes_written += out.sink(out.data, kErrorTooWide,
sizeof(kErrorTooWide));
483 spec->type = (*format)[spec_len];
484 *format += spec_len + 1;
500static size_t write_digits(
buffer_sink_t out, uint32_t value, uint32_t width,
501 char padding, uint32_t base,
const char *glyphs) {
504 static const int kWordBits =
sizeof(uint32_t) * 8;
505 char buffer[kWordBits];
509 buffer[kWordBits - 1] = glyphs[0];
513 uint32_t digit = value % base;
515 buffer[kWordBits - 1 - len] = glyphs[digit];
518 width = width == 0 ? 1 : width;
519 width = width > kWordBits ? kWordBits : width;
520 while (len < width) {
521 buffer[kWordBits - len - 1] = padding;
524 return out.sink(out.data, buffer + (kWordBits - len), len);
527static size_t write_status(
buffer_sink_t out, status_t value,
bool as_json) {
529 char mod[] = {0, 0, 0};
532 bool err = status_extract(value, &start, &arg, mod);
535 const char *end = start;
540 len += out.sink(out.data,
"{\"", as_json ? 2 : 0);
541 len += out.sink(out.data, start, (
size_t)(end - start));
542 len += out.sink(out.data,
"\"", as_json ? 1 : 0);
544 len += out.sink(out.data,
":", 1);
547 len += out.sink(out.data,
"[\"", 2);
548 for (
size_t i = 0; i < 3; i++) {
549 if (mod[i] ==
'\\') {
550 len += out.sink(out.data,
"\\\\", 2);
552 len += out.sink(out.data, &mod[i], 1);
555 len += out.sink(out.data,
"\",", 2);
556 len += write_digits(out, (uint32_t)arg, 0, 0, 10, kDigitsLow);
557 len += out.sink(out.data,
"]", 1);
560 len += write_digits(out, (uint32_t)arg, 0, 0, 10, kDigitsLow);
562 len += out.sink(out.data,
"}", as_json ? 1 : 0);
580static size_t hex_dump(
buffer_sink_t out,
const char *bytes,
size_t len,
581 uint32_t width,
char padding,
bool big_endian,
582 const char *glyphs) {
583 size_t bytes_written = 0;
588 memset(buf, padding,
sizeof(buf));
590 size_t to_write = width >
ARRAYSIZE(buf) ? 32 : width;
591 bytes_written += out.sink(out.data, buf, to_write);
596 for (
size_t i = 0; i < len; ++i) {
597 size_t idx = big_endian ? len - i - 1 : i;
598 buf[buffered] = glyphs[(bytes[idx] >> 4) & 0xf];
599 buf[buffered + 1] = glyphs[bytes[idx] & 0xf];
603 bytes_written += out.sink(out.data, buf, buffered);
609 bytes_written += out.sink(out.data, buf, buffered);
611 return bytes_written;
625static void process_specifier(
buffer_sink_t out, format_specifier_t spec,
626 size_t *bytes_written, va_list *args) {
632 if (spec.is_nonstd) {
635 *bytes_written += out.sink(out.data,
"%", 1);
639 if (spec.is_nonstd) {
642 char value = (char)va_arg(*args, uint32_t);
643 *bytes_written += out.sink(out.data, &value, 1);
647 uint32_t value = va_arg(*args, uint32_t);
648 for (
size_t i = 0; i <
sizeof(uint32_t); ++i, value >>= 8) {
649 uint8_t ch = (uint8_t)value;
650 if (ch >= 32 && ch < 127) {
651 *bytes_written += out.sink(out.data, (
const char *)&ch, 1);
653 *bytes_written += out.sink(out.data,
"\\x", 2);
654 *bytes_written += out.sink(out.data, &kDigitsLow[ch >> 4], 1);
655 *bytes_written += out.sink(out.data, &kDigitsLow[ch & 15], 1);
662 if (spec.is_nonstd) {
664 len = va_arg(*args,
size_t);
667 char *value = va_arg(*args,
char *);
668 while (!spec.is_nonstd && value[len] !=
'\0') {
673 *bytes_written += out.sink(out.data, value, len);
678 if (spec.is_nonstd) {
681 uint32_t value = va_arg(*args, uint32_t);
682 if (((int32_t)value) < 0) {
683 *bytes_written += out.sink(out.data,
"-", 1);
687 write_digits(out, value, spec.width, spec.padding, 10, kDigitsLow);
691 if (spec.is_nonstd) {
694 uint32_t value = va_arg(*args, uint32_t);
696 write_digits(out, value, spec.width, spec.padding, 8, kDigitsLow);
700 if (spec.is_nonstd) {
709 *bytes_written += out.sink(out.data,
"0x", 2);
710 uintptr_t value = va_arg(*args, uintptr_t);
712 write_digits(out, value,
sizeof(uintptr_t) * 2,
'0', 16, kDigitsLow);
715 case kUnsignedHexLow:
716 if (spec.is_nonstd) {
717 size_t len = va_arg(*args,
size_t);
718 char *value = va_arg(*args,
char *);
719 *bytes_written += hex_dump(out, value, len, spec.width, spec.padding,
725 uint32_t value = va_arg(*args, uint32_t);
727 write_digits(out, value, spec.width, spec.padding, 16, kDigitsLow);
730 case kUnsignedHexHigh:
731 if (spec.is_nonstd) {
732 size_t len = va_arg(*args,
size_t);
733 char *value = va_arg(*args,
char *);
734 *bytes_written += hex_dump(out, value, len, spec.width, spec.padding,
740 uint32_t value = va_arg(*args, uint32_t);
742 write_digits(out, value, spec.width, spec.padding, 16, kDigitsHigh);
746 if (!spec.is_nonstd) {
749 size_t len = va_arg(*args,
size_t);
750 char *value = va_arg(*args,
char *);
751 *bytes_written += hex_dump(out, value, len, spec.width, spec.padding,
756 if (!spec.is_nonstd) {
759 size_t len = va_arg(*args,
size_t);
760 char *value = va_arg(*args,
char *);
761 *bytes_written += hex_dump(out, value, len, spec.width, spec.padding,
766 if (spec.is_nonstd) {
769 uint32_t value = va_arg(*args, uint32_t);
771 write_digits(out, value, spec.width, spec.padding, 10, kDigitsLow);
775 if (spec.is_nonstd) {
778 if (va_arg(*args,
int) != 0) {
779 *bytes_written += out.sink(out.data,
"true", 4);
781 *bytes_written += out.sink(out.data,
"false", 5);
785 uint32_t value = va_arg(*args, uint32_t);
787 write_digits(out, value, spec.width, spec.padding, 2, kDigitsLow);
790 case kStatusResult: {
791 status_t value = va_arg(*args, status_t);
792 *bytes_written += write_status(out, value, spec.is_nonstd);
797 *bytes_written += out.sink(out.data, kUnknownSpec,
sizeof(kUnknownSpec));
803 if (out.sink == NULL) {
804 out.sink = &base_dev_null;
812 va_copy(args_copy, args);
814 size_t bytes_written = 0;
815 while (format[0] !=
'\0') {
816 if (!consume_until_percent(out, &format, &bytes_written)) {
819 format_specifier_t spec;
820 if (!consume_format_specifier(out, &format, &bytes_written, &spec)) {
824 process_specifier(out, spec, &bytes_written, &args_copy);
828 return bytes_written;
834 "................................"
836 " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
838 "................................................................"
839 "................................................................"
846 .alphabet = &kBaseHexdumpDefaultFmtAlphabet,
849size_t base_hexdump(
const char *buf,
size_t len) {
850 return base_hexdump_with(kBaseHexdumpDefaultFmt, buf, len);
853size_t base_snhexdump(
char *out,
size_t out_len,
const char *buf,
size_t len) {
854 return base_snhexdump_with(out, out_len, kBaseHexdumpDefaultFmt, buf, len);
858 return base_fhexdump_with(out, kBaseHexdumpDefaultFmt, buf, len);
862 return base_fhexdump_with(base_stdout, fmt, buf, len);
866 const char *buf,
size_t len) {
869 .bytes_left = out_len,
873 .sink = &snprintf_sink,
875 return base_fhexdump_with(sink, fmt, buf, len);
879 const char *buf,
size_t len) {
880 if (out.sink == NULL) {
881 out.sink = &base_dev_null;
884 size_t bytes_written = 0;
887 for (
size_t line = 0; line < len; line += bytes_per_line) {
888 bytes_written += base_fprintf(out,
"%08x:", line);
891 size_t line_bytes_written = 0;
892 for (
size_t word = 0; word < bytes_per_line; word += fmt.
bytes_per_word) {
893 if (len < line + word) {
895 while (line_bytes_written < chars_per_line) {
896 size_t to_print = chars_per_line - line_bytes_written;
897 if (to_print >
sizeof(spaces)) {
898 to_print =
sizeof(spaces);
900 line_bytes_written += base_fprintf(out,
"%!s", to_print, spaces);
905 size_t bytes_left = len - line - word;
909 line_bytes_written += base_fprintf(out,
" ");
910 line_bytes_written +=
911 hex_dump(out, buf + line + word, bytes_left, bytes_left,
'0',
914 bytes_written += line_bytes_written;
916 bytes_written += base_fprintf(out,
" ");
918 char glyph_buffer[16];
919 for (
size_t byte = 0;
byte < bytes_per_line; ++byte) {
920 if (buffered ==
sizeof(glyph_buffer)) {
921 bytes_written += base_fprintf(out,
"%!s", buffered, glyph_buffer);
924 if (line +
byte >= len) {
927 glyph_buffer[buffered++] =
928 (*fmt.
alphabet)[(
size_t)(uint8_t)buf[line +
byte]];
931 bytes_written += base_fprintf(out,
"%!s", buffered, glyph_buffer);
933 bytes_written += base_fprintf(out,
"\n");
936 return bytes_written;