понедельник, 5 июля 2010 г.

Мониторинг и контроль COM-порта

И хотя COM- порт уже отжил свое в первоначальной железной реализации на персональных ПК, но в радиолюбительской практике и промышленных устройствах он до сих пор остается актуальным. По большей части благодаря тому, что большинство существующих USB интерфейсов от блютуз-радиомодулей до плат контроля параметров сред, различных гаджетов, конверторов, эмулируют виртуальный COM- порт в системе, из-за простоты работы с этим интерфейсом. Часто перед начинающим ембеддером возникает задача контроля разного рода устройств по USB. Для этого используются чипы FTDI и CP-21xx, эмулирующие виртуальный COM-порт.

Для асинхронного режима ввода-вывода и открытия порта можем воспользоваться WinAPI функцией CreateFile(). Заглянем в MSDN, синтаксис будет следующим:
HANDLE WINAPI CreateFile(
  _In_      LPCTSTR lpFileName,
  _In_      DWORD dwDesiredAccess,
  _In_      DWORD dwShareMode,
  _In_opt_  LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  _In_      DWORD dwCreationDisposition,
  _In_      DWORD dwFlagsAndAttributes,
  _In_opt_  HANDLE hTemplateFile
);
После того, как получили хэндл порта, а значит и доступ к нему, его необходимо настроить: задать формат данных, параметры четности и битности, скорость обмена и разме буфера и т.д. Основные параметры последовательного порта задают структуры DCB и COMMTIMEOUTS. Синтаксис записи структуры выглядит следующи образом (в комментариях дается расшифровка параметра):
typedef struct _DCB {
DWORD DCBlength; // sizeof(DCB)
DWORD BaudRate; // current baud rate
DWORD fBinary:1; // binary mode, no EOF check
DWORD fParity:1; // enable parity checking
DWORD fOutxCtsFlow:1; // CTS output flow control
DWORD fOutxDsrFlow:1; // DSR output flow control
DWORD fDtrControl:2; // DTR flow control type
DWORD fDsrSensitivity:1; // DSR sensitivity
DWORD fTXContinueOnXoff:1; // XOFF continues Tx
DWORD fOutX:1; // XON/XOFF out flow control
DWORD fInX:1; // XON/XOFF in flow control
DWORD fErrorChar:1; // enable error replacement
DWORD fNull:1; // enable null stripping
DWORD fRtsControl:2; // RTS flow control
DWORD fAbortOnError:1; // abort reads/writes on error
DWORD fDummy2:17; // reserved
WORD wReserved; // not currently used
WORD XonLim; // transmit XON threshold
WORD XoffLim; // transmit XOFF threshold
BYTE ByteSize; // number of bits/byte, 4-8
BYTE Parity; // 0-4=no,odd,even,mark,space
BYTE StopBits; // 0,1,2 = 1, 1.5, 2
char XonChar; // Tx and Rx XON character
char XoffChar; // Tx and Rx XOFF character
char ErrorChar; // error replacement character
char EofChar; // end of input character
char EvtChar; // received event character
WORD wReserved1; // reserved; do not use
} DCB;
Для управления сигналом RTS можем передать команду через функцию EscapeCommFunction(). Синтаксис ее записи будет выглядеть следующим образом:
BOOL WINAPI EscapeCommFunction(
  _In_  HANDLE hFile,
  _In_  DWORD dwFunc
);
Таким образом, задача установки бита будет состоять из следующих шагов:
  1. Открыть порт CreateFile и получить хэндл порта.
  2. Заполнить структуру DCB (или считать текущие настройки).
  3. Установить бит через EscapeCommFunction.
К примеру, для установки RTS можем записать (3 – установить RTS, 4 – сбросить RTS):
EscapeCommFunction(Handle, 3)
Для установки DTR (5 – установить DTR, 6 – сбросить DTR):
EscapeCommFunction(Handle, 5)
Хорошо, скажете вы. Помигать светодиодом мы можем, а если подключить кнопку к входным служебным пинам (DSR/CTS), то как считать ее состояние? Для этого есть функция GetOverlappedResult(). Синтаксис ее следующий:
BOOL WINAPI GetOverlappedResult(
  _In_   HANDLE hFile,
  _In_   LPOVERLAPPED lpOverlapped,
  _Out_  LPDWORD lpNumberOfBytesTransferred,
  _In_   BOOL bWait
);
где параметр 'pOverlapped' не что иное, как указатель на структуру:
typedef struct _OVERLAPPED {
  ULONG_PTR Internal;
  ULONG_PTR InternalHigh;
  union {
    struct {
      DWORD Offset;
      DWORD OffsetHigh;
    };
    PVOID  Pointer;
  };
  HANDLE    hEvent;
} OVERLAPPED, *LPOVERLAPPED;
Но для того, чтобы наша функция работала, нужно установить перехват события через функцию SetCommMask():
BOOL WINAPI SetCommMask(
  _In_  HANDLE hFile,
  _In_  DWORD dwEvtMask
);
где в параметре 'dwEvtMask' можно указать по те сигналы, которые нужно будет отслеживать. Ожидание событие можно установить через функцию WaitCommEvent:
BOOL WINAPI WaitCommEvent(
  _In_   HANDLE hFile,
  _Out_  LPDWORD lpEvtMask,
  _In_   LPOVERLAPPED lpOverlapped
);
Как читать и передавать в порт вы тоже уже знаете. Для того, чтобы завершить работу с портом используем небезызвестную функцию CloseHandle():
BOOL WINAPI CloseHandle(
  _In_  HANDLE hObject
);
Таким образом, уже можем сформировать основные требования к нашему запросчику-монитору:
  1. Возможность контроля сигналов RTS/DTR;
  2. Возможность мониторинга сигналов CTS/DSR/RI;
  3. Возможность осуществления приема и передачи тестового пакета на TX/RX;
  4. Автоподключение к COM-порту (физическому или виртуальному);
  5. Возможность интеграции алгоритма в состав других приложений;
  6. Возможность сохранения пользовательских настроек.
Активацию и деактивацию передачу тестового пакета на линии TX через WriteFile() осуществим в потоке-таймере путем создания и уничтожения мультимедийного таймера уже известными вам функциями TimeSetEvent(), TimeKillEvent(). Для осуществления чтения данных достаточно будет добавить функцию ReadFile(). Но как узнать, есть ли в приемном буфере RS232 данные и сколько их? Обратимся снова к MSDN, для этого существует функция ClearCommError(). Ее синтаксис выглядит следующим образом:
BOOL WINAPI ClearCommError(
  _In_       HANDLE hFile,
  _Out_opt_  LPDWORD lpErrors,
  _Out_opt_  LPCOMSTAT lpStat
);
где третий параметр есть не что иное как структура:
typedef struct _COMSTAT {
  DWORD fCtsHold  :1;
  DWORD fDsrHold  :1;
  DWORD fRlsdHold  :1;
  DWORD fXoffHold  :1;
  DWORD fXoffSent  :1;
  DWORD fEof  :1;
  DWORD fTxim  :1;
  DWORD fReserved  :25;
  DWORD cbInQue;
  DWORD cbOutQue;
} COMSTAT, *LPCOMSTAT;
и значения параметров 'cbInQue' и 'cbOutQue' в ней даст нам информацию о количестве байт в приемном и передающем буфере COM- порта. Все остальные параметры в структуре можем оставить по-умолчанию.

Реализация




забрать добро себе

Комментариев нет:

Отправить комментарий

В комментариях уважайте собеседника, внимательно читайте посты и не додумывайте. Просьбы и предложения из разряда: «можно ваш Skype/Viber/телефон», «напишите мне в vk/FB», а также другие им подобные — игнорируются. Выход новых версий ПО, внешняя ссылка, переставшая работать с течением времени и т.п. не является основанием для претензий. Желающие спокойно подискутировать и высказаться — Welcome. Желающие спонсировать блог — Donate. Нарушение этих простых правил ведет к бану и удалению комментариев без предупреждения.