//----------------------------------------------------------------------------
// HACNET                                                     19950908 CHG
// HACNET protocol driver
//
// Protocol format:
// Frame: <STX> <ID> <SUBID> <EVENTID> <DATA1>...<DATAn> <SUM> <ETX>
//
//1  STX       = 0x0D
//2  ID        = Devicetype
//2  SUBID     = Control/Address of the device
//               Bit 7..4 = Packet number, changes for each new transmission
//                          from the master. (if equal in two consecutive trans-
//                          missions, we do a resend only, else we react on data.
//               Bit 3..0 = Device address, 0x00..0x0F
//2  EVENTID   = Event/Command code
//               Bit 7    = 1: To Master (Answer)
//                        = 0: To Device (Request)
//               Bit 6..0 = Event number
//2  DATA      = Dataarea, defined for each <EVENTID>
//2  SUM       = Simple checksum of the whole telegram [STX..DATAn]
//1  ETX       = 0x0A
//³
//ÀÄ Length in bytes of each field on physical HACNET (ASCII bytes)
//   All bytes between STX and ETX are ASCII coded hex digits('0'..'F')
//
//
//
//----------------------------------------------------------------------------
#include <reg2051.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>

//----------------------------------------------------------------------------
// Constants...
//----------------------------------------------------------------------------
#define TRUE   1
#define FALSE  0

#define STX 0x0D       // Start of frame
#define ETX 0x0A       // End of frame

//----------------------------------------------------------------------------
// I/O definitions...
// Note: SW11..SW14 is the address switches. These are given by the standard
// used on the hardware for all HAC modules.
// The same way, HACTX is the standard "Request To Send" to the RS485 Driver.
//----------------------------------------------------------------------------
#define SW11    P16    // Address switch 1 ( a '1' is off state, '0' is on)
#define SW12    P15    // Address switch 2
#define SW13    P14    // Address switch 3
#define SW14    P13    // Address switch 4

#define HACTX   P17    // Put MAX485 in transmit mode

//----------------------------------------------------------------------------
// Variables...
//----------------------------------------------------------------------------
static unsigned char MyAddress;   // Which address i should respond to
static unsigned char MyDeviceType;// Which type of device i am

static unsigned char RxIndex=0;   // Index into RX buffer
static unsigned char RxSize;      // Size of the RxBuffer
bit TxIdle;                       // Transmitter ready for next byte
static unsigned char LastPacketNumber=0xFF;    // Last received packetnumber
static unsigned char CurrentPacketNumber;      // Packetnumber for the frame we just received

extern unsigned char RxBuffer[];  // RxBuffer (Supplied by the Client module)
bit RxAvail;                      // Message available in RX Buffer
bit Resend;                       // Resend last message

//----------------------------------------------------------------------------
// Initialize HACNET driver...
// Returns MyAddress
//----------------------------------------------------------------------------
unsigned char InitHACNET(unsigned char DevType, unsigned char Size) {
  // Disable transmitter
  HACTX=0;
  // Set devicetype...
  MyDeviceType=DevType;
  // Size of RxBuffer
  RxSize=Size;
  // Calculate my own address...
  MyAddress=(SW11 ? 0:1) + (SW12 ? 0:2) + (SW13 ? 0:4) + (SW14 ? 0:8);
  // Configure onchip resources...
  SCON  = 0x50;                   /* SCON: mode 1, 8-bit UART, enable rcvr    */
  TMOD |= 0x20;                   /* TMOD: timer 1, mode 2, 8-bit reload      */
  TH1   = 0xFF;  //FD = 9600      /* TH1:  reload value for 28.8 Kbaud        */
  PCON  = 0x80;                   /* PCON: Double baudrate, 57.6 Kbaud        */
  TR1   = 1;                      /* TR1:  timer 1 run                        */
  ES    = 1;                      /* ES:   Enable serial port int             */
  TI    = 1;                      /* TI:   set TI to send first char of UART  */
  return MyAddress;
}

//----------------------------------------------------------------------------
// Interrupt on serial channel
//----------------------------------------------------------------------------
void SerialInt(void) interrupt 4 using 1 {
  static bit HighNibble=TRUE; // True if waiting for High nibble part
  unsigned char Tmp, Sum=0;
  static bit LookingForSTX=TRUE; // We are waiting for a STX to arrive...

  //-----------------------------
  // Check if Tx register empty
  //-----------------------------
  if (TI) {
    TI=0;
    // Report Transmitter as idle and ready to send next byte...
    TxIdle=TRUE;
  }
 
 //-----------------------------
 // Check if receive interrupt...
 //-----------------------------
  if (RI) {
    RI=0;
    if (RxAvail) return; // If we aren't finished reacting on the last frame just abort.
    switch (SBUF) {
      case STX: RxIndex=0; HighNibble=TRUE; LookingForSTX=FALSE; break;
      case ETX:
        // The next we wanna see is a STX...
        LookingForSTX=TRUE;
        // If we havn't received suffient data, just abort it...
        if (RxIndex<4) break;
        // NB: Checksum is incl STX...
        Sum=STX; 
        // Calculate checksum...
        for (Tmp=0; Tmp<=RxIndex-2; Tmp++) Sum += RxBuffer[Tmp];
        // if error in checksum...
        if (Sum!=RxBuffer[RxIndex-1])
          break; // Do nothing...
        // Checksum was ok...
        else {
          // Take a sniff at the current packetnumber...
          CurrentPacketNumber = RxBuffer[1] & 0xF0;
          // Check if message is for me...
          if ((MyDeviceType==RxBuffer[0]) && (MyAddress==(RxBuffer[1] & 0x0F))) {
            // If we either have a new packetnumber, or we just powered up, react on it...
            if (LastPacketNumber == CurrentPacketNumber)
              // Resend what we send last time...
              Resend=TRUE;
            else {
              // move the real data to start of buffer (overwriting ID,SUBID fields)
              memcpy(&RxBuffer[0], &RxBuffer[2], RxIndex-3);
              RxAvail=TRUE;
            }
          }
          // Remember this packet number (regardless if message was for me or not)...
          LastPacketNumber = CurrentPacketNumber;
        }
        break;
      default:
        // If we are waiting for an STX, do nothing
        if (LookingForSTX) break;

        // if overflow...
        if (RxIndex == RxSize) {
          RxIndex=0;
          LookingForSTX=TRUE;
        } else {
          // Store character...
          Tmp=SBUF;
          if (HighNibble) // Store in MSB...
            RxBuffer[RxIndex] = toint(Tmp)<<4;
          else // Store in LSB...
            RxBuffer[RxIndex++] |= toint(Tmp);
          // Expect the other part
          HighNibble=!HighNibble;
        }
        break;
    }
  } // if RI
}


//----------------------------------------------------------------------------
// Wait for transmitter empty, and send one byte.
//----------------------------------------------------------------------------
static unsigned char Send(unsigned char Data) {
  while (TxIdle==FALSE);  // Wait for TX to become ready
  TxIdle=FALSE;           // Transmitter busy
  SBUF=Data;
  return Data;
}

//----------------------------------------------------------------------------
// Send one byte as 2 ASCII hex bytes.
//----------------------------------------------------------------------------
static unsigned char SendHex(unsigned char Data) {
  unsigned char Tmp;
  Tmp=((Data >> 4) & 0x0F);
  Send(Tmp <= 9 ? Tmp+0x30 : Tmp+0x37);

  Tmp= Data & 0x0F;
  Send(Tmp <= 9 ? Tmp+0x30 : Tmp+0x37);
  return Data;
}


//----------------------------------------------------------------------------
// HacTransmit
//----------------------------------------------------------------------------
void HacTransmit(unsigned char *Buffer, Length) {
  unsigned char Index, Sum;
  static unsigned char LastLength;

  HACTX=1; // Activate Transmitter...
 
  if (Length==0xFF)
    Length=LastLength;
  else
    LastLength=Length;

  Sum = Send(STX);
  Sum += SendHex(MyDeviceType);
  // Copy current packetnumber into bit 7..4 of MyAddress...
  Sum += SendHex(MyAddress | CurrentPacketNumber);

  // Send each byte as Hex ASCII chars...
  for (Index=0; Index<Length; Index++) Sum += SendHex(*(Buffer+Index));
  // Send checksum
  SendHex(Sum);
  // Send End Of Text
  Send(ETX);

  // Wait for completion of last byte
  while (TxIdle==FALSE);
  // Deactivate Transmitter...
  HACTX=0;
}

