Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых

Программирование модемов

© Александр Фролов, Григорий Фролов
Том 4, М.: Диалог-МИФИ, 1993, 236 стр.

[Назад] [Содеожание] [Дальше]

5.5. Сигнальные лампы для внутреннего модема

Как мы говорили ранее, одним из преимуществ внешнего модема над внутренним является наличие на его лицевой панели световых индикаторов, по которым можно определить состояние модема.

Мы приведем маленькую резидентную программу, которая отображает на экране дисплея состояние модема. Наша программа компенсирует недостаток внутреннего модема, связанный с отсутствием индикации.

Программу можно также использовать при отладке своих приложений, работающих с COM-портами, так как фактически она отображает состояние регистров микросхемы UART.

Как работает эта программа? Она перехватывает прерывание от таймера (с номером 1Сh) и таким образом получает управление несколько раз в секунду. Затем она считывает значения регистров состояния линии, состояния модема и регистра управления модемом.

По состоянию регистра управления модемом программа определяет состояние линий DTR и RTS, управляющих процессом подтверждения связи. Регистр состояния модема отражает состояние сигналов CTS, DSR, используемых для управления потоком, а также линий RI и DCD. Сигнал RI означает, что пришел вызов от удаленного модема, а сигнал DCD - что модемы установили и поддерживают связь.

После того как программа считает состояние регистров асинхронного порта, она отображает их состояние на экране дисплея. Вывод данных на экран наша программа выполняет путем непосредственного доступа к видеопамяти. При этом данные выводятся, начиная с адреса B800:0000. Если вы собираетесь использовать программу в графических режимах видеоадаптера или отображать данные о сотоянии регистров в другом месте экрана, то вам надо самим изменить процедуру вывода.

После запуска программы в левом верхнем углу экрана появится небольшое окно, в котором будет отображаться состояние линий TD, RD, RTS, CTS, RI, CDC, DTR, DSR:

--T-T-T-T-T-T-T-¬
¦t¦r¦r¦c¦r¦d¦d¦d¦
¦d¦d¦t¦t¦i¦c¦t¦s¦
¦ ¦ ¦s¦s¦ ¦d¦r¦r¦
LT+T+T+T+T+T+T+T-
 ¦ ¦ ¦ ¦ ¦ ¦ ¦ L---- сигнал DSR
 ¦ ¦ ¦ ¦ ¦ ¦ L------ сигнал DTR
 ¦ ¦ ¦ ¦ ¦ L-------- сигнал DCD
 ¦ ¦ ¦ ¦ L---------- сигнал RI
 ¦ ¦ ¦ L------------ сигнал CTS
 ¦ ¦ L-------------- сигнал RTS
 ¦ L---------------- данные принимаются
 L------------------ данные передаются

Если какой-нибудь из этих сигналов примет значение логической единицы, то первый символ в названии этого сигнала будет отображаться с заглавной буквы. Например, если модем установил связь и передает данные, будут активными линии TD, RTS, CTS, DCD, DTR и DSR:

T r R C r D D D
d d t t i c t s
    s s   d r r

Итак, текст программы:

// LIGHT.C
// сигнальные лампы модема

#include <stdlib.h>
#include <string.h>
#include <dos.h>

// включаемый файл uart_reg.h можно найти в приложении

#include "uart_reg.h"

// отключаем проверку стека и указателей

#pragma check_stack( off )
#pragma check_pointer( off )

// количество прерываний от таймера за одну секунду

#define TICKPERMIN  1092L


char _huge *tsrstack;
char _huge *appstack;
char _huge *tsrbottom;

// объявления функций

void (_interrupt _far *oldtimer)( void );
void _interrupt _far newtimer( void );

void test_com_port( void );
void hello( void );
void help( void );

// определяем указатель на счетчик таймера

long _far *pcurtick = (long _far *)0x0000046cL;
long goaltick;

// следующий массив содержит возможные базовые адреса
// различных последовательных портов

unsigned uart_reg[] = { 0, 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
unsigned com_port;


// главная процедура

void main( int argc, char *argv[] ) {

   unsigned  tsrsize;

   // параметр программы должен содержать номер
   // используемого COM-порта

   if( argc < 2 ) help();

   hello();

   _asm mov  WORD PTR tsrstack[0], sp
   _asm mov  WORD PTR tsrstack[2], ss

   FP_SEG( tsrbottom ) = _psp;
   FP_OFF( tsrbottom ) = 0;


   com_port = ( unsigned ) uart_reg[atoi( argv[1] )];

   printf( "\nпорт %x\n", com_port );

   // определяем момент первой проверки регистров
   // асинхронного адаптера

   goaltick += TICKPERMIN / 10L;

   // переустанавливаем вектор прерывания от таймера

   oldtimer = _dos_getvect( 0x1c );
   _dos_setvect( 0x1c, newtimer );

   // вычисляем размер резидентной части программы

   tsrsize = ((tsrstack - tsrbottom) >> 4) + 1;
   _dos_freemem( _psp );

   // оставляем программу резидентной в памяти

   _dos_keep( 0, tsrsize );
}


void hello( void ) {

   printf("\n(c) Frolov G.V. Сигнальные лампы\n \n"
        "   trrcrddd \n"
        "   ddtticts \n"
        "     ss drr \n"
        "   ¦¦¦¦¦¦¦¦ \n"
        "   ¦¦¦¦¦¦¦L---- сигнал DSR \n"
        "   ¦¦¦¦¦¦L----- сигнал DTR \n"
        "   ¦¦¦¦¦L------ сигнал DCD \n"
        "   ¦¦¦¦L------- сигнал RI \n"
        "   ¦¦¦L-------- сигнал CTS \n"
        "   ¦¦L--------- сигнал RTS \n"
        "   ¦L---------- данные принимаются \n"
        "   L----------- данные передаются \n"
      );
}


void help( void ) {

   printf(" Неправильно задан параметр программы - \n"
        " пример: LIGHT [1|2|3|4] \n");
   exit(0);
}


// обработчик прерываний от таймера

void _interrupt _far newtimer() {

   // если пришло время, проверяем регистры COM-порта

   if(*pcurtick >= goaltick) {

      (*oldtimer)();

      // вычисляем время следующей проверки

      goaltick += TICKPERMIN / 10L;

      // проверяем регистры COM-порта и отображаем их на экране

      test_com_port();
   }

   else
      _chain_intr( oldtimer );
}


void test_com_port( void ) {

   char data[]  = "trrcrddd";
   char data2[] = "ddtticts";
   char data3[] = "  ss drr";

   char attr[9];

  _asm {

      // получаем адрес регистра состояния линии

      mov     dx,com_port
      add     dx,LSR_N
      in      al,dx

      // проверяем, пуст ли регистр сдвига передатчика

      test    al,40h
      jz      next_1

      mov     ah,'t'
      mov     data[0],ah
      mov     attr[0],0x71
      jmp     short next_2

next_1:

      // если регистр сдвига не пуст, значит, модем
      // осуществляет передачу данных

      mov     ah,'T'
      mov     data[0],ah
      mov     attr[0],0x79

next_2:

      // проверяем, есть ли данные, готовые для чтения

      test    al,1
      jnz     next_3
      mov     ah,'r'
      mov     data[1],ah
      mov     attr[1],0x71
      jmp     short next_4

next_3:

      // если есть данные для чтения, отображаем на экране
      // символ 'R'

      mov     ah,'R'
      mov     data[1],ah
      mov     attr[1],0x79

next_4:

      // считываем регистр состояния модема

      mov     dx,com_port
      add     dx,MSR_N
      in      al,dx

      // определяем состояние линии CTS

      test    al,10h
      jnz     next_5

      // линия CTS неактивна

      mov     ah,'c'
      mov     data[3],ah
      mov     attr[3],0x72
      jmp     short next_6

next_5:

      // линия CTS активна

      mov     ah,'C'
      mov     data[3],ah
      mov     attr[3],0x7a

next_6:

      // определяем состояние линии DSR

      test    al,20h
      jnz     next_7

      // линия DSR неактивна

      mov     ah,'d'
      mov     data[7],ah
      mov     attr[7],0x72
      jmp     short next_8

next_7:

      // линия DSR активна

      mov     ah,'D'
      mov     data[7],ah
      mov     attr[7],0x7a

next_8:

      // определяем состояние линии RI

      test    al,40h
      jnz     next_9

      // линия RI находится в неактивном состоянии

      mov     ah,'r'
      mov     data[4],ah
      mov     attr[4],0x76
      jmp     short next_10

next_9:

      // линия RI находится в активном состоянии

      mov     ah,'R'
      mov     data[4],ah
      mov     attr[4],0x7e

next_10:

      // определяем состояние линии DCD

      test    al,80h
      jnz     next_11

      // линия DCD неактивна

      mov     ah,'d'
      mov     data[5],ah
      mov     attr[5],0x76
      jmp     short next_12

next_11:

      // линия DCD активна

      mov     ah,'D'
      mov     data[5],ah
      mov     attr[5],0x7e

next_12:

      // считываем регистр управления модемом

      mov     dx,MCR_N
      add     dx,com_port
      in      al,dx

      // проверяем линию RTS

      test    al,2
      jnz     next_13

      // линия RTS находится в неактивном состоянии

      mov     ah,'r'
      mov     data[2],ah
      mov     attr[2],0x74
      jmp     short next_14

next_13:

      // линия RTS находится в активном состоянии

      mov     ah,'R'
      mov     data[2],ah
      mov     attr[2],0x7c

next_14:

      // проверяем линию DTR

      test    al,1
      jnz     next_15

      // линия DTR неактивна

      mov     ah,'d'
      mov     data[6],ah
      mov     attr[6],0x74
      jmp     short next_16

next_15:

      // линия DTR активна

      mov     ah,'D'
      mov     data[6],ah
      mov     attr[6],0x7c

next_16:

// отображаем на экране состояние регистров
// вывод на экран происходит непосредственно
// через видеопамять

      // сегмент видеопамяти

      mov     ax,0B800h
      mov     es,ax

      xor     si,si
      mov     di,0
      mov     cx,8

next_char:

      // отображаем на экране очередной символ
      // из массива data

      mov      ah,data[si]
      mov      es:[di],ah

      inc      di

      // устанавливаем атрибуты этого символа

      mov      ah,attr[si]
      mov      es:[di],ah
      sti

      inc      di
      inc      si

      loop     next_char

      xor     si,si
      mov     di,160
      mov     cx,8

next_str2:
      mov      ah,data2[si]
      mov      es:[di],ah
      inc      di
      mov      ah,attr[si]
      mov      es:[di],ah
      sti
      inc      di
      inc      si
      loop     next_str2


      xor     si,si
      mov     di,320
      mov     cx,8

next_str3:
      mov      ah,data3[si]
      mov      es:[di],ah
      inc      di
      mov      ah,attr[si]
      mov      es:[di],ah
      sti
      inc      di
      inc      si
      loop     next_str3

   }
}

[Назад] [Содеожание] [Дальше]