// 64-byte Message Services using libhidraw (Linux only)
// Copyright (C)2025, Philip Munts dba Munts Technologies.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
using System;
namespace IO.Objects.Message64.libhidraw
{
///
/// Encapsulates Linux raw HID devices using libsimpleio.
///
public class Messenger : IO.Interfaces.Message64.Messenger
{
private readonly int myfd;
private readonly int timeout;
///
/// Constructor for a single raw HID device.
///
/// Vendor ID.
/// Product ID.
/// Serial Number.
/// Time in milliseconds to wait for
/// read and write operations to complete. Zero means wait
/// forever.
public Messenger(int VID = IO.Devices.USB.Munts.HID.Vendor,
int PID = IO.Devices.USB.Munts.HID.Product, string serial = null,
int timeoutms = 1000)
{
// Validate parameters
if ((VID < 0) || (VID > 65535))
{
throw new Exception("Invalid vendor ID");
}
if ((PID < 0) || (PID > 65535))
{
throw new Exception("Invalid product ID");
}
if (timeoutms < 0)
{
throw new Exception("Invalid timeout");
}
IO.Bindings.libsimpleio.HIDRAW_open3(VID, PID,
serial, out this.myfd, out int error);
if (error != 0)
{
throw new Exception("HIDRAW_open3() failed, " +
errno.strerror(error));
}
this.timeout = timeoutms;
}
///
/// Send a 64-byte command message to a raw HID device.
///
/// 64-byte command message.
public void Send(IO.Interfaces.Message64.Message cmd)
{
IO.Bindings.libsimpleio.HIDRAW_send(this.myfd,
cmd.payload, IO.Interfaces.Message64.Message.Size, out int count,
out int error);
if (error != 0)
{
throw new Exception("HIDRAW_send() failed, " +
errno.strerror(error));
}
}
///
/// Receive a 64-byte response message from a raw HID device.
///
/// 64-byte response message.
public void Receive(IO.Interfaces.Message64.Message resp)
{
int error;
if (this.timeout > 0)
{
int[] files = { this.fd };
int[] events = { IO.Bindings.libsimpleio.POLLIN };
int[] results = { 0 };
IO.Bindings.libsimpleio.LINUX_poll(1, files, events,
results, this.timeout, out error);
if (error != 0)
{
throw new Exception("LINUX_poll() failed, " +
errno.strerror(error));
}
}
IO.Bindings.libsimpleio.HIDRAW_receive(this.myfd,
resp.payload, IO.Interfaces.Message64.Message.Size,
out int count, out error);
if (error != 0)
{
throw new Exception("HIDRAW_send() failed, " +
errno.strerror(error));
}
}
///
/// Send a 64-byte command message and receive a 64-byte response
/// message.
///
/// 64-byte command message.
/// 64-byte response message.
public void Transaction(IO.Interfaces.Message64.Message cmd,
IO.Interfaces.Message64.Message resp)
{
this.Send(cmd);
this.Receive(resp);
}
///
/// Read-only property returning the device information string for a
/// raw HID device.
///
public string name
{
get
{
System.Text.StringBuilder buf =
new System.Text.StringBuilder(256);
IO.Bindings.libsimpleio.HIDRAW_get_name(this.fd, buf,
buf.Capacity, out int error);
if (error != 0)
{
throw new Exception("HIDRAW_get_name() failed, " +
errno.strerror(error));
}
return buf.ToString();
}
}
///
/// Read-only property returning the bus type identifier for a raw HID
/// device.
///
public int bustype
{
get
{
IO.Bindings.libsimpleio.HIDRAW_get_info(this.fd,
out int bus, out int vid, out int pid, out int error);
if (error != 0)
{
throw new Exception("HIDRAW_get_info() failed, " +
errno.strerror(error));
}
return bus;
}
}
///
/// Read-only property returning the vendor identifier for a raw HID
/// device.
///
public int vendor
{
get
{
IO.Bindings.libsimpleio.HIDRAW_get_info(this.fd,
out int bus, out int vid, out int pid, out int error);
if (error != 0)
{
throw new Exception("HIDRAW_get_info() failed, " +
errno.strerror(error));
}
return vid;
}
}
///
/// Read-only property returning the product identifier for a raw HID
/// device.
///
public int product
{
get
{
IO.Bindings.libsimpleio.HIDRAW_get_info(this.fd,
out int bus, out int vid, out int pid, out int error);
if (error != 0)
{
throw new Exception("HIDRAW_get_info() failed, " +
errno.strerror(error));
}
return pid;
}
}
///
/// Read-only property returning the Linux file descriptor for a raw
/// HID device.
///
public int fd
{
get
{
return this.myfd;
}
}
}
}