| /* |
| * Copyright (c) 2019-2020, Arm Limited. All rights reserved. |
| * |
| * SPDX-License-Identifier: BSD-3-Clause |
| * |
| */ |
| |
| #include <stdarg.h> |
| #include <stddef.h> |
| #include <stdint.h> |
| #include "uart_stdout.h" |
| |
| #define PRINT_BUFF_SIZE 32 |
| #define NUM_BUFF_SIZE 12 |
| |
| struct formatted_buffer_t { |
| size_t pos; |
| uint8_t buf[PRINT_BUFF_SIZE]; |
| }; |
| |
| const char hex_digits_lo[] = {'0', '1', '2', '3', '4', '5', '6', '7', |
| '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; |
| const char hex_digits_up[] = {'0', '1', '2', '3', '4', '5', '6', '7', |
| '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; |
| |
| static void _tfm_flush_formatted_buffer(struct formatted_buffer_t *pb, |
| uint8_t data) |
| { |
| pb->buf[pb->pos++] = data; |
| if (pb->pos >= PRINT_BUFF_SIZE) { |
| pb->pos = 0; |
| /* uart flush and print here. */ |
| stdio_output_string(pb->buf, PRINT_BUFF_SIZE); |
| } |
| } |
| |
| static int _tfm_string_output(struct formatted_buffer_t *pb, |
| const char *str) |
| { |
| int count = 0; |
| |
| while (*str) { |
| _tfm_flush_formatted_buffer(pb, *str++); |
| count++; |
| } |
| |
| return count; |
| } |
| |
| static int _tfm_dec_num_output(struct formatted_buffer_t *pb, |
| int32_t num, uint8_t sign) |
| { |
| int count = 0; |
| uint8_t num_buff[NUM_BUFF_SIZE] = {0}; |
| uint32_t number = (uint32_t)num; |
| uint32_t k = 0; |
| |
| if (sign == 'd' && num < 0) { |
| _tfm_flush_formatted_buffer(pb, '-'); |
| count++; |
| number = -num; |
| } |
| |
| do { |
| num_buff[k++] = '0' + number % 10; |
| number /= 10; |
| } while (number); |
| |
| while (k) { |
| _tfm_flush_formatted_buffer(pb, num_buff[--k]); |
| count++; |
| } |
| |
| return count; |
| } |
| |
| static int _tfm_hex_num_output(struct formatted_buffer_t *pb, uint32_t num, |
| const char *hex_digits) |
| { |
| int count = 0; |
| uint8_t num_buff[NUM_BUFF_SIZE] = {0}; |
| uint32_t k = 0; |
| |
| do { |
| num_buff[k++] = hex_digits[num & 0x0f]; |
| num >>= 4; |
| } while (num); |
| |
| while (k) { |
| _tfm_flush_formatted_buffer(pb, num_buff[--k]); |
| count++; |
| } |
| |
| return count; |
| } |
| |
| static int _tfm_log_vprintf(const char *fmt, va_list ap) |
| { |
| int count = 0; |
| struct formatted_buffer_t outputbuf; |
| |
| outputbuf.pos = 0; |
| |
| while (*fmt) { |
| if (*fmt == '%') { |
| switch (*(++fmt)) { |
| case 'd': |
| case 'i': |
| count += _tfm_dec_num_output(&outputbuf, |
| va_arg(ap, int32_t), 'd'); |
| break; |
| case 'u': |
| count += _tfm_dec_num_output(&outputbuf, |
| va_arg(ap, int32_t), 'u'); |
| break; |
| case 'x': |
| count += _tfm_hex_num_output(&outputbuf, va_arg(ap, uint32_t), |
| hex_digits_lo); |
| break; |
| case 'X': |
| count += _tfm_hex_num_output(&outputbuf, va_arg(ap, uint32_t), |
| hex_digits_up); |
| break; |
| case 'p': |
| count += _tfm_string_output(&outputbuf, "0x"); |
| count += _tfm_hex_num_output(&outputbuf, va_arg(ap, uint32_t), |
| hex_digits_lo); |
| break; |
| case 's': |
| count += _tfm_string_output(&outputbuf, va_arg(ap, char*)); |
| break; |
| case 'c': |
| _tfm_flush_formatted_buffer(&outputbuf, |
| (uint8_t)va_arg(ap, int32_t)); |
| count++; |
| break; |
| case '%': |
| _tfm_flush_formatted_buffer(&outputbuf, '%'); |
| count++; |
| break; |
| default: |
| count += _tfm_string_output(&outputbuf, "[Unsupported Tag]"); |
| continue; |
| } |
| fmt++; |
| } else { |
| _tfm_flush_formatted_buffer(&outputbuf, *fmt++); |
| count++; |
| } |
| } |
| |
| /* End of printf, flush buf */ |
| if (outputbuf.pos) { |
| count += stdio_output_string(outputbuf.buf, outputbuf.pos); |
| } |
| |
| return count; |
| } |
| |
| int tfm_log_printf(const char *fmt, ...) |
| { |
| int count = 0; |
| va_list ap; |
| |
| va_start(ap, fmt); |
| count = _tfm_log_vprintf(fmt, ap); |
| va_end(ap); |
| |
| return count; |
| } |