C# - Communicate with WinUSB device with LIBUSB - c#

I am trying to communicate with a Nokia Lumia phone(RM-917), over USB using LIBUSING and C#. LIBUSB is able to see the device's information(pid,vid,etc). However, I am not able to successfully write to ANY endpoint, even sending the exact command as the Windows Device Recovery Tool.
According to WinUSB, the write endpoint is EP07, however, this endpoint just times out. I have tried every other endpoint, and all of these fail.
`
public void initDevice()
{
if(this.lumiaDevice == null)
{
throw new Exception("LumiaPhoneManager does not have a selected device");
}
UsbDeviceFinder MyUsbFinder = new UsbDeviceFinder(0x0421, 0x0661);
MyUsbDevice = UsbDevice.OpenUsbDevice(MyUsbFinder);
IUsbDevice wholeUsbDevice = MyUsbDevice as IUsbDevice;
if (!ReferenceEquals(wholeUsbDevice, null))
{
// This is a "whole" USB device. Before it can be used,
// the desired configuration and interface must be selected.
// Select config #1
wholeUsbDevice.SetConfiguration(1);
// Claim interface #0.
wholeUsbDevice.ClaimInterface(1);
}
if (this.writer == null)
{
writer = MyUsbDevice.OpenEndpointWriter(WriteEndpointID.Ep07);
}
}
public void readPCode()
{
currentID++;
var _x = new jsonPkt();
ErrorCode ec = ErrorCode.None;
int bytesWritten;
_x.id = this.currentID + 1;
_x.method = "ReadProductCode";
string value = #"{""jsonrpc"":""<JSONRPC>"",""id"":<ID>,""method"":""<METHOD>"",""params"":null}";
value = value.Replace("<JSONRPC>", "2.0");
value = value.Replace("<ID>", currentID.ToString());
value = value.Replace("<METHOD>", _x.method.ToString());
ec = writer.Write(Encoding.Default.GetBytes(value), 8000, out bytesWritten);
currentID++;
if (ec != ErrorCode.None) throw new Exception(UsbDevice.LastErrorString);
byte[] readBuffer = new byte[1024];
while (ec == ErrorCode.None)
{
int bytesRead;
// If the device hasn't sent data in the last 100 milliseconds,
// a timeout error (ec = IoTimedOut) will occur.
ec = reader.Read(readBuffer, 100, out bytesRead);
// if (bytesRead == 0) throw new Exception("No more bytes!");
// Write that output to the console.
this.rtb.Text += Encoding.Default.GetString(readBuffer, 0, bytesRead).ToString() + "\n";
}
}

Found the solution
Debugged the OEM software and found the program was using a different path to the USB device. After that I was getting access denied errors, which was solved by moving the project to a different drive. For reasons unknown, when the program runs on c drive, the CreateFile function fails with access denied

Its possible that to activate write, you need to send some class specific control request first. You mentioned that windows device recovery tool is able to write.
You can install USB packet sniffer software in your windows PC and then use the device manager to write some data to the device. Packet sniffer tool will be able to capture all the packets sent to the device.
This way you can see the exact device requests which are required to enable write operation.
Analyzer software - http://www.usblyzer.com/
Please try this way to resolve your problem.
PS- I am assuming you do not have a hardware USB packet analyzer like Lecroy advisor or Beagle. Software packet sniffer should be fine since the host is a PC.

Related

Get data from USB device descriptor

In my project (C#, WPF application) I have device that appears as VCP. I need connect to it. I am detecting serial port using WMI and filter by VID and PID. It makes job done in 90%. Device manufacturer uses same VID/PID pair for all devices. Accurate model is in USB descriptor (Device Decsriptor part, property iProduct). I can't find this anywhere exploring WMI.
How can I get to USB decriptor with .NET? In C# read USB Descriptor answers suggest to use WMI. In WMI device description is not USB descriptor. I don't need to list connected USB devices but to read specific data from USB device descriptor.
Very helpful article https://lihashgnis.blogspot.com/2018/07/getting-descriptors-from-usb-device.html
I have just added some code to get String Descriptor:
USB_STRING_DESCRIPTOR* stringDescriptor = nullptr;
int sBufferSize = sizeof(USB_DESCRIPTOR_REQUEST) + MAXIMUM_USB_STRING_LENGTH;
BYTE *sBuffer = new BYTE[sBufferSize];
memset(sBuffer, 0, sBufferSize);
requestPacket = (USB_DESCRIPTOR_REQUEST*)sBuffer;
stringDescriptor = (USB_STRING_DESCRIPTOR*)((BYTE*)sBuffer + sizeof(USB_DESCRIPTOR_REQUEST));
requestPacket->SetupPacket.bmRequest = 0x80;
requestPacket->SetupPacket.bRequest = USB_REQUEST_GET_DESCRIPTOR;
requestPacket->ConnectionIndex = usbPortNumber;
requestPacket->SetupPacket.wValue = (USB_STRING_DESCRIPTOR_TYPE << 8); // String Descriptior 0
requestPacket->SetupPacket.wLength = MAXIMUM_USB_STRING_LENGTH;
err = DeviceIoControl(hUsbHub, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, sBuffer, sBufferSize, sBuffer, sBufferSize, &bytesReturned, nullptr);
// Now get iProduct string in language at zero index
requestPacket->SetupPacket.wValue = (USB_STRING_DESCRIPTOR_TYPE << 8) | deviceDescriptor->iProduct;
requestPacket->SetupPacket.wIndex = (USHORT)stringDescriptor->bString[0];
err = DeviceIoControl(hUsbHub, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, sBuffer, sBufferSize, sBuffer, sBufferSize, &bytesReturned, nullptr);
std::wcout << stringDescriptor->bString

Send audio output to two devices with AudioGraph in an UWP app

I try to send the input from a microphone to the speaker and a connected headset simultaneously.
I know how to do this with a file and a device but I don't know how to connect the second device with an output node and attach it to the graph.
I can create nodes with CreateDeviceOutputNodeAsync but I have no clue hwo to associate the device with the node.
For one device it works when I give the device as the PrimaryRenderDevice in the settings when the graph is created.
This is the working code for one output device. I don't know how fix this to make it work for two output devices.
private async Task CreateAudioGraph()
{
AudioGraphSettings settings = new AudioGraphSettings(AudioRenderCategory.Speech);
settings.QuantumSizeSelectionMode = QuantumSizeSelectionMode.LowestLatency;
settings.DesiredRenderDeviceAudioProcessing = Windows.Media.AudioProcessing.Raw; // this is also set automatically when LowestLatency is set
settings.PrimaryRenderDevice = OutputDeviceForInput;
CreateAudioGraphResult result = await AudioGraph.CreateAsync(settings);
if (result.Status != AudioGraphCreationStatus.Success)
{
// Cannot create graph
ConnectionStatus = String.Format("AudioGraph Creation Error because {0}", result.Status.ToString());
return;
}
graphForInputDeviceNo1 = result.Graph;
ConnectionStatus = "Graph successfully created!";
// Create a device input node using the selectedt input device
CreateAudioDeviceInputNodeResult deviceInputNodeResult = await graphForInputDeviceNo1.CreateDeviceInputNodeAsync(MediaCategory.Speech, graphForInputDeviceNo1.EncodingProperties, FirstInputDevice);
if (deviceInputNodeResult.Status != AudioDeviceNodeCreationStatus.Success)
{
// Cannot create device input node
ConnectionStatus = String.Format("Audio Device Input unavailable because {0}", deviceInputNodeResult.Status.ToString());
return;
}
deviceInputNode = deviceInputNodeResult.DeviceInputNode;
// Create the first device output node
CreateAudioDeviceOutputNodeResult deviceOutputNodeNo1Result = await graphForInputDeviceNo1.CreateDeviceOutputNodeAsync();
if (deviceOutputNodeNo1Result.Status != AudioDeviceNodeCreationStatus.Success)
{
// Cannot create device output node
ConnectionStatus = String.Format("Audio Device Output unavailable because {0}", deviceOutputNodeNo1Result.Status.ToString());
return;
}
deviceOutputNodeNo1 = deviceOutputNodeNo1Result.DeviceOutputNode;
// Create the second device output node
CreateAudioDeviceOutputNodeResult deviceOutputNodeNo2Result = await graphForInputDeviceNo1.CreateDeviceOutputNodeAsync();
if (deviceOutputNodeNo2Result.Status != AudioDeviceNodeCreationStatus.Success)
{
// Cannot create device output node
ConnectionStatus = String.Format("Audio Device Output unavailable because {0}", deviceOutputNodeNo2Result.Status.ToString());
return;
}
deviceOutputNodeNo2 = deviceOutputNodeNo2Result.DeviceOutputNode;
ConnectionStatus = "Device Output connection successfully created";
deviceInputNode.AddOutgoingConnection(deviceOutputNodeNo1);
ConnectionStatus = "Device Input connection successfully created";
deviceInputNode.AddOutgoingConnection(deviceOutputNodeNo2);
// Because we are using lowest latency setting, we need to handle device disconnection errors
graphForInputDeviceNo1.UnrecoverableErrorOccurred += Graph_UnrecoverableErrorOccurred;
graphForInputDeviceNo1.Start(); // erst damit geht es los
}
The MSDN document is a bit confusing:
Creates a new AudioDeviceOutputNode that outputs audio data from the audio graph to the system's default output device, such as speakers or headphones.
In fact, the output device is not necessary the system's default output device. However, since you are not able to change the Device property of the node, and the constructor does not give you that option, it seems it must be from the system settings.
However, there are another place we can set this up: the AudioGraphSettings class allows you to set the PrimaryRenderDevice property, and this is actually the device will be used when creating the output node.
You can try the following:
var settings = new AudioGraphSettings(AudioRenderCategory.Other);
settings.PrimaryRenderDevice = device_other_than_system_output;
var ag_result = await AudioGraph.CreateAsync(settings);
var ag = ag_result.Graph;
var result = await ag.CreateDeviceOutputNodeAsync();
assert(result.DeviceOutputNode == device_other_than_system_output);
Technically, this didn't solve your problem since a AudioGraph is still not able to have two output nodes. However, you can try to create multiple AudioGraphs that consumes the same input(s), and output to different render devices, to have the same effect as you wish.

UWP/C# - Issue with AQS and USB Devices

I have an issue with a UWP app that I am trying to write. I am connecting to a custom embedded USB Bulk device that I have programmed (it is actually an out of the box example from Cypress Semiconductor). I am using the WinUSB.sys driver using the embedded MS OS string in the device to allow the device to be used with out having to write a custom INF file to call the WinUSB.sys driver.
In my code, I am using the UsbDevice.GetDeviceSelector method to return an AQS that can then be passed into DeviceInformation.FindAllAsync to begin communicating with the device in my app. I have confirmed that the device shows up in the device manager without any issues, and I have checked in the registry to ensure that it has an Interface GUID. I have a screenshot from USBViewer to show the configuration of the device. This method for finding and connecting with USB devices is from this MSDN example found here.
When I use the UsbDevice.GetDeviceSelector method, it returns a GUID that is not associated with this device. The GUID that it returns is actually associated with Lumia Phones (DEE824EF-729B-4A0E-9C14-B7117D33A817). Because of this, it does not find my device connected to the system.
To troubleshoot, I have both called the DeviceInformation.FindAllAsync with out any arguments to see if my device is listed, and it does find the device (amongst over 1000 other devices that have been connected ever to my machine). I then wrote a custom AQS string without the help of the GetDeviceSelector method, starting with just the GUID. Doing this returned 27 devices, but when I tried to add the VID and PID to this AQS string, nothing returned.
I have also made sure that the device that I want to use is listed in the app manifest by its appropriate VID and PID as this is required for a device with a Custom Class of 0xFF. I have used the Custom USB UWP device example and it can find the device, though it uses a completely different method with a device picker, which I will go to if needed, but this is not my desire as it makes that part of the app not as clean of a solution.
I have posted this question over in the MSDN forums here with more information, but I have not gotten a lot of engagement there. Any help would be appreciated. I know that I must be missing something simple.
Adam
private async void button_Click(object sender, RoutedEventArgs e)
{
//UInt32 vid = 0x04B4;
//UInt32 pid = 0x00F0;
UInt32 vid = uint.Parse(textBox1.Text, System.Globalization.NumberStyles.HexNumber);
UInt32 pid = UInt32.Parse(textBox2.Text, System.Globalization.NumberStyles.HexNumber);
Guid winusbInterfaceGuid = new Guid("a5dcbf10-6530-11d2-901f-00c04fb951ed");
//string aqs = UsbDevice.GetDeviceSelector(vid, pid);
string aqs = UsbDevice.GetDeviceSelector(winusbInterfaceGuid);
var myDevices = await DeviceInformation.FindAllAsync(aqs, null);
//var myDevices = await DeviceInformation.FindAllAsync();
var myDevicesCount = myDevices.Count;
if (myDevicesCount >= 1)
{
textBlock2.Text = "Device Found";
} else
{
textBlock2.Text = "Searching";
await Task.Delay(1000);
textBlock2.Text = "looking for device";
}
}
just dropped you a mail asking about progress (I think, had to guess your mail address), but now it seems I found a solution myself. Please see my answer on UWP app cannot find/connect to USB device
In short, you have to create an inf for installing the winusb driver. I have no clue why, but that did the trick for me (and someone else, see Cannot create UsbDevice from DeviceInformation.Id)
The Guid DEE824EF-729B-4A0E-9C14-B7117D33A817 is actually the standard WinUSB Guid. I don't think it has anything to do with Lumia Phones. I don't know why it is not documented anywhere. I think that the Guid a5dcbf10-6530-11d2-901f-00c04fb951ed you specified is actually a red herring. I mistakenly used that as well, but it just led me down the garden path. It shows up USB interfaces, but I can't connect to them.
You might want to try this class https://github.com/MelbourneDeveloper/Device.Net/blob/master/src/Usb.Net.UWP/UWPUsbDevice.cs .
Here is how it gets the device:
public async Task<IEnumerable<DeviceDefinition>> GetConnectedDeviceDefinitions(uint? vendorId, uint? productId)
{
var aqsFilter = "System.Devices.InterfaceClassGuid:=\"{DEE824EF-729B-4A0E-9C14-B7117D33A817}\" AND System.Devices.InterfaceEnabled:=System.StructuredQueryType.Boolean#True AND " + $" System.DeviceInterface.WinUsb.UsbVendorId:={vendorId.Value} AND System.DeviceInterface.WinUsb.UsbProductId:={productId.Value}";
var deviceInformationCollection = await wde.DeviceInformation.FindAllAsync(aqsFilter).AsTask();
//TODO: return the vid/pid if we can get it from the properties. Also read/write buffer size
var deviceIds = deviceInformationCollection.Select(d => new DeviceDefinition { DeviceId = d.Id, DeviceType = DeviceType.Usb }).ToList();
return deviceIds;
}
This sample connects to a device and I think you'll be able to connect to the device in the same way:
private static async Task InitializeTrezor()
{
//Register the factory for creating Usb devices. This only needs to be done once.
UWPUsbDeviceFactory.Register();
//Register the factory for creating Usb devices. This only needs to be done once.
UWPHidDeviceFactory.Register();
//Note: other custom device types could be added here
//Define the types of devices to search for. This particular device can be connected to via USB, or Hid
var deviceDefinitions = new List<DeviceDefinition>
{
new DeviceDefinition{ DeviceType= DeviceType.Hid, VendorId= 0x534C, ProductId=0x0001, Label="Trezor One Firmware 1.6.x" },
new DeviceDefinition{ DeviceType= DeviceType.Usb, VendorId= 0x1209, ProductId=0x53C1, ReadBufferSize=64, WriteBufferSize=64, Label="Trezor One Firmware 1.7.x" },
new DeviceDefinition{ DeviceType= DeviceType.Usb, VendorId= 0x1209, ProductId=0x53C0, ReadBufferSize=64, WriteBufferSize=64, Label="Model T" }
};
//Get the first available device and connect to it
var devices = await DeviceManager.Current.GetDevices(deviceDefinitions);
var trezorDevice = devices.FirstOrDefault();
await trezorDevice.InitializeAsync();
//Create a buffer with 3 bytes (initialize)
var buffer = new byte[64];
buffer[0] = 0x3f;
buffer[1] = 0x23;
buffer[2] = 0x23;
//Write the data to the device
await trezorDevice.WriteAsync(buffer);
//Read the response
var readBuffer = await trezorDevice.ReadAsync();
}
If you connect to the device in this way, you'll get Windows classic, and Android support for free with Device.Net (https://github.com/MelbourneDeveloper/Device.Net)
With Device.net's DeviceManager.Current.GetDevices(deviceDefinitions) using .NET 5 I can't find any device connected to my win10, which can be easily selected by ManagementObjectSearcher:
public List<ManagementBaseObject> GetLogicalDevices()
{
List<ManagementBaseObject> devices = new List<ManagementBaseObject>();
ManagementObjectCollection collection;
ManagementObjectSearcher seacher = new ManagementObjectSearcher("root\\CIMV2", "SELECT * FROM CIM_LogicalDevice");
collection = seacher.Get();
foreach (var device in collection)
{
devices.Add(device);
}
return devices;
}

Error 10049 while connecting bluetooth device with 32feet

I'm trying to establish a connection with a custom bluetooth device without using COM ports. However, I'm getting an error: [10049] "The requested address is not valid in its context". What am I doing wrong?
static Guid serviceClass= new Guid("4d36e978-e325-11ce-bfc1-08002be10318"); //GUID of device class
static BluetoothAddress addr = BluetoothAddress.Parse("001210160177"); //from device
BluetoothDeviceInfo device = new BluetoothDeviceInfo(addr);
device.SetServiceState(serviceClass, true);
Console.WriteLine(BluetoothSecurity.PairRequest(device.DeviceAddress, "0000")); //pairing my device - writes True
BluetoothEndPoint ep = new BluetoothEndPoint(addr, serviceClass);
BluetoothClient conn = new BluetoothClient(ep); //10049 error
conn.Connect(ep);
Console.WriteLine(conn.GetStream());
Its all covered in the project's documentation. :-)
In short, remove that SetServiceState line it is unnecessary/bad. Doing the pairing each time is also unnecessary and a bit slow but probably not worth changing if its working well.
Docs:
1) http://32feet.codeplex.com/documentation
"See section General Bluetooth Data Connections below. The BluetoothClient provides the Stream to read and write on -- there is no need to use virtual COM ports"
2) http://32feet.codeplex.com/wikipage?title=General%20Bluetooth%20Data%20Connections
BluetoothAddress addr
= BluetoothAddress.Parse("001122334455");
Guid serviceClass;
serviceClass = BluetoothService.SerialPort;
// - or - etc
// serviceClass = MyConsts.MyServiceUuid
//
var ep = new BluetoothEndPoint(addr, serviceClass);
var cli = new BluetoothClient();
cli.Connect(ep);
Stream peerStream = cli.GetStream();
peerStream.Write/Read ...
3) http://32feet.codeplex.com/wikipage?title=Errors
10049 "The requested address is not valid in its context."
No Service with given Service Class Id is running on the remote device
i.e. Wrong Service Class Id.
Here's how it finally rolls.
device.SetServiceState(serviceClass, true); //do it before pairing
...
BluetoothClient conn = new BluetoothClient();
conn.Connect(ep);
Also, my mistake here:
static Guid serviceClass = new Guid("4d36e978-e325-11ce-bfc1-08002be10318");
//GUID of device class
Should be:
static Guid serviceClass = new Guid("00001101-0000-1000-8000-00805f9b34fb");
//GUID of bluetooth service
For seeing the proper GUID, refer to your device's (not dongle's) settings/properties. You can see them from Windows.

How to find a list of wireless networks (SSID's) in Java, C#, and/or C?

Is there a toolkit/package that is available that I could use to find a list of wireless networks (SSID's) that are available in either Java, C#, or C for Windows XP+? Any sample code would be appreciated.
For C#, take a look at the Managed Wifi API, which is a wrapper for the Native Wifi API provided with Windows XP SP2 and later.
I have not tested this code, but looking at the Managed Wifi API sample code, this should list the available SSIDs.
WlanClient client = new WlanClient();
foreach ( WlanClient.WlanInterface wlanIface in client.Interfaces )
{
// Lists all available networks
Wlan.WlanAvailableNetwork[] networks = wlanIface.GetAvailableNetworkList( 0 );
foreach ( Wlan.WlanAvailableNetwork network in networks )
{
Console.WriteLine( "Found network with SSID {0}.", GetStringForSSID(network.dot11Ssid));
}
}
static string GetStringForSSID(Wlan.Dot11Ssid ssid)
{
return Encoding.ASCII.GetString( ssid.SSID, 0, (int) ssid.SSIDLength );
}
ArrayList<String>ssids=new ArrayList<String>();
ArrayList<String>signals=new ArrayList<String>();
ProcessBuilder builder = new ProcessBuilder(
"cmd.exe", "/c", "netsh wlan show all");
builder.redirectErrorStream(true);
Process p = builder.start();
BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while (true) {
line = r.readLine();
if (line.contains("SSID")||line.contains("Signal")){
if(!line.contains("BSSID"))
if(line.contains("SSID")&&!line.contains("name")&&!line.contains("SSIDs"))
{
line=line.substring(8);
ssids.add(line);
}
if(line.contains("Signal"))
{
line=line.substring(30);
signals.add(line);
}
if(signals.size()==7)
{
break;
}
}
}
for (int i=1;i<ssids.size();i++)
{
System.out.println("SSID name == "+ssids.get(i)+" and its signal == "+signals.get(i) );
}
Well, you didn't specify the OS so, for Linux I will suggest Wireless Tools for Linux by Jean Tourrilhes (http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html). The iwlist() command displays a lot of information about the available networks. The source code is in C. Another way is to write your own code in C using libpcap for capturing the beacon frames and extracting SSID from them (in monitor mode only). I haven't tested my sniffing code yet so I won't paste it here but it is pretty simple job.

Categories