Skip to content

Commit 9821a2a

Browse files
committed
Merge branch 'feature/support_base64_logs' into 'master'
feat(binlog): Support binary log format expansion in monitor See merge request espressif/esp-idf-monitor!24
2 parents 52e1bee + 815d48f commit 9821a2a

File tree

9 files changed

+567
-11
lines changed

9 files changed

+567
-11
lines changed

.pre-commit-config.yaml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,14 @@ repos:
77
- repo: https://github.com/pre-commit/pre-commit-hooks
88
rev: v3.4.0
99
hooks:
10-
- id: trailing-whitespace
1110
- id: end-of-file-fixer
11+
exclude: ^test/host_test/inputs
12+
- id: trailing-whitespace
13+
exclude: ^test/host_test/inputs
1214
- id: check-executables-have-shebangs
1315
- id: mixed-line-ending
1416
args: ['-f=lf']
17+
exclude: ^test/host_test/inputs
1518
- id: double-quote-string-fixer
1619

1720
- repo: https://github.com/pycqa/flake8

esp_idf_monitor/base/binlog.py

Lines changed: 383 additions & 0 deletions
Large diffs are not rendered by default.

esp_idf_monitor/base/serial_handler.py

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
1+
# SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
22
# SPDX-License-Identifier: Apache-2.0
33

44
import hashlib
@@ -12,6 +12,7 @@
1212
from esp_idf_panic_decoder import PanicOutputDecoder
1313
from serial.tools import miniterm # noqa: F401
1414

15+
from .binlog import BinaryLog
1516
from .console_parser import (ConsoleParser, key_description, # noqa: F401
1617
prompt_next_action)
1718
from .console_reader import ConsoleReader # noqa: F401
@@ -84,21 +85,35 @@ def __init__(self, last_line_part, serial_check_exit, logger, decode_panic, read
8485
self.reset = Reset(serial_instance, target)
8586
self.panic_handler = PanicOutputDecoder(toolchain_prefix, elf_files, target)
8687
self.disable_auto_color = disable_auto_color
88+
self.binlog = BinaryLog(elf_files)
89+
self.binary_log_detected = False
8790

8891
def splitdata(self, data): # type: (bytes) -> List[bytes]
8992
"""
9093
Split data into lines, while keeping newlines, and move unfinished line for future processing
9194
"""
9295
# if data is empty fallback to empty string for easier concatenation with last line
93-
sp = data.splitlines(keepends=True) or [b'']
94-
if self._last_line_part != b'':
95-
# add unprocessed part from previous "data" to the first line
96-
sp[0] = self._last_line_part + sp[0]
97-
self._last_line_part = b''
98-
if not sp[-1].endswith(b'\n'):
99-
# last part is not a full line
100-
self._last_line_part = sp.pop()
101-
return sp
96+
self.binary_log_detected = (
97+
self.binlog.detected(self._last_line_part[0])
98+
if self._last_line_part
99+
else self.binlog.detected(data[0]) if data
100+
else False
101+
)
102+
if self.binary_log_detected:
103+
if self._last_line_part != b'':
104+
data = self._last_line_part + data
105+
self._last_line_part = b''
106+
return [data]
107+
else:
108+
sp = data.splitlines(keepends=True) or [b'']
109+
if self._last_line_part != b'':
110+
# add unprocessed part from previous "data" to the first line
111+
sp[0] = self._last_line_part + sp[0]
112+
self._last_line_part = b''
113+
if not sp[-1].endswith(b'\n'):
114+
# last part is not a full line
115+
self._last_line_part = sp.pop()
116+
return sp
102117

103118
def print_colored(self, line: bytes) -> None:
104119
if self.disable_auto_color:
@@ -148,6 +163,12 @@ def handle_serial_input(self, data, console_parser, coredump, gdb_helper, line_m
148163
data = data[(pos + 1):]
149164

150165
sp = self.splitdata(data)
166+
if self.binary_log_detected:
167+
text_lines, self._last_line_part = self.binlog.convert_to_text(sp[0])
168+
for line in text_lines:
169+
self.print_colored(line)
170+
return
171+
151172
for line in sp:
152173
line_strip = line.strip()
153174
if self._serial_check_exit and line_strip == EXIT_KEY.encode('latin-1'):

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ dependencies = [
3030
"pyserial>=3.3",
3131
"esp-coredump~=1.2",
3232
"esp-idf-panic-decoder~=1.2",
33+
"pyelftools",
3334
]
3435

3536
[project.readme]

test/host_test/inputs/binlog

3.35 KB
Binary file not shown.
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
Serial port /dev/ttyUSB0
2+
Connecting....
3+
ets Jul 29 2019 12:21:46
4+
5+
rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
6+
configsip: 0, SPIWP:0xee
7+
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
8+
mode:DIO, clock div:2
9+
load:0x3fff0040,len:2524
10+
ho 0 tail 12 room 4
11+
load:0x40078000,len:17096
12+
ho 0 tail 12 room 4
13+
load:0x40080400,len:3860
14+
entry 0x4008068c
15+
I (31) boot: ESP-IDF v5.5-dev-2410-g306d67599fd-dirt 2nd stage bootloader
16+
I (31) boot: compile time Mar 20 2025 11:15:24
17+
I (31) boot: Multicore bootloader
18+
I (32) boot: chip revision: v3.0
19+
I (32) boot.esp32: SPI Speed : 40MHz
20+
I (35) boot.esp32: SPI Mode : DIO
21+
I (38) boot.esp32: SPI Flash Size : 2MB
22+
I (40) boot: Enabling RNG early entropy source...
23+
I (42) boot: Partition Table:
24+
I (43) boot: ## Label Usage Type ST Offset Length
25+
I (45) boot: 0 nvs WiFi data 01 02 00009000 00006000
26+
I (49) boot: 1 phy_init RF data 01 01 0000f000 00001000
27+
I (54) boot: 2 factory factory app 00 00 00010000 00100000
28+
I (60) boot: End of partition table
29+
I (61) esp_image: segment 0: paddr=00010020 vaddr=3f400020 size=06a2ch ( 27180) map
30+
I (75) esp_image: segment 1: paddr=00016a54 vaddr=3ff80000 size=0001ch ( 28) load
31+
I (75) esp_image: segment 2: paddr=00016a78 vaddr=3ffb0000 size=02050h ( 8272) load
32+
I (78) esp_image: segment 3: paddr=00018ad0 vaddr=40080000 size=07548h ( 30024) load
33+
I (90) esp_image: segment 4: paddr=00020020 vaddr=400d0020 size=0ff14h ( 65300) map
34+
I (113) esp_image: segment 5: paddr=0002ff3c vaddr=40087548 size=05858h ( 22616) load
35+
I (128) boot: Loaded app from partition at offset 0x10000
36+
I (129) boot: Disabling RNG early entropy source...
37+
I (133) cpu_start: Multicore app
38+
I (141) cpu_start: Pro cpu start user code
39+
I (141) cpu_start: cpu freq: 160000000 Hz
40+
I (141) app_init: Application information:
41+
I (141) app_init: Project name: log
42+
I (141) app_init: App version: v5.5-dev-2410-g306d67599fd-dirt
43+
I (141) app_init: Compile time: Mar 20 2025 11:15:15
44+
I (141) app_init: ELF file SHA256: 5cd3b3293...
45+
I (142) app_init: ESP-IDF: v5.5-dev-2410-g306d67599fd-dirt
46+
I (144) efuse_init: Min chip rev: v0.0
47+
I (146) efuse_init: Max chip rev: v3.99 
48+
I (148) efuse_init: Chip rev: v3.0
49+
I (151) heap_init: Initializing. RAM available for dynamic allocation:
50+
I (152) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM
51+
I (155) heap_init: At 3FFB28A8 len 0002D758 (181 KiB): DRAM
52+
I (158) heap_init: At 3FFE0440 len 00003AE0 (14 KiB): D/IRAM
53+
I (160) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
54+
I (163) heap_init: At 4008CDA0 len 00013260 (76 KiB): IRAM
55+
I (167) spi_flash: detected chip: generic
56+
I (169) spi_flash: flash io: dio
57+
W (171) spi_flash: Detected size(4096k) larger than the size in the binary image header(2048k). Using the size in the binary image header.
58+
I (174) main_task: Started on CPU0
59+
I (184) main_task: Calling app_main()
60+
I (184) example: Start
61+
I (184) example: char_var A 0x41
62+
I (184) example: var8 240 -120
63+
I (184) example: var16 65303 -16954 0xff17
64+
I (184) example: const int var -1024
65+
I (184) example: const long long unsigned var 2095
66+
I (184) example: int_var 4095 -4095
67+
I (184) example: var32 9000 -2000
68+
I (194) example: var64 10700 -29468
69+
I (194) example: 64 32 64 vars 10700 9000 10800
70+
I (194) example: var_size 96843 4
71+
I (194) example: float var 1.600000
72+
I (204) example: double var -70.199997
73+
I (204) example: int, double, var32, float, float, char 4095 -70.199997 9000 1.600000 1.600000 A
74+
I (204) example: str_array 0x3ffb3a20
75+
I (214) example: str_ptr 0x3f402b38
76+
I (214) example: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
77+
I (214) example: 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f
78+
I (214) example: 20 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21
79+
I (214) example: 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35
80+
I (214) example: 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f
81+
I (214) example: 50 51 52 53 54 55 56 57 58 59
82+
I (224) example: 0x3ffb3a2a 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F |................|
83+
I (224) example: 0x3ffb3a3a 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F |................|
84+
I (224) example: 0x3ffb3a4a 20 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 | !!!!!!!!!!!!!!!|
85+
I (224) example: 0x3ffb3a5a 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 |0123456789012345|
86+
I (224) example: 0x3ffb3a6a 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F |@ABCDEFGHIJKLMNO|
87+
I (224) example: 0x3ffb3a7a 50 51 52 53 54 55 56 57 58 59 |PQRSTUVWXY|
88+
I (234) example: Text1:The way to
89+
I (234) example: get started is 
90+
I (234) example: to quit talking 
91+
I (234) example: and begin doing.
92+
I (234) example: - Walt Disney
93+
I (244) example: Text2:The way to
94+
I (244) example: get started is 
95+
I (244) example: to quit talking 
96+
I (244) example: and begin doing.
97+
I (244) example: - Walt Disney
98+
I (244) example: buffer2 0x3ffb3ad4
99+
I (244) example: 0x3ffb3ad4 00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 |................|
100+
I (244) example: 0x3ffb3ae4 04 00 00 00 05 00 00 00 06 00 00 00 07 00 00 00 |................|
101+
I (244) example: 0x3ffb3af4 08 00 00 00 09 00 00 00 0A 00 00 00 0B 00 00 00 |................|
102+
I (244) example: 0x3ffb3b04 0C 00 00 00 0D 00 00 00 0E 00 00 00 0F 00 00 00 |................|
103+
I (244) example: 0x3ffb3b14 10 00 00 00 11 00 00 00 12 00 00 00 13 00 00 00 |................|
104+
I (254) example: buffer3 0x3ffb3b28
105+
I (254) example: 0x3ffb3b28 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 |................|
106+
I (254) example: 0x3ffb3b38 02 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00 |................|
107+
I (254) example: 0x3ffb3b48 04 00 00 00 00 00 00 00 05 00 00 00 00 00 00 00 |................|
108+
I (254) example: 0x3ffb3b58 06 00 00 00 00 00 00 00 07 00 00 00 00 00 00 00 |................|
109+
I (254) example: 0x3ffb3b68 08 00 00 00 00 00 00 00 09 00 00 00 00 00 00 00 |................|
110+
I (254) example: 0x3ffb3b78 0A 00 00 00 00 00 00 00 |........|
111+
I (264) example: Precision and Width Tests
112+
I (274) example: int width | 42| |00042| |42 |
113+
I (274) example: int precision | 42| |00042| |00042|
114+
I (274) example: float width | 3.141590| |3.141590 | |3.141590|
115+
I (274) example: double width |-123.456789| |-123.456789| |-123.456789|
116+
I (284) example: string width |ESP32 | |ESP32 | |ESP32 Test|
117+
I (284) example: longs |1234567890| |123456789012345|
118+
I (284) example: shorts |ffff| |ff|
119+
I (294) example: Precision and Width Tests Complete
120+
I (294) example: Flag and Specifier Tests
121+
I (294) example: + flag |+42| |-42|
122+
I (294) example: flag | 42| |-42|
123+
I (294) example: # flag |0xff| |0XFF| |0377|
124+
I (304) example: # flag long |0x499602d2| |011145401322|
125+
I (304) example: Octal format |377| |0377|
126+
I (304) example: Octal short |777| |0777|
127+
I (304) example: Combined Flags | +42| | 42| | 0x2a| | 052|
128+
I (314) example: Left-aligned Combined Flags |+42 | | 42 | |0x2a | |052 |
129+
I (314) example: Flag and Specifier Tests Complete
130+
I (314) example: Success
131+
I (314) main_task: Returned from app_main()
608 KB
Binary file not shown.

test/host_test/inputs/log.elf

2.57 MB
Binary file not shown.

test/host_test/test_monitor.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,23 @@ def test_wrong_elf_file(self):
345345
stderr = f_err.read()
346346
assert "--- Warning: ELF file 'non_existing.elf' does not exist" in stderr
347347

348+
def test_binary_logging(self):
349+
args = [IN_DIR + '/log.elf', IN_DIR + '/bootloader.elf']
350+
out, err = self.run_monitor(args, 'binlog', timeout=10)
351+
with open(err, 'r') as f_err:
352+
stderr = f_err.read()
353+
assert 'Stopping condition has been received' in stderr
354+
355+
ansi_regex = re.compile(r'\x1B\[\d+(;\d+){0,2}m')
356+
with open(out, 'r') as f_out, open(os.path.join(IN_DIR, 'binlog_out.txt'), 'r') as f_expected:
357+
for line_out, line_expected in zip(f_out, f_expected):
358+
if os.name == 'nt':
359+
line_expected = ansi_regex.sub('', line_expected)
360+
line_out = ansi_regex.sub('', line_out)
361+
line_out = line_out.strip()
362+
line_expected = line_expected.strip()
363+
assert line_out == line_expected, f'Mismatch: {line_out} != {line_expected}'
364+
348365

349366
@pytest.mark.skipif(os.name == 'nt', reason='Linux/MacOS only')
350367
class TestConfig(TestBaseClass):

0 commit comments

Comments
 (0)