2013-03-12 3 views
1

Я работал с HIDAPI с C и пытался подключить Mono к HIDAPI, используя interop. Я много раз искал и не смог найти тех, кто получил HIDAPI для работы с Mono на OS X.Опции для HIDAPI на OS X

Кто-нибудь знает, могу ли я перенаправить вывод с HID-устройства с помощью HIDAPI на локальный виртуальный последовательный порт, а затем Моно только что прочитал из последовательного порта?

Еще один вариант: кто-нибудь знает, могу ли я использовать что-то вроде Arduino leonardo или Circuits @ Home USB Host Shield?

По крайней мере, пока я не смогу разобраться в PInvoke на Mono.

Благодаря

ответ

0

Arduino Leonardo не может выступать в качестве USB-хоста.

В принципе, да, вы можете заставить устройство действовать как последовательный порт CDC на стороне устройства и заставить его работать как хост-USB для устройства HID.

Кроме того, вы можете полностью пропустить шаг HIDAPI и использовать HidSharp. :) Это будет P/Invoke непосредственно в родные API MacOS X.

Надеется, что это помогает

Джеймс

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; } 
    } 
}