#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
#include "sysp.h"

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

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

// Макро для выдачи звукового сигнала

#define BEEP() _asm { \
	_asm mov bx,0 \
	_asm mov ax, 0E07h \
	_asm int 10h \
}

void main(void);

// Описание программы-обработчика прерывания
// будильника

void _interrupt _far alarm(void);

// Переменная для хранения старого
// вектора будильника

void (_interrupt _far *old_4a)(void);


void main(void) {

char *month_to_text[] = {

	"январь",
	"февраль",
	"март",
	"апрель",
	"май",
	"июнь",
	"июль",
	"август",
	"сентябрь",
	"октябрь",
	"ноябрь",
	"декабрь"

};

SYSTIMER tmr;

// Определяем текущие дату и время

	timer(RTC_GET_DATE, &tmr);
	timer(RTC_GET_TIME, &tmr);

// Выводим дату и время на экран

	printf("\nСейчас %d год, %s, %d число."
			 "\n",
			 bcd2bin(&(tmr.year)),
			 month_to_text[bcd1bin(&(tmr.month)) - 1],
			 bcd1bin(&(tmr.day)));

	printf("\nВремя - %02.2d:%02.2d:%02.2d"
			 "\n",
			 bcd1bin(&(tmr.hour)),
			 bcd1bin(&(tmr.min)),
			 bcd1bin(&(tmr.sec)));

// Для установки будильника увеличиваем
// счетчик минут на единицу. Для упрощения
// программы мы не проверяем счетчик на
// переполнение, поэтому если текущее
// значение счетчика минут равно 59,
// будильник не сработает. Вы можете сами
// немного усовершенствовать программу для
// проверки переполнения.

	bin1bcd(bcd1bin(&(tmr.min)) + 1,
						 &(tmr.min));

// Выводим на экран время, когда сработает
// будильник.

	printf("\nВремя срабатывания будильника"
					"- %02.2d:%02.2d:%02.2d"
			 "\n",
			 bcd1bin(&(tmr.hour)),
			 bcd1bin(&(tmr.min)),
			 bcd1bin(&(tmr.sec)));

// Подключаем свой обработчик прерывания
// будильника, старое значение вектора
// 0x4a сохраняем

	old_4a = _dos_getvect(0x4a);

	_dos_setvect(0x4a, alarm);

// Устанавливаем будильник

	timer(RTC_SET_ALARM, &tmr);

	printf("\nБудильник установлен. Для отмены "
				 "и завершения программы нажмите"
			 "\nлюбую клавишу...");

	getch();

// Сбрасываем будильник и восстанавливаем
// вектор прерывания будильника

	timer(RTC_CLEAR_ALARM, &tmr);

	_dos_setvect(0x4a, old_4a);

	exit(0);
}

// ----------------------------------
// Преобразование однобайтового
// числа из формата BCD в двоичный
// формат.
// ----------------------------------

int bcd1bin(char *bcd) {

	return( ((*bcd) & 0x0f) +
			  10 * (((*bcd) & 0xf0) >> 4) );

}

// ----------------------------------
// Преобразование двухбайтового
// числа из формата BCD в двоичный
// формат.
// ----------------------------------

int bcd2bin(char *bcd) {

	return( bcd1bin(bcd) + 100 * bcd1bin(bcd + 1) );

}

// ----------------------------------
// Преобразование однобайтового
// числа из двоичного формата
// формат BCD.
// ----------------------------------

int bin1bcd(int bin, char *bcd) {

	int i;

	i = bin / 10;

	*bcd = (i << 4) + (bin - (i * 10));

}

// ----------------------------------
// Программа получает управление
// при срабатывании будильника.
// Ее назначение - выдать звуковой сигнал.
// ----------------------------------

void _interrupt _far alarm(void) {

	BEEP();
	BEEP();
	BEEP();
	BEEP();
	BEEP();
	BEEP();
	BEEP();

}
