diff --git a/src/Smdn.Devices.MCP2221/Smdn.Devices.MCP2221/MCP2221.Commands.cs b/src/Smdn.Devices.MCP2221/Smdn.Devices.MCP2221/MCP2221.Commands.cs index 9ab58fc..40c280c 100644 --- a/src/Smdn.Devices.MCP2221/Smdn.Devices.MCP2221/MCP2221.Commands.cs +++ b/src/Smdn.Devices.MCP2221/Smdn.Devices.MCP2221/MCP2221.Commands.cs @@ -194,31 +194,63 @@ static void CreateRevisionString(Span str, (char major, char minor) revisi } } - private static class RetrieveChipFactorySerialNumberCommand { - public static void ConstructCommand(Span comm, ReadOnlySpan userData, int _) + // [MCP2221A] 3.1.2 READ FLASH DATA + private enum ReadFlashDataSubCode : byte { + UsbDescriptorStringManufacturer = 0x02, + UsbDescriptorStringProduct = 0x03, + UsbDescriptorStringSerialNumber = 0x04, + ChipFactorySerialNumber = 0x05 + } + + private static class RetrieveFlashStringCommand { + public static void ConstructCommand(Span comm, ReadOnlySpan userData, ReadFlashDataSubCode subCode) { // [MCP2221A] 3.1.2 READ FLASH DATA comm[0] = 0xB0; // Read Flash Data - comm[1] = 0x05; // Read Chip Factory Serial Number + + // Read Flash Data Sub Code + // 0x02: Read USB Manufacturer Descriptor String + // 0x03: Read USB Product Descriptor String + // 0x04: Read USB Manufacturer Descriptor String + // 0x05: Read Chip Factory Serial Number + comm[1] = (byte)subCode; } - public static unsafe string ParseResponse(ReadOnlySpan resp, int _) + public static unsafe string ParseResponse(ReadOnlySpan resp, ReadFlashDataSubCode subCode) { + if (subCode == ReadFlashDataSubCode.ChipFactorySerialNumber) { #if false // XXX: string.Create does not accept ReadOnlySpan, dotnet/runtime#30175 - return string.Create((int)resp[2], resp, (str, re) => { - for (var i = 0; i < str.Length; i++) { - str[i] = (char)re[i]; + return string.Create((int)resp[2], resp, (str, re) => { + for (var i = 0; i < str.Length; i++) { + str[i] = (char)re[i]; + } } - } #endif - var length = (int)resp[2]; - Span serialNumberChars = stackalloc char[length]; + var length = (int)resp[2]; + Span serialNumberChars = stackalloc char[length]; - for (var i = 0; i < length; i++) { - serialNumberChars[i] = (char)resp[4 + i]; + for (var i = 0; i < length; i++) { + serialNumberChars[i] = (char)resp[4 + i]; + } + + return new string(serialNumberChars); } + else { + // 0x02: The number of bytes + 2 in the provided USB Manufacturer/Product/Serial Number Descriptor String. + var lengthInBytes = (int)resp[2] - 2; + var length = lengthInBytes / 2; + + Span descriptorStringChars = stackalloc char[length]; - return new string(serialNumberChars); + for (var i = 0; i < length; i++) { + var lower = resp[4 + 2 * i + 0]; + var higher = resp[4 + 2 * i + 1]; + + descriptorStringChars[i] = (char)(lower | (higher << 8)); + } + + return new string(descriptorStringChars); + } } } @@ -238,12 +270,36 @@ Action validateFirmwareRevision validateHardwareRevision?.Invoke(HardwareRevision); validateFirmwareRevision?.Invoke(FirmwareRevision); + ManufacturerDescriptor = await CommandAsync( + userData: default, + arg: ReadFlashDataSubCode.UsbDescriptorStringManufacturer, + cancellationToken: default, + constructCommand: RetrieveFlashStringCommand.ConstructCommand, + parseResponse: RetrieveFlashStringCommand.ParseResponse + ).ConfigureAwait(false); + + ProductDescriptor = await CommandAsync( + userData: default, + arg: ReadFlashDataSubCode.UsbDescriptorStringProduct, + cancellationToken: default, + constructCommand: RetrieveFlashStringCommand.ConstructCommand, + parseResponse: RetrieveFlashStringCommand.ParseResponse + ).ConfigureAwait(false); + + SerialNumberDescriptor = await CommandAsync( + userData: default, + arg: ReadFlashDataSubCode.UsbDescriptorStringSerialNumber, + cancellationToken: default, + constructCommand: RetrieveFlashStringCommand.ConstructCommand, + parseResponse: RetrieveFlashStringCommand.ParseResponse + ).ConfigureAwait(false); + ChipFactorySerialNumber = await CommandAsync( userData: default, - arg: 0, + arg: ReadFlashDataSubCode.ChipFactorySerialNumber, cancellationToken: default, - constructCommand: RetrieveChipFactorySerialNumberCommand.ConstructCommand, - parseResponse: RetrieveChipFactorySerialNumberCommand.ParseResponse + constructCommand: RetrieveFlashStringCommand.ConstructCommand, + parseResponse: RetrieveFlashStringCommand.ParseResponse ).ConfigureAwait(false); } @@ -263,12 +319,36 @@ Action validateFirmwareRevision validateHardwareRevision?.Invoke(HardwareRevision); validateFirmwareRevision?.Invoke(FirmwareRevision); + ManufacturerDescriptor = Command( + userData: default, + arg: ReadFlashDataSubCode.UsbDescriptorStringManufacturer, + cancellationToken: default, + constructCommand: RetrieveFlashStringCommand.ConstructCommand, + parseResponse: RetrieveFlashStringCommand.ParseResponse + ); + + ProductDescriptor = Command( + userData: default, + arg: ReadFlashDataSubCode.UsbDescriptorStringProduct, + cancellationToken: default, + constructCommand: RetrieveFlashStringCommand.ConstructCommand, + parseResponse: RetrieveFlashStringCommand.ParseResponse + ); + + SerialNumberDescriptor = Command( + userData: default, + arg: ReadFlashDataSubCode.UsbDescriptorStringSerialNumber, + cancellationToken: default, + constructCommand: RetrieveFlashStringCommand.ConstructCommand, + parseResponse: RetrieveFlashStringCommand.ParseResponse + ); + ChipFactorySerialNumber = Command( userData: default, - arg: 0, + arg: ReadFlashDataSubCode.ChipFactorySerialNumber, cancellationToken: default, - constructCommand: RetrieveChipFactorySerialNumberCommand.ConstructCommand, - parseResponse: RetrieveChipFactorySerialNumberCommand.ParseResponse + constructCommand: RetrieveFlashStringCommand.ConstructCommand, + parseResponse: RetrieveFlashStringCommand.ParseResponse ); } } diff --git a/src/Smdn.Devices.MCP2221/Smdn.Devices.MCP2221/MCP2221.cs b/src/Smdn.Devices.MCP2221/Smdn.Devices.MCP2221/MCP2221.cs index 88639d3..d199803 100644 --- a/src/Smdn.Devices.MCP2221/Smdn.Devices.MCP2221/MCP2221.cs +++ b/src/Smdn.Devices.MCP2221/Smdn.Devices.MCP2221/MCP2221.cs @@ -199,6 +199,9 @@ public static MCP2221 Open(Func createHidDevice, IServiceProvider public string HardwareRevision { get; private set; } = null; public string FirmwareRevision { get; private set; } = null; + public string ManufacturerDescriptor { get; private set; } = null; + public string ProductDescriptor { get; private set; } = null; + public string SerialNumberDescriptor { get; private set; } = null; public string ChipFactorySerialNumber { get; private set; } = null; private MCP2221(IUsbHidDevice hidDevice, IUsbHidStream hidStream, IServiceProvider? serviceProvider)