//----------------------------------------------------------------------------
// HACIO                                                      19950831 CHG
// 16 digital (2 * HC589) inputs
// 16 digital (Ћ * UCN5818) outputs
//
// HACBUS:
//   Device type: 0x01               ; HACIO type
//   Address    : 0x01..0x0F         ; Address 1..15
//   Commands   : 0x00               ; Poll
//          Resp: 0x80 [XX XX YY YY] ; XX XX is "changed mask" and YY YY is new data
//                                   ; for the changed inputs, no data if no change
//              : 0x01 XX XX         ; Set all 16 outputs to value XX XX
//          Resp: 0x81               ;
//              : 0x02 XX YY         ; Set output number XX to value YY
//          Resp: 0x82               ;
//              : 0x03               ; Get all inputs
//          Resp: 0x83 XX XX         ;
//----------------------------------------------------------------------------
#include <reg2051.h>
#include <stdio.h>
#include "..\HACNET\HACNET.H"

//----------------------------------------------------------------------------
// Constants...
//----------------------------------------------------------------------------
#define TRUE   1
#define FALSE  0
#define MyDeviceType 0x01
#define RxSize 3+3             // Maximum size of RxBuffer

//----------------------------------------------------------------------------
// I/O definitions...
//----------------------------------------------------------------------------
#define OutClk  P37    // Clock to UCN5818 output driver
#define OutStr  P10    // Strobe to UCN5818 output driver
#define OutData P11    // Data to UCN5818 output driver
#define OutBlank P12   // Blanking (disable) all outputs

#define InRCK   P35    // RCK from HC589
#define InSCK   P33    // SCK ----//----
#define InData  P32    // Qh  ----//----
#define InSLOAD P34    // SLOAD --//---

//----------------------------------------------------------------------------
// Variables...
//----------------------------------------------------------------------------
// UCN5818 driver specific...
#define  BitsOut       16              // Max number of outputs
                                       // (number of UCN5818's * 32)
unsigned char Output[BitsOut / 8];     // number of bytes to hold these outputs
// HC589 driver specific...
#define  BitsIn        16              // Max number of inputs
                                       // (number of HC589's * 8)
unsigned char Input[BitsIn / 8];       // number of bytes to hold these inputs

unsigned char RxBuffer[RxSize];       // RxBuffer
extern bit RxAvail;                   // Message available in RX Buffer
extern bit Resend;                    // Resend last response


//----------------------------------------------------------------------------
// wait for a specific time in 10 mSec
// Based on a 11.059 MHz crystal
//----------------------------------------------------------------------------
void Delay(unsigned char t) {
  unsigned int i;
  while (t--) for(i=0;i<774; i++);
}


//лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл
// HC589 Helper routines.                                         19950726 CHG
// Manages a number of HC589 daisy chained.
// Global constants/variables that must be declared:
// #define  BitsIn        16           // Max number of outputs
//                                     // (number of HC589's * 8)
// unsigned char Input[BitsIn / 8];    // number of bytes to hold these inputs
//лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл

//----------------------------------------------------------------------------
// Check a specific bit in the Input buffer...
//----------------------------------------------------------------------------
unsigned char GetInput(unsigned char Num) {
  return (Input[Num / 8] & (1 << (Num % 8)) ? 1:0);
}

//----------------------------------------------------------------------------
// Read all inputs from HC589 chain
//----------------------------------------------------------------------------
void GetHC589(void) {
  unsigned char j;
  unsigned char dummy;

  InSCK = 0; InRCK = 0; InSLOAD = 0; dummy++;
  InRCK = 1; dummy++;
  InRCK = 0; InSLOAD = 1; dummy++;
  for (j=0;j<BitsIn; j++) {
   // NB: Input level is reversed !
    if (!InData)
      Input[j / 8] |= (1 << (j % 8)); // Set the bit in the byte...
    else
      Input[j / 8] &=~(1 << (j % 8)); // Clr the bit in the byte...
    InSCK = 1;  dummy++;
    InSCK = 0;  dummy++;
  }
  InSCK = 0; InRCK = 0; InSLOAD = 0; dummy++;
}
//лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл


//лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл
// UCN5818 Helper routines.                                       19950726 CHG
// Manages a number of UCN5818 daisy chained.
// Global constants/variables that must be declared:
// #define  BitsOut       32              // Max number of outputs
//                                        // (number of UCN5818's * 32)
// unsigned char Output[BitsOut / 8];     // number of bytes to hold these outputs
//лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл
//----------------------------------------------------------------------------
// Set a specific bit in the Output buffer to on or off...
//----------------------------------------------------------------------------
void SetOutput(unsigned char Num, unsigned char Value) {
 // Modify bit pattern...
  if (Value)
    Output[Num / 8] |= (1 << (Num % 8)); // Set the bit in the word...
  else
    Output[Num / 8] &=~(1 << (Num % 8)); // Clr the bit in the word...
}

//----------------------------------------------------------------------------
// Check a specific bit in the Output buffer...
//----------------------------------------------------------------------------
unsigned char GetOutput(unsigned char Num) {
  return (Output[Num / 8] & (1 << (Num % 8)) ? 1:0);
}

//----------------------------------------------------------------------------
// Send all outputs out to the UCN5818 driver
//----------------------------------------------------------------------------
void UpdateUCN5818(void) {
  unsigned char j;
  unsigned char dummy;
  for (j=0; j<BitsOut; j++) {
    if (GetOutput(j)) {
 //   if (Output[j / 8] & (1 << (j % 8))) {
      OutData = 1; dummy++;
      OutClk  = 1; dummy++;
    } else {
      OutClk= 1; dummy++;
    }
    OutClk = 0; OutData  = 0; dummy++;
  }
  OutStr= 1; dummy++;
  OutStr= 0; dummy++;
}
//лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл


//----------------------------------------------------------------------------
// Main part
//----------------------------------------------------------------------------
void main() {
  unsigned char Rsp[5];         // Buffer for responses
  unsigned char LastInput[2];   // Holds last requested input string
  bit PwrUp=TRUE;
  unsigned char MyAddress;      // My assigned address on the Dip switches.

 //----------------------------------------------------------------------------
 // Initialize HACNET driver...
 //----------------------------------------------------------------------------
  MyAddress=InitHACNET(MyDeviceType, RxSize);

 //---------------------------------
 // Initialize outputs...
 //---------------------------------
  OutClk=0;
  OutData=0;
  OutStr=0;
  Output[0]=Output[1]=0;
  UpdateUCN5818();     // Clear outputs
  OutBlank=FALSE;

 //------------------------------
 // Configure onchip resources...
 //------------------------------
 EA=1;        // Global int enable

  //----------------------------------------------------------------------------
  // Forever
  //----------------------------------------------------------------------------
  while(1) {
    //----------------------------------------------------------------------------
    // Diagnostic mode, Address is 0x00
    //----------------------------------------------------------------------------
    if (MyAddress==0) {
      Delay(50);
      HacTransmit("DIAG\n\r",6);
    } else {
    //----------------------------------------------------------------------------
    // Normal mode
    //----------------------------------------------------------------------------
      // Check if we have to resend last response...
      if (Resend) {
        Resend=FALSE;
 //       SetOutput(0,1);
 //       SetOutput(1,0);
 //       UpdateUCN5818();
 //       Delay(100);
        HacTransmit(Rsp, 0xFF);
      }
      if (RxAvail) {
 //       SetOutput(0,0);
 //       SetOutput(1,1);
 //       UpdateUCN5818();
 //       Delay(100);
        switch (RxBuffer[0]) {
          case 0 :
            Rsp[0]=0x80; // Response code
            // Take a peek at the inputs...
            GetHC589();
            // If any difference in last input and current...
            if (LastInput[0]!=Input[0] || LastInput[1]!=Input[1] || PwrUp) {
              // Build "changed mask"...
              if (PwrUp) {
                Rsp[2]=0xFF; // Mark all as changed...
                Rsp[1]=0xFF;
              } else {
                Rsp[2]=LastInput[1] ^ Input[1]; // XOR with old vector
                Rsp[1]=LastInput[0] ^ Input[0];
              }
              PwrUp=FALSE;
              // The input vector...
              Rsp[4]=Input[1];
              Rsp[3]=Input[0];
              // Make this new input vector the "old" one...
              LastInput[0]=Input[0];
              LastInput[1]=Input[1];
              HacTransmit(Rsp, 5);
            } else
              HacTransmit(Rsp, 1); // Empty response
            break;
          case 1 :
            Output[0]=RxBuffer[1];
            Output[1]=RxBuffer[2];
            // Set the outputs...
            UpdateUCN5818();
            Rsp[0]=0x81; // Response code
            HacTransmit(Rsp, 1); // Empty response
            break;
          case 2 :
            SetOutput(RxBuffer[1], RxBuffer[2]);
            // Set the outputs...
            UpdateUCN5818();
            Rsp[0]=0x82; // Response code
            HacTransmit(Rsp, 1); // Empty response
            break;
          case 3:
            Rsp[0]=0x83; // Response code
            // Take a peek at the inputs...
            GetHC589();
            PwrUp=FALSE;
            Rsp[2]=Input[1];
            Rsp[1]=Input[0];
            LastInput[0]=Input[0];
            LastInput[1]=Input[1];
            HacTransmit(Rsp, 3);
            break;
        }
        RxAvail=0;
      }
    }
  }
}

