16 using JumpCallback = void (*)(
void*);
17 static constexpr uint32_t SEAL_MAGIC = 0x4C414553u;
25 uint32_t magic = SEAL_MAGIC;
26 uint32_t image_size = 0u;
28 uint32_t crc32_inv = 0u;
41 size_t seal_offset, JumpCallback jump_to_app,
42 void* jump_app_ctx =
nullptr,
bool autorun =
true)
44 image_offset_(image_offset),
45 image_size_limit_(image_size_limit),
46 seal_offset_(seal_offset),
47 jump_to_app_(jump_to_app),
48 jump_app_ctx_(jump_app_ctx),
52 if (erase_block_size_ == 0u)
54 erase_block_size_ = 1u;
56 erase_block_count_ = (image_size_limit_ + erase_block_size_ - 1u) / erase_block_size_;
57 if (erase_block_count_ > 0u)
59 erased_blocks_ =
new uint8_t[erase_block_count_];
60 std::memset(erased_blocks_, 0, erase_block_count_);
63 AlignUp(
sizeof(SealRecord), NonZeroWriteSize(flash_.
MinWriteSize()));
64 seal_storage_ =
new uint8_t[seal_storage_size_];
65 transfer_size_ = PayloadLimit();
66 if (transfer_size_ == 0u)
68 transfer_size_ = 1024u;
70 if (transfer_size_ > 4096u)
72 transfer_size_ = 4096u;
74 write_buffer_ =
new uint8_t[transfer_size_];
76 image_.launch_requested =
false;
78 image_.stored_size = 0u;
81 DfuBootloaderBackend(
const DfuBootloaderBackend&) =
delete;
82 DfuBootloaderBackend& operator=(
const DfuBootloaderBackend&) =
delete;
90 caps.can_download =
true;
91 caps.can_upload =
true;
92 caps.manifestation_tolerant =
false;
93 caps.will_detach =
false;
94 caps.detach_timeout_ms = 0u;
96 if (transfer_size_ > 0xFFFFu)
98 caps.transfer_size = 0xFFFFu;
102 caps.transfer_size =
static_cast<uint16_t
>(transfer_size_);
117 ResetTransferState();
118 image_.launch_requested =
false;
119 image_.ready =
false;
120 image_.stored_size = 0u;
128 ResetTransferState();
129 image_.launch_requested =
false;
132 DFUStatusCode DfuDownload(uint8_t alt, uint16_t block_num,
ConstRawData data,
133 uint32_t& poll_timeout_ms)
135 poll_timeout_ms = 0u;
139 return DFUStatusCode::ERR_TARGET;
141 if (data.
addr_ ==
nullptr || data.
size_ == 0u || data.
size_ > transfer_size_)
143 return DFUStatusCode::ERR_USBR;
145 if (HasPendingWrite() || HasPendingManifest())
147 return DFUStatusCode::ERR_NOTDONE;
150 if ((block_num == 0u) &&
151 (download_.session_started &&
152 (download_.received_bytes != 0u || download_.expected_block_num != 0u)))
159 ResetTransferState();
162 if (!download_.session_started)
166 return DFUStatusCode::ERR_ADDRESS;
168 StartDownloadSession();
170 else if (block_num != download_.expected_block_num)
172 return DFUStatusCode::ERR_ADDRESS;
175 const size_t offset = download_.received_bytes;
176 const size_t payload_limit = PayloadLimit();
177 if (offset + data.
size_ < offset || (offset + data.
size_) > payload_limit)
179 return DFUStatusCode::ERR_ADDRESS;
182 std::memcpy(write_buffer_, data.
addr_, data.
size_);
183 write_.offset = offset;
184 write_.len = data.
size_;
185 write_.block_num = block_num;
186 write_.pending =
true;
187 download_.last_status = DFUStatusCode::OK;
188 download_.next_poll_timeout_ms = ComputeWritePollTimeout(offset, data.
size_);
189 poll_timeout_ms = download_.next_poll_timeout_ms;
190 return DFUStatusCode::OK;
193 DFUStatusCode DfuGetDownloadStatus(uint8_t alt,
bool& busy, uint32_t& poll_timeout_ms)
198 poll_timeout_ms = 0u;
199 return DFUStatusCode::ERR_TARGET;
201 busy = HasPendingWrite();
202 poll_timeout_ms = busy ? download_.next_poll_timeout_ms : 0u;
203 return download_.last_status;
206 size_t DfuUpload(uint8_t alt, uint16_t block_num, RawData data, DFUStatusCode& status,
207 uint32_t& poll_timeout_ms)
209 poll_timeout_ms = 0u;
210 status = DFUStatusCode::OK;
214 status = DFUStatusCode::ERR_TARGET;
217 if (data.addr_ ==
nullptr || data.size_ == 0u)
219 status = DFUStatusCode::ERR_USBR;
225 upload_.session_started =
true;
227 upload_.expected_block_num = 1u;
228 size_t image_size = 0u;
231 image_size = image_.stored_size;
233 else if (!ProbeStoredImage(&image_size))
237 upload_.image_size = image_size;
238 if (upload_.image_size == 0u)
240 status = DFUStatusCode::ERR_FIRMWARE;
244 else if (!upload_.session_started || block_num != upload_.expected_block_num)
246 status = DFUStatusCode::ERR_ADDRESS;
250 if (upload_.offset >= upload_.image_size)
255 size_t read_size = upload_.image_size - upload_.offset;
256 if (read_size > data.size_)
258 read_size = data.size_;
260 if (flash_.
Read(image_offset_ + upload_.offset,
261 {reinterpret_cast<uint8_t*>(data.addr_), read_size}) !=
ErrorCode::OK)
263 status = DFUStatusCode::ERR_FIRMWARE;
267 upload_.offset += read_size;
268 upload_.expected_block_num =
static_cast<uint16_t
>(block_num + 1u);
277 poll_timeout_ms = 0u;
281 return DFUStatusCode::ERR_TARGET;
283 if (!download_.session_started || download_.received_bytes == 0u || HasPendingWrite())
285 return DFUStatusCode::ERR_NOTDONE;
287 manifest_.pending =
true;
288 manifest_.last_status = DFUStatusCode::OK;
289 poll_timeout_ms = manifest_.poll_timeout_ms;
290 return DFUStatusCode::OK;
301 poll_timeout_ms = 0u;
302 return DFUStatusCode::ERR_TARGET;
304 busy = HasPendingManifest();
305 poll_timeout_ms = busy ? manifest_.poll_timeout_ms : 0u;
306 return manifest_.last_status;
317 ProcessPendingWrite();
320 if (manifest_.pending)
322 ProcessPendingManifest();
326 bool TryRequestRunApp()
334 size_t image_size = 0u;
335 image_.ready = ProbeStoredImage(&image_size);
336 image_.stored_size = image_.ready ? image_size : 0u;
340 image_.launch_requested =
true;
346 void DfuCommitManifestWaitReset(uint8_t alt)
352 if (autorun_ && image_.ready)
354 image_.launch_requested =
true;
358 bool TryConsumeAppLaunch(uint32_t)
360 if (!image_.launch_requested || !image_.ready)
364 image_.launch_requested =
false;
365 if (jump_to_app_ !=
nullptr)
367 jump_to_app_(jump_app_ctx_);
372 bool HasPendingWork()
const {
return HasPendingWrite() || HasPendingManifest(); }
374 bool HasValidImage()
const {
return image_.ready; }
375 size_t ImageSize()
const {
return image_.stored_size; }
380 size_t PayloadLimit()
const
382 if (seal_offset_ > image_size_limit_)
389 static size_t NonZeroWriteSize(
size_t write_size)
391 return (write_size == 0u) ? 1u : write_size;
394 static size_t AlignUp(
size_t value,
size_t align)
400 const size_t rem = value % align;
401 return (rem == 0u) ? value : (value + align - rem);
406 void StartDownloadSession()
408 ResetTransferState();
409 if (erase_block_count_ > 0u)
411 std::memset(erased_blocks_, 0, erase_block_count_);
413 download_.session_started =
true;
414 image_.ready =
false;
415 image_.stored_size = 0u;
416 image_.launch_requested =
false;
419 void ResetTransferState()
431 bool HasPendingWrite()
const {
return write_.pending; }
433 bool HasPendingManifest()
const {
return manifest_.pending; }
439 uint32_t ComputeWritePollTimeout(
size_t offset,
size_t len)
const
441 const size_t first_block = offset / erase_block_size_;
442 const size_t last_block = (offset + len - 1u) / erase_block_size_;
443 for (
size_t block = first_block; block <= last_block && block < erase_block_count_;
446 if (erased_blocks_[block] == 0u)
460 void ProcessPendingWrite()
462 if (!EnsureBlocksErased(write_.offset, write_.len))
464 download_.last_status = DFUStatusCode::ERR_ERASE;
465 write_.pending =
false;
468 if (flash_.
Write(image_offset_ + write_.offset, {write_buffer_, write_.len}) !=
471 download_.last_status = DFUStatusCode::ERR_PROG;
472 write_.pending =
false;
476 download_.received_bytes = write_.offset + write_.len;
477 download_.expected_block_num =
static_cast<uint16_t
>(write_.block_num + 1u);
478 download_.last_status = DFUStatusCode::OK;
479 write_.pending =
false;
484 void ProcessPendingManifest()
486 const size_t payload_limit = PayloadLimit();
487 if (download_.received_bytes == 0u || download_.received_bytes > payload_limit)
489 manifest_.last_status = DFUStatusCode::ERR_ADDRESS;
490 manifest_.pending =
false;
495 if (!ComputeImageCrc32(download_.received_bytes, crc32))
497 manifest_.last_status = DFUStatusCode::ERR_VERIFY;
498 manifest_.pending =
false;
501 if (!WriteSeal(download_.received_bytes, crc32))
503 manifest_.last_status = DFUStatusCode::ERR_VERIFY;
504 manifest_.pending =
false;
508 image_.stored_size = download_.received_bytes;
510 image_.launch_requested =
false;
511 manifest_.last_status = DFUStatusCode::OK;
512 download_.session_started =
false;
513 download_.received_bytes = 0u;
514 download_.expected_block_num = 0u;
515 upload_.session_started =
false;
517 upload_.expected_block_num = 0u;
518 upload_.image_size = 0u;
519 manifest_.pending =
false;
524 bool ComputeImageCrc32(
size_t image_size, uint32_t& crc32_out)
530 uint32_t crc = 0xFFFFFFFFu;
532 while (offset < image_size)
534 size_t chunk = image_size - offset;
535 if (chunk >
sizeof(crc_buffer_))
537 chunk =
sizeof(crc_buffer_);
543 const uint8_t* buf = crc_buffer_;
544 size_t remain = chunk;
545 while (remain-- > 0u)
557 bool ReadSeal(SealRecord& seal)
559 return flash_.
Read(image_offset_ + seal_offset_, {
reinterpret_cast<uint8_t*
>(&seal),
566 bool WriteSeal(
size_t image_size, uint32_t crc32)
568 std::memset(seal_storage_, 0xFF, seal_storage_size_);
569 auto* seal =
reinterpret_cast<SealRecord*
>(seal_storage_);
570 seal->magic = SEAL_MAGIC;
571 seal->image_size =
static_cast<uint32_t
>(image_size);
573 seal->crc32_inv = ~crc32;
575 if (!EnsureBlocksErased(seal_offset_, seal_storage_size_))
579 return flash_.
Write(image_offset_ + seal_offset_,
587 bool ProbeStoredImage(
size_t* out_image_size)
589 SealRecord seal = {};
594 if (seal.magic != SEAL_MAGIC)
598 if ((seal.crc32 ^ seal.crc32_inv) != 0xFFFFFFFFu)
602 const size_t image_size =
static_cast<size_t>(seal.image_size);
603 if (image_size == 0u || image_size > PayloadLimit())
607 uint32_t actual_crc = 0u;
608 if (!ComputeImageCrc32(image_size, actual_crc))
612 if (actual_crc != seal.crc32)
616 if (out_image_size !=
nullptr)
618 *out_image_size = image_size;
627 bool EnsureBlocksErased(
size_t offset,
size_t len)
634 const size_t first_block = offset / erase_block_size_;
635 const size_t last_block = (offset + len - 1u) / erase_block_size_;
636 if (last_block >= erase_block_count_)
641 for (
size_t block = first_block; block <= last_block; ++block)
643 if (erased_blocks_[block] != 0u)
647 const size_t block_offset = block * erase_block_size_;
652 erased_blocks_[block] = 1u;
663 bool launch_requested =
false;
665 size_t stored_size = 0u;
673 bool session_started =
false;
674 size_t received_bytes = 0u;
675 uint16_t expected_block_num = 0u;
676 uint32_t next_poll_timeout_ms = 0u;
677 DFUStatusCode last_status = DFUStatusCode::OK;
687 uint16_t block_num = 0u;
688 bool pending =
false;
696 bool pending =
false;
697 uint32_t poll_timeout_ms = 50u;
698 DFUStatusCode last_status = DFUStatusCode::OK;
706 bool session_started =
false;
708 uint16_t expected_block_num = 0u;
709 size_t image_size = 0u;
713 size_t image_offset_ = 0u;
714 size_t image_size_limit_ = 0u;
715 size_t seal_offset_ = 0u;
716 JumpCallback jump_to_app_ =
nullptr;
717 void* jump_app_ctx_ =
nullptr;
718 bool autorun_ =
true;
719 ImageState image_ = {};
720 size_t erase_block_size_ = 1u;
721 size_t erase_block_count_ = 0u;
722 uint8_t* erased_blocks_ =
nullptr;
723 size_t seal_storage_size_ = 0u;
724 uint8_t* seal_storage_ =
nullptr;
725 size_t transfer_size_ = 0u;
726 uint8_t* write_buffer_ =
nullptr;
727 uint8_t crc_buffer_[256] = {};
728 DownloadState download_ = {};
729 WriteState write_ = {};
730 ManifestState manifest_ = {};
731 UploadState upload_ = {};
742 static_assert(MAX_TRANSFER_SIZE > 0u,
"DFU transfer size must be non-zero.");
743 static_assert(MAX_TRANSFER_SIZE <= 0xFFFFu,
744 "DFU transfer size must fit in wTransferSize.");
746 static constexpr uint8_t INTERFACE_CLASS = 0xFEu;
747 static constexpr uint8_t INTERFACE_SUB_CLASS = 0x01u;
748 static constexpr uint8_t INTERFACE_PROTOCOL = 0x02u;
749 static constexpr uint16_t DFU_VERSION = 0x0110u;
751 static constexpr uint8_t ATTR_CAN_DOWNLOAD = 0x01u;
752 static constexpr uint8_t ATTR_CAN_UPLOAD = 0x02u;
753 static constexpr uint8_t ATTR_MANIFESTATION_TOLERANT = 0x04u;
754 static constexpr uint8_t ATTR_WILL_DETACH = 0x08u;
765 uint8_t bDescriptorType = 0x21;
766 uint8_t bmAttributes = 0;
767 uint16_t wDetachTimeOut = 0;
768 uint16_t wTransferSize = 0;
769 uint16_t bcdDFUVersion = DFU_VERSION;
778 uint8_t bwPollTimeout[3] = {0, 0, 0};
782 void SetPollTimeout(uint32_t timeout_ms)
784 bwPollTimeout[0] =
static_cast<uint8_t
>(timeout_ms & 0xFFu);
785 bwPollTimeout[1] =
static_cast<uint8_t
>((timeout_ms >> 8) & 0xFFu);
786 bwPollTimeout[2] =
static_cast<uint8_t
>((timeout_ms >> 16) & 0xFFu);
797 static_cast<uint8_t
>(DescriptorType::INTERFACE),
810 "DFU functional descriptor size mismatch.");
811 static_assert(
sizeof(
StatusResponse) == 6,
"DFU status response size mismatch.");
814 static constexpr const char* DEFAULT_INTERFACE_STRING =
"XRUSB DFU";
815 static constexpr const char* DEFAULT_WINUSB_DEVICE_INTERFACE_GUID =
816 DfuInterfaceClassBase::DEFAULT_WINUSB_DEVICE_INTERFACE_GUID;
817 static constexpr uint8_t DEFAULT_WINUSB_VENDOR_CODE =
818 DfuInterfaceClassBase::DEFAULT_WINUSB_VENDOR_CODE;
838 Backend& backend,
const char* interface_string = DEFAULT_INTERFACE_STRING,
839 const char* webusb_landing_page_url =
nullptr,
840 uint8_t webusb_vendor_code = LibXR::USB::WebUsb::WEBUSB_VENDOR_CODE_DEFAULT,
841 const char* winusb_device_interface_guid = DEFAULT_WINUSB_DEVICE_INTERFACE_GUID,
842 uint8_t winusb_vendor_code = DEFAULT_WINUSB_VENDOR_CODE)
844 webusb_vendor_code, winusb_device_interface_guid,
856 interface_num_ = start_itf_num;
857 current_alt_setting_ = 0u;
859 caps_ = backend_.GetDfuCapabilities();
860 if (caps_.transfer_size == 0u || caps_.transfer_size > MAX_TRANSFER_SIZE)
862 caps_.transfer_size =
static_cast<uint16_t
>(MAX_TRANSFER_SIZE);
868 desc_block_.func_desc.bmAttributes = BuildAttributeBitmap(caps_);
869 desc_block_.func_desc.wDetachTimeOut = caps_.detach_timeout_ms;
870 desc_block_.func_desc.wTransferSize = caps_.transfer_size;
871 desc_block_.func_desc.bcdDFUVersion = DFU_VERSION;
873 SetData(
RawData{
reinterpret_cast<uint8_t*
>(&desc_block_),
sizeof(desc_block_)});
875 ResetProtocolState();
876 auto ec = backend_.DfuSetAlternate(current_alt_setting_);
893 backend_.DfuAbort(current_alt_setting_);
896 ResetProtocolState();
912 if (itf != interface_num_)
920 if (state_ == DFUState::DFU_DNBUSY || state_ == DFUState::DFU_MANIFEST ||
921 state_ == DFUState::DFU_MANIFEST_WAIT_RESET)
928 auto ec = backend_.DfuSetAlternate(alt);
934 backend_.DfuAbort(current_alt_setting_);
935 current_alt_setting_ = alt;
942 if (itf != interface_num_)
946 alt = current_alt_setting_;
953 const uint8_t desc_type =
static_cast<uint8_t
>((wValue >> 8) & 0xFFu);
954 if (desc_type != desc_block_.func_desc.bDescriptorType)
959 out_data = {
reinterpret_cast<const uint8_t*
>(&desc_block_.func_desc),
960 sizeof(desc_block_.func_desc)};
971 if ((wIndex & 0xFFu) != interface_num_)
976 switch (
static_cast<DFURequest
>(bRequest))
978 case DFURequest::DETACH:
979 return HandleDetach(result);
981 case DFURequest::DNLOAD:
982 return HandleDnload(wValue, wLength, result);
984 case DFURequest::UPLOAD:
985 return HandleUpload(wValue, wLength, result);
987 case DFURequest::GETSTATUS:
988 return HandleGetStatus(result);
990 case DFURequest::CLRSTATUS:
991 return HandleClearStatus(result);
993 case DFURequest::GETSTATE:
994 return HandleGetState(result);
996 case DFURequest::ABORT:
997 return HandleAbort(result);
1000 return ProtocolStall(DFUStatusCode::ERR_STALLEDPKT);
1006 const auto request =
static_cast<DFURequest
>(bRequest);
1009 if (request != DFURequest::DNLOAD)
1014 if (pending_dnload_length_ == 0u)
1022 uint32_t poll_timeout_ms = 0u;
1023 auto status = backend_.DfuDownload(current_alt_setting_, pending_block_num_, data,
1025 pending_dnload_length_ = 0u;
1026 poll_timeout_ms_ = poll_timeout_ms;
1028 if (status == DFUStatusCode::OK)
1030 state_ = DFUState::DFU_DNLOAD_SYNC;
1031 status_ = DFUStatusCode::OK;
1032 download_started_ =
true;
1036 EnterErrorState(status);
1043 if (
static_cast<DFURequest
>(bRequest) != DFURequest::GETSTATUS)
1047 if (state_ == DFUState::DFU_MANIFEST_WAIT_RESET)
1053 backend_.DfuCommitManifestWaitReset(current_alt_setting_);
1058 static constexpr uint8_t BuildAttributeBitmap(
const DFUCapabilities& caps)
1060 return static_cast<uint8_t
>(
1061 (caps.can_download ? ATTR_CAN_DOWNLOAD : 0u) |
1062 (caps.can_upload ? ATTR_CAN_UPLOAD : 0u) |
1063 (caps.manifestation_tolerant ? ATTR_MANIFESTATION_TOLERANT : 0u) |
1064 (caps.will_detach ? ATTR_WILL_DETACH : 0u));
1067 ErrorCode HandleDetach(ControlTransferResult&)
1071 return ProtocolStall(DFUStatusCode::ERR_STALLEDPKT);
1074 ErrorCode HandleDnload(uint16_t block_num, uint16_t wLength,
1075 ControlTransferResult& result)
1077 if (!caps_.can_download)
1079 return ProtocolStall(DFUStatusCode::ERR_STALLEDPKT);
1081 if (!(state_ == DFUState::DFU_IDLE || state_ == DFUState::DFU_DNLOAD_IDLE))
1083 return ProtocolStall(DFUStatusCode::ERR_STALLEDPKT);
1085 if (wLength > caps_.transfer_size)
1087 return ProtocolStall(DFUStatusCode::ERR_USBR);
1096 pending_dnload_length_ = 0u;
1097 pending_block_num_ = block_num;
1098 if (!download_started_)
1100 EnterErrorState(DFUStatusCode::ERR_NOTDONE);
1104 state_ = DFUState::DFU_MANIFEST_SYNC;
1105 status_ = DFUStatusCode::OK;
1106 poll_timeout_ms_ = 0u;
1108 result.SendStatusInZLP() =
true;
1112 pending_block_num_ = block_num;
1113 pending_dnload_length_ = wLength;
1114 result.OutData() = {transfer_buffer_, wLength};
1118 ErrorCode HandleUpload(uint16_t block_num, uint16_t wLength,
1119 ControlTransferResult& result)
1121 if (!caps_.can_upload)
1123 return ProtocolStall(DFUStatusCode::ERR_STALLEDPKT);
1125 if (!(state_ == DFUState::DFU_IDLE || state_ == DFUState::DFU_UPLOAD_IDLE))
1127 return ProtocolStall(DFUStatusCode::ERR_STALLEDPKT);
1131 return ProtocolStall(DFUStatusCode::ERR_USBR);
1134 size_t req_size = wLength;
1135 if (req_size > caps_.transfer_size)
1137 req_size = caps_.transfer_size;
1140 DFUStatusCode op_status = DFUStatusCode::OK;
1141 uint32_t poll_timeout_ms = 0u;
1142 const size_t read_size =
1143 backend_.DfuUpload(current_alt_setting_, block_num, {transfer_buffer_, req_size},
1144 op_status, poll_timeout_ms);
1146 poll_timeout_ms_ = poll_timeout_ms;
1147 if (op_status != DFUStatusCode::OK)
1149 return ProtocolStall(op_status);
1151 if (read_size > req_size)
1153 return ProtocolStall(DFUStatusCode::ERR_USBR);
1156 status_ = DFUStatusCode::OK;
1157 state_ = (read_size < req_size) ? DFUState::DFU_IDLE : DFUState::DFU_UPLOAD_IDLE;
1158 result.InData() = {transfer_buffer_, read_size};
1162 ErrorCode HandleGetStatus(ControlTransferResult& result)
1164 AdvanceStateForStatusRead();
1165 status_response_.bStatus =
static_cast<uint8_t
>(status_);
1166 status_response_.SetPollTimeout(poll_timeout_ms_);
1167 status_response_.bState =
static_cast<uint8_t
>(state_);
1168 status_response_.iString = 0u;
1169 result.InData() = {
reinterpret_cast<const uint8_t*
>(&status_response_),
1170 sizeof(status_response_)};
1174 ErrorCode HandleClearStatus(ControlTransferResult& result)
1176 if (state_ != DFUState::DFU_ERROR)
1178 return ProtocolStall(DFUStatusCode::ERR_STALLEDPKT);
1180 backend_.DfuClearStatus(current_alt_setting_);
1182 result.SendStatusInZLP() =
true;
1186 ErrorCode HandleGetState(ControlTransferResult& result)
1188 state_response_ =
static_cast<uint8_t
>(state_);
1189 result.InData() = {&state_response_,
sizeof(state_response_)};
1193 ErrorCode HandleAbort(ControlTransferResult& result)
1197 case DFUState::DFU_IDLE:
1198 case DFUState::DFU_DNLOAD_SYNC:
1199 case DFUState::DFU_DNLOAD_IDLE:
1200 case DFUState::DFU_UPLOAD_IDLE:
1201 case DFUState::DFU_MANIFEST_SYNC:
1202 backend_.DfuAbort(current_alt_setting_);
1204 result.SendStatusInZLP() =
true;
1208 return ProtocolStall(DFUStatusCode::ERR_STALLEDPKT);
1212 void AdvanceStateForStatusRead()
1219 case DFUState::DFU_DNLOAD_SYNC:
1220 RefreshDownloadStatus();
1223 case DFUState::DFU_MANIFEST_SYNC:
1225 if (status_ != DFUStatusCode::OK)
1227 state_ = DFUState::DFU_ERROR;
1231 uint32_t poll_timeout_ms = 0u;
1232 auto manifest_status =
1233 backend_.DfuManifest(current_alt_setting_, poll_timeout_ms);
1234 poll_timeout_ms_ = poll_timeout_ms;
1235 if (manifest_status == DFUStatusCode::OK)
1237 status_ = DFUStatusCode::OK;
1238 state_ = DFUState::DFU_MANIFEST;
1242 EnterErrorState(manifest_status);
1247 case DFUState::DFU_DNBUSY:
1248 RefreshDownloadStatus();
1251 case DFUState::DFU_MANIFEST:
1252 RefreshManifestStatus();
1260 void RefreshDownloadStatus()
1262 if (status_ != DFUStatusCode::OK)
1264 state_ = DFUState::DFU_ERROR;
1269 uint32_t poll_timeout_ms = 0u;
1270 const auto download_status =
1271 backend_.DfuGetDownloadStatus(current_alt_setting_, busy, poll_timeout_ms);
1272 poll_timeout_ms_ = poll_timeout_ms;
1273 if (download_status != DFUStatusCode::OK)
1275 EnterErrorState(download_status);
1283 state_ = busy ? DFUState::DFU_DNBUSY : DFUState::DFU_DNLOAD_IDLE;
1286 void RefreshManifestStatus()
1288 if (status_ != DFUStatusCode::OK)
1290 state_ = DFUState::DFU_ERROR;
1295 uint32_t poll_timeout_ms = 0u;
1296 const auto manifest_status =
1297 backend_.DfuGetManifestStatus(current_alt_setting_, busy, poll_timeout_ms);
1298 poll_timeout_ms_ = poll_timeout_ms;
1299 if (manifest_status != DFUStatusCode::OK)
1301 EnterErrorState(manifest_status);
1307 state_ = DFUState::DFU_MANIFEST;
1313 download_started_ =
false;
1314 state_ = caps_.manifestation_tolerant ? DFUState::DFU_IDLE
1315 : DFUState::DFU_MANIFEST_WAIT_RESET;
1318 void ResetProtocolState()
1324 pending_block_num_ = 0u;
1325 pending_dnload_length_ = 0u;
1326 poll_timeout_ms_ = 0u;
1327 current_alt_setting_ = 0u;
1328 download_started_ =
false;
1332 void ClearErrorState()
1334 status_ = DFUStatusCode::OK;
1335 state_ = DFUState::DFU_IDLE;
1336 poll_timeout_ms_ = 0u;
1339 void EnterErrorState(DFUStatusCode status)
1346 state_ = DFUState::DFU_ERROR;
1347 poll_timeout_ms_ = 0u;
1350 ErrorCode ProtocolStall(DFUStatusCode status)
1352 EnterErrorState(status);
1358 DFUCapabilities caps_ = {};
1359 DescriptorBlock desc_block_ = {};
1360 StatusResponse status_response_ = {};
1361 uint8_t state_response_ = 0u;
1362 uint8_t transfer_buffer_[MAX_TRANSFER_SIZE] =
1364 bool download_started_ =
false;
1365 uint16_t pending_block_num_ = 0u;
1366 uint16_t pending_dnload_length_ = 0u;
1367 uint32_t poll_timeout_ms_ = 0u;
1368 DFUState state_ = DFUState::DFU_IDLE;
1369 DFUStatusCode status_ = DFUStatusCode::OK;