//----------------------------------------------------------------------------
// HACAIDO                                                    19950905 CHG
// 16 analog inputs
// 16 digital (Ћ * UCN5818) outputs
//
// HACBUS:
//   Device type: 0x02         ; HACAIDO type
//   Address    : 0x01..0x0F   ; Address 1..15
//   Commands   : 0x00                      ; Poll
//          Resp: 0x80 [XX XX AA BB..YY ZZ] ;
//                                     ; XX XX is "changed" vector and AA BB is new data
//                                     ; for the changed inputs, no data if no change
//                                     ;
//              : 0x01 An              ; Request value of a number of A/D channels
//                                     ; starting with channel 0
//          Resp: 0x81 AA BB..YY ZZ    ; Return values of the number of channels
//                                     ; specified.
//              : 0x02 XX              ; Set AND mask,XX, for the lower 8 bits
//                                     ; from the A/D converter (to avoid "noise").
//          Resp: 0x82                 ;
//              : 0x03 XX XX           ; Set all 16 outputs to value XX XX
//          Resp: 0x83                 ;
//              : 0x04 XX YY           ; Set output number XX to value YY
//          Resp: 0x84                 ;
//----------------------------------------------------------------------------
#include <reg2051.h>
#include <stdio.h>
#include "..\HACNET\HACNET.H"


//----------------------------------------------------------------------------
// Constants...
//----------------------------------------------------------------------------
#define TRUE  1
#define FALSE 0

#define MyDeviceType 0x02      // My devicetype
#define RxSize 3+3             // Maximum size of RxBuffer

//----------------------------------------------------------------------------
// I/O definitions...
//----------------------------------------------------------------------------
#define OutClk  P37    // Clock to UCN5818 output driver (Shared with MAX187 !)
#define OutStr  P10    // Strobe to UCN5818 output driver
#define OutData P11    // Data to UCN5818 output driver  (Shared with MAX187 !)

#define CS      P37   // pin on MAX187 A/D converter (Shared with OutClk !)
#define SCLK    P11   // pin on MAX187 A/D converter (Shared with OutData !)
#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

//----------------------------------------------------------------------------
// 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

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


//лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл
// 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;

  OutStr= 0; dummy++;
  OutData = 0; dummy++;
  OutClk=0; 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++;
}


//лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл
// 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 Rsp[35];       // Buffer for responses
  unsigned int OldAD[16];      // Last read value from each of the 16 channels
  unsigned char i, Pos;
  unsigned int ChangeMask;     // Mask of changed channels since last read.
  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
  SetChannel(0);

  for (i=0; i<16; OldAD[i++]=0xFEDE);

 //------------------------------
 // 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;
    //    Delay(200);
        HacTransmit(Rsp, 0xFF);
      }
      if (RxAvail) {
     //   Delay(200);
        switch (RxBuffer[0]) {
          case 0 :
            Rsp[0]=0x80; // Response code
            ChangeMask=0x0000;
            Pos=3;
            for (i=0; i<16; i++) {
             SetChannel(i);
             Data=GetMAX187() & (0xFF00 | ((unsigned int)AIMask));
              if (Data!=OldAD[i]) {
                OldAD[i]=Data; // Remember value
                Rsp[Pos]=(unsigned char)(Data & 0x00FF);
                Rsp[Pos+1]  =(unsigned char)(Data>>8);
                Pos +=2;
                // Mark the channel as modified
                ChangeMask |= 1 << i;
              }
            }
            // Store changemask
            Rsp[2]=(unsigned char)(ChangeMask >> 8);
            Rsp[1]=(unsigned char)(ChangeMask & 0x00FF);
            if (!ChangeMask)
              HacTransmit(Rsp, 1); // Empty response
            else
              HacTransmit(Rsp, Pos); // Send the changemask and the modified
                                     // channels...
            break;
        case 1 :
          Rsp[0]=0x81; // Response code
          // sample all the channels specified...
          for (i=0; i<RxBuffer[1]; i++) {
            SetChannel(i);
            Data=GetMAX187() & (0xFF00 | ((unsigned int)AIMask));
            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[1]*2));
          break;
          case 2 :
            Rsp[0]=0x82; // Response code
            AIMask=RxBuffer[1];
            HacTransmit(Rsp, 1);
            break;
          case 3 :
            Output[0]=RxBuffer[1];
            Output[1]=RxBuffer[2];
            UpdateUCN5818();
            Rsp[0]=0x83; // Response code
            HacTransmit(Rsp, 1); // Empty response
            break;
          case 4 :
            SetOutput(RxBuffer[1], RxBuffer[2]);
            // Set the outputs...
            UpdateUCN5818();
            Rsp[0]=0x84; // Response code
            HacTransmit(Rsp, 1); // Empty response
            break;
        }
        RxAvail=0;
      }
    }
  }
}
