22#ifdef USE_SHD_FIRMWARE_DATA
37constexpr uint8_t STM32_ACK = 0x79;
38constexpr uint8_t STM32_NACK = 0x1F;
39constexpr uint8_t STM32_BUSY = 0x76;
41constexpr uint8_t STM32_CMD_INIT = 0x7F;
42constexpr uint8_t STM32_CMD_GET = 0x00;
43constexpr uint8_t STM32_CMD_GVR = 0x01;
44constexpr uint8_t STM32_CMD_GID = 0x02;
45constexpr uint8_t STM32_CMD_RM = 0x11;
46constexpr uint8_t STM32_CMD_GO = 0x21;
47constexpr uint8_t STM32_CMD_WM = 0x31;
48constexpr uint8_t STM32_CMD_WM_NS = 0x32;
49constexpr uint8_t STM32_CMD_ER = 0x43;
50constexpr uint8_t STM32_CMD_EE = 0x44;
51constexpr uint8_t STM32_CMD_EE_NS = 0x45;
52constexpr uint8_t STM32_CMD_WP = 0x63;
53constexpr uint8_t STM32_CMD_WP_NS = 0x64;
54constexpr uint8_t STM32_CMD_UW = 0x73;
55constexpr uint8_t STM32_CMD_UW_NS = 0x74;
56constexpr uint8_t STM32_CMD_RP = 0x82;
57constexpr uint8_t STM32_CMD_RP_NS = 0x83;
58constexpr uint8_t STM32_CMD_UR = 0x92;
59constexpr uint8_t STM32_CMD_UR_NS = 0x93;
60constexpr uint8_t STM32_CMD_CRC = 0xA1;
61constexpr uint8_t STM32_CMD_ERR = 0xFF;
63constexpr uint32_t STM32_RESYNC_TIMEOUT = 35 * 1000;
64constexpr uint32_t STM32_MASSERASE_TIMEOUT = 35 * 1000;
65constexpr uint32_t STM32_PAGEERASE_TIMEOUT = 5 * 1000;
66constexpr uint32_t STM32_BLKWRITE_TIMEOUT = 1 * 1000;
67constexpr uint32_t STM32_WUNPROT_TIMEOUT = 1 * 1000;
68constexpr uint32_t STM32_WPROT_TIMEOUT = 1 * 1000;
69constexpr uint32_t STM32_RPROT_TIMEOUT = 1 * 1000;
70constexpr uint32_t DEFAULT_TIMEOUT = 5 * 1000;
72constexpr uint8_t STM32_CMD_GET_LENGTH = 17;
78constexpr uint8_t STM_RESET_CODE[] = {
83 0x0c, 0xed, 0x00, 0xe0,
84 0x04, 0x00, 0xfa, 0x05
87constexpr uint32_t STM_RESET_CODE_SIZE =
sizeof(STM_RESET_CODE);
100constexpr uint8_t STM_OBL_LAUNCH_CODE[] = {
105 0x10, 0x20, 0x02, 0x40,
106 0x00, 0x20, 0x00, 0x00
109constexpr uint32_t STM_OBL_LAUNCH_CODE_SIZE =
sizeof(STM_OBL_LAUNCH_CODE);
111constexpr char TAG[] =
"stm32flash";
120 if (!(addr >= stm->dev->fl_start && addr <= stm->dev->fl_end))
124 addr -= stm->dev->fl_start;
125 const auto *psize = stm->dev->fl_ps;
127 while (addr >= psize[0]) {
134 return addr ? page + 1 : page;
138 auto *stream = stm->stream;
145 timeout = DEFAULT_TIMEOUT;
150 if (!stream->available()) {
151 if (
millis() - start_time < timeout)
153 ESP_LOGD(TAG,
"Failed to read ACK timeout=%i", timeout);
154 return STM32_ERR_UNKNOWN;
157 stream->read_byte(&rxbyte);
159 if (rxbyte == STM32_ACK)
161 if (rxbyte == STM32_NACK)
162 return STM32_ERR_NACK;
163 if (rxbyte != STM32_BUSY) {
164 ESP_LOGD(TAG,
"Got byte 0x%02x instead of ACK", rxbyte);
165 return STM32_ERR_UNKNOWN;
173 auto *
const stream = stm->stream;
175 static constexpr auto BUFFER_SIZE = 2;
176 const uint8_t buf[] = {
178 static_cast<uint8_t
>(cmd ^ 0xFF),
180 static_assert(
sizeof(buf) == BUFFER_SIZE,
"Buf expected to be 2 bytes");
182 stream->write_array(buf, BUFFER_SIZE);
185 stm32_err_t s_err = stm32_get_ack_timeout(stm, timeout);
186 if (s_err == STM32_ERR_OK)
188 if (s_err == STM32_ERR_NACK) {
189 ESP_LOGD(TAG,
"Got NACK from device on command 0x%02x", cmd);
191 ESP_LOGD(TAG,
"Unexpected reply from device on command 0x%02x", cmd);
193 return STM32_ERR_UNKNOWN;
197 return stm32_send_command_timeout(stm, cmd, 0);
202 auto *
const stream = stm->stream;
206 static constexpr auto BUFFER_SIZE = 2;
207 const uint8_t buf[] = {
209 static_cast<uint8_t
>(STM32_CMD_ERR ^ 0xFF),
211 static_assert(
sizeof(buf) == BUFFER_SIZE,
"Buf expected to be 2 bytes");
214 while (t1 - t0 < STM32_RESYNC_TIMEOUT) {
215 stream->write_array(buf, BUFFER_SIZE);
217 if (!stream->read_array(&
ack, 1)) {
221 if (
ack == STM32_NACK)
225 return STM32_ERR_UNKNOWN;
241 auto *
const stream = stm->stream;
243 if (stm32_send_command(stm, cmd) != STM32_ERR_OK)
244 return STM32_ERR_UNKNOWN;
247 if (!stream->read_array(data, 1))
248 return STM32_ERR_UNKNOWN;
250 if (!stream->read_array(data + 1,
len + 1))
251 return STM32_ERR_UNKNOWN;
255 const auto ret = stream->read_array(data,
len + 2);
256 if (ret &&
len == data[0])
260 if (stm32_resync(stm) != STM32_ERR_OK)
261 return STM32_ERR_UNKNOWN;
262 if (stm32_send_command(stm, cmd) != STM32_ERR_OK)
263 return STM32_ERR_UNKNOWN;
264 if (!stream->read_array(data, 1))
265 return STM32_ERR_UNKNOWN;
268 ESP_LOGD(TAG,
"Re sync (len = %d)", data[0]);
269 if (stm32_resync(stm) != STM32_ERR_OK)
270 return STM32_ERR_UNKNOWN;
273 if (stm32_send_command(stm, cmd) != STM32_ERR_OK)
274 return STM32_ERR_UNKNOWN;
276 if (!stream->read_array(data,
len + 2))
277 return STM32_ERR_UNKNOWN;
289 auto *
const stream = stm->stream;
291 stream->write_array(&STM32_CMD_INIT, 1);
295 bool ret = stream->read_array(&
byte, 1);
296 if (ret &&
byte == STM32_ACK)
298 if (ret &&
byte == STM32_NACK) {
300 ESP_LOGD(TAG,
"Warning: the interface was not closed properly.");
304 ESP_LOGD(TAG,
"Failed to init device.");
305 return STM32_ERR_UNKNOWN;
312 stream->write_array(&STM32_CMD_INIT, 1);
315 ret = stream->read_array(&
byte, 1);
316 if (ret &&
byte == STM32_NACK)
318 ESP_LOGD(TAG,
"Failed to init device.");
319 return STM32_ERR_UNKNOWN;
323 auto *
const stream = stm->stream;
325 if (stm32_send_command(stm, stm->cmd->er) != STM32_ERR_OK) {
326 ESP_LOGD(TAG,
"Can't initiate chip mass erase!");
327 return STM32_ERR_UNKNOWN;
331 if (stm->cmd->er == STM32_CMD_ER) {
332 const auto s_err = stm32_send_command_timeout(stm, 0xFF, STM32_MASSERASE_TIMEOUT);
333 if (s_err != STM32_ERR_OK) {
334 return STM32_ERR_UNKNOWN;
340 static constexpr auto BUFFER_SIZE = 3;
341 const uint8_t buf[] = {
345 static_assert(
sizeof(buf) == BUFFER_SIZE,
"Expected the buffer to be 3 bytes");
346 stream->write_array(buf, 3);
349 const auto s_err = stm32_get_ack_timeout(stm, STM32_MASSERASE_TIMEOUT);
350 if (s_err != STM32_ERR_OK) {
351 ESP_LOGD(TAG,
"Mass erase failed. Try specifying the number of pages to be erased.");
352 return STM32_ERR_UNKNOWN;
357template<
typename T> std::unique_ptr<T[], void (*)(T *memory)> malloc_array_raii(
size_t size) {
359 static const auto DELETOR = [](T *memory) {
362 return std::unique_ptr<T[],
decltype(DELETOR)>{
static_cast<T *
>(malloc(
size)),
367 auto *
const stream = stm->stream;
374 if (stm32_send_command(stm, stm->cmd->er) != STM32_ERR_OK) {
375 ESP_LOGD(TAG,
"Can't initiate chip mass erase!");
376 return STM32_ERR_UNKNOWN;
380 if (stm->cmd->er == STM32_CMD_ER) {
382 auto buf = malloc_array_raii<uint8_t>(1 + pages + 1);
385 return STM32_ERR_UNKNOWN;
387 buf[i++] = pages - 1;
389 for (
auto pg_num = spage; pg_num < (pages + spage); pg_num++) {
394 stream->write_array(&buf[0], i);
397 const auto s_err = stm32_get_ack_timeout(stm, pages * STM32_PAGEERASE_TIMEOUT);
398 if (s_err != STM32_ERR_OK) {
399 return STM32_ERR_UNKNOWN;
407 auto buf = malloc_array_raii<uint8_t>(2 + 2 * pages + 1);
410 return STM32_ERR_UNKNOWN;
413 uint8_t pg_byte = (pages - 1) >> 8;
416 pg_byte = (pages - 1) & 0xFF;
420 for (
auto pg_num = spage; pg_num < spage + pages; pg_num++) {
421 pg_byte = pg_num >> 8;
424 pg_byte = pg_num & 0xFF;
429 stream->write_array(&buf[0], i);
432 const auto s_err = stm32_get_ack_timeout(stm, pages * STM32_PAGEERASE_TIMEOUT);
433 if (s_err != STM32_ERR_OK) {
434 ESP_LOGD(TAG,
"Page-by-page erase failed. Check the maximum pages your device supports.");
435 return STM32_ERR_UNKNOWN;
449 return STM32_ERR_UNKNOWN;
455 static constexpr int N = 1;
458 return *
reinterpret_cast<const char *
>(&N) == 1;
463 return ((v & 0xFF000000) >> 24) | ((v & 0x00FF0000) >> 8) | ((v & 0x0000FF00) << 8) | ((v & 0x000000FF) << 24);
467template<
size_t N>
void populate_buffer_with_address(uint8_t (&buffer)[N],
uint32_t address) {
468 buffer[0] =
static_cast<uint8_t
>(
address >> 24);
469 buffer[1] =
static_cast<uint8_t
>((
address >> 16) & 0xFF);
470 buffer[2] =
static_cast<uint8_t
>((
address >> 8) & 0xFF);
471 buffer[3] =
static_cast<uint8_t
>(
address & 0xFF);
472 buffer[4] =
static_cast<uint8_t
>(buffer[0] ^ buffer[1] ^ buffer[2] ^ buffer[3]);
476 static const auto CLOSE = [](
stm32_t *stm32) {
484 return std::unique_ptr<
stm32_t,
decltype(CLOSE)>{ptr, CLOSE};
490#define newer(prev, a) (((prev) == STM32_CMD_ERR) ? (a) : (((prev) > (a)) ? (prev) : (a)))
495 auto stm = make_stm32_with_deletor(
static_cast<stm32_t *
>(calloc(
sizeof(
stm32_t), 1)));
498 return make_stm32_with_deletor(
nullptr);
500 stm->stream = stream;
505 return make_stm32_with_deletor(
nullptr);
507 memset(stm->cmd, STM32_CMD_ERR,
sizeof(
stm32_cmd_t));
510 if (stm32_send_init_seq(stm) != STM32_ERR_OK)
511 return make_stm32_with_deletor(
nullptr);
515 if (stm32_send_command(stm, STM32_CMD_GVR) != STM32_ERR_OK) {
516 return make_stm32_with_deletor(
nullptr);
523 return make_stm32_with_deletor(
nullptr);
525 stm->version = buf[0];
528 if (stm32_get_ack(stm) != STM32_ERR_OK) {
529 return make_stm32_with_deletor(
nullptr);
534 const auto len = ([&]() {
536 if (stm->cmd_get_reply) {
537 for (
auto i = 0; stm->cmd_get_reply[i].length; ++i) {
538 if (stm->version == stm->cmd_get_reply[i].version) {
539 return stm->cmd_get_reply[i].length;
544 return STM32_CMD_GET_LENGTH;
547 if (stm32_guess_len_cmd(stm, STM32_CMD_GET, buf,
len) != STM32_ERR_OK)
548 return make_stm32_with_deletor(
nullptr);
551 const auto stop = buf[0] + 1;
552 stm->bl_version = buf[1];
554 for (
auto i = 1; i < stop; ++i) {
555 const auto val = buf[i + 1];
573 case STM32_CMD_WM_NS:
574 stm->cmd->wm = newer(stm->cmd->wm,
val);
578 case STM32_CMD_EE_NS:
579 stm->cmd->er = newer(stm->cmd->er,
val);
582 case STM32_CMD_WP_NS:
583 stm->cmd->wp = newer(stm->cmd->wp,
val);
586 case STM32_CMD_UW_NS:
587 stm->cmd->uw = newer(stm->cmd->uw,
val);
590 case STM32_CMD_RP_NS:
591 stm->cmd->rp = newer(stm->cmd->rp,
val);
594 case STM32_CMD_UR_NS:
595 stm->cmd->ur = newer(stm->cmd->ur,
val);
598 stm->cmd->crc = newer(stm->cmd->crc,
val);
601 if (new_cmds++ == 0) {
602 ESP_LOGD(TAG,
"GET returns unknown commands (0x%2x",
val);
604 ESP_LOGD(TAG,
", 0x%2x",
val);
611 if (stm32_get_ack(stm) != STM32_ERR_OK) {
612 return make_stm32_with_deletor(
nullptr);
615 if (stm->cmd->get == STM32_CMD_ERR || stm->cmd->gvr == STM32_CMD_ERR || stm->cmd->gid == STM32_CMD_ERR) {
616 ESP_LOGD(TAG,
"Error: bootloader did not returned correct information from GET command");
617 return make_stm32_with_deletor(
nullptr);
621 if (stm32_guess_len_cmd(stm, stm->cmd->gid, buf, 1) != STM32_ERR_OK) {
622 return make_stm32_with_deletor(
nullptr);
624 const auto returned = buf[0] + 1;
626 ESP_LOGD(TAG,
"Only %d bytes sent in the PID, unknown/unsupported device", returned);
627 return make_stm32_with_deletor(
nullptr);
629 stm->pid = (buf[1] << 8) | buf[2];
631 ESP_LOGD(TAG,
"This bootloader returns %d extra bytes in PID:", returned);
632 for (
auto i = 2; i <= returned; i++)
633 ESP_LOGD(TAG,
" %02x", buf[i]);
635 if (stm32_get_ack(stm) != STM32_ERR_OK) {
636 return make_stm32_with_deletor(
nullptr);
640 while (stm->dev->id != 0x00 && stm->dev->id != stm->pid)
644 ESP_LOGD(TAG,
"Unknown/unsupported device (Device ID: 0x%03x)", stm->pid);
645 return make_stm32_with_deletor(
nullptr);
652 const unsigned int len) {
653 auto *
const stream = stm->stream;
659 ESP_LOGD(TAG,
"Error: READ length limit at 256 bytes");
660 return STM32_ERR_UNKNOWN;
663 if (stm->cmd->rm == STM32_CMD_ERR) {
664 ESP_LOGD(TAG,
"Error: READ command not implemented in bootloader.");
665 return STM32_ERR_NO_CMD;
668 if (stm32_send_command(stm, stm->cmd->rm) != STM32_ERR_OK)
669 return STM32_ERR_UNKNOWN;
671 static constexpr auto BUFFER_SIZE = 5;
672 uint8_t buf[BUFFER_SIZE];
673 populate_buffer_with_address(buf,
address);
675 stream->write_array(buf, BUFFER_SIZE);
678 if (stm32_get_ack(stm) != STM32_ERR_OK)
679 return STM32_ERR_UNKNOWN;
681 if (stm32_send_command(stm,
len - 1) != STM32_ERR_OK)
682 return STM32_ERR_UNKNOWN;
684 if (!stream->read_array(data,
len))
685 return STM32_ERR_UNKNOWN;
691 const unsigned int len) {
692 auto *
const stream = stm->stream;
698 ESP_LOGD(TAG,
"Error: READ length limit at 256 bytes");
699 return STM32_ERR_UNKNOWN;
704 ESP_LOGD(TAG,
"Error: WRITE address must be 4 byte aligned");
705 return STM32_ERR_UNKNOWN;
708 if (stm->cmd->wm == STM32_CMD_ERR) {
709 ESP_LOGD(TAG,
"Error: WRITE command not implemented in bootloader.");
710 return STM32_ERR_NO_CMD;
714 if (stm32_send_command(stm, stm->cmd->wm) != STM32_ERR_OK)
715 return STM32_ERR_UNKNOWN;
717 static constexpr auto BUFFER_SIZE = 5;
718 uint8_t buf1[BUFFER_SIZE];
719 populate_buffer_with_address(buf1,
address);
721 stream->write_array(buf1, BUFFER_SIZE);
723 if (stm32_get_ack(stm) != STM32_ERR_OK)
724 return STM32_ERR_UNKNOWN;
726 const unsigned int aligned_len = (
len + 3) & ~3;
727 uint8_t cs = aligned_len - 1;
728 uint8_t buf[256 + 2];
730 buf[0] = aligned_len - 1;
731 for (
auto i = 0; i <
len; i++) {
733 buf[i + 1] = data[i];
736 for (
auto i =
len; i < aligned_len; i++) {
740 buf[aligned_len + 1] = cs;
741 stream->write_array(buf, aligned_len + 2);
744 const auto s_err = stm32_get_ack_timeout(stm, STM32_BLKWRITE_TIMEOUT);
745 if (s_err != STM32_ERR_OK) {
746 return STM32_ERR_UNKNOWN;
752 if (stm->cmd->uw == STM32_CMD_ERR) {
753 ESP_LOGD(TAG,
"Error: WRITE UNPROTECT command not implemented in bootloader.");
754 return STM32_ERR_NO_CMD;
757 if (stm32_send_command(stm, stm->cmd->uw) != STM32_ERR_OK)
758 return STM32_ERR_UNKNOWN;
760 return stm32_check_ack_timeout(stm32_get_ack_timeout(stm, STM32_WUNPROT_TIMEOUT),
761 []() { ESP_LOGD(TAG,
"Error: Failed to WRITE UNPROTECT"); });
765 if (stm->cmd->wp == STM32_CMD_ERR) {
766 ESP_LOGD(TAG,
"Error: WRITE PROTECT command not implemented in bootloader.");
767 return STM32_ERR_NO_CMD;
770 if (stm32_send_command(stm, stm->cmd->wp) != STM32_ERR_OK)
771 return STM32_ERR_UNKNOWN;
773 return stm32_check_ack_timeout(stm32_get_ack_timeout(stm, STM32_WPROT_TIMEOUT),
774 []() { ESP_LOGD(TAG,
"Error: Failed to WRITE PROTECT"); });
778 if (stm->cmd->ur == STM32_CMD_ERR) {
779 ESP_LOGD(TAG,
"Error: READOUT UNPROTECT command not implemented in bootloader.");
780 return STM32_ERR_NO_CMD;
783 if (stm32_send_command(stm, stm->cmd->ur) != STM32_ERR_OK)
784 return STM32_ERR_UNKNOWN;
786 return stm32_check_ack_timeout(stm32_get_ack_timeout(stm, STM32_MASSERASE_TIMEOUT),
787 []() { ESP_LOGD(TAG,
"Error: Failed to READOUT UNPROTECT"); });
791 if (stm->cmd->rp == STM32_CMD_ERR) {
792 ESP_LOGD(TAG,
"Error: READOUT PROTECT command not implemented in bootloader.");
793 return STM32_ERR_NO_CMD;
796 if (stm32_send_command(stm, stm->cmd->rp) != STM32_ERR_OK)
797 return STM32_ERR_UNKNOWN;
799 return stm32_check_ack_timeout(stm32_get_ack_timeout(stm, STM32_RPROT_TIMEOUT),
800 []() { ESP_LOGD(TAG,
"Error: Failed to READOUT PROTECT"); });
807 if (stm->cmd->er == STM32_CMD_ERR) {
808 ESP_LOGD(TAG,
"Error: ERASE command not implemented in bootloader.");
809 return STM32_ERR_NO_CMD;
823 if (!(stm->dev->flags & F_NO_ME))
824 return stm32_mass_erase(stm);
826 pages = flash_addr_to_page_ceil(stm, stm->dev->fl_end);
833 static constexpr uint32_t MAX_PAGE_SIZE = 512;
835 const auto n = std::min(pages, MAX_PAGE_SIZE);
836 const auto s_err = stm32_pages_erase(stm, spage, n);
837 if (s_err != STM32_ERR_OK)
847 static constexpr uint32_t BUFFER_SIZE = 256;
849 const auto stack_le = le_u32(0x20002000);
850 const auto code_address_le = le_u32(target_address + 8 + 1);
854 if (target_address & 0x3) {
855 ESP_LOGD(TAG,
"Error: code address must be 4 byte aligned");
856 return STM32_ERR_UNKNOWN;
860 static const auto DELETOR = [](uint8_t *memory) {
865 std::unique_ptr<uint8_t,
decltype(DELETOR)> mem{
static_cast<uint8_t *
>(malloc(
length)),
869 return STM32_ERR_UNKNOWN;
871 memcpy(mem.get(), &stack_le,
sizeof(stack_le));
872 memcpy(mem.get() + 4, &code_address_le,
sizeof(code_address_le));
873 memcpy(mem.get() + 8, code, code_size);
875 auto *
pos = mem.get();
878 const auto w = std::min(
length, BUFFER_SIZE);
880 return STM32_ERR_UNKNOWN;
888 return stm32_go(stm, target_address);
892 auto *
const stream = stm->stream;
894 if (stm->cmd->go == STM32_CMD_ERR) {
895 ESP_LOGD(TAG,
"Error: GO command not implemented in bootloader.");
896 return STM32_ERR_NO_CMD;
899 if (stm32_send_command(stm, stm->cmd->go) != STM32_ERR_OK)
900 return STM32_ERR_UNKNOWN;
902 static constexpr auto BUFFER_SIZE = 5;
903 uint8_t buf[BUFFER_SIZE];
904 populate_buffer_with_address(buf,
address);
906 stream->write_array(buf, BUFFER_SIZE);
909 if (stm32_get_ack(stm) != STM32_ERR_OK)
910 return STM32_ERR_UNKNOWN;
915 const auto target_address = stm->dev->ram_start;
917 if (stm->dev->flags & F_OBLL) {
919 return stm32_run_raw_code(stm, target_address, STM_OBL_LAUNCH_CODE, STM_OBL_LAUNCH_CODE_SIZE);
921 return stm32_run_raw_code(stm, target_address, STM_RESET_CODE, STM_RESET_CODE_SIZE);
927 static constexpr auto BUFFER_SIZE = 5;
928 auto *
const stream = stm->stream;
931 ESP_LOGD(TAG,
"Start and end addresses must be 4 byte aligned");
932 return STM32_ERR_UNKNOWN;
935 if (stm->cmd->crc == STM32_CMD_ERR) {
936 ESP_LOGD(TAG,
"Error: CRC command not implemented in bootloader.");
937 return STM32_ERR_NO_CMD;
940 if (stm32_send_command(stm, stm->cmd->crc) != STM32_ERR_OK)
941 return STM32_ERR_UNKNOWN;
944 static constexpr auto BUFFER_SIZE = 5;
945 uint8_t buf[BUFFER_SIZE];
946 populate_buffer_with_address(buf,
address);
948 stream->write_array(buf, BUFFER_SIZE);
952 if (stm32_get_ack(stm) != STM32_ERR_OK)
953 return STM32_ERR_UNKNOWN;
956 static constexpr auto BUFFER_SIZE = 5;
957 uint8_t buf[BUFFER_SIZE];
958 populate_buffer_with_address(buf,
address);
960 stream->write_array(buf, BUFFER_SIZE);
964 if (stm32_get_ack(stm) != STM32_ERR_OK)
965 return STM32_ERR_UNKNOWN;
967 if (stm32_get_ack(stm) != STM32_ERR_OK)
968 return STM32_ERR_UNKNOWN;
971 uint8_t buf[BUFFER_SIZE];
972 if (!stream->read_array(buf, BUFFER_SIZE))
973 return STM32_ERR_UNKNOWN;
975 if (buf[4] != (buf[0] ^ buf[1] ^ buf[2] ^ buf[3]))
976 return STM32_ERR_UNKNOWN;
978 *crc = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
993 static constexpr uint32_t CRCPOLY_BE = 0x04c11db7;
994 static constexpr uint32_t CRC_MSBMASK = 0x80000000;
997 ESP_LOGD(TAG,
"Buffer length must be multiple of 4 bytes");
1003 data |= *buf++ << 8;
1004 data |= *buf++ << 16;
1005 data |= *buf++ << 24;
1010 for (
size_t i = 0; i < 32; ++i) {
1011 if (crc & CRC_MSBMASK) {
1012 crc = (crc << 1) ^ CRCPOLY_BE;
1022 static constexpr uint32_t CRC_INIT_VALUE = 0xFFFFFFFF;
1023 static constexpr uint32_t BUFFER_SIZE = 256;
1025 uint8_t buf[BUFFER_SIZE];
1028 ESP_LOGD(TAG,
"Start and end addresses must be 4 byte aligned");
1029 return STM32_ERR_UNKNOWN;
1032 if (stm->cmd->crc != STM32_CMD_ERR)
1036 const auto total_len =
length;
1037 uint32_t current_crc = CRC_INIT_VALUE;
1039 const auto len = std::min(BUFFER_SIZE,
length);
1041 ESP_LOGD(TAG,
"Failed to read memory at address 0x%08x, target write-protected?",
address);
1042 return STM32_ERR_UNKNOWN;
1048 ESP_LOGD(TAG,
"\rCRC address 0x%08x (%.2f%%) ",
address, (100.0f / (
float) total_len) * (
float) (
address - start));
1050 ESP_LOGD(TAG,
"Done.");
1052 return STM32_ERR_OK;
bool read_array(uint8_t *data, size_t len)
const std::vector< uint8_t > & data
stm32_err_t stm32_wunprot_memory(const stm32_unique_ptr &stm)
stm32_err_t stm32_reset_device(const stm32_unique_ptr &stm)
stm32_unique_ptr stm32_init(uart::UARTDevice *stream, const uint8_t flags, const char init)
constexpr auto STREAM_OPT_CMD_INIT
constexpr auto STREAM_OPT_RETRY
struct Stm32 { uart::UARTDevice *stream; uint8_t flags; struct VarlenCmd *cmd_get_reply; uint8_t bl_version; uint8_t version; uint8_t option1, option2; uint16_t pid; stm32_cmd_t *cmd; const stm32_dev_t *dev;} stm32_t
stm32_err_t stm32_readprot_memory(const stm32_unique_ptr &stm)
stm32_err_t stm32_crc_wrapper(const stm32_unique_ptr &stm, uint32_t address, uint32_t length, uint32_t *crc)
struct Stm32Cmd { uint8_t get; uint8_t gvr; uint8_t gid; uint8_t rm; uint8_t go; uint8_t wm; uint8_t er; uint8_t wp; uint8_t uw; uint8_t rp; uint8_t ur; uint8_t crc;} stm32_cmd_t
stm32_err_t stm32_write_memory(const stm32_unique_ptr &stm, uint32_t address, const uint8_t *data, const unsigned int len)
constexpr stm32_dev_t DEVICES[]
constexpr auto STM32_MASS_ERASE
constexpr auto STM32_MAX_PAGES
stm32_err_t stm32_runprot_memory(const stm32_unique_ptr &stm)
stm32_err_t stm32_go(const stm32_unique_ptr &stm, const uint32_t address)
stm32_err_t stm32_crc_memory(const stm32_unique_ptr &stm, const uint32_t address, const uint32_t length, uint32_t *const crc)
stm32_err_t stm32_read_memory(const stm32_unique_ptr &stm, const uint32_t address, uint8_t *data, const unsigned int len)
uint32_t stm32_sw_crc(uint32_t crc, uint8_t *buf, unsigned int len)
constexpr auto STREAM_OPT_BYTE
constexpr auto STREAM_OPT_GVR_ETX
stm32_err_t stm32_erase_memory(const stm32_unique_ptr &stm, uint32_t spage, uint32_t pages)
std::unique_ptr< stm32_t, void(*)(stm32_t *)> stm32_unique_ptr
enum Stm32Err { STM32_ERR_OK=0, STM32_ERR_UNKNOWN, STM32_ERR_NACK, STM32_ERR_NO_CMD, } stm32_err_t
stm32_err_t stm32_wprot_memory(const stm32_unique_ptr &stm)
uint32_t IRAM_ATTR HOT millis()