MelbourneDeveloper / Device.Net

A C# cross platform connected device framework
MIT License
620 stars 119 forks source link

BytesTransferred is 4294967295 in PerformControlTransferAsync #206

Open D0ctorWh0 opened 3 years ago

D0ctorWh0 commented 3 years ago

I have code that works well with WinUSB on windows and trying to do the same on android.

So in WinUSB I have commands

device.ControlTransferOut(0x41, 0x54, 0, 0, new byte[] { 0x01 });
device.ControlTransferIn(0xC1, 0x4e, 0, 0, 4);

and they work.

I tried to do the same with Device.Net on android

var res1 = await device.PerformControlTransferAsync(new SetupPacket(new UsbDeviceRequestType(RequestDirection.Out, RequestType.Standard, RequestRecipient.Device), 0x54,  0, 0, 1), new byte[] { 0x01 }).ConfigureAwait(false);
var res2 = await device.PerformControlTransferAsync(new SetupPacket(new UsbDeviceRequestType(RequestDirection.In, RequestType.Standard, RequestRecipient.Device), 0x4e, 0, 0, 4)).ConfigureAwait(false);

but for Out command I got BytesTransferred is 4294967295 (I guess it is -1 for uint?) and In command throws exception "Requested 4 bytes but received 4294967295".

What am I doing wrong? Can anyone help me?

MelbourneDeveloper commented 3 years ago

@D0ctorWh0 thanks for getting in contact.

I personally could not get control transfer working on Android either. I recommend that you clone this repo and debug the code directly. You can see the Android control transfer code here.

You might want to try copying and pasting the code from the Android library and create a clean Android solution. If you get it to work, please post your code here.

I suspect that there may be extra initialization etc. needed on Android. Maybe claiming the interface or something like that is necessary.

D0ctorWh0 commented 3 years ago

I got it working by passing request type byte into UsbDeviceConnection ControlTransfer function and casting it to UsbAddressing.

So for my WinUSB commands

device.ControlTransferOut(0x41, 0x54, 0, 0, new byte[] { 0x01 });
device.ControlTransferIn(0xC1, 0x4e, 0, 0, 4);

I got following UsbDeviceConnection.ControlTransferAsync commands

await UsbConnection.ControlTransferAsync((UsbAddressing)0x41, 0x54, 0, 0, new byte[] { 0x01 }, 1, 2000).ConfigureAwait(false);

byte[] buffer1 = new byte[4];
await UsbConnection.ControlTransferAsync((UsbAddressing)0xC1, 0x4e, 0, 0, buffer1, 4, 2000).ConfigureAwait(false);
MelbourneDeveloper commented 3 years ago

@D0ctorWh0 amazing! I think I see what you did there. Is there any chance you could get that working in Device.Net and do a pull request for that?

D0ctorWh0 commented 3 years ago

I've never made pull requests before, but I could try at the end of the week.

MelbourneDeveloper commented 3 years ago

@D0ctorWh0 it's very straight forward. Just

D0ctorWh0 commented 3 years ago

I added casting of RequestDirection to UsbAddressing in PerformControlTransferAndroid function like this https://github.com/D0ctorWh0/Device.Net/commit/9bae9f27585be554125e07243f5185ff0b569309 . So I am able to use my request type byte and stopped getting -1 transferred bytes count. But it still not working properly. At my device initialization stage first two control transfer reads (control transfer in) return some data, but third control transfer read returns transferred bytes count 0 and further initialization fails...

Screenshot_20210619_235751

MelbourneDeveloper commented 3 years ago

@D0ctorWh0 amazing. Could you please do a PR of what you've already done?

Try putting a delay between each call and consider using Polly for retry.

Have a look at the extension methods here and how they implement Polly to do retry

https://github.com/MelbourneDeveloper/Device.Net/blob/c0ab331b78b156cf3af91722661c35dae993e31e/src/Device.Net.UnitTests/IntegrationTests.cs#L320