/* Файл, содержащий вспомогательные функции :
         -  перехода в графический режим и инициализацию переменных
         -  рисования графиков, названия текущего режима
         -  окна помощи
         -  обработчик нажатия на клавишу
         -  обработчик прерывания IRQ3                                */

#include <graphics.h>
#include <dos.h>
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

/* константы для клавиатуры	*/
#define  KF1      	315
#define  Tab		9
#define  Esc		27
#define  Ret		13
#define  Left		331
#define  Right		333
#define  Ins		338
#define  Up		328
#define  Down		336
#define  PgUp		329
#define  PgDn		337
#define  Space      	32

/* Константа, определяющая минимальный интервал ввода в микросекундах   */
#define MIN_RATE	10

/* Константа, определяющая максимальный интервал ввода в микросекундах.
   На самом деле, максимальный интервал ввода равен 65535 микросекундам,
   значение 2000 выбрано, чтобы не было скучно ждать конца ввода.        */
#define MAX_RATE	2000

/* Константа, определяющая, на сколько будет увеличиваться/уменьшаться
   интервал ввода при нажатии на клавиши PgDn/PgUp.                       */
#define RATE_STEP	20

/* объявление используемых функций */
int handle_keyboard(int key);	/* обработчик нажатия на клавиатуру	*/
void ShowModeName(void);	/* рисование названия текущего режима 	*/
void initialize(void);	        /* переход в графический режим		*/
void DrawBufer(int *d, int nch, int n); /* рисование графиков		*/
void SetChannels(void);		/* наложение коэффициента усиления на
				   номера каналов                  	*/
void ClearWorkWindow(void);	/* очистка рабочего поля экрана		*/
void DrawMessage(char *Message);/* рисование сообщения в центре экрана  */
void HelpWindow(void);		/* переход в окно помощи		*/
void DrawCurrentParameters(void);/* рисование текущих параметров ввода  */
void DrawHelpMessages(void);     /* рисование названий параметров ввода */
void show_head(void);            /* рисование названия программы и строки
                                    помощи                              */

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

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

/* объявление переменных, объявленных в функции MAIN.C                  */
extern unsigned CurrentMode, NModes, Rate, NPoint, Channel, Usil;
extern unsigned far Channels[];
extern unsigned AutoSwitch, Nch, X;
extern char *ModesName[];

/* объявление графических переменных                                    */
int MaxX, MaxY;     /* максимальные значения по горизонтальной и
                       вертикальной координат в пикселях                */
int gdriver = DETECT, gmode; /* автораспознование типа дисплея          */
int  backcl=BLUE;            /* фон экрана - синий                      */
int WindowLeft,WindowTop;    /* координата верхнего левого угла окна    */
int WindowRight,WindowBottom;/* координата правого нижнего угла окна    */
int WindowHigh,WindowLength; /* высота и длина окна                     */
int WindowHalf;              /* половина высоты окна                    */
int WindowMiddle;            /* абсолютная координата середины окна     */

int MainColor=WHITE;         /* цвет графика                            */
int BackColor=DARKGRAY;      /* цвет фона графика                       */
int font;                    /* номер фонта с русским шрифтом           */

/* переменные, опрелеляющие положение окна помощи на экране             */
int HelpInfoX, HelpInfoY, HelpInfoH, HelpInfoLength;

/* названия параметров ввода */
char *HelpInfoStrings[]=
     {
     "ЧАСТОТА ВВОДА",
     "ЧИСЛО КАНАЛОВ",
     "КАНАЛ АЦП"
     };

/* функция перехода в графический режим и инициализация графических
   переменных                                                          */
void initialize()
{
/* проинициализируем графику			*/
initgraph(&gdriver, &gmode, "");
if (graphresult() != grOk)
    {
     printf("Не найден файл EGAVGA.BGI в текущей директории\n");
     exit(1);
    }

directvideo=0;

/* очистим экран                                                        */
setbkcolor(backcl);
cleardevice();

/* установим графические переменные 		                        */
MaxX=getmaxx();
MaxY=getmaxy();

WindowLeft=5;
WindowTop=40;
WindowRight=MaxX-50;
WindowBottom=MaxY-30;

WindowHigh=WindowBottom-WindowTop;
WindowLength=WindowRight-WindowLeft;
WindowHalf=WindowHigh/2;
WindowMiddle=WindowTop+WindowHalf;

HelpInfoX=WindowLeft+8;
HelpInfoY=WindowTop+8;
HelpInfoH=25;
HelpInfoLength=200;

NPoint=WindowLength-2;

/* загрузим русский фонт 			                        */
font=installuserfont("TRIP");
if(font == -11)
  {
   closegraph();
   cprintf("Не найден файл с русским фонтом TRIP.CHR в текущей директории\n");
   exit(1);
  }
settextstyle(font, HORIZ_DIR, 0);

/* нарисуем название программы и строки помощи                          */
show_head();

/*  нарисуем  название текущего режима                                  */
ShowModeName();
}

/* рисование графиков с автомасштабированием                            */
void DrawBufer(int *bufer, int nch, int n)
{
int i, j, k;
int y[16], max[16], h, *ptr, h2;

/* очистим экран 				                        */
ClearWorkWindow();

/* посчитаем координаты				                        */
for(i=0, h=WindowHigh/nch, h2=h/2; i < nch; i++) y[i]=WindowTop+i*h;

/* найдем максимальные значения для автомасштабирования                 */
for(i=0; i < nch; i++)
   for(j=max[i]=1, ptr=bufer+i; j < n; j++, ptr+=nch)
       if(abs(*ptr) > max[i]) max[i]=abs(*ptr);

/* нарисуем графики                                                     */
for(i=0, h2=h2*0.9, setcolor(MainColor); i < nch; i++)
   for(j=0, ptr=bufer+i,
       moveto(WindowLeft, y[i]+h/2-(long)(*ptr)*(long)h2/max[i]);
       j < n; j++, ptr+=nch)
            lineto(WindowLeft+j+1,y[i]+h/2-(long)(*ptr)*(long)h2/max[i]);
}

/* рисование вспомогательных надписей                                   */
void show_head(void)
{
setcolor(WHITE);

setusercharsize(40, 61, 30, 38);
outtextxy(5, 0, "Демонстрационная программа работы платы L-154.");

setusercharsize(40, 61, 30, 48);
outtextxy(5, MaxY-25, "F1 - Помощь .  Esc - Выход .  Пробел - новый режим .");

setusercharsize(40, 91, 30, 48);
outtextxy(MaxX-48, 5, "режим");
}

/* рисовалка названия текущего режима                           */
void ShowModeName(void)
{
int i, j, l, step, h2;
char buf[2];

/* очистим часть экрана 				        */
setfillstyle(SOLID_FILL, BLUE);
bar(WindowRight, WindowTop, MaxX, WindowBottom);

setcolor(WHITE);
setusercharsize(40, 40, 40, 38);

l=strlen(ModesName[CurrentMode]);
step=WindowHigh/l;

for(i=buf[1]=0, h2=step/4; i < l; i++)
  {
  buf[0]=ModesName[CurrentMode][i];
  outtextxy(MaxX-30, WindowTop+i*step+h2, buf);
  }
}

/* заполнение массива с номерами каналов для многоканального ввода,
   с установлением коэффициента усиления */
void SetChannels(void)
{
int i;

for(i=0; i < 16; i++) Channels[i]=i | Usil << 6;

Channel &= 0x0F;
Channel |= Usil << 6;
}

/* очистим экран 				*/
void ClearWorkWindow(void)
{
setfillstyle(SOLID_FILL, BackColor);
bar(WindowLeft, WindowTop, WindowRight, WindowBottom);
}

/* рисовалка сообщения 				                */
void DrawMessage(char *Message)
{
int l, i;

setcolor(WHITE);
l=strlen(Message)*12;
i=WindowLeft+WindowLength/2-l/2;

settextstyle(font, HORIZ_DIR, 2);

outtextxy(i, WindowMiddle, Message);
settextstyle(font, HORIZ_DIR, 0);
}

/* окно подсказки 			                        */
void HelpWindow(void)
{
int key;

/* очистим окно                 */
ClearWorkWindow();

/* нарисуем названия параметров */
DrawHelpMessages();
do
  {
  DrawCurrentParameters();      /* рисование значений параметров        */
  if(!(key=getch())) key=getch()+256;
  if(key == Esc) break;
  while(kbhit()) getch();
  } while(handle_keyboard((key > 255) ? key : toupper(key)));
}

/* обработаем нажатие на клавишу 					*/
int handle_keyboard(int key)
{
int flag=1;

    switch(key)
       {
       case Space :     /* пробел -> преход в следующий режим 		*/
			if(++CurrentMode == NModes) CurrentMode=0;
			ShowModeName();
			break;

       case 'P':	/* пауза 					*/
			getch();
			break;

      case 'A':		/* автоинкремент режима 			*/
			AutoSwitch ^= 1;
			break;

      case 'N':
			/* увеличим количество каналов для
			   многоканального ввода			*/
			if(++Nch > 16) Nch=2;
			break;

      case Right:	/* увеличим номер канала для
			   одноканального ввода				*/
			Channel &= 0x0F;
			if(++Channel > 15) Channel=0;
			Channel |= Usil << 6;
			break;

      case Left:	/* уменьшим номер канала для одноканального
			   ввода					*/
			Channel &= 0x0F;
			Channel=(Channel) ? Channel-1 : 15;
			Channel |= Usil << 6;
			break;

      case Down:   	/* уменьшим частоту ввода на единицу	*/
			if(++Rate < MIN_RATE || Rate > MAX_RATE)
                             Rate=MAX_RATE;
			break;

      case Up:   	/* увеличим частоту ввода на единицу	*/
			if(--Rate < MIN_RATE) Rate=MIN_RATE;
			break;

      case PgDn:   	/* уменьшим частоту ввода на единицу	*/
			Rate+=RATE_STEP;
			if(Rate < MIN_RATE || Rate > MAX_RATE)
                             Rate=MAX_RATE;
			break;

      case PgUp:   	/* увеличим частоту ввода на RATE_STEP	*/
			Rate-=RATE_STEP;
			if(Rate < MIN_RATE || Rate > MAX_RATE)
                             Rate=MIN_RATE;
                        break;

      default    :      flag=0;
			/* если переходим в новый режим			*/
			if(key >= '0' && key <= '7')
			   {
			   CurrentMode=key-'0';
			   ShowModeName();
			   AutoSwitch=1;
			   break;
			   }
       }

return flag;
}

/* рисование названий параметров ввода */
void DrawHelpMessages(void)
{
int i, col=LIGHTCYAN;

setcolor(col);
setusercharsize(40, 55, 30, 50);
for(i=0; i < 3; i++)
   outtextxy(HelpInfoX, HelpInfoY+HelpInfoH*i, HelpInfoStrings[i]);
}

/* рисование текущих параметров ввода  */
void DrawCurrentParameters(void)
{
int i, col=10;
char buf[50];

/* очистим экран 				*/
setfillstyle(SOLID_FILL, BackColor);
bar(HelpInfoX+HelpInfoLength, HelpInfoY,
    HelpInfoX+HelpInfoLength+340, HelpInfoY+HelpInfoH*3);

setcolor(col);
setusercharsize(40, 55, 30, 50);

/* нарисуем текущую частоту ввода                               */
if(Rate > 1000) sprintf(buf, "%5u мкс (%7.0f Гц)", Rate, 1000000./Rate);
  else sprintf(buf, "%5u мкс (%7.3f кГц)", Rate, 1000./Rate);
outtextxy(HelpInfoX+HelpInfoLength, HelpInfoY, buf);

/* нарисуем число каналов для многоканального ввода             */
sprintf(buf, "%7u", Nch);
outtextxy(HelpInfoX+HelpInfoLength, HelpInfoY+HelpInfoH*1, buf);

/* нарисуем номер канала для одноканального ввода               */
sprintf(buf, "%7u", (Channel & 0x0F) + 1);
outtextxy(HelpInfoX+HelpInfoLength, HelpInfoY+HelpInfoH*2, buf);
}

/* Драйвер обработчик прерывания IRQ3 от платы L-154.
   Вводит один отсчет и отображает его на экране. 	*/
void interrupt E_Interrupt(PARM)
{
/* проверим на конец окна 				*/
if(X < WindowLength)
    {
    if (!X)
      {
      moveto(X+WindowLeft+1,WindowMiddle-(long)SAMPLE()*
	    (long)WindowHalf/2048);
      setcolor(WHITE);
      }
     else lineto( X+WindowLeft+1, WindowMiddle-(long)SAMPLE()*
                                  (long)WindowHalf/2048);
    X++;
    }

/* сбросим флаг прерывания 				*/
RESET_IRQ();
}
