?use80286
//директивы для драйвера
?sysattribute 0X8008	//АТРИБУТ - СИМВОЛЬНЫЕ ЧАСЫ
?sysname "CLOCK$"       //ИМЯ ДРАЙВЕРА
//СПИСОК КОМАНД
?syscommand INIT,NONE,NONE,NONE,INPUT,NONE,NONE,NONE,OUTPUT,OUTPUT,NONE,NONE,
            NONE,NONE,NONE,NONE,NONE;

?include "CONVERT.H--"
?include "WRITE.H--"
?include "driver.h--"

?define SCR_POS 144

//Структура даты DOS
?define dos_day 0	//дней после 1/1/80
?define dos_min 2	//минуты
?define dos_hr  3	//часы
?define dos_hun 4       //сотые секунды
?define dos_sec 5       //секунды

byte monday={31,28,31,30,31,30,31,31,30,31,30,31};
word OLD1C[2]=0;
word refresh=0;
word viewtime=FALSE;
word time[8]=0X1f3A;

INPUT()
{
	AX=ESWORD[BX+rh4_buf_seg];
	BX=ESWORD[BX+rh4_buf_ofs];	//АДРЕС ОБЛАСТИ ДАННЫХ
	ES=AX;
	$PUSH AX
	$PUSH BX
	AH=2;
	$INT 0X1A
	ESBYTE[BX+dos_min]=BCD2HEX(char CL);
	ESBYTE[BX+dos_hr]=BCD2HEX(char CH);
	ESBYTE[BX+dos_sec]=BCD2HEX(char DH);
	AL=refresh;
	CH=AL;
	CH>>=1;
	ESBYTE[BX+dos_hun]=AL*5+CH;
	AH=4;
	$INT 0X1A
	IF(CX<0X1995){	//ГОД МЕНЬШЕ 1998 - ВЕРОЯТНО СЛЕДУЮЩИЙ ВЕК
		IF(CX>0X1979)CL=CL-0x80;
		CH=0X20;
		$PUSH DX
		$PUSH CX
		AH=5;
		$INT 0X1A
		$POP CX
		$POP DX
	}
	BL=CL;
	$PUSH DX	//СОХРАНИТЬ ДЕНЬ И МЕСЯЦ
	CH=BCD2HEX(char CH);	//ВЕКОВ
	CL=BCD2HEX(char BL);
	DX=100;	//Преобразовать год в HEX
	AL=CH;
	AH=0;
	$MUL DX
	CH=0;
	AX+=CX;	//ТЕКУЩИЙ ГОД
	AX-=1980;	//ЧИСЛО ЛЕТ ПОСЛЕ 1980
	$PUSH AX
	BX=365;
	$MUL BX	//ДНЕЙ ПОСЛЕ 1980
	BX><AX;
	$POP AX
	CL=4;
	$DIV CL	//ВЫСОКОСНЫХ ЛЕТ
	CH=AH;	//ПРИЗНАК ВЫСОКОСНОГО ГОДА
	AH=0;
	BX+=AX;	//ДНЕЙ С ВЫСОКОСНЫМИ ДНЯМИ
	IF(CH==0)BX--;
	$POP DX	//ВОСТАНОВИТЬ ДЕНЬ И МЕСЯЦ
	$PUSH BX	//СОХРАНИТЬ ЧИСЛО ДНЕЙ
	BH=BCD2HEX(char DL);	//ДЕНЬ
	BL=BCD2HEX(char DH);  //МЕСЯЦ
	FOR(AL=BH,AH=0,BH=0,BX--,BX--;int BX>=0;BX--){
		DX=monday[BX];
		AX+=DX;
		IF((BL==1)&&(CH==0))AX++;
	}
	$POP BX
	AX+=BX;
	$POP BX
	$POP ES
	ESWORD[BX+dos_day]=AX;
	AX=0X100;
}

OUTPUT()
{
	SI=ESWORD[BX+rh8_buf_ofs];	//АДРЕС ОБЛАСТИ ДАННЫХ
	ES=ESWORD[BX+rh8_buf_seg];
	CH=HEX2BCD(char ESBYTE[SI+dos_hr]);
	CL=HEX2BCD(char ESBYTE[SI+dos_min]);
	DH=HEX2BCD(char ESBYTE[SI+dos_sec]);
	DL=0;
	AH=3;
	$INT 0X1A
//вычислить дату
	AX=ESWORD[SI+dos_day];//dosdays;
	AX++;
	AX=AX/365;	//число лет и остаток дней в последнем году
	DX++;
	$PUSH DX	//СОХР ОСТАВШИЕСЯ ДНИ
	BX=AX;
	CL=4;
	$DIV CL
	CL=AH;	//Признак высокосного года
	AH=0;   //AX - ЧИСЛО ВЫСОКОСНЫХ ЛЕТ
	AX++;   //т.к. 1980-высокосный
	$POP DX
	AX><DX;
	AX-=DX;	//уменьшить остаток на число высокосных дней
	IF(int AX <=0){	//до этого года
		AX+=365;
		IF(CL==0)AX++;
		BX--;
		CL--;
	}
	$PUSH BX	//ЧИСЛО ЛЕТ
	IF(CL==0)&&(AX<=60){	//в высокосный год до 1 марта
		IF(ZEROFLAG){
			CX=2;
			AX=29;
			GOTO OUT7;
		}
		AX++;
	}
	AX--;
	FOR(SI=0;;SI++){
		BX=monday[SI];
		IF(AX<=BX)BREAK;
		AX-=BX;
	}
	SI++;
	CX=SI;
OUT7:
	$POP BX
	BL+=80;
	BH=19;
	IF(BL>99){
		BL-=100;
		BH++;
	}
	DL=HEX2BCD();
	DH=HEX2BCD(char CL);
	CH=HEX2BCD(char BH);
	CL=HEX2BCD(char BL);
	AH=5;
	$INT 0X1A
	AX=0X100;
}

DISPLAY()
//получить время и преобразовать его в текстовую строку
{
	$PUSH CX
	$PUSH DX
	AH=2;
	$INT 0X1A
	BCD2ASC(char CH);
	DSBYTE[#time]=AL;
	DSBYTE[#time+2]=AH;
	BCD2ASC(char CL);
	DSBYTE[#time+6]=AL;
	DSBYTE[#time+8]=AH;
	BCD2ASC(char DH);
	DSBYTE[#time+12]=AL;
	DSBYTE[#time+14]=AH;
	$POP DX
	$POP CX
}

interrupt CLKINT()
//обработчик прерывания 1C
{
	asm{
		PUSHF
		CALL FAR CSDWORD[#OLD1C]	//вызов старого обработчика
		PUSH AX
		PUSH DS
		PUSH CS
		POP DS
	}
	AL=refresh;
	AL++;
	IF(AL>=18){	//прошла секунда
		IF(viewtime!=FALSE)DISPLAY();	//если нужно время получить его
		AL=0;
	}
	refresh=AL;
	IF(viewtime!=FALSE){	//отобразить время на экране, если это необходимо
		asm{
			CLI
			PUSH CX
			PUSH ES
			PUSH DI
			PUSH SI
		}
		ES=0XB800;
		DI=SCR_POS;
		CX=8;
		SI=#time;
		asm{
			cld
			REPE
			MOVSW
			POP SI
			POP DI
			POP ES
			POP CX
			STI
		}
	}
	$POP DS
	$POP AX
}

?setdinproc
/*
	нижележащий код будет отброшен после инициализации драйвера
 */

INIT()
{
	AX=#INIT;
	ESWORD[BX+rh0_brk_ofs]=AX;	//ОТБРОСИТЬ ПРОЦЕДУРУ ИНИЦИАЛИЗАЦИИ
	ESWORD[BX+rh0_brk_seg]=CS;
	SI=ESWORD[BX+rh0_bpb_tbo];	//проверка параметра ком строки
	$push DS
	$CLD
	CX=0;
	DS=ESWORD[BX+rh0_bpb_tbs];
	do{
		$LODSB
	}while(AL>' ');	//пропустить имя драйвера
	IF(AL!=13){
		do{
			$LODSB
		}while(AL==' ');	//пропустить пробелы
		IF(AL=='T'){	//проверить параметр на TIME
			$LODSW
			IF(AX==0X4D49){
				$LODSW
				IF(AL=='E')&&(AH<=' ')CL=1;	//есть то что искали
			}
		}
	}
	$POP DS
	viewtime=CX;
	WRITESTR("Device driver clock.\n(C) Copyright Mishel Sheker 1998.\nUdomlia Russia. Fido 2:5021/3.111.");
	$CLI	//перехватить вектор 1C
	ES=0;
	OLD1C[0]=ESWORD[0X1C*4];
	OLD1C[2]=ESWORD[0X1C*4+2];
	ESWORD[0X1C*4]=#CLKINT;
	ESWORD[0X1C*4+2]=CS;
	$STI
	IF(viewtime!=FALSE)DISPLAY();
	AX=0X100;
}
