ESPHome  2024.4.1
stm32flash.cpp
Go to the documentation of this file.
1 /*
2  stm32flash - Open Source ST STM32 flash program for Arduino
3  Copyright 2010 Geoffrey McRae <[email protected]>
4  Copyright 2012-2014 Tormod Volden <[email protected]>
5 
6  This program is free software; you can redistribute it and/or
7  modify it under the terms of the GNU General Public License
8  as published by the Free Software Foundation; either version 2
9  of the License, or (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program; if not, write to the Free Software
18  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
20 
21 #include "esphome/core/defines.h"
22 #ifdef USE_SHD_FIRMWARE_DATA
23 
24 #include <cstdint>
25 
26 #include "stm32flash.h"
27 #include "debug.h"
28 
29 #include "dev_table.h"
30 #include "esphome/core/log.h"
31 
32 #include <algorithm>
33 #include <memory>
34 
35 namespace {
36 
37 constexpr uint8_t STM32_ACK = 0x79;
38 constexpr uint8_t STM32_NACK = 0x1F;
39 constexpr uint8_t STM32_BUSY = 0x76;
40 
41 constexpr uint8_t STM32_CMD_INIT = 0x7F;
42 constexpr uint8_t STM32_CMD_GET = 0x00; /* get the version and command supported */
43 constexpr uint8_t STM32_CMD_GVR = 0x01; /* get version and read protection status */
44 constexpr uint8_t STM32_CMD_GID = 0x02; /* get ID */
45 constexpr uint8_t STM32_CMD_RM = 0x11; /* read memory */
46 constexpr uint8_t STM32_CMD_GO = 0x21; /* go */
47 constexpr uint8_t STM32_CMD_WM = 0x31; /* write memory */
48 constexpr uint8_t STM32_CMD_WM_NS = 0x32; /* no-stretch write memory */
49 constexpr uint8_t STM32_CMD_ER = 0x43; /* erase */
50 constexpr uint8_t STM32_CMD_EE = 0x44; /* extended erase */
51 constexpr uint8_t STM32_CMD_EE_NS = 0x45; /* extended erase no-stretch */
52 constexpr uint8_t STM32_CMD_WP = 0x63; /* write protect */
53 constexpr uint8_t STM32_CMD_WP_NS = 0x64; /* write protect no-stretch */
54 constexpr uint8_t STM32_CMD_UW = 0x73; /* write unprotect */
55 constexpr uint8_t STM32_CMD_UW_NS = 0x74; /* write unprotect no-stretch */
56 constexpr uint8_t STM32_CMD_RP = 0x82; /* readout protect */
57 constexpr uint8_t STM32_CMD_RP_NS = 0x83; /* readout protect no-stretch */
58 constexpr uint8_t STM32_CMD_UR = 0x92; /* readout unprotect */
59 constexpr uint8_t STM32_CMD_UR_NS = 0x93; /* readout unprotect no-stretch */
60 constexpr uint8_t STM32_CMD_CRC = 0xA1; /* compute CRC */
61 constexpr uint8_t STM32_CMD_ERR = 0xFF; /* not a valid command */
62 
63 constexpr uint32_t STM32_RESYNC_TIMEOUT = 35 * 1000; /* milliseconds */
64 constexpr uint32_t STM32_MASSERASE_TIMEOUT = 35 * 1000; /* milliseconds */
65 constexpr uint32_t STM32_PAGEERASE_TIMEOUT = 5 * 1000; /* milliseconds */
66 constexpr uint32_t STM32_BLKWRITE_TIMEOUT = 1 * 1000; /* milliseconds */
67 constexpr uint32_t STM32_WUNPROT_TIMEOUT = 1 * 1000; /* milliseconds */
68 constexpr uint32_t STM32_WPROT_TIMEOUT = 1 * 1000; /* milliseconds */
69 constexpr uint32_t STM32_RPROT_TIMEOUT = 1 * 1000; /* milliseconds */
70 constexpr uint32_t DEFAULT_TIMEOUT = 5 * 1000; /* milliseconds */
71 
72 constexpr uint8_t STM32_CMD_GET_LENGTH = 17; /* bytes in the reply */
73 
74 /* Reset code for ARMv7-M (Cortex-M3) and ARMv6-M (Cortex-M0)
75  * see ARMv7-M or ARMv6-M Architecture Reference Manual (table B3-8)
76  * or "The definitive guide to the ARM Cortex-M3", section 14.4.
77  */
78 constexpr uint8_t STM_RESET_CODE[] = {
79  0x01, 0x49, // ldr r1, [pc, #4] ; (<AIRCR_OFFSET>)
80  0x02, 0x4A, // ldr r2, [pc, #8] ; (<AIRCR_RESET_VALUE>)
81  0x0A, 0x60, // str r2, [r1, #0]
82  0xfe, 0xe7, // endless: b endless
83  0x0c, 0xed, 0x00, 0xe0, // .word 0xe000ed0c <AIRCR_OFFSET> = NVIC AIRCR register address
84  0x04, 0x00, 0xfa, 0x05 // .word 0x05fa0004 <AIRCR_RESET_VALUE> = VECTKEY | SYSRESETREQ
85 };
86 
87 constexpr uint32_t STM_RESET_CODE_SIZE = sizeof(STM_RESET_CODE);
88 
89 /* RM0360, Empty check
90  * On STM32F070x6 and STM32F030xC devices only, internal empty check flag is
91  * implemented to allow easy programming of the virgin devices by the boot loader. This flag is
92  * used when BOOT0 pin is defining Main Flash memory as the target boot space. When the
93  * flag is set, the device is considered as empty and System memory (boot loader) is selected
94  * instead of the Main Flash as a boot space to allow user to program the Flash memory.
95  * This flag is updated only during Option bytes loading: it is set when the content of the
96  * address 0x08000 0000 is read as 0xFFFF FFFF, otherwise it is cleared. It means a power
97  * on or setting of OBL_LAUNCH bit in FLASH_CR register is needed to clear this flag after
98  * programming of a virgin device to execute user code after System reset.
99  */
100 constexpr uint8_t STM_OBL_LAUNCH_CODE[] = {
101  0x01, 0x49, // ldr r1, [pc, #4] ; (<FLASH_CR>)
102  0x02, 0x4A, // ldr r2, [pc, #8] ; (<OBL_LAUNCH>)
103  0x0A, 0x60, // str r2, [r1, #0]
104  0xfe, 0xe7, // endless: b endless
105  0x10, 0x20, 0x02, 0x40, // address: FLASH_CR = 40022010
106  0x00, 0x20, 0x00, 0x00 // value: OBL_LAUNCH = 00002000
107 };
108 
109 constexpr uint32_t STM_OBL_LAUNCH_CODE_SIZE = sizeof(STM_OBL_LAUNCH_CODE);
110 
111 constexpr char TAG[] = "stm32flash";
112 
113 } // Anonymous namespace
114 
115 namespace esphome {
116 namespace shelly_dimmer {
117 
118 namespace {
119 
120 int flash_addr_to_page_ceil(const stm32_unique_ptr &stm, uint32_t addr) {
121  if (!(addr >= stm->dev->fl_start && addr <= stm->dev->fl_end))
122  return 0;
123 
124  int page = 0;
125  addr -= stm->dev->fl_start;
126  const auto *psize = stm->dev->fl_ps;
127 
128  while (addr >= psize[0]) {
129  addr -= psize[0];
130  page++;
131  if (psize[1])
132  psize++;
133  }
134 
135  return addr ? page + 1 : page;
136 }
137 
138 stm32_err_t stm32_get_ack_timeout(const stm32_unique_ptr &stm, uint32_t timeout) {
139  auto *stream = stm->stream;
140  uint8_t rxbyte;
141 
142  if (!(stm->flags & STREAM_OPT_RETRY))
143  timeout = 0;
144 
145  if (timeout == 0)
146  timeout = DEFAULT_TIMEOUT;
147 
148  const uint32_t start_time = millis();
149  do {
150  yield();
151  if (!stream->available()) {
152  if (millis() < start_time + timeout)
153  continue;
154  ESP_LOGD(TAG, "Failed to read ACK timeout=%i", timeout);
155  return STM32_ERR_UNKNOWN;
156  }
157 
158  stream->read_byte(&rxbyte);
159 
160  if (rxbyte == STM32_ACK)
161  return STM32_ERR_OK;
162  if (rxbyte == STM32_NACK)
163  return STM32_ERR_NACK;
164  if (rxbyte != STM32_BUSY) {
165  ESP_LOGD(TAG, "Got byte 0x%02x instead of ACK", rxbyte);
166  return STM32_ERR_UNKNOWN;
167  }
168  } while (true);
169 }
170 
171 stm32_err_t stm32_get_ack(const stm32_unique_ptr &stm) { return stm32_get_ack_timeout(stm, 0); }
172 
173 stm32_err_t stm32_send_command_timeout(const stm32_unique_ptr &stm, const uint8_t cmd, const uint32_t timeout) {
174  auto *const stream = stm->stream;
175 
176  static constexpr auto BUFFER_SIZE = 2;
177  const uint8_t buf[] = {
178  cmd,
179  static_cast<uint8_t>(cmd ^ 0xFF),
180  };
181  static_assert(sizeof(buf) == BUFFER_SIZE, "Buf expected to be 2 bytes");
182 
183  stream->write_array(buf, BUFFER_SIZE);
184  stream->flush();
185 
186  stm32_err_t s_err = stm32_get_ack_timeout(stm, timeout);
187  if (s_err == STM32_ERR_OK)
188  return STM32_ERR_OK;
189  if (s_err == STM32_ERR_NACK) {
190  ESP_LOGD(TAG, "Got NACK from device on command 0x%02x", cmd);
191  } else {
192  ESP_LOGD(TAG, "Unexpected reply from device on command 0x%02x", cmd);
193  }
194  return STM32_ERR_UNKNOWN;
195 }
196 
197 stm32_err_t stm32_send_command(const stm32_unique_ptr &stm, const uint8_t cmd) {
198  return stm32_send_command_timeout(stm, cmd, 0);
199 }
200 
201 /* if we have lost sync, send a wrong command and expect a NACK */
202 stm32_err_t stm32_resync(const stm32_unique_ptr &stm) {
203  auto *const stream = stm->stream;
204  uint32_t t0 = millis();
205  auto t1 = t0;
206 
207  static constexpr auto BUFFER_SIZE = 2;
208  const uint8_t buf[] = {
209  STM32_CMD_ERR,
210  static_cast<uint8_t>(STM32_CMD_ERR ^ 0xFF),
211  };
212  static_assert(sizeof(buf) == BUFFER_SIZE, "Buf expected to be 2 bytes");
213 
214  uint8_t ack;
215  while (t1 < t0 + STM32_RESYNC_TIMEOUT) {
216  stream->write_array(buf, BUFFER_SIZE);
217  stream->flush();
218  if (!stream->read_array(&ack, 1)) {
219  t1 = millis();
220  continue;
221  }
222  if (ack == STM32_NACK)
223  return STM32_ERR_OK;
224  t1 = millis();
225  }
226  return STM32_ERR_UNKNOWN;
227 }
228 
229 /*
230  * some command receive reply frame with variable length, and length is
231  * embedded in reply frame itself.
232  * We can guess the length, but if we guess wrong the protocol gets out
233  * of sync.
234  * Use resync for frame oriented interfaces (e.g. I2C) and byte-by-byte
235  * read for byte oriented interfaces (e.g. UART).
236  *
237  * to run safely, data buffer should be allocated for 256+1 bytes
238  *
239  * len is value of the first byte in the frame.
240  */
241 stm32_err_t stm32_guess_len_cmd(const stm32_unique_ptr &stm, const uint8_t cmd, uint8_t *const data, unsigned int len) {
242  auto *const stream = stm->stream;
243 
244  if (stm32_send_command(stm, cmd) != STM32_ERR_OK)
245  return STM32_ERR_UNKNOWN;
246  if (stm->flags & STREAM_OPT_BYTE) {
247  /* interface is UART-like */
248  if (!stream->read_array(data, 1))
249  return STM32_ERR_UNKNOWN;
250  len = data[0];
251  if (!stream->read_array(data + 1, len + 1))
252  return STM32_ERR_UNKNOWN;
253  return STM32_ERR_OK;
254  }
255 
256  const auto ret = stream->read_array(data, len + 2);
257  if (ret && len == data[0])
258  return STM32_ERR_OK;
259  if (!ret) {
260  /* restart with only one byte */
261  if (stm32_resync(stm) != STM32_ERR_OK)
262  return STM32_ERR_UNKNOWN;
263  if (stm32_send_command(stm, cmd) != STM32_ERR_OK)
264  return STM32_ERR_UNKNOWN;
265  if (!stream->read_array(data, 1))
266  return STM32_ERR_UNKNOWN;
267  }
268 
269  ESP_LOGD(TAG, "Re sync (len = %d)", data[0]);
270  if (stm32_resync(stm) != STM32_ERR_OK)
271  return STM32_ERR_UNKNOWN;
272 
273  len = data[0];
274  if (stm32_send_command(stm, cmd) != STM32_ERR_OK)
275  return STM32_ERR_UNKNOWN;
276 
277  if (!stream->read_array(data, len + 2))
278  return STM32_ERR_UNKNOWN;
279  return STM32_ERR_OK;
280 }
281 
282 /*
283  * Some interface, e.g. UART, requires a specific init sequence to let STM32
284  * autodetect the interface speed.
285  * The sequence is only required one time after reset.
286  * This function sends the init sequence and, in case of timeout, recovers
287  * the interface.
288  */
289 stm32_err_t stm32_send_init_seq(const stm32_unique_ptr &stm) {
290  auto *const stream = stm->stream;
291 
292  stream->write_array(&STM32_CMD_INIT, 1);
293  stream->flush();
294 
295  uint8_t byte;
296  bool ret = stream->read_array(&byte, 1);
297  if (ret && byte == STM32_ACK)
298  return STM32_ERR_OK;
299  if (ret && byte == STM32_NACK) {
300  /* We could get error later, but let's continue, for now. */
301  ESP_LOGD(TAG, "Warning: the interface was not closed properly.");
302  return STM32_ERR_OK;
303  }
304  if (!ret) {
305  ESP_LOGD(TAG, "Failed to init device.");
306  return STM32_ERR_UNKNOWN;
307  }
308 
309  /*
310  * Check if previous STM32_CMD_INIT was taken as first byte
311  * of a command. Send a new byte, we should get back a NACK.
312  */
313  stream->write_array(&STM32_CMD_INIT, 1);
314  stream->flush();
315 
316  ret = stream->read_array(&byte, 1);
317  if (ret && byte == STM32_NACK)
318  return STM32_ERR_OK;
319  ESP_LOGD(TAG, "Failed to init device.");
320  return STM32_ERR_UNKNOWN;
321 }
322 
323 stm32_err_t stm32_mass_erase(const stm32_unique_ptr &stm) {
324  auto *const stream = stm->stream;
325 
326  if (stm32_send_command(stm, stm->cmd->er) != STM32_ERR_OK) {
327  ESP_LOGD(TAG, "Can't initiate chip mass erase!");
328  return STM32_ERR_UNKNOWN;
329  }
330 
331  /* regular erase (0x43) */
332  if (stm->cmd->er == STM32_CMD_ER) {
333  const auto s_err = stm32_send_command_timeout(stm, 0xFF, STM32_MASSERASE_TIMEOUT);
334  if (s_err != STM32_ERR_OK) {
335  return STM32_ERR_UNKNOWN;
336  }
337  return STM32_ERR_OK;
338  }
339 
340  /* extended erase */
341  static constexpr auto BUFFER_SIZE = 3;
342  const uint8_t buf[] = {
343  0xFF, /* 0xFFFF the magic number for mass erase */
344  0xFF, 0x00, /* checksum */
345  };
346  static_assert(sizeof(buf) == BUFFER_SIZE, "Expected the buffer to be 3 bytes");
347  stream->write_array(buf, 3);
348  stream->flush();
349 
350  const auto s_err = stm32_get_ack_timeout(stm, STM32_MASSERASE_TIMEOUT);
351  if (s_err != STM32_ERR_OK) {
352  ESP_LOGD(TAG, "Mass erase failed. Try specifying the number of pages to be erased.");
353  return STM32_ERR_UNKNOWN;
354  }
355  return STM32_ERR_OK;
356 }
357 
358 template<typename T> std::unique_ptr<T[], void (*)(T *memory)> malloc_array_raii(size_t size) {
359  // Could be constexpr in c++17
360  static const auto DELETOR = [](T *memory) {
361  free(memory); // NOLINT
362  };
363  return std::unique_ptr<T[], decltype(DELETOR)>{static_cast<T *>(malloc(size)), // NOLINT
364  DELETOR};
365 }
366 
367 stm32_err_t stm32_pages_erase(const stm32_unique_ptr &stm, const uint32_t spage, const uint32_t pages) {
368  auto *const stream = stm->stream;
369  uint8_t cs = 0;
370  int i = 0;
371 
372  /* The erase command reported by the bootloader is either 0x43, 0x44 or 0x45 */
373  /* 0x44 is Extended Erase, a 2 byte based protocol and needs to be handled differently. */
374  /* 0x45 is clock no-stretching version of Extended Erase for I2C port. */
375  if (stm32_send_command(stm, stm->cmd->er) != STM32_ERR_OK) {
376  ESP_LOGD(TAG, "Can't initiate chip mass erase!");
377  return STM32_ERR_UNKNOWN;
378  }
379 
380  /* regular erase (0x43) */
381  if (stm->cmd->er == STM32_CMD_ER) {
382  // Free memory with RAII
383  auto buf = malloc_array_raii<uint8_t>(1 + pages + 1);
384 
385  if (!buf)
386  return STM32_ERR_UNKNOWN;
387 
388  buf[i++] = pages - 1;
389  cs ^= (pages - 1);
390  for (auto pg_num = spage; pg_num < (pages + spage); pg_num++) {
391  buf[i++] = pg_num;
392  cs ^= pg_num;
393  }
394  buf[i++] = cs;
395  stream->write_array(&buf[0], i);
396  stream->flush();
397 
398  const auto s_err = stm32_get_ack_timeout(stm, pages * STM32_PAGEERASE_TIMEOUT);
399  if (s_err != STM32_ERR_OK) {
400  return STM32_ERR_UNKNOWN;
401  }
402  return STM32_ERR_OK;
403  }
404 
405  /* extended erase */
406 
407  // Free memory with RAII
408  auto buf = malloc_array_raii<uint8_t>(2 + 2 * pages + 1);
409 
410  if (!buf)
411  return STM32_ERR_UNKNOWN;
412 
413  /* Number of pages to be erased - 1, two bytes, MSB first */
414  uint8_t pg_byte = (pages - 1) >> 8;
415  buf[i++] = pg_byte;
416  cs ^= pg_byte;
417  pg_byte = (pages - 1) & 0xFF;
418  buf[i++] = pg_byte;
419  cs ^= pg_byte;
420 
421  for (auto pg_num = spage; pg_num < spage + pages; pg_num++) {
422  pg_byte = pg_num >> 8;
423  cs ^= pg_byte;
424  buf[i++] = pg_byte;
425  pg_byte = pg_num & 0xFF;
426  cs ^= pg_byte;
427  buf[i++] = pg_byte;
428  }
429  buf[i++] = cs;
430  stream->write_array(&buf[0], i);
431  stream->flush();
432 
433  const auto s_err = stm32_get_ack_timeout(stm, pages * STM32_PAGEERASE_TIMEOUT);
434  if (s_err != STM32_ERR_OK) {
435  ESP_LOGD(TAG, "Page-by-page erase failed. Check the maximum pages your device supports.");
436  return STM32_ERR_UNKNOWN;
437  }
438 
439  return STM32_ERR_OK;
440 }
441 
442 template<typename T> stm32_err_t stm32_check_ack_timeout(const stm32_err_t s_err, const T &&log) {
443  switch (s_err) {
444  case STM32_ERR_OK:
445  return STM32_ERR_OK;
446  case STM32_ERR_NACK:
447  log();
448  // TODO: c++17 [[fallthrough]]
449  /* fallthrough */
450  default:
451  return STM32_ERR_UNKNOWN;
452  }
453 }
454 
455 /* detect CPU endian */
456 bool cpu_le() {
457  static constexpr int N = 1;
458 
459  // returns true if little endian
460  return *reinterpret_cast<const char *>(&N) == 1;
461 }
462 
463 uint32_t le_u32(const uint32_t v) {
464  if (!cpu_le())
465  return ((v & 0xFF000000) >> 24) | ((v & 0x00FF0000) >> 8) | ((v & 0x0000FF00) << 8) | ((v & 0x000000FF) << 24);
466  return v;
467 }
468 
469 template<size_t N> void populate_buffer_with_address(uint8_t (&buffer)[N], uint32_t address) {
470  buffer[0] = static_cast<uint8_t>(address >> 24);
471  buffer[1] = static_cast<uint8_t>((address >> 16) & 0xFF);
472  buffer[2] = static_cast<uint8_t>((address >> 8) & 0xFF);
473  buffer[3] = static_cast<uint8_t>(address & 0xFF);
474  buffer[4] = static_cast<uint8_t>(buffer[0] ^ buffer[1] ^ buffer[2] ^ buffer[3]);
475 }
476 
477 template<typename T> stm32_unique_ptr make_stm32_with_deletor(T ptr) {
478  static const auto CLOSE = [](stm32_t *stm32) {
479  if (stm32) {
480  free(stm32->cmd); // NOLINT
481  }
482  free(stm32); // NOLINT
483  };
484 
485  // Cleanup with RAII
486  return std::unique_ptr<stm32_t, decltype(CLOSE)>{ptr, CLOSE};
487 }
488 
489 } // Anonymous namespace
490 
491 } // namespace shelly_dimmer
492 } // namespace esphome
493 
494 namespace esphome {
495 namespace shelly_dimmer {
496 
497 /* find newer command by higher code */
498 #define newer(prev, a) (((prev) == STM32_CMD_ERR) ? (a) : (((prev) > (a)) ? (prev) : (a)))
499 
500 stm32_unique_ptr stm32_init(uart::UARTDevice *stream, const uint8_t flags, const char init) {
501  uint8_t buf[257];
502 
503  auto stm = make_stm32_with_deletor(static_cast<stm32_t *>(calloc(sizeof(stm32_t), 1))); // NOLINT
504 
505  if (!stm) {
506  return make_stm32_with_deletor(nullptr);
507  }
508  stm->stream = stream;
509  stm->flags = flags;
510 
511  stm->cmd = static_cast<stm32_cmd_t *>(malloc(sizeof(stm32_cmd_t))); // NOLINT
512  if (!stm->cmd) {
513  return make_stm32_with_deletor(nullptr);
514  }
515  memset(stm->cmd, STM32_CMD_ERR, sizeof(stm32_cmd_t));
516 
517  if ((stm->flags & STREAM_OPT_CMD_INIT) && init) {
518  if (stm32_send_init_seq(stm) != STM32_ERR_OK)
519  return make_stm32_with_deletor(nullptr);
520  }
521 
522  /* get the version and read protection status */
523  if (stm32_send_command(stm, STM32_CMD_GVR) != STM32_ERR_OK) {
524  return make_stm32_with_deletor(nullptr);
525  }
526 
527  /* From AN, only UART bootloader returns 3 bytes */
528  {
529  const auto len = (stm->flags & STREAM_OPT_GVR_ETX) ? 3 : 1;
530  if (!stream->read_array(buf, len))
531  return make_stm32_with_deletor(nullptr);
532 
533  stm->version = buf[0];
534  stm->option1 = (stm->flags & STREAM_OPT_GVR_ETX) ? buf[1] : 0;
535  stm->option2 = (stm->flags & STREAM_OPT_GVR_ETX) ? buf[2] : 0;
536  if (stm32_get_ack(stm) != STM32_ERR_OK) {
537  return make_stm32_with_deletor(nullptr);
538  }
539  }
540 
541  {
542  const auto len = ([&]() {
543  /* get the bootloader information */
544  if (stm->cmd_get_reply) {
545  for (auto i = 0; stm->cmd_get_reply[i].length; ++i) {
546  if (stm->version == stm->cmd_get_reply[i].version) {
547  return stm->cmd_get_reply[i].length;
548  }
549  }
550  }
551 
552  return STM32_CMD_GET_LENGTH;
553  })();
554 
555  if (stm32_guess_len_cmd(stm, STM32_CMD_GET, buf, len) != STM32_ERR_OK)
556  return make_stm32_with_deletor(nullptr);
557  }
558 
559  const auto stop = buf[0] + 1;
560  stm->bl_version = buf[1];
561  int new_cmds = 0;
562  for (auto i = 1; i < stop; ++i) {
563  const auto val = buf[i + 1];
564  switch (val) {
565  case STM32_CMD_GET:
566  stm->cmd->get = val;
567  break;
568  case STM32_CMD_GVR:
569  stm->cmd->gvr = val;
570  break;
571  case STM32_CMD_GID:
572  stm->cmd->gid = val;
573  break;
574  case STM32_CMD_RM:
575  stm->cmd->rm = val;
576  break;
577  case STM32_CMD_GO:
578  stm->cmd->go = val;
579  break;
580  case STM32_CMD_WM:
581  case STM32_CMD_WM_NS:
582  stm->cmd->wm = newer(stm->cmd->wm, val);
583  break;
584  case STM32_CMD_ER:
585  case STM32_CMD_EE:
586  case STM32_CMD_EE_NS:
587  stm->cmd->er = newer(stm->cmd->er, val);
588  break;
589  case STM32_CMD_WP:
590  case STM32_CMD_WP_NS:
591  stm->cmd->wp = newer(stm->cmd->wp, val);
592  break;
593  case STM32_CMD_UW:
594  case STM32_CMD_UW_NS:
595  stm->cmd->uw = newer(stm->cmd->uw, val);
596  break;
597  case STM32_CMD_RP:
598  case STM32_CMD_RP_NS:
599  stm->cmd->rp = newer(stm->cmd->rp, val);
600  break;
601  case STM32_CMD_UR:
602  case STM32_CMD_UR_NS:
603  stm->cmd->ur = newer(stm->cmd->ur, val);
604  break;
605  case STM32_CMD_CRC:
606  stm->cmd->crc = newer(stm->cmd->crc, val);
607  break;
608  default:
609  if (new_cmds++ == 0) {
610  ESP_LOGD(TAG, "GET returns unknown commands (0x%2x", val);
611  } else {
612  ESP_LOGD(TAG, ", 0x%2x", val);
613  }
614  }
615  }
616  if (new_cmds) {
617  ESP_LOGD(TAG, ")");
618  }
619  if (stm32_get_ack(stm) != STM32_ERR_OK) {
620  return make_stm32_with_deletor(nullptr);
621  }
622 
623  if (stm->cmd->get == STM32_CMD_ERR || stm->cmd->gvr == STM32_CMD_ERR || stm->cmd->gid == STM32_CMD_ERR) {
624  ESP_LOGD(TAG, "Error: bootloader did not returned correct information from GET command");
625  return make_stm32_with_deletor(nullptr);
626  }
627 
628  /* get the device ID */
629  if (stm32_guess_len_cmd(stm, stm->cmd->gid, buf, 1) != STM32_ERR_OK) {
630  return make_stm32_with_deletor(nullptr);
631  }
632  const auto returned = buf[0] + 1;
633  if (returned < 2) {
634  ESP_LOGD(TAG, "Only %d bytes sent in the PID, unknown/unsupported device", returned);
635  return make_stm32_with_deletor(nullptr);
636  }
637  stm->pid = (buf[1] << 8) | buf[2];
638  if (returned > 2) {
639  ESP_LOGD(TAG, "This bootloader returns %d extra bytes in PID:", returned);
640  for (auto i = 2; i <= returned; i++)
641  ESP_LOGD(TAG, " %02x", buf[i]);
642  }
643  if (stm32_get_ack(stm) != STM32_ERR_OK) {
644  return make_stm32_with_deletor(nullptr);
645  }
646 
647  stm->dev = DEVICES;
648  while (stm->dev->id != 0x00 && stm->dev->id != stm->pid)
649  ++stm->dev;
650 
651  if (!stm->dev->id) {
652  ESP_LOGD(TAG, "Unknown/unsupported device (Device ID: 0x%03x)", stm->pid);
653  return make_stm32_with_deletor(nullptr);
654  }
655 
656  return stm;
657 }
658 
659 stm32_err_t stm32_read_memory(const stm32_unique_ptr &stm, const uint32_t address, uint8_t *data,
660  const unsigned int len) {
661  auto *const stream = stm->stream;
662 
663  if (!len)
664  return STM32_ERR_OK;
665 
666  if (len > 256) {
667  ESP_LOGD(TAG, "Error: READ length limit at 256 bytes");
668  return STM32_ERR_UNKNOWN;
669  }
670 
671  if (stm->cmd->rm == STM32_CMD_ERR) {
672  ESP_LOGD(TAG, "Error: READ command not implemented in bootloader.");
673  return STM32_ERR_NO_CMD;
674  }
675 
676  if (stm32_send_command(stm, stm->cmd->rm) != STM32_ERR_OK)
677  return STM32_ERR_UNKNOWN;
678 
679  static constexpr auto BUFFER_SIZE = 5;
680  uint8_t buf[BUFFER_SIZE];
681  populate_buffer_with_address(buf, address);
682 
683  stream->write_array(buf, BUFFER_SIZE);
684  stream->flush();
685 
686  if (stm32_get_ack(stm) != STM32_ERR_OK)
687  return STM32_ERR_UNKNOWN;
688 
689  if (stm32_send_command(stm, len - 1) != STM32_ERR_OK)
690  return STM32_ERR_UNKNOWN;
691 
692  if (!stream->read_array(data, len))
693  return STM32_ERR_UNKNOWN;
694 
695  return STM32_ERR_OK;
696 }
697 
698 stm32_err_t stm32_write_memory(const stm32_unique_ptr &stm, uint32_t address, const uint8_t *data,
699  const unsigned int len) {
700  auto *const stream = stm->stream;
701 
702  if (!len)
703  return STM32_ERR_OK;
704 
705  if (len > 256) {
706  ESP_LOGD(TAG, "Error: READ length limit at 256 bytes");
707  return STM32_ERR_UNKNOWN;
708  }
709 
710  /* must be 32bit aligned */
711  if (address & 0x3) {
712  ESP_LOGD(TAG, "Error: WRITE address must be 4 byte aligned");
713  return STM32_ERR_UNKNOWN;
714  }
715 
716  if (stm->cmd->wm == STM32_CMD_ERR) {
717  ESP_LOGD(TAG, "Error: WRITE command not implemented in bootloader.");
718  return STM32_ERR_NO_CMD;
719  }
720 
721  /* send the address and checksum */
722  if (stm32_send_command(stm, stm->cmd->wm) != STM32_ERR_OK)
723  return STM32_ERR_UNKNOWN;
724 
725  static constexpr auto BUFFER_SIZE = 5;
726  uint8_t buf1[BUFFER_SIZE];
727  populate_buffer_with_address(buf1, address);
728 
729  stream->write_array(buf1, BUFFER_SIZE);
730  stream->flush();
731  if (stm32_get_ack(stm) != STM32_ERR_OK)
732  return STM32_ERR_UNKNOWN;
733 
734  const unsigned int aligned_len = (len + 3) & ~3;
735  uint8_t cs = aligned_len - 1;
736  uint8_t buf[256 + 2];
737 
738  buf[0] = aligned_len - 1;
739  for (auto i = 0; i < len; i++) {
740  cs ^= data[i];
741  buf[i + 1] = data[i];
742  }
743  /* padding data */
744  for (auto i = len; i < aligned_len; i++) {
745  cs ^= 0xFF;
746  buf[i + 1] = 0xFF;
747  }
748  buf[aligned_len + 1] = cs;
749  stream->write_array(buf, aligned_len + 2);
750  stream->flush();
751 
752  const auto s_err = stm32_get_ack_timeout(stm, STM32_BLKWRITE_TIMEOUT);
753  if (s_err != STM32_ERR_OK) {
754  return STM32_ERR_UNKNOWN;
755  }
756  return STM32_ERR_OK;
757 }
758 
760  if (stm->cmd->uw == STM32_CMD_ERR) {
761  ESP_LOGD(TAG, "Error: WRITE UNPROTECT command not implemented in bootloader.");
762  return STM32_ERR_NO_CMD;
763  }
764 
765  if (stm32_send_command(stm, stm->cmd->uw) != STM32_ERR_OK)
766  return STM32_ERR_UNKNOWN;
767 
768  return stm32_check_ack_timeout(stm32_get_ack_timeout(stm, STM32_WUNPROT_TIMEOUT),
769  []() { ESP_LOGD(TAG, "Error: Failed to WRITE UNPROTECT"); });
770 }
771 
773  if (stm->cmd->wp == STM32_CMD_ERR) {
774  ESP_LOGD(TAG, "Error: WRITE PROTECT command not implemented in bootloader.");
775  return STM32_ERR_NO_CMD;
776  }
777 
778  if (stm32_send_command(stm, stm->cmd->wp) != STM32_ERR_OK)
779  return STM32_ERR_UNKNOWN;
780 
781  return stm32_check_ack_timeout(stm32_get_ack_timeout(stm, STM32_WPROT_TIMEOUT),
782  []() { ESP_LOGD(TAG, "Error: Failed to WRITE PROTECT"); });
783 }
784 
786  if (stm->cmd->ur == STM32_CMD_ERR) {
787  ESP_LOGD(TAG, "Error: READOUT UNPROTECT command not implemented in bootloader.");
788  return STM32_ERR_NO_CMD;
789  }
790 
791  if (stm32_send_command(stm, stm->cmd->ur) != STM32_ERR_OK)
792  return STM32_ERR_UNKNOWN;
793 
794  return stm32_check_ack_timeout(stm32_get_ack_timeout(stm, STM32_MASSERASE_TIMEOUT),
795  []() { ESP_LOGD(TAG, "Error: Failed to READOUT UNPROTECT"); });
796 }
797 
799  if (stm->cmd->rp == STM32_CMD_ERR) {
800  ESP_LOGD(TAG, "Error: READOUT PROTECT command not implemented in bootloader.");
801  return STM32_ERR_NO_CMD;
802  }
803 
804  if (stm32_send_command(stm, stm->cmd->rp) != STM32_ERR_OK)
805  return STM32_ERR_UNKNOWN;
806 
807  return stm32_check_ack_timeout(stm32_get_ack_timeout(stm, STM32_RPROT_TIMEOUT),
808  []() { ESP_LOGD(TAG, "Error: Failed to READOUT PROTECT"); });
809 }
810 
811 stm32_err_t stm32_erase_memory(const stm32_unique_ptr &stm, uint32_t spage, uint32_t pages) {
812  if (!pages || spage > STM32_MAX_PAGES || ((pages != STM32_MASS_ERASE) && ((spage + pages) > STM32_MAX_PAGES)))
813  return STM32_ERR_OK;
814 
815  if (stm->cmd->er == STM32_CMD_ERR) {
816  ESP_LOGD(TAG, "Error: ERASE command not implemented in bootloader.");
817  return STM32_ERR_NO_CMD;
818  }
819 
820  if (pages == STM32_MASS_ERASE) {
821  /*
822  * Not all chips support mass erase.
823  * Mass erase can be obtained executing a "readout protect"
824  * followed by "readout un-protect". This method is not
825  * suggested because can hang the target if a debug SWD/JTAG
826  * is connected. When the target enters in "readout
827  * protection" mode it will consider the debug connection as
828  * a tentative of intrusion and will hang.
829  * Erasing the flash page-by-page is the safer way to go.
830  */
831  if (!(stm->dev->flags & F_NO_ME))
832  return stm32_mass_erase(stm);
833 
834  pages = flash_addr_to_page_ceil(stm, stm->dev->fl_end);
835  }
836 
837  /*
838  * Some device, like STM32L152, cannot erase more than 512 pages in
839  * one command. Split the call.
840  */
841  static constexpr uint32_t MAX_PAGE_SIZE = 512;
842  while (pages) {
843  const auto n = std::min(pages, MAX_PAGE_SIZE);
844  const auto s_err = stm32_pages_erase(stm, spage, n);
845  if (s_err != STM32_ERR_OK)
846  return s_err;
847  spage += n;
848  pages -= n;
849  }
850  return STM32_ERR_OK;
851 }
852 
853 static stm32_err_t stm32_run_raw_code(const stm32_unique_ptr &stm, uint32_t target_address, const uint8_t *code,
854  uint32_t code_size) {
855  static constexpr uint32_t BUFFER_SIZE = 256;
856 
857  const auto stack_le = le_u32(0x20002000);
858  const auto code_address_le = le_u32(target_address + 8 + 1); // thumb mode address (!)
859  uint32_t length = code_size + 8;
860 
861  /* Must be 32-bit aligned */
862  if (target_address & 0x3) {
863  ESP_LOGD(TAG, "Error: code address must be 4 byte aligned");
864  return STM32_ERR_UNKNOWN;
865  }
866 
867  // Could be constexpr in c++17
868  static const auto DELETOR = [](uint8_t *memory) {
869  free(memory); // NOLINT
870  };
871 
872  // Free memory with RAII
873  std::unique_ptr<uint8_t, decltype(DELETOR)> mem{static_cast<uint8_t *>(malloc(length)), // NOLINT
874  DELETOR};
875 
876  if (!mem)
877  return STM32_ERR_UNKNOWN;
878 
879  memcpy(mem.get(), &stack_le, sizeof(stack_le));
880  memcpy(mem.get() + 4, &code_address_le, sizeof(code_address_le));
881  memcpy(mem.get() + 8, code, code_size);
882 
883  auto *pos = mem.get();
884  auto address = target_address;
885  while (length > 0) {
886  const auto w = std::min(length, BUFFER_SIZE);
887  if (stm32_write_memory(stm, address, pos, w) != STM32_ERR_OK) {
888  return STM32_ERR_UNKNOWN;
889  }
890 
891  address += w;
892  pos += w;
893  length -= w;
894  }
895 
896  return stm32_go(stm, target_address);
897 }
898 
899 stm32_err_t stm32_go(const stm32_unique_ptr &stm, const uint32_t address) {
900  auto *const stream = stm->stream;
901 
902  if (stm->cmd->go == STM32_CMD_ERR) {
903  ESP_LOGD(TAG, "Error: GO command not implemented in bootloader.");
904  return STM32_ERR_NO_CMD;
905  }
906 
907  if (stm32_send_command(stm, stm->cmd->go) != STM32_ERR_OK)
908  return STM32_ERR_UNKNOWN;
909 
910  static constexpr auto BUFFER_SIZE = 5;
911  uint8_t buf[BUFFER_SIZE];
912  populate_buffer_with_address(buf, address);
913 
914  stream->write_array(buf, BUFFER_SIZE);
915  stream->flush();
916 
917  if (stm32_get_ack(stm) != STM32_ERR_OK)
918  return STM32_ERR_UNKNOWN;
919  return STM32_ERR_OK;
920 }
921 
923  const auto target_address = stm->dev->ram_start;
924 
925  if (stm->dev->flags & F_OBLL) {
926  /* set the OBL_LAUNCH bit to reset device (see RM0360, 2.5) */
927  return stm32_run_raw_code(stm, target_address, STM_OBL_LAUNCH_CODE, STM_OBL_LAUNCH_CODE_SIZE);
928  } else {
929  return stm32_run_raw_code(stm, target_address, STM_RESET_CODE, STM_RESET_CODE_SIZE);
930  }
931 }
932 
933 stm32_err_t stm32_crc_memory(const stm32_unique_ptr &stm, const uint32_t address, const uint32_t length,
934  uint32_t *const crc) {
935  static constexpr auto BUFFER_SIZE = 5;
936  auto *const stream = stm->stream;
937 
938  if (address & 0x3 || length & 0x3) {
939  ESP_LOGD(TAG, "Start and end addresses must be 4 byte aligned");
940  return STM32_ERR_UNKNOWN;
941  }
942 
943  if (stm->cmd->crc == STM32_CMD_ERR) {
944  ESP_LOGD(TAG, "Error: CRC command not implemented in bootloader.");
945  return STM32_ERR_NO_CMD;
946  }
947 
948  if (stm32_send_command(stm, stm->cmd->crc) != STM32_ERR_OK)
949  return STM32_ERR_UNKNOWN;
950 
951  {
952  static constexpr auto BUFFER_SIZE = 5;
953  uint8_t buf[BUFFER_SIZE];
954  populate_buffer_with_address(buf, address);
955 
956  stream->write_array(buf, BUFFER_SIZE);
957  stream->flush();
958  }
959 
960  if (stm32_get_ack(stm) != STM32_ERR_OK)
961  return STM32_ERR_UNKNOWN;
962 
963  {
964  static constexpr auto BUFFER_SIZE = 5;
965  uint8_t buf[BUFFER_SIZE];
966  populate_buffer_with_address(buf, address);
967 
968  stream->write_array(buf, BUFFER_SIZE);
969  stream->flush();
970  }
971 
972  if (stm32_get_ack(stm) != STM32_ERR_OK)
973  return STM32_ERR_UNKNOWN;
974 
975  if (stm32_get_ack(stm) != STM32_ERR_OK)
976  return STM32_ERR_UNKNOWN;
977 
978  {
979  uint8_t buf[BUFFER_SIZE];
980  if (!stream->read_array(buf, BUFFER_SIZE))
981  return STM32_ERR_UNKNOWN;
982 
983  if (buf[4] != (buf[0] ^ buf[1] ^ buf[2] ^ buf[3]))
984  return STM32_ERR_UNKNOWN;
985 
986  *crc = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
987  }
988 
989  return STM32_ERR_OK;
990 }
991 
992 /*
993  * CRC computed by STM32 is similar to the standard crc32_be()
994  * implemented, for example, in Linux kernel in ./lib/crc32.c
995  * But STM32 computes it on units of 32 bits word and swaps the
996  * bytes of the word before the computation.
997  * Due to byte swap, I cannot use any CRC available in existing
998  * libraries, so here is a simple not optimized implementation.
999  */
1000 uint32_t stm32_sw_crc(uint32_t crc, uint8_t *buf, unsigned int len) {
1001  static constexpr uint32_t CRCPOLY_BE = 0x04c11db7;
1002  static constexpr uint32_t CRC_MSBMASK = 0x80000000;
1003 
1004  if (len & 0x3) {
1005  ESP_LOGD(TAG, "Buffer length must be multiple of 4 bytes");
1006  return 0;
1007  }
1008 
1009  while (len) {
1010  uint32_t data = *buf++;
1011  data |= *buf++ << 8;
1012  data |= *buf++ << 16;
1013  data |= *buf++ << 24;
1014  len -= 4;
1015 
1016  crc ^= data;
1017 
1018  for (size_t i = 0; i < 32; ++i) {
1019  if (crc & CRC_MSBMASK) {
1020  crc = (crc << 1) ^ CRCPOLY_BE;
1021  } else {
1022  crc = (crc << 1);
1023  }
1024  }
1025  }
1026  return crc;
1027 }
1028 
1029 stm32_err_t stm32_crc_wrapper(const stm32_unique_ptr &stm, uint32_t address, uint32_t length, uint32_t *crc) {
1030  static constexpr uint32_t CRC_INIT_VALUE = 0xFFFFFFFF;
1031  static constexpr uint32_t BUFFER_SIZE = 256;
1032 
1033  uint8_t buf[BUFFER_SIZE];
1034 
1035  if (address & 0x3 || length & 0x3) {
1036  ESP_LOGD(TAG, "Start and end addresses must be 4 byte aligned");
1037  return STM32_ERR_UNKNOWN;
1038  }
1039 
1040  if (stm->cmd->crc != STM32_CMD_ERR)
1041  return stm32_crc_memory(stm, address, length, crc);
1042 
1043  const auto start = address;
1044  const auto total_len = length;
1045  uint32_t current_crc = CRC_INIT_VALUE;
1046  while (length) {
1047  const auto len = std::min(BUFFER_SIZE, length);
1048  if (stm32_read_memory(stm, address, buf, len) != STM32_ERR_OK) {
1049  ESP_LOGD(TAG, "Failed to read memory at address 0x%08x, target write-protected?", address);
1050  return STM32_ERR_UNKNOWN;
1051  }
1052  current_crc = stm32_sw_crc(current_crc, buf, len);
1053  length -= len;
1054  address += len;
1055 
1056  ESP_LOGD(TAG, "\rCRC address 0x%08x (%.2f%%) ", address, (100.0f / (float) total_len) * (float) (address - start));
1057  }
1058  ESP_LOGD(TAG, "Done.");
1059  *crc = current_crc;
1060  return STM32_ERR_OK;
1061 }
1062 
1063 } // namespace shelly_dimmer
1064 } // namespace esphome
1065 
1066 #endif // USE_SHD_FIRMWARE_DATA
constexpr auto STREAM_OPT_CMD_INIT
Definition: stm32flash.h:35
stm32_err_t stm32_wprot_memory(const stm32_unique_ptr &stm)
Definition: stm32flash.cpp:772
enum Stm32Err { STM32_ERR_OK=0, STM32_ERR_UNKNOWN, STM32_ERR_NACK, STM32_ERR_NO_CMD, } stm32_err_t
Definition: stm32flash.h:54
stm32_err_t stm32_wunprot_memory(const stm32_unique_ptr &stm)
Definition: stm32flash.cpp:759
stm32_err_t stm32_crc_wrapper(const stm32_unique_ptr &stm, uint32_t address, uint32_t length, uint32_t *crc)
stm32_err_t stm32_write_memory(const stm32_unique_ptr &stm, uint32_t address, const uint8_t *data, const unsigned int len)
Definition: stm32flash.cpp:698
constexpr auto STREAM_OPT_RETRY
Definition: stm32flash.h:36
struct Stm32Cmd { uint8_t get stm32_cmd_t
Definition: stm32flash.h:62
stm32_err_t stm32_crc_memory(const stm32_unique_ptr &stm, const uint32_t address, const uint32_t length, uint32_t *const crc)
Definition: stm32flash.cpp:933
mopeka_std_values val[4]
uint32_t IRAM_ATTR HOT millis()
Definition: core.cpp:25
const stm32_dev_t * dev
Definition: stm32flash.h:97
const char *const TAG
Definition: spi.cpp:8
stm32_err_t stm32_readprot_memory(const stm32_unique_ptr &stm)
Definition: stm32flash.cpp:798
constexpr auto STREAM_OPT_BYTE
Definition: stm32flash.h:33
constexpr stm32_dev_t DEVICES[]
Definition: dev_table.h:62
uint32_t stm32_sw_crc(uint32_t crc, uint8_t *buf, unsigned int len)
stm32_err_t stm32_go(const stm32_unique_ptr &stm, const uint32_t address)
Definition: stm32flash.cpp:899
constexpr auto STM32_MAX_PAGES
Definition: stm32flash.h:46
stm32_unique_ptr stm32_init(uart::UARTDevice *stream, const uint8_t flags, const char init)
Definition: stm32flash.cpp:500
std::unique_ptr< stm32_t, void(*)(stm32_t *)> stm32_unique_ptr
Definition: stm32flash.h:112
constexpr auto STM32_MASS_ERASE
Definition: stm32flash.h:47
constexpr auto STREAM_OPT_GVR_ETX
Definition: stm32flash.h:34
stm32_err_t stm32_read_memory(const stm32_unique_ptr &stm, const uint32_t address, uint8_t *data, const unsigned int len)
Definition: stm32flash.cpp:659
const uint32_t flags
Definition: stm32flash.h:85
stm32_err_t stm32_erase_memory(const stm32_unique_ptr &stm, uint32_t spage, uint32_t pages)
Definition: stm32flash.cpp:811
struct Stm32 { uart::UARTDevice *stream stm32_t
Definition: stm32flash.h:89
std::string size_t len
Definition: helpers.h:292
void IRAM_ATTR HOT yield()
Definition: core.cpp:24
stm32_err_t stm32_runprot_memory(const stm32_unique_ptr &stm)
Definition: stm32flash.cpp:785
bool read_array(uint8_t *data, size_t len)
Definition: uart.h:32
uint16_t length
Definition: tt21100.cpp:12
This is a workaround until we can figure out a way to get the tflite-micro idf component code availab...
Definition: a01nyub.cpp:7
void init()
Definition: core.cpp:80
stm32_err_t stm32_reset_device(const stm32_unique_ptr &stm)
Definition: stm32flash.cpp:922
stm32_cmd_t * cmd
Definition: stm32flash.h:96