mirror of
https://github.com/ckaczor/WorkIndicator.git
synced 2026-01-13 17:23:18 -05:00
Initial commit
This commit is contained in:
272
Delcom/Delcom.cs
Normal file
272
Delcom/Delcom.cs
Normal file
@@ -0,0 +1,272 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
namespace WorkIndicator.Delcom
|
||||
{
|
||||
public class Delcom
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct HidTxPacketStruct
|
||||
{
|
||||
public Byte MajorCmd;
|
||||
public Byte MinorCmd;
|
||||
public Byte LSBData;
|
||||
public Byte MSBData;
|
||||
public Byte HidData0;
|
||||
public Byte HidData1;
|
||||
public Byte HidData2;
|
||||
public Byte HidData3;
|
||||
public Byte ExtData0;
|
||||
public Byte ExtData1;
|
||||
public Byte ExtData2;
|
||||
public Byte ExtData3;
|
||||
public Byte ExtData4;
|
||||
public Byte ExtData5;
|
||||
public Byte ExtData6;
|
||||
public Byte ExtData7;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct HidRxPacketStruct
|
||||
{
|
||||
public Byte Data0;
|
||||
public Byte Data1;
|
||||
public Byte Data2;
|
||||
public Byte Data3;
|
||||
public Byte Data4;
|
||||
public Byte Data5;
|
||||
public Byte Data6;
|
||||
public Byte Data7;
|
||||
}
|
||||
|
||||
private readonly DeviceManagement _deviceManagement = new DeviceManagement();
|
||||
private readonly HID _hid = new HID();
|
||||
|
||||
private SafeFileHandle _deviceHandle;
|
||||
private Boolean _deviceDetected;
|
||||
private String _devicePathName;
|
||||
private UInt32 _matchingDevicesFound;
|
||||
private HidTxPacketStruct _transmitPacket;
|
||||
|
||||
public bool RawCommand(int major, int minor, int lsbData, int msbData)
|
||||
{
|
||||
_transmitPacket.MajorCmd = Convert.ToByte(major);
|
||||
_transmitPacket.MinorCmd = Convert.ToByte(minor);
|
||||
|
||||
_transmitPacket.LSBData = Convert.ToByte(lsbData);
|
||||
_transmitPacket.MSBData = Convert.ToByte(msbData);
|
||||
|
||||
return HID.HidD_SetFeature(_deviceHandle, StructureToByteArray(_transmitPacket), 8);
|
||||
}
|
||||
|
||||
public int WriteBlink(int lsb, int msb)
|
||||
{
|
||||
try
|
||||
{
|
||||
_transmitPacket.MajorCmd = 101;
|
||||
_transmitPacket.MinorCmd = 20;
|
||||
|
||||
_transmitPacket.LSBData = Convert.ToByte(lsb);
|
||||
_transmitPacket.MSBData = Convert.ToByte(msb);
|
||||
|
||||
int r = HID.HidD_SetFeature(_deviceHandle, StructureToByteArray(_transmitPacket), 8) ? 0 : 1;
|
||||
|
||||
_transmitPacket.MajorCmd = 101;
|
||||
_transmitPacket.MinorCmd = 25;
|
||||
|
||||
_transmitPacket.LSBData = Convert.ToByte(msb);
|
||||
_transmitPacket.MSBData = Convert.ToByte(0);
|
||||
|
||||
HID.HidD_SetFeature(_deviceHandle, StructureToByteArray(_transmitPacket), 8);
|
||||
|
||||
return r;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
public int WritePorts(int port0, int port1)
|
||||
{
|
||||
try
|
||||
{
|
||||
_transmitPacket.MajorCmd = 101;
|
||||
_transmitPacket.MinorCmd = 10;
|
||||
|
||||
_transmitPacket.LSBData = Convert.ToByte(port0);
|
||||
_transmitPacket.MSBData = Convert.ToByte(port1);
|
||||
|
||||
return HID.HidD_SetFeature(_deviceHandle, StructureToByteArray(_transmitPacket), 8) ? 0 : 1;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
public UInt32 ReadPort0(ref UInt32 port0)
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
Byte[] buffer = new Byte[16];
|
||||
|
||||
buffer[0] = 100; // Read ports command
|
||||
|
||||
if (!HID.HidD_GetFeature(_deviceHandle, buffer, 8))
|
||||
return 1;
|
||||
|
||||
port0 = Convert.ToUInt32(buffer[0]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
public int ReadPorts(ref int port0, ref int port1)
|
||||
{
|
||||
try
|
||||
{
|
||||
Byte[] buffer = new Byte[16];
|
||||
|
||||
buffer[0] = 100; // Read ports command
|
||||
|
||||
if (!HID.HidD_GetFeature(_deviceHandle, buffer, 8))
|
||||
return 1;
|
||||
|
||||
port0 = Convert.ToInt32(buffer[0]);
|
||||
port1 = Convert.ToInt32(buffer[1]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
public UInt32 Close()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!_deviceHandle.IsClosed)
|
||||
_deviceHandle.Close();
|
||||
|
||||
return 0;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
public UInt32 Open()
|
||||
{
|
||||
return OpenNthDevice(1);
|
||||
}
|
||||
|
||||
public UInt32 OpenNthDevice(UInt32 deviceIndex)
|
||||
{
|
||||
if (_deviceHandle != null)
|
||||
Close();
|
||||
|
||||
if (!FindTheHID(deviceIndex))
|
||||
return 1;
|
||||
|
||||
_deviceHandle = FileIODeclarations.CreateFile(_devicePathName, FileIODeclarations.GenericRead | FileIODeclarations.GenericWrite, FileIODeclarations.FileShareRead | FileIODeclarations.FileShareWrite, IntPtr.Zero, FileIODeclarations.OpenExisting, 0, 0);
|
||||
|
||||
return _deviceHandle.IsInvalid ? 2 : (uint) 0;
|
||||
}
|
||||
|
||||
public string GetDeviceName()
|
||||
{
|
||||
return _devicePathName;
|
||||
}
|
||||
|
||||
public UInt32 GetDevicesCount()
|
||||
{
|
||||
FindTheHID(0);
|
||||
|
||||
return _matchingDevicesFound;
|
||||
}
|
||||
|
||||
private Boolean FindTheHID(UInt32 deviceIndex)
|
||||
{
|
||||
const ushort productId = 0xB080;
|
||||
const ushort vendorId = 0x0FC5;
|
||||
|
||||
String[] devicePathName = new String[128];
|
||||
Guid hidGuid = Guid.Empty;
|
||||
UInt32 matchingDevices = 0;
|
||||
|
||||
_deviceDetected = false;
|
||||
|
||||
HID.HidD_GetHidGuid(ref hidGuid);
|
||||
|
||||
Boolean deviceFound = _deviceManagement.FindDeviceFromGuid(hidGuid, ref devicePathName);
|
||||
|
||||
if (deviceFound)
|
||||
{
|
||||
Int32 memberIndex = 0;
|
||||
do
|
||||
{
|
||||
SafeFileHandle hidHandle = FileIODeclarations.CreateFile(devicePathName[memberIndex], FileIODeclarations.GenericRead | FileIODeclarations.GenericWrite, FileIODeclarations.FileShareRead | FileIODeclarations.FileShareWrite, IntPtr.Zero, FileIODeclarations.OpenExisting, 0, 0);
|
||||
|
||||
if (!hidHandle.IsInvalid)
|
||||
{
|
||||
_hid.DeviceAttributes.Size = Marshal.SizeOf(_hid.DeviceAttributes);
|
||||
|
||||
Boolean success = HID.HidD_GetAttributes(hidHandle, ref _hid.DeviceAttributes);
|
||||
if (success)
|
||||
{
|
||||
if (_hid.DeviceAttributes.VendorID == vendorId && _hid.DeviceAttributes.ProductID == productId)
|
||||
{
|
||||
matchingDevices++;
|
||||
_deviceDetected = true;
|
||||
}
|
||||
|
||||
if (_deviceDetected && matchingDevices == deviceIndex)
|
||||
{
|
||||
_devicePathName = devicePathName[memberIndex];
|
||||
hidHandle.Close();
|
||||
}
|
||||
else
|
||||
{
|
||||
_deviceDetected = false;
|
||||
hidHandle.Close();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_deviceDetected = false;
|
||||
hidHandle.Close();
|
||||
}
|
||||
}
|
||||
|
||||
memberIndex = memberIndex + 1;
|
||||
}
|
||||
while (!(_deviceDetected || memberIndex == devicePathName.Length));
|
||||
}
|
||||
|
||||
_matchingDevicesFound = matchingDevices;
|
||||
|
||||
return _deviceDetected;
|
||||
}
|
||||
|
||||
private static byte[] StructureToByteArray(object obj)
|
||||
{
|
||||
int length = Marshal.SizeOf(obj);
|
||||
byte[] buffer = new byte[length];
|
||||
IntPtr ptr = Marshal.AllocHGlobal(length);
|
||||
Marshal.StructureToPtr(obj, ptr, true);
|
||||
Marshal.Copy(ptr, buffer, 0, length);
|
||||
Marshal.FreeHGlobal(ptr);
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
357
Delcom/DeviceManagement.cs
Normal file
357
Delcom/DeviceManagement.cs
Normal file
@@ -0,0 +1,357 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace WorkIndicator.Delcom
|
||||
{
|
||||
sealed internal partial class DeviceManagement
|
||||
{
|
||||
/// <summary>
|
||||
/// Compares two device path names. Used to find out if the device name
|
||||
/// of a recently attached or removed device matches the name of a
|
||||
/// device the application is communicating with.
|
||||
/// </summary>
|
||||
///
|
||||
/// <param name="m"> a WM_DEVICECHANGE message. A call to RegisterDeviceNotification
|
||||
/// causes WM_DEVICECHANGE messages to be passed to an OnDeviceChange routine.. </param>
|
||||
/// <param name="mydevicePathName"> a device pathname returned by
|
||||
/// SetupDiGetDeviceInterfaceDetail in an SP_DEVICE_INTERFACE_DETAIL_DATA structure. </param>
|
||||
///
|
||||
/// <returns>
|
||||
/// True if the names match, False if not.
|
||||
/// </returns>
|
||||
///
|
||||
internal Boolean DeviceNameMatch(Message m, String mydevicePathName)
|
||||
{
|
||||
DevBroadcastDeviceInterface1 devBroadcastDeviceInterface = new DevBroadcastDeviceInterface1();
|
||||
DevBroadcastHdr devBroadcastHeader = new DevBroadcastHdr();
|
||||
|
||||
// The LParam parameter of Message is a pointer to a DEV_BROADCAST_HDR structure.
|
||||
|
||||
Marshal.PtrToStructure(m.LParam, devBroadcastHeader);
|
||||
|
||||
if ((devBroadcastHeader.dbch_devicetype == DbtDevTypDeviceInterface))
|
||||
{
|
||||
// The dbch_devicetype parameter indicates that the event applies to a device interface.
|
||||
// So the structure in LParam is actually a DEV_BROADCAST_INTERFACE structure,
|
||||
// which begins with a DEV_BROADCAST_HDR.
|
||||
|
||||
// Obtain the number of characters in dbch_name by subtracting the 32 bytes
|
||||
// in the strucutre that are not part of dbch_name and dividing by 2 because there are
|
||||
// 2 bytes per character.
|
||||
|
||||
Int32 stringSize = Convert.ToInt32((devBroadcastHeader.dbch_size - 32) / 2);
|
||||
|
||||
// The dbcc_name parameter of devBroadcastDeviceInterface contains the device name.
|
||||
// Trim dbcc_name to match the size of the String.
|
||||
|
||||
devBroadcastDeviceInterface.dbcc_name = new Char[stringSize + 1];
|
||||
|
||||
// Marshal data from the unmanaged block pointed to by m.LParam
|
||||
// to the managed object devBroadcastDeviceInterface.
|
||||
|
||||
Marshal.PtrToStructure(m.LParam, devBroadcastDeviceInterface);
|
||||
|
||||
// Store the device name in a String.
|
||||
String deviceNameString = new String(devBroadcastDeviceInterface.dbcc_name, 0, stringSize);
|
||||
|
||||
// Compare the name of the newly attached device with the name of the device
|
||||
// the application is accessing (mydevicePathName).
|
||||
// Set ignorecase True.
|
||||
|
||||
return String.Compare(deviceNameString, mydevicePathName, StringComparison.OrdinalIgnoreCase) == 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use SetupDi API functions to retrieve the device path name of an
|
||||
/// attached device that belongs to a device interface class.
|
||||
/// </summary>
|
||||
///
|
||||
/// <param name="myGuid"> an interface class GUID. </param>
|
||||
/// <param name="devicePathName"> a pointer to the device path name
|
||||
/// of an attached device. </param>
|
||||
///
|
||||
/// <returns>
|
||||
/// True if a device is found, False if not.
|
||||
/// </returns>
|
||||
internal Boolean FindDeviceFromGuid(Guid myGuid, ref String[] devicePathName)
|
||||
{
|
||||
Int32 bufferSize = 0;
|
||||
IntPtr detailDataBuffer = IntPtr.Zero;
|
||||
IntPtr deviceInfoSet = new IntPtr();
|
||||
Boolean lastDevice = false;
|
||||
SpDeviceInterfaceData deviceInterfaceData = new SpDeviceInterfaceData();
|
||||
|
||||
try
|
||||
{
|
||||
// ***
|
||||
// API function
|
||||
|
||||
// summary
|
||||
// Retrieves a device information set for a specified group of devices.
|
||||
// SetupDiEnumDeviceInterfaces uses the device information set.
|
||||
|
||||
// parameters
|
||||
// Interface class GUID.
|
||||
// Null to retrieve information for all device instances.
|
||||
// Optional handle to a top-level window (unused here).
|
||||
// Flags to limit the returned information to currently present devices
|
||||
// and devices that expose interfaces in the class specified by the GUID.
|
||||
|
||||
// Returns
|
||||
// Handle to a device information set for the devices.
|
||||
// ***
|
||||
|
||||
deviceInfoSet = SetupDiGetClassDevs(ref myGuid, IntPtr.Zero, IntPtr.Zero, DigCfPresent | DigCfDeviceInterface);
|
||||
|
||||
Boolean deviceFound = false;
|
||||
Int32 memberIndex = 0;
|
||||
|
||||
// The cbSize element of the MyDeviceInterfaceData structure must be set to
|
||||
// the structure's size in bytes.
|
||||
// The size is 28 bytes for 32-bit code and 32 bits for 64-bit code.
|
||||
|
||||
deviceInterfaceData.CbSize = Marshal.SizeOf(deviceInterfaceData);
|
||||
|
||||
do
|
||||
{
|
||||
// Begin with 0 and increment through the device information set until
|
||||
// no more devices are available.
|
||||
|
||||
// ***
|
||||
// API function
|
||||
|
||||
// summary
|
||||
// Retrieves a handle to a SP_DEVICE_INTERFACE_DATA structure for a device.
|
||||
// On return, MyDeviceInterfaceData contains the handle to a
|
||||
// SP_DEVICE_INTERFACE_DATA structure for a detected device.
|
||||
|
||||
// parameters
|
||||
// DeviceInfoSet returned by SetupDiGetClassDevs.
|
||||
// Optional SP_DEVINFO_DATA structure that defines a device instance
|
||||
// that is a member of a device information set.
|
||||
// Device interface GUID.
|
||||
// Index to specify a device in a device information set.
|
||||
// Pointer to a handle to a SP_DEVICE_INTERFACE_DATA structure for a device.
|
||||
|
||||
// Returns
|
||||
// True on success.
|
||||
// ***
|
||||
|
||||
Boolean success = SetupDiEnumDeviceInterfaces(deviceInfoSet, IntPtr.Zero, ref myGuid, memberIndex, ref deviceInterfaceData);
|
||||
|
||||
// Find out if a device information set was retrieved.
|
||||
|
||||
if (!success)
|
||||
{
|
||||
lastDevice = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// A device is present.
|
||||
|
||||
// ***
|
||||
// API function:
|
||||
|
||||
// summary:
|
||||
// Retrieves an SP_DEVICE_INTERFACE_DETAIL_DATA structure
|
||||
// containing information about a device.
|
||||
// To retrieve the information, call this function twice.
|
||||
// The first time returns the size of the structure.
|
||||
// The second time returns a pointer to the data.
|
||||
|
||||
// parameters
|
||||
// DeviceInfoSet returned by SetupDiGetClassDevs
|
||||
// SP_DEVICE_INTERFACE_DATA structure returned by SetupDiEnumDeviceInterfaces
|
||||
// A returned pointer to an SP_DEVICE_INTERFACE_DETAIL_DATA
|
||||
// Structure to receive information about the specified interface.
|
||||
// The size of the SP_DEVICE_INTERFACE_DETAIL_DATA structure.
|
||||
// Pointer to a variable that will receive the returned required size of the
|
||||
// SP_DEVICE_INTERFACE_DETAIL_DATA structure.
|
||||
// Returned pointer to an SP_DEVINFO_DATA structure to receive information about the device.
|
||||
|
||||
// Returns
|
||||
// True on success.
|
||||
// ***
|
||||
|
||||
SetupDiGetDeviceInterfaceDetail(deviceInfoSet, ref deviceInterfaceData, IntPtr.Zero, 0, ref bufferSize, IntPtr.Zero);
|
||||
|
||||
// Allocate memory for the SP_DEVICE_INTERFACE_DETAIL_DATA structure using the returned buffer size.
|
||||
|
||||
detailDataBuffer = Marshal.AllocHGlobal(bufferSize);
|
||||
|
||||
// Store cbSize in the first bytes of the array. The number of bytes varies with 32- and 64-bit systems.
|
||||
|
||||
Marshal.WriteInt32(detailDataBuffer, (IntPtr.Size == 4) ? (4 + Marshal.SystemDefaultCharSize) : 8);
|
||||
|
||||
// Call SetupDiGetDeviceInterfaceDetail again.
|
||||
// This time, pass a pointer to DetailDataBuffer
|
||||
// and the returned required buffer size.
|
||||
|
||||
SetupDiGetDeviceInterfaceDetail(deviceInfoSet, ref deviceInterfaceData, detailDataBuffer, bufferSize, ref bufferSize, IntPtr.Zero);
|
||||
|
||||
// Skip over cbsize (4 bytes) to get the address of the devicePathName.
|
||||
|
||||
IntPtr pDevicePathName = new IntPtr(detailDataBuffer.ToInt32() + 4);
|
||||
|
||||
// Get the String containing the devicePathName.
|
||||
|
||||
devicePathName[memberIndex] = Marshal.PtrToStringAuto(pDevicePathName);
|
||||
|
||||
deviceFound = true;
|
||||
}
|
||||
memberIndex = memberIndex + 1;
|
||||
}
|
||||
while (lastDevice != true);
|
||||
|
||||
return deviceFound;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (detailDataBuffer != IntPtr.Zero)
|
||||
{
|
||||
// Free the memory allocated previously by AllocHGlobal.
|
||||
|
||||
Marshal.FreeHGlobal(detailDataBuffer);
|
||||
}
|
||||
// ***
|
||||
// API function
|
||||
|
||||
// summary
|
||||
// Frees the memory reserved for the DeviceInfoSet returned by SetupDiGetClassDevs.
|
||||
|
||||
// parameters
|
||||
// DeviceInfoSet returned by SetupDiGetClassDevs.
|
||||
|
||||
// returns
|
||||
// True on success.
|
||||
// ***
|
||||
|
||||
if (deviceInfoSet != IntPtr.Zero)
|
||||
{
|
||||
SetupDiDestroyDeviceInfoList(deviceInfoSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Requests to receive a notification when a device is attached or removed.
|
||||
/// </summary>
|
||||
///
|
||||
/// <param name="devicePathName"> handle to a device. </param>
|
||||
/// <param name="formHandle"> handle to the window that will receive device events. </param>
|
||||
/// <param name="classGuid"> device interface GUID. </param>
|
||||
/// <param name="deviceNotificationHandle"> returned device notification handle. </param>
|
||||
///
|
||||
/// <returns>
|
||||
/// True on success.
|
||||
/// </returns>
|
||||
///
|
||||
internal Boolean RegisterForDeviceNotifications(String devicePathName, IntPtr formHandle, Guid classGuid, ref IntPtr deviceNotificationHandle)
|
||||
{
|
||||
// A DEV_BROADCAST_DEVICEINTERFACE header holds information about the request.
|
||||
|
||||
DevBroadcastDeviceInterface devBroadcastDeviceInterface = new DevBroadcastDeviceInterface();
|
||||
IntPtr devBroadcastDeviceInterfaceBuffer = IntPtr.Zero;
|
||||
|
||||
try
|
||||
{
|
||||
// Set the parameters in the DEV_BROADCAST_DEVICEINTERFACE structure.
|
||||
|
||||
// Set the size.
|
||||
|
||||
Int32 size = Marshal.SizeOf(devBroadcastDeviceInterface);
|
||||
devBroadcastDeviceInterface.dbcc_size = size;
|
||||
|
||||
// Request to receive notifications about a class of devices.
|
||||
|
||||
devBroadcastDeviceInterface.dbcc_devicetype = DbtDevTypDeviceInterface;
|
||||
|
||||
devBroadcastDeviceInterface.dbcc_reserved = 0;
|
||||
|
||||
// Specify the interface class to receive notifications about.
|
||||
|
||||
devBroadcastDeviceInterface.dbcc_classguid = classGuid;
|
||||
|
||||
// Allocate memory for the buffer that holds the DEV_BROADCAST_DEVICEINTERFACE structure.
|
||||
|
||||
devBroadcastDeviceInterfaceBuffer = Marshal.AllocHGlobal(size);
|
||||
|
||||
// Copy the DEV_BROADCAST_DEVICEINTERFACE structure to the buffer.
|
||||
// Set fDeleteOld True to prevent memory leaks.
|
||||
|
||||
Marshal.StructureToPtr(devBroadcastDeviceInterface, devBroadcastDeviceInterfaceBuffer, true);
|
||||
|
||||
// ***
|
||||
// API function
|
||||
|
||||
// summary
|
||||
// Request to receive notification messages when a device in an interface class
|
||||
// is attached or removed.
|
||||
|
||||
// parameters
|
||||
// Handle to the window that will receive device events.
|
||||
// Pointer to a DEV_BROADCAST_DEVICEINTERFACE to specify the type of
|
||||
// device to send notifications for.
|
||||
// DEVICE_NOTIFY_WINDOW_HANDLE indicates the handle is a window handle.
|
||||
|
||||
// Returns
|
||||
// Device notification handle or NULL on failure.
|
||||
// ***
|
||||
|
||||
deviceNotificationHandle = RegisterDeviceNotification(formHandle, devBroadcastDeviceInterfaceBuffer, DeviceNotifyWindowHandle);
|
||||
|
||||
// Marshal data from the unmanaged block devBroadcastDeviceInterfaceBuffer to
|
||||
// the managed object devBroadcastDeviceInterface
|
||||
|
||||
Marshal.PtrToStructure(devBroadcastDeviceInterfaceBuffer, devBroadcastDeviceInterface);
|
||||
|
||||
return deviceNotificationHandle.ToInt32() != IntPtr.Zero.ToInt32();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (devBroadcastDeviceInterfaceBuffer != IntPtr.Zero)
|
||||
{
|
||||
// Free the memory allocated previously by AllocHGlobal.
|
||||
|
||||
Marshal.FreeHGlobal(devBroadcastDeviceInterfaceBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Requests to stop receiving notification messages when a device in an
|
||||
/// interface class is attached or removed.
|
||||
/// </summary>
|
||||
///
|
||||
/// <param name="deviceNotificationHandle"> handle returned previously by
|
||||
/// RegisterDeviceNotification. </param>
|
||||
internal void StopReceivingDeviceNotifications(IntPtr deviceNotificationHandle)
|
||||
{
|
||||
// ***
|
||||
// API function
|
||||
|
||||
// summary
|
||||
// Stop receiving notification messages.
|
||||
|
||||
// parameters
|
||||
// Handle returned previously by RegisterDeviceNotification.
|
||||
|
||||
// returns
|
||||
// True on success.
|
||||
// ***
|
||||
|
||||
// Ignore failures.
|
||||
|
||||
UnregisterDeviceNotification(deviceNotificationHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
95
Delcom/DeviceManagementDeclarations.cs
Normal file
95
Delcom/DeviceManagementDeclarations.cs
Normal file
@@ -0,0 +1,95 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace WorkIndicator.Delcom
|
||||
{
|
||||
internal sealed partial class DeviceManagement
|
||||
{
|
||||
///<summary >
|
||||
// API declarations relating to device management (SetupDixxx and
|
||||
// RegisterDeviceNotification functions).
|
||||
/// </summary>
|
||||
|
||||
// from dbt.h
|
||||
|
||||
internal const Int32 DbtDeviceArrival = 0x8000;
|
||||
internal const Int32 DbtDeviceRemoveComplete = 0x8004;
|
||||
internal const Int32 DbtDevTypDeviceInterface = 5;
|
||||
internal const Int32 DbtDevTypHandle = 6;
|
||||
internal const Int32 DeviceNotifyAllInterfaceClasses = 4;
|
||||
internal const Int32 DeviceNotifyServiceHandle = 1;
|
||||
internal const Int32 DeviceNotifyWindowHandle = 0;
|
||||
internal const Int32 WmDeviceChange = 0x219;
|
||||
|
||||
// from setupapi.h
|
||||
|
||||
internal const Int32 DigCfPresent = 2;
|
||||
internal const Int32 DigCfDeviceInterface = 0X10;
|
||||
|
||||
// Two declarations for the DEV_BROADCAST_DEVICEINTERFACE structure.
|
||||
|
||||
// Use this one in the call to RegisterDeviceNotification() and
|
||||
// in checking dbch_devicetype in a DEV_BROADCAST_HDR structure:
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal class DevBroadcastDeviceInterface
|
||||
{
|
||||
internal Int32 dbcc_size;
|
||||
internal Int32 dbcc_devicetype;
|
||||
internal Int32 dbcc_reserved;
|
||||
internal Guid dbcc_classguid;
|
||||
internal Int16 dbcc_name;
|
||||
}
|
||||
|
||||
// Use this to read the dbcc_name String and classguid:
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||
internal class DevBroadcastDeviceInterface1
|
||||
{
|
||||
internal Int32 dbcc_size;
|
||||
internal Int32 dbcc_devicetype;
|
||||
internal Int32 dbcc_reserved;
|
||||
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 16)]
|
||||
internal Byte[] dbcc_classguid;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 255)]
|
||||
internal Char[] dbcc_name;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal class DevBroadcastHdr
|
||||
{
|
||||
internal Int32 dbch_size;
|
||||
internal Int32 dbch_devicetype;
|
||||
internal Int32 dbch_reserved;
|
||||
}
|
||||
|
||||
internal struct SpDeviceInterfaceData
|
||||
{
|
||||
internal Int32 CbSize;
|
||||
internal Guid InterfaceClassGuid;
|
||||
internal Int32 Flags;
|
||||
internal IntPtr Reserved;
|
||||
}
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
internal static extern IntPtr RegisterDeviceNotification(IntPtr hRecipient, IntPtr notificationFilter, Int32 flags);
|
||||
|
||||
[DllImport("setupapi.dll", SetLastError = true)]
|
||||
internal static extern Int32 SetupDiCreateDeviceInfoList(ref Guid classGuid, Int32 hwndParent);
|
||||
|
||||
[DllImport("setupapi.dll", SetLastError = true)]
|
||||
internal static extern Int32 SetupDiDestroyDeviceInfoList(IntPtr deviceInfoSet);
|
||||
|
||||
[DllImport("setupapi.dll", SetLastError = true)]
|
||||
internal static extern Boolean SetupDiEnumDeviceInterfaces(IntPtr deviceInfoSet, IntPtr deviceInfoData, ref Guid interfaceClassGuid, Int32 memberIndex, ref SpDeviceInterfaceData spDeviceInterfaceData);
|
||||
|
||||
[DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
internal static extern IntPtr SetupDiGetClassDevs(ref Guid classGuid, IntPtr enumerator, IntPtr hwndParent, Int32 flags);
|
||||
|
||||
[DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
internal static extern Boolean SetupDiGetDeviceInterfaceDetail(IntPtr deviceInfoSet, ref SpDeviceInterfaceData spDeviceInterfaceData, IntPtr deviceInterfaceDetailData, Int32 deviceInterfaceDetailDataSize, ref Int32 requiredSize, IntPtr deviceInfoData);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
internal static extern Boolean UnregisterDeviceNotification(IntPtr handle);
|
||||
}
|
||||
}
|
||||
53
Delcom/FileIODeclarations.cs
Normal file
53
Delcom/FileIODeclarations.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
namespace WorkIndicator.Delcom
|
||||
{
|
||||
internal sealed class FileIODeclarations
|
||||
{
|
||||
internal const Int32 FileFlagOverlapped = 0x40000000;
|
||||
|
||||
internal const Int32 FileShareRead = 1;
|
||||
internal const Int32 FileShareWrite = 2;
|
||||
|
||||
internal const UInt32 GenericRead = 0x80000000;
|
||||
internal const UInt32 GenericWrite = 0x40000000;
|
||||
|
||||
internal const Int32 InvalidHandleValue = -1;
|
||||
|
||||
internal const Int32 OpenExisting = 3;
|
||||
|
||||
internal const Int32 WaitTimeout = 0x102;
|
||||
internal const Int32 WaitObject0 = 0;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal class SecurityAttributes
|
||||
{
|
||||
internal Int32 nLength;
|
||||
internal Int32 lpSecurityDescriptor;
|
||||
internal Int32 bInheritHandle;
|
||||
}
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
internal static extern Int32 CancelIo(SafeFileHandle hFile);
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
internal static extern IntPtr CreateEvent(IntPtr securityAttributes, Boolean bManualReset, Boolean bInitialState, String lpName);
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
internal static extern SafeFileHandle CreateFile(String lpFileName, UInt32 dwDesiredAccess, Int32 dwShareMode, IntPtr lpSecurityAttributes, Int32 dwCreationDisposition, Int32 dwFlagsAndAttributes, Int32 hTemplateFile);
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
internal static extern Boolean GetOverlappedResult(SafeFileHandle hFile, IntPtr lpOverlapped, ref Int32 lpNumberOfBytesTransferred, Boolean bWait);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
internal static extern Boolean ReadFile(SafeFileHandle hFile, IntPtr lpBuffer, Int32 nNumberOfBytesToRead, ref Int32 lpNumberOfBytesRead, IntPtr lpOverlapped);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
internal static extern Int32 WaitForSingleObject(IntPtr hHandle, Int32 dwMilliseconds);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
internal static extern Boolean WriteFile(SafeFileHandle hFile, Byte[] lpBuffer, Int32 nNumberOfBytesToWrite, ref Int32 lpNumberOfBytesWritten, IntPtr lpOverlapped);
|
||||
}
|
||||
}
|
||||
851
Delcom/HID.cs
Normal file
851
Delcom/HID.cs
Normal file
@@ -0,0 +1,851 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
namespace WorkIndicator.Delcom
|
||||
{
|
||||
internal sealed partial class HID
|
||||
{
|
||||
private const String ModuleName = "Hid";
|
||||
|
||||
internal HidpCaps Capabilities;
|
||||
internal HiddAttributes DeviceAttributes;
|
||||
|
||||
internal abstract class ReportIn
|
||||
{
|
||||
internal abstract void Read(SafeFileHandle hidHandle, SafeFileHandle readHandle, SafeFileHandle writeHandle, ref Boolean myDeviceDetected, ref Byte[] readBuffer, ref Boolean success);
|
||||
}
|
||||
|
||||
internal class InFeatureReport : ReportIn
|
||||
{
|
||||
internal override void Read(SafeFileHandle hidHandle, SafeFileHandle readHandle, SafeFileHandle writeHandle, ref Boolean myDeviceDetected, ref Byte[] inFeatureReportBuffer, ref Boolean success)
|
||||
{
|
||||
try
|
||||
{
|
||||
success = HidD_GetFeature(hidHandle, inFeatureReportBuffer, inFeatureReportBuffer.Length);
|
||||
|
||||
Debug.Print("HidD_GetFeature success = " + success);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DisplayException(ModuleName, ex);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class InputReportViaControlTransfer : ReportIn
|
||||
{
|
||||
internal override void Read(SafeFileHandle hidHandle, SafeFileHandle readHandle, SafeFileHandle writeHandle, ref Boolean myDeviceDetected, ref Byte[] inputReportBuffer, ref Boolean success)
|
||||
{
|
||||
try
|
||||
{
|
||||
success = HidD_GetInputReport(hidHandle, inputReportBuffer, inputReportBuffer.Length + 1);
|
||||
|
||||
Debug.Print("HidD_GetInputReport success = " + success);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DisplayException(ModuleName, ex);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For reading Input reports.
|
||||
/// </summary>
|
||||
|
||||
internal class InputReportViaInterruptTransfer : ReportIn
|
||||
{
|
||||
internal void CancelTransfer(SafeFileHandle hidHandle, SafeFileHandle readHandle, SafeFileHandle writeHandle, IntPtr eventObject)
|
||||
{
|
||||
try
|
||||
{
|
||||
// ***
|
||||
// API function: CancelIo
|
||||
|
||||
// Purpose: Cancels a call to ReadFile
|
||||
|
||||
// Accepts: the device handle.
|
||||
|
||||
// Returns: True on success, False on failure.
|
||||
// ***
|
||||
|
||||
FileIODeclarations.CancelIo(readHandle);
|
||||
|
||||
Debug.WriteLine("************ReadFile error*************");
|
||||
//String functionName = "CancelIo";
|
||||
//Debug.WriteLine(MyDebugging.ResultOfAPICall(functionName));
|
||||
Debug.WriteLine("");
|
||||
|
||||
// The failure may have been because the device was removed,
|
||||
// so close any open handles and
|
||||
// set myDeviceDetected=False to cause the application to
|
||||
// look for the device on the next attempt.
|
||||
|
||||
if ((!(hidHandle.IsInvalid)))
|
||||
{
|
||||
hidHandle.Close();
|
||||
}
|
||||
|
||||
if ((!(readHandle.IsInvalid)))
|
||||
{
|
||||
readHandle.Close();
|
||||
}
|
||||
|
||||
if ((!(writeHandle.IsInvalid)))
|
||||
{
|
||||
writeHandle.Close();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DisplayException(ModuleName, ex);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an event object for the overlapped structure used with ReadFile.
|
||||
/// </summary>
|
||||
///
|
||||
/// <param name="hidOverlapped"> the overlapped structure </param>
|
||||
/// <param name="eventObject"> the event object </param>
|
||||
|
||||
internal void PrepareForOverlappedTransfer(ref NativeOverlapped hidOverlapped, ref IntPtr eventObject)
|
||||
{
|
||||
try
|
||||
{
|
||||
// ***
|
||||
// API function: CreateEvent
|
||||
|
||||
// Purpose: Creates an event object for the overlapped structure used with ReadFile.
|
||||
|
||||
// Accepts:
|
||||
// A security attributes structure or IntPtr.Zero.
|
||||
// Manual Reset = False (The system automatically resets the state to nonsignaled
|
||||
// after a waiting thread has been released.)
|
||||
// Initial state = False (not signaled)
|
||||
// An event object name (optional)
|
||||
|
||||
// Returns: a handle to the event object
|
||||
// ***
|
||||
|
||||
eventObject = FileIODeclarations.CreateEvent(IntPtr.Zero, false, false, "");
|
||||
|
||||
// Set the members of the overlapped structure.
|
||||
|
||||
hidOverlapped.OffsetLow = 0;
|
||||
hidOverlapped.OffsetHigh = 0;
|
||||
hidOverlapped.EventHandle = eventObject;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DisplayException(ModuleName, ex);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// reads an Input report from the device using interrupt transfers.
|
||||
/// </summary>
|
||||
///
|
||||
/// <param name="hidHandle"> the handle for learning about the device and exchanging Feature reports. </param>
|
||||
/// <param name="readHandle"> the handle for reading Input reports from the device. </param>
|
||||
/// <param name="writeHandle"> the handle for writing Output reports to the device. </param>
|
||||
/// <param name="myDeviceDetected"> tells whether the device is currently attached. </param>
|
||||
/// <param name="inputReportBuffer"> contains the requested report. </param>
|
||||
/// <param name="success"> read success </param>
|
||||
|
||||
internal override void Read(SafeFileHandle hidHandle, SafeFileHandle readHandle, SafeFileHandle writeHandle, ref Boolean myDeviceDetected, ref Byte[] inputReportBuffer, ref Boolean success)
|
||||
{
|
||||
IntPtr eventObject = IntPtr.Zero;
|
||||
NativeOverlapped hidOverlapped = new NativeOverlapped();
|
||||
Int32 numberOfBytesRead = 0;
|
||||
|
||||
try
|
||||
{
|
||||
// Set up the overlapped structure for ReadFile.
|
||||
|
||||
PrepareForOverlappedTransfer(ref hidOverlapped, ref eventObject);
|
||||
|
||||
// Allocate memory for the input buffer and overlapped structure.
|
||||
|
||||
IntPtr nonManagedBuffer = Marshal.AllocHGlobal(inputReportBuffer.Length);
|
||||
IntPtr nonManagedOverlapped = Marshal.AllocHGlobal(Marshal.SizeOf(hidOverlapped));
|
||||
Marshal.StructureToPtr(hidOverlapped, nonManagedOverlapped, false);
|
||||
|
||||
// ***
|
||||
// API function: ReadFile
|
||||
// Purpose: Attempts to read an Input report from the device.
|
||||
|
||||
// Accepts:
|
||||
// A device handle returned by CreateFile
|
||||
// (for overlapped I/O, CreateFile must have been called with FILE_FLAG_OVERLAPPED),
|
||||
// A pointer to a buffer for storing the report.
|
||||
// The Input report length in bytes returned by HidP_GetCaps,
|
||||
// A pointer to a variable that will hold the number of bytes read.
|
||||
// An overlapped structure whose hEvent member is set to an event object.
|
||||
|
||||
// Returns: the report in ReadBuffer.
|
||||
|
||||
// The overlapped call returns immediately, even if the data hasn't been received yet.
|
||||
|
||||
// To read multiple reports with one ReadFile, increase the size of ReadBuffer
|
||||
// and use NumberOfBytesRead to determine how many reports were returned.
|
||||
// Use a larger buffer if the application can't keep up with reading each report
|
||||
// individually.
|
||||
// ***
|
||||
|
||||
success = FileIODeclarations.ReadFile(readHandle, nonManagedBuffer, inputReportBuffer.Length, ref numberOfBytesRead, nonManagedOverlapped);
|
||||
|
||||
if (!success)
|
||||
{
|
||||
Debug.WriteLine("waiting for ReadFile");
|
||||
|
||||
// API function: WaitForSingleObject
|
||||
|
||||
// Purpose: waits for at least one report or a timeout.
|
||||
// Used with overlapped ReadFile.
|
||||
|
||||
// Accepts:
|
||||
// An event object created with CreateEvent
|
||||
// A timeout value in milliseconds.
|
||||
|
||||
// Returns: A result code.
|
||||
|
||||
Int32 result = FileIODeclarations.WaitForSingleObject(eventObject, 3000);
|
||||
|
||||
// Find out if ReadFile completed or timeout.
|
||||
|
||||
switch (result)
|
||||
{
|
||||
case FileIODeclarations.WaitObject0:
|
||||
|
||||
// ReadFile has completed
|
||||
|
||||
success = true;
|
||||
Debug.WriteLine("ReadFile completed successfully.");
|
||||
|
||||
// Get the number of bytes read.
|
||||
|
||||
// API function: GetOverlappedResult
|
||||
|
||||
// Purpose: gets the result of an overlapped operation.
|
||||
|
||||
// Accepts:
|
||||
// A device handle returned by CreateFile.
|
||||
// A pointer to an overlapped structure.
|
||||
// A pointer to a variable to hold the number of bytes read.
|
||||
// False to return immediately.
|
||||
|
||||
// Returns: non-zero on success and the number of bytes read.
|
||||
|
||||
FileIODeclarations.GetOverlappedResult(readHandle, nonManagedOverlapped, ref numberOfBytesRead, false);
|
||||
|
||||
break;
|
||||
|
||||
case FileIODeclarations.WaitTimeout:
|
||||
|
||||
// Cancel the operation on timeout
|
||||
|
||||
CancelTransfer(hidHandle, readHandle, writeHandle, eventObject);
|
||||
Debug.WriteLine("Readfile timeout");
|
||||
success = false;
|
||||
myDeviceDetected = false;
|
||||
break;
|
||||
default:
|
||||
|
||||
// Cancel the operation on other error.
|
||||
|
||||
CancelTransfer(hidHandle, readHandle, writeHandle, eventObject);
|
||||
Debug.WriteLine("Readfile undefined error");
|
||||
success = false;
|
||||
myDeviceDetected = false;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
if (success)
|
||||
{
|
||||
// A report was received.
|
||||
// Copy the received data to inputReportBuffer for the application to use.
|
||||
|
||||
Marshal.Copy(nonManagedBuffer, inputReportBuffer, 0, numberOfBytesRead);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DisplayException(ModuleName, ex);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For reports the host sends to the device.
|
||||
/// </summary>
|
||||
|
||||
internal abstract class ReportOut
|
||||
{
|
||||
/// <summary>
|
||||
/// Each class that handles writing reports defines a Write method for
|
||||
/// writing a type of report.
|
||||
/// </summary>
|
||||
///
|
||||
/// <param name="reportBuffer"> contains the report ID and report data. </param>
|
||||
/// <param name="deviceHandle"> handle to the device. </param>
|
||||
///
|
||||
/// <returns>
|
||||
/// True on success. False on failure.
|
||||
/// </returns>
|
||||
|
||||
internal abstract Boolean Write(Byte[] reportBuffer, SafeFileHandle deviceHandle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For Feature reports the host sends to the device.
|
||||
/// </summary>
|
||||
|
||||
internal class OutFeatureReport : ReportOut
|
||||
{
|
||||
/// <summary>
|
||||
/// writes a Feature report to the device.
|
||||
/// </summary>
|
||||
///
|
||||
/// <param name="outFeatureReportBuffer"> contains the report ID and report data. </param>
|
||||
/// <param name="hidHandle"> handle to the device. </param>
|
||||
///
|
||||
/// <returns>
|
||||
/// True on success. False on failure.
|
||||
/// </returns>
|
||||
|
||||
internal override Boolean Write(Byte[] outFeatureReportBuffer, SafeFileHandle hidHandle)
|
||||
{
|
||||
try
|
||||
{
|
||||
// ***
|
||||
// API function: HidD_SetFeature
|
||||
|
||||
// Purpose: Attempts to send a Feature report to the device.
|
||||
|
||||
// Accepts:
|
||||
// A handle to a HID
|
||||
// A pointer to a buffer containing the report ID and report
|
||||
// The size of the buffer.
|
||||
|
||||
// Returns: true on success, false on failure.
|
||||
// ***
|
||||
|
||||
Boolean success = HidD_SetFeature(hidHandle, outFeatureReportBuffer, outFeatureReportBuffer.Length);
|
||||
|
||||
Debug.Print("HidD_SetFeature success = " + success);
|
||||
|
||||
return success;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DisplayException(ModuleName, ex);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For writing Output reports via control transfers
|
||||
/// </summary>
|
||||
|
||||
internal class OutputReportViaControlTransfer : ReportOut
|
||||
{
|
||||
/// <summary>
|
||||
/// writes an Output report to the device using a control transfer.
|
||||
/// </summary>
|
||||
///
|
||||
/// <param name="outputReportBuffer"> contains the report ID and report data. </param>
|
||||
/// <param name="hidHandle"> handle to the device. </param>
|
||||
///
|
||||
/// <returns>
|
||||
/// True on success. False on failure.
|
||||
/// </returns>
|
||||
|
||||
internal override Boolean Write(Byte[] outputReportBuffer, SafeFileHandle hidHandle)
|
||||
{
|
||||
try
|
||||
{
|
||||
// ***
|
||||
// API function: HidD_SetOutputReport
|
||||
|
||||
// Purpose:
|
||||
// Attempts to send an Output report to the device using a control transfer.
|
||||
// Requires Windows XP or later.
|
||||
|
||||
// Accepts:
|
||||
// A handle to a HID
|
||||
// A pointer to a buffer containing the report ID and report
|
||||
// The size of the buffer.
|
||||
|
||||
// Returns: true on success, false on failure.
|
||||
// ***
|
||||
|
||||
Boolean success = HidD_SetOutputReport(hidHandle, outputReportBuffer, outputReportBuffer.Length + 1);
|
||||
|
||||
Debug.Print("HidD_SetOutputReport success = " + success);
|
||||
|
||||
return success;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DisplayException(ModuleName, ex);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For Output reports the host sends to the device.
|
||||
/// Uses interrupt or control transfers depending on the device and OS.
|
||||
/// </summary>
|
||||
|
||||
internal class OutputReportViaInterruptTransfer : ReportOut
|
||||
{
|
||||
/// <summary>
|
||||
/// writes an Output report to the device.
|
||||
/// </summary>
|
||||
///
|
||||
/// <param name="outputReportBuffer"> contains the report ID and report data. </param>
|
||||
/// <param name="writeHandle"> handle to the device. </param>
|
||||
///
|
||||
/// <returns>
|
||||
/// True on success. False on failure.
|
||||
/// </returns>
|
||||
|
||||
internal override Boolean Write(Byte[] outputReportBuffer, SafeFileHandle writeHandle)
|
||||
{
|
||||
try
|
||||
{
|
||||
// The host will use an interrupt transfer if the the HID has an interrupt OUT
|
||||
// endpoint (requires USB 1.1 or later) AND the OS is NOT Windows 98 Gold (original version).
|
||||
// Otherwise the the host will use a control transfer.
|
||||
// The application doesn't have to know or care which type of transfer is used.
|
||||
|
||||
Int32 numberOfBytesWritten = 0;
|
||||
|
||||
// ***
|
||||
// API function: WriteFile
|
||||
|
||||
// Purpose: writes an Output report to the device.
|
||||
|
||||
// Accepts:
|
||||
// A handle returned by CreateFile
|
||||
// An integer to hold the number of bytes written.
|
||||
|
||||
// Returns: True on success, False on failure.
|
||||
// ***
|
||||
|
||||
Boolean success = FileIODeclarations.WriteFile(writeHandle, outputReportBuffer, outputReportBuffer.Length, ref numberOfBytesWritten, IntPtr.Zero);
|
||||
|
||||
Debug.Print("WriteFile success = " + success);
|
||||
|
||||
if (!((success)))
|
||||
{
|
||||
|
||||
if ((!(writeHandle.IsInvalid)))
|
||||
{
|
||||
writeHandle.Close();
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DisplayException(ModuleName, ex);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove any Input reports waiting in the buffer.
|
||||
/// </summary>
|
||||
///
|
||||
/// <param name="hidHandle"> a handle to a device. </param>
|
||||
///
|
||||
/// <returns>
|
||||
/// True on success, False on failure.
|
||||
/// </returns>
|
||||
|
||||
internal Boolean FlushQueue(SafeFileHandle hidHandle)
|
||||
{
|
||||
try
|
||||
{
|
||||
// ***
|
||||
// API function: HidD_FlushQueue
|
||||
|
||||
// Purpose: Removes any Input reports waiting in the buffer.
|
||||
|
||||
// Accepts: a handle to the device.
|
||||
|
||||
// Returns: True on success, False on failure.
|
||||
// ***
|
||||
|
||||
Boolean success = HidD_FlushQueue(hidHandle);
|
||||
|
||||
return success;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DisplayException(ModuleName, ex);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a structure with information about a device's capabilities.
|
||||
/// </summary>
|
||||
///
|
||||
/// <param name="hidHandle"> a handle to a device. </param>
|
||||
///
|
||||
/// <returns>
|
||||
/// An HIDP_CAPS structure.
|
||||
/// </returns>
|
||||
|
||||
internal HidpCaps GetDeviceCapabilities(SafeFileHandle hidHandle)
|
||||
{
|
||||
IntPtr preparsedData = new IntPtr();
|
||||
|
||||
try
|
||||
{
|
||||
// ***
|
||||
// API function: HidD_GetPreparsedData
|
||||
|
||||
// Purpose: retrieves a pointer to a buffer containing information about the device's capabilities.
|
||||
// HidP_GetCaps and other API functions require a pointer to the buffer.
|
||||
|
||||
// Requires:
|
||||
// A handle returned by CreateFile.
|
||||
// A pointer to a buffer.
|
||||
|
||||
// Returns:
|
||||
// True on success, False on failure.
|
||||
// ***
|
||||
|
||||
HidD_GetPreparsedData(hidHandle, ref preparsedData);
|
||||
|
||||
// ***
|
||||
// API function: HidP_GetCaps
|
||||
|
||||
// Purpose: find out a device's capabilities.
|
||||
// For standard devices such as joysticks, you can find out the specific
|
||||
// capabilities of the device.
|
||||
// For a custom device where the software knows what the device is capable of,
|
||||
// this call may be unneeded.
|
||||
|
||||
// Accepts:
|
||||
// A pointer returned by HidD_GetPreparsedData
|
||||
// A pointer to a HIDP_CAPS structure.
|
||||
|
||||
// Returns: True on success, False on failure.
|
||||
// ***
|
||||
|
||||
Int32 result = HidP_GetCaps(preparsedData, ref Capabilities);
|
||||
if ((result != 0))
|
||||
{
|
||||
Debug.WriteLine("");
|
||||
Debug.WriteLine(" Usage: " + Convert.ToString(Capabilities.Usage, 16));
|
||||
Debug.WriteLine(" Usage Page: " + Convert.ToString(Capabilities.UsagePage, 16));
|
||||
Debug.WriteLine(" Input Report Byte Length: " + Capabilities.InputReportByteLength);
|
||||
Debug.WriteLine(" Output Report Byte Length: " + Capabilities.OutputReportByteLength);
|
||||
Debug.WriteLine(" Feature Report Byte Length: " + Capabilities.FeatureReportByteLength);
|
||||
Debug.WriteLine(" Number of Link Collection Nodes: " + Capabilities.NumberLinkCollectionNodes);
|
||||
Debug.WriteLine(" Number of Input Button Caps: " + Capabilities.NumberInputButtonCaps);
|
||||
Debug.WriteLine(" Number of Input Value Caps: " + Capabilities.NumberInputValueCaps);
|
||||
Debug.WriteLine(" Number of Input Data Indices: " + Capabilities.NumberInputDataIndices);
|
||||
Debug.WriteLine(" Number of Output Button Caps: " + Capabilities.NumberOutputButtonCaps);
|
||||
Debug.WriteLine(" Number of Output Value Caps: " + Capabilities.NumberOutputValueCaps);
|
||||
Debug.WriteLine(" Number of Output Data Indices: " + Capabilities.NumberOutputDataIndices);
|
||||
Debug.WriteLine(" Number of Feature Button Caps: " + Capabilities.NumberFeatureButtonCaps);
|
||||
Debug.WriteLine(" Number of Feature Value Caps: " + Capabilities.NumberFeatureValueCaps);
|
||||
Debug.WriteLine(" Number of Feature Data Indices: " + Capabilities.NumberFeatureDataIndices);
|
||||
|
||||
// ***
|
||||
// API function: HidP_GetValueCaps
|
||||
|
||||
// Purpose: retrieves a buffer containing an array of HidP_ValueCaps structures.
|
||||
// Each structure defines the capabilities of one value.
|
||||
// This application doesn't use this data.
|
||||
|
||||
// Accepts:
|
||||
// A report type enumerator from hidpi.h,
|
||||
// A pointer to a buffer for the returned array,
|
||||
// The NumberInputValueCaps member of the device's HidP_Caps structure,
|
||||
// A pointer to the PreparsedData structure returned by HidD_GetPreparsedData.
|
||||
|
||||
// Returns: True on success, False on failure.
|
||||
// ***
|
||||
|
||||
|
||||
Int32 vcSize = Capabilities.NumberInputValueCaps;
|
||||
Byte[] valueCaps = new Byte[vcSize];
|
||||
HidP_GetValueCaps(HidPInput, valueCaps, ref vcSize, preparsedData);
|
||||
|
||||
//result = HidP_GetValueCaps(HidP_Input, ref valueCaps[0], ref Capabilities.NumberInputValueCaps, preparsedData);
|
||||
|
||||
// (To use this data, copy the ValueCaps byte array into an array of structures.)
|
||||
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DisplayException(ModuleName, ex);
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
// ***
|
||||
// API function: HidD_FreePreparsedData
|
||||
|
||||
// Purpose: frees the buffer reserved by HidD_GetPreparsedData.
|
||||
|
||||
// Accepts: A pointer to the PreparsedData structure returned by HidD_GetPreparsedData.
|
||||
|
||||
// Returns: True on success, False on failure.
|
||||
// ***
|
||||
|
||||
if (preparsedData != IntPtr.Zero)
|
||||
{
|
||||
HidD_FreePreparsedData(preparsedData);
|
||||
}
|
||||
}
|
||||
|
||||
return Capabilities;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a 32-bit Usage from the Usage Page and Usage ID.
|
||||
/// Determines whether the Usage is a system mouse or keyboard.
|
||||
/// Can be modified to detect other Usages.
|
||||
/// </summary>
|
||||
///
|
||||
/// <param name="capabilities"> a HIDP_CAPS structure retrieved with HidP_GetCaps. </param>
|
||||
///
|
||||
/// <returns>
|
||||
/// A String describing the Usage.
|
||||
/// </returns>
|
||||
|
||||
internal String GetHidUsage(HidpCaps capabilities)
|
||||
{
|
||||
String usageDescription = "";
|
||||
|
||||
try
|
||||
{
|
||||
// Create32-bit Usage from Usage Page and Usage ID.
|
||||
|
||||
Int32 usage = capabilities.UsagePage * 256 + capabilities.Usage;
|
||||
|
||||
if (usage == Convert.ToInt32(0X102))
|
||||
{
|
||||
usageDescription = "mouse";
|
||||
}
|
||||
|
||||
if (usage == Convert.ToInt32(0X106))
|
||||
{
|
||||
usageDescription = "keyboard";
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DisplayException(ModuleName, ex);
|
||||
throw;
|
||||
}
|
||||
|
||||
return usageDescription;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the number of Input reports the host can store.
|
||||
/// </summary>
|
||||
///
|
||||
/// <param name="hidDeviceObject"> a handle to a device </param>
|
||||
/// <param name="numberOfInputBuffers"> an integer to hold the returned value. </param>
|
||||
///
|
||||
/// <returns>
|
||||
/// True on success, False on failure.
|
||||
/// </returns>
|
||||
|
||||
internal Boolean GetNumberOfInputBuffers(SafeFileHandle hidDeviceObject, ref Int32 numberOfInputBuffers)
|
||||
{
|
||||
try
|
||||
{
|
||||
Boolean success;
|
||||
if (!IsWindows98Gold())
|
||||
{
|
||||
// ***
|
||||
// API function: HidD_GetNumInputBuffers
|
||||
|
||||
// Purpose: retrieves the number of Input reports the host can store.
|
||||
// Not supported by Windows 98 Gold.
|
||||
// If the buffer is full and another report arrives, the host drops the
|
||||
// ldest report.
|
||||
|
||||
// Accepts: a handle to a device and an integer to hold the number of buffers.
|
||||
|
||||
// Returns: True on success, False on failure.
|
||||
// ***
|
||||
|
||||
success = HidD_GetNumInputBuffers(hidDeviceObject, ref numberOfInputBuffers);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Under Windows 98 Gold, the number of buffers is fixed at 2.
|
||||
|
||||
numberOfInputBuffers = 2;
|
||||
success = true;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DisplayException(ModuleName, ex);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// sets the number of input reports the host will store.
|
||||
/// Requires Windows XP or later.
|
||||
/// </summary>
|
||||
///
|
||||
/// <param name="hidDeviceObject"> a handle to the device.</param>
|
||||
/// <param name="numberBuffers"> the requested number of input reports. </param>
|
||||
///
|
||||
/// <returns>
|
||||
/// True on success. False on failure.
|
||||
/// </returns>
|
||||
|
||||
internal Boolean SetNumberOfInputBuffers(SafeFileHandle hidDeviceObject, Int32 numberBuffers)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!IsWindows98Gold())
|
||||
{
|
||||
// ***
|
||||
// API function: HidD_SetNumInputBuffers
|
||||
|
||||
// Purpose: Sets the number of Input reports the host can store.
|
||||
// If the buffer is full and another report arrives, the host drops the
|
||||
// oldest report.
|
||||
|
||||
// Requires:
|
||||
// A handle to a HID
|
||||
// An integer to hold the number of buffers.
|
||||
|
||||
// Returns: true on success, false on failure.
|
||||
// ***
|
||||
|
||||
HidD_SetNumInputBuffers(hidDeviceObject, numberBuffers);
|
||||
return true;
|
||||
}
|
||||
// Not supported under Windows 98 Gold.
|
||||
|
||||
return false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DisplayException(ModuleName, ex);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find out if the current operating system is Windows XP or later.
|
||||
/// (Windows XP or later is required for HidD_GetInputReport and HidD_SetInputReport.)
|
||||
/// </summary>
|
||||
|
||||
internal Boolean IsWindowsXpOrLater()
|
||||
{
|
||||
try
|
||||
{
|
||||
OperatingSystem myEnvironment = Environment.OSVersion;
|
||||
|
||||
// Windows XP is version 5.1.
|
||||
|
||||
Version versionXP = new Version(5, 1);
|
||||
|
||||
if (myEnvironment.Version >= versionXP)
|
||||
{
|
||||
Debug.Write("The OS is Windows XP or later.");
|
||||
return true;
|
||||
}
|
||||
|
||||
Debug.Write("The OS is earlier than Windows XP.");
|
||||
return false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DisplayException(ModuleName, ex);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find out if the current operating system is Windows 98 Gold (original version).
|
||||
/// Windows 98 Gold does not support the following:
|
||||
/// Interrupt OUT transfers (WriteFile uses control transfers and Set_Report).
|
||||
/// HidD_GetNumInputBuffers and HidD_SetNumInputBuffers
|
||||
/// (Not yet tested on a Windows 98 Gold system.)
|
||||
/// </summary>
|
||||
|
||||
internal Boolean IsWindows98Gold()
|
||||
{
|
||||
try
|
||||
{
|
||||
OperatingSystem myEnvironment = Environment.OSVersion;
|
||||
|
||||
// Windows 98 Gold is version 4.10 with a build number less than 2183.
|
||||
|
||||
Version version98Se = new Version(4, 10, 2183);
|
||||
|
||||
Boolean result;
|
||||
if (myEnvironment.Version < version98Se)
|
||||
{
|
||||
Debug.Write("The OS is Windows 98 Gold.");
|
||||
result = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Write("The OS is more recent than Windows 98 Gold.");
|
||||
result = false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DisplayException(ModuleName, ex);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides a central mechanism for exception handling.
|
||||
/// Displays a message box that describes the exception.
|
||||
/// </summary>
|
||||
///
|
||||
/// <param name="moduleName"> the module where the exception occurred. </param>
|
||||
/// <param name="e"> the exception </param>
|
||||
|
||||
internal static void DisplayException(String moduleName, Exception e)
|
||||
{
|
||||
// Create an error message.
|
||||
|
||||
string message = "Exception: " + e.Message + "\r\n" + "Module: " + moduleName + "\r\n" + "Method: " + e.TargetSite.Name;
|
||||
|
||||
//MessageBox.Show(message, caption, MessageBoxButtons.OK);
|
||||
Debug.Write(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
87
Delcom/HIDDeclarations.cs
Normal file
87
Delcom/HIDDeclarations.cs
Normal file
@@ -0,0 +1,87 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
namespace WorkIndicator.Delcom
|
||||
{
|
||||
internal sealed partial class HID
|
||||
{
|
||||
// API declarations for HID communications.
|
||||
|
||||
// from hidpi.h
|
||||
// Typedef enum defines a set of integer constants for HidP_Report_Type
|
||||
|
||||
internal const Int16 HidPInput = 0;
|
||||
internal const Int16 HidPOutput = 1;
|
||||
internal const Int16 HidPFeature = 2;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HiddAttributes
|
||||
{
|
||||
internal Int32 Size;
|
||||
internal UInt16 VendorID;
|
||||
internal UInt16 ProductID;
|
||||
internal UInt16 VersionNumber;
|
||||
}
|
||||
|
||||
internal struct HidpCaps
|
||||
{
|
||||
internal Int16 Usage;
|
||||
internal Int16 UsagePage;
|
||||
internal Int16 InputReportByteLength;
|
||||
internal Int16 OutputReportByteLength;
|
||||
internal Int16 FeatureReportByteLength;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)]
|
||||
internal Int16[] Reserved;
|
||||
internal Int16 NumberLinkCollectionNodes;
|
||||
internal Int16 NumberInputButtonCaps;
|
||||
internal Int16 NumberInputValueCaps;
|
||||
internal Int16 NumberInputDataIndices;
|
||||
internal Int16 NumberOutputButtonCaps;
|
||||
internal Int16 NumberOutputValueCaps;
|
||||
internal Int16 NumberOutputDataIndices;
|
||||
internal Int16 NumberFeatureButtonCaps;
|
||||
internal Int16 NumberFeatureValueCaps;
|
||||
internal Int16 NumberFeatureDataIndices;
|
||||
}
|
||||
|
||||
[DllImport("hid.dll", SetLastError = true)]
|
||||
internal static extern Boolean HidD_FlushQueue(SafeFileHandle hidDeviceObject);
|
||||
|
||||
[DllImport("hid.dll", SetLastError = true)]
|
||||
internal static extern Boolean HidD_FreePreparsedData(IntPtr preparsedData);
|
||||
|
||||
[DllImport("hid.dll", SetLastError = true)]
|
||||
internal static extern Boolean HidD_GetAttributes(SafeFileHandle hidDeviceObject, ref HiddAttributes hiddAttributes);
|
||||
|
||||
[DllImport("hid.dll", SetLastError = true)]
|
||||
internal static extern Boolean HidD_GetFeature(SafeFileHandle hidDeviceObject, Byte[] lpReportBuffer, Int32 reportBufferLength);
|
||||
|
||||
[DllImport("hid.dll", SetLastError = true)]
|
||||
internal static extern Boolean HidD_GetInputReport(SafeFileHandle hidDeviceObject, Byte[] lpReportBuffer, Int32 reportBufferLength);
|
||||
|
||||
[DllImport("hid.dll", SetLastError = true)]
|
||||
internal static extern void HidD_GetHidGuid(ref Guid hidGuid);
|
||||
|
||||
[DllImport("hid.dll", SetLastError = true)]
|
||||
internal static extern Boolean HidD_GetNumInputBuffers(SafeFileHandle hidDeviceObject, ref Int32 numberBuffers);
|
||||
|
||||
[DllImport("hid.dll", SetLastError = true)]
|
||||
internal static extern Boolean HidD_GetPreparsedData(SafeFileHandle hidDeviceObject, ref IntPtr preparsedData);
|
||||
|
||||
[DllImport("hid.dll", SetLastError = true)]
|
||||
internal static extern Boolean HidD_SetFeature(SafeFileHandle hidDeviceObject, Byte[] lpReportBuffer, Int32 reportBufferLength);
|
||||
|
||||
[DllImport("hid.dll", SetLastError = true)]
|
||||
internal static extern Boolean HidD_SetNumInputBuffers(SafeFileHandle hidDeviceObject, Int32 numberBuffers);
|
||||
|
||||
[DllImport("hid.dll", SetLastError = true)]
|
||||
internal static extern Boolean HidD_SetOutputReport(SafeFileHandle hidDeviceObject, Byte[] lpReportBuffer, Int32 reportBufferLength);
|
||||
|
||||
[DllImport("hid.dll", SetLastError = true)]
|
||||
internal static extern Int32 HidP_GetCaps(IntPtr preparsedData, ref HidpCaps capabilities);
|
||||
|
||||
[DllImport("hid.dll", SetLastError = true)]
|
||||
internal static extern Int32 HidP_GetValueCaps(Int32 reportType, Byte[] valueCaps, ref Int32 valueCapsLength, IntPtr preparsedData);
|
||||
}
|
||||
}
|
||||
130
Delcom/StoplightIndicator.cs
Normal file
130
Delcom/StoplightIndicator.cs
Normal file
@@ -0,0 +1,130 @@
|
||||
using System;
|
||||
|
||||
using Common.Extensions;
|
||||
|
||||
namespace WorkIndicator.Delcom
|
||||
{
|
||||
public class StoplightIndicator : IDisposable
|
||||
{
|
||||
public enum Light
|
||||
{
|
||||
Green,
|
||||
Yellow,
|
||||
Red
|
||||
}
|
||||
|
||||
public enum LightState
|
||||
{
|
||||
Off,
|
||||
On,
|
||||
Blink
|
||||
}
|
||||
|
||||
private readonly Delcom _delcom;
|
||||
|
||||
private LightState _green = LightState.Off;
|
||||
private LightState _yellow = LightState.Off;
|
||||
private LightState _red = LightState.Off;
|
||||
|
||||
public StoplightIndicator()
|
||||
{
|
||||
_delcom = new Delcom();
|
||||
_delcom.Open();
|
||||
|
||||
SetLights(_red, _yellow, _green);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_delcom.Close();
|
||||
}
|
||||
|
||||
public Delcom Device
|
||||
{
|
||||
get { return _delcom; }
|
||||
}
|
||||
|
||||
public void GetLights(out LightState red, out LightState yellow, out LightState green)
|
||||
{
|
||||
red = _red;
|
||||
yellow = _yellow;
|
||||
green = _green;
|
||||
}
|
||||
|
||||
public LightState GetLight(Light light)
|
||||
{
|
||||
switch (light)
|
||||
{
|
||||
case Light.Red:
|
||||
return _red;
|
||||
|
||||
case Light.Yellow:
|
||||
return _yellow;
|
||||
|
||||
case Light.Green:
|
||||
return _green;
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("light");
|
||||
}
|
||||
}
|
||||
|
||||
public void SetLights(LightState red, LightState yellow, LightState green)
|
||||
{
|
||||
int port1 = 0;
|
||||
|
||||
_red = red;
|
||||
_yellow = yellow;
|
||||
_green = green;
|
||||
|
||||
port1 = port1.SetBitValue((int) Light.Green, green == LightState.Off);
|
||||
port1 = port1.SetBitValue((int) Light.Yellow, yellow == LightState.Off);
|
||||
port1 = port1.SetBitValue((int) Light.Red, red == LightState.Off);
|
||||
|
||||
_delcom.WritePorts(0, port1);
|
||||
|
||||
int blinkEnable = 0;
|
||||
int blinkDisable = 0;
|
||||
|
||||
if (red == LightState.Blink)
|
||||
blinkEnable = blinkEnable.SetBitValue((int) Light.Red, true);
|
||||
else
|
||||
blinkDisable = blinkDisable.SetBitValue((int) Light.Red, true);
|
||||
|
||||
if (yellow == LightState.Blink)
|
||||
blinkEnable = blinkEnable.SetBitValue((int) Light.Yellow, true);
|
||||
else
|
||||
blinkDisable = blinkDisable.SetBitValue((int) Light.Yellow, true);
|
||||
|
||||
if (green == LightState.Blink)
|
||||
blinkEnable = blinkEnable.SetBitValue((int) Light.Green, true);
|
||||
else
|
||||
blinkDisable = blinkDisable.SetBitValue((int) Light.Green, true);
|
||||
|
||||
_delcom.WriteBlink(blinkDisable, blinkEnable);
|
||||
}
|
||||
|
||||
public void SetLight(Light light, LightState state)
|
||||
{
|
||||
switch (light)
|
||||
{
|
||||
case Light.Red:
|
||||
_red = state;
|
||||
break;
|
||||
|
||||
case Light.Yellow:
|
||||
_yellow = state;
|
||||
break;
|
||||
|
||||
case Light.Green:
|
||||
_green = state;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("light");
|
||||
}
|
||||
|
||||
SetLights(_red, _yellow, _green);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user