5#include "dfu/dfu_def.hpp"
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)
76 image_.launch_requested =
false;
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;
98 caps.transfer_size = 0xFFFFu;
117 ResetTransferState();
118 image_.launch_requested =
false;
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;
143 return DFUStatusCode::ERR_USBR;
145 if (HasPendingWrite() || HasPendingManifest())
147 return DFUStatusCode::ERR_NOTDONE;
150 if ((block_num == 0u) &&
159 ResetTransferState();
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;
185 write_.block_num = block_num;
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;
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;
240 status = DFUStatusCode::ERR_FIRMWARE;
244 else if (!
upload_.session_started || block_num !=
upload_.expected_block_num)
246 status = DFUStatusCode::ERR_ADDRESS;
256 if (read_size > data.size_)
258 read_size = data.size_;
261 {reinterpret_cast<uint8_t*>(data.addr_), read_size}) !=
ErrorCode::OK)
263 status = DFUStatusCode::ERR_FIRMWARE;
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;
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;
317 ProcessPendingWrite();
322 ProcessPendingManifest();
326 bool TryRequestRunApp()
334 size_t image_size = 0u;
335 image_.ready = ProbeStoredImage(&image_size);
340 image_.launch_requested =
true;
346 void DfuCommitManifestWaitReset(uint8_t alt)
354 image_.launch_requested =
true;
358 bool TryConsumeAppLaunch(uint32_t)
364 image_.launch_requested =
false;
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
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();
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
460 void ProcessPendingWrite()
464 download_.last_status = DFUStatusCode::ERR_ERASE;
471 download_.last_status = DFUStatusCode::ERR_PROG;
477 download_.expected_block_num =
static_cast<uint16_t
>(
write_.block_num + 1u);
478 download_.last_status = DFUStatusCode::OK;
484 void ProcessPendingManifest()
486 const size_t payload_limit = PayloadLimit();
489 manifest_.last_status = DFUStatusCode::ERR_ADDRESS;
495 if (!ComputeImageCrc32(
download_.received_bytes, crc32))
497 manifest_.last_status = DFUStatusCode::ERR_VERIFY;
501 if (!WriteSeal(
download_.received_bytes, crc32))
503 manifest_.last_status = DFUStatusCode::ERR_VERIFY;
510 image_.launch_requested =
false;
511 manifest_.last_status = DFUStatusCode::OK;
515 upload_.session_started =
false;
517 upload_.expected_block_num = 0u;
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;
544 size_t remain = chunk;
545 while (remain-- > 0u)
557 bool ReadSeal(SealRecord& seal)
566 bool WriteSeal(
size_t image_size, uint32_t crc32)
570 seal->magic = SEAL_MAGIC;
571 seal->image_size =
static_cast<uint32_t
>(image_size);
573 seal->crc32_inv = ~crc32;
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)
641 for (
size_t block = first_block; block <= last_block; ++block)
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;
739template <
typename Backend,
size_t MAX_TRANSFER_SIZE = 4096u>
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;
860 if (
caps_.transfer_size == 0u ||
caps_.transfer_size > MAX_TRANSFER_SIZE)
862 caps_.transfer_size =
static_cast<uint16_t
>(MAX_TRANSFER_SIZE);
875 ResetProtocolState();
876 auto ec =
backend_.DfuSetAlternate(current_alt_setting_);
894 backend_.DfuAbort(current_alt_setting_);
897 ResetProtocolState();
913 if (itf != interface_num_)
921 if (
state_ == DFUState::DFU_DNBUSY ||
state_ == DFUState::DFU_MANIFEST ||
922 state_ == DFUState::DFU_MANIFEST_WAIT_RESET)
929 auto ec =
backend_.DfuSetAlternate(alt);
935 backend_.DfuAbort(current_alt_setting_);
936 current_alt_setting_ = alt;
943 if (itf != interface_num_)
947 alt = current_alt_setting_;
954 const uint8_t desc_type =
static_cast<uint8_t
>((wValue >> 8) & 0xFFu);
955 if (desc_type !=
desc_block_.func_desc.bDescriptorType)
960 out_data = {
reinterpret_cast<const uint8_t*
>(&
desc_block_.func_desc),
972 if ((wIndex & 0xFFu) != interface_num_)
977 switch (
static_cast<DFURequest
>(bRequest))
979 case DFURequest::DETACH:
980 return HandleDetach(result);
982 case DFURequest::DNLOAD:
983 return HandleDnload(wValue, wLength, result);
985 case DFURequest::UPLOAD:
986 return HandleUpload(wValue, wLength, result);
988 case DFURequest::GETSTATUS:
989 return HandleGetStatus(result);
991 case DFURequest::CLRSTATUS:
992 return HandleClearStatus(result);
994 case DFURequest::GETSTATE:
995 return HandleGetState(result);
997 case DFURequest::ABORT:
998 return HandleAbort(result);
1001 return ProtocolStall(DFUStatusCode::ERR_STALLEDPKT);
1007 const auto request =
static_cast<DFURequest
>(bRequest);
1010 if (request != DFURequest::DNLOAD)
1023 uint32_t poll_timeout_ms = 0u;
1029 if (status == DFUStatusCode::OK)
1031 state_ = DFUState::DFU_DNLOAD_SYNC;
1037 EnterErrorState(status);
1044 if (
static_cast<DFURequest
>(bRequest) != DFURequest::GETSTATUS)
1048 if (
state_ == DFUState::DFU_MANIFEST_WAIT_RESET)
1054 backend_.DfuCommitManifestWaitReset(current_alt_setting_);
1059 static constexpr uint8_t BuildAttributeBitmap(
const DFUCapabilities& caps)
1061 return static_cast<uint8_t
>(
1062 (caps.can_download ? ATTR_CAN_DOWNLOAD : 0u) |
1063 (caps.can_upload ? ATTR_CAN_UPLOAD : 0u) |
1064 (caps.manifestation_tolerant ? ATTR_MANIFESTATION_TOLERANT : 0u) |
1065 (caps.will_detach ? ATTR_WILL_DETACH : 0u));
1068 ErrorCode HandleDetach(ControlTransferResult&)
1072 return ProtocolStall(DFUStatusCode::ERR_STALLEDPKT);
1075 ErrorCode HandleDnload(uint16_t block_num, uint16_t wLength,
1076 ControlTransferResult& result)
1078 if (!
caps_.can_download)
1080 return ProtocolStall(DFUStatusCode::ERR_STALLEDPKT);
1082 if (!(
state_ == DFUState::DFU_IDLE ||
state_ == DFUState::DFU_DNLOAD_IDLE))
1084 return ProtocolStall(DFUStatusCode::ERR_STALLEDPKT);
1086 if (wLength >
caps_.transfer_size)
1088 return ProtocolStall(DFUStatusCode::ERR_USBR);
1101 EnterErrorState(DFUStatusCode::ERR_NOTDONE);
1105 state_ = DFUState::DFU_MANIFEST_SYNC;
1109 result.SendStatusInZLP() =
true;
1119 ErrorCode HandleUpload(uint16_t block_num, uint16_t wLength,
1120 ControlTransferResult& result)
1122 if (!
caps_.can_upload)
1124 return ProtocolStall(DFUStatusCode::ERR_STALLEDPKT);
1126 if (!(
state_ == DFUState::DFU_IDLE ||
state_ == DFUState::DFU_UPLOAD_IDLE))
1128 return ProtocolStall(DFUStatusCode::ERR_STALLEDPKT);
1132 return ProtocolStall(DFUStatusCode::ERR_USBR);
1135 size_t req_size = wLength;
1136 if (req_size >
caps_.transfer_size)
1138 req_size =
caps_.transfer_size;
1141 DFUStatusCode op_status = DFUStatusCode::OK;
1142 uint32_t poll_timeout_ms = 0u;
1143 const size_t read_size =
1145 op_status, poll_timeout_ms);
1148 if (op_status != DFUStatusCode::OK)
1150 return ProtocolStall(op_status);
1152 if (read_size > req_size)
1154 return ProtocolStall(DFUStatusCode::ERR_USBR);
1158 state_ = (read_size < req_size) ? DFUState::DFU_IDLE : DFUState::DFU_UPLOAD_IDLE;
1163 ErrorCode HandleGetStatus(ControlTransferResult& result)
1165 AdvanceStateForStatusRead();
1175 ErrorCode HandleClearStatus(ControlTransferResult& result)
1177 if (
state_ != DFUState::DFU_ERROR)
1179 return ProtocolStall(DFUStatusCode::ERR_STALLEDPKT);
1181 backend_.DfuClearStatus(current_alt_setting_);
1183 result.SendStatusInZLP() =
true;
1187 ErrorCode HandleGetState(ControlTransferResult& result)
1194 ErrorCode HandleAbort(ControlTransferResult& result)
1198 case DFUState::DFU_IDLE:
1199 case DFUState::DFU_DNLOAD_SYNC:
1200 case DFUState::DFU_DNLOAD_IDLE:
1201 case DFUState::DFU_UPLOAD_IDLE:
1202 case DFUState::DFU_MANIFEST_SYNC:
1203 backend_.DfuAbort(current_alt_setting_);
1205 result.SendStatusInZLP() =
true;
1209 return ProtocolStall(DFUStatusCode::ERR_STALLEDPKT);
1213 void AdvanceStateForStatusRead()
1220 case DFUState::DFU_DNLOAD_SYNC:
1221 RefreshDownloadStatus();
1224 case DFUState::DFU_MANIFEST_SYNC:
1226 if (
status_ != DFUStatusCode::OK)
1228 state_ = DFUState::DFU_ERROR;
1232 uint32_t poll_timeout_ms = 0u;
1233 auto manifest_status =
1234 backend_.DfuManifest(current_alt_setting_, poll_timeout_ms);
1236 if (manifest_status == DFUStatusCode::OK)
1239 state_ = DFUState::DFU_MANIFEST;
1243 EnterErrorState(manifest_status);
1248 case DFUState::DFU_DNBUSY:
1249 RefreshDownloadStatus();
1252 case DFUState::DFU_MANIFEST:
1253 RefreshManifestStatus();
1261 void RefreshDownloadStatus()
1263 if (
status_ != DFUStatusCode::OK)
1265 state_ = DFUState::DFU_ERROR;
1270 uint32_t poll_timeout_ms = 0u;
1271 const auto download_status =
1272 backend_.DfuGetDownloadStatus(current_alt_setting_, busy, poll_timeout_ms);
1274 if (download_status != DFUStatusCode::OK)
1276 EnterErrorState(download_status);
1284 state_ = busy ? DFUState::DFU_DNBUSY : DFUState::DFU_DNLOAD_IDLE;
1287 void RefreshManifestStatus()
1289 if (
status_ != DFUStatusCode::OK)
1291 state_ = DFUState::DFU_ERROR;
1296 uint32_t poll_timeout_ms = 0u;
1297 const auto manifest_status =
1298 backend_.DfuGetManifestStatus(current_alt_setting_, busy, poll_timeout_ms);
1300 if (manifest_status != DFUStatusCode::OK)
1302 EnterErrorState(manifest_status);
1308 state_ = DFUState::DFU_MANIFEST;
1315 state_ =
caps_.manifestation_tolerant ? DFUState::DFU_IDLE
1316 : DFUState::DFU_MANIFEST_WAIT_RESET;
1319 void ResetProtocolState()
1328 current_alt_setting_ = 0u;
1333 void ClearErrorState()
1336 state_ = DFUState::DFU_IDLE;
1340 void EnterErrorState(DFUStatusCode status)
1347 state_ = DFUState::DFU_ERROR;
1351 ErrorCode ProtocolStall(DFUStatusCode status)
1353 EnterErrorState(status);
1380 using JumpCallback = DfuBootloaderBackend::JumpCallback;
1383 size_t seal_offset, JumpCallback jump_to_app,
1384 void* jump_app_ctx =
nullptr,
bool autorun =
true)
1385 : backend_(flash, image_base, image_limit, seal_offset, jump_to_app, jump_app_ctx,
1387 image_base_(image_base),
1388 image_limit_(image_limit),
1389 seal_offset_(seal_offset)
1394 size_t image_base_ = 0u;
1395 size_t image_limit_ = 0u;
1396 size_t seal_offset_ = 0u;
1403template <
size_t MAX_TRANSFER_SIZE = 4096u>
1405 public DFUClass<DfuBootloaderBackend, MAX_TRANSFER_SIZE>
1411 using JumpCallback = DfuBootloaderBackend::JumpCallback;
1412 static constexpr uint8_t VENDOR_REQUEST_RUN_APP = 0x5Au;
1415 Flash& flash,
size_t image_base,
size_t image_limit,
size_t seal_offset,
1416 JumpCallback jump_to_app,
void* jump_app_ctx =
nullptr,
bool autorun =
true,
1417 const char* interface_string = Base::DEFAULT_INTERFACE_STRING,
1418 const char* webusb_landing_page_url =
nullptr,
1419 uint8_t webusb_vendor_code = LibXR::USB::WebUsb::WEBUSB_VENDOR_CODE_DEFAULT,
1420 const char* winusb_device_interface_guid =
1421 Base::DEFAULT_WINUSB_DEVICE_INTERFACE_GUID,
1422 uint8_t winusb_vendor_code = Base::DEFAULT_WINUSB_VENDOR_CODE)
1423 :
Storage(flash, image_base, image_limit, seal_offset, jump_to_app, jump_app_ctx,
1425 Base(Storage::backend_, interface_string, webusb_landing_page_url,
1426 webusb_vendor_code, winusb_device_interface_guid, winusb_vendor_code)
1432 void Process() { Storage::backend_.Process(); }
1433 bool RequestRunApp() {
return Storage::backend_.TryRequestRunApp(); }
1435 bool TryConsumeAppLaunch(uint32_t now_ms)
1437 return Storage::backend_.TryConsumeAppLaunch(now_ms);
1440 bool HasPendingWork()
const {
return Storage::backend_.HasPendingWork(); }
1441 bool HasValidImage()
const {
return Storage::backend_.HasValidImage(); }
1442 size_t ImageSize()
const {
return Storage::backend_.ImageSize(); }
1443 size_t ImageBase()
const {
return Storage::image_base_; }
1444 size_t ImageLimit()
const {
return Storage::image_limit_; }
1445 size_t SealOffset()
const {
return Storage::seal_offset_; }
1452 if (bRequest != VENDOR_REQUEST_RUN_APP)
1456 if (wLength != 0u || wValue != 0u)
1460 if (Storage::backend_.HasPendingWork())
1466 if (!Storage::backend_.TryRequestRunApp())
1472 result.SendStatusInZLP() =
true;
1477using DfuBootloaderClass = DfuBootloaderClassT<4096u>;
static bool inited_
查找表是否已初始化 / Whether the lookup table is initialized
static uint32_t tab_[256]
CRC32 查找表 / CRC32 lookup table.
static void GenerateTable()
生成 CRC32 查找表 / Generates the CRC32 lookup table
只读原始数据视图 / Immutable raw data view
size_t size_
数据字节数 / Data size in bytes
const void * addr_
数据起始地址 / Data start address
Abstract base class representing a flash memory interface. 抽象基类,表示闪存接口。
size_t MinWriteSize() const
Returns the minimum writable block size in bytes. 获取最小可写块大小(字节)。
virtual ErrorCode Erase(size_t offset, size_t size)=0
Erases a section of the flash memory. 擦除闪存的指定区域。
virtual ErrorCode Write(size_t offset, ConstRawData data)=0
Writes data to the flash memory. 向闪存写入数据。
virtual ErrorCode Read(size_t offset, RawData data)
Reads data from the flash memory. 从闪存中读取数据。
size_t MinEraseSize() const
Returns the minimum erasable block size in bytes. 获取最小可擦除块大小(字节)。
可写原始数据视图 / Mutable raw data view
void SetData(RawData data)
设置内部数据缓存 / Set internal data cache
通用 DFU 前端:实现标准 DFU 状态机,backend 只负责存储细节 Generic DFU frontend: implements the standard DFU state machin...
ErrorCode SetAltSetting(uint8_t itf, uint8_t alt) override
可选:设置接口备用设置 / Optional: set interface alternate setting
bool HasIAD() override
是否包含 IAD / Whether an IAD is used
ErrorCode OnClassData(bool, uint8_t bRequest, LibXR::ConstRawData &data) override
处理 Class request 数据阶段 / Handle class request data stage
ErrorCode WriteDeviceDescriptor(DeviceDescriptor &header) override
可选:覆盖设备描述符字段 / Optional: override device descriptor fields
DFUState state_
DFU 状态 / DFU state.
size_t GetInterfaceCount() override
接口数量 / Number of interfaces contributed
void UnbindEndpoints(EndpointPool &, bool) override
解绑端点资源 / Unbind endpoint resources
uint32_t poll_timeout_ms_
当前轮询超时 / Current poll timeout
uint8_t transfer_buffer_[MAX_TRANSFER_SIZE]
EP0 传输缓冲 / EP0 transfer buffer.
DFUStatusCode status_
DFU 状态码 / DFU status code.
DFUClass(Backend &backend, const char *interface_string=DEFAULT_INTERFACE_STRING, const char *webusb_landing_page_url=nullptr, uint8_t webusb_vendor_code=LibXR::USB::WebUsb::WEBUSB_VENDOR_CODE_DEFAULT, const char *winusb_device_interface_guid=DEFAULT_WINUSB_DEVICE_INTERFACE_GUID, uint8_t winusb_vendor_code=DEFAULT_WINUSB_VENDOR_CODE)
Backend 需要满足的接口契约 / Backend contract requirements.
ErrorCode OnGetDescriptor(bool, uint8_t, uint16_t wValue, uint16_t, ConstRawData &out_data) override
处理标准请求 GET_DESCRIPTOR(类特定描述符) Handle standard GET_DESCRIPTOR request (class-specific descriptors).
uint16_t pending_block_num_
待提交 block 编号 / Pending block number
void BindEndpoints(EndpointPool &, uint8_t start_itf_num, bool) override
绑定端点资源 / Bind endpoint resources
size_t GetMaxConfigSize() override
最大配置描述符占用 / Maximum bytes required in configuration descriptor
uint16_t pending_dnload_length_
待提交 DNLOAD 长度 / Pending DNLOAD length
uint8_t state_response_
GETSTATE 缓冲字节 / GETSTATE byte buffer.
DescriptorBlock desc_block_
描述符缓存 / Descriptor cache
ErrorCode GetAltSetting(uint8_t itf, uint8_t &alt) override
可选:获取接口备用设置 / Optional: get interface alternate setting
void OnClassInDataStatusComplete(bool, uint8_t bRequest) override
类请求的 IN 数据阶段在 STATUS OUT 完成后回调 Called after the STATUS OUT completes for a Class IN data request.
Backend & backend_
后端实现 / Backend implementation
bool download_started_
是否已有有效下载数据 / Whether payload has started
StatusResponse status_response_
GETSTATUS 缓冲区 / GETSTATUS buffer.
DFUCapabilities caps_
能力集缓存 / Capability cache
ErrorCode OnClassRequest(bool, uint8_t bRequest, uint16_t wValue, uint16_t wLength, uint16_t wIndex, ControlTransferResult &result) override
处理 Class-specific 请求(Setup stage)/ Handle class-specific request (Setup stage)
uint8_t GetInterfaceStringIndex(size_t local_interface_index) const
返回已分配的接口字符串索引 Return the assigned USB string index for a local interface.
USB描述符基类 USB descriptor base class.
Data data_
设备描述符数据实例 / Internal data instance
@ APPLICATION_SPECIFIC
应用专用类 / Application Specific
Bootloader DFU 的通用后端:围绕 Flash 基类实现 download/upload/manifest Generic bootloader DFU backend built arou...
uint8_t * erased_blocks_
每块擦除标记 / Per-block erase marks
uint8_t crc_buffer_[256]
CRC 分块缓冲 / CRC chunk buffer.
size_t erase_block_count_
受管块数量 / Number of tracked erase blocks
DFUStatusCode DfuGetManifestStatus(uint8_t alt, bool &busy, uint32_t &poll_timeout_ms)
查询 manifest 异步状态 / Query manifest async status
DownloadState download_
Download 状态 / Download state.
size_t transfer_size_
单次 DFU 传输上限 / Per-transfer DFU limit
uint8_t * seal_storage_
seal 暂存区 / Seal scratch buffer
void DfuClearStatus(uint8_t)
清除 DFU 错误态 / Clear the DFU error state
Flash & flash_
底层 flash 设备 / Underlying flash device
size_t seal_offset_
seal 相对镜像区偏移 / Seal offset inside image region
size_t erase_block_size_
最小擦除粒度 / Minimum erase granularity
size_t image_size_limit_
镜像区总边界 / Image region limit
WriteState write_
写入步骤状态 / Write-step state
UploadState upload_
Upload 状态 / Upload state.
ManifestState manifest_
Manifest 状态 / Manifest state.
bool autorun_
manifest 后是否自动请求运行 / Autorun after manifest
void * jump_app_ctx_
跳转上下文 / Jump callback context
uint8_t * write_buffer_
下载块暂存区 / Download chunk buffer
ImageState image_
镜像级状态 / Image-level state
DFUStatusCode DfuManifest(uint8_t alt, uint32_t &poll_timeout_ms)
启动 manifest 阶段 / Start the manifest stage
size_t seal_storage_size_
seal 暂存大小 / Seal scratch size
JumpCallback jump_to_app_
跳 app 回调 / App jump callback
DFUCapabilities GetDfuCapabilities() const
报告 DFU 能力集 / Report DFU capabilities
size_t image_offset_
镜像区起始偏移 / Image base offset
void DfuAbort(uint8_t)
放弃当前协议会话 / Abort the current protocol session
把 backend 与前端 DFUClass 组装在一起的存储基类 Storage base that assembles the backend and the DFU frontend class.
面向单镜像 bootloader 区的 DFU 类 Bootloader DFU class for a single image region.
ErrorCode OnVendorRequest(bool, uint8_t bRequest, uint16_t wValue, uint16_t wLength, uint16_t, typename Base::ControlTransferResult &result) override
处理 Vendor request(Setup stage)/ Handle vendor request (Setup stage)
DFU 单接口类公共基类 / Common base for single-interface DFU classes.
USB端点池类 / USB endpoint pool class.
@ INIT_ERR
初始化错误 | Initialization error
@ NOT_FOUND
未找到 | Not found
@ NOT_SUPPORT
不支持 | Not supported
@ FAILED
操作失败 | Operation failed
@ OK
操作成功 | Operation successful
@ ARG_ERR
参数错误 | Argument error
接口描述符(9 字节)/ Interface descriptor (9 bytes)
uint8_t iInterface
接口字符串索引 / Interface string index
uint8_t bAlternateSetting
备用设置号 / Alternate setting
uint8_t bInterfaceNumber
接口号 / Interface number
DFU 功能能力集合 / DFU functional capability set.
Bootloader DFU 的接口描述符块 / Bootloader DFU descriptor block.
DFU Functional Descriptor(固件模式) DFU Functional Descriptor for firmware mode.
GETSTATUS 返回包 / GETSTATUS response payload.
控制请求(Class/Vendor)处理结果 / Control request (Class/Vendor) handling result
ClassID bDeviceClass
设备类代码 / Device class code
uint8_t bDeviceSubClass
设备子类代码 / Device subclass code
uint8_t bDeviceProtocol
协议代码 / Protocol code
Download 会话状态 / Download session state.
镜像级状态:独立于一次具体的 DFU 传输会话 Image-level state kept outside any single DFU transfer session.
Manifest 会话状态 / Manifest session state.
seal 区固定记录 / Fixed record stored in the seal region
Upload 会话状态 / Upload session state.
延迟写入步骤状态 / Deferred write-step state