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

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

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

#define TICKPERMIN  1092L


#define equip_bits  10h

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");
}


void help( void ) {

	printf("не правильно задан параметр программы \n"
			 "LIGHT n, где n от 1 до 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[9];
	char data2[] = "ddttidts";
	char data3[] = "  ss  rr";

	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,'c'
		mov     data[5],ah
		mov     attr[5],0x76
		jmp     short next_12

next_11:

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

		mov     ah,'C'
		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


	}
}
