/************************************************************************/
/*                                                                      */
/*    Демонстрационная программа использования драйвера L154DRV.ASM    */
/*                       для платы  L-154                              */
/*                                                                      */
/*    Функциональные клавиши:                                           */
/*                                                                      */
/*	   'Esc'	-  выход из программы;                          */
/*	    'P'		-  пауза                                        */
/*	    'A'		-  включение авторотации режима                 */
/*	    'N'	        -  увеличение числа вводимых каналов            */
/*	    'F1'        -  вывод окна помощи                            */
/*      'Space'(пробел)	-  переход к следующему режиму                  */
/*     Стрелкм Влево/Вправо - выбор номера канала АЦП                   */
/*     Стрелки Вверх/Вниз -  увеличение/уменьшение интервала ввода на   */
/*			   одну микросекунду                            */
/*	  PgUp/PgDn     -  увеличение/уменьшение интервала ввода на     */
/*			   двадцать микросекунд                         */
/************************************************************************/

#include <graphics.h>
#include <dos.h>
#include <math.h>
#include <alloc.h>
#include <conio.h>
#include <ctype.h>

/* константы для клавиатуры	*/
#define  Esc		27
#define  Space      	32
#define  KF1      	315

/* объявление используемых функций */
int handle_keyboard(int key);	/* обработчик нажатия на клавиатуру	*/
void ShowModeName(void);	/* рисование названия текущего режима 	*/
void initialize(void);	        /* переход в графический режим		*/
void DrawBufer(int *d, int nch, int n); /* рисование графиков		*/
void SetChannels(void);		/* наложение коэффициента усиления на
                                   номера каналов, первые пять бит
                                   номера канала содержат собственно сам
				   номер канала, следующий бит определяет
                                   режим подключения, следующие два бита
				   содержат коэффициент усиления :
                                       00 - отключение канала
				       01 - 1.024 В
				       10 - 2.56 В
				       11 - 5.12 В                  	*/
void ClearWorkWindow(void);	/* очистка рабочего поля экрана		*/
void DrawMessage(char *Message);/* рисование сообщения в центре экрана  */
void HelpWindow(void);		/* переход в окно помощи		*/

/* переменная, определяющая длину рабочего окна                         */
extern int WindowLength;

/* Объявление функции обработчика прерывания 	                        */
#ifndef __cplusplus
#define PARM void
#else
#define PARM ...
#endif

#include "function.h"
void interrupt E_Interrupt(PARM);

/* объявление глобальных переменных                                    */
int far *Bufer;	      /* указатель на буфер для вводимых/выводимых данных*/
unsigned CurrentMode=0;
unsigned NModes=8;    /* число демонстрационных режимов                   */
unsigned Rate=100;    /* частота ввода 10 кГц ( 100 мкс )                 */
unsigned NPoint;      /* число вводимых отсчетов на один канал            */
unsigned Channel=0;   /* номер канала для многоканльного ввода            */
unsigned far Channels[16];/* массив с номерами каналов для многоканального
			 ввода                                            */
unsigned Usil=3;      /* коэффициент усиления
			  00 - отключение канала
			  01 - 1.024 В
			  10 - 2.56 В
			  11 - 5.12 В                  	          */
unsigned Nch=4;       /* число каналов для многоканального ввода          */
unsigned X;           /* горизонтальная координата текущей выводимой
			 точки в режиме прерываний                        */
unsigned BaseAddress=0x300;/* базовый адрес платы в пространстве PC       */
unsigned AutoSwitch=1; /* определяет, включен ли режим непрерывного
			  переключения режимов                            */

/* названия демонстрационных режимов                                   */
char *ModesName[]={"ADCHAN","SAMPLE","KADR","STREAM","SOFT",
		   "INTERRUPT", "OUT DA", "DA STREAM"};


/************************************************************************/
/* Основная функция							*/
/************************************************************************/
main(void)
{
int i, j, n, nseg, key, rate;

/* выделим память	*/
Bufer=(int *)malloc(40960L);
if(Bufer == NULL) { cprintf("\n\rNo Memory "); exit(1); }

/* укажем, какой базовый адрес использовать драйверу  			*/
SETBASEADDRESS(BaseAddress);

/* Проверим на наличие платы с загруженным драйвером 			*/
if(PLATA_TEST()) { cprintf("\n\rNo L154 Found.\n\r"); exit(1); }

/* укажем драйверу, который номер IRQ установлен на плате
     irq_number = 0   -> IRQ3
     irq_number = 1   -> IRQ4
     irq_number = 2   -> IRQ5
     irq_number = 3   -> IRQ6.						*/
INTR_SETUP(0);

/* заполним массив с номерами каналов и коэффициентом усиления          */
SetChannels();

/* перейдем в графический режим						*/
initialize();

/********************* Основной цикл программы *****************/
for(key=0;;)
    {
    /* введем что-то с клавиатуры с отслеживанием функционалных клавиш */
    if(kbhit())
       {
       if(!(key=getch())) key=getch()+256;

       if(key == Esc) break;

       /* прочистим очередь клавиатуры, чтобы вдруг не запищала		*/
       while(kbhit()) getch();

       if(key == KF1)  HelpWindow();
       }

    /* обработаем нажатие на клавишу				*/
    handle_keyboard((key > 255) ? key : toupper(key));

    /* войдем в текущий демонстрационный режим 			*/
    switch(CurrentMode)
       {
       case 0:	/****************************************************
		   режим однократного ввода при помощи функции ADCHAN
		   с синхронизацией от внутреннего таймера
		   Вызываемые функции : ADCHAN, TIMER, WAIT_TIMER
								*/
		do
		{
		/* установим режим генерирования меандра на таймере */
		TIMER(0,3,Rate);

		/* введем данные */
		SETCHANNEL(Channel);
		for(i=0; i < NPoint; i++)
		   {
		   WAIT_TIMER(0); /* дождемся перехода на таймере*/
		   Bufer[i]=SAMPLE(); /* введем значение */
		   }

		/* отобразим введенный массив			*/
		DrawBufer(Bufer, 1, NPoint);
		} while(!kbhit() && AutoSwitch);
		break;

       case  1:	/****************************************************
		   режим однократного ввода при помощи функции SAMPLE
		   с синхронизацией от внутреннего таймера
		   Вызываемые функции : SAMPLE, TIMER, WAIT_TIMER,
					SETCHANNEL		*/
		do
		{
		/* установим режим генерирования меандра на таймере */
		TIMER(0,3,Rate);

		/* введем данные */
		SETCHANNEL(Channel);
		for(i=0; i < NPoint; i++)
		   {
		   WAIT_TIMER(0); /* дождемся перехода на таймере*/
		   Bufer[i]=SAMPLE(); /* введем значение */
		   }

		/* отобразим введенный массив			*/
		DrawBufer(Bufer, 1, NPoint);
		} while(!kbhit() && AutoSwitch);
		break;


       case 2:	/****************************************************
		   режим однократного многоканального ввода при помощи
		   функции KADR с синхронизацией от внутреннего таймера
		   Вызываемые функции : KADR, TIMER, WAIT_TIMER */
		do
		{
		/* установим режим генерирования меандра на таймере     */
		TIMER(0,3,Rate);

		/* введем данные */
		for(i=0; i < NPoint; i++)
		   {
		   WAIT_TIMER(0); /* дождемся перехода на таймере*/
		   KADR(Bufer+i*Nch, Channels, Nch); /* введем значение */
		   }

		/* отобразим введенный массив			*/
		DrawBufer(Bufer, Nch, NPoint);
		} while(!kbhit() && AutoSwitch);
		break;

       case 3:	/****************************************************
		   режим одноканального ввода в программном режиме
		   при помощи функции STREAM.
		   Вызываемые функции : STREAM.
		   Предельная частота ввода 100 кГц (10 мкс).      */

		do {
		STREAM(Bufer, NPoint, Channel, Rate); /* введем данные     */
		DrawBufer(Bufer, 1, NPoint); /* отобразим введенный массив */
		} while(!kbhit() && AutoSwitch);
		break;

       case 4:	/****************************************************
		   режим многоканального ввода в программном режиме
		   при помощи функции SOFT.
		   Вызываемые функции : SOFT
		   Предельная частота ввода 100 кГц (10 мкс) на канал  плюс
								    */

		rate=(Rate < Nch*10) ? Nch*10 : Rate;
		do {
		SOFT(Bufer, NPoint, Channels, Nch, rate);
		DrawBufer(Bufer, Nch, NPoint);
		} while(!kbhit() && AutoSwitch);
		break;

       case 5:	/****************************************************
		   режим генерации прерываний :
		   драйвер - обработчик прерывания вводит отсчет с канала
		   Channel и отображает его на экране
		   Вызываемые функции : SETCHANNEL, SAMPLE, INITINTR,
					STOP_INTR.
								*/

		SETCHANNEL(Channel); /* установим номер канала  */

		X=700;    /* запретим прерыванию вводить данные */

		/* установим интервал между прерываниями 1000 мкс и
		   адрес обработчика E_Interrupt                */
		INITINTR(100, 10, E_Interrupt);

		do {
		/* очистим экран 				*/
		ClearWorkWindow();
		X=0;

		/* подождем либо завершения заполнения экрана либо
		   нажатия на клавишу 				*/
		while(!kbhit() && X < WindowLength);

		/* если произошло нажатие на клавиатуре 	*/
		if(kbhit()) break;

		} while(!kbhit() && AutoSwitch);

                /* запретим прерывания от платы и восстановим
                   контроллер прерываний                        */
		STOP_INTR();
		break;

       case 6:	/****************************************************
		   режим вывода на первый ЦАП пилообразного сигнала
		   при помощи функции OUTDA.
		   Вызываемые функции : OUTDA.
								*/

		ClearWorkWindow();
		DrawMessage("На ЦАП выводится пилообразный сигнал.");
		do   for(i=0; i < 4096; i++) OUTDA(i);
		while(!kbhit() && AutoSwitch);
		break;

       case 7:	/****************************************************
		   режим вывода на первый ЦАП пилообразного сигнала
		   при помощи функции OUTSTREAM.
		   Вызываемые функции : OUTSTREAM.
								*/
		ClearWorkWindow();
		DrawMessage("На ЦАП выводится пилообразный сигнал.");
		for(i=0; i < 4096; i++) Bufer[i]=i;
		do OUTDAARRAY(Bufer, 20, 4096);
		while(!kbhit() && AutoSwitch);
		break;

       }
    if(!AutoSwitch) { key=Space;  delay(750);  }
    }

/* выйдем из графического режима 			*/
closegraph();

/* выйдем из программы, заодно освободив всю память	*/
exit(0);

return 0;
}
