Futaba MDM166A – C++Builder/Delphi example
This page tries to give some clues on programming the Futaba MDM166A USB display using Delphi/C++Builder under Windows. First of all we need an additional component created by the unforgotten Robert Marquardt. The component does most of all work, as it provides an easy to use interface to the complex WinAP-interfaces to enumerate, accessing and working with USB devices. Mike Lischke provides access to the latest revision of the “HID Controller” (TJvHidDeviceController) on his website. There is no need to install it as component – it can be instanciated dynamically prior use. On all following steps, I assume to work on an instance of the TJvHidDeviceController class.
First of all we need to open (check-out) the USB device to get exclusive access and handles. These handles and further informations are held by the TJvHidDevice class. To check-out a device we need a variable of this type which will be used when calling the CheckOutXXX() methods. As we know the Vendor ID (VID) and Product ID (PID), we can use the CheckOutByID() method.
var lDevice: TJvHidDevice; begin // check out device if JvHidDeviceController1.CheckOutByID(lDevice, $19c2, $6a11) then begin // open device if lDevice.OpenFile then begin // read on... lDevice.CloseFile; end; JvHidDeviceController1.CheckIn(lDevice); end; end;
Now it is the time to open the inofficial protocol documentation written by me (can be found here) and start to send commands to the display. The display requires data packets in a predefined size. This size can be retrieved using the property Caps.OutputReportByteLength of the local lDevice instance (returned on check-out). On the Futaba MDM166A display the returned value should be 65 bytes. To be prepared for the future, use a dynamic array sized by the property.
var lBuffer: array of byte; begin // check-out & open device // size the buffer & initialize with zeros SetLength(lBuffer, lDevice.Caps.OutputReportByteLength); FillChar(lBuffer, lDevice.Caps.OutputReportByteLength, 0); // so, read on ... end;
The first byte of the buffer contains the ReportID used to transmit the data to the device. This ReportID need to be zero for the Futaba MDM166A display. All other bytes (64 bytes) are raw data and needs to be filled according to the protocol documentation. The first byte of the raw data represents the amount of data following.
As an example we lit the mute symbol on the display. So the command data consists of the prefix (0x1b), the command id (0×30 – SetSymbol), the symbol id (0×05 – mute) and the symbol state (0×01 – enable). The command data overall contains 4 bytes, so the complete buffer including the ReportID should look like this:
0x00, 0x04, 0x1b, 0x30, 0x05, 0x01
ReportID, DataSize, CmdPrefix, CmdSetSymbol, SymbolID, SymbolState
To send the data to the display use the WriteFile() method of the lDevice instance. Check the result and the amount of bytes written. Now, all codes combined:
var lDevice: TJvHidDevice; lBuffer: array of byte; lWritten: LongWord; begin // check out device if JvHidDeviceController1.CheckOutByID(lDevice, $19c2, $6a11) then begin // open device if lDevice.OpenFile then begin // size the buffer & initialize with zeros SetLength(lBuffer, lDevice.Caps.OutputReportByteLength); FillChar(lBuffer, lDevice.Caps.OutputReportByteLength, 0); // build data lBuffer := $00; // ReportID lBuffer := $04; // data size lBuffer := $1b; // command prefix (ESCape) lBuffer := $30; // command (SetSymbol) lBuffer := $05; // SymbolID (mute) lBuffer := $01; // SymbolState (on) // send to device lDevice.WriteFile(lBuffer, lDevice.Caps.OutputReportByteLength, lWritten); // close USB device lDevice.CloseFile; end; // check in device JvHidDeviceController1.CheckIn(lDevice); end; end;