gpt4 book ai didi

c++ - WriteFile 到调制解调器后的 ReadFile 仅返回通过 WriteFile 发送的内容

转载 作者:搜寻专家 更新时间:2023-10-31 01:11:23 27 4
gpt4 key购买 nike

我正在尝试使用 C++ 代码将 AT 命令发送到通过 USB 连接的调制解调器。我正在使用“AT+MDN”进行测试,它在这个特定的调制解调器上返回其电话号码,并且在通过连接到其串行端口的 Putty 进行测试时正常工作。 GetComPort 确定调制解调器连接到的 com 端口号并为其创建句柄。 sendCommand() 方法打开端口、发送命令、刷新缓冲区然后尝试读取结果但只接收回发送的命令,因此在本例中它接收到“AT+MDN”。我尝试了我能找到的针对此问题的所有各种修复方法(刷新缓冲区,在写入和读取之间添加休眠)但没有一个奏效。

串行ATDT.cpp

#include "SerialATDT.h"
#include "EventSem.h"
#include "Traces.h"
#include <setupapi.h>
#include <devguid.h>
#include <regstr.h>

SerialATDT::SerialATDT(String ident) : mComPortIdentifier(ident)
{
}

SerialATDT::~SerialATDT(void)
{
}

String SerialATDT::getComPortId()
{
HDEVINFO hDevInfo;
SP_DEVINFO_DATA DeviceInfoData;
int devOffset = 0;
DWORD propertyDataType;
HKEY devKey;
DWORD portNameSize;
DWORD result;
String comPort = "";
BYTE friendlyName[4096];
TCHAR devName[4096];
TCHAR portName[4096];

// Create a HDEVINFO with all present devices.
hDevInfo = SetupDiGetClassDevs(&GUID_DEVCLASS_MODEM, 0, 0, DIGCF_PRESENT);
if (hDevInfo == INVALID_HANDLE_VALUE)
{
TRACE_L(TEXT("\nSetupDiGetClassDevs() failed: %d\n"), GetLastError());
return "";
}

// Enumerate through all devices in Set.
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
while (SetupDiEnumDeviceInfo(hDevInfo, devOffset++, &DeviceInfoData))
{

if (!SetupDiGetDeviceRegistryProperty(hDevInfo, &DeviceInfoData, SPDRP_FRIENDLYNAME,
&propertyDataType, friendlyName, sizeof(friendlyName), NULL))
{
TRACE_L(TEXT("\nSetupDiEnumDeviceInfo() failed: %d\n"), GetLastError());
continue;
}

// Look for identifying info in the name
if ( mComPortIdentifier.size() > 0 ) {
const char *temp = strstr((const char*)friendlyName, mComPortIdentifier.c_str());

if ( temp == 0 ) {
continue;
}
}

// Get the device name.
if (!SetupDiGetDeviceInstanceId(hDevInfo, &DeviceInfoData, devName, MAX_PATH, NULL))
{
TRACE_L(TEXT("\nSetupDiGetDeviceInstanceId() failed: %d\n"), GetLastError());
continue;
}

// Open the registry key associated with the device.
devKey = SetupDiOpenDevRegKey(hDevInfo, &DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ);
if (devKey == INVALID_HANDLE_VALUE)
{
TRACE_L(TEXT("\nSetupDiOpenDevRegKey() failed: %d\n"), GetLastError());
continue;
}

// Read the PortName registry key.
portNameSize = sizeof(portName);
result = RegQueryValueEx(devKey, TEXT("PortName"), NULL, NULL, (LPBYTE) portName, &portNameSize);
if(result != ERROR_SUCCESS)
{
TRACE_L(TEXT("\nRegQueryValueEx() failed: %d\n"), result);
continue;
}

// We are not guaranteed a null terminated string from RegQueryValueEx, so explicitly NULL-terminate it.
portName[portNameSize / sizeof(TCHAR)] = TEXT('\0');

// Close the registry key.
result = RegCloseKey(devKey);
if (result != ERROR_SUCCESS)
{
TRACE_L(TEXT("\nRegCloseKey() failed: %d\n"), result);
continue;
}

// Try to open the COM port.
comPort = portName;
}

SetupDiDestroyDeviceInfoList(hDevInfo);

return comPort;
}

bool SerialATDT::getComPort(HANDLE *hFile)
{
String comPort = getComPortId();

*hFile = INVALID_HANDLE_VALUE;

if ( comPort.size() > 0 ) {
String comPortStr;

comPortStr.Format("\\\\.\\%s", comPort.c_str());

*hFile = ::CreateFile( comPortStr.c_str(),
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL );

if ( *hFile == INVALID_HANDLE_VALUE ) {
TRACE_L("AT file open error %ld", GetLastError());
}
}

return *hFile != INVALID_HANDLE_VALUE;
}

bool SerialATDT::sendCommand(String command, String &response)
{
bool retFlag = true;
HANDLE hFile = NULL;

response = "";

if ( !getComPort(&hFile) ) {
TRACE("SerialATDT-Unable to get comport");
return false;
}

::SetupComm( hFile, 2048, 2048 );

DCB dcb = { 0 };
dcb.DCBlength = sizeof(DCB);
::GetCommState( hFile, &dcb );

dcb.BaudRate = 9600;

// set additional parameters for 8-bit, no parity, one stop bit, no flow control
dcb.fRtsControl = RTS_CONTROL_DISABLE;
dcb.ByteSize = 8;
dcb.Parity = NOPARITY;
dcb.StopBits = ONESTOPBIT;
dcb.fOutxCtsFlow = FALSE;
dcb.fOutxDsrFlow = FALSE;
dcb.fDtrControl = DTR_CONTROL_DISABLE;
dcb.fDsrSensitivity = FALSE;
dcb.fOutX = FALSE;
dcb.fInX = FALSE;

::SetCommState( hFile, &dcb );

// Retrieve the timeout parameters for all read and write operations on the port.
COMMTIMEOUTS CommTimeouts;
::GetCommTimeouts (hFile, &CommTimeouts);

#define BUFFER_LENGTH 256

// Change the COMMTIMEOUTS structure settings.
CommTimeouts.ReadIntervalTimeout = 50;
CommTimeouts.ReadTotalTimeoutMultiplier = (2000/BUFFER_LENGTH); // Only wait 2 seconds (2000ms).
CommTimeouts.ReadTotalTimeoutConstant = 50;
CommTimeouts.WriteTotalTimeoutMultiplier = 50;
CommTimeouts.WriteTotalTimeoutConstant = 50;

// Set the timeout parameters for all read and write operations on the port.
::SetCommTimeouts (hFile, &CommTimeouts);

char buffer[BUFFER_LENGTH+1];
OVERLAPPED m_ReadSync;
unsigned error = 0;
EventSem readWait;
bool finished = false;


memset(&m_ReadSync, 0, sizeof(OVERLAPPED));

m_ReadSync.hEvent = readWait.GetHandle();
m_ReadSync.Pointer = (void*)buffer;

static int index = 0;

// Edited here
command += "\r";

// First write the command out to the serial port
UInt32 numBytesWritten = 0;
UInt32 totalBytesWritten = 0;
do {
if ( !::WriteFile(hFile, command.c_str(), command.length(), &numBytesWritten, NULL) ) {
TRACE("SerialATDT-sendCommand failed on sending.");
retFlag = false;
break;
}

totalBytesWritten += numBytesWritten;
} while (totalBytesWritten < command.length() );

::FlushFileBuffers(hFile);

// Read in the response
if ( retFlag ) {
Sleep(1000);

while ( !finished ) {
UInt32 numBytesRead = 0;

buffer[0] = '\0';

if ( !::ReadFile(hFile, buffer, BUFFER_LENGTH, &numBytesRead, &m_ReadSync ) )
{
if ( ( error = ::GetLastError() ) == ERROR_IO_PENDING )
{
error = 0;
if ( !::GetOverlappedResult( hFile, &m_ReadSync, &numBytesRead, true ) )
{
error = ::GetLastError();
}
}
}

// We read something
if ( numBytesRead > 0 ) {
buffer[numBytesRead] = '\0';
response += buffer;
} else { // We timed out so just drop out
finished = true;
}
}
}

// Remove the command from what we read in the response
if ( response.find(command) != std::string::npos ) {
response = response.substr(command.length());
}

if ( hFile != INVALID_HANDLE_VALUE ) {
::CloseHandle( hFile );
}

return retFlag;
}

和SerialATDT.h

#ifndef SERIALATDT_H
#define SERIALATDT_H

#pragma once

#include "SgiString.h"
#include "FileSystem.h"

using namespace sgi;

class SerialATDT
{
private:
String mComPortIdentifier;

bool getComPort(HANDLE *hFile);
String getComPortId();

public:
SerialATDT(String ident);
~SerialATDT(void);

bool sendCommand(String command, String &response);
};

#endif

最佳答案

当您取回写入的字符串时,这可能是调制解调器有意回显(这是您可以查看在 Putty 中键入的内容的一种方式)。你试过再读一遍吗?另外,您是否检查过写入字符串上的不同行结尾。有些调制解调器只需要一个换行符“\n”,有些则需要一个回车换行符“\r\n”。如果没有正确的行结尾,调制解调器可能不会执行您的 AT 命令。

关于c++ - WriteFile 到调制解调器后的 ReadFile 仅返回通过 WriteFile 发送的内容,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14989283/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com