//----------------------------------------------------------------------------
// HACAIDI                                                    19951103 CHG
// 16 analog inputs
// 16 digital (2 * HC589) inputs
//
// HACBUS:
//   Device type: 0x07         ; HACAIDI type
//   Address    : 0x01..0x0F   ; Address 1..15
//   Commands   : 0x00         ; Poll
//
//
//          Resp: 0x80 00 [XX XX YY YY]        ; Change of DI
//     OR:  Resp: 0x80 01 [XX XX AA BB..RR SS] ; Change of AI
//                             ; Change of digital inputs:
//                             ; XX XX is a "changed" vector, each '1' signals a
//                             ; changed value of the channel. YY YY is
//                             ; the new (actual) input values.
//                             ; Change of analog inputs:
//                             ; XX XX is "changed" vector and AA BB..RR SS is new data
//                             ; for the changed inputs, no data if no change
//                             ; On the first poll, we will check DI, on the next poll
//                             ; we will check AI channels 0..7, and on the third poll
//                             ; we will check AI channels 8..15. Then we start all over again.
//
//              : 0x01                 ; Get all inputs
//          Resp: 0x81 XX XX           ; Input vector
//              : 0x02 An Bn           ; Request value of a number of A/D channels
//                                     ; starting with channel An ending with Bn
//          Resp: 0x82 AA BB..YY ZZ    ; Return values of the number of channels
//                                     ; specified.
//              : 0x03 XX              ; Set AND mask,XX, for the lower 8 bits
//                                     ; from the A/D converter (to avoid "noise").
//          Resp: 0x83                 ;
//                                     ;
//----------------------------------------------------------------------------
#include <reg2051.h>
#include <stdio.h>
#include "..\HACNET\HACNET.H"

//----------------------------------------------------------------------------
// Constants...
//----------------------------------------------------------------------------
#define TRUE  1
#define FALSE 0

#define MyDeviceType 0x07
#define RxSize 3+3             // Maximum size of RxBuffer

//----------------------------------------------------------------------------
// I/O definitions...
//----------------------------------------------------------------------------
// OBSERVE, SOME SIGNALS SHARED !!
#define CS      P37   // pin on MAX187 A/D converter
#define SCLK    P11   // pin on MAX187 A/D converter
#define DOut    P12   // pin on MAX187 A/D converter

#define MuxD    P35    // Address D on MAX306 Analog MUX
#define MuxC    P34    // Address C on MAX306 Analog MUX
#define MuxB    P33    // Address B on MAX306 Analog MUX
#define MuxA    P32    // Address A on MAX306 Analog MUX

#define InRCK   P11    // RCK from HC589
#define InSCK   P37    // SCK ----//----
#define InData  P10    // Qh  ----//----
#define InSLOAD P35    // SLOAD --//---

//----------------------------------------------------------------------------
// Variables...
//----------------------------------------------------------------------------
// 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

unsigned char AIMask=0xFF;            // Masks off some of the lower 8 bits
                                      // on each conversion result from A/D

//лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл
// 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
//лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл

//----------------------------------------------------------------------------
// 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++;
}
//лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл


//лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл
// MAX187 Helper routine
// Reads analog value from A/D converter
// Global constants/variables that must be declared:
// #define CS      P37   // pin on MAX187 A/D converter
// #define SCLK    P10   // pin on MAX187 A/D converter
// #define DOut    P12   // pin on MAX187 A/D converter
//
//лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл
unsigned int GetMAX187(void) {
  unsigned char i;
  unsigned int Data;
 // Start conversion
  CS=1;
  SCLK=0;
  CS=0;
 // Wait for completion (EOC)
  while (DOut==0);
 // Toggle first bit
  SCLK=1;
  SCLK=0;
  Data=0;
  for (i=0; i<12; i++) {
    SCLK=1;
    Data <<=1; // Advance to next bit position
    if (DOut)  // Check state of bit
      Data |=0x0001; // Put in a '1'
    else
      Data &=0xFFFE; // Put in a '0'
    SCLK=0;
  }
  CS=1;
  return Data;
}


//лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл


//----------------------------------------------------------------------------
// 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++);
}


//----------------------------------------------------------------------------
// Select channel 0..15 on Analog MUX.
//----------------------------------------------------------------------------
void SetChannel(unsigned char Channel) {
  // Map around to the real world...
  if (Channel<8)
    Channel = 7 - Channel;
  else
    Channel = 23 - Channel;
  MuxA=Channel & 0x01;
  MuxB=Channel & 0x02;
  MuxC=Channel & 0x04;
  MuxD=Channel & 0x08;
}


//----------------------------------------------------------------------------
// Main part
//----------------------------------------------------------------------------
void main() {
  unsigned int Data;
  unsigned char i;
  unsigned char Rsp[20];        // Buffer for responses
  bit PwrUp=TRUE;
  unsigned char LastInput[2];   // Holds last requested input string
  unsigned int  ChangeMask;
  unsigned char Pos;
  unsigned Check=0;             // What we are checking on this poll
  unsigned int OldAD[16];       // Last read A/D value for each channel...

 //----------------------------------------------------------------------------
 // Initialize HACNET Driver
 //----------------------------------------------------------------------------
  InitHACNET(MyDeviceType, RxSize);

 //---------------------------------
 // Initialize outputs...
 //---------------------------------
  SetChannel(0);

 //------------------------------
 // Configure onchip resources...
 //------------------------------
  EA=1;        // Global int enable

  for (i=0; i<16; OldAD[i++]=0xFEDE);
  //----------------------------------------------------------------------------
  // Forever
  //----------------------------------------------------------------------------
  while(1) {
   // Check if we have to resend last response...
   if (Resend) {
     Resend=FALSE;
   //  Delay(200);
     HacTransmit(Rsp, 0xFF);
   }
   if (RxAvail) {
    // Delay(200);
     switch (RxBuffer[0]) {
       case 0 :
         Rsp[0]=0x80; // Response code
         // if we are checking digital inputs...
         if (Check==0) {
           // 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) {
             Rsp[1]=0x00;
             // Build "changed mask"...
             if (PwrUp) {
               Rsp[3]=0xFF; // Mark all as changed...
               Rsp[2]=0xFF;
             } else {
               Rsp[3]=LastInput[1] ^ Input[1]; // XOR with old vector
               Rsp[2]=LastInput[0] ^ Input[0];
             }
             // The input vector...
             Rsp[5]=Input[1];
             Rsp[4]=Input[0];
             // Make this new input vector the "old" one...
             LastInput[0]=Input[0];
             LastInput[1]=Input[1];
             HacTransmit(Rsp, 6); // Send the changed inputs...
           } else
             HacTransmit(Rsp, 1); // Empty response...
           PwrUp=FALSE;
         // Check analog inputs...
         } else {
           Rsp[1]=0x01;

           Pos=4;
           ChangeMask=0x0000; // no one changed...
           for (i= (Check==1 ? 0:8); i< (Check==1 ? 8:16); i++) {
             SetChannel(i);
             Data=GetMAX187() & (0xFF00 | ((unsigned int)AIMask));
             if (Data!=OldAD[i]) {
               OldAD[i]=Data; // Remember value
               Rsp[Pos+1]  =(unsigned char)(Data>>8); // Store new value...
               Rsp[Pos]=(unsigned char)(Data & 0x00FF);
               Pos +=2;
               // Mark the channel as modified
               ChangeMask |= 1 << i;
             }
           }
           // Store AI changemask
           Rsp[3]=(unsigned char)(ChangeMask >> 8);
           Rsp[2]=(unsigned char)(ChangeMask & 0x00FF);
           if (ChangeMask)
             HacTransmit(Rsp, Pos); // Send the AI channels that has changed...
           else
             HacTransmit(Rsp, 1); // Empty response
          }
          Check++;
          if (Check>2) Check=0;
          break;
        case 1:
          Rsp[0]=0x81; // 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;
        case 2 :
          Rsp[0]=0x82; // Response code
          // sample all the channels specified...
          for (i=RxBuffer[1]; i<=RxBuffer[2]; i++) {
            SetChannel(i);
            Data=GetMAX187() & (0xFF00 | ((unsigned int)AIMask)); // !!!!! SINCE RELEASE TEST !!!!
            OldAD[i]=Data; // Remember value
            Rsp[(i*2)+2]=(unsigned char)(Data>>8);
            Rsp[(i*2)+1]=(unsigned char)(Data & 0x00FF);
          }
          HacTransmit(Rsp, 1+((RxBuffer[2]-RxBuffer[1]+1)*2));
          break;
        case 3 :
          Rsp[0]=0x83; // Response code
          AIMask=RxBuffer[1];
          HacTransmit(Rsp, 1);
          break;
      }
      RxAvail=0;
    }
  }
}
