From 3225669c84cb502508d051f3f7481f719e991966 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20Vi=C3=B6l?= Date: Tue, 28 Nov 2023 09:56:38 +0100 Subject: [PATCH 01/25] Update dependecies --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 067cb2c..36bbeb4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,8 +12,8 @@ repository = "https://github.com/rust-embedded-community/usb-device" [dependencies] defmt = { version = "0.3", optional = true } portable-atomic = { version = "1.2.0", default-features = false } -num_enum = { version = "0.6.1", default-features = false } -heapless = "0.7" +num_enum = { version = "0.7.1", default-features = false } +heapless = "0.8" [dev-dependencies] rusb = "0.9.1" From 0ca8f09dbe007d88862b8c958e93f5b9f0c281e7 Mon Sep 17 00:00:00 2001 From: "m. interrupt" Date: Wed, 3 Jan 2024 02:17:53 -0500 Subject: [PATCH 02/25] Update README.md 2 spellings fixes --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a6545dc..df04b8b 100644 --- a/README.md +++ b/README.md @@ -5,9 +5,9 @@ USB stack for embedded devices in Rust. The UsbDevice object represents a composite USB device and is the most important object for application implementors. The UsbDevice combines a number of UsbClasses (either custom ones, or -pre-existing ones provided by other crates) and a UsbBus device drives to implement the USB device. +pre-existing ones provided by other crates) and a UsbBus device driver to implement the USB device. -The UsbClass trait can be used to implemented USB classes such as a HID device or a serial port. An +The UsbClass trait can be used to implement USB classes such as a HID device or a serial port. An implementation may also use a custom class if the required functionality isn't covered by a standard class. From 34b60163ea5285493291ece3d1e27a1234fd0cb5 Mon Sep 17 00:00:00 2001 From: Jose Acevedo Date: Wed, 31 Jan 2024 02:49:19 -0500 Subject: [PATCH 03/25] fix: make LangID optional on get_string --- src/class.rs | 2 +- src/device.rs | 29 ++++++++++++++++------------- src/test_class.rs | 4 ++-- 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/class.rs b/src/class.rs index 9b18cc0..3eae3c4 100644 --- a/src/class.rs +++ b/src/class.rs @@ -44,7 +44,7 @@ pub trait UsbClass { /// * `index` - A string index allocated earlier with /// [`UsbAllocator`](crate::bus::UsbBusAllocator). /// * `lang_id` - The language ID for the string to retrieve. - fn get_string(&self, index: StringIndex, lang_id: LangID) -> Option<&str> { + fn get_string(&self, index: StringIndex, lang_id: Option) -> Option<&str> { let _ = (index, lang_id); None } diff --git a/src/device.rs b/src/device.rs index e1ca323..2c7297d 100644 --- a/src/device.rs +++ b/src/device.rs @@ -563,22 +563,25 @@ impl UsbDevice<'_, B> { // rest STRING Requests _ => { - let lang_id = match LangID::try_from(req.index) { - Err(_err) => { - #[cfg(feature = "defmt")] - defmt::warn!( - "Receive unknown LANGID {:#06X}, reject the request", - _err.number - ); - xfer.reject().ok(); - return; - } + let lang_id = LangID::try_from(req.index); - Ok(req_lang_id) => req_lang_id, - }; let string = match index { // Manufacturer, product, and serial are handled directly here. 1..=3 => { + let lang_id = match lang_id { + Err(_err) => { + #[cfg(feature = "defmt")] + defmt::warn!( + "Receive unknown LANGID {:#06X}, reject the request", + _err.number + ); + xfer.reject().ok(); + return; + } + + Ok(req_lang_id) => req_lang_id, + }; + let Some(lang) = config .string_descriptors .iter() @@ -599,7 +602,7 @@ impl UsbDevice<'_, B> { let index = StringIndex::new(index); classes .iter() - .find_map(|cls| cls.get_string(index, lang_id)) + .find_map(|cls| cls.get_string(index, lang_id.ok())) } }; diff --git a/src/test_class.rs b/src/test_class.rs index ec26f77..c2fb13d 100644 --- a/src/test_class.rs +++ b/src/test_class.rs @@ -232,8 +232,8 @@ impl UsbClass for TestClass<'_, B> { Ok(()) } - fn get_string(&self, index: StringIndex, lang_id: LangID) -> Option<&str> { - if lang_id == LangID::EN_US { + fn get_string(&self, index: StringIndex, lang_id: Option) -> Option<&str> { + if lang_id == Some(LangID::EN_US) { if index == self.custom_string { return Some(CUSTOM_STRING); } else if index == self.interface_string { From b96ccb9179c2f066d92a8c746d5db6a192986cdd Mon Sep 17 00:00:00 2001 From: Vitalii Bursov Date: Sun, 18 Feb 2024 19:54:29 +0200 Subject: [PATCH 04/25] Convert LangID from u16 enum to tuple struct containing u16 Relax lang_id checks provided by enum so that any lang_id could be used, not only values listed in the enum. These checks increased the code size considerably without much benefit. Resolves #139. Language identifiers like LangID::EN_US have a new type, but this should not require source code changes in a code which uses them. Provide two traits to convert LangID to and from u16 freely. This implicitly provides TryFrom trait which previously was derived using TryFromPrimitive. There's no special constructor for LangID for values outside of the provided constants, but it can be converted from any u16. As TryFromPrimitive in no longer used, remove num_enum dependency. --- Cargo.toml | 1 - src/descriptor/lang_id.rs | 934 +++++++++++++++++++------------------- src/device.rs | 15 +- 3 files changed, 468 insertions(+), 482 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 36bbeb4..36aebc9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,6 @@ repository = "https://github.com/rust-embedded-community/usb-device" [dependencies] defmt = { version = "0.3", optional = true } portable-atomic = { version = "1.2.0", default-features = false } -num_enum = { version = "0.7.1", default-features = false } heapless = "0.8" [dev-dependencies] diff --git a/src/descriptor/lang_id.rs b/src/descriptor/lang_id.rs index 588c99b..1e90a9f 100644 --- a/src/descriptor/lang_id.rs +++ b/src/descriptor/lang_id.rs @@ -1,478 +1,478 @@ #![allow(non_upper_case_globals, non_camel_case_types)] -use num_enum::TryFromPrimitive; +#[allow(missing_docs)] +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub struct LangID(u16); -impl From<&LangID> for u16 { - fn from(lang_id: &LangID) -> Self { - *lang_id as u16 +impl From for u16 { + fn from(lang_id: LangID) -> Self { + let LangID(id) = lang_id; + id } } -impl From for u16 { - fn from(lang_id: LangID) -> Self { - lang_id as u16 +impl From for LangID { + fn from(id: u16) -> Self { + LangID(id) } } #[allow(missing_docs)] -#[derive(Clone, Copy, PartialEq, Debug, TryFromPrimitive)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[repr(u16)] -pub enum LangID { - AR = 0x0001, - BG = 0x0002, - CA = 0x0003, - ZH_HANS = 0x0004, - CS = 0x0005, - DA = 0x0006, - DE = 0x0007, - EL = 0x0008, - EN = 0x0009, - ES = 0x000A, - FI = 0x000B, - FR = 0x000C, - HE = 0x000D, - HU = 0x000E, - IS = 0x000F, - IT = 0x0010, - JA = 0x0011, - KO = 0x0012, - NL = 0x0013, - NO = 0x0014, - PL = 0x0015, - PT = 0x0016, - RM = 0x0017, - RO = 0x0018, - RU = 0x0019, - HR = 0x001A, - SK = 0x001B, - SQ = 0x001C, - SV = 0x001D, - TH = 0x001E, - TR = 0x001F, - UR = 0x0020, - ID = 0x0021, - UK = 0x0022, - BE = 0x0023, - SL = 0x0024, - ET = 0x0025, - LV = 0x0026, - LT = 0x0027, - TG = 0x0028, - FA = 0x0029, - VI = 0x002A, - HY = 0x002B, - AZ = 0x002C, - EU = 0x002D, - HSB = 0x002E, - MK = 0x002F, - ST = 0x0030, - TS = 0x0031, - TN = 0x0032, - VE = 0x0033, - XH = 0x0034, - ZU = 0x0035, - AF = 0x0036, - KA = 0x0037, - FO = 0x0038, - HI = 0x0039, - MT = 0x003A, - SE = 0x003B, - GA = 0x003C, - YI = 0x003D, - MS = 0x003E, - KK = 0x003F, - KY = 0x0040, - SW = 0x0041, - TK = 0x0042, - UZ = 0x0043, - TT = 0x0044, - BN = 0x0045, - PA = 0x0046, - GU = 0x0047, - OR = 0x0048, - TA = 0x0049, - TE = 0x004A, - KN = 0x004B, - ML = 0x004C, - AS = 0x004D, - MR = 0x004E, - SA = 0x004F, - MN = 0x0050, - BO = 0x0051, - CY = 0x0052, - KM = 0x0053, - LO = 0x0054, - MY = 0x0055, - GL = 0x0056, - KOK = 0x0057, - MNI = 0x0058, - SD = 0x0059, - SYR = 0x005A, - SI = 0x005B, - CHR = 0x005C, - IU = 0x005D, - AM = 0x005E, - TZM = 0x005F, - KS = 0x0060, - NE = 0x0061, - FY = 0x0062, - PS = 0x0063, - FIL = 0x0064, - DV = 0x0065, - BIN = 0x0066, - FF = 0x0067, - HA = 0x0068, - IBB = 0x0069, - YO = 0x006A, - QUZ = 0x006B, - NSO = 0x006C, - BA = 0x006D, - LB = 0x006E, - KL = 0x006F, - IG = 0x0070, - KR = 0x0071, - OM = 0x0072, - TI = 0x0073, - GN = 0x0074, - HAW = 0x0075, - LA = 0x0076, - SO = 0x0077, - II = 0x0078, - PAP = 0x0079, - ARN = 0x007A, - MOH = 0x007C, - BR = 0x007E, - UG = 0x0080, - MI = 0x0081, - OC = 0x0082, - CO = 0x0083, - GSW = 0x0084, - SAH = 0x0085, - QUT = 0x0086, - RW = 0x0087, - WO = 0x0088, - PRS = 0x008C, - GD = 0x0091, - KU = 0x0092, - QUC = 0x0093, - AR_SA = 0x0401, - BG_BG = 0x0402, - CA_ES = 0x0403, - ZH_TW = 0x0404, - CS_CZ = 0x0405, - DA_DK = 0x0406, - DE_DE = 0x0407, - EL_GR = 0x0408, - EN_US = 0x0409, - ES_ES_TRADNL = 0x040A, - FI_FI = 0x040B, - FR_FR = 0x040C, - HE_IL = 0x040D, - HU_HU = 0x040E, - IS_IS = 0x040F, - IT_IT = 0x0410, - JA_JP = 0x0411, - KO_KR = 0x0412, - NL_NL = 0x0413, - NB_NO = 0x0414, - PL_PL = 0x0415, - PT_BR = 0x0416, - RM_CH = 0x0417, - RO_RO = 0x0418, - RU_RU = 0x0419, - HR_HR = 0x041A, - SK_SK = 0x041B, - SQ_AL = 0x041C, - SV_SE = 0x041D, - TH_TH = 0x041E, - TR_TR = 0x041F, - UR_PK = 0x0420, - ID_ID = 0x0421, - UK_UA = 0x0422, - BE_BY = 0x0423, - SL_SI = 0x0424, - ET_EE = 0x0425, - LV_LV = 0x0426, - LT_LT = 0x0427, - TG_CYRL_TJ = 0x0428, - FA_IR = 0x0429, - VI_VN = 0x042A, - HY_AM = 0x042B, - AZ_LATN_AZ = 0x042C, - EU_ES = 0x042D, - HSB_DE = 0x042E, - MK_MK = 0x042F, - ST_ZA = 0x0430, - TS_ZA = 0x0431, - TN_ZA = 0x0432, - VE_ZA = 0x0433, - XH_ZA = 0x0434, - ZU_ZA = 0x0435, - AF_ZA = 0x0436, - KA_GE = 0x0437, - FO_FO = 0x0438, - HI_IN = 0x0439, - MT_MT = 0x043A, - SE_NO = 0x043B, - YI_001 = 0x043D, - MS_MY = 0x043E, - KK_KZ = 0x043F, - KY_KG = 0x0440, - SW_KE = 0x0441, - TK_TM = 0x0442, - UZ_LATN_UZ = 0x0443, - TT_RU = 0x0444, - BN_IN = 0x0445, - PA_IN = 0x0446, - GU_IN = 0x0447, - OR_IN = 0x0448, - TA_IN = 0x0449, - TE_IN = 0x044A, - KN_IN = 0x044B, - ML_IN = 0x044C, - AS_IN = 0x044D, - MR_IN = 0x044E, - SA_IN = 0x044F, - MN_MN = 0x0450, - BO_CN = 0x0451, - CY_GB = 0x0452, - KM_KH = 0x0453, - LO_LA = 0x0454, - MY_MM = 0x0455, - GL_ES = 0x0456, - KOK_IN = 0x0457, - MNI_IN = 0x0458, - SD_DEVA_IN = 0x0459, - SYR_SY = 0x045A, - SI_LK = 0x045B, - CHR_CHER_US = 0x045C, - IU_CANS_CA = 0x045D, - AM_ET = 0x045E, - TZM_ARAB_MA = 0x045F, - KS_ARAB = 0x0460, - NE_NP = 0x0461, - FY_NL = 0x0462, - PS_AF = 0x0463, - FIL_PH = 0x0464, - DV_MV = 0x0465, - BIN_NG = 0x0466, - FF_NG__FF_LATN_NG = 0x0467, - HA_LATN_NG = 0x0468, - IBB_NG = 0x0469, - YO_NG = 0x046A, - QUZ_BO = 0x046B, - NSO_ZA = 0x046C, - BA_RU = 0x046D, - LB_LU = 0x046E, - KL_GL = 0x046F, - IG_NG = 0x0470, - KR_LATN_NG = 0x0471, - OM_ET = 0x0472, - TI_ET = 0x0473, - GN_PY = 0x0474, - HAW_US = 0x0475, - LA_VA = 0x0476, - SO_SO = 0x0477, - II_CN = 0x0478, - PAP_029 = 0x0479, - ARN_CL = 0x047A, - MOH_CA = 0x047C, - BR_FR = 0x047E, - UG_CN = 0x0480, - MI_NZ = 0x0481, - OC_FR = 0x0482, - CO_FR = 0x0483, - GSW_FR = 0x0484, - SAH_RU = 0x0485, - QUT_GT = 0x0486, - RW_RW = 0x0487, - WO_SN = 0x0488, - PRS_AF = 0x048C, - PLT_MG = 0x048D, - ZH_YUE_HK = 0x048E, - TDD_TALE_CN = 0x048F, - KHB_TALU_CN = 0x0490, - GD_GB = 0x0491, - KU_ARAB_IQ = 0x0492, - QUC_CO = 0x0493, - QPS_PLOC = 0x0501, - QPS_PLOCA = 0x05FE, - AR_IQ = 0x0801, - CA_ES_VALENCIA = 0x0803, - ZH_CN = 0x0804, - DE_CH = 0x0807, - EN_GB = 0x0809, - ES_MX = 0x080A, - FR_BE = 0x080C, - IT_CH = 0x0810, - JA_PLOC_JP = 0x0811, - NL_BE = 0x0813, - NN_NO = 0x0814, - PT_PT = 0x0816, - RO_MD = 0x0818, - RU_MD = 0x0819, - SR_LATN_CS = 0x081A, - SV_FI = 0x081D, - UR_IN = 0x0820, - AZ_CYRL_AZ = 0x082C, - DSB_DE = 0x082E, - TN_BW = 0x0832, - SE_SE = 0x083B, - GA_IE = 0x083C, - MS_BN = 0x083E, - KK_LATN_KZ = 0x083F, - UZ_CYRL_UZ = 0x0843, - BN_BD = 0x0845, - PA_ARAB_PK = 0x0846, - TA_LK = 0x0849, - MN_MONG_CN = 0x0850, - BO_BT = 0x0851, - SD_ARAB_PK = 0x0859, - IU_LATN_CA = 0x085D, - TZM_LATN_DZ = 0x085F, - KS_DEVA_IN = 0x0860, - NE_IN = 0x0861, - FF_LATN_SN = 0x0867, - QUZ_EC = 0x086B, - TI_ER = 0x0873, - QPS_PLOCM = 0x09FF, - LOCALE_CUSTOM_USER_DEFAULT = 0x0C00, - AR_EG = 0x0C01, - ZH_HK = 0x0C04, - DE_AT = 0x0C07, - EN_AU = 0x0C09, - ES_ES = 0x0C0A, - FR_CA = 0x0C0C, - SR_CYRL_CS = 0x0C1A, - SE_FI = 0x0C3B, - MN_MONG_MN = 0x0C50, - DZ_BT = 0x0C51, - TMZ_MA = 0x0C5F, - QUZ_PE = 0x0C6B, - LOCALE_CUSTOM_UNSPECIFIED = 0x1000, - AR_LY = 0x1001, - ZH_SG = 0x1004, - DE_LU = 0x1007, - EN_CA = 0x1009, - ES_GT = 0x100A, - FR_CH = 0x100C, - HR_BA = 0x101A, - SMJ_NO = 0x103B, - TZM_TFNG_MA = 0x105F, - AR_DZ = 0x1401, - ZH_MO = 0x1404, - DE_LI = 0x1407, - EN_NZ = 0x1409, - ES_CR = 0x140A, - FR_LU = 0x140C, - BS_LATN_BA = 0x141A, - SMJ_SE = 0x143B, - AR_MA = 0x1801, - EN_IE = 0x1809, - ES_PA = 0x180A, - FR_MC = 0x180C, - SR_LATN_BA = 0x181A, - SMA_NO = 0x183B, - AR_TN = 0x1C01, - EN_ZA = 0x1C09, - ES_DO = 0x1C0A, - FR_029 = 0x1C0C, - SR_CYRL_BA = 0x1C1A, - SMA_SE = 0x1C3B, - AR_OM = 0x2001, - EN_JM = 0x2009, - ES_VE = 0x200A, - FR_RE = 0x200C, - BS_CYRL_BA = 0x201A, - SMS_FI = 0x203B, - AR_YE = 0x2401, - EN_029 = 0x2409, - ES_CO = 0x240A, - FR_CD = 0x240C, - SR_LATN_RS = 0x241A, - SMN_FI = 0x243B, - AR_SY = 0x2801, - EN_BZ = 0x2809, - ES_PE = 0x280A, - FR_SN = 0x280C, - SR_CYRL_RS = 0x281A, - AR_JO = 0x2C01, - EN_TT = 0x2C09, - ES_AR = 0x2C0A, - FR_CM = 0x2C0C, - SR_LATN_ME = 0x2C1A, - AR_LB = 0x3001, - EN_ZW = 0x3009, - ES_EC = 0x300A, - FR_CI = 0x300C, - SR_CYRL_ME = 0x301A, - AR_KW = 0x3401, - EN_PH = 0x3409, - ES_CL = 0x340A, - FR_ML = 0x340C, - AR_AE = 0x3801, - EN_ID = 0x3809, - ES_UY = 0x380A, - FR_MA = 0x380C, - AR_BH = 0x3C01, - EN_HK = 0x3C09, - ES_PY = 0x3C0A, - FR_HT = 0x3C0C, - AR_QA = 0x4001, - EN_IN = 0x4009, - ES_BO = 0x400A, - AR_PLOC_SA = 0x4401, - EN_MY = 0x4409, - ES_SV = 0x440A, - AR_145 = 0x4801, - EN_SG = 0x4809, - ES_HN = 0x480A, - EN_AE = 0x4C09, - ES_NI = 0x4C0A, - EN_BH = 0x5009, - ES_PR = 0x500A, - EN_EG = 0x5409, - ES_US = 0x540A, - EN_JO = 0x5809, - ES_419 = 0x580A, - EN_KW = 0x5C09, - ES_CU = 0x5C0A, - EN_TR = 0x6009, - EN_YE = 0x6409, - BS_CYRL = 0x641A, - BS_LATN = 0x681A, - SR_CYRL = 0x6C1A, - SR_LATN = 0x701A, - SMN = 0x703B, - AZ_CYRL = 0x742C, - SMS = 0x743B, - ZH = 0x7804, - NN = 0x7814, - BS = 0x781A, - AZ_LATN = 0x782C, - SMA = 0x783B, - KK_CYRL = 0x783F, - UZ_CYRL = 0x7843, - MN_CYRL = 0x7850, - IU_CANS = 0x785D, - TZM_TFNG = 0x785F, - ZH_HANT = 0x7C04, - NB = 0x7C14, - SR = 0x7C1A, - TG_CYRL = 0x7C28, - DSB = 0x7C2E, - SMJ = 0x7C3B, - KK_LATN = 0x7C3F, - UZ_LATN = 0x7C43, - PA_ARAB = 0x7C46, - MN_MONG = 0x7C50, - SD_ARAB = 0x7C59, - CHR_CHER = 0x7C5C, - IU_LATN = 0x7C5D, - TZM_LATN = 0x7C5F, - FF_LATN = 0x7C67, - HA_LATN = 0x7C68, - KU_ARAB = 0x7C92, - FR_015 = 0xE40C, +impl LangID { + pub const AR: LangID = LangID(0x0001); + pub const BG: LangID = LangID(0x0002); + pub const CA: LangID = LangID(0x0003); + pub const ZH_HANS: LangID = LangID(0x0004); + pub const CS: LangID = LangID(0x0005); + pub const DA: LangID = LangID(0x0006); + pub const DE: LangID = LangID(0x0007); + pub const EL: LangID = LangID(0x0008); + pub const EN: LangID = LangID(0x0009); + pub const ES: LangID = LangID(0x000A); + pub const FI: LangID = LangID(0x000B); + pub const FR: LangID = LangID(0x000C); + pub const HE: LangID = LangID(0x000D); + pub const HU: LangID = LangID(0x000E); + pub const IS: LangID = LangID(0x000F); + pub const IT: LangID = LangID(0x0010); + pub const JA: LangID = LangID(0x0011); + pub const KO: LangID = LangID(0x0012); + pub const NL: LangID = LangID(0x0013); + pub const NO: LangID = LangID(0x0014); + pub const PL: LangID = LangID(0x0015); + pub const PT: LangID = LangID(0x0016); + pub const RM: LangID = LangID(0x0017); + pub const RO: LangID = LangID(0x0018); + pub const RU: LangID = LangID(0x0019); + pub const HR: LangID = LangID(0x001A); + pub const SK: LangID = LangID(0x001B); + pub const SQ: LangID = LangID(0x001C); + pub const SV: LangID = LangID(0x001D); + pub const TH: LangID = LangID(0x001E); + pub const TR: LangID = LangID(0x001F); + pub const UR: LangID = LangID(0x0020); + pub const ID: LangID = LangID(0x0021); + pub const UK: LangID = LangID(0x0022); + pub const BE: LangID = LangID(0x0023); + pub const SL: LangID = LangID(0x0024); + pub const ET: LangID = LangID(0x0025); + pub const LV: LangID = LangID(0x0026); + pub const LT: LangID = LangID(0x0027); + pub const TG: LangID = LangID(0x0028); + pub const FA: LangID = LangID(0x0029); + pub const VI: LangID = LangID(0x002A); + pub const HY: LangID = LangID(0x002B); + pub const AZ: LangID = LangID(0x002C); + pub const EU: LangID = LangID(0x002D); + pub const HSB: LangID = LangID(0x002E); + pub const MK: LangID = LangID(0x002F); + pub const ST: LangID = LangID(0x0030); + pub const TS: LangID = LangID(0x0031); + pub const TN: LangID = LangID(0x0032); + pub const VE: LangID = LangID(0x0033); + pub const XH: LangID = LangID(0x0034); + pub const ZU: LangID = LangID(0x0035); + pub const AF: LangID = LangID(0x0036); + pub const KA: LangID = LangID(0x0037); + pub const FO: LangID = LangID(0x0038); + pub const HI: LangID = LangID(0x0039); + pub const MT: LangID = LangID(0x003A); + pub const SE: LangID = LangID(0x003B); + pub const GA: LangID = LangID(0x003C); + pub const YI: LangID = LangID(0x003D); + pub const MS: LangID = LangID(0x003E); + pub const KK: LangID = LangID(0x003F); + pub const KY: LangID = LangID(0x0040); + pub const SW: LangID = LangID(0x0041); + pub const TK: LangID = LangID(0x0042); + pub const UZ: LangID = LangID(0x0043); + pub const TT: LangID = LangID(0x0044); + pub const BN: LangID = LangID(0x0045); + pub const PA: LangID = LangID(0x0046); + pub const GU: LangID = LangID(0x0047); + pub const OR: LangID = LangID(0x0048); + pub const TA: LangID = LangID(0x0049); + pub const TE: LangID = LangID(0x004A); + pub const KN: LangID = LangID(0x004B); + pub const ML: LangID = LangID(0x004C); + pub const AS: LangID = LangID(0x004D); + pub const MR: LangID = LangID(0x004E); + pub const SA: LangID = LangID(0x004F); + pub const MN: LangID = LangID(0x0050); + pub const BO: LangID = LangID(0x0051); + pub const CY: LangID = LangID(0x0052); + pub const KM: LangID = LangID(0x0053); + pub const LO: LangID = LangID(0x0054); + pub const MY: LangID = LangID(0x0055); + pub const GL: LangID = LangID(0x0056); + pub const KOK: LangID = LangID(0x0057); + pub const MNI: LangID = LangID(0x0058); + pub const SD: LangID = LangID(0x0059); + pub const SYR: LangID = LangID(0x005A); + pub const SI: LangID = LangID(0x005B); + pub const CHR: LangID = LangID(0x005C); + pub const IU: LangID = LangID(0x005D); + pub const AM: LangID = LangID(0x005E); + pub const TZM: LangID = LangID(0x005F); + pub const KS: LangID = LangID(0x0060); + pub const NE: LangID = LangID(0x0061); + pub const FY: LangID = LangID(0x0062); + pub const PS: LangID = LangID(0x0063); + pub const FIL: LangID = LangID(0x0064); + pub const DV: LangID = LangID(0x0065); + pub const BIN: LangID = LangID(0x0066); + pub const FF: LangID = LangID(0x0067); + pub const HA: LangID = LangID(0x0068); + pub const IBB: LangID = LangID(0x0069); + pub const YO: LangID = LangID(0x006A); + pub const QUZ: LangID = LangID(0x006B); + pub const NSO: LangID = LangID(0x006C); + pub const BA: LangID = LangID(0x006D); + pub const LB: LangID = LangID(0x006E); + pub const KL: LangID = LangID(0x006F); + pub const IG: LangID = LangID(0x0070); + pub const KR: LangID = LangID(0x0071); + pub const OM: LangID = LangID(0x0072); + pub const TI: LangID = LangID(0x0073); + pub const GN: LangID = LangID(0x0074); + pub const HAW: LangID = LangID(0x0075); + pub const LA: LangID = LangID(0x0076); + pub const SO: LangID = LangID(0x0077); + pub const II: LangID = LangID(0x0078); + pub const PAP: LangID = LangID(0x0079); + pub const ARN: LangID = LangID(0x007A); + pub const MOH: LangID = LangID(0x007C); + pub const BR: LangID = LangID(0x007E); + pub const UG: LangID = LangID(0x0080); + pub const MI: LangID = LangID(0x0081); + pub const OC: LangID = LangID(0x0082); + pub const CO: LangID = LangID(0x0083); + pub const GSW: LangID = LangID(0x0084); + pub const SAH: LangID = LangID(0x0085); + pub const QUT: LangID = LangID(0x0086); + pub const RW: LangID = LangID(0x0087); + pub const WO: LangID = LangID(0x0088); + pub const PRS: LangID = LangID(0x008C); + pub const GD: LangID = LangID(0x0091); + pub const KU: LangID = LangID(0x0092); + pub const QUC: LangID = LangID(0x0093); + pub const AR_SA: LangID = LangID(0x0401); + pub const BG_BG: LangID = LangID(0x0402); + pub const CA_ES: LangID = LangID(0x0403); + pub const ZH_TW: LangID = LangID(0x0404); + pub const CS_CZ: LangID = LangID(0x0405); + pub const DA_DK: LangID = LangID(0x0406); + pub const DE_DE: LangID = LangID(0x0407); + pub const EL_GR: LangID = LangID(0x0408); + pub const EN_US: LangID = LangID(0x0409); + pub const ES_ES_TRADNL: LangID = LangID(0x040A); + pub const FI_FI: LangID = LangID(0x040B); + pub const FR_FR: LangID = LangID(0x040C); + pub const HE_IL: LangID = LangID(0x040D); + pub const HU_HU: LangID = LangID(0x040E); + pub const IS_IS: LangID = LangID(0x040F); + pub const IT_IT: LangID = LangID(0x0410); + pub const JA_JP: LangID = LangID(0x0411); + pub const KO_KR: LangID = LangID(0x0412); + pub const NL_NL: LangID = LangID(0x0413); + pub const NB_NO: LangID = LangID(0x0414); + pub const PL_PL: LangID = LangID(0x0415); + pub const PT_BR: LangID = LangID(0x0416); + pub const RM_CH: LangID = LangID(0x0417); + pub const RO_RO: LangID = LangID(0x0418); + pub const RU_RU: LangID = LangID(0x0419); + pub const HR_HR: LangID = LangID(0x041A); + pub const SK_SK: LangID = LangID(0x041B); + pub const SQ_AL: LangID = LangID(0x041C); + pub const SV_SE: LangID = LangID(0x041D); + pub const TH_TH: LangID = LangID(0x041E); + pub const TR_TR: LangID = LangID(0x041F); + pub const UR_PK: LangID = LangID(0x0420); + pub const ID_ID: LangID = LangID(0x0421); + pub const UK_UA: LangID = LangID(0x0422); + pub const BE_BY: LangID = LangID(0x0423); + pub const SL_SI: LangID = LangID(0x0424); + pub const ET_EE: LangID = LangID(0x0425); + pub const LV_LV: LangID = LangID(0x0426); + pub const LT_LT: LangID = LangID(0x0427); + pub const TG_CYRL_TJ: LangID = LangID(0x0428); + pub const FA_IR: LangID = LangID(0x0429); + pub const VI_VN: LangID = LangID(0x042A); + pub const HY_AM: LangID = LangID(0x042B); + pub const AZ_LATN_AZ: LangID = LangID(0x042C); + pub const EU_ES: LangID = LangID(0x042D); + pub const HSB_DE: LangID = LangID(0x042E); + pub const MK_MK: LangID = LangID(0x042F); + pub const ST_ZA: LangID = LangID(0x0430); + pub const TS_ZA: LangID = LangID(0x0431); + pub const TN_ZA: LangID = LangID(0x0432); + pub const VE_ZA: LangID = LangID(0x0433); + pub const XH_ZA: LangID = LangID(0x0434); + pub const ZU_ZA: LangID = LangID(0x0435); + pub const AF_ZA: LangID = LangID(0x0436); + pub const KA_GE: LangID = LangID(0x0437); + pub const FO_FO: LangID = LangID(0x0438); + pub const HI_IN: LangID = LangID(0x0439); + pub const MT_MT: LangID = LangID(0x043A); + pub const SE_NO: LangID = LangID(0x043B); + pub const YI_001: LangID = LangID(0x043D); + pub const MS_MY: LangID = LangID(0x043E); + pub const KK_KZ: LangID = LangID(0x043F); + pub const KY_KG: LangID = LangID(0x0440); + pub const SW_KE: LangID = LangID(0x0441); + pub const TK_TM: LangID = LangID(0x0442); + pub const UZ_LATN_UZ: LangID = LangID(0x0443); + pub const TT_RU: LangID = LangID(0x0444); + pub const BN_IN: LangID = LangID(0x0445); + pub const PA_IN: LangID = LangID(0x0446); + pub const GU_IN: LangID = LangID(0x0447); + pub const OR_IN: LangID = LangID(0x0448); + pub const TA_IN: LangID = LangID(0x0449); + pub const TE_IN: LangID = LangID(0x044A); + pub const KN_IN: LangID = LangID(0x044B); + pub const ML_IN: LangID = LangID(0x044C); + pub const AS_IN: LangID = LangID(0x044D); + pub const MR_IN: LangID = LangID(0x044E); + pub const SA_IN: LangID = LangID(0x044F); + pub const MN_MN: LangID = LangID(0x0450); + pub const BO_CN: LangID = LangID(0x0451); + pub const CY_GB: LangID = LangID(0x0452); + pub const KM_KH: LangID = LangID(0x0453); + pub const LO_LA: LangID = LangID(0x0454); + pub const MY_MM: LangID = LangID(0x0455); + pub const GL_ES: LangID = LangID(0x0456); + pub const KOK_IN: LangID = LangID(0x0457); + pub const MNI_IN: LangID = LangID(0x0458); + pub const SD_DEVA_IN: LangID = LangID(0x0459); + pub const SYR_SY: LangID = LangID(0x045A); + pub const SI_LK: LangID = LangID(0x045B); + pub const CHR_CHER_US: LangID = LangID(0x045C); + pub const IU_CANS_CA: LangID = LangID(0x045D); + pub const AM_ET: LangID = LangID(0x045E); + pub const TZM_ARAB_MA: LangID = LangID(0x045F); + pub const KS_ARAB: LangID = LangID(0x0460); + pub const NE_NP: LangID = LangID(0x0461); + pub const FY_NL: LangID = LangID(0x0462); + pub const PS_AF: LangID = LangID(0x0463); + pub const FIL_PH: LangID = LangID(0x0464); + pub const DV_MV: LangID = LangID(0x0465); + pub const BIN_NG: LangID = LangID(0x0466); + pub const FF_NG__FF_LATN_NG: LangID = LangID(0x0467); + pub const HA_LATN_NG: LangID = LangID(0x0468); + pub const IBB_NG: LangID = LangID(0x0469); + pub const YO_NG: LangID = LangID(0x046A); + pub const QUZ_BO: LangID = LangID(0x046B); + pub const NSO_ZA: LangID = LangID(0x046C); + pub const BA_RU: LangID = LangID(0x046D); + pub const LB_LU: LangID = LangID(0x046E); + pub const KL_GL: LangID = LangID(0x046F); + pub const IG_NG: LangID = LangID(0x0470); + pub const KR_LATN_NG: LangID = LangID(0x0471); + pub const OM_ET: LangID = LangID(0x0472); + pub const TI_ET: LangID = LangID(0x0473); + pub const GN_PY: LangID = LangID(0x0474); + pub const HAW_US: LangID = LangID(0x0475); + pub const LA_VA: LangID = LangID(0x0476); + pub const SO_SO: LangID = LangID(0x0477); + pub const II_CN: LangID = LangID(0x0478); + pub const PAP_029: LangID = LangID(0x0479); + pub const ARN_CL: LangID = LangID(0x047A); + pub const MOH_CA: LangID = LangID(0x047C); + pub const BR_FR: LangID = LangID(0x047E); + pub const UG_CN: LangID = LangID(0x0480); + pub const MI_NZ: LangID = LangID(0x0481); + pub const OC_FR: LangID = LangID(0x0482); + pub const CO_FR: LangID = LangID(0x0483); + pub const GSW_FR: LangID = LangID(0x0484); + pub const SAH_RU: LangID = LangID(0x0485); + pub const QUT_GT: LangID = LangID(0x0486); + pub const RW_RW: LangID = LangID(0x0487); + pub const WO_SN: LangID = LangID(0x0488); + pub const PRS_AF: LangID = LangID(0x048C); + pub const PLT_MG: LangID = LangID(0x048D); + pub const ZH_YUE_HK: LangID = LangID(0x048E); + pub const TDD_TALE_CN: LangID = LangID(0x048F); + pub const KHB_TALU_CN: LangID = LangID(0x0490); + pub const GD_GB: LangID = LangID(0x0491); + pub const KU_ARAB_IQ: LangID = LangID(0x0492); + pub const QUC_CO: LangID = LangID(0x0493); + pub const QPS_PLOC: LangID = LangID(0x0501); + pub const QPS_PLOCA: LangID = LangID(0x05FE); + pub const AR_IQ: LangID = LangID(0x0801); + pub const CA_ES_VALENCIA: LangID = LangID(0x0803); + pub const ZH_CN: LangID = LangID(0x0804); + pub const DE_CH: LangID = LangID(0x0807); + pub const EN_GB: LangID = LangID(0x0809); + pub const ES_MX: LangID = LangID(0x080A); + pub const FR_BE: LangID = LangID(0x080C); + pub const IT_CH: LangID = LangID(0x0810); + pub const JA_PLOC_JP: LangID = LangID(0x0811); + pub const NL_BE: LangID = LangID(0x0813); + pub const NN_NO: LangID = LangID(0x0814); + pub const PT_PT: LangID = LangID(0x0816); + pub const RO_MD: LangID = LangID(0x0818); + pub const RU_MD: LangID = LangID(0x0819); + pub const SR_LATN_CS: LangID = LangID(0x081A); + pub const SV_FI: LangID = LangID(0x081D); + pub const UR_IN: LangID = LangID(0x0820); + pub const AZ_CYRL_AZ: LangID = LangID(0x082C); + pub const DSB_DE: LangID = LangID(0x082E); + pub const TN_BW: LangID = LangID(0x0832); + pub const SE_SE: LangID = LangID(0x083B); + pub const GA_IE: LangID = LangID(0x083C); + pub const MS_BN: LangID = LangID(0x083E); + pub const KK_LATN_KZ: LangID = LangID(0x083F); + pub const UZ_CYRL_UZ: LangID = LangID(0x0843); + pub const BN_BD: LangID = LangID(0x0845); + pub const PA_ARAB_PK: LangID = LangID(0x0846); + pub const TA_LK: LangID = LangID(0x0849); + pub const MN_MONG_CN: LangID = LangID(0x0850); + pub const BO_BT: LangID = LangID(0x0851); + pub const SD_ARAB_PK: LangID = LangID(0x0859); + pub const IU_LATN_CA: LangID = LangID(0x085D); + pub const TZM_LATN_DZ: LangID = LangID(0x085F); + pub const KS_DEVA_IN: LangID = LangID(0x0860); + pub const NE_IN: LangID = LangID(0x0861); + pub const FF_LATN_SN: LangID = LangID(0x0867); + pub const QUZ_EC: LangID = LangID(0x086B); + pub const TI_ER: LangID = LangID(0x0873); + pub const QPS_PLOCM: LangID = LangID(0x09FF); + pub const LOCALE_CUSTOM_USER_DEFAULT: LangID = LangID(0x0C00); + pub const AR_EG: LangID = LangID(0x0C01); + pub const ZH_HK: LangID = LangID(0x0C04); + pub const DE_AT: LangID = LangID(0x0C07); + pub const EN_AU: LangID = LangID(0x0C09); + pub const ES_ES: LangID = LangID(0x0C0A); + pub const FR_CA: LangID = LangID(0x0C0C); + pub const SR_CYRL_CS: LangID = LangID(0x0C1A); + pub const SE_FI: LangID = LangID(0x0C3B); + pub const MN_MONG_MN: LangID = LangID(0x0C50); + pub const DZ_BT: LangID = LangID(0x0C51); + pub const TMZ_MA: LangID = LangID(0x0C5F); + pub const QUZ_PE: LangID = LangID(0x0C6B); + pub const LOCALE_CUSTOM_UNSPECIFIED: LangID = LangID(0x1000); + pub const AR_LY: LangID = LangID(0x1001); + pub const ZH_SG: LangID = LangID(0x1004); + pub const DE_LU: LangID = LangID(0x1007); + pub const EN_CA: LangID = LangID(0x1009); + pub const ES_GT: LangID = LangID(0x100A); + pub const FR_CH: LangID = LangID(0x100C); + pub const HR_BA: LangID = LangID(0x101A); + pub const SMJ_NO: LangID = LangID(0x103B); + pub const TZM_TFNG_MA: LangID = LangID(0x105F); + pub const AR_DZ: LangID = LangID(0x1401); + pub const ZH_MO: LangID = LangID(0x1404); + pub const DE_LI: LangID = LangID(0x1407); + pub const EN_NZ: LangID = LangID(0x1409); + pub const ES_CR: LangID = LangID(0x140A); + pub const FR_LU: LangID = LangID(0x140C); + pub const BS_LATN_BA: LangID = LangID(0x141A); + pub const SMJ_SE: LangID = LangID(0x143B); + pub const AR_MA: LangID = LangID(0x1801); + pub const EN_IE: LangID = LangID(0x1809); + pub const ES_PA: LangID = LangID(0x180A); + pub const FR_MC: LangID = LangID(0x180C); + pub const SR_LATN_BA: LangID = LangID(0x181A); + pub const SMA_NO: LangID = LangID(0x183B); + pub const AR_TN: LangID = LangID(0x1C01); + pub const EN_ZA: LangID = LangID(0x1C09); + pub const ES_DO: LangID = LangID(0x1C0A); + pub const FR_029: LangID = LangID(0x1C0C); + pub const SR_CYRL_BA: LangID = LangID(0x1C1A); + pub const SMA_SE: LangID = LangID(0x1C3B); + pub const AR_OM: LangID = LangID(0x2001); + pub const EN_JM: LangID = LangID(0x2009); + pub const ES_VE: LangID = LangID(0x200A); + pub const FR_RE: LangID = LangID(0x200C); + pub const BS_CYRL_BA: LangID = LangID(0x201A); + pub const SMS_FI: LangID = LangID(0x203B); + pub const AR_YE: LangID = LangID(0x2401); + pub const EN_029: LangID = LangID(0x2409); + pub const ES_CO: LangID = LangID(0x240A); + pub const FR_CD: LangID = LangID(0x240C); + pub const SR_LATN_RS: LangID = LangID(0x241A); + pub const SMN_FI: LangID = LangID(0x243B); + pub const AR_SY: LangID = LangID(0x2801); + pub const EN_BZ: LangID = LangID(0x2809); + pub const ES_PE: LangID = LangID(0x280A); + pub const FR_SN: LangID = LangID(0x280C); + pub const SR_CYRL_RS: LangID = LangID(0x281A); + pub const AR_JO: LangID = LangID(0x2C01); + pub const EN_TT: LangID = LangID(0x2C09); + pub const ES_AR: LangID = LangID(0x2C0A); + pub const FR_CM: LangID = LangID(0x2C0C); + pub const SR_LATN_ME: LangID = LangID(0x2C1A); + pub const AR_LB: LangID = LangID(0x3001); + pub const EN_ZW: LangID = LangID(0x3009); + pub const ES_EC: LangID = LangID(0x300A); + pub const FR_CI: LangID = LangID(0x300C); + pub const SR_CYRL_ME: LangID = LangID(0x301A); + pub const AR_KW: LangID = LangID(0x3401); + pub const EN_PH: LangID = LangID(0x3409); + pub const ES_CL: LangID = LangID(0x340A); + pub const FR_ML: LangID = LangID(0x340C); + pub const AR_AE: LangID = LangID(0x3801); + pub const EN_ID: LangID = LangID(0x3809); + pub const ES_UY: LangID = LangID(0x380A); + pub const FR_MA: LangID = LangID(0x380C); + pub const AR_BH: LangID = LangID(0x3C01); + pub const EN_HK: LangID = LangID(0x3C09); + pub const ES_PY: LangID = LangID(0x3C0A); + pub const FR_HT: LangID = LangID(0x3C0C); + pub const AR_QA: LangID = LangID(0x4001); + pub const EN_IN: LangID = LangID(0x4009); + pub const ES_BO: LangID = LangID(0x400A); + pub const AR_PLOC_SA: LangID = LangID(0x4401); + pub const EN_MY: LangID = LangID(0x4409); + pub const ES_SV: LangID = LangID(0x440A); + pub const AR_145: LangID = LangID(0x4801); + pub const EN_SG: LangID = LangID(0x4809); + pub const ES_HN: LangID = LangID(0x480A); + pub const EN_AE: LangID = LangID(0x4C09); + pub const ES_NI: LangID = LangID(0x4C0A); + pub const EN_BH: LangID = LangID(0x5009); + pub const ES_PR: LangID = LangID(0x500A); + pub const EN_EG: LangID = LangID(0x5409); + pub const ES_US: LangID = LangID(0x540A); + pub const EN_JO: LangID = LangID(0x5809); + pub const ES_419: LangID = LangID(0x580A); + pub const EN_KW: LangID = LangID(0x5C09); + pub const ES_CU: LangID = LangID(0x5C0A); + pub const EN_TR: LangID = LangID(0x6009); + pub const EN_YE: LangID = LangID(0x6409); + pub const BS_CYRL: LangID = LangID(0x641A); + pub const BS_LATN: LangID = LangID(0x681A); + pub const SR_CYRL: LangID = LangID(0x6C1A); + pub const SR_LATN: LangID = LangID(0x701A); + pub const SMN: LangID = LangID(0x703B); + pub const AZ_CYRL: LangID = LangID(0x742C); + pub const SMS: LangID = LangID(0x743B); + pub const ZH: LangID = LangID(0x7804); + pub const NN: LangID = LangID(0x7814); + pub const BS: LangID = LangID(0x781A); + pub const AZ_LATN: LangID = LangID(0x782C); + pub const SMA: LangID = LangID(0x783B); + pub const KK_CYRL: LangID = LangID(0x783F); + pub const UZ_CYRL: LangID = LangID(0x7843); + pub const MN_CYRL: LangID = LangID(0x7850); + pub const IU_CANS: LangID = LangID(0x785D); + pub const TZM_TFNG: LangID = LangID(0x785F); + pub const ZH_HANT: LangID = LangID(0x7C04); + pub const NB: LangID = LangID(0x7C14); + pub const SR: LangID = LangID(0x7C1A); + pub const TG_CYRL: LangID = LangID(0x7C28); + pub const DSB: LangID = LangID(0x7C2E); + pub const SMJ: LangID = LangID(0x7C3B); + pub const KK_LATN: LangID = LangID(0x7C3F); + pub const UZ_LATN: LangID = LangID(0x7C43); + pub const PA_ARAB: LangID = LangID(0x7C46); + pub const MN_MONG: LangID = LangID(0x7C50); + pub const SD_ARAB: LangID = LangID(0x7C59); + pub const CHR_CHER: LangID = LangID(0x7C5C); + pub const IU_LATN: LangID = LangID(0x7C5D); + pub const TZM_LATN: LangID = LangID(0x7C5F); + pub const FF_LATN: LangID = LangID(0x7C67); + pub const HA_LATN: LangID = LangID(0x7C68); + pub const KU_ARAB: LangID = LangID(0x7C92); + pub const FR_015: LangID = LangID(0xE40C); } diff --git a/src/device.rs b/src/device.rs index e1ca323..ddc20f6 100644 --- a/src/device.rs +++ b/src/device.rs @@ -6,7 +6,6 @@ use crate::descriptor::{descriptor_type, lang_id::LangID, BosWriter, DescriptorW pub use crate::device_builder::{StringDescriptors, UsbDeviceBuilder, UsbVidPid}; use crate::endpoint::{EndpointAddress, EndpointType}; use crate::{Result, UsbDirection}; -use core::convert::TryFrom; /// The global state of the USB device. /// @@ -563,19 +562,7 @@ impl UsbDevice<'_, B> { // rest STRING Requests _ => { - let lang_id = match LangID::try_from(req.index) { - Err(_err) => { - #[cfg(feature = "defmt")] - defmt::warn!( - "Receive unknown LANGID {:#06X}, reject the request", - _err.number - ); - xfer.reject().ok(); - return; - } - - Ok(req_lang_id) => req_lang_id, - }; + let lang_id = LangID::from(req.index); let string = match index { // Manufacturer, product, and serial are handled directly here. 1..=3 => { From 55aecddb2ea0f16298dd1b01a73ceef102f19c55 Mon Sep 17 00:00:00 2001 From: Jose Acevedo Date: Sun, 25 Feb 2024 09:38:26 -0500 Subject: [PATCH 05/25] fix: make invalid LangID default to EN_US --- src/class.rs | 5 +++-- src/device.rs | 28 ++++++++++++---------------- src/test_class.rs | 4 ++-- 3 files changed, 17 insertions(+), 20 deletions(-) diff --git a/src/class.rs b/src/class.rs index 3eae3c4..4d70c8e 100644 --- a/src/class.rs +++ b/src/class.rs @@ -43,8 +43,9 @@ pub trait UsbClass { /// /// * `index` - A string index allocated earlier with /// [`UsbAllocator`](crate::bus::UsbBusAllocator). - /// * `lang_id` - The language ID for the string to retrieve. - fn get_string(&self, index: StringIndex, lang_id: Option) -> Option<&str> { + /// * `lang_id` - The language ID for the string to retrieve. If the requested lang_id is not + /// valid it will default to EN_US. + fn get_string(&self, index: StringIndex, lang_id: LangID) -> Option<&str> { let _ = (index, lang_id); None } diff --git a/src/device.rs b/src/device.rs index 2c7297d..61aed60 100644 --- a/src/device.rs +++ b/src/device.rs @@ -563,25 +563,21 @@ impl UsbDevice<'_, B> { // rest STRING Requests _ => { - let lang_id = LangID::try_from(req.index); + let lang_id = match LangID::try_from(req.index) { + Err(_err) => { + #[cfg(feature = "defmt")] + defmt::warn!( + "Receive unknown LANGID {:#06X}, default to EN_US", + _err.number + ); + LangID::EN_US + } + Ok(req_lang_id) => req_lang_id, + }; let string = match index { // Manufacturer, product, and serial are handled directly here. 1..=3 => { - let lang_id = match lang_id { - Err(_err) => { - #[cfg(feature = "defmt")] - defmt::warn!( - "Receive unknown LANGID {:#06X}, reject the request", - _err.number - ); - xfer.reject().ok(); - return; - } - - Ok(req_lang_id) => req_lang_id, - }; - let Some(lang) = config .string_descriptors .iter() @@ -602,7 +598,7 @@ impl UsbDevice<'_, B> { let index = StringIndex::new(index); classes .iter() - .find_map(|cls| cls.get_string(index, lang_id.ok())) + .find_map(|cls| cls.get_string(index, lang_id)) } }; diff --git a/src/test_class.rs b/src/test_class.rs index c2fb13d..ec26f77 100644 --- a/src/test_class.rs +++ b/src/test_class.rs @@ -232,8 +232,8 @@ impl UsbClass for TestClass<'_, B> { Ok(()) } - fn get_string(&self, index: StringIndex, lang_id: Option) -> Option<&str> { - if lang_id == Some(LangID::EN_US) { + fn get_string(&self, index: StringIndex, lang_id: LangID) -> Option<&str> { + if lang_id == LangID::EN_US { if index == self.custom_string { return Some(CUSTOM_STRING); } else if index == self.interface_string { From 232decb635770d62ee32de94d5f2d2299840f3a7 Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Mon, 26 Feb 2024 11:20:27 +0100 Subject: [PATCH 06/25] Updating CHANGELOG --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a47e97..a058fc6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [Unreleased] +### Changed +* Invalid LangIDs will default to `EN_US` + ## [0.3.1] - 2023-11-15 ### Added From d628911b9a13fe0b9b3f3da63f44bd8be5508553 Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Mon, 26 Feb 2024 12:08:57 +0100 Subject: [PATCH 07/25] Adding USB trace support --- Cargo.toml | 4 ++++ src/control_pipe.rs | 23 ++++++++++++++++++++++- src/device.rs | 31 +++++++++++++++++++++++++++++++ src/lib.rs | 3 +++ 4 files changed, 60 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 36bbeb4..80b3733 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ defmt = { version = "0.3", optional = true } portable-atomic = { version = "1.2.0", default-features = false } num_enum = { version = "0.7.1", default-features = false } heapless = "0.8" +log = { version = "0.4", default-features = false, optional = true} [dev-dependencies] rusb = "0.9.1" @@ -23,6 +24,9 @@ rand = "0.8.5" # Use a 256 byte buffer for control transfers instead of 128. control-buffer-256 = [] +# Enable logging and tracing via the `log` crate +log = ["dep:log"] + # Use larger endpoint buffers for highspeed operation (default fullspeed) # # Note: usb-device doesn't truly support high speed enumeration yet, so setting this will make diff --git a/src/control_pipe.rs b/src/control_pipe.rs index f6e3958..1f142f3 100644 --- a/src/control_pipe.rs +++ b/src/control_pipe.rs @@ -63,6 +63,7 @@ impl ControlPipe<'_, B> { } pub fn reset(&mut self) { + usb_trace!("Control pipe reset"); self.state = ControlState::Idle; } @@ -87,6 +88,7 @@ impl ControlPipe<'_, B> { // Now that we have properly parsed the setup packet, ensure the end-point is no longer in // a stalled state. + usb_trace!("EP0 request received: {req:?}"); self.ep_out.unstall(); /*sprintln!("SETUP {:?} {:?} {:?} req:{} val:{} idx:{} len:{} {:?}", @@ -142,8 +144,10 @@ impl ControlPipe<'_, B> { }; self.i += count; + usb_trace!("Read {count} bytes on EP0-OUT"); if self.i >= self.len { + usb_debug!("Request OUT complete: {req}"); self.state = ControlState::CompleteOut; return Some(req); } @@ -154,11 +158,19 @@ impl ControlPipe<'_, B> { | ControlState::DataInLast | ControlState::DataInZlp | ControlState::StatusOut => { + usb_debug!( + "Terminating DATA stage early. Current state: {:?}", + self.state + ); let _ = self.ep_out.read(&mut []); self.state = ControlState::Idle; } _ => { // Discard the packet + usb_debug!( + "Discarding EP0 data due to unexpected state. Current state: {:?}", + self.state + ); let _ = self.ep_out.read(&mut []); // Unexpected OUT packet @@ -181,6 +193,7 @@ impl ControlPipe<'_, B> { return false; } + usb_trace!("wrote EP0-IN: ZLP"); self.state = ControlState::DataInLast; } ControlState::DataInLast => { @@ -192,12 +205,14 @@ impl ControlPipe<'_, B> { return true; } ControlState::Idle => { + usb_debug!("Ignoring EP0-IN while in IDLE"); // If we received a message on EP0 while sending the last portion of an IN // transfer, we may have already transitioned to IDLE without getting the last // IN-complete status. Just ignore this indication. } _ => { // Unexpected IN packet + usb_debug!("Unexpected EP0-IN. Current state: {:?}", self.state); self.set_error(); } }; @@ -213,9 +228,14 @@ impl ControlPipe<'_, B> { Ok(c) => c, // There isn't much we can do if the write fails, except to wait for another poll or for // the host to resend the request. - Err(_) => return, + Err(_err) => { + usb_debug!("Failed to write EP0-IN: {_err:?}"); + return; + } }; + usb_trace!("wrote EP0-IN: {:?}", &buffer[self.i..(self.i + count)]); + self.i += count; if self.i >= self.len { @@ -286,6 +306,7 @@ impl ControlPipe<'_, B> { } fn set_error(&mut self) { + usb_debug!("EP0 stalled - error"); self.state = ControlState::Error; self.ep_out.stall(); self.ep_in.stall(); diff --git a/src/device.rs b/src/device.rs index 61aed60..219b098 100644 --- a/src/device.rs +++ b/src/device.rs @@ -204,6 +204,12 @@ impl UsbDevice<'_, B> { // Pending events for endpoint 0? if (eps & 1) != 0 { + usb_debug!( + "EP0: setup={}, in={}, out={}", + ep_setup & 1, + ep_in_complete & 1, + ep_out & 1 + ); // Handle EP0-IN conditions first. When both EP0-IN and EP0-OUT have completed, // it is possible that EP0-OUT is a zero-sized out packet to complete the STATUS // phase of the control transfer. We have to process EP0-IN first to update our @@ -230,6 +236,10 @@ impl UsbDevice<'_, B> { None }; + if let Some(_req) = req { + usb_trace!("Handling EP0 request: {_req}"); + } + match req { Some(req) if req.direction == UsbDirection::In => { self.control_in(classes, req) @@ -250,18 +260,21 @@ impl UsbDevice<'_, B> { for i in 1..MAX_ENDPOINTS { if (ep_setup & bit) != 0 { for cls in classes.iter_mut() { + usb_trace!("Handling EP{i}-SETUP"); cls.endpoint_setup(EndpointAddress::from_parts( i, UsbDirection::Out, )); } } else if (ep_out & bit) != 0 { + usb_trace!("Handling EP{i}-OUT"); for cls in classes.iter_mut() { cls.endpoint_out(EndpointAddress::from_parts(i, UsbDirection::Out)); } } if (ep_in_complete & bit) != 0 { + usb_trace!("Handling EP{i}-IN"); for cls in classes.iter_mut() { cls.endpoint_in_complete(EndpointAddress::from_parts( i, @@ -289,6 +302,7 @@ impl UsbDevice<'_, B> { } PollResult::Resume => {} PollResult::Suspend => { + usb_debug!("Suspending bus"); self.bus.suspend(); self.suspended_device_state = Some(self.device_state); self.device_state = UsbDeviceState::Suspend; @@ -314,6 +328,7 @@ impl UsbDevice<'_, B> { match (req.recipient, req.request) { (Recipient::Device, Request::GET_STATUS) => { + usb_trace!("Processing Device::GetStatus"); let status: u16 = if self.self_powered { 0x0001 } else { 0x0000 } | if self.remote_wakeup_enabled { 0x0002 @@ -325,12 +340,14 @@ impl UsbDevice<'_, B> { } (Recipient::Interface, Request::GET_STATUS) => { + usb_trace!("Processing Interface::GetStatus"); let status: u16 = 0x0000; let _ = xfer.accept_with(&status.to_le_bytes()); } (Recipient::Endpoint, Request::GET_STATUS) => { + usb_trace!("Processing EP::GetStatus"); let ep_addr = ((req.index as u8) & 0x8f).into(); let status: u16 = if self.bus.is_stalled(ep_addr) { @@ -343,10 +360,12 @@ impl UsbDevice<'_, B> { } (Recipient::Device, Request::GET_DESCRIPTOR) => { + usb_trace!("Processing Device::GetDescriptor"); UsbDevice::get_descriptor(&self.config, classes, xfer) } (Recipient::Device, Request::GET_CONFIGURATION) => { + usb_trace!("Processing Device::GetConfiguration"); let config = match self.device_state { UsbDeviceState::Configured => CONFIGURATION_VALUE, _ => CONFIGURATION_NONE, @@ -356,6 +375,7 @@ impl UsbDevice<'_, B> { } (Recipient::Interface, Request::GET_INTERFACE) => { + usb_trace!("Processing Interface::GetInterface"); // Reject interface numbers bigger than 255 if req.index > core::u8::MAX.into() { let _ = xfer.reject(); @@ -381,6 +401,7 @@ impl UsbDevice<'_, B> { } if self.control.waiting_for_response() { + usb_debug!("Rejecting control transfer because we were waiting for a response"); let _ = self.control.reject(); } } @@ -409,11 +430,13 @@ impl UsbDevice<'_, B> { Request::CLEAR_FEATURE, Request::FEATURE_DEVICE_REMOTE_WAKEUP, ) => { + usb_debug!("Remote wakeup disabled"); self.remote_wakeup_enabled = false; let _ = xfer.accept(); } (Recipient::Endpoint, Request::CLEAR_FEATURE, Request::FEATURE_ENDPOINT_HALT) => { + usb_debug!("EP{} halt removed", req.index & 0x8f); self.bus .set_stalled(((req.index as u8) & 0x8f).into(), false); let _ = xfer.accept(); @@ -424,17 +447,20 @@ impl UsbDevice<'_, B> { Request::SET_FEATURE, Request::FEATURE_DEVICE_REMOTE_WAKEUP, ) => { + usb_debug!("Remote wakeup enabled"); self.remote_wakeup_enabled = true; let _ = xfer.accept(); } (Recipient::Endpoint, Request::SET_FEATURE, Request::FEATURE_ENDPOINT_HALT) => { + usb_debug!("EP{} halted", req.index & 0x8f); self.bus .set_stalled(((req.index as u8) & 0x8f).into(), true); let _ = xfer.accept(); } (Recipient::Device, Request::SET_ADDRESS, 1..=127) => { + usb_debug!("Setting device address to {}", req.value); if B::QUIRK_SET_ADDRESS_BEFORE_STATUS { self.bus.set_device_address(req.value as u8); self.device_state = UsbDeviceState::Addressed; @@ -445,11 +471,13 @@ impl UsbDevice<'_, B> { } (Recipient::Device, Request::SET_CONFIGURATION, CONFIGURATION_VALUE_U16) => { + usb_debug!("Device configured"); self.device_state = UsbDeviceState::Configured; let _ = xfer.accept(); } (Recipient::Device, Request::SET_CONFIGURATION, CONFIGURATION_NONE_U16) => { + usb_debug!("Device deconfigured"); match self.device_state { UsbDeviceState::Default => { let _ = xfer.accept(); @@ -479,8 +507,10 @@ impl UsbDevice<'_, B> { // Default behaviour, if no class implementation accepted the alternate setting. if alt_setting == DEFAULT_ALTERNATE_SETTING_U16 { + usb_debug!("Accepting unused alternate settings"); let _ = xfer.accept(); } else { + usb_debug!("Rejecting unused alternate settings"); let _ = xfer.reject(); } } @@ -493,6 +523,7 @@ impl UsbDevice<'_, B> { } if self.control.waiting_for_response() { + usb_debug!("Rejecting control transfer due to waiting response"); let _ = self.control.reject(); } } diff --git a/src/lib.rs b/src/lib.rs index 201f6b2..b33c4b8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -36,6 +36,9 @@ #![no_std] #![warn(missing_docs)] +#[macro_use] +mod macros; + /// A USB stack error. #[derive(Copy, Clone, Eq, PartialEq, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] From d09d74a220d17db4bf489910c0e793d997dfbe0c Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Mon, 26 Feb 2024 12:09:25 +0100 Subject: [PATCH 08/25] Updating CHANGELOG --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a058fc6..d7f77bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [Unreleased] +### Added +* A new `log` feature can be enabled to provide logging and tracing information about the USB +interface. + ### Changed * Invalid LangIDs will default to `EN_US` From bec509364a74fe1f7c43ad97417808c74216aa21 Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Mon, 26 Feb 2024 13:47:58 +0100 Subject: [PATCH 09/25] Updating tracing, changing EP0 handling --- CHANGELOG.md | 1 + src/control_pipe.rs | 48 +++++++++++++++++++++++++++------------------ src/device.rs | 44 ++++++++++++++++++++--------------------- 3 files changed, 52 insertions(+), 41 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d7f77bc..fb9bc56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ interface. ### Changed * Invalid LangIDs will default to `EN_US` +* Changed handling of EP0 state to eliminate unexpected issues with device enumeration ## [0.3.1] - 2023-11-15 diff --git a/src/control_pipe.rs b/src/control_pipe.rs index 1f142f3..ea95887 100644 --- a/src/control_pipe.rs +++ b/src/control_pipe.rs @@ -69,10 +69,12 @@ impl ControlPipe<'_, B> { pub fn handle_setup(&mut self) -> Option { let count = match self.ep_out.read(&mut self.buf[..]) { - Ok(count) => count, + Ok(count) => { + usb_trace!("Read {count} bytes on EP0-OUT: {:?}", &self.buf[..count]); + count + } Err(UsbError::WouldBlock) => return None, Err(_) => { - self.set_error(); return None; } }; @@ -80,17 +82,17 @@ impl ControlPipe<'_, B> { let req = match Request::parse(&self.buf[0..count]) { Ok(req) => req, Err(_) => { - // Failed to parse SETUP packet - self.set_error(); + // Failed to parse SETUP packet. We are supposed to silently ignore this. return None; } }; // Now that we have properly parsed the setup packet, ensure the end-point is no longer in // a stalled state. - usb_trace!("EP0 request received: {req:?}"); self.ep_out.unstall(); + usb_debug!("EP0 request received: {req:?}"); + /*sprintln!("SETUP {:?} {:?} {:?} req:{} val:{} idx:{} len:{} {:?}", req.direction, req.request_type, req.recipient, req.request, req.value, req.index, req.length, @@ -104,7 +106,6 @@ impl ControlPipe<'_, B> { if req.length as usize > self.buf.len() { // Data stage won't fit in buffer - self.set_error(); return None; } @@ -143,11 +144,11 @@ impl ControlPipe<'_, B> { } }; + usb_trace!("Read {count} bytes on EP0-OUT: {:?}", &self.buf[i..(i + count)]); self.i += count; - usb_trace!("Read {count} bytes on EP0-OUT"); if self.i >= self.len { - usb_debug!("Request OUT complete: {req}"); + usb_debug!("Request OUT complete: {req:?}"); self.state = ControlState::CompleteOut; return Some(req); } @@ -159,7 +160,7 @@ impl ControlPipe<'_, B> { | ControlState::DataInZlp | ControlState::StatusOut => { usb_debug!( - "Terminating DATA stage early. Current state: {:?}", + "Control transfer completed. Current state: {:?}", self.state ); let _ = self.ep_out.read(&mut []); @@ -193,7 +194,7 @@ impl ControlPipe<'_, B> { return false; } - usb_trace!("wrote EP0-IN: ZLP"); + usb_trace!("wrote EP0: ZLP"); self.state = ControlState::DataInLast; } ControlState::DataInLast => { @@ -205,15 +206,14 @@ impl ControlPipe<'_, B> { return true; } ControlState::Idle => { - usb_debug!("Ignoring EP0-IN while in IDLE"); // If we received a message on EP0 while sending the last portion of an IN // transfer, we may have already transitioned to IDLE without getting the last // IN-complete status. Just ignore this indication. } _ => { - // Unexpected IN packet - usb_debug!("Unexpected EP0-IN. Current state: {:?}", self.state); - self.set_error(); + // If we get IN-COMPLETE indications in unexpected states, it's generally because + // of control flow in previous phases updating after our packet was successfully + // sent. Ignore these indications if they don't drive any further behavior. } }; @@ -229,12 +229,12 @@ impl ControlPipe<'_, B> { // There isn't much we can do if the write fails, except to wait for another poll or for // the host to resend the request. Err(_err) => { - usb_debug!("Failed to write EP0-IN: {_err:?}"); + usb_debug!("Failed to write EP0: {_err:?}"); return; } }; - usb_trace!("wrote EP0-IN: {:?}", &buffer[self.i..(self.i + count)]); + usb_trace!("wrote EP0: {:?}", &buffer[self.i..(self.i + count)]); self.i += count; @@ -252,7 +252,10 @@ impl ControlPipe<'_, B> { pub fn accept_out(&mut self) -> Result<()> { match self.state { ControlState::CompleteOut => {} - _ => return Err(UsbError::InvalidState), + _ => { + usb_debug!("Cannot ACK, invalid state: {:?}", self.state); + return Err(UsbError::InvalidState) + }, }; let _ = self.ep_in.write(&[]); @@ -263,7 +266,10 @@ impl ControlPipe<'_, B> { pub fn accept_in(&mut self, f: impl FnOnce(&mut [u8]) -> Result) -> Result<()> { let req = match self.state { ControlState::CompleteIn(req) => req, - _ => return Err(UsbError::InvalidState), + _ => { + usb_debug!("EP0-IN cannot ACK, invalid state: {:?}", self.state); + return Err(UsbError::InvalidState); + }, }; let len = f(&mut self.buf[..])?; @@ -279,7 +285,10 @@ impl ControlPipe<'_, B> { pub fn accept_in_static(&mut self, data: &'static [u8]) -> Result<()> { let req = match self.state { ControlState::CompleteIn(req) => req, - _ => return Err(UsbError::InvalidState), + _ => { + usb_debug!("EP0-IN cannot ACK, invalid state: {:?}", self.state); + return Err(UsbError::InvalidState); + } }; self.static_in_buf = Some(data); @@ -297,6 +306,7 @@ impl ControlPipe<'_, B> { } pub fn reject(&mut self) -> Result<()> { + usb_debug!("EP0 transfer rejected"); if !self.waiting_for_response() { return Err(UsbError::InvalidState); } diff --git a/src/device.rs b/src/device.rs index 219b098..55cd108 100644 --- a/src/device.rs +++ b/src/device.rs @@ -205,28 +205,11 @@ impl UsbDevice<'_, B> { // Pending events for endpoint 0? if (eps & 1) != 0 { usb_debug!( - "EP0: setup={}, in={}, out={}", + "EP0: setup={}, in_complete={}, out={}", ep_setup & 1, ep_in_complete & 1, ep_out & 1 ); - // Handle EP0-IN conditions first. When both EP0-IN and EP0-OUT have completed, - // it is possible that EP0-OUT is a zero-sized out packet to complete the STATUS - // phase of the control transfer. We have to process EP0-IN first to update our - // internal state properly. - if (ep_in_complete & 1) != 0 { - let completed = self.control.handle_in_complete(); - - if !B::QUIRK_SET_ADDRESS_BEFORE_STATUS - && completed - && self.pending_address != 0 - { - self.bus.set_device_address(self.pending_address); - self.pending_address = 0; - - self.device_state = UsbDeviceState::Addressed; - } - } let req = if (ep_setup & 1) != 0 { self.control.handle_setup() @@ -236,10 +219,6 @@ impl UsbDevice<'_, B> { None }; - if let Some(_req) = req { - usb_trace!("Handling EP0 request: {_req}"); - } - match req { Some(req) if req.direction == UsbDirection::In => { self.control_in(classes, req) @@ -247,6 +226,27 @@ impl UsbDevice<'_, B> { Some(req) if req.direction == UsbDirection::Out => { self.control_out(classes, req) } + + None if ((ep_in_complete & 1) != 0) => { + // We only handle EP0-IN completion if there's no other request being + // processed. EP0-IN tokens may be issued due to completed STATUS + // phases of the control transfer. If we just got a SETUP packet or + // an OUT token, we can safely ignore the IN-COMPLETE indication and + // continue with the next transfer. + let completed = self.control.handle_in_complete(); + + if !B::QUIRK_SET_ADDRESS_BEFORE_STATUS + && completed + && self.pending_address != 0 + { + self.bus.set_device_address(self.pending_address); + self.pending_address = 0; + + self.device_state = UsbDeviceState::Addressed; + } + + }, + _ => (), }; From 495c09afe1f2b8d8960af5c5c9bf568cb5868839 Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Mon, 26 Feb 2024 13:51:01 +0100 Subject: [PATCH 10/25] Adding logging macros --- src/macros.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 src/macros.rs diff --git a/src/macros.rs b/src/macros.rs new file mode 100644 index 0000000..ecb7c6d --- /dev/null +++ b/src/macros.rs @@ -0,0 +1,24 @@ +#[cfg(feature = "log")] +macro_rules! usb_log { + (trace, $($arg:expr),*) => { log::trace!($($arg),*) }; + (debug, $($arg:expr),*) => { log::trace!($($arg),*) }; +} + +#[cfg(feature = "defmt")] +macro_rules! net_log { + (trace, $($arg:expr),*) => { defmt::trace!($($arg),*) }; + (debug, $($arg:expr),*) => { defmt::debug!($($arg),*) }; +} + +#[cfg(not(any(feature = "log", feature = "defmt")))] +macro_rules! usb_log { + ($level:ident, $($arg:expr),*) => {{ $( let _ = $arg; )* }} +} + +macro_rules! usb_trace { + ($($arg:expr),*) => (usb_log!(trace, $($arg),*)); +} + +macro_rules! usb_debug { + ($($arg:expr),*) => (usb_log!(debug, $($arg),*)); +} From af340092074123540098da6821d10fa64dbc9e9f Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Mon, 26 Feb 2024 13:52:53 +0100 Subject: [PATCH 11/25] Fixing format --- src/control_pipe.rs | 11 +++++++---- src/device.rs | 3 +-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/control_pipe.rs b/src/control_pipe.rs index ea95887..0848812 100644 --- a/src/control_pipe.rs +++ b/src/control_pipe.rs @@ -144,7 +144,10 @@ impl ControlPipe<'_, B> { } }; - usb_trace!("Read {count} bytes on EP0-OUT: {:?}", &self.buf[i..(i + count)]); + usb_trace!( + "Read {count} bytes on EP0-OUT: {:?}", + &self.buf[i..(i + count)] + ); self.i += count; if self.i >= self.len { @@ -254,8 +257,8 @@ impl ControlPipe<'_, B> { ControlState::CompleteOut => {} _ => { usb_debug!("Cannot ACK, invalid state: {:?}", self.state); - return Err(UsbError::InvalidState) - }, + return Err(UsbError::InvalidState); + } }; let _ = self.ep_in.write(&[]); @@ -269,7 +272,7 @@ impl ControlPipe<'_, B> { _ => { usb_debug!("EP0-IN cannot ACK, invalid state: {:?}", self.state); return Err(UsbError::InvalidState); - }, + } }; let len = f(&mut self.buf[..])?; diff --git a/src/device.rs b/src/device.rs index 55cd108..a7db4d4 100644 --- a/src/device.rs +++ b/src/device.rs @@ -244,8 +244,7 @@ impl UsbDevice<'_, B> { self.device_state = UsbDeviceState::Addressed; } - - }, + } _ => (), }; From 6de076b984dd9b5bf1d894c45649dcc9c0472217 Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Mon, 26 Feb 2024 13:55:48 +0100 Subject: [PATCH 12/25] Fixing defmt build --- src/macros.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/macros.rs b/src/macros.rs index ecb7c6d..bb6744f 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -5,7 +5,7 @@ macro_rules! usb_log { } #[cfg(feature = "defmt")] -macro_rules! net_log { +macro_rules! usb_log { (trace, $($arg:expr),*) => { defmt::trace!($($arg),*) }; (debug, $($arg:expr),*) => { defmt::debug!($($arg),*) }; } From 610aded162529065140f21919de365d6571d4231 Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Mon, 26 Feb 2024 14:13:45 +0100 Subject: [PATCH 13/25] Fixing builds --- src/control_pipe.rs | 11 ++++++----- src/device.rs | 6 +++--- src/macros.rs | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/control_pipe.rs b/src/control_pipe.rs index 0848812..c3d2a56 100644 --- a/src/control_pipe.rs +++ b/src/control_pipe.rs @@ -70,7 +70,7 @@ impl ControlPipe<'_, B> { pub fn handle_setup(&mut self) -> Option { let count = match self.ep_out.read(&mut self.buf[..]) { Ok(count) => { - usb_trace!("Read {count} bytes on EP0-OUT: {:?}", &self.buf[..count]); + usb_trace!("Read {} bytes on EP0-OUT: {:?}", count, &self.buf[..count]); count } Err(UsbError::WouldBlock) => return None, @@ -91,7 +91,7 @@ impl ControlPipe<'_, B> { // a stalled state. self.ep_out.unstall(); - usb_debug!("EP0 request received: {req:?}"); + usb_debug!("EP0 request received: {:?}", req); /*sprintln!("SETUP {:?} {:?} {:?} req:{} val:{} idx:{} len:{} {:?}", req.direction, req.request_type, req.recipient, @@ -145,13 +145,14 @@ impl ControlPipe<'_, B> { }; usb_trace!( - "Read {count} bytes on EP0-OUT: {:?}", + "Read {} bytes on EP0-OUT: {:?}", + count, &self.buf[i..(i + count)] ); self.i += count; if self.i >= self.len { - usb_debug!("Request OUT complete: {req:?}"); + usb_debug!("Request OUT complete: {:?}", req); self.state = ControlState::CompleteOut; return Some(req); } @@ -232,7 +233,7 @@ impl ControlPipe<'_, B> { // There isn't much we can do if the write fails, except to wait for another poll or for // the host to resend the request. Err(_err) => { - usb_debug!("Failed to write EP0: {_err:?}"); + usb_debug!("Failed to write EP0: {:?}", _err); return; } }; diff --git a/src/device.rs b/src/device.rs index a7db4d4..2bd8555 100644 --- a/src/device.rs +++ b/src/device.rs @@ -259,21 +259,21 @@ impl UsbDevice<'_, B> { for i in 1..MAX_ENDPOINTS { if (ep_setup & bit) != 0 { for cls in classes.iter_mut() { - usb_trace!("Handling EP{i}-SETUP"); + usb_trace!("Handling EP{}-SETUP", i); cls.endpoint_setup(EndpointAddress::from_parts( i, UsbDirection::Out, )); } } else if (ep_out & bit) != 0 { - usb_trace!("Handling EP{i}-OUT"); + usb_trace!("Handling EP{}-OUT", i); for cls in classes.iter_mut() { cls.endpoint_out(EndpointAddress::from_parts(i, UsbDirection::Out)); } } if (ep_in_complete & bit) != 0 { - usb_trace!("Handling EP{i}-IN"); + usb_trace!("Handling EP{}-IN", i); for cls in classes.iter_mut() { cls.endpoint_in_complete(EndpointAddress::from_parts( i, diff --git a/src/macros.rs b/src/macros.rs index bb6744f..e6edd32 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -1,4 +1,4 @@ -#[cfg(feature = "log")] +#[cfg(all(feature = "log", not(feature = "defmt")))] macro_rules! usb_log { (trace, $($arg:expr),*) => { log::trace!($($arg),*) }; (debug, $($arg:expr),*) => { log::trace!($($arg),*) }; From ef539cb8e8b2055362976aea0fd1ae929fd0eab5 Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Wed, 28 Feb 2024 10:50:12 +0100 Subject: [PATCH 14/25] Updating CHANGELOG --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fb9bc56..b6bad56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. interface. ### Changed -* Invalid LangIDs will default to `EN_US` +* [breaking] LangIDs no longer implement `TryFromPrimitive`. The minor version has not been bumped +as this was not intended to be used in the public API. + - If this is problematic, please open an issue in the main `usb-device` repository. * Changed handling of EP0 state to eliminate unexpected issues with device enumeration ## [0.3.1] - 2023-11-15 From ac594c15d293eca755af32bbe1748bd5b1ac16d9 Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Wed, 28 Feb 2024 11:03:57 +0100 Subject: [PATCH 15/25] Propagating results outward instead of silently ignoring --- src/control_pipe.rs | 16 ++++++++-------- src/device.rs | 41 ++++++++++++++++++++++++++--------------- 2 files changed, 34 insertions(+), 23 deletions(-) diff --git a/src/control_pipe.rs b/src/control_pipe.rs index c3d2a56..b883b1a 100644 --- a/src/control_pipe.rs +++ b/src/control_pipe.rs @@ -129,18 +129,18 @@ impl ControlPipe<'_, B> { None } - pub fn handle_out(&mut self) -> Option { + pub fn handle_out(&mut self) -> Result> { match self.state { ControlState::DataOut(req) => { let i = self.i; let count = match self.ep_out.read(&mut self.buf[i..]) { Ok(count) => count, - Err(UsbError::WouldBlock) => return None, + Err(UsbError::WouldBlock) => return Ok(None), Err(_) => { // Failed to read or buffer overflow (overflow is only possible if the host // sends more data than it indicated in the SETUP request) self.set_error(); - return None; + return Ok(None); } }; @@ -154,7 +154,7 @@ impl ControlPipe<'_, B> { if self.i >= self.len { usb_debug!("Request OUT complete: {:?}", req); self.state = ControlState::CompleteOut; - return Some(req); + return Ok(Some(req)); } } // The host may terminate a DATA stage early by sending a zero-length status packet @@ -167,7 +167,7 @@ impl ControlPipe<'_, B> { "Control transfer completed. Current state: {:?}", self.state ); - let _ = self.ep_out.read(&mut []); + self.ep_out.read(&mut [])?; self.state = ControlState::Idle; } _ => { @@ -176,14 +176,14 @@ impl ControlPipe<'_, B> { "Discarding EP0 data due to unexpected state. Current state: {:?}", self.state ); - let _ = self.ep_out.read(&mut []); + self.ep_out.read(&mut [])?; // Unexpected OUT packet self.set_error() } } - None + Ok(None) } pub fn handle_in_complete(&mut self) -> bool { @@ -262,7 +262,7 @@ impl ControlPipe<'_, B> { } }; - let _ = self.ep_in.write(&[]); + self.ep_in.write(&[])?; self.state = ControlState::StatusIn; Ok(()) } diff --git a/src/device.rs b/src/device.rs index a2f24f9..cecb31c 100644 --- a/src/device.rs +++ b/src/device.rs @@ -182,6 +182,7 @@ impl UsbDevice<'_, B> { } _ => { self.bus.resume(); + self.device_state = self .suspended_device_state .expect("Unknown state before suspend"); @@ -213,14 +214,24 @@ impl UsbDevice<'_, B> { let req = if (ep_setup & 1) != 0 { self.control.handle_setup() } else if (ep_out & 1) != 0 { - self.control.handle_out() + match self.control.handle_out() { + Ok(req) => req, + Err(_err) => { + // TODO: Propagate error out of `poll()` + usb_debug!("Failed to handle EP0: {_err}"); + None + } + } } else { None }; match req { Some(req) if req.direction == UsbDirection::In => { - self.control_in(classes, req) + if let Err(_err) = self.control_in(classes, req) { + // TODO: Propagate error out of `poll()` + usb_debug!("Failed to handle control request: {_err}"); + } } Some(req) if req.direction == UsbDirection::Out => { self.control_out(classes, req) @@ -310,14 +321,14 @@ impl UsbDevice<'_, B> { false } - fn control_in(&mut self, classes: &mut ClassList<'_, B>, req: control::Request) { + fn control_in(&mut self, classes: &mut ClassList<'_, B>, req: control::Request) -> Result<()> { use crate::control::{Recipient, Request}; for cls in classes.iter_mut() { cls.control_in(ControlIn::new(&mut self.control, &req)); if !self.control.waiting_for_response() { - return; + return Ok(()); } } @@ -334,14 +345,14 @@ impl UsbDevice<'_, B> { 0x0000 }; - let _ = xfer.accept_with(&status.to_le_bytes()); + xfer.accept_with(&status.to_le_bytes())?; } (Recipient::Interface, Request::GET_STATUS) => { usb_trace!("Processing Interface::GetStatus"); let status: u16 = 0x0000; - let _ = xfer.accept_with(&status.to_le_bytes()); + xfer.accept_with(&status.to_le_bytes())?; } (Recipient::Endpoint, Request::GET_STATUS) => { @@ -354,7 +365,7 @@ impl UsbDevice<'_, B> { 0x0000 }; - let _ = xfer.accept_with(&status.to_le_bytes()); + xfer.accept_with(&status.to_le_bytes())?; } (Recipient::Device, Request::GET_DESCRIPTOR) => { @@ -369,15 +380,14 @@ impl UsbDevice<'_, B> { _ => CONFIGURATION_NONE, }; - let _ = xfer.accept_with(&config.to_le_bytes()); + xfer.accept_with(&config.to_le_bytes())?; } (Recipient::Interface, Request::GET_INTERFACE) => { usb_trace!("Processing Interface::GetInterface"); // Reject interface numbers bigger than 255 if req.index > core::u8::MAX.into() { - let _ = xfer.reject(); - return; + return xfer.reject(); } // Ask class implementations, whether they know the alternate setting @@ -385,23 +395,24 @@ impl UsbDevice<'_, B> { for cls in classes { if let Some(setting) = cls.get_alt_setting(InterfaceNumber(req.index as u8)) { - let _ = xfer.accept_with(&setting.to_le_bytes()); - return; + return xfer.accept_with(&setting.to_le_bytes()); } } // If no class returned an alternate setting, return the default value - let _ = xfer.accept_with(&DEFAULT_ALTERNATE_SETTING.to_le_bytes()); + xfer.accept_with(&DEFAULT_ALTERNATE_SETTING.to_le_bytes())?; } - _ => (), + _ => {} }; } if self.control.waiting_for_response() { usb_debug!("Rejecting control transfer because we were waiting for a response"); - let _ = self.control.reject(); + self.control.reject()?; } + + Ok(()) } fn control_out(&mut self, classes: &mut ClassList<'_, B>, req: control::Request) { From 49ceb08d9af1df1d4971d42062493582525db91e Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Wed, 28 Feb 2024 11:10:31 +0100 Subject: [PATCH 16/25] Cleaning up further result usage --- src/control_pipe.rs | 32 ++++++++++---------------------- src/device.rs | 12 +++++++++++- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/src/control_pipe.rs b/src/control_pipe.rs index b883b1a..0a1b7d3 100644 --- a/src/control_pipe.rs +++ b/src/control_pipe.rs @@ -186,18 +186,13 @@ impl ControlPipe<'_, B> { Ok(None) } - pub fn handle_in_complete(&mut self) -> bool { + pub fn handle_in_complete(&mut self) -> Result { match self.state { ControlState::DataIn => { - self.write_in_chunk(); + self.write_in_chunk()?; } ControlState::DataInZlp => { - if self.ep_in.write(&[]).is_err() { - // There isn't much we can do if the write fails, except to wait for another - // poll or for the host to resend the request. - return false; - } - + self.ep_in.write(&[])?; usb_trace!("wrote EP0: ZLP"); self.state = ControlState::DataInLast; } @@ -207,7 +202,7 @@ impl ControlPipe<'_, B> { } ControlState::StatusIn => { self.state = ControlState::Idle; - return true; + return Ok(true); } ControlState::Idle => { // If we received a message on EP0 while sending the last portion of an IN @@ -221,23 +216,14 @@ impl ControlPipe<'_, B> { } }; - false + Ok(false) } - fn write_in_chunk(&mut self) { + fn write_in_chunk(&mut self) -> Result<()> { let count = min(self.len - self.i, self.ep_in.max_packet_size() as usize); let buffer = self.static_in_buf.unwrap_or(&self.buf); - let count = match self.ep_in.write(&buffer[self.i..(self.i + count)]) { - Ok(c) => c, - // There isn't much we can do if the write fails, except to wait for another poll or for - // the host to resend the request. - Err(_err) => { - usb_debug!("Failed to write EP0: {:?}", _err); - return; - } - }; - + let count = self.ep_in.write(&buffer[self.i..(self.i + count)])?; usb_trace!("wrote EP0: {:?}", &buffer[self.i..(self.i + count)]); self.i += count; @@ -251,6 +237,8 @@ impl ControlPipe<'_, B> { ControlState::DataInLast }; } + + Ok(()) } pub fn accept_out(&mut self) -> Result<()> { @@ -304,7 +292,7 @@ impl ControlPipe<'_, B> { self.len = min(data_len, req.length as usize); self.i = 0; self.state = ControlState::DataIn; - self.write_in_chunk(); + self.write_in_chunk()?; Ok(()) } diff --git a/src/device.rs b/src/device.rs index cecb31c..db6122b 100644 --- a/src/device.rs +++ b/src/device.rs @@ -243,7 +243,17 @@ impl UsbDevice<'_, B> { // phases of the control transfer. If we just got a SETUP packet or // an OUT token, we can safely ignore the IN-COMPLETE indication and // continue with the next transfer. - let completed = self.control.handle_in_complete(); + let completed = match self.control.handle_in_complete() { + Ok(completed) => completed, + Err(_err) => { + // TODO: Propagate this out of `poll()` + usb_debug!( + "Failed to process control-input complete: {}", + _err + ); + false + } + }; if !B::QUIRK_SET_ADDRESS_BEFORE_STATUS && completed From 8318f0cea51a3fa206d5eb76a63f4030a66e5d5e Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Wed, 28 Feb 2024 11:16:46 +0100 Subject: [PATCH 17/25] Fixing build --- src/control_pipe.rs | 3 ++- src/device.rs | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/control_pipe.rs b/src/control_pipe.rs index 0a1b7d3..f72cab6 100644 --- a/src/control_pipe.rs +++ b/src/control_pipe.rs @@ -136,10 +136,11 @@ impl ControlPipe<'_, B> { let count = match self.ep_out.read(&mut self.buf[i..]) { Ok(count) => count, Err(UsbError::WouldBlock) => return Ok(None), - Err(_) => { + Err(_err) => { // Failed to read or buffer overflow (overflow is only possible if the host // sends more data than it indicated in the SETUP request) self.set_error(); + usb_debug!("Failed EP0 read: {:?}", _err); return Ok(None); } }; diff --git a/src/device.rs b/src/device.rs index db6122b..9bff183 100644 --- a/src/device.rs +++ b/src/device.rs @@ -218,7 +218,7 @@ impl UsbDevice<'_, B> { Ok(req) => req, Err(_err) => { // TODO: Propagate error out of `poll()` - usb_debug!("Failed to handle EP0: {_err}"); + usb_debug!("Failed to handle EP0: {}", _err); None } } @@ -230,7 +230,7 @@ impl UsbDevice<'_, B> { Some(req) if req.direction == UsbDirection::In => { if let Err(_err) = self.control_in(classes, req) { // TODO: Propagate error out of `poll()` - usb_debug!("Failed to handle control request: {_err}"); + usb_debug!("Failed to handle control request: {}", _err); } } Some(req) if req.direction == UsbDirection::Out => { From 5fe6f6ad00ad7d690bcbb1611bdae9a2e693d4d1 Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Wed, 28 Feb 2024 11:18:55 +0100 Subject: [PATCH 18/25] Fixing log order --- src/control_pipe.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/control_pipe.rs b/src/control_pipe.rs index f72cab6..1dd66ca 100644 --- a/src/control_pipe.rs +++ b/src/control_pipe.rs @@ -139,8 +139,8 @@ impl ControlPipe<'_, B> { Err(_err) => { // Failed to read or buffer overflow (overflow is only possible if the host // sends more data than it indicated in the SETUP request) - self.set_error(); usb_debug!("Failed EP0 read: {:?}", _err); + self.set_error(); return Ok(None); } }; From deec99cb691a1cdd0bf9fc5405301452b0964f96 Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Wed, 28 Feb 2024 11:20:34 +0100 Subject: [PATCH 19/25] Fixing log format --- src/device.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/device.rs b/src/device.rs index 9bff183..3ac1eb1 100644 --- a/src/device.rs +++ b/src/device.rs @@ -218,7 +218,7 @@ impl UsbDevice<'_, B> { Ok(req) => req, Err(_err) => { // TODO: Propagate error out of `poll()` - usb_debug!("Failed to handle EP0: {}", _err); + usb_debug!("Failed to handle EP0: {:?}", _err); None } } @@ -230,7 +230,7 @@ impl UsbDevice<'_, B> { Some(req) if req.direction == UsbDirection::In => { if let Err(_err) = self.control_in(classes, req) { // TODO: Propagate error out of `poll()` - usb_debug!("Failed to handle control request: {}", _err); + usb_debug!("Failed to handle control request: {:?}", _err); } } Some(req) if req.direction == UsbDirection::Out => { @@ -248,7 +248,7 @@ impl UsbDevice<'_, B> { Err(_err) => { // TODO: Propagate this out of `poll()` usb_debug!( - "Failed to process control-input complete: {}", + "Failed to process control-input complete: {:?}", _err ); false From c82290cabc1b05780a807240d62b7032a321f032 Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Wed, 28 Feb 2024 11:25:37 +0100 Subject: [PATCH 20/25] Using proper log macro --- src/macros.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/macros.rs b/src/macros.rs index e6edd32..ff96a6d 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -1,7 +1,7 @@ #[cfg(all(feature = "log", not(feature = "defmt")))] macro_rules! usb_log { (trace, $($arg:expr),*) => { log::trace!($($arg),*) }; - (debug, $($arg:expr),*) => { log::trace!($($arg),*) }; + (debug, $($arg:expr),*) => { log::debug!($($arg),*) }; } #[cfg(feature = "defmt")] From beb6b9ee93c8885692d4a04bd2dc22a743242ac4 Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Wed, 28 Feb 2024 12:06:02 +0100 Subject: [PATCH 21/25] Cleaning up more result propagation --- src/device.rs | 85 +++++++++++++++++++++++++++++---------------------- 1 file changed, 49 insertions(+), 36 deletions(-) diff --git a/src/device.rs b/src/device.rs index 3ac1eb1..e5b49df 100644 --- a/src/device.rs +++ b/src/device.rs @@ -230,11 +230,14 @@ impl UsbDevice<'_, B> { Some(req) if req.direction == UsbDirection::In => { if let Err(_err) = self.control_in(classes, req) { // TODO: Propagate error out of `poll()` - usb_debug!("Failed to handle control request: {:?}", _err); + usb_debug!("Failed to handle input control request: {:?}", _err); } } Some(req) if req.direction == UsbDirection::Out => { - self.control_out(classes, req) + if let Err(_err) = self.control_out(classes, req) { + // TODO: Propagate error out of `poll()` + usb_debug!("Failed to handle output control request: {:?}", _err); + } } None if ((ep_in_complete & 1) != 0) => { @@ -380,7 +383,7 @@ impl UsbDevice<'_, B> { (Recipient::Device, Request::GET_DESCRIPTOR) => { usb_trace!("Processing Device::GetDescriptor"); - UsbDevice::get_descriptor(&self.config, classes, xfer) + UsbDevice::get_descriptor(&self.config, classes, xfer)?; } (Recipient::Device, Request::GET_CONFIGURATION) => { @@ -425,14 +428,14 @@ impl UsbDevice<'_, B> { Ok(()) } - fn control_out(&mut self, classes: &mut ClassList<'_, B>, req: control::Request) { + fn control_out(&mut self, classes: &mut ClassList<'_, B>, req: control::Request) -> Result<()> { use crate::control::{Recipient, Request}; for cls in classes.iter_mut() { cls.control_out(ControlOut::new(&mut self.control, &req)); if !self.control.waiting_for_response() { - return; + return Ok(()); } } @@ -451,14 +454,14 @@ impl UsbDevice<'_, B> { ) => { usb_debug!("Remote wakeup disabled"); self.remote_wakeup_enabled = false; - let _ = xfer.accept(); + xfer.accept()?; } (Recipient::Endpoint, Request::CLEAR_FEATURE, Request::FEATURE_ENDPOINT_HALT) => { usb_debug!("EP{} halt removed", req.index & 0x8f); self.bus .set_stalled(((req.index as u8) & 0x8f).into(), false); - let _ = xfer.accept(); + xfer.accept()?; } ( @@ -468,14 +471,14 @@ impl UsbDevice<'_, B> { ) => { usb_debug!("Remote wakeup enabled"); self.remote_wakeup_enabled = true; - let _ = xfer.accept(); + xfer.accept()?; } (Recipient::Endpoint, Request::SET_FEATURE, Request::FEATURE_ENDPOINT_HALT) => { usb_debug!("EP{} halted", req.index & 0x8f); self.bus .set_stalled(((req.index as u8) & 0x8f).into(), true); - let _ = xfer.accept(); + xfer.accept()?; } (Recipient::Device, Request::SET_ADDRESS, 1..=127) => { @@ -486,24 +489,24 @@ impl UsbDevice<'_, B> { } else { self.pending_address = req.value as u8; } - let _ = xfer.accept(); + xfer.accept()?; } (Recipient::Device, Request::SET_CONFIGURATION, CONFIGURATION_VALUE_U16) => { usb_debug!("Device configured"); self.device_state = UsbDeviceState::Configured; - let _ = xfer.accept(); + xfer.accept()?; } (Recipient::Device, Request::SET_CONFIGURATION, CONFIGURATION_NONE_U16) => { usb_debug!("Device deconfigured"); match self.device_state { UsbDeviceState::Default => { - let _ = xfer.accept(); + xfer.accept()?; } _ => { self.device_state = UsbDeviceState::Addressed; - let _ = xfer.accept(); + xfer.accept()?; } } } @@ -511,43 +514,49 @@ impl UsbDevice<'_, B> { (Recipient::Interface, Request::SET_INTERFACE, alt_setting) => { // Reject interface numbers and alt settings bigger than 255 if req.index > core::u8::MAX.into() || alt_setting > core::u8::MAX.into() { - let _ = xfer.reject(); - return; + xfer.reject()?; + return Ok(()); } // Ask class implementations, whether they accept the alternate interface setting. for cls in classes { if cls.set_alt_setting(InterfaceNumber(req.index as u8), alt_setting as u8) { - let _ = xfer.accept(); - return; + xfer.accept()?; + return Ok(()); } } // Default behaviour, if no class implementation accepted the alternate setting. if alt_setting == DEFAULT_ALTERNATE_SETTING_U16 { usb_debug!("Accepting unused alternate settings"); - let _ = xfer.accept(); + xfer.accept()?; } else { usb_debug!("Rejecting unused alternate settings"); - let _ = xfer.reject(); + xfer.reject()?; } } _ => { - let _ = xfer.reject(); - return; + xfer.reject()?; + return Ok(()); } } } if self.control.waiting_for_response() { usb_debug!("Rejecting control transfer due to waiting response"); - let _ = self.control.reject(); + self.control.reject()?; } + + Ok(()) } - fn get_descriptor(config: &Config, classes: &mut ClassList<'_, B>, xfer: ControlIn) { + fn get_descriptor( + config: &Config, + classes: &mut ClassList<'_, B>, + xfer: ControlIn, + ) -> Result<()> { let req = *xfer.request(); let (dtype, index) = req.descriptor_type_index(); @@ -555,12 +564,14 @@ impl UsbDevice<'_, B> { fn accept_writer( xfer: ControlIn, f: impl FnOnce(&mut DescriptorWriter) -> Result<()>, - ) { - let _ = xfer.accept(|buf| { + ) -> Result<()> { + xfer.accept(|buf| { let mut writer = DescriptorWriter::new(buf); f(&mut writer)?; Ok(writer.position()) - }); + })?; + + Ok(()) } match dtype { @@ -575,9 +586,9 @@ impl UsbDevice<'_, B> { bw.end_bos(); Ok(()) - }), + })?, - descriptor_type::DEVICE => accept_writer(xfer, |w| w.device(config)), + descriptor_type::DEVICE => accept_writer(xfer, |w| w.device(config))?, descriptor_type::CONFIGURATION => accept_writer(xfer, |w| { w.configuration(config)?; @@ -590,7 +601,7 @@ impl UsbDevice<'_, B> { w.end_configuration(); Ok(()) - }), + })?, descriptor_type::STRING => match index { // first STRING Request @@ -608,7 +619,7 @@ impl UsbDevice<'_, B> { descriptor_type::STRING, &lang_id_bytes[..config.string_descriptors.len() * 2], ) - }) + })?; } // rest STRING Requests @@ -623,8 +634,8 @@ impl UsbDevice<'_, B> { .iter() .find(|lang| lang.id == lang_id) else { - xfer.reject().ok(); - return; + xfer.reject()?; + return Ok(()); }; match index { @@ -643,17 +654,19 @@ impl UsbDevice<'_, B> { }; if let Some(string_descriptor) = string { - accept_writer(xfer, |w| w.string(string_descriptor)); + accept_writer(xfer, |w| w.string(string_descriptor))?; } else { - let _ = xfer.reject(); + xfer.reject()?; } } }, _ => { - let _ = xfer.reject(); + xfer.reject()?; } - } + }; + + Ok(()) } fn reset(&mut self, classes: &mut ClassList<'_, B>) { From 2cc436f27d2f58e0c26bcb25b264423d3343edf2 Mon Sep 17 00:00:00 2001 From: Vitalii Bursov Date: Wed, 28 Feb 2024 14:06:47 +0200 Subject: [PATCH 22/25] Restore deriving defmt::Format for LangID when defmt feature is enabled --- src/descriptor/lang_id.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/descriptor/lang_id.rs b/src/descriptor/lang_id.rs index 1e90a9f..298da80 100644 --- a/src/descriptor/lang_id.rs +++ b/src/descriptor/lang_id.rs @@ -2,6 +2,7 @@ #[allow(missing_docs)] #[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct LangID(u16); impl From for u16 { From 859eb3756f882c1901f166293343a9086601f3bf Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Mon, 4 Mar 2024 09:56:32 +0100 Subject: [PATCH 23/25] Preparing for 0.3.2 release --- CHANGELOG.md | 5 ++++- Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b6bad56..9583f65 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [Unreleased] +## [0.3.2] - 2024-03-04 + ### Added * A new `log` feature can be enabled to provide logging and tracing information about the USB interface. @@ -81,7 +83,8 @@ as this was not intended to be used in the public API. This is the initial release to crates.io. -[Unreleased]: https://github.com/rust-embedded-community/usb-device/compare/v0.3.1...HEAD +[Unreleased]: https://github.com/rust-embedded-community/usb-device/compare/v0.3.2...HEAD +[0.3.2]: https://github.com/rust-embedded-community/usb-device/compare/v0.3.0...v0.3.2 [0.3.1]: https://github.com/rust-embedded-community/usb-device/compare/v0.3.0...v0.3.1 [0.3.0]: https://github.com/rust-embedded-community/usb-device/compare/v0.2.9...v0.3.0 [0.2.9]: https://github.com/rust-embedded-community/usb-device/compare/v0.2.8...v0.2.9 diff --git a/Cargo.toml b/Cargo.toml index 0083a54..d5c2c6c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "usb-device" description = "USB stack for embedded devices." -version = "0.3.1" +version = "0.3.2" edition = "2018" readme = "README.md" keywords = ["no-std", "embedded", "usb"] From a158cfa49a4ac3c63b9d854070619a76458fe396 Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Wed, 6 Mar 2024 10:05:40 +0100 Subject: [PATCH 24/25] Update CHANGELOG.md Co-authored-by: Jonathan 'theJPster' Pallant --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9583f65..224cbc8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -84,7 +84,7 @@ as this was not intended to be used in the public API. This is the initial release to crates.io. [Unreleased]: https://github.com/rust-embedded-community/usb-device/compare/v0.3.2...HEAD -[0.3.2]: https://github.com/rust-embedded-community/usb-device/compare/v0.3.0...v0.3.2 +[0.3.2]: https://github.com/rust-embedded-community/usb-device/compare/v0.3.1...v0.3.2 [0.3.1]: https://github.com/rust-embedded-community/usb-device/compare/v0.3.0...v0.3.1 [0.3.0]: https://github.com/rust-embedded-community/usb-device/compare/v0.2.9...v0.3.0 [0.2.9]: https://github.com/rust-embedded-community/usb-device/compare/v0.2.8...v0.2.9 From bb4e9f106bc079df9ccee7d0506535f674707e4e Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Wed, 6 Mar 2024 10:06:14 +0100 Subject: [PATCH 25/25] Bumping release date --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 224cbc8..dfaba74 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [Unreleased] -## [0.3.2] - 2024-03-04 +## [0.3.2] - 2024-03-06 ### Added * A new `log` feature can be enabled to provide logging and tracing information about the USB