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;
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;
450 return STM32_ERR_UNKNOWN;
456 static constexpr int N = 1;
459 return *
reinterpret_cast<const char *
>(&N) == 1;
464 return ((v & 0xFF000000) >> 24) | ((v & 0x00FF0000) >> 8) | ((v & 0x0000FF00) << 8) | ((v & 0x000000FF) << 24);
468template<
size_t N>
void populate_buffer_with_address(uint8_t (&buffer)[N], uint32_t
address) {
469 buffer[0] =
static_cast<uint8_t
>(
address >> 24);
470 buffer[1] =
static_cast<uint8_t
>((
address >> 16) & 0xFF);
471 buffer[2] =
static_cast<uint8_t
>((
address >> 8) & 0xFF);
472 buffer[3] =
static_cast<uint8_t
>(
address & 0xFF);
473 buffer[4] =
static_cast<uint8_t
>(buffer[0] ^ buffer[1] ^ buffer[2] ^ buffer[3]);
477 static const auto CLOSE = [](
stm32_t *stm32) {
485 return std::unique_ptr<
stm32_t,
decltype(CLOSE)>{ptr, CLOSE};
494namespace shelly_dimmer {
497#define newer(prev, a) (((prev) == STM32_CMD_ERR) ? (a) : (((prev) > (a)) ? (prev) : (a)))
502 auto stm = make_stm32_with_deletor(
static_cast<stm32_t *
>(calloc(
sizeof(
stm32_t), 1)));
505 return make_stm32_with_deletor(
nullptr);
507 stm->stream = stream;
512 return make_stm32_with_deletor(
nullptr);
514 memset(stm->cmd, STM32_CMD_ERR,
sizeof(
stm32_cmd_t));
517 if (stm32_send_init_seq(stm) != STM32_ERR_OK)
518 return make_stm32_with_deletor(
nullptr);
522 if (stm32_send_command(stm, STM32_CMD_GVR) != STM32_ERR_OK) {
523 return make_stm32_with_deletor(
nullptr);
530 return make_stm32_with_deletor(
nullptr);
532 stm->version = buf[0];
535 if (stm32_get_ack(stm) != STM32_ERR_OK) {
536 return make_stm32_with_deletor(
nullptr);
541 const auto len = ([&]() {
543 if (stm->cmd_get_reply) {
544 for (
auto i = 0; stm->cmd_get_reply[i].length; ++i) {
545 if (stm->version == stm->cmd_get_reply[i].version) {
546 return stm->cmd_get_reply[i].length;
551 return STM32_CMD_GET_LENGTH;
554 if (stm32_guess_len_cmd(stm, STM32_CMD_GET, buf,
len) != STM32_ERR_OK)
555 return make_stm32_with_deletor(
nullptr);
558 const auto stop = buf[0] + 1;
559 stm->bl_version = buf[1];
561 for (
auto i = 1; i < stop; ++i) {
562 const auto val = buf[i + 1];
580 case STM32_CMD_WM_NS:
581 stm->cmd->wm = newer(stm->cmd->wm,
val);
585 case STM32_CMD_EE_NS:
586 stm->cmd->er = newer(stm->cmd->er,
val);
589 case STM32_CMD_WP_NS:
590 stm->cmd->wp = newer(stm->cmd->wp,
val);
593 case STM32_CMD_UW_NS:
594 stm->cmd->uw = newer(stm->cmd->uw,
val);
597 case STM32_CMD_RP_NS:
598 stm->cmd->rp = newer(stm->cmd->rp,
val);
601 case STM32_CMD_UR_NS:
602 stm->cmd->ur = newer(stm->cmd->ur,
val);
605 stm->cmd->crc = newer(stm->cmd->crc,
val);
608 if (new_cmds++ == 0) {
609 ESP_LOGD(TAG,
"GET returns unknown commands (0x%2x",
val);
611 ESP_LOGD(TAG,
", 0x%2x",
val);
618 if (stm32_get_ack(stm) != STM32_ERR_OK) {
619 return make_stm32_with_deletor(
nullptr);
622 if (stm->cmd->get == STM32_CMD_ERR || stm->cmd->gvr == STM32_CMD_ERR || stm->cmd->gid == STM32_CMD_ERR) {
623 ESP_LOGD(TAG,
"Error: bootloader did not returned correct information from GET command");
624 return make_stm32_with_deletor(
nullptr);
628 if (stm32_guess_len_cmd(stm, stm->cmd->gid, buf, 1) != STM32_ERR_OK) {
629 return make_stm32_with_deletor(
nullptr);
631 const auto returned = buf[0] + 1;
633 ESP_LOGD(TAG,
"Only %d bytes sent in the PID, unknown/unsupported device", returned);
634 return make_stm32_with_deletor(
nullptr);
636 stm->pid = (buf[1] << 8) | buf[2];
638 ESP_LOGD(TAG,
"This bootloader returns %d extra bytes in PID:", returned);
639 for (
auto i = 2; i <= returned; i++)
640 ESP_LOGD(TAG,
" %02x", buf[i]);
642 if (stm32_get_ack(stm) != STM32_ERR_OK) {
643 return make_stm32_with_deletor(
nullptr);
647 while (stm->dev->id != 0x00 && stm->dev->id != stm->pid)
651 ESP_LOGD(TAG,
"Unknown/unsupported device (Device ID: 0x%03x)", stm->pid);
652 return make_stm32_with_deletor(
nullptr);
659 const unsigned int len) {
660 auto *
const stream = stm->stream;
666 ESP_LOGD(TAG,
"Error: READ length limit at 256 bytes");
667 return STM32_ERR_UNKNOWN;
670 if (stm->cmd->rm == STM32_CMD_ERR) {
671 ESP_LOGD(TAG,
"Error: READ command not implemented in bootloader.");
672 return STM32_ERR_NO_CMD;
675 if (stm32_send_command(stm, stm->cmd->rm) != STM32_ERR_OK)
676 return STM32_ERR_UNKNOWN;
678 static constexpr auto BUFFER_SIZE = 5;
679 uint8_t buf[BUFFER_SIZE];
680 populate_buffer_with_address(buf,
address);
682 stream->write_array(buf, BUFFER_SIZE);
685 if (stm32_get_ack(stm) != STM32_ERR_OK)
686 return STM32_ERR_UNKNOWN;
688 if (stm32_send_command(stm,
len - 1) != STM32_ERR_OK)
689 return STM32_ERR_UNKNOWN;
691 if (!stream->read_array(data,
len))
692 return STM32_ERR_UNKNOWN;
698 const unsigned int len) {
699 auto *
const stream = stm->stream;
705 ESP_LOGD(TAG,
"Error: READ length limit at 256 bytes");
706 return STM32_ERR_UNKNOWN;
711 ESP_LOGD(TAG,
"Error: WRITE address must be 4 byte aligned");
712 return STM32_ERR_UNKNOWN;
715 if (stm->cmd->wm == STM32_CMD_ERR) {
716 ESP_LOGD(TAG,
"Error: WRITE command not implemented in bootloader.");
717 return STM32_ERR_NO_CMD;
721 if (stm32_send_command(stm, stm->cmd->wm) != STM32_ERR_OK)
722 return STM32_ERR_UNKNOWN;
724 static constexpr auto BUFFER_SIZE = 5;
725 uint8_t buf1[BUFFER_SIZE];
726 populate_buffer_with_address(buf1,
address);
728 stream->write_array(buf1, BUFFER_SIZE);
730 if (stm32_get_ack(stm) != STM32_ERR_OK)
731 return STM32_ERR_UNKNOWN;
733 const unsigned int aligned_len = (
len + 3) & ~3;
734 uint8_t cs = aligned_len - 1;
735 uint8_t buf[256 + 2];
737 buf[0] = aligned_len - 1;
738 for (
auto i = 0; i <
len; i++) {
740 buf[i + 1] = data[i];
743 for (
auto i =
len; i < aligned_len; i++) {
747 buf[aligned_len + 1] = cs;
748 stream->write_array(buf, aligned_len + 2);
751 const auto s_err = stm32_get_ack_timeout(stm, STM32_BLKWRITE_TIMEOUT);
752 if (s_err != STM32_ERR_OK) {
753 return STM32_ERR_UNKNOWN;
759 if (stm->cmd->uw == STM32_CMD_ERR) {
760 ESP_LOGD(TAG,
"Error: WRITE UNPROTECT command not implemented in bootloader.");
761 return STM32_ERR_NO_CMD;
764 if (stm32_send_command(stm, stm->cmd->uw) != STM32_ERR_OK)
765 return STM32_ERR_UNKNOWN;
767 return stm32_check_ack_timeout(stm32_get_ack_timeout(stm, STM32_WUNPROT_TIMEOUT),
768 []() { ESP_LOGD(TAG,
"Error: Failed to WRITE UNPROTECT"); });
772 if (stm->cmd->wp == STM32_CMD_ERR) {
773 ESP_LOGD(TAG,
"Error: WRITE PROTECT command not implemented in bootloader.");
774 return STM32_ERR_NO_CMD;
777 if (stm32_send_command(stm, stm->cmd->wp) != STM32_ERR_OK)
778 return STM32_ERR_UNKNOWN;
780 return stm32_check_ack_timeout(stm32_get_ack_timeout(stm, STM32_WPROT_TIMEOUT),
781 []() { ESP_LOGD(TAG,
"Error: Failed to WRITE PROTECT"); });
785 if (stm->cmd->ur == STM32_CMD_ERR) {
786 ESP_LOGD(TAG,
"Error: READOUT UNPROTECT command not implemented in bootloader.");
787 return STM32_ERR_NO_CMD;
790 if (stm32_send_command(stm, stm->cmd->ur) != STM32_ERR_OK)
791 return STM32_ERR_UNKNOWN;
793 return stm32_check_ack_timeout(stm32_get_ack_timeout(stm, STM32_MASSERASE_TIMEOUT),
794 []() { ESP_LOGD(TAG,
"Error: Failed to READOUT UNPROTECT"); });
798 if (stm->cmd->rp == STM32_CMD_ERR) {
799 ESP_LOGD(TAG,
"Error: READOUT PROTECT command not implemented in bootloader.");
800 return STM32_ERR_NO_CMD;
803 if (stm32_send_command(stm, stm->cmd->rp) != STM32_ERR_OK)
804 return STM32_ERR_UNKNOWN;
806 return stm32_check_ack_timeout(stm32_get_ack_timeout(stm, STM32_RPROT_TIMEOUT),
807 []() { ESP_LOGD(TAG,
"Error: Failed to READOUT PROTECT"); });
814 if (stm->cmd->er == STM32_CMD_ERR) {
815 ESP_LOGD(TAG,
"Error: ERASE command not implemented in bootloader.");
816 return STM32_ERR_NO_CMD;
830 if (!(stm->dev->flags & F_NO_ME))
831 return stm32_mass_erase(stm);
833 pages = flash_addr_to_page_ceil(stm, stm->dev->fl_end);
840 static constexpr uint32_t MAX_PAGE_SIZE = 512;
842 const auto n = std::min(pages, MAX_PAGE_SIZE);
843 const auto s_err = stm32_pages_erase(stm, spage, n);
844 if (s_err != STM32_ERR_OK)
853 uint32_t code_size) {
854 static constexpr uint32_t BUFFER_SIZE = 256;
856 const auto stack_le = le_u32(0x20002000);
857 const auto code_address_le = le_u32(target_address + 8 + 1);
858 uint32_t
length = code_size + 8;
861 if (target_address & 0x3) {
862 ESP_LOGD(TAG,
"Error: code address must be 4 byte aligned");
863 return STM32_ERR_UNKNOWN;
867 static const auto DELETOR = [](uint8_t *memory) {
872 std::unique_ptr<uint8_t,
decltype(DELETOR)> mem{
static_cast<uint8_t *
>(malloc(
length)),
876 return STM32_ERR_UNKNOWN;
878 memcpy(mem.get(), &stack_le,
sizeof(stack_le));
879 memcpy(mem.get() + 4, &code_address_le,
sizeof(code_address_le));
880 memcpy(mem.get() + 8, code, code_size);
882 auto *pos = mem.get();
885 const auto w = std::min(
length, BUFFER_SIZE);
887 return STM32_ERR_UNKNOWN;
895 return stm32_go(stm, target_address);
899 auto *
const stream = stm->stream;
901 if (stm->cmd->go == STM32_CMD_ERR) {
902 ESP_LOGD(TAG,
"Error: GO command not implemented in bootloader.");
903 return STM32_ERR_NO_CMD;
906 if (stm32_send_command(stm, stm->cmd->go) != STM32_ERR_OK)
907 return STM32_ERR_UNKNOWN;
909 static constexpr auto BUFFER_SIZE = 5;
910 uint8_t buf[BUFFER_SIZE];
911 populate_buffer_with_address(buf,
address);
913 stream->write_array(buf, BUFFER_SIZE);
916 if (stm32_get_ack(stm) != STM32_ERR_OK)
917 return STM32_ERR_UNKNOWN;
922 const auto target_address = stm->dev->ram_start;
924 if (stm->dev->flags & F_OBLL) {
926 return stm32_run_raw_code(stm, target_address, STM_OBL_LAUNCH_CODE, STM_OBL_LAUNCH_CODE_SIZE);
928 return stm32_run_raw_code(stm, target_address, STM_RESET_CODE, STM_RESET_CODE_SIZE);
933 uint32_t *
const crc) {
934 static constexpr auto BUFFER_SIZE = 5;
935 auto *
const stream = stm->stream;
938 ESP_LOGD(TAG,
"Start and end addresses must be 4 byte aligned");
939 return STM32_ERR_UNKNOWN;
942 if (stm->cmd->crc == STM32_CMD_ERR) {
943 ESP_LOGD(TAG,
"Error: CRC command not implemented in bootloader.");
944 return STM32_ERR_NO_CMD;
947 if (stm32_send_command(stm, stm->cmd->crc) != STM32_ERR_OK)
948 return STM32_ERR_UNKNOWN;
951 static constexpr auto BUFFER_SIZE = 5;
952 uint8_t buf[BUFFER_SIZE];
953 populate_buffer_with_address(buf,
address);
955 stream->write_array(buf, BUFFER_SIZE);
959 if (stm32_get_ack(stm) != STM32_ERR_OK)
960 return STM32_ERR_UNKNOWN;
963 static constexpr auto BUFFER_SIZE = 5;
964 uint8_t buf[BUFFER_SIZE];
965 populate_buffer_with_address(buf,
address);
967 stream->write_array(buf, BUFFER_SIZE);
971 if (stm32_get_ack(stm) != STM32_ERR_OK)
972 return STM32_ERR_UNKNOWN;
974 if (stm32_get_ack(stm) != STM32_ERR_OK)
975 return STM32_ERR_UNKNOWN;
978 uint8_t buf[BUFFER_SIZE];
979 if (!stream->read_array(buf, BUFFER_SIZE))
980 return STM32_ERR_UNKNOWN;
982 if (buf[4] != (buf[0] ^ buf[1] ^ buf[2] ^ buf[3]))
983 return STM32_ERR_UNKNOWN;
985 *crc = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
1000 static constexpr uint32_t CRCPOLY_BE = 0x04c11db7;
1001 static constexpr uint32_t CRC_MSBMASK = 0x80000000;
1004 ESP_LOGD(TAG,
"Buffer length must be multiple of 4 bytes");
1009 uint32_t data = *buf++;
1010 data |= *buf++ << 8;
1011 data |= *buf++ << 16;
1012 data |= *buf++ << 24;
1017 for (
size_t i = 0; i < 32; ++i) {
1018 if (crc & CRC_MSBMASK) {
1019 crc = (crc << 1) ^ CRCPOLY_BE;
1029 static constexpr uint32_t CRC_INIT_VALUE = 0xFFFFFFFF;
1030 static constexpr uint32_t BUFFER_SIZE = 256;
1032 uint8_t buf[BUFFER_SIZE];
1035 ESP_LOGD(TAG,
"Start and end addresses must be 4 byte aligned");
1036 return STM32_ERR_UNKNOWN;
1039 if (stm->cmd->crc != STM32_CMD_ERR)
1043 const auto total_len =
length;
1044 uint32_t current_crc = CRC_INIT_VALUE;
1046 const auto len = std::min(BUFFER_SIZE,
length);
1048 ESP_LOGD(TAG,
"Failed to read memory at address 0x%08x, target write-protected?",
address);
1049 return STM32_ERR_UNKNOWN;
1055 ESP_LOGD(TAG,
"\rCRC address 0x%08x (%.2f%%) ",
address, (100.0f / (
float) total_len) * (
float) (
address - start));
1057 ESP_LOGD(TAG,
"Done.");
1059 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()