ReadFile после WriteFile модему возвращает только то, что было отправлено через WriteFile

Я пытаюсь отправить AT-команды на модем, подключенный через USB с кодом C ++. Я тестирую с использованием «AT + MDN», который на этом конкретном модеме возвращает свой номер телефона и работает правильно при тестировании через Putty, который подключается к своему последовательному порту. GetComPort определяет номер com-порта, к которому подключен модем, и создает для него дескриптор. Метод sendCommand () открывает порт, отправляет команду, очищает буфер, затем пытается прочитать результат, но получает только назад отправленную команду, поэтому в этом примере он получает «AT + MDN». Я пробовал все различные исправления для этой проблемы, которые я мог найти (очистить буфер, добавить режим ожидания между записью и чтением), но ни один не помог.

SerialATDT.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

2

Решение

Когда вы возвращаете записанную строку, это, вероятно, преднамеренное эхо от модема (это один из способов увидеть, что вы набрали в Putty). Вы пытались читать снова? Кроме того, вы проверили различные окончания строки в вашей строке записи. Некоторые модемы хотят просто перевод строки «\ n», другие хотят перевод строки через \ «\ r \ n». Без правильного окончания строки модем может не выполнять команду AT.

4

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]