- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我有一个销售点应用程序,它使用串行通信端口 (RS-232) 与称重产品的秤进行通信。我现在致力于能够直接支持 USB 设备,而不是使用虚拟串行通信端口,因为它们有令人讨厌的移动倾向。
我们发现,虽然 Windows 7 似乎会自动创建虚拟串行通信端口,但其他版本的 Windows(例如 POS Ready 7)可能不会。我们怀疑这是由于 POS Ready 7 中缺少 Windows 7 的特定 .inf 文件。有人可以确认吗?
我有一个间歇性工作的 USB 示例应用程序。我在与 ReadFile()
的 USB 级通信时遇到问题Windows API 函数。我正在使用 CreateFile()
指定 USB 设备路径以获取 I/O 句柄,然后使用 WriteFile()
和 ReadFile()
与秤沟通。 ReadFile()
在某些情况下不提供数据。
背景资料
我正在使用的特定秤 Brecknell 67xx 台式秤,直接与销售点应用程序一起使用开箱即用的虚拟串行通信端口。我使用 USB 电缆将秤连接到我的 Windows 7 PC,Windows 自动安装驱动程序以创建虚拟串行端口,在我的情况下为 COM4。然后我将应用程序配置为通过 COM4 与秤对话,一切正常。
使用秤的协议(protocol)是向秤发送一个两字节的命令“W\r”(大写字母 W 后跟一个回车符),然后读取一个 16 字节的响应,其中包含当前重量和状态有关比例机制的信息,例如 In Motion。
我正在学习的示例 USB 应用程序将成功提供权重。然后它将停止正常工作与 ReadFile()
的行为返回读取的零字节。一旦它停止工作,它将继续无法提供来自 ReadFile()
的数据。即使我拔下并重新插入 USB 电缆或重新启动我的电脑。
以前版本的学习应用卡在ReadFile()
上并且当使用 Visual Studio 完成 Break All 时,会显示一个暂停,然后显示一条指示死锁的消息。但是自从我开始使用 SetCommTimeouts()
在 ReadTotalTimeoutConstant
中有 5000 毫秒的超时值我在 ReadFile()
之前看到了一致的 5 秒停顿读取零字节返回。
奇怪的是,如果我然后使用打开虚拟串行通信端口 COM4 的应用程序,该应用程序工作正常并且秤会报告元素的重量。
然后我可以返回到使用直接 USB 而不是虚拟串行通信端口的示例应用程序,它可以很好地报告权重。
但是,如果我随后拔下连接秤与 PC 的 USB 电缆,这也会关闭秤的电源,然后重新插入 USB 电缆,示例应用程序将不再正常运行,并且我再次看到超时暂停。
然后我尝试使用依赖于使用虚拟串行端口 COM4 的串行通信端口的原始销售点应用程序,并且该应用程序可以很好地称重元素。
当我然后重试我的示例应用程序时,它也会报告项目权重。
我的问题。
如果 USB 设备在插入时创建了一个虚拟串行通信端口,那么是否只需要通过在 CreateFile()
中指定通信端口(在我的情况下为 COM4)来使用虚拟串行端口。称呼?
如何使用 CreateFile()
进行直接 USB 串行通信如果设备导致 Windows 生成虚拟通信端口,则使用 USB 设备路径?
是否有某种方法可以指定任何版本的 Windows 在插入时自动为设备创建虚拟串行通信端口?
示例 USB 应用程序的源代码
我使用 Visual Studio 2005 的示例 USB Windows 控制台应用程序的源代码如下,主要位于底部,其中大部分是用于查找特定 USB 设备然后允许 ReadFile()
的类。和 WriteFile()
:
// usb_test_cons.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <windows.h>
#include <setupapi.h>
#include <initguid.h>
#include <stdio.h>
// This is the GUID for the USB device class.
// It is defined in the include file Usbiodef.h of the Microsoft Windows Driver Kit.
// See also https://msdn.microsoft.com/en-us/library/windows/hardware/ff545972(v=vs.85).aspx which
// provides basic documentation on this GUID.
DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE, 0xA5DCBF10L, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED);
// (A5DCBF10-6530-11D2-901F-00C04FB951ED)
// Following are standard defines to be used with all of the
// devices that are use through the UIE interface.
#define UIE_DEVICE_ERROR (-11) /* error when accessing the device */
#define UIE_DEVICE_NOT_PROVIDE (-12) /* device is not provided */
#define UIE_DEVICE_ERROR_RANGE (-13) /* range error */
#define UIE_DEVICE_ERROR_COM (-14) /* communication error */
#define UIE_DEVICE_TIMEOUT (-15) /* communication error */
#define UIE_DEVICE_SPECIFIC (-20) /* device specific errors start here */
#define UIE_SCALE_ETX 0x03 /* ETX character */
#define UIE_SCALE_IN_MOTION 0x01 /* scale in motion */
#define UIE_SCALE_ZERO 0x02 /* zero weight */
#define UIE_SCALE_UNDER 0x01 /* under capacity */
#define UIE_SCALE_OVER 0x02 /* over capacity */
#define UIE_SCALE_ERROR UIE_DEVICE_ERROR /* error */
#define UIE_SCALE_NOT_PROVIDE UIE_DEVICE_NOT_PROVIDE /* not provide */
#define UIE_SCALE_TIMEOUT UIE_DEVICE_TIMEOUT /* time out when reading from scale */
#define UIE_SCALE_MOTION (UIE_DEVICE_SPECIFIC-1) /* motion */
#define UIE_SCALE_UNDER_CAPACITY (UIE_DEVICE_SPECIFIC-2) /* under capacity */
#define UIE_SCALE_OVER_CAPACITY (UIE_DEVICE_SPECIFIC-3) /* over capacity */
#define UIE_SCALE_DATAFORMAT (UIE_DEVICE_SPECIFIC-4) /* Data read from scale incorrect format in UieScaleAnalysis() */
#define UIE_SCALE_DATAUNITS (UIE_DEVICE_SPECIFIC-5) /* Units read from scale incorrect in UieScaleAnalysis() */
static SHORT UieScaleStatus(char *puchBuffer, DWORD sLength)
{
UCHAR uchByte;
switch (sLength) {
case 16:
// The scale message is a weight message with a status section.
// Move the buffer pointer to where the status section should begin.
// A status only message has the same format as the status section of a weight message.
puchBuffer += 10;
case 6:
// The scale message may be a status only message if there is a problem with the scale.
// A status only message is 6 characters with the letter S as the second character.
if (*(puchBuffer + 0) != '\n' ||
*(puchBuffer + 1) != 'S' ||
*(puchBuffer + 4) != '\r' ||
*(puchBuffer + 5) != UIE_SCALE_ETX) {
return (UIE_SCALE_DATAFORMAT); /* exit ... */
}
break;
default:
return (UIE_SCALE_DATAFORMAT); /* exit ... */
break;
}
/* --- check status of low byte --- */
uchByte = *(puchBuffer + 3) - (UCHAR)0x30;
if (uchByte & UIE_SCALE_UNDER) {
return (UIE_SCALE_UNDER_CAPACITY);
} else if (uchByte & UIE_SCALE_OVER) {
return (UIE_SCALE_OVER_CAPACITY);
}
/* --- check status of high byte --- */
uchByte = *(puchBuffer + 2) - (UCHAR)0x30;
if (uchByte & UIE_SCALE_IN_MOTION) {
return (UIE_SCALE_MOTION);
} else if (uchByte & UIE_SCALE_ZERO) {
return (0);
} else {
return (TRUE);
}
}
class UsbSerialDevice
{
public:
UsbSerialDevice();
~UsbSerialDevice();
int CreateEndPoint (wchar_t *wszVendorId);
int CloseEndPoint ();
int ReadStream (void *bString, size_t nBytes);
int WriteStream (void *bString, size_t nBytes);
DWORD m_dwError; // GetLastError() for last action
DWORD m_dwErrorWrite; // GetLastError() for last write
DWORD m_dwErrorRead; // GetLastError() for last read
DWORD m_dwBytesWritten;
DWORD m_dwBytesRead;
private:
HANDLE m_hFile;
DWORD m_dwStatError;
COMMTIMEOUTS m_timeOut;
COMSTAT m_statOut;
};
UsbSerialDevice::UsbSerialDevice() :
m_dwError(0),
m_dwErrorWrite(0),
m_dwErrorRead(0),
m_dwBytesWritten(0),
m_dwBytesRead(0),
m_hFile(NULL)
{
}
UsbSerialDevice::~UsbSerialDevice()
{
CloseHandle (m_hFile);
}
int UsbSerialDevice::WriteStream(void *bString, size_t nBytes)
{
BOOL bWrite = FALSE;
if (m_hFile) {
m_dwError = m_dwErrorWrite = 0;
m_dwBytesWritten = 0;
ClearCommError (m_hFile, &m_dwStatError, &m_statOut);
bWrite = WriteFile (m_hFile, bString, nBytes, &m_dwBytesWritten, NULL);
m_dwError = m_dwErrorWrite = GetLastError();
return 0;
}
return -1;
}
int UsbSerialDevice::ReadStream(void *bString, size_t nBytes)
{
BOOL bRead = FALSE;
if (m_hFile) {
m_dwError = m_dwErrorRead = 0;
m_dwBytesRead = 0;
ClearCommError (m_hFile, &m_dwStatError, &m_statOut);
bRead = ReadFile (m_hFile, bString, nBytes, &m_dwBytesRead, NULL);
m_dwError = m_dwErrorRead = GetLastError();
return 0;
}
return -1;
}
int UsbSerialDevice::CreateEndPoint (wchar_t *wszVendorId)
{
HDEVINFO hDevInfo;
m_dwError = ERROR_INVALID_HANDLE;
// We will try to get device information set for all USB devices that have a
// device interface and are currently present on the system (plugged in).
hDevInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_USB_DEVICE, NULL, 0, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
if (hDevInfo != INVALID_HANDLE_VALUE)
{
DWORD dwMemberIdx;
BOOL bContinue = TRUE;
SP_DEVICE_INTERFACE_DATA DevIntfData;
// Prepare to enumerate all device interfaces for the device information
// set that we retrieved with SetupDiGetClassDevs(..)
DevIntfData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
dwMemberIdx = 0;
// Next, we will keep calling this SetupDiEnumDeviceInterfaces(..) until this
// function causes GetLastError() to return ERROR_NO_MORE_ITEMS. With each
// call the dwMemberIdx value needs to be incremented to retrieve the next
// device interface information.
for (BOOL bContinue = TRUE; bContinue; ) {
PSP_DEVICE_INTERFACE_DETAIL_DATA DevIntfDetailData;
SP_DEVINFO_DATA DevData;
DWORD dwSize;
dwMemberIdx++;
SetupDiEnumDeviceInterfaces(hDevInfo, NULL, &GUID_DEVINTERFACE_USB_DEVICE, dwMemberIdx, &DevIntfData);
if (GetLastError() == ERROR_NO_MORE_ITEMS) break;
// As a last step we will need to get some more details for each
// of device interface information we are able to retrieve. This
// device interface detail gives us the information we need to identify
// the device (VID/PID), and decide if it's useful to us. It will also
// provide a DEVINFO_DATA structure which we can use to know the serial
// port name for a virtual com port.
DevData.cbSize = sizeof(DevData);
// Get the required buffer size. Call SetupDiGetDeviceInterfaceDetail with
// a NULL DevIntfDetailData pointer, a DevIntfDetailDataSize
// of zero, and a valid RequiredSize variable. In response to such a call,
// this function returns the required buffer size at dwSize.
SetupDiGetDeviceInterfaceDetail(hDevInfo, &DevIntfData, NULL, 0, &dwSize, NULL);
// Allocate memory for the DeviceInterfaceDetail struct. Don't forget to
// deallocate it later!
DevIntfDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize);
DevIntfDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
if (SetupDiGetDeviceInterfaceDetail(hDevInfo, &DevIntfData, DevIntfDetailData, dwSize, &dwSize, &DevData))
{
// Finally we can start checking if we've found a useable device,
// by inspecting the DevIntfDetailData->DevicePath variable.
//
// The DevicePath looks something like this for a Brecknell 67xx Series Serial Scale
// \\?\usb#vid_1a86&pid_7523#6&28eaabda&0&2#{a5dcbf10-6530-11d2-901f-00c04fb951ed}
//
// The VID for a particular vendor will be the same for a particular vendor's equipment.
// The PID is variable for each device of the vendor.
//
// As you can see it contains the VID/PID for the device, so we can check
// for the right VID/PID with string handling routines.
// See https://github.com/Microsoft/Windows-driver-samples/blob/master/usb/usbview/vndrlist.h
if (wcsstr (DevIntfDetailData->DevicePath, wszVendorId)) {
m_dwError = 0;
m_hFile = CreateFile (DevIntfDetailData->DevicePath, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
if (m_hFile == INVALID_HANDLE_VALUE) {
m_dwError = GetLastError();
} else {
GetCommTimeouts (m_hFile, &m_timeOut);
m_timeOut.ReadIntervalTimeout = 0;
m_timeOut.ReadTotalTimeoutMultiplier = 0;
m_timeOut.ReadTotalTimeoutConstant = 5000;
SetCommTimeouts (m_hFile, &m_timeOut);
m_dwError = GetLastError();
}
bContinue = FALSE; // found the vendor so stop processing after freeing the heap.
}
}
HeapFree(GetProcessHeap(), 0, DevIntfDetailData);
}
SetupDiDestroyDeviceInfoList(hDevInfo);
}
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
UsbSerialDevice myDev;
myDev.CreateEndPoint (L"vid_1a86&pid_7523");
switch (myDev.m_dwError) {
case 0:
// no error so just ignore.
break;
case ERROR_ACCESS_DENIED:
wprintf (_T(" CreateFile() failed. GetLastError() = %d\n ERROR_ACCESS_DENIED: Access is denied.\n Is it already in use?\n"), myDev.m_dwError);
break;
case ERROR_GEN_FAILURE:
wprintf (_T(" CreateFile() failed. GetLastError() = %d\n ERROR_GEN_FAILURE: A device attached to the system is not functioning.\n Is it an HID?\n"), myDev.m_dwError);
break;
case ERROR_INVALID_HANDLE:
wprintf (_T(" CreateFile() failed. GetLastError() = %d\n ERROR_INVALID_HANDLE: The handle is invalid.\n CreateFile() failed?\n"), myDev.m_dwError);
break;
default:
wprintf (_T(" CreateFile() failed. GetLastError() = %d\n"), myDev.m_dwError);
break;
}
if (myDev.m_dwError == 0) {
char reqWeight[] = "W\r";
char resWeight[256] = {0};
myDev.WriteStream (reqWeight, strlen (reqWeight));
wprintf (_T(" Sent request now get response.\n"));
Sleep (50);
myDev.ReadStream (resWeight, 16);
wprintf (_T(" Got response.\n"));
if (resWeight[0] != '\n' || resWeight[9] != '\r') {
wprintf (_T(" Unexpected format of response.\n"));
}
short sRet = UieScaleStatus (resWeight, myDev.m_dwBytesRead);
resWeight[9] = 0; // terminate the weight string so that we can write it out.
wprintf (_T(" ScaleStatus = %d, Response from device - \"%S\"\n"), sRet, resWeight + 1);
}
return 0;
}
最佳答案
运行 windows 的 PC(USB 主机)和秤(USB 设备)的通信遵循 USB 协议(protocol)。如果您安装 libusb 对于 Windows,当使用 lsusb -v
时,您可以获得与 PC 从 USB 设备获取的信息类似的信息。 .一个 USB 设备可以实现多个 USB 类。
如果 USB 设备创建了一个虚拟 COM 端口,它肯定会实现 CDC ACM 类(通信设备类抽象控制模型),除此之外它还可以实现其他 USB 类,如大容量存储类,...
直销 与 USB 设备的通信还取决于它实现的设备类及其接口(interface)和端点。如果 USB 设备实现了 CDC ACM(虚拟 COM),则您使用特定的 RS-232 命令(即 https://www.commfront.com/pages/3-easy-steps-to-understand-and-control-your-rs232-devices 或将十六进制“D”发送到万用表以接收测量值),如果它实现了您通常使用的大容量存储类使用批量传输
要更改您使用控制传输的 USB 设备的模式(请参阅 USB 简而言之)
在此链接中是 Win 如何在确定设备的 USB 类后确定加载哪个驱动程序 https://msdn.microsoft.com/en-us/library/windows/hardware/ff538820%28v=vs.85%29.aspx
( https://msdn.microsoft.com/en-us/library/windows/hardware/jj649944%28v=vs.85%29.aspx )
我不知道 Brecknell 如何实现作为虚拟 COM 的 CDC ACM 设备类,但是通常任何支持 USB 的 Win 版本都应该能够加载 CDC ACM 设备类(虚拟 COM)的驱动程序,因此您是正确的,这似乎是 .inf驱动文件问题或驱动程序加载机制(可能是 Brecknell CDC ACM 实现的问题,但我不这么认为)
然后,如果 Win 加载了一个正常工作的驱动程序,那么正常的方式就是你所做的:使用 CreateFile()
使用分配给 USB 设备的 COM。
奇怪的是,如果我然后使用打开虚拟串行通信端口 COM4 的应用程序,该应用程序工作正常并且秤会报告元素的重量。 <- 这并不奇怪,奇怪的是某些 Win 版本无法识别 CDC USB 设备。
CDC 设备的标准驱动程序似乎是 USBser.sys
( https://msdn.microsoft.com/de-de/library/windows/hardware/dn707976%28v=vs.85%29.aspx )
如果您搜索“windows 无法识别 CDC 设备”,您会得到结果
如果 USB 设备在插入时创建了一个虚拟串行通信端口,那么是否只需要通过在 CreateFile() 调用中指定通信端口(在我的情况下为 COM4)来使用虚拟串行端口?是的,如果 USB 设备实现了虚拟 COM,则使用此 COM 与此设备进行通信是最简单的方法
另见 http://www.beyondlogic.org/usbnutshell/usb1.shtml USB 简而言之
标准USB:设备描述符(类)->接口(interface)->(配置)->端点
关于c++ - 带有虚拟 COM 端口的 USB 串行设备 - 如果将 CreateFile() 与 USB 路径一起使用,ReadFile() 读取零字节,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40775369/
COM 内存泄漏最常见的原因是什么? 我读过将初始化的 CComBSTR 的地址作为 [out] 参数传递给函数会导致泄漏。我正在寻找像这样枚举其他常见的编程错误。 最佳答案 未能为 COM 对象使用
在COM服务器执行过程中分配一 block 内存,然后通过一个输出参数将该内存块传递给客户端是很常见的。然后,客户端有义务使用 CoTaskMemFree() 等方法释放该内存。 问题是,这 bloc
我有一些 MFC 代码(自定义 CWnd 控件和一些要公开的类),我需要将它们制作成带有接口(interface)的 activex/COM 对象。使用 MFC 支持制作 ATL 项目并以这种方式制作
Devenv.com 是 visual studio 命令行界面,当您键入 devenv/? 时,devenv 的帮助会出现在控制台上。但是,如果没有任何选项,devenv.com 只会调用 deve
如何将 COM 接口(interface)的引用作为 COM 库中的参数传递? 这是示例: 1)客户端代码成功创建coclass并接收到pFunctionDiscovery中的接口(interface
我正在使用 django,我在 s3 中存储了诸如 imgs 之类的东西(为此我使用的是 boto),但最近我收到了这个错误: 'foo.bar.com.s3.amazonaws.com' doesn
我已经使用组件服务 MSC 对话框创建了一个 COM+ 应用程序。我将一个现有的 COM 对象导入到这个新的 COM+ 应用程序中。 我知道可以通过 COM+ 应用程序调用该 COM 对象。我可以简单
关闭。这个问题是off-topic .它目前不接受答案。 想改进这个问题吗? Update the question所以它是on-topic用于堆栈溢出。 关闭 11 年前。 Improve thi
我正在使用通过 COM Interop 包装器公开的第三方 dll。但是,其中一个 COM 调用经常卡住(至少从不返回)。为了至少让我的代码更健壮一些,我异步包装了调用(_getDeviceInfoW
很多年前我读到有一个简单的 php 脚本可以将您的网站重定向到 http://example.com/google.com 到 google.com它适用于正斜杠右侧的任何域。我忘记了这个脚本是什么或
我正在实现我的第一个进程外 COM 服务器(我的第一个 COM 服务器,就此而言)。我已经按照步骤编写了一个 IDL 文件,为代理/ stub DLL 生成代码,编译 DLL,并注册它。 当我检查注册
是否可以在未知接口(interface)上增加 RCW 引用计数? (即不是底层 COM 对象的引用计数) 我有一些旧的 COM 服务器代码 int Method1(object comobject)
我注意到许多关于 COM 的书籍等都指出,在 COM 聚合中实现一个可用作内部对象的对象相对容易。但是,除非我遗漏了什么,否则聚合似乎只能在极其有限的场景中成功,因此只有在明确识别出这种场景时才应提供
假设我正在开发一个安装 COM 组件并安装程序注册它们的应用程序。这很好用。 现在该软件需要从内存棒上运行。如何注册我的库运行时并确保在运行应用程序后清理注册表? 最佳答案 您总是在 XP 或更高版本
我们已经使用Microsoft的ActiveX/COM(VB6)技术开发了一个软件系统。去年,我对自动化构建过程和整个SCM越来越感兴趣。我集中搜索了网络的大部分内容,以获取有关如何使用基于COM的软
我对 com 线程模型有点困惑。 我有一个 inproc 服务器,我想创建一个可从任何线程访问的接口(interface),而不管 CoInitializeEx 中使用的线程模型和/或标志。 当将接口
我的包以旁加载方式安装,并不断遇到特定于应用程序的权限错误。 是的,许多人建议在 regedit 和组件服务中手动更改权限和所有者。 我的应用实际上在组件服务(DCOMCNFG、DCOMCNFG -3
我正在使用第三方应用程序,并调用创建 的实例。我的 COM 对象。这个调用成功了,但是第三方应用程序上的函数没有返回指向创建对象的指针(我不知道为什么)。有没有办法获得指向我的对象的指针? 为了澄清,
我有一个用 C# 编写的托管 COM 对象和一个用 C++(MFC 和 ATL)编写的 native COM 客户端和接收器。客户端创建对象并在启动时向其事件接口(interface)提供建议,并在其
我的应用程序需要注册两个 COM DLL。如果用户有必要的访问权限,它会自动完成,否则可以使用 regsvr32 完成。 . 现在在一些工作站上会发生以下情况: 开始cmd.exe作为管理员 注册第一
我是一名优秀的程序员,十分优秀!