我一直在使用C和HIDAPI,并试图让Mono使用interop与HIDAPI进行通信。我已经做了很多搜索,并且找不到任何已经让HIDAPI在OS X上使用Mono的人。
有没有人知道我是否可以使用HIDAPI将输出从HID设备重定向到本地虚拟串行端口,然后让Mono只是从串口读取?
另一种选择,有人会知道我是否可以使用像Arduino leonardo或Circuits @ Home USB Host Shield这样的东西?
至少在我可以在单声道上整理PInvoke之前。
谢谢
答案 0 :(得分:2)
我从其他地方找到并改编了这个代码,虽然我不能为我的生活找到源头。如果有人知道,请告诉我,以便我可以正确归因并链接到它。它在Windows和OS X上都很适合我。显然,你必须为每个平台构建hidapi。
using System;
using System.Globalization;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
namespace HidApiCommunicationLayer
{
internal class HidApiInteropCommLayer
{
#region Interop
#if WINDOWS
private const string HIDAPI_DLL = "hidapi.dll";
#else
private const string HIDAPI_DLL = "hidapi.dylib";
#endif
protected IntPtr _device;
private Object _locker = new object();
public bool IsOpen()
{
return _device != IntPtr.Zero;
}
public void Open(ushort vid, ushort hid, string serial)
{
if (_device != IntPtr.Zero) throw new Exception("a device is already opened; close it first.");
IntPtr ret = hid_open(vid, hid, serial);
_device = ret;
//if (_device != IntPtr.Zero)
// hid_set_nonblocking(_device, true);
}
public int Read(byte[] buffer, int length)
{
lock (_locker)
{
AssertValidDev();
int ret = hid_read_timeout(_device, buffer, (uint)length, 1);
if (ret < 0)
throw new Exception("Failed to Read.");
return ret;
}
}
public void Close()
{
AssertValidDev();
hid_close(_device);
_device = IntPtr.Zero;
}
public int ExitHidAPI()
{
return hid_exit();
}
public String GetProductString()
{
AssertValidDev();
byte[] buf = new byte[1000];
int ret = HidApiInteropCommLayer.hid_get_product_string(_device, buf, (uint)(buf.Length / 4) - 1);
if (ret < 0)
throw new Exception("failed to receive product string");
return EncodeBuffer(buf);
}
public String GetManufacturerString()
{
AssertValidDev();
byte[] buf = new byte[1000];
int ret = HidApiInteropCommLayer.hid_get_manufacturer_string(_device, buf, (uint)(buf.Length / 4) - 1);
if (ret < 0)
throw new Exception("failed to receive manufacturer string");
return EncodeBuffer(buf);
}
public int GetFeatureReport(byte[] buffer, int length)
{
AssertValidDev();
int ret = hid_get_feature_report(_device, buffer, (uint)length);
if (ret < 0)
throw new Exception("failed to get feature report");
return ret;
}
public int SendFeatureReport(byte[] buffer)
{
int ret = hid_send_feature_report(_device, buffer, (uint)buffer.Length);
//if (ret < 0)
// throw new Exception ("failed to send feature report");
return ret;
}
public int Write(byte[] buffer)
{
lock (_locker)
{
AssertValidDev();
int ret = hid_write(_device, buffer, HID_MAX_PACKET_SIZE + 1);
//if (ret < 0)
// Custom logging
return ret;
}
}
public String Error()
{
AssertValidDev();
IntPtr ret = hid_error(_device);
return Marshal.PtrToStringAuto(ret);
}
public string GetIndexedString(int index)
{
AssertValidDev();
byte[] buf = new byte[1000];
int ret = HidApiInteropCommLayer.hid_get_indexed_string(_device, index, buf, (uint)(buf.Length / 4) - 1);
if (ret < 0)
throw new Exception("failed to receive indexed string");
return EncodeBuffer(buf);
}
public string GetSerialNumberString()
{
AssertValidDev();
byte[] buf = new byte[1000];
int ret = HidApiInteropCommLayer.hid_get_serial_number_string(_device, buf, (uint)(buf.Length / 4) - 1);
if (ret < 0)
throw new Exception("failed to receive serial number string");
return EncodeBuffer(buf);
}
private string EncodeBuffer(byte[] buffer)
{
return Encoding.Unicode.GetString(buffer).Trim('\0');
}
private void AssertValidDev()
{
if (_device == IntPtr.Zero) throw new Exception("No device opened");
}
#region DllImports
[DllImport(HIDAPI_DLL)]
private static extern int hid_read(IntPtr device, [Out, MarshalAs(UnmanagedType.LPArray)] byte[] data, uint length);
[DllImport(HIDAPI_DLL)]
private static extern int hid_read_timeout(IntPtr device, [Out, MarshalAs(UnmanagedType.LPArray)] byte[] data, uint length, int timeout);
[DllImport(HIDAPI_DLL)]
private static extern IntPtr hid_open(ushort vid, ushort pid, [MarshalAs(UnmanagedType.LPWStr)] string serial);
[DllImport(HIDAPI_DLL)]
private static extern void hid_close(IntPtr device);
[DllImport(HIDAPI_DLL)]
private static extern int hid_init();
[DllImport(HIDAPI_DLL)]
private static extern int hid_exit();
[DllImport(HIDAPI_DLL)]
private static extern int hid_get_product_string(IntPtr device, [Out] byte[] _string, uint length);
[DllImport(HIDAPI_DLL)]
private static extern int hid_get_manufacturer_string(IntPtr device, [Out] byte[] _string, uint length);
[DllImport(HIDAPI_DLL)]
private static extern int hid_get_feature_report(IntPtr device, [Out, MarshalAs(UnmanagedType.LPArray)] byte[] data, uint length);
[DllImport(HIDAPI_DLL)]
private static extern int hid_get_serial_number_string(IntPtr device, [Out] byte[] serial, uint maxlen);
[DllImport(HIDAPI_DLL)]
private static extern int hid_get_indexed_string(IntPtr device, int string_index, [Out] byte[] _string, uint maxlen);
[DllImport(HIDAPI_DLL)]
private static extern IntPtr hid_error(IntPtr device);
[DllImport(HIDAPI_DLL)]
private static extern int hid_send_feature_report(IntPtr device, [In, MarshalAs(UnmanagedType.LPArray)] byte[] data, uint length);
[DllImport(HIDAPI_DLL)]
private static extern int hid_set_nonblocking(IntPtr device, [In, MarshalAs(UnmanagedType.SysInt)] bool nonblock);
[DllImport(HIDAPI_DLL)]
private static extern int hid_write(IntPtr device, [In, MarshalAs(UnmanagedType.LPArray)] byte[] data, uint length);
[DllImport(HIDAPI_DLL)]
private static extern IntPtr hid_open_path([In, MarshalAs(UnmanagedType.LPStr)] string path);
#endregion DllImports
#endregion Interop
#region Constructors
public static HidApiInteropCommLayer GetDevice(ushort vid, ushort pid)
{
try
{
HidApiInteropCommLayer layer = new HidApiInteropCommLayer();
layer.Open(vid, pid, null);
return layer._device == IntPtr.Zero ? null : layer;
}
catch (System.BadImageFormatException fx)
{
//Custom logging
return null;
}
catch (Exception ex)
{
//Custom logging
return null;
}
}
#endregion Constructors
private const int HID_MAX_PACKET_SIZE = 1024;
#region ICommunicationLayer
public void Init()
{
try
{
if (IsOpen())
{
ContinueReadProcessing = true;
ReadThread = new Thread(new ThreadStart(ReadLoop));
ReadThread.Name = "HidApiReadThread";
ReadThread.Start();
}
else
{
Disconnect();
}
}
catch (Exception ex)
{
//Custom logging
throw;
}
}
public bool SendData(byte[] data)
{
try
{
MemoryStream stream = new MemoryStream(HID_MAX_PACKET_SIZE + 1);
stream.WriteByte(0);
stream.Write(data, 0, HID_MAX_PACKET_SIZE);
int ret = Write(stream.ToArray());
if (ret >= 0)
return true;
else
{
return false;
}
}
catch (Exception ex)
{
//Custom logging
return false;
}
}
public event EventHandler<DataEventArgs> DataReceived;
public event EventHandler Disconnected;
public void Start()
{
ContinueReadProcessing = true;
}
public void Stop()
{
Disconnect();
}
#endregion ICommunicationLayer
private Thread ReadThread = null;
protected volatile bool ContinueReadProcessing = true;
private void ReadLoop()
{
var culture = CultureInfo.InvariantCulture;
Thread.CurrentThread.CurrentCulture = culture;
Thread.CurrentThread.CurrentUICulture = culture;
Thread.CurrentThread.Priority = ThreadPriority.AboveNormal;
while (ContinueReadProcessing)
{
try
{
byte[] report = new byte[HID_MAX_PACKET_SIZE];
var result = Read(report, HID_MAX_PACKET_SIZE);
if (result > 0)
{
DataReceived(this, new DataEventArgs(report));
}
else if (result < 0)
{
Disconnect();
}
}
catch (Exception ex)
{
Disconnect();
}
Thread.Sleep(1);
}
}
private void Disconnect()
{
ContinueReadProcessing = false;
Disconnected(this, EventArgs.Empty);
}
#region IDisposable Members
public void Dispose()
{
ContinueReadProcessing = false;
ReadThread.Join(500);
if (ReadThread.IsAlive)
{
ReadThread.Abort();
}
if (IsOpen())
Close();
int res = ExitHidAPI();
}
#endregion IDisposable Members
}
internal class Utf32Marshaler : ICustomMarshaler
{
private static Utf32Marshaler instance = new Utf32Marshaler();
public static ICustomMarshaler GetInstance(string s)
{
return instance;
}
public void CleanUpManagedData(object o)
{
}
public void CleanUpNativeData(IntPtr pNativeData)
{
Marshal.FreeHGlobal(pNativeData);
//UnixMarshal.FreeHeap(pNativeData);
}
public int GetNativeDataSize()
{
return IntPtr.Size;
}
public IntPtr MarshalManagedToNative(object obj)
{
string s = obj as string;
if (s == null)
return IntPtr.Zero;
return Marshal.StringToHGlobalAuto(s);
}
public object MarshalNativeToManaged(IntPtr pNativeData)
{
return Marshal.PtrToStringAuto(pNativeData);
}
}
public class DataEventArgs : EventArgs
{
public DataEventArgs(byte[] data)
{
Data = data;
}
public byte[] Data { get; private set; }
}
}
答案 1 :(得分:0)
Arduino Leonardo不能充当USB主机。
原则上,是的,您可以将设备充当设备端的CDC串行端口,并将其作为主机USB连接到HID设备。
或者,您可以完全跳过HIDAPI步骤并使用HidSharp。 :)它将直接调用/调用MacOS X本机API。
希望这有帮助
詹姆斯