Vortran Laser USB control
edyoshikun opened this issue · 2 comments
FEATURE:
The serial command through RS232 is slow and outdated.
Describe the solution you'd like
I would like to have this controlled through USB. The device appears as HID with vendor id 0x201A
and product id 0x1001
, and I can only read from it.
I don't have much documentation on the USB side, but I have the libusb.dll from the vendor.
We got the vendor's SDK from the website where they provide use with some C# precompiled .dll
to talk to the lasers.
For simplicity, I tried using the pythonnet
code tested with the latest commit in #157. I was able to instantiate the class StradusHUB
and call its methods, but I don't seem to get responses from the lasers. I don't think I'm actually connected to them because if I run their program (img linked below) it runs and recognizes the lasers, while in theory, I have them opened in another port (python code).
This might be some useful peace of code since we can tell the buffer sizes, endpoints, and vendor ID Vid_201A & Pid_1001
.
In their C# code, they use a finite state machine and a couple of muxes to coordinate sending/receiving data StradusDevice.cs
starting at line 284
.
#region USB READ BACKGROUND WORKER THREAD
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
uint BytesWritten = 0;
uint BytesRead = 0;
byte responsePending = 0x00;
byte responseReceived = 0x00;
byte armGetResponse = 0x00;
Mutex myMute;
while (true)
{
if (readWriting) //Do not try to use the read/write handles unless the USB device is attached and ready
{
if ((WriteHandleToUSBDevice != null) && (ReadHandleToUSBDevice != null))
{
Thread.Sleep(20);
try
{
if (ReadFileManagedBuffer(ReadHandleToUSBDevice, INBuffer, 65, ref BytesRead, IntPtr.Zero)) //Blocking function, unless an "overlapped" structure is used
{
if (BytesRead > 0)
{
//INBuffer[0] is the report ID, which we don't care about.
//INBuffer[1] is the request type
//INBuffer[2] to INBuffer[63] contain the data
Buffer.BlockCopy(INBuffer, 1, RequestIn, 0, 1); //src,dst
//Parse the fields of the packet received
switch (RequestIn[0])
{
case (byte)RequestTypes.GET_RESPONSE_STATUS:
responsePending = Buffer.GetByte(INBuffer, 2);
//updateRXText("\r\nRx: " + requestIn + " GET_RESPONSE_STATUS:" + System.Convert.ToString(responsePending));
break;
case (byte)RequestTypes.GET_RESPONSE:
if (armGetResponse == 0x01) //Avoid stale data
{
armGetResponse = 0x00;
responseReceived = 0x01;
Buffer.BlockCopy(INBuffer, 2, MessageIn, 0, 63); //src,dst
}
//updateRXText("\r\nRx: " + requestIn + " GET_RESPONSE: " + Encoding.Default.GetString(MessageIn));
break;
default:
break;
}
//System.Console.WriteLine("ReqIn: "+RequestIn[0].ToString());
}
}
//System.Console.WriteLine("STATE: "+STATE);
if (STATE != PSTATE)
{
logger.Info("STATE: " + STATE);
PSTATE = STATE;
}
//Finite State Machine
switch (STATE)
{
case 0x00: //Idle state
//Poll this status continually in the idle state
SendRequest((byte)RequestTypes.GET_RESPONSE_STATUS, String.Empty);
WriteFile(WriteHandleToUSBDevice, OUTBuffer, 65, ref BytesWritten, IntPtr.Zero);
if (responsePending == 0x01) //The firmware has indicated that there is a response ready to retrieve
{
//Flag is reset by firmware
STATE = 0x02;
}
else
if (sendNow == 0x01)
{
sendNow = 0x00;
//Send a command now...
STATE = 0x03;
}
break;
case 0x01: //Set Response Received
SendRequest((byte)RequestTypes.SET_RESPONSE_RECEIVED, String.Empty);
WriteFile(WriteHandleToUSBDevice, OUTBuffer, 65, ref BytesWritten, IntPtr.Zero);
if (myParentObj != null)
System.Console.WriteLine("SET_RESPONSE_RECEIVED VR Sent...");
STATE = 0x05;
break;
case 0x02: //Get response now
//Send request to get the response
SendRequest((byte)RequestTypes.GET_RESPONSE, String.Empty);
WriteFile(WriteHandleToUSBDevice, OUTBuffer, 65, ref BytesWritten, IntPtr.Zero);
armGetResponse = 0x01;
if(myParentObj!=null)
System.Console.WriteLine("GET_RESPONSE VR Sent...");
STATE = 0x04;
break;
case 0x03: //Send a new command to laser
rwl.WaitOne();
SendRequest((byte)RequestTypes.SET_CMD_QRY, stringToSend);
WriteFile(WriteHandleToUSBDevice, OUTBuffer, 65, ref BytesWritten, IntPtr.Zero);
rwl.ReleaseMutex();
if (myParentObj != null)
System.Console.WriteLine("SET_COMMAND VR Sent... " + stringToSend);
STATE = 0x00;
break;
case 0x04: //WAIT STATE (Wait for the response to actually come back)
if (responseReceived == 0x01)
{
responseReceived = 0x00;
if (myParentObj != null)
System.Console.WriteLine("Response from firmware is:" + Encoding.Default.GetString(MessageIn));
STATE = 0x01;
}
break;
case 0x05: //WAIT STATE (Wait for GET_RESPONSE_STATUS to return 0)
SendRequest((byte)RequestTypes.GET_RESPONSE_STATUS, String.Empty);
WriteFile(WriteHandleToUSBDevice, OUTBuffer, 65, ref BytesWritten, IntPtr.Zero);
if (responsePending == 0)
{
rwlReply.WaitOne();
theReply = Encoding.Default.GetString(MessageIn);
hasReply = true;
rwlReply.ReleaseMutex();
STATE = 0x00;
System.Console.WriteLine("Command Transaction Complete");
}
break;
case 0x06:
STATE = 0x06;
break;
}
}
catch
{
throw;
//Exceptions can occur during the read or write operations. For example,
//exceptions may occur if for instance the USB device is physically unplugged
//from the host while the above read/write functions are executing.
}
}
else
{
Thread.Sleep(200); //was 200, was 5ms Add a small delay. Otherwise, this while(true) loop can execute very fast and cause
//high CPU utilization, with no particular benefit to the application.
}
} //end of while(true) loop
//-------------------------------------------------------END CUT AND PASTE BLOCK-------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------
}
}
#endregion
One thing to note is that the vendor's installation package just uses a libusub.sys
or a LibUsbDotNet.dll
to talk to the device and setup the USB drivers. Is there a better way to talk to these devices?
@gregcourville perhaps you have more experience with this? Any pointers would be appreciated. @ieivanov added this to today's copylot meeting.
Thank you both in advance.