应用程序与硬件进行交互(实现硬件绑定、应用程序与硬件通信)

一、前言
    在无操作系统的裸机中,或者类似如DOS这样操作系统中,应用程序和硬件的交互是非常简单的。如果没有操作系统,我们访问硬件空间可能只需一条指令就行,甚至可以访问任意的内存空间或者IO空间。但是在WINDOWS操作系统中,应
    用程序与硬件间被完全隔离开来,应用程序与软件的通信就必须依赖于依赖驱动程序。有点类似于现在的网上购物,卖家相当于硬件,而卖家相当于应用程序,淘宝等类似的购物网站相当于驱动程序,而卖家与买家之间的买卖就得依赖
    于淘宝等类似的购物网站。至于为什么要把硬件层和应用程序隔开,答案是——安全。允许应用程序随意访问硬件是一件很危险的事情,除了可能会造成蓝屏死机之类的问题,还会发生密码的安全性问题。那在我们日常开发过程当中哪
    些场景需要涉及到硬件与软件的交互呢?
    
二、应用程序与硬件交互的场景
    1.读取硬件信息
      当应用程序需要与硬件进行捆绑时,就需要获取对应的硬件信息,例如触摸框绑定、MCU绑定等等,需要读取出对应硬件的信息,并与预期的信息进行比较来判断是否进行了绑定。获取MCU版本号等等。
    
    2.与硬件进行通信
      应用程序与硬件进行通信,比单纯的读取硬件信息稍微复杂一点。例如通过MCU来进行定时开关机,首先需要根据对应的信息查找指定的MCU设备,然后将对应的定时开关机指定发送给MCU,MCU收到信息之后,发送信息给应用程序,告之
    定时开关机的指定是否设置成功。这其中包含了应用程序与硬件之间的通信。
    
    3.硬件的管理
      例如磁盘的管理,我们可以自己编写应用程序对磁盘进行一系列的管理,磁盘分区、磁盘大小等等。移动设备管理工具等等都可以实现。
      
    4.其他
      当然还有很多很多啦....
     
    那么,既然我们提到了这么多得应用场景,那我们如何来实现它们呢?那接下来就不得不提SetupDi这一系列API了。
    
三、SetupDi API

    1.HidD_GetHidGuid
      函数定义
      BOOL
      Hidd_GetHidGuid(
      &guidHID 指向GUID类型的指针
      );
      HID类设备是通过GUID类型值作标识的,调用函数HidD_GetHidGuid颗获得HID设备的标识

    2.SetupDiGetClassDevs
      函数定义
    HDEVINFO
    SetupDiGetClassDevs(
    const GUID *ClassGuid,//HID类设备是通过GUID类型值作标识的,如图1.图Guid示例,通过指向Guid的指针,获取对应的设备列表。
    PCTSTR Enumerator,
    HWND hwndParent,
    DWORD Flags//Flags,当值为DIGCF_ALLCLASSES,该函数会将*ClassGuid忽略掉。
    );
     获取一个指定类别或全部类别的所有已安装设备的信息,其中两个参数需要注意一下。返回值,如果函数运行成功,返回设备信息结构的句柄,该结构包含与指定参数匹配的所有已安装设备。如果失败,则返回INVALID_HANDLE_VALUE。
     
     
   3.SetupDiEnumDeviceInterfaces
     函数定义
     BOOL
     SetupDiEnumDeviceInterfaces(
     HDEVINFO DeviceInfoSet,  //一个指向设备信息集合的句柄,包含设备接口返回信息,通常是SetupDiGetClassDevs的返回
     PSP_DEVINFO_DATA DeviceInfoData,  //指向特定设备的SP_DEVINFO_DATA 类型的指针,
     const GUID *InterfaceClassGuid, //指向制定设备接口类的GUID指针
     DWORD MemberIndex,  //设备信息中接口列表的索引值(初始值为0)
     PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData //指向调用者分配的SP_DEVICE_INTERFACE_DATA类型的内存区域的指针,调用前必须先配置 DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA)
     );
     获取设备列表中指定接口的信息,通过次接口只能获取接口信息,需要取得接口的详细信息需要调用SetupDiGetDeviceInterfaceDetail这个接口。返回值,ture则成功,false为失败。
     
   4.SetupDiGetDeviceInterfaceDetail
     BOOL
     SetupDiGetDeviceInterfaceDetail(
     IN HDEVINFO  DeviceInfoSet,//指向设备信息集的指针,它包含了所要接收信息的接口。该句柄通常由SetupDiGetClassDevs函数返回。
     IN PSP_DEVICE_INTERFACE_DATA  DeviceInterfaceData,//一个指向SP_DEVICE_INTERFACE_DETAIL_DATA结构的指针,该结构用于接收指定接口的信息
     OUT PSP_DEVICE_INTERFACE_DETAIL_DATA  DeviceInterfaceDetailData..OPTIONAL,
     IN DWORD  DeviceInterfaceDetailDataSize,//缓冲的大小。该缓冲的大小不能小于 (offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA, DevicePath) + sizeof(TCHAR)) 字节。
     OUT PDWORD  RequiredSize..OPTIONAL,
     OUT PSP_DEVINFO_DATA  DeviceInfoData  OPTIONAL
     );
     返回设备接口的详细信息。这里需要特别提一下的是,该接口需要调用两次,因为该接口主要是获取设备的路径而路径会放到DeviceDetailData面, 然而每一个设备的路径是不一样的, 所以大小不一定, 所以需要调用两次,第一次
     获取路径的大小,第二次获取具体的路径信息。返回值,ture则成功,false为失败。
 
   5.CreateFile
     函数定义
     HANDLE
     CreateFile(
   LPCTSTR lpFileName, //设备路径
   DWORD dwDesiredAccess, //访问模式(写/读)
   DWORD dwShareMode, //共享模式
   LPSECURITY_ATTRIBUTES lpSecurityAttributes, //指向安全属性的指针
   DWORD dwCreationDisposition, //如何创建
   DWORD dwFlagsAndAttributes, //文件属性
   HANDLE hTemplateFile //用于复制文件句柄
   );
     与设备建立连接,获取相应的属性(设备的供应商标识与产品标识等),应用程序就能够与对应的设备进行通信了。如果调用成功,该函数返回文件的句柄;如果调用失败,则返回INVALID_HANDLE_VALUE,在打开通信设备时,应该以独占方式打开。
     
   6.HidD_GetAttributes
     函数定义
     HidD_GetAttributes(
     SafeFileHandle hidDeviceObject,//对应与选定设备的句柄
     out HiddAttributes attributes,//指向HIDD_ATTRIBUTES类型的指针
     );
     
     //设备属性结构体
    struct HiddAttributes
    {
     int Size;
     ushort VendorId;
     ushort ProductId;
     ushort VersionNumber;       
    };
    获取设备的属性
    
    已经介绍了这么多SetupDi API,那我们如何来利用这些API来实现我们的需求呢?下面就来介绍一下这些API一般情况下使用的步骤。
    
 
四、Setup API使用步骤

   以下相关代码片段为C#。
   1.调用HidD_GetHidGuid,获取Hid设备的Guid。当然,假如我们只需要获取磁盘相关设备的列表,且知道磁盘的Guid为 53f56307-b6bf-11d0-94f2-00a0c91efb8b。则无须调用HidD_GetHidGuid函数。
   
     示例代码:
     var hUsb = Guid.Empty;
     // 取得hid设备全局id
     HidD_GetHidGuid(ref hUsb);
   
  2.执行第1步,或者说知道指定的Guid,调用SetupDiGetClassDevs函数,获取Guid对应的设备集合。
 
    示例代码:
    //取得一个包含所有HID接口信息集合的句柄
    var hidInfoSet = SetupDiGetClassDevs(ref hUsb, 0, IntPtr.Zero, Digcf.DIGCF_PRESENT | Digcf.DIGCF_DEVICEINTERFACE);
    
  3.通过第2步,获取对应的设备列表,我们就可以获取其中某个接口的相关信息,这个时候,需要调用SetupDiEnumDeviceInterfaces来获取接口的信息了。
 
  4.执行完第3步之后,则需要调用SetupDiGetDeviceInterfaceDetail来获取接口的详细信息,主要是获取对应设备的路径,此函数必须连续调用两次,详情见接口说明。
 
    第3、4步的示例代码:
    for (index = 0; index < MaxUsbDevices; index++)
    {
      //得到第index个接口信息
      if (SetupDiEnumDeviceInterfaces(hidInfoSet, IntPtr.Zero, ref hUsb, index, ref interfaceInfo))
      {
         int buffsize = 0;
        // 取得接口详细信息:第一次读取错误,但可以取得信息缓冲区的大小
        SetupDiGetDeviceInterfaceDetail(hidInfoSet, ref interfaceInfo, IntPtr.Zero, buffsize, ref buffsize, null);
        //构建接收缓冲
        var pDetail = Marshal.AllocHGlobal(buffsize);
        var detail = new SpDeviceInterfaceDetailData
        {
           cbSize = Marshal.SizeOf(typeof(SpDeviceInterfaceDetailData))
        };
        Marshal.StructureToPtr(detail, pDetail, false);
        if (SetupDiGetDeviceInterfaceDetail(hidInfoSet, ref interfaceInfo, pDetail, buffsize, ref buffsize, null))
        {
           deviceList.Add(Marshal.PtrToStringAuto((IntPtr)((int)pDetail + 4)));
        }
        Marshal.FreeHGlobal(pDetail);
     }
  }
   
  5.执行完第4步后,可以获取到设备的路径,通过调用CreateFile与设备创建连接之后调用HidD_GetAttributes获取设备对应的属性,执行完这一步,我们就可以完成上述应用场景中的MCU、触摸框等相关硬件的绑定,以及与应用程序通信
  了,如图2. PID,VID属性。例如MCU的供应商标识为0x1ff7,产品标识为0x0f13,应用程序实现MCU绑定了。
     
    示例代码:
    //建立和设备的连接
    _device = CreateFile(device, Desiredaccess.GENERIC_READ | Desiredaccess.GenericWrite, 0, 0, Creationdisposition.OPEN_EXISTING, Flagsandattributes.FILE_FLAG_OVERLAPPED, 0);
      if (_device.IsInvalid) continue;
         HiddAttributes attributes;
        //获取连接属性
        HidD_GetAttributes(_device, out attributes);
        if (attributes.VendorId == vId && attributes.ProductId == pId)
        {
          IntPtr preparseData;
          HidpCaps caps;
            HidD_GetPreparsedData(_device, out preparseData);
             //获取设备具体信息   
             HidP_GetCaps(preparseData, out caps);
             HidD_FreePreparsedData(preparseData);//??
            OutputReportLength = caps.OutputReportByteLength;//获取设备接收到字节的长度
            InputReportLength = caps.InputReportByteLength;//获取设备发送的字节的长度
            //根据设备初始化FileStream实例,通过流来实现数据接收与发送
            _hidDevice = new FileStream(_device, FileAccess.ReadWrite, InputReportLength, true);
            _deviceOpened = true;
            return true;
      }
      
      
  总结:

    通过调用上述API,以及执行对应的步骤,就能够应用程序实现硬件绑定,与硬件进行交互,当然,其中可能会遇到一些问题,需要有耐心,一步一步来。关于磁盘管理、识别大容量的移动设备等,在本文中没有讲到,
  由于时间关系,过几天另起一章总结一下磁盘相关的知识。

 

相关图片:

    图1. 设备Guid示 例 

                                                                                                                                             图2. PID,VID属性

转载于:https://www.cnblogs.com/ForOne/p/3581256.html

深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值