mirror of
https://github.com/espressif/ESP8266_RTOS_SDK.git
synced 2025-05-22 01:27:11 +08:00
303 lines
7.9 KiB
C
303 lines
7.9 KiB
C
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
|
|
//
|
|
// 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 <stdint.h>
|
|
#include <stdio.h>
|
|
|
|
#include "sdkconfig.h"
|
|
|
|
#include "esp_attr.h"
|
|
|
|
#include "esp8266/eagle_soc.h"
|
|
#include "esp8266/uart_register.h"
|
|
#include "esp8266/rom_functions.h"
|
|
|
|
#ifndef CONFIG_CONSOLE_UART_NONE
|
|
static void uart_putc(int c)
|
|
{
|
|
while (1) {
|
|
uint32_t fifo_cnt = READ_PERI_REG(UART_STATUS(CONFIG_CONSOLE_UART_NUM)) & (UART_TXFIFO_CNT << UART_TXFIFO_CNT_S);
|
|
|
|
if ((fifo_cnt >> UART_TXFIFO_CNT_S & UART_TXFIFO_CNT) < 126)
|
|
break;
|
|
}
|
|
|
|
WRITE_PERI_REG(UART_FIFO(CONFIG_CONSOLE_UART_NUM) , c);
|
|
}
|
|
#else
|
|
#define uart_putc(_c) { }
|
|
#endif
|
|
|
|
int __attribute__ ((weak)) ets_putc(int c)
|
|
{
|
|
#ifdef CONFIG_NEWLIB_STDOUT_LINE_ENDING_CRLF
|
|
if (c == '\n')
|
|
uart_putc('\r');
|
|
#elif defined(CONFIG_NEWLIB_STDOUT_LINE_ENDING_CR)
|
|
if (c == '\n')
|
|
c = '\r';
|
|
#endif
|
|
|
|
uart_putc(c);
|
|
|
|
return c;
|
|
}
|
|
|
|
#if defined(CONFIG_USING_NEW_ETS_VPRINTF) && !defined(BOOTLOADER_BUILD)
|
|
|
|
#define FILL_0 0x01
|
|
#define FILL_LEFT 0x02
|
|
#define POINTOR 0x04
|
|
#define ALTERNATE 0x08
|
|
#define OUPUT_INT 0x10
|
|
#define START 0x20
|
|
|
|
#define VINT_STR_MAX 10
|
|
|
|
typedef union _val_cache {
|
|
uint8_t val8;
|
|
int32_t val32;
|
|
uint32_t val32u;
|
|
const char *valcp;
|
|
} val_cache_t;
|
|
|
|
typedef struct _val_attr {
|
|
int8_t type;
|
|
uint8_t state;
|
|
uint8_t fillbytes;
|
|
uint8_t precision;
|
|
|
|
val_cache_t value;
|
|
} val_attr_t;
|
|
|
|
#define isdigit(_c) ((_c <= '9') && (_c >= '0'))
|
|
#define fill_num(_attr) ((attr)->fillbytes)
|
|
#define isfill_0(_attr) (fill_num(_attr) && ((_attr)->state & FILL_0))
|
|
#define isfill_left(_attr) (fill_num(_attr) && ((_attr)->state & FILL_LEFT))
|
|
#define isstart(_attr) ((_attr)->state & START)
|
|
|
|
static inline void ets_printf_ch_mutlti(uint32_t c, uint32_t len)
|
|
{
|
|
while (len--)
|
|
ets_putc(c);
|
|
}
|
|
|
|
static inline void ets_printf_buf(const char *s, uint32_t len)
|
|
{
|
|
while (len--)
|
|
ets_putc(*s++);
|
|
}
|
|
|
|
static int ets_printf_str(const val_attr_t * const attr)
|
|
{
|
|
const char *s = attr->value.valcp;
|
|
s = s == NULL ? "<null>" : s;
|
|
|
|
if (fill_num(attr)) {
|
|
unsigned char left;
|
|
unsigned char len;
|
|
|
|
while (*s != '\0')
|
|
s++;
|
|
len = s - attr->value.valcp;
|
|
left = fill_num(attr) > len ? fill_num(attr) - len : 0;
|
|
|
|
if (!isfill_left(attr)) {
|
|
ets_printf_ch_mutlti(' ', left);
|
|
}
|
|
|
|
ets_printf_buf(attr->value.valcp, len);
|
|
|
|
if (isfill_left(attr)) {
|
|
ets_printf_ch_mutlti(' ', left);
|
|
}
|
|
} else {
|
|
while (*s != '\0')
|
|
ets_putc(*s++);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ets_printf_int(val_attr_t * const attr, uint8_t hex)
|
|
{
|
|
char buf[VINT_STR_MAX];
|
|
unsigned char offset = VINT_STR_MAX;
|
|
|
|
if (attr->value.val32u != 0) {
|
|
for (; attr->value.val32u > 0; attr->value.val32u /= hex) {
|
|
unsigned char c = attr->value.val32u % hex;
|
|
if (c < 10)
|
|
buf[--offset] = c + '0';
|
|
else
|
|
buf[--offset] = c + 'a' - 10;
|
|
}
|
|
} else
|
|
buf[--offset] = '0';
|
|
|
|
if (fill_num(attr)) {
|
|
char fill_data = isfill_0(attr) ? '0' : ' ';
|
|
unsigned char len = fill_num(attr) - (VINT_STR_MAX - offset);
|
|
unsigned char left = fill_num(attr) > (VINT_STR_MAX - offset) ? len : 0;
|
|
|
|
if (!isfill_left(attr)) {
|
|
ets_printf_ch_mutlti(fill_data, left);
|
|
}
|
|
|
|
ets_printf_buf(&buf[offset], VINT_STR_MAX - offset);
|
|
|
|
if (isfill_left(attr)) {
|
|
fill_data = ' ';
|
|
ets_printf_ch_mutlti(fill_data, left);
|
|
}
|
|
} else {
|
|
ets_printf_buf(&buf[offset], VINT_STR_MAX - offset);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int ets_vprintf(const char *fmt, va_list va)
|
|
{
|
|
for (; ;) {
|
|
const char *ps = fmt;
|
|
val_attr_t attr;
|
|
|
|
while (*ps != '\0' && *ps != '%')
|
|
ets_putc(*ps++);
|
|
|
|
if (*ps == '\0')
|
|
break;
|
|
|
|
fmt = ps;
|
|
|
|
attr.state = 0;
|
|
attr.type = -1;
|
|
attr.fillbytes = 0;
|
|
attr.precision = 0;
|
|
|
|
for (; ;) {
|
|
switch (*++ps) {
|
|
case 'd':
|
|
case 'i':
|
|
case 'u':
|
|
case 'x':
|
|
case 'c':
|
|
case 's':
|
|
case 'p':
|
|
case '\0':
|
|
attr.type = *ps++;
|
|
break;
|
|
case '#':
|
|
attr.state |= ALTERNATE;
|
|
ps++;
|
|
break;
|
|
case '0'...'9':
|
|
if ((!isstart(&attr) || *(ps - 1) == '-') && *ps == '0') {
|
|
attr.state |= FILL_0;
|
|
} else {
|
|
if (attr.state & POINTOR)
|
|
attr.precision = attr.precision * 10 + *ps - '0';
|
|
else
|
|
attr.fillbytes = attr.fillbytes * 10 + *ps - '0';
|
|
}
|
|
break;
|
|
case '.':
|
|
attr.state |= POINTOR;
|
|
break;
|
|
case '-':
|
|
attr.state |= FILL_LEFT;
|
|
break;
|
|
default:
|
|
attr.type = -2;
|
|
break;
|
|
}
|
|
|
|
attr.state |= START;
|
|
|
|
if (attr.type != -1)
|
|
break;
|
|
}
|
|
|
|
switch (attr.type) {
|
|
case 'c':
|
|
attr.value.val8 = (char)va_arg(va, int);
|
|
ets_putc(attr.value.val8);
|
|
break;
|
|
case 's':
|
|
attr.value.valcp = va_arg(va, const char *);
|
|
ets_printf_str(&attr);
|
|
break;
|
|
case 'i':
|
|
case 'd':
|
|
attr.value.val32 = va_arg(va, int);
|
|
if (attr.value.val32 < 0) {
|
|
ets_putc('-');
|
|
attr.value.val32 = -attr.value.val32;
|
|
}
|
|
ets_printf_int(&attr, 10);
|
|
break;
|
|
case 'u':
|
|
attr.value.val32u = va_arg(va, unsigned int);
|
|
ets_printf_int(&attr, 10);
|
|
break;
|
|
case 'x':
|
|
attr.value.val32u = va_arg(va, unsigned int);
|
|
ets_printf_int(&attr, 16);
|
|
break;
|
|
case 'p':
|
|
ets_printf_buf("0x", 2);
|
|
attr.value.valcp = va_arg(va, const char *);
|
|
ets_printf_int(&attr, 16);
|
|
default:
|
|
break;
|
|
}
|
|
|
|
fmt = ps;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#else /* defined(CONFIG_USING_NEW_ETS_VPRINTF) && !defined(BOOTLOADER_BUILD) */
|
|
|
|
int ets_vprintf(const char *fmt, va_list ap)
|
|
{
|
|
return ets_io_vprintf(ets_putc, fmt, ap);
|
|
}
|
|
|
|
#endif /* defined(CONFIG_USING_NEW_ETS_VPRINTF) && !defined(BOOTLOADER_BUILD) */
|
|
|
|
/**
|
|
* Re-write ets_printf in SDK side, since ets_printf in ROM will use a global
|
|
* variable which address is in heap region of SDK side. If use ets_printf in ROM,
|
|
* this variable maybe re-write when heap alloc and modification.
|
|
*
|
|
* Using new "ets_vprintf" costs stack without alignment and accuracy:
|
|
* just "fmt": 136 Bytes
|
|
* "%s": 172 Bytes
|
|
* "%p", "%d, "%i, "%u", "%x": 215 Bytes
|
|
*/
|
|
int ets_printf(const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
int ret;
|
|
|
|
va_start(ap, fmt);
|
|
ret = ets_vprintf(fmt, ap);
|
|
va_end(ap);
|
|
|
|
return ret;
|
|
}
|