Any ETA Keith? DLP-IO8 support would be killer. I'm using it with other tuning software that supports it and can get read rates of around 20Hz for all 8 channels. Not can bus fast but plenty fast enough for analog sensors.
Dead easy to implement. This is the code I wrote to get it up and running on some custom software I created. Feel free to use it. I have it called in a background worker thread generated from the main UI.
Code:
// ----------------------------------
// Includes
// ----------------------------------
using System.Threading.Tasks;
using System.IO.Ports;
using System.Diagnostics;
// ----------------------------------
// Declerations
// ----------------------------------
private enum dlpStateMachineStates : int
{
DLP_IDLE,
DLP_OPEN_PORT,
DLP_SEND_PING_AND_WAIT_FOR_RESPONSE,
DLP_SEND_SETUP,
DLP_CLEAR_DATA_BUFFERS,
DLP_REQUEST_DATA,
DLP_WAIT_FOR_DATA_RECEIVED,
DLP_READ_DATA,
DLP_UPDATE_DISPLAY_CHANNELS
};
int dlp_Fail_Counts;
const int MAX_DLP_COM_RETRIES = 10; // 10 * 20ms = 0.2s, after this time the com routine will timeout
const int COM_LONG_WAIT_MS = 100;
const int COM_SHORT_WAIT_MS = 20; // 2 x this value is basically how fast we will read the DLP-IO8. Value as low as 10 has worked in testing
const int DLP_READ_BYTES = 16; // changing these will break the code
string dlpComPortNumber = "";
byte[] dlpByteRx = new byte[16];
Stopwatch stopWatch_DLP = new Stopwatch(); // used for data rate calculation
dlpStateMachineStates _dlpStateMachineStates; // DLP-IO8 state machine
// --------------------------------------------------------------------------------------------------------
// Setup connection to DLP-IO8 and continuously read all 8 channels of data.
// Scale output according to user transform
// Call this method from a background worker / run async
// --------------------------------------------------------------------------------------------------------
private void dlpStateMachine()
{
try
{
switch (_dlpStateMachineStates)
{
// ------------------------------------------------------------------------------------------------
// IDLE
// ------------------------------------------------------------------------------------------------
case dlpStateMachineStates.DLP_IDLE:
if (serialPort_DLP.IsOpen == true)
{
serialPort_DLP.Close();
}
break;
// ------------------------------------------------------------------------------------------------
// OPEN COM PORT
// ------------------------------------------------------------------------------------------------
case dlpStateMachineStates.DLP_OPEN_PORT:
if (dlpComPortNumber.Contains("COM"))
{
try
{
serialPort_DLP.PortName = dlpComPortNumber;
serialPort_DLP.BaudRate = 115200;
serialPort_DLP.DataBits = 8;
serialPort_DLP.Parity = Parity.None;
serialPort_DLP.Open();
}
catch (Exception err)
{
MessageBox.Show(err.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
backgroundWorker_DLP.CancelAsync();
}
}
if (serialPort_DLP.IsOpen)
{
this.Invoke(new MethodInvoker(delegate { btn_Connect_To_DLP.Visible = false; }));
_dlpStateMachineStates = dlpStateMachineStates.DLP_SEND_PING_AND_WAIT_FOR_RESPONSE;
}
break;
// ------------------------------------------------------------------------------------------------
// SEND PING "'" AND WAIT FOR PING RESPONSE "Q" aka (char)81
// ------------------------------------------------------------------------------------------------
case dlpStateMachineStates.DLP_SEND_PING_AND_WAIT_FOR_RESPONSE:
//
// every time the ping is sent, wait for a short delay and then check the receive buffer
// for a response. If we get it and it's correct ("Q") then move on. If we don't get it
// wait for a bit longer more then loop around and try again. If after a few loops we still
// don't get a response then raise 'Can't connect to DLP' error to the user and get out of
// this code
//
for (int j = 1; j < MAX_DLP_COM_RETRIES; j++)
{
serialPort_DLP.Write("'");
System.Threading.Thread.Sleep(COM_LONG_WAIT_MS);
// check here that the ping repsonse "Q" is sent back
if (serialPort_DLP.BytesToRead > 0 && serialPort_DLP.ReadByte() == 81)
{
System.Threading.Thread.Sleep(COM_LONG_WAIT_MS); // Small delay before firing off setup byte
_dlpStateMachineStates = dlpStateMachineStates.DLP_SEND_SETUP;
break; // exit, all good
}
}
if (_dlpStateMachineStates != dlpStateMachineStates.DLP_SEND_SETUP)
{
MessageBox.Show("DLP-IO8 not found.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
backgroundWorker_DLP.CancelAsync();
}
break;
// ------------------------------------------------------------------------------------------------
// SEND SETUP BYTE "\" aka (char)92
// ------------------------------------------------------------------------------------------------
//
// puts dlp into binary mode. If this setup byte is not sent, then the DLP defaults to ascii mode
//
case dlpStateMachineStates.DLP_SEND_SETUP:
serialPort_DLP.Write(Convert.ToString((char)92));
System.Threading.Thread.Sleep(COM_LONG_WAIT_MS);
_dlpStateMachineStates = dlpStateMachineStates.DLP_REQUEST_DATA;
break;
// ------------------------------------------------------------------------------------------------
// CLEAR DATA BUFFERS
// ------------------------------------------------------------------------------------------------
//
// flush the Rx buffer
//
case dlpStateMachineStates.DLP_CLEAR_DATA_BUFFERS:
serialPort_DLP.DiscardInBuffer();
break;
// ------------------------------------------------------------------------------------------------
// REQUEST DATA
// ------------------------------------------------------------------------------------------------
//
// Send the data request for all 8 channels. Each channel has its own request character. They
// can be sent all at once or 1 at a time if you want to read each channel in turn 1 by 1
//
case dlpStateMachineStates.DLP_REQUEST_DATA:
stopWatch_DLP.Restart();
serialPort_DLP.Write("ZXCVBNM,");
System.Threading.Thread.Sleep(COM_SHORT_WAIT_MS);
_dlpStateMachineStates = dlpStateMachineStates.DLP_READ_DATA;
break;
// ------------------------------------------------------------------------------------------------
// READ DATA
// ------------------------------------------------------------------------------------------------
//
// Check the data buffers have filled up to 16 bytes which is the size of the receive repsonse
// when all 8 channels are selected to be read. If we get nothing, then wait a short time and
// loop around again. If we have looped a few times and still got nothing then send the statemachine
// back to send another data request and increment a counter. If this counter keeps getting
// incremented then raise an error that the dlp receive request has timed out and exit the
// statemachine
//
case dlpStateMachineStates.DLP_READ_DATA:
for (int j = 1; j < MAX_DLP_COM_RETRIES; j++) // go around 10x and check the buffer each time
{
if (serialPort_DLP.BytesToRead >= DLP_READ_BYTES)
{
serialPort_DLP.Read(dlpByteRx, 0, DLP_READ_BYTES);
System.Threading.Thread.Sleep(COM_SHORT_WAIT_MS);
dlp_Fail_Counts = 0;
_dlpStateMachineStates = dlpStateMachineStates.DLP_UPDATE_DISPLAY_CHANNELS;
break; // exit, all good
}
System.Threading.Thread.Sleep(COM_SHORT_WAIT_MS);
}
// nothing received. Increment counter and set statemachine to go around again. If counter is > retry count then error
// to user and get out of this code
if (_dlpStateMachineStates != dlpStateMachineStates.DLP_UPDATE_DISPLAY_CHANNELS)
{
_dlpStateMachineStates = dlpStateMachineStates.DLP_REQUEST_DATA; // got nothing, send the data request again
dlp_Fail_Counts++;
}
if (dlp_Fail_Counts >= MAX_DLP_COM_RETRIES)
{
MessageBox.Show("DLP-IO8 receive data timed out.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
backgroundWorker_DLP.CancelAsync();
}
break;
// ------------------------------------------------------------------------------------------------
// UPDATE GUI ELEMENTS
// ------------------------------------------------------------------------------------------------
//
// Your data sir, pack it up and send it to the scanner. Do what you will
//
case dlpStateMachineStates.DLP_UPDATE_DISPLAY_CHANNELS:
int[] i = new int[8];
double[] d = new double[8];
// combine the bytes into an integer. Each integer is the respective data channel
// of the DLP
i[0] = dlpByteRx[1] | dlpByteRx[0] << 8;
i[1] = dlpByteRx[3] | dlpByteRx[2] << 8;
i[2] = dlpByteRx[5] | dlpByteRx[4] << 8;
i[3] = dlpByteRx[7] | dlpByteRx[6] << 8;
i[4] = dlpByteRx[9] | dlpByteRx[8] << 8;
i[5] = dlpByteRx[11] | dlpByteRx[10] << 8;
i[6] = dlpByteRx[13] | dlpByteRx[12] << 8;
i[7] = dlpByteRx[15] | dlpByteRx[14] << 8;
// scale the ad count into what ever the user has entered for the transfrom
d[0] = (double)i[0] / 1024 * d_Scalar[0] + d_Offset[0];
d[1] = (double)i[1] / 1024 * d_Scalar[1] + d_Offset[1];
d[2] = (double)i[2] / 1024 * d_Scalar[2] + d_Offset[2];
d[3] = (double)i[3] / 1024 * d_Scalar[3] + d_Offset[3];
d[4] = (double)i[4] / 1024 * d_Scalar[4] + d_Offset[4];
d[5] = (double)i[5] / 1024 * d_Scalar[5] + d_Offset[5];
d[6] = (double)i[6] / 1024 * d_Scalar[6] + d_Offset[6];
d[7] = (double)i[7] / 1024 * d_Scalar[7] + d_Offset[7];
// Get how long it took to run on receive cycle and update the GUI rate calculation
stopWatch_DLP.Stop();
double dataRate_DLP_Hz = Math.Round(1000 / (double)stopWatch_DLP.ElapsedMilliseconds);
this.Invoke(new MethodInvoker(delegate { tBox_DataRate_DLP.Text = Convert.ToString(dataRate_DLP_Hz) + " Hz"; })); // convert to Hz
// All done here, head back and request another packet of data again
_dlpStateMachineStates = dlpStateMachineStates.DLP_REQUEST_DATA;
break;
}
}
catch (Exception err)
{
MessageBox.Show("DLP State Machine Error." + "\r\n" + "Reason:" + "\r\n" + err.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
backgroundWorker_DLP.CancelAsync();
}
}