首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >OS X上的HIDAPI选项

OS X上的HIDAPI选项
EN

Stack Overflow用户
提问于 2013-03-13 01:45:57
回答 2查看 964关注 0票数 1

我一直在用C语言处理HIDAPI,并试图让Mono使用互操作与HIDAPI通信。我已经做了很多搜索,但还没有找到任何人能够让HIDAPI在OS X上与Mono一起工作。

谁知道我是否可以使用HIDAPI将HID设备的输出重定向到本地虚拟串行端口,然后让Mono从该串行端口读取数据?

另一种选择,有没有人知道我是否可以使用像Arduino leonardo或Circuit@Home USB Host Shield这样的东西?

至少在我能解决Mono上的PInvoke之前。

谢谢

EN

回答 2

Stack Overflow用户

发布于 2014-04-24 06:58:11

我从其他地方找到并改编了这段代码,尽管我无论如何也找不到源码。如果有人知道,请让我知道,以便我可以正确地属性和链接到它。它对我来说在Windows和OS上都运行得很好。显然,你必须为每种平台构建hidapi。

代码语言:javascript
复制
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; }
    }
}
票数 2
EN

Stack Overflow用户

发布于 2013-05-07 22:25:50

Arduino Leonardo不能充当USB主机。

原则上,是的,您可以让设备充当设备端的CDC串行端口,并使其充当HID设备的主机USB。

或者,您可以完全跳过HIDAPI步骤,而使用HidSharp。:)它将直接P/Invoke到MacOS X原生API。

希望这能有所帮助

詹姆斯

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15368376

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档