/****************************************************************/
/*								*/
/* Checker - this file includes the GAL-Checker			*/
/*								*/
/*								*/
/****************************************************************/


#include <intuition/intuition.h>
#include <stdio.h>
#include <string.h>

#include <proto/locale.h>
#include <proto/graphics.h>
#include <proto/intuition.h>

#include "GALer.h"
#include "Localize.h"



extern	struct  AppString { LONG   as_ID;
		 	    STRPTR as_Str;
			  };

extern	struct  AppString AppStrings[];

extern	int	pruef_mode;
extern	int	gal_type;
extern	int	asmreadyflag;
extern	int	num_of_pins;

extern	UBYTE	PinNames[24][10];

extern  struct	Window		*window;
extern	struct	RastPort	*rp;
extern	struct	Border		Border1;
extern	struct	Border		Border2;

extern	struct	Menu		*mainmenu, *pruefermenu;

extern	struct	Gadget		Gadget1;
extern	struct	Gadget		Gadget3;
extern	struct	Gadget		Gadget14;
extern	struct	Gadget		Gadget15;
extern	struct	Gadget		Gadget16;
extern	struct	Gadget		Gadget17;
extern	struct	Gadget		Gadget18;
extern	struct	Gadget		Gadget19;
extern	struct	Gadget		Gadget20;
extern	struct	Gadget		Gadget23;
extern	struct	Gadget		Gadget21;
extern	struct	Gadget		Gadget22;
extern	struct	Gadget		Gadget30;
extern	struct	Gadget		Gadget31;
extern	struct	Gadget		Gadget37;
extern	struct	Gadget		Gadget38;
extern	struct	Gadget		Gadget39;



extern	struct	Catalog		*catalog;


int	GALType;
int	outIC1, outIC3, outIC4, outIC5;



struct	in_con	  { int IC;
		    int Bit;
		    int IO;
		    int Level; };

struct	out_con	  { int IC;
		    int Bit; };



/* in_bit[gadID]

 1. entry: IC which controls the pin which has the gadget ID gadID
 2. entry: bit of this IC which controls the pin
 3. entry: shows whether a pin is used as input or output
 4. entry: shows level of this pin
*/
struct in_con  in_bit[23] = {

		{IC4, 0x01, INPUT_PIN,  LOW},	 /* pin  1 */
		{IC4, 0x02, INPUT_PIN,  LOW},	 /* pin  2 */
		{IC4, 0x04, INPUT_PIN,  LOW},	 /* pin  3 */
		{IC4, 0x08, INPUT_PIN,  LOW},	 /* pin  4 */
		{IC4, 0x10, INPUT_PIN,  LOW},	 /* pin  5 */
		{IC4, 0x20, INPUT_PIN,  LOW},	 /* pin  6 */
		{IC4, 0x40, INPUT_PIN,  LOW},	 /* pin  7 */
		{IC4, 0x80, INPUT_PIN,  LOW},	 /* pin  8 */
		{IC5, 0x01, INPUT_PIN,  LOW},	 /* pin  9 */
		{IC5, 0x02, INPUT_PIN,  LOW},	 /* pin 10 */
		{IC5, 0x04, INPUT_PIN,  LOW},	 /* pin 11 */
		{ 0,   0,      0,        0 },	 /*  GND   */
		{IC5, 0x08, INPUT_PIN,  LOW},	 /* pin 13 */
		{IC5, 0x10, INPUT_PIN,  LOW},	 /* pin 14 */
		{IC5, 0x20, OUTPUT_PIN, LOW},	 /* pin 15 */
		{IC3, 0x01, OUTPUT_PIN, LOW},	 /* pin 16 */
		{IC3, 0x02, OUTPUT_PIN, LOW},	 /* pin 17 */
		{IC3, 0x04, OUTPUT_PIN, LOW},	 /* pin 18 */
		{IC3, 0x08, OUTPUT_PIN, LOW},	 /* pin 19 */
		{IC3, 0x10, OUTPUT_PIN, LOW},	 /* pin 20 */
		{IC3, 0x20, OUTPUT_PIN, LOW},	 /* pin 21 */
		{IC3, 0x40, OUTPUT_PIN, LOW},	 /* pin 22 */
		{IC3, 0x80, INPUT_PIN,  LOW} 	 /* pin 23 */

			    };



/*  out_bit[gadID - 14]
  1. entry: IC which can read the pin which has the gadget ID gadID
  2. entry: bit of this IC
*/
struct out_con out_bit[10] = { { IC7,  0x01 },
			       { IC7,  0x02 },
			       { IC7,  0x04 },
			       { IC7,  0x08 },
			       { IC7,  0x10 },
			       { IC7,  0x20 },
			       { IC7,  0x40 },
			       { IC7,  0x80 },
			       { IC6a, 0x01 },
			       { IC6c, 0x01 } };



/* this array shows which IO-select gadged ID corresponds with which
   level gadget

   level_gadget = IOtoLevel[gadID - 30];

   gadID: gadget ID of IO-select gadget
*/
struct Gadget  *IOtoLevel[] = { &Gadget14,
				&Gadget15,
				&Gadget16,
				&Gadget17,
				&Gadget18,
				&Gadget19,
				&Gadget20,
				&Gadget21,
				&Gadget22,
				&Gadget23 };



void Pruefer(struct Gadget *gad, USHORT gadID)
{
UBYTE	c;

  c = (UBYTE)*gad->GadgetText->IText;
					    /*** input gadgets ***/
  if ((gadID >= 1) && (gadID <= 23)) {
    if (gad->GadgetRender != (APTR)&Border2) {	/* output pin? */
      if (c == 'L') {				/* no, then set level */
        c = 'H';

        in_bit[gadID - 1].Level = HIGH;

        SetLevel(gadID, HIGH);
      }
      else {
        c = 'L';

        in_bit[gadID - 1].Level = LOW;

        SetLevel(gadID, LOW);
      }
    }
  }

					/*** input/output gadgets (I/O) ***/
  if ((gadID >= 30) && (gadID <= 39)) {
    if (c == 'O') {
      c = 'I';

						/* change color and text*/
      IOtoLevel[gadID - 30]->GadgetRender = (APTR)&Border1;

      *IOtoLevel[gadID - 30]->GadgetText->IText = 'L';

      SetLevel(gadID - 16, LOW);

      in_bit[gadID - 17].IO = INPUT_PIN;
    }
    else {
      c = 'O';

      IOtoLevel[gadID-30]->GadgetRender = (APTR)&Border2;

      in_bit[gadID-17].IO = OUTPUT_PIN;

      SetLevel(gadID-16, LOW);

    }

    RefreshGList(IOtoLevel[gadID - 30], window, NULL, 1L);
  }

  CheckOutput();

  *gad->GadgetText->IText = c;

  RefreshGList(gad, window, NULL, 1L);
}




/* set level (=HIGH or LOW) of the pin which has the gadget ID "gadID"
*/
void SetLevel(USHORT gadID, int Level)
{
int	bits, ICnum, outIC;


  ICnum = in_bit[gadID - 1].IC;			/* get IC number and output */
  bits  = in_bit[gadID - 1].Bit;		/* bit of this IC */


  if (ICnum == IC3)
    outIC = outIC3;

  if (ICnum == IC4)
    outIC = outIC4;

  if (ICnum == IC5)
    outIC = outIC5;

 
  bits ^= 0xFF;				/* invert all bits */

  outIC &= bits;			/* set the output bit of the IC */
  if (Level == HIGH) {
    bits ^= 0xFF;
    outIC |= bits;
  }

  WriteByte(outIC, ICnum);		/* set level of pin */

}



/* check whether a output is HIGH, LOW or tristate
   Call: the outputs must be switched LOW by use of the 10kOhm resistors
*/
void CheckOutput(void)
{
struct	Gadget	*gad;

int n, in_bits, out_bits, pin_Level;
int inICnum, outICnum, outIC, byte, first_out, last_out;


  switch (GALType) {			/* get possible output pins */
    case GAL16V8:
      first_out = 14;
      last_out  = 21;
      break;

    case GAL20V8:
      first_out = 15;
      last_out  = 22;
      break;

    default:				/* GAL22V10, GAL20RA10 */
      first_out = 14;
      last_out  = 23;
      break;
  }


  for(n = first_out; n <= last_out; n++) {  /* check all outputs */

    if (in_bit[n - 1].IO == OUTPUT_PIN) {

      outICnum = in_bit[n - 1].IC;
      out_bits = in_bit[n - 1].Bit;

      inICnum  = out_bit[n - 14].IC;
      in_bits  = out_bit[n - 14].Bit;


      if (outICnum == IC3)
        outIC = outIC3;

      if (outICnum == IC4)
        outIC = outIC4;

      if (outICnum == IC5)
        outIC = outIC5;


      byte = ReadByte(inICnum);		/* get level of outputs */

      if (byte & in_bits)
        pin_Level = HIGH;		/* "calculate" level of outputs */
      else
        pin_Level = LOW;

      outIC |= out_bits;		/* set output HIGH */
      WriteByte(outIC, outICnum);

      byte = ReadByte(inICnum);		/* get level of outputs */


      gad = IOtoLevel[n - 14];

      if (pin_Level != (1&&(byte & in_bits))) {	/*Ausgang widerspricht nicht->Z*/
        *gad->GadgetText->IText = 'Z';

        RefreshGList(gad, window, NULL, 1L);
      }
      else {
	if (pin_Level == LOW)
	  *gad->GadgetText->IText = 'L';
	else
          *gad->GadgetText->IText = 'H';

	RefreshGList(gad, window, NULL, 1L);
      }

      outIC &= (out_bits^0xFF);			/* switch output LOW again */
      WriteByte(outIC, outICnum);
    }
  }
}




/* switch checker on/off
*/
void TogglePruefer(void)
{
int	n;
struct	Gadget	*gad;


  if (pruef_mode) {
    LED(OFF);
    DisableVcc();

    pruef_mode = OFF;				/* exit checker*/

    gad = &Gadget3;				/* init. text of gadgets */

    while(gad != NULL) {
      if (*gad->GadgetText->IText == 'I')
        *gad->GadgetText->IText = 'O';

      if (*gad->GadgetText->IText == 'H')
        *gad->GadgetText->IText = 'L';

      if (*gad->GadgetText->IText == 'Z')
        *gad->GadgetText->IText = 'L';

      gad = gad->NextGadget;
    }
  

    gad = &Gadget14;

    for (n = 0; n < 10; n++) {			/* reset color of possible */
    						/* outputs (Gadget14..23)  */
      if (GALType == GAL22V10 || GALType == GAL20RA10)
        gad->GadgetRender = &Border2;

      if (GALType == GAL20V8)
        if (n == 0 || n == 9)
	  gad->GadgetRender = &Border1;
        else    
          gad->GadgetRender = &Border2;

      if (GALType == GAL16V8)
        if (n == 8 || n == 9)
	  gad->GadgetRender = &Border1;
        else    
          gad->GadgetRender = &Border2;

      gad = gad->NextGadget;
    }


    RefreshGList(&Gadget3, window, NULL, -1L);

    MyRequest(INFO_REQ, AppStrings[MSG_REMOVE_GAL].as_Str);

    ClearMenuStrip(window);

    SetMenuStrip(window, mainmenu);

  }
  else {
    if (MyRequest(GALTYPE_REQ, AppStrings[MSG_GAL_CHECKER].as_Str)) {

					/* initialize in_bit array */
      for (n = 0; n < 23; n++) {
        in_bit[n].Level = LOW;
	in_bit[n].IO    = INPUT_PIN;
      }

      in_bit[14].IO = OUTPUT_PIN;	/* pins 15 to 21 can always */
      in_bit[15].IO = OUTPUT_PIN;	/* be outputs */
      in_bit[16].IO = OUTPUT_PIN;
      in_bit[17].IO = OUTPUT_PIN;
      in_bit[18].IO = OUTPUT_PIN;
      in_bit[19].IO = OUTPUT_PIN;
      in_bit[20].IO = OUTPUT_PIN;

      if (GALType == GAL22V10 || GALType == GAL20RA10) {
	in_bit[13].IO = OUTPUT_PIN;
	in_bit[21].IO = OUTPUT_PIN;
	in_bit[22].IO = OUTPUT_PIN;
      }

      if (GALType == GAL16V8)
	in_bit[13].IO = OUTPUT_PIN;

      if (GALType == GAL20V8)
	in_bit[21].IO = OUTPUT_PIN;



      LED(ON);

      EnableVcc();

      pruef_mode = ON;				/* init. checker */

      WaitForTimer(100000L);

      CheckOutput();				/* test outputs */

      ClearMenuStrip(window);

      SetMenuStrip(window, pruefermenu);
    }
  }
}




/* draw GAL
*/
void DrawGAL(int type)
{
int	pins, n;
long	ypos, ic_hight;
char	pinnum[2];				/* pin number as ASCII text */
struct	Gadget	*gad;



  ClearPinNames();


  RemoveGList(window, &Gadget3, -1L);		/* remove all gadgets from */
						/* the symbolic GAL */

  Gadget21.NextGadget = NULL;			/* reset the lists of gadget */
  Gadget37.NextGadget = NULL;			/* look at GALer.c for a */
  Gadget38.NextGadget = NULL;			/* short description on */
  Gadget1.NextGadget = NULL;			/* the gadget lists */
  

  SetAPen(rp, 0L);				/* clear screen */
  RectFill(rp, 240L, 16L, 400L, 140L);
  SetAPen(rp, 1L);



  if (type == GAL16V8) {		/*** GAL16V8 ***/
    Gadget21.NextGadget = &Gadget30;
    pins = 20;

    ypos = 40L;

    ic_hight = 100L;
  }



  if (type == GAL20V8) {		/*** GAL20V8 ***/
    Gadget21.NextGadget = &Gadget22;		/* join list of gadgets for */
    Gadget1.NextGadget  = &Gadget31;		/* 20V8 GALs */
    Gadget37.NextGadget = &Gadget38;

    pins = 24;

    ypos = 20L;

    ic_hight = 120L;
  }


					/*** GAL22V10, GAL20RA10 ***/
  if (type == GAL22V10 || type == GAL20RA10) {
    Gadget21.NextGadget = &Gadget22;		/* join list of gadgets for */
    Gadget1.NextGadget  = &Gadget30;		/* 22V10 and 20RA10 GALs */
    Gadget37.NextGadget = &Gadget38;
    Gadget38.NextGadget = &Gadget39;

    pins = 24;

    ypos = 20L;

    ic_hight = 120L;
  }


  gad = &Gadget14;

  for (n = 0; n < 10; n++) {			/* reset color of possible */
    						/* outputs (Gadget14..23)  */
    if (GALType == GAL22V10 || GALType == GAL20RA10)
      gad->GadgetRender = &Border2;

    if (GALType == GAL20V8)
      if (n == 0 || n == 9)
	gad->GadgetRender = &Border1;
      else    
        gad->GadgetRender = &Border2;

    if (GALType == GAL16V8)
      if (n == 8 || n == 9)
	gad->GadgetRender = &Border1;
      else    
        gad->GadgetRender = &Border2;

    gad = gad->NextGadget;
  }


						/* add gadgets to window */

  AddGList(window, &Gadget3, -1, -1, NULL);

  RefreshGadgets(&Gadget3, window, NULL);


  Move(rp, 280L, ypos-2L);			/* draw GAL */
  Draw(rp, 360L, ypos-2L);
  Draw(rp, 360L, ypos+ic_hight);
  Draw(rp, 280L, ypos+ic_hight);
  Draw(rp, 280L, ypos-2L);

  Move(rp, 312L, ypos-2L);			/* draw mark */
  Draw(rp, 312L, ypos+3L);
  Draw(rp, 326L, ypos+3L);
  Draw(rp, 326L, ypos-2L);


  SetDrMd(rp, (long)JAM1);			/* draw pins */

  for (n = 1; n <= pins; n++) {
    sprintf(&pinnum[0], "%2d", n);

    if (n < pins/2) {
      DrawLeftPin(280L, ypos);

      Move(rp, 264L, ypos+7L);

      Text(rp, (char *)pinnum, 2L);

      Move(rp, 285L, ypos+7L);

      Text(rp, (char *)"I", 1L);

      ypos += 10L;
    }

    if (n == pins/2) {
      DrawLeftPin(280L, ypos);

      Move(rp, 264L, ypos+7L);

      Text(rp, (char *)pinnum, 2L);
    }

    if (n > pins/2) {
      DrawRightPin(360L, ypos);

      Move(rp, 361L, ypos+7L);

      Text(rp,(char *)pinnum,2L);

      if (n == pins/2+1) {
        Move(rp, 348L, ypos+7L);

        Text(rp, (char *)"I", 1L);
      }

      if ((n == 14) && (GALType == GAL20V8)) {
        Move(rp, 348L, ypos+7L);

        Text(rp, (char *)"I", 1L);
      }

      if ((n == 23) && (GALType == GAL20V8)) {
        Move(rp, 348L, ypos+7L);
        Text(rp, (char *)"I", 1L);
      }

      ypos -= 10L;
    }
  }

  SetDrMd(rp, (long)JAM2);

}



/* draw the left pins of the symbolic GAL
*/
void DrawLeftPin(long x, long y)
{
  Move(rp, x, y);

  Draw(rp, x - 18L, y);

  Draw(rp, x - 18L, y + 8L);

  Draw(rp, x, y + 8L);
}



/* draw the right pins of the symbolic GAL
*/
void DrawRightPin(long x, long y)
{
  Move(rp, x, y);

  Draw(rp, x + 18L, y);

  Draw(rp, x + 18L, y + 8L);

  Draw(rp, x, y + 8L);
}





/* set pin names at the symbolic GAL
*/
void PrintPinNames(void)
{
int	n;
long	ypos;

 if (asmreadyflag) {				/*is there a assembled file?*/
   if (gal_type == GALType) {			/*is type of GAL o.k.?*/
     ClearPinNames();
     if (GALType == GAL16V8)
       ypos = 40L;
     else
       ypos = 20L;

     for (n = 1; n <= num_of_pins; n++) {
       if (n < num_of_pins/2) {
	 Move(rp, 234L-8L*(long)strlen((char *)&PinNames[n-1][0]), ypos+7L);
	 ypos += 10;
       }

       if (n == num_of_pins/2) {
	 Move(rp, 234L-8L*(long)strlen((char *)&PinNames[n-1][0]), ypos+7L);
       }

       if (n > num_of_pins/2) {
	 Move(rp, 406L, ypos+7L);
	  ypos -= 10;
       }

       Text(rp, (char *)&PinNames[n-1][0], (long)strlen((char *)&PinNames[n-1][0]));
     }

    }
   else {
     ErrorReq(9);				/* wrong GAL selected */
   }

 }
 else {
   ErrorReq(7);					/* no names to print*/
 }

}



/* clear the pin names at the symbolic GAL
*/
void ClearPinNames(void)
{
int	n;
long	ypos;

 ypos = 20L;

 for (n = 1; n <= 24; n++) {
   if (n < 24/2) {
     Move(rp, 154L, ypos+7L);

     ypos += 10;
   }

   if (n == 24/2)
     Move(rp, 154L, ypos+7L);

   if (n > 24/2) {
     Move(rp, 406L, ypos+7L);
     ypos -= 10;
   }
   Text(rp,(char *)"          ", 10L);
 }
}

