Программирование модемов© Александр Фролов, Григорий ФроловТом 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 } } |