22 #ifdef USE_SHD_FIRMWARE_DATA 37 constexpr uint8_t STM32_ACK = 0x79;
38 constexpr uint8_t STM32_NACK = 0x1F;
39 constexpr uint8_t STM32_BUSY = 0x76;
41 constexpr uint8_t STM32_CMD_INIT = 0x7F;
42 constexpr uint8_t STM32_CMD_GET = 0x00;
43 constexpr uint8_t STM32_CMD_GVR = 0x01;
44 constexpr uint8_t STM32_CMD_GID = 0x02;
45 constexpr uint8_t STM32_CMD_RM = 0x11;
46 constexpr uint8_t STM32_CMD_GO = 0x21;
47 constexpr uint8_t STM32_CMD_WM = 0x31;
48 constexpr uint8_t STM32_CMD_WM_NS = 0x32;
49 constexpr uint8_t STM32_CMD_ER = 0x43;
50 constexpr uint8_t STM32_CMD_EE = 0x44;
51 constexpr uint8_t STM32_CMD_EE_NS = 0x45;
52 constexpr uint8_t STM32_CMD_WP = 0x63;
53 constexpr uint8_t STM32_CMD_WP_NS = 0x64;
54 constexpr uint8_t STM32_CMD_UW = 0x73;
55 constexpr uint8_t STM32_CMD_UW_NS = 0x74;
56 constexpr uint8_t STM32_CMD_RP = 0x82;
57 constexpr uint8_t STM32_CMD_RP_NS = 0x83;
58 constexpr uint8_t STM32_CMD_UR = 0x92;
59 constexpr uint8_t STM32_CMD_UR_NS = 0x93;
60 constexpr uint8_t STM32_CMD_CRC = 0xA1;
61 constexpr uint8_t STM32_CMD_ERR = 0xFF;
63 constexpr uint32_t STM32_RESYNC_TIMEOUT = 35 * 1000;
64 constexpr uint32_t STM32_MASSERASE_TIMEOUT = 35 * 1000;
65 constexpr uint32_t STM32_PAGEERASE_TIMEOUT = 5 * 1000;
66 constexpr uint32_t STM32_BLKWRITE_TIMEOUT = 1 * 1000;
67 constexpr uint32_t STM32_WUNPROT_TIMEOUT = 1 * 1000;
68 constexpr uint32_t STM32_WPROT_TIMEOUT = 1 * 1000;
69 constexpr uint32_t STM32_RPROT_TIMEOUT = 1 * 1000;
70 constexpr uint32_t DEFAULT_TIMEOUT = 5 * 1000;
72 constexpr uint8_t STM32_CMD_GET_LENGTH = 17;
78 constexpr uint8_t STM_RESET_CODE[] = {
83 0x0c, 0xed, 0x00, 0xe0,
84 0x04, 0x00, 0xfa, 0x05
87 constexpr uint32_t STM_RESET_CODE_SIZE =
sizeof(STM_RESET_CODE);
100 constexpr uint8_t STM_OBL_LAUNCH_CODE[] = {
105 0x10, 0x20, 0x02, 0x40,
106 0x00, 0x20, 0x00, 0x00
109 constexpr uint32_t STM_OBL_LAUNCH_CODE_SIZE =
sizeof(STM_OBL_LAUNCH_CODE);
111 constexpr
char TAG[] =
"stm32flash";
116 namespace shelly_dimmer {
121 if (!(addr >= stm->dev->fl_start && addr <= stm->
dev->fl_end))
125 addr -= stm->dev->fl_start;
126 const auto *psize = stm->dev->fl_ps;
128 while (addr >= psize[0]) {
135 return addr ? page + 1 : page;
139 auto *stream = stm->stream;
146 timeout = DEFAULT_TIMEOUT;
148 const uint32_t start_time =
millis();
151 if (!stream->available()) {
152 if (
millis() < start_time + timeout)
154 ESP_LOGD(TAG,
"Failed to read ACK timeout=%i", timeout);
155 return STM32_ERR_UNKNOWN;
158 stream->read_byte(&rxbyte);
160 if (rxbyte == STM32_ACK)
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;
174 auto *
const stream = stm->stream;
176 static constexpr
auto BUFFER_SIZE = 2;
177 const uint8_t buf[] = {
179 static_cast<uint8_t
>(cmd ^ 0xFF),
181 static_assert(
sizeof(buf) == BUFFER_SIZE,
"Buf expected to be 2 bytes");
183 stream->write_array(buf, BUFFER_SIZE);
186 stm32_err_t s_err = stm32_get_ack_timeout(stm, timeout);
187 if (s_err == STM32_ERR_OK)
189 if (s_err == STM32_ERR_NACK) {
190 ESP_LOGD(TAG,
"Got NACK from device on command 0x%02x", cmd);
192 ESP_LOGD(TAG,
"Unexpected reply from device on command 0x%02x", cmd);
194 return STM32_ERR_UNKNOWN;
198 return stm32_send_command_timeout(stm, cmd, 0);
203 auto *
const stream = stm->stream;
207 static constexpr
auto BUFFER_SIZE = 2;
208 const uint8_t buf[] = {
210 static_cast<uint8_t
>(STM32_CMD_ERR ^ 0xFF),
212 static_assert(
sizeof(buf) == BUFFER_SIZE,
"Buf expected to be 2 bytes");
215 while (t1 < t0 + STM32_RESYNC_TIMEOUT) {
216 stream->write_array(buf, BUFFER_SIZE);
218 if (!stream->read_array(&ack, 1)) {
222 if (ack == STM32_NACK)
226 return STM32_ERR_UNKNOWN;
242 auto *
const stream = stm->stream;
244 if (stm32_send_command(stm, cmd) != STM32_ERR_OK)
245 return STM32_ERR_UNKNOWN;
248 if (!stream->read_array(data, 1))
249 return STM32_ERR_UNKNOWN;
251 if (!stream->read_array(data + 1, len + 1))
252 return STM32_ERR_UNKNOWN;
256 const auto ret = stream->read_array(data, len + 2);
257 if (ret && len == data[0])
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;
269 ESP_LOGD(TAG,
"Re sync (len = %d)", data[0]);
270 if (stm32_resync(stm) != STM32_ERR_OK)
271 return STM32_ERR_UNKNOWN;
274 if (stm32_send_command(stm, cmd) != STM32_ERR_OK)
275 return STM32_ERR_UNKNOWN;
277 if (!stream->read_array(data, len + 2))
278 return STM32_ERR_UNKNOWN;
290 auto *
const stream = stm->stream;
292 stream->write_array(&STM32_CMD_INIT, 1);
296 bool ret = stream->read_array(&byte, 1);
297 if (ret && byte == STM32_ACK)
299 if (ret && byte == STM32_NACK) {
301 ESP_LOGD(TAG,
"Warning: the interface was not closed properly.");
305 ESP_LOGD(TAG,
"Failed to init device.");
306 return STM32_ERR_UNKNOWN;
313 stream->write_array(&STM32_CMD_INIT, 1);
316 ret = stream->read_array(&byte, 1);
317 if (ret && byte == STM32_NACK)
319 ESP_LOGD(TAG,
"Failed to init device.");
320 return STM32_ERR_UNKNOWN;
324 auto *
const stream = stm->stream;
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;
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;
341 static constexpr
auto BUFFER_SIZE = 3;
342 const uint8_t buf[] = {
346 static_assert(
sizeof(buf) == BUFFER_SIZE,
"Expected the buffer to be 3 bytes");
347 stream->write_array(buf, 3);
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;
358 template<
typename T> std::unique_ptr<T[], void (*)(T *memory)> malloc_array_raii(
size_t size) {
360 static const auto DELETOR = [](T *memory) {
363 return std::unique_ptr<T[], decltype(DELETOR)>{
static_cast<T *
>(malloc(size)),
368 auto *
const stream = stm->stream;
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;
381 if (stm->cmd->er == STM32_CMD_ER) {
383 auto buf = malloc_array_raii<uint8_t>(1 + pages + 1);
386 return STM32_ERR_UNKNOWN;
388 buf[i++] = pages - 1;
390 for (
auto pg_num = spage; pg_num < (pages + spage); pg_num++) {
395 stream->write_array(&buf[0], i);
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;
408 auto buf = malloc_array_raii<uint8_t>(2 + 2 * pages + 1);
411 return STM32_ERR_UNKNOWN;
414 uint8_t pg_byte = (pages - 1) >> 8;
417 pg_byte = (pages - 1) & 0xFF;
421 for (
auto pg_num = spage; pg_num < spage + pages; pg_num++) {
422 pg_byte = pg_num >> 8;
425 pg_byte = pg_num & 0xFF;
430 stream->write_array(&buf[0], i);
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;
451 return STM32_ERR_UNKNOWN;
457 static constexpr
int N = 1;
460 return *
reinterpret_cast<const char *
>(&N) == 1;
463 uint32_t le_u32(
const uint32_t v) {
465 return ((v & 0xFF000000) >> 24) | ((v & 0x00FF0000) >> 8) | ((v & 0x0000FF00) << 8) | ((v & 0x000000FF) << 24);
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]);
478 static const auto CLOSE = [](
stm32_t *stm32) {
486 return std::unique_ptr<stm32_t, decltype(CLOSE)>{ptr, CLOSE};
495 namespace shelly_dimmer {
498 #define newer(prev, a) (((prev) == STM32_CMD_ERR) ? (a) : (((prev) > (a)) ? (prev) : (a))) 503 auto stm = make_stm32_with_deletor(static_cast<stm32_t *>(calloc(
sizeof(
stm32_t), 1)));
506 return make_stm32_with_deletor(
nullptr);
508 stm->stream = stream;
513 return make_stm32_with_deletor(
nullptr);
515 memset(stm->cmd, STM32_CMD_ERR,
sizeof(
stm32_cmd_t));
518 if (stm32_send_init_seq(stm) != STM32_ERR_OK)
519 return make_stm32_with_deletor(
nullptr);
523 if (stm32_send_command(stm, STM32_CMD_GVR) != STM32_ERR_OK) {
524 return make_stm32_with_deletor(
nullptr);
531 return make_stm32_with_deletor(
nullptr);
533 stm->version = buf[0];
536 if (stm32_get_ack(stm) != STM32_ERR_OK) {
537 return make_stm32_with_deletor(
nullptr);
542 const auto len = ([&]() {
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;
552 return STM32_CMD_GET_LENGTH;
555 if (stm32_guess_len_cmd(stm, STM32_CMD_GET, buf, len) != STM32_ERR_OK)
556 return make_stm32_with_deletor(
nullptr);
559 const auto stop = buf[0] + 1;
560 stm->bl_version = buf[1];
562 for (
auto i = 1; i < stop; ++i) {
563 const auto val = buf[i + 1];
581 case STM32_CMD_WM_NS:
582 stm->cmd->wm = newer(stm->cmd->wm,
val);
586 case STM32_CMD_EE_NS:
587 stm->cmd->er = newer(stm->cmd->er,
val);
590 case STM32_CMD_WP_NS:
591 stm->cmd->wp = newer(stm->cmd->wp,
val);
594 case STM32_CMD_UW_NS:
595 stm->cmd->uw = newer(stm->cmd->uw,
val);
598 case STM32_CMD_RP_NS:
599 stm->cmd->rp = newer(stm->cmd->rp,
val);
602 case STM32_CMD_UR_NS:
603 stm->cmd->ur = newer(stm->cmd->ur,
val);
606 stm->cmd->crc = newer(stm->cmd->crc,
val);
609 if (new_cmds++ == 0) {
610 ESP_LOGD(TAG,
"GET returns unknown commands (0x%2x",
val);
612 ESP_LOGD(TAG,
", 0x%2x",
val);
619 if (stm32_get_ack(stm) != STM32_ERR_OK) {
620 return make_stm32_with_deletor(
nullptr);
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);
629 if (stm32_guess_len_cmd(stm, stm->cmd->gid, buf, 1) != STM32_ERR_OK) {
630 return make_stm32_with_deletor(
nullptr);
632 const auto returned = buf[0] + 1;
634 ESP_LOGD(TAG,
"Only %d bytes sent in the PID, unknown/unsupported device", returned);
635 return make_stm32_with_deletor(
nullptr);
637 stm->pid = (buf[1] << 8) | buf[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]);
643 if (stm32_get_ack(stm) != STM32_ERR_OK) {
644 return make_stm32_with_deletor(
nullptr);
648 while (stm->dev->id != 0x00 && stm->dev->id != stm->pid)
652 ESP_LOGD(TAG,
"Unknown/unsupported device (Device ID: 0x%03x)", stm->pid);
653 return make_stm32_with_deletor(
nullptr);
660 const unsigned int len) {
661 auto *
const stream = stm->stream;
667 ESP_LOGD(TAG,
"Error: READ length limit at 256 bytes");
668 return STM32_ERR_UNKNOWN;
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;
676 if (stm32_send_command(stm, stm->cmd->rm) != STM32_ERR_OK)
677 return STM32_ERR_UNKNOWN;
679 static constexpr
auto BUFFER_SIZE = 5;
680 uint8_t buf[BUFFER_SIZE];
681 populate_buffer_with_address(buf, address);
683 stream->write_array(buf, BUFFER_SIZE);
686 if (stm32_get_ack(stm) != STM32_ERR_OK)
687 return STM32_ERR_UNKNOWN;
689 if (stm32_send_command(stm, len - 1) != STM32_ERR_OK)
690 return STM32_ERR_UNKNOWN;
692 if (!stream->read_array(data, len))
693 return STM32_ERR_UNKNOWN;
699 const unsigned int len) {
700 auto *
const stream = stm->stream;
706 ESP_LOGD(TAG,
"Error: READ length limit at 256 bytes");
707 return STM32_ERR_UNKNOWN;
712 ESP_LOGD(TAG,
"Error: WRITE address must be 4 byte aligned");
713 return STM32_ERR_UNKNOWN;
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;
722 if (stm32_send_command(stm, stm->cmd->wm) != STM32_ERR_OK)
723 return STM32_ERR_UNKNOWN;
725 static constexpr
auto BUFFER_SIZE = 5;
726 uint8_t buf1[BUFFER_SIZE];
727 populate_buffer_with_address(buf1, address);
729 stream->write_array(buf1, BUFFER_SIZE);
731 if (stm32_get_ack(stm) != STM32_ERR_OK)
732 return STM32_ERR_UNKNOWN;
734 const unsigned int aligned_len = (len + 3) & ~3;
735 uint8_t cs = aligned_len - 1;
736 uint8_t buf[256 + 2];
738 buf[0] = aligned_len - 1;
739 for (
auto i = 0; i <
len; i++) {
741 buf[i + 1] = data[i];
744 for (
auto i = len; i < aligned_len; i++) {
748 buf[aligned_len + 1] = cs;
749 stream->write_array(buf, aligned_len + 2);
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;
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;
765 if (stm32_send_command(stm, stm->cmd->uw) != STM32_ERR_OK)
766 return STM32_ERR_UNKNOWN;
768 return stm32_check_ack_timeout(stm32_get_ack_timeout(stm, STM32_WUNPROT_TIMEOUT),
769 []() { ESP_LOGD(TAG,
"Error: Failed to WRITE UNPROTECT"); });
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;
778 if (stm32_send_command(stm, stm->cmd->wp) != STM32_ERR_OK)
779 return STM32_ERR_UNKNOWN;
781 return stm32_check_ack_timeout(stm32_get_ack_timeout(stm, STM32_WPROT_TIMEOUT),
782 []() { ESP_LOGD(TAG,
"Error: Failed to WRITE PROTECT"); });
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;
791 if (stm32_send_command(stm, stm->cmd->ur) != STM32_ERR_OK)
792 return STM32_ERR_UNKNOWN;
794 return stm32_check_ack_timeout(stm32_get_ack_timeout(stm, STM32_MASSERASE_TIMEOUT),
795 []() { ESP_LOGD(TAG,
"Error: Failed to READOUT UNPROTECT"); });
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;
804 if (stm32_send_command(stm, stm->cmd->rp) != STM32_ERR_OK)
805 return STM32_ERR_UNKNOWN;
807 return stm32_check_ack_timeout(stm32_get_ack_timeout(stm, STM32_RPROT_TIMEOUT),
808 []() { ESP_LOGD(TAG,
"Error: Failed to READOUT PROTECT"); });
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;
831 if (!(stm->dev->flags & F_NO_ME))
832 return stm32_mass_erase(stm);
834 pages = flash_addr_to_page_ceil(stm, stm->dev->fl_end);
841 static constexpr uint32_t MAX_PAGE_SIZE = 512;
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)
854 uint32_t code_size) {
855 static constexpr uint32_t BUFFER_SIZE = 256;
857 const auto stack_le = le_u32(0x20002000);
858 const auto code_address_le = le_u32(target_address + 8 + 1);
859 uint32_t
length = code_size + 8;
862 if (target_address & 0x3) {
863 ESP_LOGD(TAG,
"Error: code address must be 4 byte aligned");
864 return STM32_ERR_UNKNOWN;
868 static const auto DELETOR = [](uint8_t *memory) {
873 std::unique_ptr<uint8_t, decltype(DELETOR)> mem{
static_cast<uint8_t *
>(malloc(length)),
877 return STM32_ERR_UNKNOWN;
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);
883 auto *pos = mem.get();
886 const auto w = std::min(length, BUFFER_SIZE);
888 return STM32_ERR_UNKNOWN;
896 return stm32_go(stm, target_address);
900 auto *
const stream = stm->stream;
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;
907 if (stm32_send_command(stm, stm->cmd->go) != STM32_ERR_OK)
908 return STM32_ERR_UNKNOWN;
910 static constexpr
auto BUFFER_SIZE = 5;
911 uint8_t buf[BUFFER_SIZE];
912 populate_buffer_with_address(buf, address);
914 stream->write_array(buf, BUFFER_SIZE);
917 if (stm32_get_ack(stm) != STM32_ERR_OK)
918 return STM32_ERR_UNKNOWN;
923 const auto target_address = stm->dev->ram_start;
925 if (stm->dev->flags & F_OBLL) {
927 return stm32_run_raw_code(stm, target_address, STM_OBL_LAUNCH_CODE, STM_OBL_LAUNCH_CODE_SIZE);
929 return stm32_run_raw_code(stm, target_address, STM_RESET_CODE, STM_RESET_CODE_SIZE);
934 uint32_t *
const crc) {
935 static constexpr
auto BUFFER_SIZE = 5;
936 auto *
const stream = stm->stream;
938 if (address & 0x3 || length & 0x3) {
939 ESP_LOGD(TAG,
"Start and end addresses must be 4 byte aligned");
940 return STM32_ERR_UNKNOWN;
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;
948 if (stm32_send_command(stm, stm->cmd->crc) != STM32_ERR_OK)
949 return STM32_ERR_UNKNOWN;
952 static constexpr
auto BUFFER_SIZE = 5;
953 uint8_t buf[BUFFER_SIZE];
954 populate_buffer_with_address(buf, address);
956 stream->write_array(buf, BUFFER_SIZE);
960 if (stm32_get_ack(stm) != STM32_ERR_OK)
961 return STM32_ERR_UNKNOWN;
964 static constexpr
auto BUFFER_SIZE = 5;
965 uint8_t buf[BUFFER_SIZE];
966 populate_buffer_with_address(buf, address);
968 stream->write_array(buf, BUFFER_SIZE);
972 if (stm32_get_ack(stm) != STM32_ERR_OK)
973 return STM32_ERR_UNKNOWN;
975 if (stm32_get_ack(stm) != STM32_ERR_OK)
976 return STM32_ERR_UNKNOWN;
979 uint8_t buf[BUFFER_SIZE];
980 if (!stream->read_array(buf, BUFFER_SIZE))
981 return STM32_ERR_UNKNOWN;
983 if (buf[4] != (buf[0] ^ buf[1] ^ buf[2] ^ buf[3]))
984 return STM32_ERR_UNKNOWN;
986 *crc = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
1001 static constexpr uint32_t CRCPOLY_BE = 0x04c11db7;
1002 static constexpr uint32_t CRC_MSBMASK = 0x80000000;
1005 ESP_LOGD(TAG,
"Buffer length must be multiple of 4 bytes");
1010 uint32_t data = *buf++;
1011 data |= *buf++ << 8;
1012 data |= *buf++ << 16;
1013 data |= *buf++ << 24;
1018 for (
size_t i = 0; i < 32; ++i) {
1019 if (crc & CRC_MSBMASK) {
1020 crc = (crc << 1) ^ CRCPOLY_BE;
1030 static constexpr uint32_t CRC_INIT_VALUE = 0xFFFFFFFF;
1031 static constexpr uint32_t BUFFER_SIZE = 256;
1033 uint8_t buf[BUFFER_SIZE];
1035 if (address & 0x3 || length & 0x3) {
1036 ESP_LOGD(TAG,
"Start and end addresses must be 4 byte aligned");
1037 return STM32_ERR_UNKNOWN;
1040 if (stm->cmd->crc != STM32_CMD_ERR)
1044 const auto total_len =
length;
1045 uint32_t current_crc = CRC_INIT_VALUE;
1047 const auto len = std::min(BUFFER_SIZE, length);
1049 ESP_LOGD(TAG,
"Failed to read memory at address 0x%08x, target write-protected?", address);
1050 return STM32_ERR_UNKNOWN;
1056 ESP_LOGD(TAG,
"\rCRC address 0x%08x (%.2f%%) ", address, (100.0f / (
float) total_len) * (
float) (address - start));
1058 ESP_LOGD(TAG,
"Done.");
1060 return STM32_ERR_OK;
1066 #endif // USE_SHD_FIRMWARE_DATA constexpr auto STREAM_OPT_CMD_INIT
stm32_err_t stm32_wprot_memory(const stm32_unique_ptr &stm)
enum Stm32Err { STM32_ERR_OK=0, STM32_ERR_UNKNOWN, STM32_ERR_NACK, STM32_ERR_NO_CMD, } stm32_err_t
stm32_err_t stm32_wunprot_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)
stm32_err_t stm32_write_memory(const stm32_unique_ptr &stm, uint32_t address, const uint8_t *data, const unsigned int len)
constexpr auto STREAM_OPT_RETRY
struct Stm32Cmd { uint8_t get stm32_cmd_t
stm32_err_t stm32_crc_memory(const stm32_unique_ptr &stm, const uint32_t address, const uint32_t length, uint32_t *const crc)
uint32_t IRAM_ATTR HOT millis()
stm32_err_t stm32_readprot_memory(const stm32_unique_ptr &stm)
constexpr auto STREAM_OPT_BYTE
constexpr stm32_dev_t DEVICES[]
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)
constexpr auto STM32_MAX_PAGES
stm32_unique_ptr stm32_init(uart::UARTDevice *stream, const uint8_t flags, const char init)
std::unique_ptr< stm32_t, void(*)(stm32_t *)> stm32_unique_ptr
constexpr auto STM32_MASS_ERASE
constexpr auto STREAM_OPT_GVR_ETX
stm32_err_t stm32_read_memory(const stm32_unique_ptr &stm, const uint32_t address, uint8_t *data, const unsigned int len)
stm32_err_t stm32_erase_memory(const stm32_unique_ptr &stm, uint32_t spage, uint32_t pages)
struct Stm32 { uart::UARTDevice *stream stm32_t
void IRAM_ATTR HOT yield()
stm32_err_t stm32_runprot_memory(const stm32_unique_ptr &stm)
bool read_array(uint8_t *data, size_t len)
Implementation of SPI Controller mode.
stm32_err_t stm32_reset_device(const stm32_unique_ptr &stm)