SuiteUSB using .NET API for PassMark USB 3.0 plug

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
MaSy_4695346
Level 2
Level 2
10 sign-ins 10 replies posted 5 replies posted

Dear all,

My company has purchased a few PassMark USB 3.0 Loopback plugs.

The company has an API for C++ for using this plug, but since we mostly develop in C# I asked them if they supplied their API for .NET which they don't.

However their hardware uses Cypress hardware (they link to Cypress EZ-USB FX3 SDK) so I thought of using the Cypress SDK in conjunction with SuiteUSB 3.4.

So far I've managed to establish a connection and send data back and forth, using SuiteUSB 3.4, over USB and this works fine.

However, there are a few vendor specific (PassMark) commands that I would like to send to the plug.

I've looked into how this is done in PassMarks C++ console implementation and it works fine.

My idea is to mimic this behaviour using SuiteUSB3.4.

For instance they perform

double Voltage = 0;

SendVendorCommand(CurUSBDevice, VENDOR_REQ_READ, GET_VOLTAGE, (UCHAR*)&Voltage, sizeof(Voltage));

bool SendVendorCommand(CCyUSBDevice *USBDevice, USB30_VENDOR RequestType, WORD wValue, UCHAR *buf, LONG buflen)

{

CCyControlEndPoint *ept;

if (USBDevice->IsOpen() == false)

return false;

ept = USBDevice->ControlEndPt;

ept->Target = TGT_DEVICE;

ept->ReqType = REQ_VENDOR;

ept->ReqCode = 0x00;

ept->Value = wValue;

ept->Index = 0;

if (RequestType == VENDOR_REQ_READ)

ept->Read(buf, buflen);

else

ept->Write(buf, buflen);

return true;

}

which is fairly straight forward for reading the voltage for the device.

I want to perform the same in C#

ReadVendorCommand(device, GET_VOLTAGE, sizeof(double));

        private byte[] ReadVendorCommand(CyUSBDevice device, ushort wValue, int lengthToRead)

        {

            var controlEndPoint = device.ControlEndPt;

            controlEndPoint.Target = TGT_DEVICE;

            controlEndPoint.ReqType = REQ_VENDOR;

            controlEndPoint.ReqCode = 0x00;

            controlEndPoint.Value = wValue;

            controlEndPoint.Index = 0;

            controlEndPoint.Direction = 1;

            byte[] data = new byte[lengthToRead];

            var result = controlEndPoint.Read(ref data, ref lengthToRead);

            if (result) return data;

            return null;

        }

However, the data returned is all zeros (8 of them to be exact) and the lengthToRead (which was 8 when calling controlEndPoint.Read) is now only two bytes.

I've checked and the data and all patterns up to the call seem exactly the same as in the C++ code.

Since SuiteUSB 3.4 has not been updated for some quite some time (9 years) I was wondering if anyone else has any leads or tip that could point me in the right direction to resolve the issue.

Thanks a lot in advance,

Magnus Sydoff

0 Likes
1 Solution

Hello,

Looks like there is a problem setting the configuration or in passing the arguments.

Please use the code below without changing inside your function:

var controlEndPoint = device.ControlEndPt;

CyControlEndPoint ctrlEpt = controlEndPoint as CyControlEndPoint;

if (ctrlEpt is null) throw new Exception("Endpoint is not available");

else

{

ctrlEpt .Direction = CyConst.DIR_FROM_DEVICE;

ctrlEpt .Target = CyConst.TGT_DEVICE;

ctrlEpt .ReqType = CyConst.REQ_VENDOR;

ctrlEpt .ReqCode = 0x00;

ctrlEpt .Value = 0x0007;

ctrlEpt .Index = 0;

ctrlEpt .TimeOut = 3000;

int len = 8;

byte[] data = new byte[len];

bool result = controlEndPoint.XferData(ref data, ref len );

if (result)

return data;

return null;

}

Please let me know if this works, and the value returned by the XferData function.

Thanks,

Yatheesh

View solution in original post

13 Replies
YatheeshD_36
Moderator
Moderator
Moderator
750 replies posted 500 replies posted 250 solutions authored

Hello,

Please try the below in your function:

CyControlEndPoint controlEndPoint = device.ControlEndPt;

If (controlEndPoint != null)

{

            controlEndPoint.Target = CyConst.TGT_DEVICE;

            controlEndPoint.ReqType = CyConst.REQ_VENDOR;

            controlEndPoint.ReqCode = 0x00;   

            controlEndPoint.Value = wValue;

            controlEndPoint.Index = 0;

            controlEndPoint.Direction = CyConst.DIR_FROM_DEVICE;

            byte[] data = new byte[lengthToRead];

            bool result = controlEndPoint.XferData(ref data, ref lengthToRead);

            if (result) return data;

            return null;

}

else

return null;

Best Regards,

Yatheesh

0 Likes

Hello,

Thanks for you reply!

(I realize that I by mistake posted the line controlEndPoint.Direction = 1)

If I look in the CyEndPoints.cs file (which implements the read function) it is already defined as so.

        public bool Read(ref byte[] buf, ref int len)

        {

            Direction = CyConst.DIR_FROM_DEVICE;

            return XferData(ref buf, ref len);

        }

0 Likes

..but I tried your suggestion.

        private byte[] ReadVendorCommand(CyUSBDevice device, ushort wValue, int lengthToRead)

        {

            var controlEndPoint = device.ControlEndPt;

            if (controlEndPoint is null) throw new Exception("Endpoint is not available");

            controlEndPoint.Target = TGT_DEVICE;

            controlEndPoint.ReqType = REQ_VENDOR;

            controlEndPoint.ReqCode = 0x00;

            controlEndPoint.Value = wValue;

            controlEndPoint.Index = 0;

            controlEndPoint.Direction = CyConst.DIR_FROM_DEVICE;

            byte[] data = new byte[lengthToRead];

            var result = controlEndPoint.XferData(ref data, ref lengthToRead);

            if (result) return data;

            return null;

        }

Unfortunately it is the same result. The data array still contains zeros and lengthToRead is now set to 2 as opposed to previous 8.

Again, thank you for your reply !

King regards
Magnus

0 Likes

Hello again,

One thing that I notice,  that makes me curious, is that in file CyEndPoints.cs, which implements your suggested function XferData, is that in the section

  fixed (int* lenTemp = &len)

                {

                    bResult = BeginDataXfer(ref tmpBuf, ref *lenTemp, ref ovLap);

                    wResult = WaitForIO(ovLapStatus->hEvent);

                    fResult = FinishDataXfer(ref buf, ref tmpBuf, ref *lenTemp, ref ovLap);

                }

bResult is always false when I run it whereas wResult and fResult are true.

Debugging this I can see that the call to PInvoke.DeviceIoControl fails, but it is not entirely clear to me why this happens or if it is a problem since calling function does not take notice of the returned false.

King regards

Magnus

0 Likes

Hello Magnus,

Is the vendor command handled in the firmware properly?

To verify this please use the control center and do a control IN transfer with the required data filled in the fields. Please let me know if the transfer is successful in the control center.

pastedImage_0.png

Also, UsbdStatus member contains the error code returned from the last XferData or BeginDataXfer call.

Please let me know what is returned by the usbdStatus. you can refer to the CyUSB.NET.pdf document from the FX3 SDK for the API details.

Thanks,

Yatheesh

0 Likes

Hello Yatheesh,

Thank you again for your prompt reply !

This is the reply from the USB Control center.

pastedImage_0.png

When I run the code in the C++ project that is working this is what is being sent......

pastedImage_4.png

... and this is the reply I get when asking for the current USB voltage.

pastedImage_3.png

When calling BeginDataXfer the

_lastError = (uint)Marshal.GetLastWin32Error();

is 997

pastedImage_6.png

Again, thank you for helping out !

King regards

Magnus

0 Likes

....and in hex for your convenience... 

pastedImage_0.png

pastedImage_1.png

0 Likes

From CyEndPoint.cs when running

pastedImage_1.png

pastedImage_0.png

0 Likes

Hello,

Looks like there is a problem setting the configuration or in passing the arguments.

Please use the code below without changing inside your function:

var controlEndPoint = device.ControlEndPt;

CyControlEndPoint ctrlEpt = controlEndPoint as CyControlEndPoint;

if (ctrlEpt is null) throw new Exception("Endpoint is not available");

else

{

ctrlEpt .Direction = CyConst.DIR_FROM_DEVICE;

ctrlEpt .Target = CyConst.TGT_DEVICE;

ctrlEpt .ReqType = CyConst.REQ_VENDOR;

ctrlEpt .ReqCode = 0x00;

ctrlEpt .Value = 0x0007;

ctrlEpt .Index = 0;

ctrlEpt .TimeOut = 3000;

int len = 8;

byte[] data = new byte[len];

bool result = controlEndPoint.XferData(ref data, ref len );

if (result)

return data;

return null;

}

Please let me know if this works, and the value returned by the XferData function.

Thanks,

Yatheesh

Hello Yatheesh,

This looks really good !!!

I'm getting the voltage back now !!

I see that the ReqType is different and you added a timeout !!

pastedImage_0.png

I realize that the PassMark console application had a different value for ReqType which is probably what threw me under the bus....

Currently I have no idea why that works, but you helping me along the way is great !!

pastedImage_2.png

Anyway, I hope that this means that I can continue my development !

Thank you very much for your support !!!

King regards

Magnus

0 Likes

...and it works great without the timeout (i.e. using the default) and using the Read function !!

The problem was the ReqType all along... 

This is my final version.

pastedImage_0.png

0 Likes

Confusing as it is....

ReqType seems to be defined as 2 unless I don't understand C++ at all (which of course is quite possible.... )

pastedImage_2.png

0 Likes

Hello Magnus,

It's great to see that the application is working !!

There are few differences in implementing CyAPI.lib for C++ and CyUSB.dll for C#.

The Timeout can be removed as it is not necessary for control transfers.

Best wishes on the development with our product and please do create threads on community in case you face any issues.

Best Regards,

Yatheesh

0 Likes