Версия для печати


Обмен информацией с модемом
http://www.delphikingdom.com/asp/viewitem.asp?catalogID=1030

Евгений Дружинин
дата публикации 10-08-2004 14:20

Обмен информацией с модемом

Столкнувшись с необходимостью написания функции обмена данными с модемом, я был крайне удивлен практическим отсутствием информации по этому поводу. Мне было нужно организовать обмен данными с модемом так, как это происходит в "Свойствах Модема" на закладке "Диагностика" при нажатии на кнопку "Опросить модем". Порывшись в Интернете, подняв несколько раз этот вопрос на программистских форумах, я так и не нашел ответа на вопрос "как послать AT команду в модем и получить от него ответ". Стандартные отписки CreateFile, а потом WriteFile и ReadFile, ясности не вносили - модем все равно отказывался отвечать на команды. Пришлось вникнуть в особенности обмена данными с модемом и самому решить поставленную задачу.

Итак, исходные данные: модем подключен к порту COM3.
Сначала, как и описано во всех источниках, открываем COM порт, к которому подключен модем:
hCommFile := CreateFile(PChar('\\.\COM3'),
                          GENERIC_WRITE+GENERIC_READ,
                          0,
                          nil,
                          OPEN_EXISTING,
                          FILE_ATTRIBUTE_NORMAL,
                          0);

Далее, если hCommFile<> INVALID_HANDLE_VALUE, то считываем свойства COM порта функцией GetCommProperties(hCommFile,CommProp) и убеждаемся, что устройство, подключенное к порту COM3, действительно является модемом. Если CommProp.dwProvSubType = PST_MODEM, то к порту на самом деле подключен модем.

Теперь наступает первый ключевой момент, почти нигде не описанный. Надо установить размеры входного и выходного буферов, в которых будут размещаться данные, передаваемые в модем и принимаемые от него:

SetupComm(hCommFile,SizeOf(inBuffer),SizeOf(OutBuffer))
Установив размеры буферов, считываем структуру DCB COM порта.
GetCommState(hCommFile,DCB)

В считанной структуре необходимо установить количество битов данных - 8. И, при желании, скорость COM порта (я задаю максимальное значение - 115200). Записываем новые значения:

SetCommState(hCommFile,DCB)
Считываем информацию о таймаутах:
GetCommTimeouts(hCommFile,CommTOuts)
устанавливаем свои значения:
CommTOuts.ReadIntervalTimeout:=1800;
CommTOuts.ReadTotalTimeoutMultiplier:=30;
CommTOuts.ReadTotalTimeoutConstant:=6000;
CommTOuts.WriteTotalTimeoutMultiplier:=30;
CommTOuts.WriteTotalTimeoutConstant:=6000;
и записываем их:
SetCommTimeouts(hCommFile,CommTOuts)

Всё! COM порт полностью подготовлен к работе. А как же передавать команды модему и получать от него ответы? Оказывается достаточно просто!

Записываем команду в выходной буфер, не забыв завершить строку #13#10, и вызываем функцию:

WriteFile(hCommFile,
               OutBuffer,
               Length(PhoneCommand),
               NumberWritten,
               nil)

Ну, пока всё так, как и пишется во всех форумах и статьях. Однако если теперь выполнить функцию ReadFile, то во входном буфере будет та же самая строка, что и в выходном буфере. Так что же делать? А вот здесь вторая и главная особенность описываемого мной метода общения с модемом. Этого я не нашел ни в каких источниках. После выполнения функции WriteFile нужно очистить буферы:

PurgeComm(hCommFile,PURGE_TXCLEAR + PURGE_RXCLEAR)
И дальше читать:
ReadFile(hCommFile,InBuffer,SizeOf(InBuffer),BytesRead,nil)

Вот и всё. Описанным выше методом можно передавать модему АТ команды и смотреть, как он на них отвечает. Исходные коды примера и исполняемый файл находятся в прилагаемом архиве.

Евгений Дружинин.
http://www.compexp.ru

Скачать проект: Modem.zip (206 K)