Skip to content

Commit cda4905

Browse files
committed
Merge pull request #6 from higaski/erase_flash
feat: add `erase_flash` option
2 parents 4027410 + f43f669 commit cda4905

7 files changed

Lines changed: 132 additions & 42 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Changelog
22

3-
##
3+
## 1.10.0
4+
- Adopt esp-serial-flasher version number
5+
- Add `erase_flash` command ([#6](https://github.com/higaski/QtESPFlasher/pull/6))
46
- Update to esp-serial-flasher 1.10.0
57
- Update to esptool-legacy-flasher-stub 1.9.0
68

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ It currently supports the following ESP microcontrollers:
4444
- a [flasher_args.json](https://github.com/espressif/esp-idf/blob/master/components/esptool_py/flasher_args.json.in) file
4545
- a .zip archive
4646
- single/multiple loose binaries
47-
- CLI is a drop-in replace for [esptools write-flash](https://docs.espressif.com/projects/esptool/en/latest/esp32/esptool/basic-commands.html#write-binary-data-to-flash-write-flash) command
47+
- CLI is a drop-in replacement for the [write-flash](https://docs.espressif.com/projects/esptool/en/latest/esp32/esptool/basic-commands.html#write-binary-data-to-flash-write-flash) and [erase-flash](https://docs.espressif.com/projects/esptool/en/latest/esp32/esptool/basic-commands.html#erase-flash-erase-flash-erase-region) commands of [esptool](https://docs.espressif.com/projects/esptool/en/latest/esp32/esptool/index.html)
4848
- `ESPFlasher` [Qt widget library](/libs/esp_flasher) for reuse
4949
- Pre-built Windows and Linux executables
5050

@@ -94,7 +94,7 @@ The default QtESPFlasher baud rate is 115200. Slower rates may be set using `-b`
9494

9595
## Usage
9696
### CLI
97-
When used as a command line tool QtESPFlasher can be a drop-in replace for the [esptools write-flash](https://docs.espressif.com/projects/esptool/en/latest/esp32/esptool/basic-commands.html#write-binary-data-to-flash-write-flash) command.
97+
When used as a command line tool QtESPFlasher can be a drop-in replacement for [write-flash](https://docs.espressif.com/projects/esptool/en/latest/esp32/esptool/basic-commands.html#write-binary-data-to-flash-write-flash) and [erase-flash](https://docs.espressif.com/projects/esptool/en/latest/esp32/esptool/basic-commands.html#erase-flash-erase-flash-erase-region).
9898

9999
```sh
100100
./QtESPFlasher -p ttyUSB0 write_flash 0x0 bootloader/bootloader.bin 0x10000 hello_world.bin

libs/esp_flasher/include/esp_flasher/esp_flasher.hpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,12 @@ class EspFlasher : public QObject {
3535
QString after,
3636
QString no_stub,
3737
QString trace,
38-
QVector<Bin> bins);
38+
QVector<Bin> bins = {});
3939
~EspFlasher();
4040

4141
public slots:
4242
esp_loader_error_t flash();
43+
esp_loader_error_t erase();
4344

4445
signals:
4546
void finished();
@@ -97,4 +98,4 @@ public slots:
9798
static_assert(SERIAL_FLASHER_BOOT_HOLD_TIME_MS == 50);
9899
static inline uint32_t _reset_hold_time_ms{SERIAL_FLASHER_RESET_HOLD_TIME_MS};
99100
static inline uint32_t _boot_hold_time_ms{SERIAL_FLASHER_BOOT_HOLD_TIME_MS};
100-
};
101+
};

libs/esp_flasher/src/esp_flasher.cpp

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ EspFlasher::~EspFlasher() {
111111
///
112112
/// \retval ESP_LOADER_SUCCESS Success
113113
/// \retval ESP_LOADER_ERROR_FAIL Unspecified error
114-
/// \retval ESP_LOADER_ERROR_TIMEOUT Timeout elapsed
114+
/// \retval ESP_LOADER_ERROR_TIMEOUT Timeout
115115
/// \retval ESP_LOADER_ERROR_INVALID_PARAM Invalid parameter
116116
/// \retval ESP_LOADER_ERROR_INVALID_TARGET Connected target is invalid
117117
esp_loader_error_t EspFlasher::flash() {
@@ -150,6 +150,38 @@ esp_loader_error_t EspFlasher::flash() {
150150
return ESP_LOADER_SUCCESS;
151151
}
152152

153+
/// Erase
154+
///
155+
/// \retval ESP_LOADER_SUCCESS Success
156+
/// \retval ESP_LOADER_ERROR_TIMEOUT Timeout
157+
/// \retval ESP_LOADER_ERROR_INVALID_RESPONSE Internal error
158+
esp_loader_error_t EspFlasher::erase() {
159+
gsl::final_action emit_finished{[this] { emit finished(); }};
160+
161+
// Try to connect
162+
if (auto const err{connect()}; err != ESP_LOADER_SUCCESS) {
163+
qCritical().noquote().nospace()
164+
<< "Cannot connect to target (" << qstrerr(err) << ")";
165+
return err;
166+
}
167+
168+
// Erase
169+
qInfo().nospace() << "Erasing flash (this may take a while)...";
170+
if (auto const err{esp_loader_flash_erase()}; err != ESP_LOADER_SUCCESS) {
171+
qCritical().noquote().nospace() << "Erase failed (" << qstrerr(err) << ")";
172+
return err;
173+
}
174+
175+
if (_after == "hard_reset") {
176+
qInfo().noquote() << "Hard resetting via RTS pin...";
177+
loader_port_reset_target();
178+
}
179+
180+
qInfo().noquote() << "Done";
181+
182+
return ESP_LOADER_SUCCESS;
183+
}
184+
153185
/// Change to higher baud rate
154186
///
155187
/// \retval ESP_LOADER_SUCCESS Success
@@ -219,7 +251,7 @@ QSerialPort::SerialPortError EspFlasher::open(QString port, QString baud) {
219251
/// \param connect_config Timing parameters
220252
/// \retval ESP_LOADER_SUCCESS Success
221253
/// \retval ESP_LOADER_ERROR_FAIL Unspecified error
222-
/// \retval ESP_LOADER_ERROR_TIMEOUT Timeout elapsed
254+
/// \retval ESP_LOADER_ERROR_TIMEOUT Timeout
223255
/// \retval ESP_LOADER_ERROR_INVALID_PARAM Invalid parameter
224256
/// \retval ESP_LOADER_ERROR_INVALID_TARGET Connected target is invalid
225257
esp_loader_error_t
@@ -290,7 +322,7 @@ EspFlasher::connect(esp_loader_connect_args_t connect_config) {
290322
/// \param bin Binary
291323
/// \retval ESP_LOADER_SUCCESS Success
292324
/// \retval ESP_LOADER_ERROR_FAIL Unspecified error
293-
/// \retval ESP_LOADER_ERROR_TIMEOUT Timeout elapsed
325+
/// \retval ESP_LOADER_ERROR_TIMEOUT Timeout
294326
/// \retval ESP_LOADER_ERROR_INVALID_PARAM Invalid parameter
295327
esp_loader_error_t EspFlasher::flash(Bin const& bin) {
296328
constexpr uint32_t block_size{1024u};
@@ -358,7 +390,7 @@ esp_loader_error_t EspFlasher::flash(Bin const& bin) {
358390
/// \param size Number of bytes to read
359391
/// \param timeout Timeout in milliseconds
360392
/// \retval ESP_LOADER_SUCCESS Success
361-
/// \retval ESP_LOADER_ERROR_TIMEOUT Timeout elapsed
393+
/// \retval ESP_LOADER_ERROR_TIMEOUT Timeout
362394
esp_loader_error_t
363395
EspFlasher::loader_port_read(uint8_t* data, uint16_t size, uint32_t timeout) {
364396
assert(_serial && _serial->isOpen());
@@ -381,7 +413,7 @@ EspFlasher::loader_port_read(uint8_t* data, uint16_t size, uint32_t timeout) {
381413
/// \param size Size of data in bytes
382414
/// \param timeout Timeout in milliseconds
383415
/// \retval ESP_LOADER_SUCCESS Success
384-
/// \retval ESP_LOADER_ERROR_TIMEOUT Timeout elapsed
416+
/// \retval ESP_LOADER_ERROR_TIMEOUT Timeout
385417
esp_loader_error_t EspFlasher::loader_port_write(uint8_t const* data,
386418
uint16_t size,
387419
uint32_t timeout) {

src/cli.cpp

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -59,15 +59,16 @@ int print_available_ports() {
5959

6060
/// Execute write_flash command
6161
///
62-
/// \retval 0 Success
63-
/// \retval -1 Error
62+
/// \param parser Command line parser
63+
/// \retval 0 Success
64+
/// \retval -1 Error
6465
int write_flash(QCommandLineParser const& parser) {
6566
auto pos_args{parser.positionalArguments()};
6667
pos_args.pop_front();
6768

6869
if (pos_args.size() % 2) {
69-
qCritical() << "write_flash: error: argument <offset> <filename>: Must be "
70-
"pairs of an offset and the binary filename to write there";
70+
qCritical() << "write_flash: error: argument <address> <filename>: Must be "
71+
"pairs of an address and the binary filename to write there";
7172
return -1;
7273
}
7374

@@ -88,14 +89,15 @@ int write_flash(QCommandLineParser const& parser) {
8889
bool ok{};
8990
auto const offset{pos_args[i].toUInt(&ok, 0)};
9091
if (!ok) {
91-
qCritical() << "write_flash: error: argument <offset> <filename>: Offset"
92-
<< pos_args[i] << "must be a number";
92+
qCritical()
93+
<< "write_flash: error: argument <address> <filename>: Address"
94+
<< pos_args[i] << "must be a number";
9395
return -1;
9496
}
9597

9698
QFile file{pos_args[i + 1]};
9799
if (!file.open(QIODeviceBase::ReadOnly)) {
98-
qCritical() << "write_flash: error: argument <offset> <filename>: No "
100+
qCritical() << "write_flash: error: argument <address> <filename>: No "
99101
"such file or directory:"
100102
<< pos_args[i + 1];
101103
return -1;
@@ -107,6 +109,27 @@ int write_flash(QCommandLineParser const& parser) {
107109
return esp_flasher.flash();
108110
}
109111

112+
/// Execute erase_flash command
113+
///
114+
/// \param parser Command line parser
115+
/// \retval 0 Success
116+
/// \retval -1 Error
117+
int erase_flash(QCommandLineParser const& parser) {
118+
// Defaults
119+
QString const chip{parser.isSet("chip") ? parser.value("chip") : "auto"};
120+
QString const port{parser.isSet("port") ? parser.value("port") : "auto"};
121+
QString const baud{parser.isSet("baud") ? parser.value("baud") : "auto"};
122+
QString const before{parser.isSet("before") ? parser.value("before")
123+
: "default_reset"};
124+
QString const after{parser.isSet("after") ? parser.value("after")
125+
: "hard_reset"};
126+
QString const no_stub{parser.isSet("no-stub") ? "no-stub" : ""};
127+
QString const trace{parser.isSet("trace") ? "trace" : ""};
128+
129+
EspFlasher esp_flasher{chip, port, baud, before, after, no_stub, trace};
130+
return esp_flasher.erase();
131+
}
132+
110133
} // namespace
111134

112135
/// Run CLI
@@ -137,9 +160,12 @@ int cli(QApplication const& app) {
137160
});
138161

139162
// Add commands
140-
parser.addPositionalArgument("write_flash",
141-
"Write a binary blob to flash\nwrite_flash "
142-
"<offset> <filename> [<offset> <filename> ...]");
163+
parser.addPositionalArgument(
164+
"write_flash",
165+
"Write a binary blob to flash\nwrite_flash "
166+
"<address> <filename> [<address> <filename> ...]");
167+
parser.addPositionalArgument("erase_flash",
168+
"Perform Chip Erase on SPI flash");
143169

144170
// Parse arguments
145171
parser.process(app);
@@ -150,5 +176,6 @@ int cli(QApplication const& app) {
150176
// Execute commands
151177
if (auto pos_args{parser.positionalArguments()}; !pos_args.size()) return 0;
152178
else if (pos_args.first() == "write_flash") return write_flash(parser);
179+
else if (pos_args.first() == "erase_flash") return erase_flash(parser);
153180
else return -1;
154181
}

src/com_box.cpp

Lines changed: 42 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,20 @@
1717

1818
/// Create layout of various dropdown menus and a start/stop button
1919
ComBox::ComBox(QWidget* parent) : QGroupBox{parent} {
20-
// Start/stop button
20+
// Flash button
2121
QPixmap pixmap_off{":/dark/play.svg"};
2222
QPixmap pixmap_on{":/dark/stop.svg"};
2323
QIcon ico;
2424
ico.addPixmap(pixmap_off, QIcon::Normal, QIcon::Off);
2525
ico.addPixmap(pixmap_on, QIcon::Normal, QIcon::On);
26-
_start_stop_button->setIcon(ico);
27-
_start_stop_button->setText("Start");
28-
_start_stop_button->setCheckable(true);
26+
_flash_button->setIcon(ico);
27+
_flash_button->setText("Flash");
28+
_flash_button->setCheckable(true);
29+
30+
// Erase button
31+
_erase_button->setIcon(ico);
32+
_erase_button->setText("Erase");
33+
_erase_button->setCheckable(true);
2934

3035
// Add before/after options
3136
for (auto const& before : befores) _before_combobox->addItem(before);
@@ -69,7 +74,8 @@ ComBox::ComBox(QWidget* parent) : QGroupBox{parent} {
6974
// Workaround: top margin must be zero for the layout to be vertically
7075
// centered
7176
layout->setContentsMargins(11, 0, 11, 11);
72-
layout->addWidget(_start_stop_button, 0, 0);
77+
layout->addWidget(_flash_button, 0, 0);
78+
layout->addWidget(_erase_button, 1, 0);
7379
layout->addWidget(new QLabel{"Before"}, 0, 1, Qt::AlignRight);
7480
layout->addWidget(new QLabel{"After"}, 1, 1, Qt::AlignRight);
7581
layout->addWidget(_before_combobox, 0, 2);
@@ -84,24 +90,43 @@ ComBox::ComBox(QWidget* parent) : QGroupBox{parent} {
8490
layout->addWidget(_baud_combobox, 2, 4);
8591
setLayout(layout);
8692

87-
connect(_start_stop_button,
88-
&QPushButton::clicked,
89-
this,
90-
&ComBox::startStopButtonClicked);
93+
connect(
94+
_flash_button, &QPushButton::clicked, this, &ComBox::flashButtonClicked);
95+
connect(
96+
_erase_button, &QPushButton::clicked, this, &ComBox::eraseButtonClicked);
9197
}
9298

9399
/// Set binaries slot
94100
///
95101
/// \param bins Binaries
96102
void ComBox::binaries(QVector<Bin> bins) { _bins = bins; }
97103

98-
/// Start/stop button slot
104+
/// Flash slot
105+
///
106+
/// \param start Start or stop flashing
107+
void ComBox::flashButtonClicked(bool start) {
108+
buttonClicked(start, _flash_button, &EspFlasher::flash);
109+
}
110+
111+
/// Erase slot
99112
///
100-
/// \param start
101-
void ComBox::startStopButtonClicked(bool start) {
113+
/// \param start Start or stop erasing
114+
void ComBox::eraseButtonClicked(bool start) {
115+
buttonClicked(start, _erase_button, &EspFlasher::erase);
116+
}
117+
118+
/// Flash or erase slot
119+
///
120+
/// \param start Start or stop action
121+
/// \param button Button used
122+
/// \param action Action to start or stop
123+
void ComBox::buttonClicked(bool start,
124+
QPushButton* button,
125+
esp_loader_error_t (EspFlasher::*action)()) {
102126
// Start thread
103127
if (start) {
104-
_start_stop_button->setText("Stop");
128+
auto text{button->text()};
129+
button->setText("Stop");
105130

106131
QString const chip{_chip_combobox->currentText()};
107132
QString const port{_port_combobox->currentText()};
@@ -119,10 +144,7 @@ void ComBox::startStopButtonClicked(bool start) {
119144
_esp_flasher->moveToThread(_thread);
120145

121146
// Thread starts loader
122-
connect(_thread,
123-
&QThread::started,
124-
_esp_flasher,
125-
qOverload<>(&EspFlasher::flash));
147+
connect(_thread, &QThread::started, _esp_flasher, action);
126148

127149
// When loader finishes, quit thread and delete loader
128150
connect(_esp_flasher, &EspFlasher::finished, _thread, &QThread::quit);
@@ -135,9 +157,9 @@ void ComBox::startStopButtonClicked(bool start) {
135157
connect(_thread, &QThread::finished, _thread, &QThread::deleteLater);
136158

137159
// Once thread is destroyed, reset button
138-
connect(_thread, &QThread::destroyed, [this] {
139-
_start_stop_button->setChecked(false);
140-
_start_stop_button->setText("Start");
160+
connect(_thread, &QThread::destroyed, [this, button, text] {
161+
button->setChecked(false);
162+
button->setText(text);
141163
});
142164

143165
_thread->start();

src/com_box.hpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,17 +32,23 @@ public slots:
3232
void binaries(QVector<Bin> bins);
3333

3434
private slots:
35-
void startStopButtonClicked(bool start);
35+
void flashButtonClicked(bool start);
36+
void eraseButtonClicked(bool start);
3637

3738
private:
39+
void buttonClicked(bool start,
40+
QPushButton* button,
41+
esp_loader_error_t (EspFlasher::*action)());
42+
3843
QComboBox* _chip_combobox{new QComboBox};
3944
QComboBox* _port_combobox{new QComboBox};
4045
QComboBox* _baud_combobox{new QComboBox};
4146
QComboBox* _before_combobox{new QComboBox};
4247
QComboBox* _after_combobox{new QComboBox};
4348
QCheckBox* _no_stub_checkbox{new QCheckBox};
4449
QCheckBox* _trace_checkbox{new QCheckBox};
45-
QPushButton* _start_stop_button{new QPushButton};
50+
QPushButton* _flash_button{new QPushButton};
51+
QPushButton* _erase_button{new QPushButton};
4652
QVector<Bin> _bins{};
4753
QThread* _thread{};
4854
EspFlasher* _esp_flasher{};

0 commit comments

Comments
 (0)