-
Notifications
You must be signed in to change notification settings - Fork 117
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Desktop support (Linux / Windows / Mac) (ESF-122) #102
base: master
Are you sure you want to change the base?
Changes from 3 commits
1f6ca72
947301c
98d215b
4b650f8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,6 @@ | ||
[submodule "submodules/stm32-cmake"] | ||
path = submodules/stm32-cmake | ||
url = https://github.com/ObKo/stm32-cmake.git | ||
[submodule "submodules/serial"] | ||
path = submodules/serial | ||
url = https://github.com/wjwwood/serial | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,11 +17,21 @@ | |
#include <stdlib.h> | ||
#include <string.h> | ||
#include <inttypes.h> | ||
#if !defined(WIN32) | ||
#include <sys/param.h> | ||
#endif | ||
#include "esp_loader_io.h" | ||
#include "esp_loader.h" | ||
#include "example_common.h" | ||
|
||
#ifndef MAX | ||
#define MAX(a, b) ((a) > (b)) ? (a) : (b) | ||
#endif | ||
|
||
#ifndef MIN | ||
#define MIN(a, b) ((a) < (b)) ? (a) : (b) | ||
#endif | ||
|
||
#ifndef SINGLE_TARGET_SUPPORT | ||
|
||
|
||
|
@@ -336,7 +346,8 @@ esp_loader_error_t load_ram_binary(const uint8_t *bin) | |
printf("Start loading\n"); | ||
esp_loader_error_t err; | ||
const esp_loader_bin_header_t *header = (const esp_loader_bin_header_t *)bin; | ||
esp_loader_bin_segment_t segments[header->segments]; | ||
//esp_loader_bin_segment_t segments[header->segments]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this being moved to the heap? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because it didn't compile on MSVC There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah yes, after C99 VLAs are a GNU extension as well. We shouldn't be using VLAs in the first place IMO but I am unsure about using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A simple static array with a max segment count should suffice. |
||
esp_loader_bin_segment_t* segments = malloc(header->segments * sizeof(esp_loader_bin_segment_t)); | ||
|
||
// Parse segments | ||
uint32_t seg; | ||
|
@@ -357,6 +368,7 @@ esp_loader_error_t load_ram_binary(const uint8_t *bin) | |
err = esp_loader_mem_start(segments[seg].addr, segments[seg].size, ESP_RAM_BLOCK); | ||
if (err != ESP_LOADER_SUCCESS) { | ||
printf("Loading ram start with error %d.\n", err); | ||
free(segments); | ||
return err; | ||
} | ||
|
||
|
@@ -367,6 +379,7 @@ esp_loader_error_t load_ram_binary(const uint8_t *bin) | |
err = esp_loader_mem_write(data_pos, data_size); | ||
if (err != ESP_LOADER_SUCCESS) { | ||
printf("\nPacket could not be written! Error %d.\n", err); | ||
free(segments); | ||
return err; | ||
} | ||
data_pos += data_size; | ||
|
@@ -377,9 +390,11 @@ esp_loader_error_t load_ram_binary(const uint8_t *bin) | |
err = esp_loader_mem_finish(header->entrypoint); | ||
if (err != ESP_LOADER_SUCCESS) { | ||
printf("\nLoad ram finish with Error %d.\n", err); | ||
free(segments); | ||
return err; | ||
} | ||
printf("\nFinished loading\n"); | ||
|
||
free(segments); | ||
return ESP_LOADER_SUCCESS; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
set(ESPSERIAL_PATH ${CMAKE_CURRENT_LIST_DIR}/../../) | ||
|
||
# LIB serial | ||
|
||
SET(serial_path ${ESPSERIAL_PATH}submodules/serial) | ||
SET(serial_SRCS ${serial_path}/src/serial.cc) | ||
|
||
if(APPLE) | ||
# If OSX | ||
list(APPEND serial_SRCS ${serial_path}/src/impl/unix.cc) | ||
list(APPEND serial_SRCS ${serial_path}/src/impl/list_ports/list_ports_osx.cc) | ||
elseif(UNIX) | ||
# If unix | ||
list(APPEND serial_SRCS ${serial_path}/src/impl/unix.cc) | ||
list(APPEND serial_SRCS ${serial_path}/src/impl/list_ports/list_ports_linux.cc) | ||
else() | ||
# If windows | ||
list(APPEND serial_SRCS ${serial_path}/src/impl/win.cc) | ||
list(APPEND serial_SRCS ${serial_path}/src/impl/list_ports/list_ports_win.cc) | ||
endif() | ||
|
||
add_library(serial | ||
${serial_SRCS} | ||
) | ||
|
||
target_include_directories(serial PUBLIC | ||
${serial_path}/include | ||
) | ||
|
||
# LIB esp_serial | ||
|
||
include(${ESPSERIAL_PATH}examples/common/bin2array.cmake) | ||
create_resources(${ESPSERIAL_PATH}examples/binaries/Hello-world ${CMAKE_BINARY_DIR}/binaries_1.c) | ||
set_property(SOURCE ${CMAKE_BINARY_DIR}/binaries_1.c PROPERTY GENERATED 1) | ||
create_resources(${ESPSERIAL_PATH}examples/binaries/RAM_APP ${CMAKE_BINARY_DIR}/binaries_2.c) | ||
set_property(SOURCE ${CMAKE_BINARY_DIR}/binaries_2.c PROPERTY GENERATED 1) | ||
|
||
|
||
add_library(esp_serial | ||
${ESPSERIAL_PATH}port/serial_port.cpp | ||
${ESPSERIAL_PATH}src/esp_loader.c | ||
${ESPSERIAL_PATH}src/esp_targets.c | ||
${ESPSERIAL_PATH}src/md5_hash.c | ||
${ESPSERIAL_PATH}src/slip.c | ||
${ESPSERIAL_PATH}src/protocol_uart.c | ||
${ESPSERIAL_PATH}src/protocol_common.c | ||
${CMAKE_BINARY_DIR}/binaries_1.c | ||
${CMAKE_BINARY_DIR}/binaries_2.c | ||
${ESPSERIAL_PATH}examples/common/example_common.c | ||
) | ||
|
||
target_include_directories(esp_serial PUBLIC | ||
${ESPSERIAL_PATH}include | ||
${ESPSERIAL_PATH}port | ||
${ESPSERIAL_PATH}examples/common | ||
) | ||
|
||
target_include_directories(esp_serial PRIVATE | ||
${ESPSERIAL_PATH}private_include | ||
) | ||
|
||
target_compile_definitions(esp_serial PUBLIC | ||
-DSERIAL_FLASHER_INTERFACE_USB | ||
-DMD5_ENABLED | ||
-DSERIAL_FLASHER_WRITE_BLOCK_RETRIES=4 | ||
) | ||
|
||
target_link_libraries(esp_serial PUBLIC | ||
serial | ||
) | ||
|
||
# EXECUTABLE desktop_esp32_example | ||
|
||
add_executable(desktop_esp32_example | ||
main/main.cpp | ||
) | ||
|
||
target_link_libraries(desktop_esp32_example PRIVATE | ||
esp_serial | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
/* Flash multiple partitions example | ||
|
||
This example code is in the Public Domain (or CC0 licensed, at your option.) | ||
|
||
Unless required by applicable law or agreed to in writing, this | ||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR | ||
CONDITIONS OF ANY KIND, either express or implied. | ||
*/ | ||
|
||
#include "stdio.h" | ||
#include <string.h> | ||
|
||
#include "serial_port.h" | ||
#include "esp_loader.h" | ||
#include "esp_loader_io.h" | ||
extern "C" { | ||
#include "example_common.h" | ||
|
||
} | ||
|
||
#include "serial/serial.h" | ||
|
||
#define HIGHER_BAUDRATE 230400 | ||
|
||
int main(int argv, char **argc) | ||
{ | ||
if(argv < 2) { | ||
printf("Usage: %s <port>\n", argc[0]); | ||
return 1; | ||
} | ||
|
||
example_binaries_t bin; | ||
|
||
loader_serial_config_t config; | ||
config.portName = argc[1]; | ||
// config.portName = "COM4"; | ||
config.baudrate = 115200; | ||
config.timeout = 1000; | ||
|
||
if (loader_port_serial_init((const loader_serial_config_t*)&config) != ESP_LOADER_SUCCESS) { | ||
printf("Serial initialization failed.\n"); | ||
return -1; | ||
} | ||
|
||
printf("Connecting...\n"); | ||
if (connect_to_target(HIGHER_BAUDRATE) == ESP_LOADER_SUCCESS) { | ||
|
||
get_example_binaries(esp_loader_get_target(), &bin); | ||
|
||
printf("Loading bootloader...\n"); | ||
flash_binary(bin.boot.data, bin.boot.size, bin.boot.addr); | ||
printf("Loading partition table...\n"); | ||
flash_binary(bin.part.data, bin.part.size, bin.part.addr); | ||
printf("Loading app...\n"); | ||
flash_binary(bin.app.data, bin.app.size, bin.app.addr); | ||
printf("Done!\n"); | ||
} else { | ||
printf("Connect failed\n"); | ||
return -1; | ||
} | ||
|
||
return 0; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
/* Copyright 2020-2023 Espressif Systems (Shanghai) CO 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 <string.h> | ||
#include <stdint.h> | ||
#include <stdio.h> | ||
#include <thread> | ||
#include <chrono> | ||
#include <memory> | ||
#include "serial/serial.h" | ||
|
||
#include "serial_port.h" | ||
|
||
using std::chrono::high_resolution_clock; | ||
using std::chrono::duration_cast; | ||
using std::chrono::duration; | ||
using std::chrono::milliseconds; | ||
using namespace std::chrono_literals; | ||
|
||
loader_serial_config_t serial_config; | ||
std::unique_ptr<serial::Serial> serial_port; | ||
DNedic marked this conversation as resolved.
Show resolved
Hide resolved
|
||
std::chrono::steady_clock::time_point serial_timer; | ||
|
||
#ifdef SERIAL_FLASHER_DEBUG_TRACE | ||
static void transfer_debug_print(const uint8_t *data, uint16_t size, bool write) | ||
{ | ||
static bool write_prev = false; | ||
|
||
if (write_prev != write) { | ||
write_prev = write; | ||
printf("\n--- %s ---\n", write ? "WRITE" : "READ"); | ||
} | ||
|
||
for (uint32_t i = 0; i < size; i++) { | ||
printf("%02x ", data[i]); | ||
} | ||
} | ||
#endif | ||
|
||
void setTimeout(uint32_t timeout) | ||
{ | ||
if(timeout == serial_config.timeout) | ||
return; | ||
|
||
if(!serial_port || !serial_port->isOpen()) | ||
return; | ||
|
||
serial_port->setTimeout(serial::Timeout::simpleTimeout(timeout)); | ||
serial_config.timeout = timeout; | ||
} | ||
|
||
esp_loader_error_t loader_port_write(const uint8_t *data, uint16_t size, uint32_t timeout) | ||
{ | ||
try { | ||
if(!serial_port || !serial_port->isOpen()) | ||
return ESP_LOADER_ERROR_FAIL; | ||
|
||
setTimeout(timeout); | ||
size_t result = serial_port->write(data, size); | ||
if (result != size) { | ||
return ESP_LOADER_ERROR_FAIL; | ||
} | ||
} catch (std::exception &e){ | ||
loader_port_debug_print(e.what()); | ||
return ESP_LOADER_ERROR_FAIL; | ||
} | ||
|
||
#ifdef SERIAL_FLASHER_DEBUG_TRACE | ||
transfer_debug_print(data, size, true); | ||
#endif | ||
|
||
return ESP_LOADER_SUCCESS; | ||
} | ||
|
||
|
||
esp_loader_error_t loader_port_read(uint8_t *data, uint16_t size, uint32_t timeout) | ||
{ | ||
try { | ||
if(!serial_port || !serial_port->isOpen()) | ||
return ESP_LOADER_ERROR_FAIL; | ||
|
||
setTimeout(timeout); | ||
size_t result = serial_port->read(data, size); | ||
if (result != size) { | ||
return ESP_LOADER_ERROR_FAIL; | ||
} | ||
} catch (std::exception &e){ | ||
loader_port_debug_print(e.what()); | ||
return ESP_LOADER_ERROR_FAIL; | ||
} | ||
|
||
#ifdef SERIAL_FLASHER_DEBUG_TRACE | ||
transfer_debug_print(data, size, true); | ||
#endif | ||
|
||
return ESP_LOADER_SUCCESS; | ||
} | ||
|
||
esp_loader_error_t loader_port_serial_init(const loader_serial_config_t *config) | ||
{ | ||
serial_config = *config; | ||
|
||
try { | ||
serial_port = std::make_unique<serial::Serial>(serial_config.portName, config->baudrate, serial::Timeout::simpleTimeout(config->timeout)); | ||
if ( serial_port->isOpen() == false ) { | ||
return ESP_LOADER_ERROR_FAIL; | ||
} | ||
} catch (std::exception &e){ | ||
loader_port_debug_print(e.what()); | ||
return ESP_LOADER_ERROR_FAIL; | ||
} | ||
|
||
return ESP_LOADER_SUCCESS; | ||
} | ||
|
||
// Set GPIO0 LOW, then | ||
// assert reset pin for 100 milliseconds. | ||
void loader_port_enter_bootloader(void) | ||
{ | ||
// todo | ||
loader_port_reset_target(); | ||
} | ||
|
||
|
||
void loader_port_reset_target(void) | ||
{ | ||
// todo | ||
} | ||
|
||
|
||
void loader_port_delay_ms(uint32_t ms) | ||
{ | ||
std::this_thread::sleep_for(std::chrono::milliseconds(ms)); | ||
} | ||
|
||
|
||
void loader_port_start_timer(uint32_t ms) | ||
{ | ||
serial_timer = high_resolution_clock::now() + (ms * 1ms); | ||
} | ||
|
||
|
||
uint32_t loader_port_remaining_time(void) | ||
{ | ||
auto time_now = high_resolution_clock::now(); | ||
int32_t remaining = (duration_cast<milliseconds>(serial_timer - time_now)).count(); | ||
return (remaining > 0) ? (uint32_t)remaining : 0; | ||
} | ||
|
||
|
||
void loader_port_debug_print(const char *str) | ||
{ | ||
printf("DEBUG: %s", str); | ||
} | ||
|
||
esp_loader_error_t loader_port_change_transmission_rate(uint32_t baudrate) | ||
{ | ||
if(!serial_port || !serial_port->isOpen()) | ||
return ESP_LOADER_ERROR_FAIL; | ||
|
||
try { | ||
serial_port->setBaudrate(baudrate); | ||
} catch (std::exception &e){ | ||
loader_port_debug_print(e.what()); | ||
return ESP_LOADER_ERROR_FAIL; | ||
} | ||
|
||
return ESP_LOADER_SUCCESS; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just my 2c, I would recommend fetching this project at build time using
ExternalProject
orFetchContent
CMake modules, instead of adding a submodule into esp-serial-flasher.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea! This would be a good time to move over the
stm32-cmake
submodule toFetchContent
as well.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps a find_package script which can do the fetching if needed. In my application the serial library is already present. As a note, I didn't use add_subdirectory on this since it wants catkin as a dependancy, which I don't need here.