使用 C# UsbDevice 类时未从 USBTMC 设备获取响应

问题描述 投票:0回答:1

周五我第一次开始尝试设置USB接口。我正在尝试使用 Winusb.sysWindows.Devices.Usb 命名空间在 C# 中编写通用 USB 通信类。我通常会关注 Microsoft 关于该主题的教程

我的目标是编写一个与 USBTMC 设备通信的通用 USB 通信接口。我希望创建类似 C# 的 SerialPort 类,但针对 USB 设备。我知道 NI-VISA。我用过。坦白说,我讨厌它。它需要大量的软件依赖性。我的目标是创建一个便携式解决方案,而不需要在计算机上安装千兆字节的 NI 驱动程序和软件。

到目前为止,我已经创建并安装了自定义 INF,以将 USBTMC 设备与 WinUsb 相关联。我制作了一个简单的 Windows 窗体应用程序来枚举、显示和连接到与 USBTMC 类标识符匹配的 USB 设备。我还可以读取设备描述符。我复制了应该写入和读取的代码。我编写了一个批量传输类来处理创建批量传输标头并生成对齐字节。我还下载了一个名为 Usblyzer 的随机 USB 分析器/嗅探器。

我正在尝试发送一个简单的 SCPI“*IDN?”要求。附上what the usb sniffer sees。在我看来,一切都是对的,然而,当我尝试回读时,我却从未得到任何回应。据我所知,我已经生成了格式正确的 Bulk-Out USBTMC 传输。我已通读 USBTMC 规范和 USB488 子类规范的部分内容。我还没有完整地读过这两本书,所以如果我错过了其中一些简单的内容,我深表歉意。

下面是控制USB交互的两段代码。 UsbComm 旨在成为通用通信接口。 BulkOutMessage 是一个帮助器类,可以更轻松地创建批量传输标头。

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Devices.Enumeration;
using Windows.Devices.Usb;
using Windows.Storage.Streams;

namespace USB_Testing
{
    public class UsbComm : IDisposable
    {
        private UsbDevice usbDevice;
        private DataWriter writer;
        private DataReader reader;
        /// <summary>
        /// Used to track the number of bulk transfers initiated which in turn is used to generate the bTag for subsequent bulk transfers. 
        /// This must be incremented for each transfer to comply with USB protocols.
        /// </summary>
        private byte messageCounter = 0;

        public static async Task<UsbComm> CreateAsync(DeviceInformation deviceInformation)
        {
            return await CreateAsync(deviceInformation.Id);
        }

        public static async Task<UsbComm> CreateAsync(string deviceId)
        {
            var newClass = new UsbComm();
            return await newClass.InitializeAsync(deviceId);
        }

        private async Task<UsbComm> InitializeAsync(string deviceId)
        {
            this.usbDevice = await UsbDevice.FromIdAsync(deviceId);
            this.writer = InitializeWriter();
            this.reader = InitializeReader();
            return this;
        }

        private DataWriter InitializeWriter()
        {
            UsbBulkOutPipe writePipe = usbDevice.DefaultInterface.BulkOutPipes[0];
            writePipe.WriteOptions |= UsbWriteOptions.ShortPacketTerminate | UsbWriteOptions.AutoClearStall;
            return new DataWriter(writePipe.OutputStream);
        }

        private DataReader InitializeReader()
        {
            UsbBulkInPipe readPipe = usbDevice.DefaultInterface.BulkInPipes[0];
            readPipe.ReadOptions |= UsbReadOptions.IgnoreShortPacket | UsbReadOptions.AutoClearStall;
            return new DataReader(readPipe.InputStream);
        }

        private UsbComm()
        {
            
        }


        public static async Task<DeviceInformationCollection> EnumerateDevices(UInt32 vid = 0x00, UInt32 pid = 0x00)
        {
            // VID and PID can be found by opening Device Manage > Right click device of interest > Properties > Details > Select Hardware Ids from the Property dropdown > Copy the values
            // VID and PID should not be used unless we wish to enumerate only specific devices from specific manufacturers. Otherwise, we should enumerate all in the test and measurement class devices.
            // A selector can be made from the VID and PID alone
            //UsbDevice.GetDeviceSelector(vid, pid);
            string selector = "";
            if (vid != 0x00 || pid != 0x00)
            {
                // If the caller specified and VID and/or PID we should enumerate using this.
                selector = UsbDevice.GetDeviceSelector(vid, pid);
            }
            else
            {
                // Otherwise, we should enumerate all USBTMC devices and let the caller filter the result as they see fit.
                selector = UsbDevice.GetDeviceClassSelector(UsbDeviceClasses.Measurement);
            }
            // We !MUST! use the selector to search for USB devices. If the selector created from VID / PID or Device Class does not return the device of interest, then it is not configured properly.
            // If we search for our device with a more broad selector, we may find the device, but when we try to connect to it "UsbDevice.FromIdAsync" will return null.
            return await DeviceInformation.FindAllAsync(selector);
        }

        public async Task<uint> SendMessage(string message)
        {
            return await sendMessage(new BulkOutMessage(message, this.messageCounter, false));
        }

        private async Task<uint> sendMessage(BulkOutMessage bulkOutMessage)
        {
            this.messageCounter++;
            writer.WriteBytes(bulkOutMessage.ToBytes());
            return await writer.StoreAsync();
        }

        public async Task<string> ReadMessage()
        {
            await reader.LoadAsync(512);
            IBuffer buffer = reader.ReadBuffer(reader.UnconsumedBufferLength);
            return buffer.ToString();
        }

        public void Dispose()
        {
            if (this.usbDevice != null)
            {
                this.usbDevice.Dispose();
            }
        }

        #region GetDescriptorStrings
        public string GetDeviceDescriptorAsString()
        {
            string content = null;

            var deviceDescriptor = this.usbDevice.DeviceDescriptor;

            content = "Device Descriptor\n"
                    + "\nUsb Spec Number : 0x" + deviceDescriptor.BcdUsb.ToString("X4", NumberFormatInfo.InvariantInfo)
                    + "\nMax Packet Size (Endpoint 0) : " + deviceDescriptor.MaxPacketSize0.ToString("D", NumberFormatInfo.InvariantInfo)
                    + "\nVendor ID : 0x" + deviceDescriptor.VendorId.ToString("X4", NumberFormatInfo.InvariantInfo)
                    + "\nProduct ID : 0x" + deviceDescriptor.ProductId.ToString("X4", NumberFormatInfo.InvariantInfo)
                    + "\nDevice Revision : 0x" + deviceDescriptor.BcdDeviceRevision.ToString("X4", NumberFormatInfo.InvariantInfo)
                    + "\nNumber of Configurations : " + deviceDescriptor.NumberOfConfigurations.ToString("D", NumberFormatInfo.InvariantInfo);

            return content;
        }

        public string GetConfigurationDescriptorAsString()
        {
            string content = null;

            var usbConfiguration = this.usbDevice.Configuration;
            var configurationDescriptor = usbConfiguration.ConfigurationDescriptor;

            content = "Configuration Descriptor\n"
                    + "\nNumber of Interfaces : " + usbConfiguration.UsbInterfaces.Count.ToString("D", NumberFormatInfo.InvariantInfo)
                    + "\nConfiguration Value : 0x" + configurationDescriptor.ConfigurationValue.ToString("X2", NumberFormatInfo.InvariantInfo)
                    + "\nSelf Powered : " + configurationDescriptor.SelfPowered.ToString()
                    + "\nRemote Wakeup : " + configurationDescriptor.RemoteWakeup.ToString()
                    + "\nMax Power (milliAmps) : " + configurationDescriptor.MaxPowerMilliamps.ToString("D", NumberFormatInfo.InvariantInfo);

            return content;
        }

        public string GetInterfaceDescriptorsAsString()
        {
            string content = null;

            var interfaces = this.usbDevice.Configuration.UsbInterfaces;

            content = "Interface Descriptors";

            foreach (UsbInterface usbInterface in interfaces)
            {
                // Class/subclass/protocol values from the first interface setting.

                UsbInterfaceDescriptor usbInterfaceDescriptor = usbInterface.InterfaceSettings[0].InterfaceDescriptor;

                content += "\n\nInterface Number: 0x" + usbInterface.InterfaceNumber.ToString("X2", NumberFormatInfo.InvariantInfo)
                        + "\nClass Code: 0x" + usbInterfaceDescriptor.ClassCode.ToString("X2", NumberFormatInfo.InvariantInfo)
                        + "\nSubclass Code: 0x" + usbInterfaceDescriptor.SubclassCode.ToString("X2", NumberFormatInfo.InvariantInfo)
                        + "\nProtocol Code: 0x" + usbInterfaceDescriptor.ProtocolCode.ToString("X2", NumberFormatInfo.InvariantInfo)
                        + "\nNumber of Interface Settings: " + usbInterface.InterfaceSettings.Count.ToString("D", NumberFormatInfo.InvariantInfo)
                        + "\nNumber of open Bulk In pipes: " + usbInterface.BulkInPipes.Count.ToString("D", NumberFormatInfo.InvariantInfo)
                        + "\nNumber of open Bulk Out pipes: " + usbInterface.BulkOutPipes.Count.ToString("D", NumberFormatInfo.InvariantInfo)
                        + "\nNumber of open Interrupt In pipes: " + usbInterface.InterruptInPipes.Count.ToString("D", NumberFormatInfo.InvariantInfo)
                        + "\nNumber of open Interrupt Out pipes: " + usbInterface.InterruptOutPipes.Count.ToString("D", NumberFormatInfo.InvariantInfo);
            }

            return content;
        }

        public string GetEndpointDescriptorsAsString()
        {
            string content = null;

            var usbInterface = this.usbDevice.DefaultInterface;
            var bulkInPipes = usbInterface.BulkInPipes;
            var bulkOutPipes = usbInterface.BulkOutPipes;
            var interruptInPipes = usbInterface.InterruptInPipes;
            var interruptOutPipes = usbInterface.InterruptOutPipes;

            content = "Endpoint Descriptors for open pipes";

            // Print Bulk In Endpoint descriptors
            foreach (UsbBulkInPipe bulkInPipe in bulkInPipes)
            {
                var endpointDescriptor = bulkInPipe.EndpointDescriptor;

                content += "\n\nBulk In Endpoint Descriptor"
                        + "\nEndpoint Number : 0x" + endpointDescriptor.EndpointNumber.ToString("X2", NumberFormatInfo.InvariantInfo)
                        + "\nMax Packet Size : " + endpointDescriptor.MaxPacketSize.ToString("D", NumberFormatInfo.InvariantInfo);
            }

            // Print Bulk Out Endpoint descriptors
            foreach (UsbBulkOutPipe bulkOutPipe in bulkOutPipes)
            {
                var endpointDescriptor = bulkOutPipe.EndpointDescriptor;

                content += "\n\nBulk Out Endpoint Descriptor"
                        + "\nEndpoint Number : 0x" + endpointDescriptor.EndpointNumber.ToString("X2", NumberFormatInfo.InvariantInfo)
                        + "\nMax Packet Size : " + endpointDescriptor.MaxPacketSize.ToString("D", NumberFormatInfo.InvariantInfo);
            }

            // Print Interrupt In Endpoint descriptors
            foreach (UsbInterruptInPipe interruptInPipe in interruptInPipes)
            {
                var endpointDescriptor = interruptInPipe.EndpointDescriptor;

                content += "\n\nInterrupt In Endpoint Descriptor"
                        + "\nEndpoint Number : 0x" + endpointDescriptor.EndpointNumber.ToString("X2", NumberFormatInfo.InvariantInfo)
                        + "\nMax Packet Size : " + endpointDescriptor.MaxPacketSize.ToString("D", NumberFormatInfo.InvariantInfo)
                        + "\nInterval : " + endpointDescriptor.Interval.Duration().ToString();
            }

            // Print Interrupt Out Endpoint descriptors
            foreach (UsbInterruptOutPipe interruptOutPipe in interruptOutPipes)
            {
                var endpointDescriptor = interruptOutPipe.EndpointDescriptor;

                content += "\n\nInterrupt Out Endpoint Descriptor"
                        + "\nEndpoint Number : 0x" + endpointDescriptor.EndpointNumber.ToString("X2", NumberFormatInfo.InvariantInfo)
                        + "\nMax Packet Size : " + endpointDescriptor.MaxPacketSize.ToString("D", NumberFormatInfo.InvariantInfo)
                        + "\nInterval : " + endpointDescriptor.Interval.Duration().ToString();
            }

            return content;
        }

        public string GetCustomDescriptorsAsString()
        {
            string content = null;
            // Descriptor information will be appended to this string and then printed to UI
            content = "Raw Descriptors";

            var configuration = this.usbDevice.Configuration;
            var allRawDescriptors = configuration.Descriptors;

            // Print first 2 bytes of all descriptors within the configuration descriptor    
            // because the first 2 bytes are always length and descriptor type
            // the UsbDescriptor's DescriptorType and Length properties, but we will not use these properties
            // in order to demonstrate ReadDescriptorBuffer() and how to parse it.

            foreach (UsbDescriptor descriptor in allRawDescriptors)
            {
                var descriptorBuffer = new Windows.Storage.Streams.Buffer(descriptor.Length);
                descriptor.ReadDescriptorBuffer(descriptorBuffer);

                DataReader reader = DataReader.FromBuffer(descriptorBuffer);

                // USB data is Little Endian according to the USB spec.
                reader.ByteOrder = ByteOrder.LittleEndian;

                // ReadByte has a side effect where it consumes the current byte, so the next ReadByte will read the next character.
                // Putting multiple ReadByte() on the same line (same variable assignment) may cause the bytes to be read out of order.
                var length = reader.ReadByte().ToString("D", NumberFormatInfo.InvariantInfo);
                var type = "0x" + reader.ReadByte().ToString("X2", NumberFormatInfo.InvariantInfo);

                content += "\n\nDescriptor"
                        + "\nLength : " + length
                        + "\nDescriptorType : " + type;
            }

            return content;
        }
        #endregion GetDescriptorStrings
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace USB_Testing
{
    public class BulkOutMessage
    {
        private byte MsgId;
        private byte bTag;
        private byte bTagInverse;
        private UInt32 TransferSize;
        /// <summary>
        /// Digit 7 through Digit 2 Reserved. All bits must be 0.
        /// 
        /// D1 =
        ///   1 – All of the following are true:
        ///     • The USBTMC interface supports TermChar
        ///     • The bmTransferAttributes. TermCharEnabled bit was set in the REQUEST_DEV_DEP_MSG_IN.
        ///     • The last USBTMC message data byte in this transfer matches the TermChar in the REQUEST_DEV_DEP_MSG_IN.
        ///   0 – One or more of the above conditions is not met.
        /// D0 EOM (End Of Message)
        ///   1 - The last USBTMC message data byte in the transfer is the last byte of the USBTMC message.
        ///   0 – The last USBTMC message data byte in the transfer is not the last byte of the USBTMC message.
        /// </summary>
        private byte bmTransferAttributes;
        private string Message;

        public BulkOutMessage(string messageData, byte bTagValue, bool isLastMessageInTransfer)
        {
            this.Message = messageData;
            this.MsgId = 2;
            this.bTag = bTagValue;
            // Take the ones complement using '~'
            this.bTagInverse = (byte)~this.bTag;
            this.TransferSize = (uint)messageData.Length;
            /// D1 =
            ///   1 – All of the following are true:
            ///     • The USBTMC interface supports TermChar
            ///     • The bmTransferAttributes. TermCharEnabled bit was set in the REQUEST_DEV_DEP_MSG_IN.
            ///     • The last USBTMC message data byte in this transfer matches the TermChar in the REQUEST_DEV_DEP_MSG_IN.
            ///   0 – One or more of the above conditions is not met.
            byte TermCharSetBit = (byte)0x00;
            /// D0 EOM (End Of Message)
            ///   1 - The last USBTMC message data byte in the transfer is the last byte of the USBTMC message.
            ///   0 – The last USBTMC message data byte in the transfer is not the last byte of the USBTMC message.
            byte EomBit = isLastMessageInTransfer ? (byte)0x01 : (byte)0x01;
            //                   Top 6 bits are 0 - bit 1 is TermCharSetBit - bit 0 is EomBit
            this.bmTransferAttributes = (byte)(0x00 | (TermCharSetBit << 1) | EomBit);
        }

        public byte[] ToBytes()
        {
            List<byte> data = new List<byte>()
            {
                MsgId,
                bTag,
                bTagInverse,
                0x00, // Reserved
                ((byte)(TransferSize >> 0)),
                ((byte)(TransferSize >> 8)),
                ((byte)(TransferSize >> 16)),
                ((byte)(TransferSize >> 24)),
                bmTransferAttributes,
                0x00, // Reserved
                0x00, // Reserved
                0x00, // Reserved
            };
            // Add all data to transfer
            data.AddRange(Message.Select(x => (byte)x));
            data.AddRange(Enumerable.Repeat(0x00, 4 - data.Count % 4).Select(x => (byte)x));
            return data.ToArray();
        }
    }
}
c# windows uwp usb protocols
1个回答
0
投票

我没有时间分析你的代码,但你可以尝试使用我创建的ScpiNet库

© www.soinside.com 2019 - 2024. All rights reserved.