|
COM-порт -общение компьютера с черным ящиком |
|
|
|
Feb 12 2010, 16:46
|
Участник

Группа: Участник
Сообщений: 16
Регистрация: 26-02-06
Пользователь №: 14 713

|
Есть некое устройство и программа, которая общается с ним. Исходников и документации нет. Общается по 3-м проводам (GND, RX, TX). Хочется написать свою программку. Сниффинг обмена вроде бы прояснил ситуацию, протокол вроде бы понятен, но с общением есть проблемы При работе через терминальные проги железяка или молчит в ответ на запросы, или отвечает один раз и больше не реагирует. Вот пример лога общения родной программы (использовал Eltima Serial Port Monitor 4, но пробовал и другие): CODE [12/02/2010 17:19:21] 9245 IRP_MJ_CREATE - Opens a COM port (COM1) [12/02/2010 17:19:21] 9247 IOCTL_SERIAL_SET_QUEUE_SIZE - Request sets the size of the internal receive buffer InSize - 1024 OutSize - 300 [12/02/2010 17:19:21] 9249 IOCTL_SERIAL_GET_BAUD_RATE BaudRate - 9600 [12/02/2010 17:19:21] 9251 IOCTL_SERIAL_GET_LINE_CONTROL StopBits - 0 Parity - 0 WordLength - 8 [12/02/2010 17:19:21] 9253 IOCTL_SERIAL_GET_CHARS EofChar - 0 ErrorChar - 0 BreakChar - 0 EventChar - 0 XonChar - 17 XoffChar - 19 [12/02/2010 17:19:21] 9255 IOCTL_SERIAL_GET_HANDFLOW ControlHandShake - 0x1 (SERIAL_DTR_CONTROL) FlowReplace - 0x40 (SERIAL_RTS_CONTROL) XonLimit - 2048 XoffLimit - 512
Зачем-то еще раз GET_BAUDRATE, GET_LINE_CONTROL, GET_CHARS, GET_HANDFLOW
[12/02/2010 17:19:21] 9265 IOCTL_SERIAL_SET_BAUD_RATE BaudRate - 9600 [12/02/2010 17:19:21] 9267 IOCTL_SERIAL_SET_RTS [12/02/2010 17:19:21] 9269 IOCTL_SERIAL_SET_DTR [12/02/2010 17:19:21] 9271 IOCTL_SERIAL_SET_LINE_CONTROL StopBits - 0 Parity - 0 WordLength - 8 [12/02/2010 17:19:21] 9273 IOCTL_SERIAL_SET_CHARS EofChar - 0 ErrorChar - 0 BreakChar - 0 EventChar - 0 XonChar - 17 XoffChar - 19 [12/02/2010 17:19:21] 9275 IOCTL_SERIAL_SET_HANDFLOW - Request sets the configuration of handshake flow control ControlHandShake - 0x1 (SERIAL_DTR_CONTROL) FlowReplace - 0x40 (SERIAL_RTS_CONTROL) XonLimit - 2048 XoffLimit - 512
Несколько десятков вот таких команд:
[12/02/2010 17:19:21] 9277 IRP_MJ_DEVICE_CONTROL - Request operates a serial port STATUS_SUCCESS IOCTL_SERIAL_GET_COMMSTATUS - Request returns information about the communication status of a COM port Errors - 0 HoldReasons - 0 AmountInInQueue - 0 AmountInOutQueue - 0 EofReceived - 0 WaitForImmediate - 0
Запрос железке:
[12/02/2010 17:19:23] 9347 IRP_MJ_DEVICE_CONTROL - Request operates a serial port STATUS_SUCCESS IOCTL_SERIAL_SET_BREAK_ON - Sets the line control break signal active 9349 IRP_MJ_DEVICE_CONTROL - Request operates a serial port STATUS_SUCCESS IOCTL_SERIAL_SET_BREAK_OFF - Request sets the line control break signal inactive
[12/02/2010 17:19:23] 9351 IRP_MJ_WRITE - Request transfers data from a client to a COM port STATUS_SUCCESS 00 ff ff 01 f0 a6 10 47 .??.?│.G
Вот тут непонятно, почему Errors = 1 - глюк программы-сниффера?
[12/02/2010 17:19:23] 9353 IRP_MJ_DEVICE_CONTROL - Request operates a serial port STATUS_SUCCESS IOCTL_SERIAL_GET_COMMSTATUS - Request returns information about the communication status of a COM port Errors - 1 HoldReasons - 0 AmountInInQueue - 0 AmountInOutQueue - 0 EofReceived - 0 WaitForImmediate - 0 [12/02/2010 17:19:23] 9355 IRP_MJ_DEVICE_CONTROL - Request operates a serial port STATUS_SUCCESS IOCTL_SERIAL_GET_COMMSTATUS - Request returns information about the communication status of a COM port Errors - 0 HoldReasons - 0 AmountInInQueue - 25 AmountInOutQueue - 0 EofReceived - 0 WaitForImmediate - 0
Ну и сам ответ железки:
[12/02/2010 17:19:23] 9357 IRP_MJ_READ - Transfers data from a COM port to a client STATUS_SUCCESS 00 00 00 00 01 f0 a6 10 29 99 04 50 00 00 00 00 .....?│.)T.P.... 00 00 00 00 00 00 00 00 a3 99 04 50 00 00 00 00 ........?T.P....
Дальше пара IOCTL_SERIAL_GET_COMMSTATUS IOCTL_SERIAL_SET_BREAK_ON IOCTL_SERIAL_SET_BREAK_OFF IRP_MJ_WRITE 00 ff ff 01 03 00 04 06 - запрос железке IOCTL_SERIAL_GET_COMMSTATUS IRP_MJ_READ - ответ железки
ну и т.д. В winapi я не силен, попробовал накропать небольшую программенку, на основе каких-то примеров. CODE #include <windows.h> #include <stdio.h>
HANDLE hCom;
char *pcCommPort = "COM1";
void mem_read (char *buffer, WORD addr, unsigned char count) { unsigned char command_mem_request [8] = { 0, 0xFF, 0xFF, 1, 0xF0, 0xA6, 0x10, 0x47 };
unsigned char buffer2 [30];
// Зачем это - не знаю. // В логе фирменной программы была установка/снятие BREAK SetCommBreak (hCom); ClearCommBreak (hCom);
// Запрос железке WriteFile (hCom, @command_mem_request, 8, &dwBytes, NULL); if (dwBytes != 8) printf ("Error!!!\n");
// Хотим ответ // По факту ничего не получаем while (1) { ReadFile (hCom, &buffer2, 0x1, &dwBytes, NULL); printf ("%u bytes read!\n", dwBytes); } }
int main(int argc, char *argv[]) { unsigned char buffer, buffer_prev = 0xF0; COMMTIMEOUTS CommTimeouts; DCB dcb;
hCom = CreateFile( pcCommPort, GENERIC_READ | GENERIC_WRITE, 0, // must be opened with exclusive-access NULL, // no security attributes OPEN_EXISTING, // must use OPEN_EXISTING 0, // not overlapped I/O NULL // hTemplate must be NULL for comm devices );
if (hCom == INVALID_HANDLE_VALUE) { printf ("CreateFile failed with error %d.\n", GetLastError()); return (1); }
if (!SetupComm (hCom, 1024, 300); ) { printf ("SetupComm with error %d.\n", GetLastError()); return (1); }
if (!GetCommState (hCom, &dcb)) { printf ("GetCommState failed with error %d.\n", GetLastError()); return (1); } dcb.BaudRate = CBR_9600; dcb.ByteSize = 8; dcb.Parity = NOPARITY; dcb.StopBits = ONESTOPBIT; if (!SetCommState(hCom, &dcb)) { printf ("SetCommState failed with error %d.\n", GetLastError()); return (1); }
if (hCom != INVALID_HANDLE_VALUE && hCom != NULL) printf ("COM1 cofigured!\n");
mem_read (NULL, 0xA6F0, 0x10);
return (0); } Лог сниффера: CODE IRP_MJ_CREATE IOCTL_SERIAL_SET_QUEUE_SIZE InSize - 1024 OutSize - 300 IOCTL_SERIAL_GET_BAUD_RATE BaudRate - 9600 IOCTL_SERIAL_GET_LINE_CONTROL StopBits - 0 Parity - 0 WordLength - 8 IOCTL_SERIAL_GET_CHARS EofChar - 0 ErrorChar - 0 BreakChar - 0 EventChar - 0 XonChar - 17 XoffChar - 19 IOCTL_SERIAL_GET_HANDFLOW ControlHandShake - 0x1 (SERIAL_DTR_CONTROL) FlowReplace - 0x40 (SERIAL_RTS_CONTROL) XonLimit - 2048 XoffLimit - 512
Зачем-то еще раз GET_BAUDRATE, GET_LINE_CONTROL, GET_CHARS, GET_HANDFLOW
IOCTL_SERIAL_SET_BAUD_RATE BaudRate - 9600 IOCTL_SERIAL_SET_RTS IOCTL_SERIAL_SET_DTR IOCTL_SERIAL_SET_LINE_CONTROL StopBits - 0 Parity - 0 WordLength - 8 IOCTL_SERIAL_SET_CHARS EofChar - 0 ErrorChar - 0 BreakChar - 0 EventChar - 0 XonChar - 17 XoffChar - 19 IOCTL_SERIAL_SET_HANDFLOW ControlHandShake - 0x1 (SERIAL_DTR_CONTROL) FlowReplace - 0x40 (SERIAL_RTS_CONTROL) XonLimit - 2048 XoffLimit - 512
Даем запрос устройству.
IOCTL_SERIAL_SET_BREAK_ON IOCTL_SERIAL_SET_BREAK_OFF IRP_MJ_WRITE 00 ff ff 01 f0 a6 10 47
И вместо ответа вот такая ерунда в цикле:
14101 IRP_MJ_READ - STATUS_TIMEOUT Есть у кого-нибудь мысли, что я делаю не так? Какая функция winapi вызывает IOCTL_SERIAL_GET_COMMSTATUS? P.S. Прошу прощения за большой объем сообщения
Сообщение отредактировал rezident - Feb 12 2010, 23:24
Причина редактирования: Уменьшение видимого размера цитаты исходника.
|
|
|
|
|
 |
Ответов
|
Feb 12 2010, 19:55
|

Гуру
     
Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237

|
Тогда не знаю... Но если вы так быстро это проверяете, то проверьте для меня вот это: Код BOOL TransmitCommChar( HANDLE hFile, // handle of communications device char cChar // character to transmit ); Дает ли она какой-нибудь IOCTL, а если да, то какой? Это самая загадочная команда из всех, т.к. про нее прочти ничего не написано. А очень хотелось бы знать, в каком виде она поступает на USB-устройство.
|
|
|
|
|
Feb 12 2010, 20:45
|
Участник

Группа: Участник
Сообщений: 16
Регистрация: 26-02-06
Пользователь №: 14 713

|
Цитата(Xenia @ Feb 12 2010, 22:55)  Тогда не знаю... Но если вы так быстро это проверяете, то проверьте для меня вот это: Код BOOL TransmitCommChar( HANDLE hFile, // handle of communications device char cChar // character to transmit ); Дает ли она какой-нибудь IOCTL, а если да, то какой? Это самая загадочная команда из всех, т.к. про нее прочти ничего не написано. А очень хотелось бы знать, в каком виде она поступает на USB-устройство. [12/02/2010 22:23:32] 41636 IRP_MJ_DEVICE_CONTROL - Request operates a serial port STATUS_SUCCESS IOCTL_SERIAL_IMMEDIATE_CHAR - Request causes a specified character to be transmitted as soon as possible Попробовал с помощью нее побайтно запрос отправить - все равно устройство не отвечает. Serial Port Monitor ее как-то странно обрабатывает. Что команда есть - рисует, а в dump view (дамп принимаемых/отсылаемых байт) ничего нет. Наверное не поддерживает ее полностью =) Цитата(UniSoft @ Feb 12 2010, 22:58)  Скорее всего эта Код BOOL ClearCommError( Спасибо! Это действительно она. Правда, после посылки запроса и ClearCommError, железка не отвечает AmountInInQueue = 0 =( Код IOCTL_SERIAL_GET_COMMSTATUS - Request returns information about the communication status of a COM port Errors - 0 HoldReasons - 0 AmountInInQueue - 0 AmountInOutQueue - 0 EofReceived - 0 WaitForImmediate - 0 То ли порт как-то хитро инициализируется, то ли что.... =(
Сообщение отредактировал MEFF - Feb 12 2010, 21:07
|
|
|
|
|
Feb 12 2010, 21:01
|

Участник

Группа: Свой
Сообщений: 68
Регистрация: 7-05-05
Из: China, Shenzhen
Пользователь №: 4 812

|
Цитата(MEFF @ Feb 13 2010, 04:45)  [12/02/2010 22:23:32] То ли порт как-то хитро инициализируется, то ли что.... =( А что за прога если не секрет? Если не большая, и написана не на каком-нибудь визуал басике или жаве, то я могу глянуть что там происходит.
|
|
|
|
|
Feb 12 2010, 21:17
|
Участник

Группа: Участник
Сообщений: 16
Регистрация: 26-02-06
Пользователь №: 14 713

|
Цитата(UniSoft @ Feb 13 2010, 00:01)  А что за прога если не секрет? Если не большая, и написана не на каком-нибудь визуал басике или жаве, то я могу глянуть что там происходит. Прога - специфическая, для мониторинга оборудования. Она защищена HardLock донглом. Написана ногами, и наверняка на васике =) Как распаковать exe-шник от донгловского упаковщика не знаю =(
Сообщение отредактировал MEFF - Feb 12 2010, 21:22
|
|
|
|
|
Feb 12 2010, 22:24
|

Участник

Группа: Свой
Сообщений: 68
Регистрация: 7-05-05
Из: China, Shenzhen
Пользователь №: 4 812

|
вот так должно работать CODE #include <windows.h> #include <stdio.h>
HANDLE hCom;
char *pcCommPort = "\\\\.\\COM1";
int comport_read(HANDLE hPort,char *buffer,int cnt,int timeout) { DWORD dwErr; OVERLAPPED o; COMSTAT cstat; int BytesReaded = 0; int tmo = GetTickCount(); while ( (GetTickCount() - tmo) < timeout ) { ClearCommError(hPort, &dwErr, &cstat); if (cstat.cbInQue >= cnt) break; Sleep(1); // это нужно чтобы дать поработать другим процессам системы, // а не занимать весь временной слот ожидая данные и тем самым не грузить систему } BytesReaded = cstat.cbInQue; if (BytesReaded > 0) { if (BytesReaded > cnt) BytesReaded = cnt; o.Internal = 0; o.InternalHigh = 0; o.loffset = 0; o.OffsetHigh = 0; o.hEvent = 0; // можно и так // memclr(&o,0,sizeof(OVERLAPPED)); if (!ReadFile(hPort,buffer,BytesReaded,&BytesReaded,&o)) { BytesReaded = 0; } } return (BytesReaded); }
void mem_read (char *buffer, WORD addr, unsigned char count) { unsigned char command_mem_request [8] = { 0, 0xFF, 0xFF, 1, 0xF0, 0xA6, 0x10, 0x47 };
unsigned char buffer2 [300]; OVERLAPPED o; PurgeComm(hCom, PURGE_TXCLEAR | PURGE_RXCLEAR);
// Зачем это - не знаю. // В логе фирменной программы была установка/снятие BREAK // SetCommBreak (hCom); // ClearCommBreak (hCom);
// Запрос железке // обнулим структуру OVERLAPPED o.Internal = 0; o.InternalHigh = 0; o.loffset = 0; o.OffsetHigh = 0; o.hEvent = 0; // можно и так // memclr(&o,0,sizeof(OVERLAPPED)); WriteFile (hCom, @command_mem_request, 8, &dwBytes, &o); if (dwBytes != 8) printf ("Error!!!\n");
// Хотим ответ // По факту возможно получаем dwBytes = comport_read(hCom,&buffer2,32,5000); // << ждем ответ 5 секунд printf ("%u bytes read!\n", dwBytes); }
int main(int argc, char *argv[]) { unsigned char buffer, buffer_prev = 0xF0; COMMTIMEOUTS CommTimeouts; DCB dcb;
hCom = CreateFile( pcCommPort, GENERIC_READ | GENERIC_WRITE, NULL, // must be opened with exclusive-access NULL, // no security attributes OPEN_EXISTING, // must use OPEN_EXISTING 0, // not overlapped I/O FILE_FLAG_OVERLAPPED // hTemplate must be NULL for comm devices );
if (hCom == INVALID_HANDLE_VALUE) { printf ("CreateFile failed with error %d.\n", GetLastError()); return (1); } if (!SetupComm (hCom, 1024, 300); ) { printf ("SetupComm with error %d.\n", GetLastError()); return (1); }
if (!GetCommState (hCom, &dcb)) { printf ("GetCommState failed with error %d.\n", GetLastError()); return (1); } dcb.BaudRate = CBR_9600; dcb.ByteSize = 8; dcb.Parity = NOPARITY; dcb.StopBits = ONESTOPBIT; if (!SetCommState(hCom, &dcb)) { printf ("SetCommState failed with error %d.\n", GetLastError()); return (1); } PurgeComm(hCom,PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
if (hCom != INVALID_HANDLE_VALUE && hCom != NULL) printf ("COM1 cofigured!\n");
mem_read (NULL, 0xA6F0, 0x10);
return (0); }
Сообщение отредактировал rezident - Feb 12 2010, 23:21
Причина редактирования: Уменьшение видимого размера цитаты исходника.
|
|
|
|
|
Feb 12 2010, 22:57
|
Участник

Группа: Участник
Сообщений: 16
Регистрация: 26-02-06
Пользователь №: 14 713

|
Цитата(UniSoft @ Feb 13 2010, 01:24)  вот так должно работать Код #include <windows.h> #include <stdio.h> Код if (!WriteFile (hCom, &command_mem_request, 8, &dwBytes, &o)) { printf ("WriteFile failed with error %d.\n", GetLastError()); return; } WriteFile failed with error 997. Сейчас попробую сам поразбираться...
|
|
|
|
|
Feb 12 2010, 23:23
|

Участник

Группа: Свой
Сообщений: 68
Регистрация: 7-05-05
Из: China, Shenzhen
Пользователь №: 4 812

|
Цитата(MEFF @ Feb 13 2010, 06:57)  Код if (!WriteFile (hCom, &command_mem_request, 8, &dwBytes, &o)) { printf ("WriteFile failed with error %d.\n", GetLastError()); return; } WriteFile failed with error 997. Сейчас попробую сам поразбираться... упс, конечно-же, я не туда прописал константу Код hCom = CreateFile( pcCommPort, GENERIC_READ | GENERIC_WRITE, NULL, // must be opened with exclusive-access NULL, // no security attributes OPEN_EXISTING, // must use OPEN_EXISTING 0, // not overlapped I/O FILE_FLAG_OVERLAPPED // [color="#FF0000"][b]<<<< Вот тут ошибся[/b][/color] ); надо так Код hCom = CreateFile( pcCommPort, GENERIC_READ | GENERIC_WRITE, NULL, // must be opened with exclusive-access NULL, // no security attributes OPEN_EXISTING, // must use OPEN_EXISTING FILE_FLAG_OVERLAPPED , // not overlapped I/O NULL // );
|
|
|
|
|
Feb 13 2010, 01:07
|
Участник

Группа: Участник
Сообщений: 16
Регистрация: 26-02-06
Пользователь №: 14 713

|
Цитата(UniSoft @ Feb 13 2010, 02:23)  упс, конечно-же, я не туда прописал константу надо так Код hCom = CreateFile( pcCommPort, GENERIC_READ | GENERIC_WRITE, NULL, // must be opened with exclusive-access NULL, // no security attributes OPEN_EXISTING, // must use OPEN_EXISTING FILE_FLAG_OVERLAPPED , // not overlapped I/O NULL // ); Почти =) Код hCom = CreateFile( pcCommPort, GENERIC_READ | GENERIC_WRITE, 0, // must be opened with exclusive-access NULL, // no security attributes OPEN_EXISTING, // must use OPEN_EXISTING FILE_FLAG_OVERLAPPED, // hTemplate must be NULL for comm devices NULL ); Это все я понял и так... Тут выяснился вопрос. Если устройство выключить/включить, то работает и ваш вариант, и мой. Но только на один раз. Например, нужно послать команды (и получить ответ после каждой) 00 FF FF 01 F0 A6 10 47 00 FF FF 01 03 00 04 06 00 FF FF 01 F0 F0 0A 0B На первую команду устройство отвечает, а на остальные - тишина. Устройство больше не реагирует на команды от нашей проги. Нужно его выключить/включить - и оно опять работает на одну команду. Самое интересное, что фирменная прога отлично пашет даже когда железка якобы зависла (не отвечала на самописную программку). Т.е. как по мне, дело не в железке...
|
|
|
|
|
Feb 13 2010, 01:53
|

Участник

Группа: Свой
Сообщений: 68
Регистрация: 7-05-05
Из: China, Shenzhen
Пользователь №: 4 812

|
Цитата(MEFF @ Feb 13 2010, 09:07)  Тут выяснился вопрос. Если устройство выключить/включить, то работает и ваш вариант, и мой. Но только на один раз. Например, нужно послать команды (и получить ответ после каждой) 00 FF FF 01 F0 A6 10 47 00 FF FF 01 03 00 04 06 00 FF FF 01 F0 F0 0A 0B
На первую команду устройство отвечает, а на остальные - тишина. Устройство больше не реагирует на команды от нашей проги. Нужно его выключить/включить - и оно опять работает на одну команду.
Самое интересное, что фирменная прога отлично пашет даже когда железка якобы зависла (не отвечала на самописную программку).
Т.е. как по мне, дело не в железке... Ну тут уже нужно более детально анализировать протокол обмена... А там точно не используются дополнительные сигналы порта, как DTR и/или RTS??? либо программный контроль через BREAK??? не зря они там есть... А не отвечает, значит чего-то ждет, может нужно дрыгнуть какой ногой порта, либо может то самое дрыгание BREAK'ом... Цитата Самое интересное, что фирменная прога отлично пашет даже когда железка якобы зависла Это еще раз подтверждает, что устройство как-то перезапускается... и скорее всего это один из сигналов... Цитата 00 FF FF 01 F0 A6 10 47 а последний байт в командах это CRC (XOR всех байт)  Для более подробной информации нужно глубже копать само устройство
Сообщение отредактировал UniSoft - Feb 13 2010, 01:54
|
|
|
|
|
Feb 13 2010, 02:59
|
Участник

Группа: Участник
Сообщений: 16
Регистрация: 26-02-06
Пользователь №: 14 713

|
Цитата(UniSoft @ Feb 13 2010, 04:53)  Ну тут уже нужно более детально анализировать протокол обмена... А там точно не используются дополнительные сигналы порта, как DTR и/или RTS??? DTR и RTS не используются. Я отпаял в кабеле все провода кроме TX, RX и GND =) Цитата либо программный контроль через BREAK??? не зря они там есть... А не отвечает, значит чего-то ждет, может нужно дрыгнуть какой ногой порта, либо может то самое дрыгание BREAK'ом... SetCommBreak (hCom); ClearCommBreak (hCom); Это не дрыганье? Или нужно что-то сложнее? Завтра буду искать, чтобы почитать на эту тему. Цитата Это еще раз подтверждает, что устройство как-то перезапускается... и скорее всего это один из сигналов... а последний байт в командах это CRC (XOR всех байт)  Ага =) Цитата Для более подробной информации нужно глубже копать само устройство Не знаю уже куда копать, кроме логов сниффера =( А там вроде ничего такого. Только BREAK ON-OFF перед WRITE
|
|
|
|
|
Feb 13 2010, 04:53
|
Участник

Группа: Участник
Сообщений: 16
Регистрация: 26-02-06
Пользователь №: 14 713

|
Цитата(MEFF @ Feb 13 2010, 05:59)  SetCommBreak (hCom); ClearCommBreak (hCom); Это не дрыганье? Или нужно что-то сложнее? Завтра буду искать, чтобы почитать на эту тему. Внимательно почитал, что делают SetCommBreak / ClearCommBreak и у меня появились сомнения =) Ехарный бабай! Оказывается снифферам не во всем можно доверять! По логам эти две команды вызывались сразу подряд, а на деле нужно выдержать паузу 10 мс! И ВСЕ  Всем большое спасибо за помощь! Особенно UniSoft!
Сообщение отредактировал MEFF - Feb 13 2010, 04:54
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|