Skip to content

Commit 20211fd

Browse files
committed
Merge branch 'feat/stub_support' into 'master'
feat: add stub-support Closes ESF-126 and ESF-65 See merge request espressif/esp-serial-flasher!105
2 parents 92dfdeb + 684b796 commit 20211fd

24 files changed

+976
-102
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
name: Stub sources correctness checks
2+
3+
on:
4+
push:
5+
branches: [ "master" ]
6+
pull_request:
7+
branches: [ "master" ]
8+
9+
jobs:
10+
pre_commit:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- name: Checkout
14+
uses: actions/checkout@v3
15+
with:
16+
fetch-depth: 0
17+
18+
- name: Configure the stub example with the stub version argument
19+
run: idf.py reconfigure -DSERIAL_FLASHER_STUB_PULL_VERSION='0.3.0'
20+
working-directory: ${{github.workspace}}/examples/esp32_stub_example
21+
22+
- name: Run git diff to check if the sources in the repo match the generated ones
23+
run: git diff --exit-code

.gitlab-ci.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ variables:
3636
- cd $CI_PROJECT_DIR/examples/esp32_example
3737
- idf.py build -DMD5_ENABLED=1
3838
- idf.py build -DMD5_ENABLED=0
39+
- cd $CI_PROJECT_DIR/examples/esp32_stub_example
40+
- idf.py build
3941
- cd $CI_PROJECT_DIR/examples/esp32_load_ram_example
4042
- idf.py build
4143
- cd $CI_PROJECT_DIR/examples/esp32_spi_load_ram_example
@@ -55,6 +57,16 @@ run_pre_commit:
5557
- pip install pre-commit
5658
- pre-commit run --show-diff-on-failure --from-ref origin/master --to-ref HEAD
5759

60+
check_stub_source_correctness:
61+
stage: pre_check
62+
image: espressif/idf:latest
63+
tags:
64+
- internet
65+
script:
66+
- cd $CI_PROJECT_DIR/examples/esp32_stub_example
67+
- idf.py reconfigure -DSERIAL_FLASHER_STUB_PULL_VERSION='0.3.0'
68+
- git diff --exit-code
69+
5870
# Special case as ESP-IDF v4.3 is not supported by the usb_host_cdc_acm component
5971
# required by the USB CDC ACM interface port and its example
6072
build_idf_v4.3:
@@ -71,6 +83,8 @@ build_idf_v4.3:
7183
- cd $CI_PROJECT_DIR/examples/esp32_example
7284
- idf.py build -DMD5_ENABLED=1
7385
- idf.py build -DMD5_ENABLED=0
86+
- cd $CI_PROJECT_DIR/examples/esp32_stub_example
87+
- idf.py build
7488
- cd $CI_PROJECT_DIR/examples/esp32_load_ram_example
7589
- idf.py build
7690
- cd $CI_PROJECT_DIR/examples/esp32_spi_load_ram_example

CMakeLists.txt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ endif()
4646

4747
if (DEFINED SERIAL_FLASHER_INTERFACE_UART OR CONFIG_SERIAL_FLASHER_INTERFACE_UART STREQUAL "y")
4848
list(APPEND srcs
49+
src/esp_stubs.c
4950
src/protocol_uart.c
5051
src/slip.c
5152
)
@@ -58,6 +59,7 @@ if (DEFINED SERIAL_FLASHER_INTERFACE_UART OR CONFIG_SERIAL_FLASHER_INTERFACE_UAR
5859

5960
elseif(DEFINED SERIAL_FLASHER_INTERFACE_USB OR CONFIG_SERIAL_FLASHER_INTERFACE_USB STREQUAL "y")
6061
list(APPEND srcs
62+
src/esp_stubs.c
6163
src/protocol_uart.c
6264
src/slip.c
6365
)
@@ -141,3 +143,16 @@ else()
141143
endif()
142144

143145
target_compile_definitions(${target} PUBLIC ${defs})
146+
147+
# This segment pulls the flasher stubs at a specified version at wish, and generates the
148+
# esp_stubs.c/h files, overwriting the library provided ones.
149+
# It is also possible to override stub generation to use a custom url or a local folder.
150+
# Please check if the license under which the custom stub sources are released fits your usecase.
151+
if (DEFINED SERIAL_FLASHER_STUB_PULL_VERSION OR DEFINED SERIAL_FLASHER_STUB_PULL_OVERRIDE_PATH)
152+
include(cmake/serial_flasher_pull_stubs.cmake)
153+
serial_flasher_pull_stubs(
154+
VERSION ${SERIAL_FLASHER_STUB_PULL_VERSION}
155+
SOURCE ${SERIAL_FLASHER_STUB_PULL_SOURCE}
156+
PATH_OVERRIDE ${SERIAL_FLASHER_STUB_PULL_OVERRIDE_PATH}
157+
)
158+
endif()

cmake/esp_stubs.c.template

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/* Copyright 2020-{current_year} Espressif Systems (Shanghai) CO LTD
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
// auto-generated stubs from esp-flasher-stub v{stub_version}
17+
18+
#include "esp_stubs.h"
19+
20+
static bool stub_running = false;
21+
22+
bool esp_stub_get_running(void)
23+
{{
24+
return stub_running;
25+
}}
26+
27+
void esp_stub_set_running(bool stub_status)
28+
{{
29+
stub_running = stub_status;
30+
}}
31+
32+
#if (defined SERIAL_FLASHER_INTERFACE_UART) || (defined SERIAL_FLASHER_INTERFACE_USB)
33+
34+
#if __STDC_VERSION__ >= 201112L
35+
_Static_assert(ESP8266_CHIP == 0, "Stub order matches target_chip_t enumeration");
36+
_Static_assert(ESP32_CHIP == 1, "Stub order matches target_chip_t enumeration");
37+
_Static_assert(ESP32S2_CHIP == 2, "Stub order matches target_chip_t enumeration");
38+
_Static_assert(ESP32C3_CHIP == 3, "Stub order matches target_chip_t enumeration");
39+
_Static_assert(ESP32S3_CHIP == 4, "Stub order matches target_chip_t enumeration");
40+
_Static_assert(ESP32C2_CHIP == 5, "Stub order matches target_chip_t enumeration");
41+
_Static_assert(ESP32_RESERVED0_CHIP == 6, "Stub order matches target_chip_t enumeration");
42+
_Static_assert(ESP32H2_CHIP == 7, "Stub order matches target_chip_t enumeration");
43+
_Static_assert(ESP32C6_CHIP == 8, "Stub order matches target_chip_t enumeration");
44+
_Static_assert(ESP_MAX_CHIP == {max_chip_number}, "Stub order matches target_chip_t enumeration");
45+
#endif
46+
47+
const esp_stub_t esp_stub[ESP_MAX_CHIP] = {{

cmake/esp_stubs.h.template

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/* Copyright 2020-{current_year} Espressif Systems (Shanghai) CO LTD
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
// auto-generated stubs from esp-flasher-stub v{stub_version}
17+
18+
#pragma once
19+
20+
#include <stdint.h>
21+
#include <stdbool.h>
22+
#include "esp_loader.h"
23+
24+
#ifdef __cplusplus
25+
extern "C" {{
26+
#endif
27+
28+
bool esp_stub_get_running(void);
29+
void esp_stub_set_running(bool stub_status);
30+
31+
#if (defined SERIAL_FLASHER_INTERFACE_UART) || (defined SERIAL_FLASHER_INTERFACE_USB)
32+
33+
typedef struct {{
34+
esp_loader_bin_header_t header;
35+
esp_loader_bin_segment_t segments[2];
36+
}} esp_stub_t;
37+
38+
extern const esp_stub_t esp_stub[ESP_MAX_CHIP];
39+
40+
#endif
41+
42+
#ifdef __cplusplus
43+
}}
44+
#endif

cmake/gen_stub_sources.py

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
import base64
2+
import json
3+
import os
4+
import sys
5+
import urllib.request
6+
from datetime import datetime
7+
8+
"""
9+
This python module generates esp_stubs.c/h files from a given version and url, with
10+
<stub_download_url>/v<stub_version>/esp32xx.json as the required format.
11+
12+
It is also possible to override stub generation to use a local folder for testing purposes.
13+
"""
14+
15+
# Paths
16+
stub_version = sys.argv[1]
17+
stub_download_url = sys.argv[2]
18+
root_path = sys.argv[3]
19+
stub_override_path = sys.argv[4] if len(sys.argv) == 5 else None
20+
21+
template_path = os.path.join(root_path, "cmake")
22+
priv_inc_path = os.path.join(root_path, "private_include")
23+
src_path = os.path.join(root_path, "src")
24+
h_template_path = os.path.join(template_path, "esp_stubs.h.template")
25+
c_template_path = os.path.join(template_path, "esp_stubs.c.template")
26+
hfile_path = os.path.join(priv_inc_path, "esp_stubs.h")
27+
cfile_path = os.path.join(src_path, "esp_stubs.c")
28+
current_year = datetime.now().year
29+
30+
# Matches order of target_chip_t enumeration
31+
files_to_download = [
32+
None, # ESP8266_CHIP
33+
"esp32.json", # ESP32_CHIP
34+
"esp32s2.json", # ESP32S2_CHIP
35+
"esp32c3.json", # ESP32C3_CHIP
36+
"esp32s3.json", # ESP32S3_CHIP
37+
"esp32c2.json", # ESP32C2_CHIP
38+
None, # ESP32_RESERVED0_CHIP
39+
"esp32h2.json", # ESP32H2_CHIP
40+
"esp32c6.json", # ESP32C6_CHIP
41+
]
42+
43+
def read_stub_json(json_file):
44+
stub = json.load(json_file)
45+
entry = stub["entry"]
46+
text = base64.b64decode(stub["text"])
47+
text_start = stub["text_start"]
48+
try:
49+
data = base64.b64decode(stub["data"])
50+
data_start = stub["data_start"]
51+
except KeyError:
52+
data = None
53+
data_start = None
54+
55+
text_str = ", ".join([hex(b) for b in text])
56+
text_size = len(text)
57+
data_str = "" if data is None else ", ".join([hex(b) for b in data])
58+
data_size = 0 if data is None else len(data)
59+
data_start = 0 if data_start is None else data_start
60+
61+
stub_data = f""" // {file_to_download}
62+
{{
63+
.header = {{
64+
.entrypoint = {entry},
65+
}},
66+
.segments = {{
67+
{{
68+
.addr = {text_start},
69+
.size = {text_size},
70+
.data = (uint8_t[]){{{text_str}}},
71+
}},
72+
{{
73+
.addr = {data_start},
74+
.size = {data_size},
75+
.data = (uint8_t[]){{{data_str}}},
76+
}},
77+
}},
78+
}},
79+
80+
"""
81+
return stub_data
82+
83+
84+
if __name__ == "__main__":
85+
# .h and .c file templates
86+
with open(h_template_path, "r") as h_template_file, open(c_template_path, "r") as c_template_file:
87+
h_template = h_template_file.read()
88+
c_template = c_template_file.read()
89+
90+
# .h and .c file to generate
91+
with open(hfile_path, "w") as hfile, open(cfile_path, "w") as cfile:
92+
hfile.write(
93+
h_template.format(
94+
current_year=current_year,
95+
stub_version=stub_version,
96+
)
97+
)
98+
99+
cfile.write(
100+
c_template.format(
101+
current_year=current_year,
102+
stub_version=stub_version,
103+
max_chip_number=len(files_to_download),
104+
)
105+
)
106+
107+
for file_to_download in files_to_download:
108+
if file_to_download is None:
109+
cfile.write(" // placeholder\n" " {},\n" "\n")
110+
else:
111+
if stub_override_path:
112+
with open(f"{stub_override_path}/{file_to_download}") as file_path:
113+
cfile.write(read_stub_json(file_path))
114+
else:
115+
with urllib.request.urlopen(f"{stub_download_url}/v{stub_version}/{file_to_download}") as url:
116+
cfile.write(read_stub_json(url))
117+
118+
cfile.write("};\n" "\n" "#endif\n")
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
macro(serial_flasher_pull_stubs)
2+
set(ONE_VALUE_KEYWORDS VERSION SOURCE PATH_OVERRIDE)
3+
cmake_parse_arguments(FLASHER_STUB "" "${ONE_VALUE_KEYWORDS}" "" "${ARGN}")
4+
5+
# Don't make this mandatory, some users might not have Python installed
6+
find_package(Python COMPONENTS Interpreter)
7+
if(NOT Python_Interpreter_FOUND)
8+
message(WARNING "Python not found, cannot run gen_stub_sources.py")
9+
return()
10+
endif()
11+
12+
# By default use the esp-flasher-stub project stubs
13+
if (NOT DEFINED FLASHER_STUB_SOURCE)
14+
set(FLASHER_STUB_SOURCE "https://github.com/esp-rs/esp-flasher-stub/releases/download")
15+
endif()
16+
17+
execute_process(
18+
COMMAND
19+
${Python_EXECUTABLE}
20+
${CMAKE_CURRENT_SOURCE_DIR}/cmake/gen_stub_sources.py
21+
${FLASHER_STUB_VERSION}
22+
${FLASHER_STUB_SOURCE}
23+
${CMAKE_CURRENT_SOURCE_DIR}
24+
${FLASHER_STUB_PATH_OVERRIDE}
25+
)
26+
endmacro()

examples/common/example_common.c

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,41 @@ esp_loader_error_t connect_to_target(uint32_t higher_transmission_rate)
277277
}
278278

279279
#if (defined SERIAL_FLASHER_INTERFACE_UART) || (defined SERIAL_FLASHER_INTERFACE_USB)
280+
esp_loader_error_t connect_to_target_with_stub(const uint32_t current_transmission_rate,
281+
const uint32_t higher_transmission_rate)
282+
{
283+
esp_loader_connect_args_t connect_config = ESP_LOADER_CONNECT_DEFAULT();
284+
285+
esp_loader_error_t err = esp_loader_connect_with_stub(&connect_config);
286+
if (err != ESP_LOADER_SUCCESS) {
287+
printf("Cannot connect to target. Error: %u\n", err);
288+
return err;
289+
}
290+
printf("Connected to target\n");
291+
292+
if (higher_transmission_rate != current_transmission_rate) {
293+
err = esp_loader_change_transmission_rate_stub(current_transmission_rate,
294+
higher_transmission_rate);
295+
296+
if (err == ESP_LOADER_ERROR_UNSUPPORTED_FUNC) {
297+
printf("ESP8266 does not support change transmission rate command.");
298+
return err;
299+
} else if (err != ESP_LOADER_SUCCESS) {
300+
printf("Unable to change transmission rate on target.");
301+
return err;
302+
} else {
303+
err = loader_port_change_transmission_rate(higher_transmission_rate);
304+
if (err != ESP_LOADER_SUCCESS) {
305+
printf("Unable to change transmission rate.");
306+
return err;
307+
}
308+
printf("Transmission rate changed changed\n");
309+
}
310+
}
311+
312+
return ESP_LOADER_SUCCESS;
313+
}
314+
280315
esp_loader_error_t flash_binary(const uint8_t *bin, size_t size, size_t address)
281316
{
282317
esp_loader_error_t err;

examples/common/example_common.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,5 +59,7 @@ typedef struct example_bin_segment {
5959
void get_example_binaries(target_chip_t target, example_binaries_t *binaries);
6060
void get_example_ram_app_binary(target_chip_t target, example_ram_app_binary_t *bin);
6161
esp_loader_error_t connect_to_target(uint32_t higher_transmission_rate);
62+
esp_loader_error_t connect_to_target_with_stub(uint32_t current_transmission_rate,
63+
uint32_t higher_transmission_rate);
6264
esp_loader_error_t flash_binary(const uint8_t *bin, size_t size, size_t address);
6365
esp_loader_error_t load_ram_binary(const uint8_t *bin);
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# The following lines of boilerplate have to be in your project's CMakeLists
2+
# in this exact order for cmake to work correctly
3+
cmake_minimum_required(VERSION 3.5)
4+
5+
set(EXTRA_COMPONENT_DIRS ../../)
6+
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
7+
project(esp-serial-flasher)
8+
9+
# There are issues with ESP-IDF 4.4 and -Wunused-parameter
10+
if ("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER "4.4")
11+
idf_component_get_property(flasher esp-serial-flasher COMPONENT_LIB)
12+
13+
target_compile_options(${flasher}
14+
PRIVATE
15+
-Wunused-parameter
16+
-Wshadow
17+
)
18+
endif()

0 commit comments

Comments
 (0)