/*------------------------------- i r c . c  -------------------------------*/
/* Experimental interrupt handler.                                          */
/* This routine sets up a level 2 interrupt server that is triggered by the */
/* ACK pin of the parallel port going low.  The interrupt server then uses  */
/* Timer B in CIA-B to time reading in data from the parallel port.         */
/* The ACK and one data input pin on the parallel port are tied             */
/* together by the hardware I built.  Initially the ACK interrupt is        */
/* enabled and the software sits and waits for something to happen.         */
/*                                                                          */
/* NEED TO CHECK RESOURCES  ---- FREEMEM!!!!!!!!!!!!!!!!*/
/*--------------------------------------------------------------------------*/
 
/*--- Includes and Defines. */

#include "irc.h"
#include "IRMaster.h"   /* Definitions of Screen, Window and gadgets. */

/* DBG = 1 --> Turn on debug printf's, DBG = 0 --> Turn off debug printf's. */
#define DBG 1
/* Set DEBUG to 0 to comment out code related to opening screen and window.*/
#define DEBUG 1

#define NOERROR 0
#define ERROR 1
/*--- NSAMPLES is the number of data samples to be read into buffer. */
#define NSAMPLES 3000
/*--- TOLERENCE is the number of samples difference that is tolerated in */
/*--- order to match two patterns. */
#define TOLERENCE 50

/*--- External system variables. */

extern struct Custom custom;
extern struct CIA ciab;

extern struct GfxBase *GfxBase;
extern struct IntuitionBase *IntuitionBase;
extern struct WBStartup *WBenchMsg;  /* For Workbench startup. */

/**********************************************************/  
/***************** Timer B Interrupt code *****************/
/**********************************************************/  
/*
   Update Timer every TIME_SLICE microseconds.
   TIME_SLICE = 1.397 * (desired # of microseconds) [71 = 100us]
   71, 50 work.
*/
#define TIME_SLICE ((unsigned short)35)

/* Defines to make the code more readable. */

#define ciatlo		ciab.ciatblo
#define ciathi		ciab.ciatbhi
#define ciacr		ciab.ciacrb
#define ciaicr		ciab.ciaicr

int TimerSigBit = -1;   /* Allocated signal bit. */
ULONG TimerSigMask;      /* TimerSigBit converted into a mask. */
static struct Library *CIAResource = NULL;
struct Task *thisTask;

int NSamples;           /* Number of samples in buffer. */

int SetUpTimer()
{
   char temp;
   unsigned short micros;

   /*--- Check to see if timer B in CIA-B is already in use. */
   /*--- If START bit is set timer is probably being used. */

#if DBG
   printf("\n Timer B control register = %X",ciab.ciacrb);
#endif
   if(ciab.ciacrb & 0x01)
   {
      printf("\n Timer B is already allocated.  Proceding anyway.");
   }

   /*--- Set latched value for timer to count down from. */

   micros = TIME_SLICE;
#if DBG
   printf("\n Sampling interval = %d * 1.397 microseconds", micros);
#endif
   ciatlo = micros & 0xFF;
   ciathi = micros >> 8;

   /*--- Get ID for this task so can send it a signal. */

   thisTask = NULL;
   thisTask = FindTask(NULL);
   if(thisTask == NULL)
   {
      printf("\n Error - Can't find this task ID.");
      return(ERROR);
   }

   /*--- Get a signal bit. */

   if((TimerSigBit = AllocSignal(-1L)) == -1)
   {
      printf("\n Timer: AllocSignal failed.");
      StopTime();  /* Deallocate resources. */
      return(ERROR);
   }
   TimerSigMask = 1L << TimerSigBit;

   /*--- Open the CIA resource. */

   if((CIAResource = OpenResource(CIABNAME)) == NULL)
   {
      printf("\n Timer: Couldn't open %s.", CIABNAME);
      StopTime();  /* Deallocate resources. */
      return(ERROR);
   }

   /*--- Interrupts have been enabled so may already */
   /*--- have an interrupt.  So do this... */

   ciab.ciacrb &= ~CIACRBF_START;	/* stop timer */

   temp = ciaicr;  /* Read IRC register to clear interrupt. */

   SetSignal(0, TimerSigMask);	/* clear signal */

#if DBG
   printf("\n About to set RUNMODE");
#endif
   ciacr &= ~CIACRBF_RUNMODE; /* Set it to reload upon underflow. */
   ciacr &= ~CIACRBF_PBON; /* Output line PB7 is left alone. */
   ciacr &= ~CIACRBF_INMODE0; /* Count clock pulses. */
   ciacr &= ~CIACRBF_INMODE1; /* Count clock pulses. */

#if DBG
   printf("\n About to strobe LOAD");
#endif
   ciacr |= CIACRBF_LOAD; /* Strobe Load to latch in countdown value. */

#if DBG
   printf("\n About to enable timer b interrupts");
#endif
   ciaicr = 0x7D;  /* Disable all other CIA-B interrupts. */
   ciaicr = CIAICRF_SETCLR|CIAICRF_TB;  /* Enable timer B interrupts. */
#if DBG
   printf("\n Enabled timer b interrupts");
#endif

   return(NOERROR);
}

int StopTime()
{
   if(thisTask != NULL)
   {
      /*--- Disable timer B interrupts. */

#if DBG
      printf("\n Stopping timer B.");
#endif
      ciaicr = CIAICRF_TB;

      /*--- Halt timer. */

      ciacr &= ~CIACRBF_START;

      /*--- Free resources. */

      if(TimerSigBit != -1)
      {
#if DBG
         printf("\n Freeing signal bit.");
#endif
         FreeSignal(TimerSigBit);
      }
   }

   return(NOERROR);
}

/**********************************************************/  
/***************** LEVEL 2 Interrupt code *****************/
/**********************************************************/  

extern void ircserver();
struct Interrupt intrpt;

int AddINT2Server()
{
   /*--- init NODE structure */

   intrpt.is_Node.ln_Type = NT_INTERRUPT;
   /* Was 0 but glasses flickered.  3 fixed it. */
   intrpt.is_Node.ln_Pri  = 127;
   intrpt.is_Node.ln_Name = "WWB";
   intrpt.is_Code        = ircserver;
   intrpt.is_Data        = NULL;

#if DBG
   printf("\n About to add interrupt server...");
#endif

   AddIntServer(INTB_PORTS, &intrpt);		/* Add server to chain */

#if DBG
   printf("\n Added interrupt server.");
#endif

   return(NOERROR);
}


int RemoveServer()
{
   RemIntServer(INTB_PORTS, &intrpt);

   return(NOERROR);
}


/**********************************************************/  
/************************** MAIN **************************/
/**********************************************************/  

unsigned char *buffer;  /* Pointer to storage for data to be read in. */
unsigned char zuffer[NSAMPLES];  /* Storage for data to be read in. */
unsigned char pattern[20][NSAMPLES];  /* Stored signal patterns. */
char *address, mask;

struct Screen *Screen = NULL;
struct Window *Window = NULL;
struct RastPort *WRPort;
struct ViewPort *WVPort;

struct IntuiMessage *message;
ULONG class;
USHORT code;
struct Gadget *igad;
USHORT gadget_id;
extern int BackGround();
int helptxt();
int IRButtonOff();                 /* Unhighlight button. */
int IRButtonOn();                  /* Highlight button. */
int IRButtonLabel();               /* Relabel button. */
int GetPattern();                  /* Get signal pattern. */
int DisplayPattern();              /* Draw the signal pattern. */
int DPattern();                    /* Debug. */

/*--- Buffers for area fill and text. */

WORD chip areaArray[100];  /* Max of 20 vertices times 5 words per vertex. */
struct AreaInfo myAreaInfo;
PLANEPTR workspace;
struct TmpRas myTmpRas;

#define NOTHING 0
int active[21] =  /* Used to remember which buttons have patterns. */
{ 
   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 
   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 
   FALSE
};




main(argc, argv)
int argc;
char **argv;
{
   int it, error, iz, is, try;
   int diff[4], match, smallest;
   BOOL exitflag;
   int mode;  /* Current mode of program (LEARN, NOTHING, etc. ) */
   int IRButtonSelected = -1;         /* Index of button currently selected. */

   /*--- Ignore CTRL-C and CTRL-D. */

   signal(SIGINT, SIG_IGN);

   /*--- Open graphics and Intuition Libraries. */

   GfxBase = NULL;
   GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 33);
   if(GfxBase == NULL)
   {
      printf("\n Error opening graphics library.");
      goto ShutDown;
   }

   IntuitionBase = NULL;
   IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 33);
   if(IntuitionBase == NULL)
   {
      printf("\n Error opening Intuition library.");
      goto ShutDown;
   }

   /*--- Open a new screen. */

   Screen = (struct Screen *) OpenScreen(&NewScreenStructure); 
   if(Screen == 0L)
   {
      printf("\n Error opening a new screen.");
      goto ShutDown;
   }

#if DEBUG
   /*--- Open window in screen. */

   NewWindowStructure1.Screen = Screen;
 
   Window = (struct Window *) OpenWindow(&NewWindowStructure1);
 
   if(Window == 0L)
   {
      printf("\nError opening a new window");
      goto ShutDown;
   }

   /*--- Get pointers to window structures. */

   WRPort = Window->RPort;   /* Get pointer to windows' RastPort. */
   WVPort = (struct ViewPort *)ViewPortAddress(Window); /* Get pointer to window viewport. */

   /*--- Set up area fill and text work buffers. */

   InitArea(&myAreaInfo, &areaArray[0], 20);
   WRPort->AreaInfo = &myAreaInfo;

   workspace = AllocRaster(640, 200);
   if(workspace == 0)
   {
      printf("\n Error - No space for temporary raster.");
      goto ShutDown;
   } else
   {
      InitTmpRas(&myTmpRas, workspace, RASSIZE(640,200));
      WRPort->TmpRas = &myTmpRas;
   }

   /*--- Set color map. */

   LoadRGB4(WVPort, Palette, (SHORT)16);

   /*--- Draw raised background areas. */

   BackGround();

   /*--- Redraw the gadgets on top of the raised background. */

   RefreshGadgets(&ARexx, Window, 0);
#endif /*DEBUG*/

   /*--- Allocate the parallel port resource so that other tasks know it  */
   /*--- is taken. (This might not be a good idea.  Online! allocates the */
   /*--- the parallel port and this prevents me from doing                */
   /*--- "copy file to par:" in a seperate window.  So leave it out for   */
   /*--- now.  User will know if one program walks over another.          */

   /*****************
   MR_ALLOCMISCRESOURCE(MR_PARALLELPORT, "IRMaster");
   MR_ALLOCMISCRESOURCE(MR_PARALLELBITS, "IRMaster");
   *****************/

   /*--- Set up pointer to data buffer for SoftHandler(). */
   /*--- Assembler doesn't seem to recognize zuffer but DOES buffer. */

   buffer = &zuffer[0];
#if DBG
   printf("\n buffer = %X", buffer);
#endif

   /*--- Set up all the interrupt servers. */

   AddINT2Server();

   error = SetUpTimer();
   if(error)goto Fini;

   /*--- Explicitly enable level6 and level2 interrupts (even though */
   /*--- they already seem to be enabled by default).                */

/********* Causes sometimes guru.
   Disable();
   custom.intena |= INTF_SETCLR | INTF_EXTER;
   custom.intena |= INTF_SETCLR | INTF_SOFTINT;
   Enable();
*********/

#if DBG
   /* This is slightly dangerous since it might clear any pending interrupts. */
   /*printf("\n Enabled interrupts are: %X", custom.intenar);*/
#endif

   /*--- Set address for IRC register (used in GetSample.) */

   address = (char *)0xBFED01;/* Address of the Interrupt Control Register in 8520-A */

   /*--- MAIN PROGRAM LOOP. */
   /*--- Get messages from window until user presses CloseWindow gadget. */

#if DEBUG
   exitflag = FALSE;
   mode = NOTHING;
   while(exitflag == FALSE)
   {
      /*--- If in DOIT mode wait for IR input. */
 
      if(mode == DOIT)
      {
         /*--- Wait for user to press a button. */

         GetSample();

         /*--- Match input to stored samples. */

         match = find_match();
      }

      /*--- Check for user action. */

      message = (struct IntuiMessage *)GetMsg(Window->UserPort);
      if(message != 0)
      {
         class = message->Class;
         code = message->Code;
         igad = (struct Gadget *)message->IAddress;/*get pointer to gadget */
         ReplyMsg((struct Message *)message);

         if(class == GADGETUP)
         {
            gadget_id = igad->GadgetID;   /* get my gadget code */
            switch(gadget_id)
            {
               case COMMANDSTR3:
#if DBG
                  printf("COMMANDSTR3\n");
#endif
                  break;

               case COMMANDSTR1:
#if DBG
                  printf("COMMANDSTR1 = %s\n", commandstr1SIBuff);
#endif
                  /*--- Change the label on the button. */

                  IRButtonLabel(commandstr1SIBuff, IRButtonSelected);

                  /*--- Prompt user for next action. */

                  helptxt("Now press the button on your handheld IR remote control",
                     "that you want memorized.");

                  /*--- Get verified signal sample from the IR receiver. */

                  GetPattern(IRButtonSelected);

                  /*--- Remember which buttons have patterns stored. */

                  active[IRButtonSelected] = TRUE;

                  /*--- Unhighlight the control button. */

                  IRButtonOff(&IRButtonSelected);
                  mode = NOTHING;

                  break;

               case COMMANDSTR2:
#if DBG
                  printf("COMMANDSTR2\n");
#endif
                  break;

              default:
                  break;
            } /* switch(gadget_id) */
         } /* if(GADGETUP) */

         if(class == GADGETDOWN)
         {
            gadget_id = igad->GadgetID;   /* get my gadget code */
            switch(gadget_id)
            {
               case EXIT:
#if DBG
                  printf("EXIT\n");
#endif
                  goto Fini;
                  break;

               case AUTHOR:
#if DBG
                  printf("AUTHOR\n");
#endif
                  break;

               case DOIT:
#if DBG
                  printf("DOIT\n");
#endif
                  mode = DOIT;
                  break;

               case GETSET:
#if DBG
                  printf("GETSET\n");
#endif
                  break;

               case SAVESET:
#if DBG
                  printf("SAVESET\n");
#endif
                  break;

               case LEARN:
#if DBG
                  printf("LEARN\n");
#endif
                  helptxt("Press one of the twenty control buttons above.","");
                  mode = LEARN;
                  break;

               case AREXX:
#if DBG
                  printf("AREXX\n");
#endif
                  break;

               case IR20:
               case IR19:
               case IR18:
               case IR17:
               case IR16:
               case IR15:
               case IR14:
               case IR13:
               case IR12:
               case IR11:
               case IR10:
               case IR9:
               case IR8:
               case IR7:
               case IR6:
               case IR5:
               case IR4:
               case IR3:
               case IR2:
               case IR1:
                  /*--- Unhighlight any currently selected button. */

                  IRButtonOff(&IRButtonSelected);

                  /*--- Set current button to highlight and highlight it. */

                  IRButtonSelected = (gadget_id - IR1) + 1;

                  IRButtonOn(IRButtonSelected);
#if DBG
                  printf("IR-%d\n", (gadget_id - IR1) + 1);
#endif
                  if(mode == LEARN)
                  {
                     /*--- Prompt user. */

                     helptxt("Enter the label name for the control button,",
                        "then press RETURN.");
                  } else
                  {
                     helptxt("Please choose a function button first.", "");
                  }
                  break;


               default:
                  mode = NOTHING;
                  printf("Error - Got a hit on an unknown gadget\n");
                  printf(" Gadget id was: hex: %X  decimal: %d\n", gadget_id,
                     gadget_id);
                  break;
            } /* switch(gadget_id) */
         } /* if(message) */
      } /* if(class...) */
   } /* while(GetMsg) */
#endif /*DEBUG*/


#if DBG
   printf("\n Timer B control register = %X",ciab.ciacrb);
   printf("\n buffer = %X", buffer);
#endif

   /*--- Shut down timer B */

Fini:
   StopTime();

   /*--- Turn off the 8520's recognition of the ACK as an interrupt. */

   mask = 0x10; /* Hex 10 = 00010000 Should disable the 8520 FLAG interrupt. */
   *address = mask;  /* Disable the interrupt. */

   /*--- Remove the level2 interrupt server from server chain. */

   RemoveServer();

   /*--- Exit cleanly. */

ShutDown:

   /*--- Deallocate parallel port resource. Commented out for reasons above. */

   /*****************
   MR_FREEMISCRESOURCE(MR_PARALLELPORT);
   MR_FREEMISCRESOURCE(MR_PARALLELBITS);
   *****************/

   /*--- Close window and screen. */

#if DEBUG
   if(Window)CloseWindow(Window);
   if(Screen)CloseScreen(Screen);
#endif /*DEBUG*/

   /*--- Close libraries. */

   if(GfxBase)CloseLibrary((struct Library *)GfxBase);
   if(IntuitionBase)CloseLibrary((struct Library *)IntuitionBase);

   /*--- Free allocated memory. */
#if DEBUG
   if(workspace != 0)FreeRaster(workspace, 640, 200);
#endif /*DEBUG*/

   return(0);  /* To keep compiler happy. */
} /* End of main(). */



int GetSample()
{
   int idx;

   /*--- Set up for taking another sample. */

#if DBG
   printf("\n Setting up for next sample.");
#endif
   for(idx=0; idx<NSAMPLES; idx++)zuffer[idx] = 0; /* Zero the buffer. */
   NSamples = NSAMPLES;  /* Reset sample counter. */
   buffer = &zuffer[0];  /* Reset pointer to start of buffer. */

   ciacr |= CIACRBF_LOAD; /* Strobe Load to latch in countdown value. */
   ciaicr = CIAICRF_SETCLR|CIAICRF_TB;  /* Enable timer B interrupts. */
   mask = *address;  /* Clear any pending interrupts. */
   mask = 0x90;  /* Hex 90 = 10010000 Should enable the 8520 FLAG interrupt. */
   *address = mask;  /* Enable the ACK interrupt. */

   /*--- Interrupts are now all armed and dangerous.  */
   /*--- Wait until data is ready. */

#if DBG
   printf("\n Waiting...press a button.");
#endif
   Wait(TimerSigMask);  /* Wait for full buffer. */

   /*--- Stop timer B from counting. */

#if DBG
   printf("\n Stopping timer B");
#endif
   ciacr &= ~CIACRBF_START;

   /*--- Wait until user lets go of button. */

   LetGo();

   return(0);
}

#if DEBUG
/*-------------------- h e l p t x t . c ------------------------*/
/* This routine clears the help message area and writes a new    */
/* message into it.                                              */
/*---------------------------------------------------------------*/

int helptxt(msg1, msg2)
  char *msg1, *msg2;
{

   /*--- Erase any old text that exists. */

   SetAPen(WRPort, 0);
   RectFill(WRPort, 24, 163, 617, 188);

   /*--- Write new text. */


   SetAPen(WRPort, 1);
   Move(WRPort, 25, 173);
   Text(WRPort, msg1, strlen(msg1));
   Move(WRPort, 25, 185);
   Text(WRPort, msg2, strlen(msg2));

   return(0);
}

/*---------------------- I R B u t t o n s O f f . c ---------------------*/
/* This routine unhighlights any currently selected control button.       */
/*------------------------------------------------------------------------*/

int IRButtonOff(button)
  int *button;  /* Button to turn off. */
{
   USHORT position;

   if((*button >= 1) && (*button <= 20))
   {
      /*--- Remove currently selected gadget from list. */

      position = RemoveGList(Window, IR[*button-1], 1L);

      /*--- Unselect the gadget. */

      IR[*button-1]->Flags &= (~SELECTED);

      /*--- Put the gadget back into the same place in the list. */

      AddGList(Window, IR[*button-1], (LONG)position, 1L, NULL);

      /*--- Refresh gadgets on display. */

      RefreshGList(IR[*button-1], Window, NULL, 1L);

      /*--- Set currently selected gadget to none. */

      *button = -1;
   }

   return(TRUE);
}


/*---------------------- I R B u t t o n s O n . c -----------------------*/
/* This routine highlights the currently selected control button.         */
/*------------------------------------------------------------------------*/


int IRButtonOn(button)
  int button;  /* Button number to highlight. */
{
   USHORT position;

   if((button >= 1) && (button <= 20))
   {
      /*--- Remove the selected gadget from list. */

      position = RemoveGList(Window, IR[button-1], 1L);

      /*--- Select the gadget. */

      IR[button-1]->Flags |= SELECTED;

      /*--- Put the gadget back into the same place in the list. */

      AddGList(Window, IR[button-1], (LONG)position, 1L, NULL);

      /*--- Refresh gadgets on display. */

      RefreshGList(IR[button-1], Window, NULL, 1L);
   }

   return(TRUE);
}

/*------------------- I R B u t t o n L a b e l . c -------------------*/
/* This routine relabels the selected button.                          */
/*---------------------------------------------------------------------*/

int IRButtonLabel(buffer, button)
  UBYTE *buffer;
  int button;
{
   USHORT position;

   if((button >= 1) && (button <= 20))
   {
      /*--- Remove the selected gadget from list. */

      position = RemoveGList(Window, IR[button-1], 1L);

      /*--- Change the label. */

      strncpy(IR[button-1]->GadgetText->IText , (char *)buffer, 7);

      /*--- Put the gadget back into the same place in the list. */

      AddGList(Window, IR[button-1], (LONG)position, 1L, NULL);

      /*--- Refresh gadgets on display. */

      RefreshGList(IR[button-1], Window, NULL, 1L);
   }

   return(TRUE);
}


/*------------------ G e t P a t t e r n . c ---------------------*/
/* This routine gets a signal sample from the IR receiver and     */
/* then tries up to four times to verify it.                      */
/*----------------------------------------------------------------*/

GetPattern(button)
  int button;  /* Currently selected control button. */
{
   int it, iz, is, try;
   int diff[4], match, smallest;

#if DBG
   printf("\n\n **** Storing pattern %d ****", button);
#endif

   /*--- Get a sample. */

   GetSample();

   /*--- Plot data on screen. */

   helptxt("Data received.", "");
   /*DPattern(button, 1);*/
   DisplayPattern(button, 0);

#if DBG
   printf("\n NSamples=%d", NSamples);
#endif

   /*--- Transfer data to storage. */

#if DBG
   printf("\n Xferring to pattern memory.");
#endif
   for(iz=0; iz<NSAMPLES; iz++)
   {
      pattern[button-1][iz] = zuffer[iz] & 0x01;
#if DBG
/*
      if(pattern[button-1][iz] == 1)printf("|");
      if(pattern[button-1][iz] == 0)printf("_");
*/
#endif
   }

   helptxt("Press the button again to verify the pattern.", "");

   match = 0;
   for(try=0; try<4; try++)  /* Try four times to get a match. */
   {
      GetSample(); /* Read IR signal again. */

      helptxt("Data received.  Verifying match.", "");
/*   DPattern(button, try+2);*/
      DisplayPattern(button, 1);

      /*--- Find number of cells that don't match. */

      diff[try] = 0;
      smallest = NSAMPLES+10;
      for(iz=0; iz<NSAMPLES; iz++)
      {
         zuffer[iz] = zuffer[iz] & 0x01;
         if(pattern[button-1][iz] != zuffer[iz])
         {
            diff[try]++;
         }
#if DBG
/*
         if(zuffer[iz] == 1)printf("|");
         if(zuffer[iz] == 0)printf("_");
*/
#endif
      }
      if(diff[try] > TOLERENCE)
      {
#if DBG
         printf("\n Samples do not match:%d  Please try again.",diff[try]);
#endif
         helptxt("Samples do not match.  Please press button again.", "");
         if(diff[try] < smallest)
         {
            /*--- Store the best pattern so far. */
            smallest = diff[try];
            for(iz=0; iz<NSAMPLES; iz++)
            {
               pattern[button-1][iz] = zuffer[iz];
            }
         }
      } else
      {
         match = 1;
         break;
      }
   }
   if(match == 0)
   {
      helptxt("Could not verify pattern.  Will use the best match of four tries.", "");
#if DBG
      printf("\n Could not verify pattern.  Will use the best match.");
      printf("\n Try the analyzer to verify compatability of your unit.");
#endif
   } else
   {
      helptxt("Successful pattern match!", "");
      DisplayPattern(button, 0);
   }

   return(TRUE);
}


/*-------------------- D i s p l a y P a t t e r n . c ------------------*/
/* This routine draws the acquired pattern on the screen in the help     */
/* message area.                                                         */
/*-----------------------------------------------------------------------*/

int DisplayPattern(button, mode)
  int button;  /* Currently selected control button. */
  int mode;    /* 0 = draw pattern, 1 = draw difference. */
{
   int it;
   SHORT row;

   /*--- Any old text or pattern that existed should have been erased with */
   /*--- a help message. */

   /*--- Draw pattern. X range = 24 to 617 */

   SetAPen(WRPort, 1);
   row = 0;
   for(it=0; it<NSAMPLES; it++)
   {
      if(mode == 0)
      {
         if((zuffer[it] & 0x01) == 1)
         {
            Move(WRPort, 26 + (SHORT)(it%590), 175 + row);
            Draw(WRPort, 26 + (SHORT)(it%590), 175 + row);
         }
      } else
      {
         if((zuffer[it] & 0x01) != pattern[button-1][it])
         {
            Move(WRPort, 26 + (SHORT)(it%590), 175 + row);
            Draw(WRPort, 26 + (SHORT)(it%590), 175 + row);
         }
      }

      /*--- Space the data in rows. */

      if((it%590 == 0) &&(it != 0))row = row + 2;
   }
#if DBG
   printf("\n Drew the pattern.");
#endif

   return(TRUE);
}



int DPattern(button, mode)
  int button;  /* Currently selected control button. */
  int mode;    /* 0 = draw pattern, 1 = draw difference. */
{
   int it;
   SHORT row;

   /*--- Any old text or pattern that existed should have been erased with */
   /*--- a help message. */

   /*--- Draw pattern. X range = 24 to 617 */

   SetAPen(WRPort, 1);
   row = 0;
   for(it=0; it<NSAMPLES; it++)
   {
      if((zuffer[it] & 0x01) == 1)
      {
         Move(WRPort, 26 + (SHORT)(it%590), 175 + row - mode*20);
         Draw(WRPort, 26 + (SHORT)(it%590), 175 + row - mode*20);
      }

      /*--- Space the data in rows. */

      if((it%590 == 0) &&(it != 0))row = row + 2;
   }

   return(TRUE);
}
#endif /*DEBUG*/

/*-------------------- f i n d _ m a t c h . c ----------------------*/
/*  Find pattern which is the closest match to the one just read in. */
/*-------------------------------------------------------------------*/

int find_match()
{
   int match, it, smallest;
   int diff, pat;

#if DBG
   printf("\n Matching patterns...");
#endif

   /*--- Mask of bit of interest in zuffer. */

   for(it=0; it<NSAMPLES; it++)zuffer[it] = zuffer[it] & 0x01;

   /*--- Compare data to stored patterns. */

   match = -1;
   smallest = NSAMPLES+10;
   for(pat=0; pat<20; pat++)  /* Step through all stored patterns. */
   {
      if(active[pat+1])  /* Only examine active patterns to save time. */
      {
         diff = 0;
         for(it=0; it<NSAMPLES; it++)
         {
            if(pattern[pat][it] != zuffer[it])diff++;
         }
      }
      if(diff < smallest)
      {
         smallest = diff;
         match = pat;
      }
#if DBG
      printf("\n diff(%d)=%d", pat, diff);
#endif
   }

#if DBG
   printf("\n Best match is pattern %d", match);
   if(match == -1)
   {
      printf("\n No match for pattern!");
   }
#endif

   return(match);
}
