LibUsbDotNet UsbDevice.ControlTransfer hangs - c#

I have a C# .Net Winforms application, which uses LibUsbDotNet to program firmware into an USB-device (Atmel AVR32) using "DFU_DNLOAD" transfers, which is a special kind of control-transfers. This all works, BUT: A specific kind of transfer, which causes the device to erase its internal flash, fails to send an ACK within the correct timing.
When this happens, my LibUsbDotNet connection becomes irreparably broken, which causes everything to fail.
My code does the following:
int TransferToDevice(byte request, short value, byte[] data)
{
var setup = new UsbSetupPacket(
(byte)(UsbCtrlFlags.Direction_Out | UsbCtrlFlags.RequestType_Class | UsbCtrlFlags.Recipient_Interface),
request,
value,
0,
(short)data.Length);
int n;
IntPtr unmanagedPointer = System.Runtime.InteropServices.Marshal.AllocHGlobal(data.Length);
System.Runtime.InteropServices.Marshal.Copy(data, 0, unmanagedPointer, data.Length);
// UsbDevice obtained else-where
if (!UsbDevice.ControlTransfer(ref setup, unmanagedPointer, data.Length, out n))
{
n = 0;
}
System.Runtime.InteropServices.Marshal.FreeHGlobal(unmanagedPointer);
return n;
}
// In order to do a "DFU_DNLOAD", the method above is used as follows:
TransferToDevice(DFU_DNLOAD, Transactions++, data); // "data" is the payload
// where DFU_DNLOAD is:
private const byte DFU_DNLOAD = 1;
// Transactions is
short Transaction = 0;
The above code works (the device correctly receives the "DFU_DNLOAD" message), but the missing ACK is the problem. Once the error occurs, every attempt to communicate with the device (even if I try to re-initialize everything) fails, untill the device is disconnected and re-inserted...
I would like to be able to reset or re-initialize the USB-connection somehow, when this error occurs. Currently I am only able to re-establish communications with the device by exiting my application and re-starting it manually.

This was never solved to my satisfaction, ended up implementing my own "DFU" protocol ontop of LibUSB using plain C, and P/Invoke to that, avoiding LibUsbDotNet entirely... This solution seems to work.

Just guessing, but in case if data is array of short, than size of the buffer should be adjusted
int numberOfValues = data.Length;
int size = Marshal.SizeOf(typeof(short));
IntPtr unmanagedPointer = Marshal.AllocHGlobal(numberOfValues*size);
if (unmanagedPointer == IntPtr.Zero)
throw new OutOfMemoryException("Unable allocate memory");

Related

PIC18 UART receiving corrupted bytes from PC

I seem to have issue to receive correct bytes from a PC to a PIC18F27J53.
The PIC UART is set standard, asynchronous, 8bits, 9600, No parity.
The PC is a win 10, I have made a simple UART program, and sending a few ints, all separated by commas, like the following.
"123,24,65,98,12,45,564,987,321,0,5.9,87,65,789,123,6554,213,8754\n"
I have tried different ways,
Tried to send each char one by one, however the PIC seems to get stuck midway or early in the transfer and the RX flag doesn't go high anymore.
I have tried to send each int followed by "\n" and my PIC to parse each chars and cut the read after a "\n" is found. This seems better, I can get more data in, but the final received data is corrupted: some ints are wrong etc.
It clearly show this is a sync issue, it looks like the PC is too fast for the PIC?
If so, I am looking at having a synchronous uart, however according to the web, this seems to be far from the chosen method, which makes me thing I must have another issue to resolve, in asynchronous mode?
My question, what is the most popular robust way to do that PIC to PC UART full duplex communication?
Here are my PIC receive APIs, fairly standard and simple (I think).
void int_receive_data(void)
{
char input_element[10] = { 0 };
char full_rx[128] = { 0 };
for (int i = 0; i < 22; i++) {
p18f47j53_uart2_read_text(input_element, sizeof(input_element));
strncat(full_rx, input_element, strlen(input_element));
strncat(full_rx, ",", 1);
}
}
void p18f47j53_uart2_read_text(char *output, uint8_t max_length)
{
uint8_t c;
char buffer[64] = { 0 };
for (uint8_t i = 0; i < max_length; i++) {
c = p18f47j53_uart2_receive_u8();
buffer[i] = c;
if ((c == 10) || (c == '\n')) {
buffer[i] = 0;
memcpy(output, buffer, i);
i = max_length;
}
}
}
uint8_t p18f47j53_uart2_receive_u8(void)
{
// wait for the flag
while (!PIR3bits.RC2IF);
// reset receiver if over run error
if (RCSTA2bits.OERR) {
RCSTA2bits.CREN = 0;
RCSTA2bits.CREN = 1;
return PIC_RC_FAIL;
}
// reset if frame error
if (RCSTA2bits.FERR) {
RCSTA2bits.SPEN = 0;
RCSTA2bits.SPEN = 1;
return PIC_RC_FAIL;
}
return RCREG2;
}
On the PC C# side, my sending looks like this
string[] full_separated = full_tx.Split(',');
foreach (string s in full_separated)
my_port.WriteLine(s);
The PIC is running from its internal clock 8MHz.
I never tried the synchronous way as it seems more complicated and 99 percent of the web result will show asynchronous way, which makes me think I better debug what I am doing.
Any idea? advice? Thanks
Well not really a solution, but an alternative. You should break the frame in small chunks. And if possible the receiver to ack with a char to notify the transmitter to go ahead with another chunk.
Reason I am saying that, I have a mikroE dev board with a similar PIC, and while running an "out of the box" example, and sending
"111,222,333,444,555,666,777,888,999"
It looks like the "999" is creating issues, too much byte, maybe buffer issue, maybe the not perfect baud rate mismatch builds up after a few bytes?
Repeat the sending every 50ms, 500ms or 1000ms doesn't make it better.
Changing the baud rate neither.
Only removing ",999" and it seems to work all right.
Without the ",999" I am guessing it is still on the "edge of working", so maybe just remove "666,777,888,999" and the communication should feel more comfortable.
More code, more traffic, but at least it works..

How to write data to USB HID device in Android with only a single input endpoint

I have a USB HID device that I would like to communicate with. I am successfully doing so on Windows using the HidSharp library (link: https://github.com/treehopper-electronics/HIDSharp). My Windows application is developed using the .NET Framework 4.5, C#, and Visual Studio.
I now want to communicate with this same USB HID device from an Android tablet instead of from the Windows desktop. I am encountering some problems doing so. When I have the device plugged in to my tablet, it reports a single interface with a single "read" endpoint. Here is what is reported to me:
Interface #0
Class: Human Interaction Device (0x3)
Endpoint: #0
Address : 0x81 (10000001)
Number : 1
Direction : Inbound (0x80)
Type : Intrrupt (0x3)
Poll Interval : 1
Max Packet Size: 64
Attributes : 000000011
As you can see, it only reports a single endpoint, which is an inbound endpoint. I need to be able to output simple commands to this device, which I was able to do so successfully on Windows using HidSharp.
HidSharp abstracted everything into a single "stream" object that you could read from and write to. Using the Android APIs, there isn't a single "stream" object, but rather there seem to be 3 different ways of reading/writing: bulk transfer, control transfer, and USB Request. I've tried sending out data using all 3, but with seemingly no success.
Any suggestions on what to do? Is there a reason why I could send out data to this device on Windows, but seemingly cannot do so from Android? Is there a way to use a single endpoint as both a read and a write endpoint? Is there something that I am just obviously missing and not understanding?
I am using Xamarin as my development environment (C#, Visual Studio 2017). Since code is always helpful, here is how I am connecting to the device:
int VendorID = 0x04d8;
int ProductID = 0x2742;
UsbManager USB_Manager = null;
UsbDevice USB_Device = null;
UsbDeviceConnection DeviceConnection = null;
UsbInterface DeviceInterface = null;
UsbEndpoint OutputEndpoint = null;
UsbEndpoint InputEndpoint = null;
//Grab the Android USB manager and get a list of connected devices
var USB_Manager = MyMainActivity.ApplicationContext.GetSystemService(Android.Content.Context.UsbService) as Android.Hardware.Usb.UsbManager;
var attached_devices = USB_Manager.DeviceList;
//Find the device in the list of connected devices
foreach (var d in attached_devices.Keys)
{
if (attached_devices[d].VendorId == VendorID && attached_devices[d].ProductId == ProductID)
{
USB_Device = attached_devices[d];
break;
}
}
//Assuming we found the correct device, let's set everything up
if (USB_Device != null)
{
for (int j = 0; j < USB_Device.InterfaceCount; j++)
{
DeviceInterface = USB_Device.GetInterface(j);
for (int i = 0; i < DeviceInterface.EndpointCount; i++)
{
var temp_ep = DeviceInterface.GetEndpoint(i);
if (temp_ep.Type == Android.Hardware.Usb.UsbAddressing.XferInterrupt)
{
if (temp_ep.Direction == Android.Hardware.Usb.UsbAddressing.In)
{
InputEndpoint = temp_ep;
}
if (temp_ep.Direction == Android.Hardware.Usb.UsbAddressing.Out)
{
OutputEndpoint = temp_ep;
}
}
}
}
//Request permission to communicate with this USB device
UsbReceiver receiver = new UsbReceiver();
PendingIntent pending_intent = PendingIntent.GetBroadcast(Game.Activity, 0, new Android.Content.Intent(UsbReceiver.ACTION_USB_PERMISSION), 0);
IntentFilter intent_filter = new IntentFilter(UsbReceiver.ACTION_USB_PERMISSION);
Game.Activity.RegisterReceiver(receiver, intent_filter);
USB_Manager.RequestPermission(USB_Device, pending_intent);
bool has_permission = USB_Manager.HasPermission(USB_Device);
var device_connection = USB_Manager.OpenDevice(USB_Device);
device_connection.ClaimInterface(DeviceInterface, true);
DeviceConnection = device_connection;
}
Next, here is how I attempt to read from the device:
//3 methods of attempting to read from the device
//Method 1:
byte[] inpt = new byte[64];
var request = new UsbRequest();
request.Initialize(DeviceConnection, InputEndpoint);
var byte_buffer = ByteBuffer.Allocate(64);
request.Queue(byte_buffer, 64);
DeviceConnection.RequestWait();
byte_buffer.Rewind();
for(int i = 0; i < 64; i++)
{
inpt[i] = (byte) byte_buffer.Get();
}
//Method 2:
byte[] inpt = new byte[64];
DeviceConnection.BulkTransfer(InputEndpoint, inpt, inpt.Length, 1000);
//Method 3:
byte[] inpt = new byte[64];
DeviceConnection.ControlTransfer(UsbAddressing.In, 0, 0, 0, inpt, 64, 1000);
And finally, here is how I attempt to write data to this device:
//Method 1:
byte[] output_msg; //This variable is assigned elsewhere in the code
DeviceConnection.BulkTransfer(OutputEndpoint, output_msg, output_msg.Length, 30);
//Method 2:
byte[] output_msg; //This variable is assigned elsewhere in the code
DeviceConnection.ControlTransfer(UsbAddressing.Out, 0, 0, 0, output_msg, output_msg.Length, 1000);
//Method 3:
byte[] output_msg; //This variable is assigned elsewhere in the code
var write_request = new UsbRequest();
write_request.Initialize(DeviceConnection, OutputEndpoint);
var byte_buffer_write = ByteBuffer.Wrap(output_msg);
request.Queue(byte_buffer_write, output_msg.Length);
DeviceConnection.RequestWait();
"OutputEndpoint" is typically null because there is no output endpoint, so I often replace "OutputEndpoint" with "InputEndpoint", but with no success.
Any help would be greatly appreciated! Thanks!!!
You are dealing with HID devices which means you should do Interrupt Transfers.
In Android, you should use UsbRequest to perform Interrupt Transfers (as it does Asynchronous NonBlocking IO).
The endpoints are unidirectional and can be used for both inbounds and outbound (but not at the same time)
If the endpoint is inbound then submit the Urb using UsbRequest and queue as you tried before but using empty buffer with expected bufferLength.
The RequestWait will return UsbRequest Object back upon completion.
If the usbRequest.getEndPoint().getDirection() is inbound then your buffer variable will be updated with read buffer from the device.
If the usbRequest.getEndpoint().getDirection() is outbound then you should pass your buffer to write data to the device

BASS WASAPI BPMCounter

I want to analyse my default playback device and detect the beats. I've been using the BASS WASAPI to get the FFT data of the selected device with:
int ret = BassWasapi.BASS_WASAPI_GetData(_fft, (int)BASSData.BASS_DATA_FFT2048);
Now I was using the data to generate spectrum data and display this to the user. In addition I want to detect the Beats using the BPMCounter Class from BASS. However as far as I can tell the BPMCounter.ProcessAudio() function requires a stream (which I don't get with WASAPI) in order to work. Is there a ways I can use BPMCounter with WASAPI? Would be great if someone can point me to the right direction. Thanks
Edit:
Tried this to convert the data to a stream, but without success:
int ret = BassWasapi.BASS_WASAPI_GetData(_fft, (int)BASSData.BASS_DATA_FFT2048); //get channel fft data
var chan = Bass.BASS_StreamCreate(0, 44100, BASSFlag.BASS_DEFAULT, BASSStreamProc.STREAMPROC_PUSH);
Bass.BASS_ChannelPlay(chan, false);
Bass.BASS_StreamPutData(chan, _fft, _fft.Length);
bool beat = _count.ProcessAudio(chan, true);
Debug.Write(beat);
beat is always False, however I can see at the Spectrum that the capturing of the FFT Data is corrent.
I've just started playing with this lib a few hours ago and i am still going through the examples. So my answer maybe is not what you want. For my project i also want to transform WASAPI into a stream and use it for a displaying a spectrum. What i did was to create a StreamPush, right after BASS_WASAPI initialization.
To init your WASAPI use this call and this delegate:
private InitWasapi()
{
WASAPIPROC _process = new WASAPIPROC(Process); // Delegate
bool res = BassWasapi.BASS_WASAPI_Init(_YourDeviceNumber, 0, 0, BASSWASAPIInit.BASS_WASAPI_BUFFER, 1f, 0f, _process, IntPtr.Zero);
if (!res)
{
// Do error checking
}
// This is the part you are looking for (maybe!)
// Use these flags because Wasapi needs 32-bit sample data
var info = BassWasapi.BASS_WASAPI_GetInfo();
_stream = Bass.BASS_StreamCreatePush(info.freq, info.chans, BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_SAMPLE_FLOAT, IntPtr.Zero);
BassWasapi.BASS_WASAPI_Start();
}
private int Process(IntPtr buffer, int length, IntPtr user)
{
Bass.BASS_StreamPutData(_stream, buffer, length);
return length;
}
Please note: This works, but i am still experimenting. For example i am not getting the same spectrum output as when i create the stream from the music file itself. There are some (small) differences. Maybe it's because i am using a custom EQ in Winamp for playing the same .mp3. So if anyone knows more on this subject, i would like also to hear it!

Unable to return same double using Google Protocol Buffers from C# to C++ and back

I'm trying to communicate between C# and C++ with varying amounts of success.
I am able to send a message between the two using reply/request, but the doubles that I am receiving are not correct.
For debugging purposes and understanding, I am currently running the following:
Clrzmq 3.0 rc1, Google ProtocolBuffer 2.5, Protobuf-csharp-port-2.4, ZeroMQ-3.2.3
.Proto
package InternalComm;
message Point
{
optional double x = 1;
optional double y = 2;
optional string label = 3;
}
server.cpp (the relevant part)
while (true) {
zmq::message_t request;
// Wait for next request from client
socket.recv (&request);
zmq::message_t reply (request.size());
memcpy ((void*)reply.data(), request.data(), request.size());
socket.send(reply);
}
client.cs (the relevant part)
public static Point ProtobufPoint(Point point)
{
Point rtn = new Point(0,0);
using (var context = ZmqContext.Create())
{
using (ZmqSocket requester = context.CreateSocket(SocketType.REQ))
{
requester.Connect("tcp://localhost:5555");
var p = InternalComm.Point.CreateBuilder().SetX(point.X).SetY(point.Y).Build().ToByteArray();
requester.Send(p);
string reply = requester.Receive(Encoding.ASCII);
Console.WriteLine("Input: {0}", point);
byte[] bytes = System.Text.Encoding.ASCII.GetBytes(reply);
var message = InternalComm.Point.ParseFrom(bytes);
rtn.X = message.X;
rtn.Y = message.Y;
Console.WriteLine("Output: {0}", rtn);
}
}
return rtn;
}
On the C# side, Point is a very simple struct. Just x and y properties.
Here is what I'm getting from my unit tests as a result of running the above code.
Input (1.31616874365468, 4.55516872325469)
Output (0.000473917985115791, 4.55516872323627)
Input (274.120398471829, 274.128936418736)
Output (274.077917334613, 274.128936049925)
Input (150.123798461987, 2.345E-12)
Output (145.976459594794, 1.11014954927532E-13)
Input (150, 0)
Output (145.96875, 0)
I am thinking that the problem is my protobuf code is incorrect (doubtful this is a bug on Skeet's side). I am also running under the assumption that server.cpp is doing nothing to the message but returning it as is.
Thoughts?
The requestor.Receive(Encoding.ASCII) call is designed to receive a string, not a block of bytes. You are asking the ZmqSocket instance to return the message as an ASCII string, which is highly likely to cause modifications to the content. If you're sending a byte array, receive a byte array.
Try this:
int readSize;
byte[] reply = requester.Receive(null, out readSize);
var message = InternalComm.Point.ParseFrom(reply);
The readSize variable will contain the actual number of valid bytes in the received block, which may vary from the size of the reply array, so you may need to slice up the array to make it palatable to ProtoBuf.
Why the ASCII --> bytes --> parsing step? If you're parsing bytes, you should read bytes. If you're parsing text, you should read that.
Unnecessary charset-conversions look very likely to be erroneous.

Serial number of the usb on windows Ce 6.0 in c#

I need to get the serial number of a usb stick connected to a windows ce 6.0 device. I tried with KernelIoControl and i get the serial number of the window ce 6.0 device but not the usb connected to it.
private static string GetDeviceID()
{
// Initialize the output buffer to the size of a
// Win32 DEVICE_ID structure.
byte[] outbuff = new byte[20];
Int32 dwOutBytes;
bool done = false;
Int32 nBuffSize = outbuff.Length;
// Set DEVICEID.dwSize to size of buffer. Some platforms look at
// this field rather than the nOutBufSize param of KernelIoControl
// when determining if the buffer is large enough.
BitConverter.GetBytes(nBuffSize).CopyTo(outbuff, 0);
dwOutBytes = 0;
// Loop until the device ID is retrieved or an error occurs.
while (!done)
{
if (KernelIoControl(IOCTL_HAL_GET_DEVICEID, IntPtr.Zero,
0, outbuff, nBuffSize, ref dwOutBytes))
{
done = true;
}
else
{
int error = Marshal.GetLastWin32Error();
switch (error)
{
case ERROR_NOT_SUPPORTED:
throw new NotSupportedException(
"IOCTL_HAL_GET_DEVICEID is not supported on this device",
new Win32Exception(error));
case ERROR_INSUFFICIENT_BUFFER:
// The buffer is not big enough for the data. The
// required size is in the first 4 bytes of the output
// buffer (DEVICE_ID.dwSize).
nBuffSize = BitConverter.ToInt32(outbuff, 0);
outbuff = new byte[nBuffSize];
// Set DEVICEID.dwSize to size of buffer. Some
// platforms look at this field rather than the
// nOutBufSize param of KernelIoControl when
// determining if the buffer is large enough.
BitConverter.GetBytes(nBuffSize).CopyTo(outbuff, 0);
break;
default:
throw new Win32Exception(error, "Unexpected error");
}
}
}
When i connect the usb stick to the windows ce 6 device, it shows me a new hard disk recognize, i need to come to the properties of this new device registered, get control of the usb ports available on my windows ce 6 device.
What you're probably looking for is USB_DEVICE_DESCRIPTOR. In big windows, you would use SetupDiGetDeviceProperty to get this information, but in CE this value is only available to the driver. I don't think there is a generic way of getting this information back from the driver in CE. Your driver may contain a special IOCTL_ to get that information, though. Contact your OEM.

Categories

Resources