последовательный порт — Какой тип переменной использовать для параметра LPVOID lpBuffer в функциях C ++ WriteFile и ReadFile

Какой тип переменной следует использовать для lpBuffer C ++ ReadFile а также WriteFile функции для связи между ПК на базе Windows XP и системой на основе микроконтроллера? ПК имеет приложение WinForm в VS2010 C ++ / CLI. Прошивка микроконтроллера — ANSI C.

Предполагается, что мой компьютер передает символы команд (например, «S», «C» и т. Д.), За которыми следует символ завершения команды 0xd (шестнадцатеричное для десятичной 13). Система на основе микроконтроллера будет отвечать 5-10 байтами, которые будут представлять собой смесь символов ASCII и шестнадцатеричных чисел, например, «V» с последующим 0x41 0x72 и т.п.

ПК передает и микроконтроллер получает:

  1. TxMessage, PP1 а также pTx объявлен как char и сохраняя nNumberOfBytesToWrite как 2, заставляет микроконтроллер получать 0x53 за ‘S’, а затем 0xC3 вместо 0xd,

  2. TxMessage, PP1 а также pTx объявлен как wchar_t и сохраняя nNumberOfBytesToWrite как 2, заставляет микроконтроллер получать 0x53 только для «S».

  3. TxMessage, PP1 а также pTx объявлен как wchar_t и сохраняя nNumberOfBytesToWrite как 4, заставляет микроконтроллер получать 0x53 за ‘S’, а затем 0xd правильно.

Третья схема передачи и получения выше соответствует моему ожидаемому поведению решения. Но путаница здесь: хотя ПК может передавать 4 байта (для двух wchar типы), микроконтроллер получает 2 байта 0x53 для ‘S’, правильно следует 0xD,

Микроконтроллер передает и ПК получает:

При условии, что wchar_t это правильный выбор для lpBuffer, что должно быть моим nNumberOfBytesToRead для получения 10 байтов от микроконтроллера? ReadFile будет ожидать 20 байтов в силу wchar_tтогда как микроконтроллер будет передавать только 10 байтов.

Удивительно, независимо от объявления (RxMessage, PP2 а также pRx) как wchar_t, char или же unsigned charReadFile получает 10 байтов от микроконтроллера (соответствует моему ожидаемому поведению решения). Но проблема в том, что 10 раз передавая «A» с микроконтроллера, ReadFile на конце ПК получает нежелательную информацию, такую ​​как «S», 0x0, 0xd, 0x54, 0x29,

/// Required designer variable.
HANDLE hCommPort;
BOOL fSuccess;
array<wchar_t> ^ TxMessage;
array<unsigned char> ^ RxMessage;

TxMessage = gcnew array<wchar_t> (12);
RxMessage = gcnew array<unsigned char> (12);{
TxMessage[0]='S';//target cmd
TxMessage[1]=0xd;//cmd termination character
DWORD dwhandled;
if (hCommPort != INVALID_HANDLE_VALUE)
{
pin_ptr<wchar_t> pp1 = &TxMessage[0];
wchar_t *pTx = pp1;
fSuccess = WriteFile(hCommPort, pTx, 4, &dwhandled, NULL);PurgeComm(hCommPort, PURGE_RXABORT|PURGE_TXABORT|PURGE_RXCLEAR|PURGE_TXCLEAR);

pin_ptr<unsigned char> pp2 = &RxMessage[0];
unsigned char *pRx = pp2;
fSuccess = ReadFile(hCommPort, pRx, 10, &dwhandled, NULL);

}//if IsOpen
else{
this->toolStripStatusLabel4->Text="Port Not Opened";}
}

2

Решение

ReadFile/WriteFile не заботятся о типах C ++, они работают с точки зрения чтения / записи байтов. ReadFile читает указанное количество байтов (или меньше, если для чтения меньше байтов) из файла / устройства и помещает их в память, указанную lpBuffer, WriteFile записывает указанное количество байтов в файл / устройство из памяти, на которую указывает lpcBuffer, Буфер памяти для этих функций — это просто область выделенной памяти, которая имеет размер, по крайней мере, столько же байтов, сколько вы указываете этим функциям в третьем параметре.

wchat_t многобайтовый тип Его размер может быть больше одного байта. Следовательно, ваш TxMessage[0]='S'; TxMessage[1]=0xd; фактически может заполнять не два байта в памяти, а, скажем, 4 байта. Например, это может быть x0053 , x000D в wchar_t представление. С точки зрения WriteFile это не волнует, как и что вы положили в эту память. Он будет читать сырую память и будет записывать на устройство. Итак, если ваше устройство ожидает x530D, это может быть не получится, но x0053,

В общем, подумайте о байтах. Если вам нужно написать 4 байта x0A0B0C0D для вашего устройства не имеет значения, КАК вы выделили буфер для этого значения. Это может быть 4 байта unsigned int = x0A0B0C0D, может быть char[ 4 ] = {x0A, x0B, x0C, x0D}, может быть int short [ 2 ]= {x0A0B, x0C0D}, это может быть ЛЮБОЙ тип C ++, включая пользовательский класс. Но первые 4 байта памяти, указанные указателем памяти, передаются WriteFile должно быть x0A0B0C0D,

Так же, ReadFile будет читать количество байтов, которые вы укажете. Если ваше устройство отправляет вам, скажем, 2 байта, ReadFile запишет 2 байта, которые попадет в память, указанную указателем, который вы передаете ему (и вы несете ответственность за то, чтобы у него было достаточно выделенных байтов). Опять же, не имеет значения, как вы распределили его, если выделено 2 байта. После этого, опять же, вы можете посмотреть на эти два байта как хотите — это может быть char[ 2 ], может быть int short и т.п.

1

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

Использование байтов — естественное совпадение, последовательные порты — это устройства, ориентированные на байты. Вы могли бы сделать свой передающий код похожим на это:

bool SendCommand(HANDLE hCommPort) {
auto TxMessage = gcnew array<Byte> { 'S', '\r' };
pin_ptr<Byte> pbytes = &TxMessage[0];
DWORD bytesSent = 0;
BOOL fSuccess = WriteFile(hCommPort, pbytes, TxMessage->Length,
&bytesSent, NULL);
return fSuccess && bytesSent == TxMessage->Length);
}

Ваш принимающий код должен выполнять больше работы, количество байтов, возвращаемых вами из ReadFile (), непредсказуемо. Протокол необходим, чтобы указать, когда вы должны прекратить чтение. Фиксированная длина ответа является распространенным явлением. Или специальный последний символ очень распространен. Это может выглядеть так:

bool ReceiveResponse(HANDLE hCommPort, array<Byte>^ RxMessage, int% RxCount) {
for (; RxCount < RxMessage->Length; ) {
DWORD bytesReceived = 0;
pin_ptr<Byte> pbytes = &RxMessage[0];
BOOL fSuccess = ReadFile(hCommPort, pbytes, RxMessage->Length - RxCount,
&bytesReceived, NULL);
if (!fSuccess) return false;
int rxStart = RxCount;
RxCount += bytesReceived;
for (int ix = rxStart; ix < RxCount; ++ix) {
if (RxMessage[ix] == '\r') return true;
}
}
return true;
}

Не забывайте о классе .NET System :: IO :: Ports :: SerialPort. Он имеет встроенную поддержку кодирования, которая облегчает работу с символами против байтов. Ваш метод ReceiveResponse () может привести к простому вызову ReadLine () с правильно установленным свойством NewLine.

1

Извиняюсь за неспособность ответить раньше, чем это. Фактически проблема была идентифицирована и исправлена ​​после публикации моего последнего комментария. Это связано с 9-битным протоколом, навязанным микроконтроллером. Оригинальная микропрограмма — это 9-битный протокол для работы с одним из множества подчиненных. Для тестирования разработки у меня была временная модификация 8-битного протокола. К сожалению, модификации пропустили регистр режима UART, который остался как 9-битный режим. С коробкой / предвзятым умом я продолжал отлаживать

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