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";
116namespace 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;
358template<
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;
463uint32_t le_u32(
const uint32_t v) {
465 return ((v & 0xFF000000) >> 24) | ((v & 0x00FF0000) >> 8) | ((v & 0x0000FF00) << 8) | ((v & 0x000000FF) << 24);
469template<
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};
495namespace 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;
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];
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;
bool read_array(uint8_t *data, size_t len)
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)
Providing packet encoding functions for exchanging data with a remote host.
void IRAM_ATTR HOT yield()
uint32_t IRAM_ATTR HOT millis()