//----------------------------------------------------------------------------
// RADIOIO                                                    19980326 CHG
// "Virtual Wire" module.
// The unit has 8 digital inputs, and 8 digital outputs.
// The 8 inputs will be transmitted over the air to another module's output
// and the outputs will reflect the inputs on the other module.
//----------------------------------------------------------------------------
#include <reg52.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
//----------------------------------------------------------------------------
// Constants...
//----------------------------------------------------------------------------
#define TRUE   1
#define FALSE  0
#define STX    0x0D
#define ETX    0x0A

#define RxSize 8

#define tNOCOMPre 200


//----------------------------------------------------------------------------
// I/O definitions...
//----------------------------------------------------------------------------
#define RPC_Reset P30   // Reset* RPC module
#define RPC_RxA   P31   // RxA* to RPC
#define RPC_RxR   P32   // RxR* from RPC (Used only as INT0* input)
#define RPC_TxA   P33   // TxA* from RPC
#define RPC_TxR   P23   // TxR to RPC
#define RPC_D3    P24   // D3/D7 to/from RPC
#define RPC_D2    P25   // D2/D6 to/from RPC
#define RPC_D1    P26   // D1/D5 to/from RPC
#define RPC_D0    P27   // D0/D4 to/from RPC

#define nIn       P0    // The 8 inputs

#define nOut      P1    // The 8 outputs

//----------------------------------------------------------------------------
// Variables...
//----------------------------------------------------------------------------
unsigned int Timer10mSec=0;     // General timer, tick is 10 mSec
unsigned char RxBuffer[RxSize]; // Frame received from either HACBUS or RPC
unsigned char RxIndex;          // Index into RxBuffer
bit RxAvail;                    // Frame ready in RxBuffer
unsigned int tNOCOM=0;          // Timer for no comm

//----------------------------------------------------------------------------
// wait for a specific time in 10 mSec
// Based on a 11.059 MHz crystal
//----------------------------------------------------------------------------
void Delay(unsigned char t) {
  unsigned int i;
  if (t==0) return;
  while (t--) for(i=0;i<774; i++);
}

//----------------------------------------------------------------------------
// Timer 0 interrupt service function
// executes each 10 mSec @ 11.0592 MHz Crystal Clock
//----------------------------------------------------------------------------
timer0() interrupt 1 using 2 {
  TH0  = 0xDC;         // reload timer again
  TL0  = 0x00;         // to 10 mSec timeout
  if (Timer10mSec) Timer10mSec--;
  if (tNOCOM) tNOCOM--;
}

//лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл
// RPC Helper routines, receive on interrupt and transmit routines
// I/O definitions
//#define RPC_Reset P16  // Reset* RPC module
//#define RPC_RxA   P15  // RxA* to RPC
//#define RPC_RxR   P32  // RxR* from RPC (Used only as INT0* input)
//#define RPC_TxA   P33  // TxA* from RPC
//#define RPC_TxR   P14  // TxR to RPC
//#define RPC_D3    P13  // D3/D7 to/from RPC
//#define RPC_D2    P12  // D2/D6 to/from RPC
//#define RPC_D1    P11  // D1/D5 to/from RPC
//#define RPC_D0    P10  // D0/D4 to/from RPC
//bit RxAvail;                    // Frame ready in RxBuffer
//лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл
//----------------------------------------------------------------------------
// RxR issued from RPC, ie it has some data for us...
//---------------------------------------------------------------------------- 
void Int0(void) interrupt 0 using 1 {
  static unsigned char Count=0;
  unsigned char RPCRxChar;
 
  RPC_D0=RPC_D1=RPC_D2=RPC_D3=1; // Configure port-pins as inputs...
  RPC_RxA=0; // Acknowledge to RPC module
  while (RPC_RxR==0); // Wait for stable data from RPC
  // Get LSB
  RPCRxChar=(RPC_D0 ? 1:0) + (RPC_D1 ? 2:0) + (RPC_D2 ? 4:0) + (RPC_D3 ? 8:0);
  RPC_RxA=1; // Ready for next nibble

  while (RPC_RxR==1); // Wait for MSB 
  RPC_RxA=0; // Acknowledge to RPC module
  while (RPC_RxR==0); // Wait for stable data from RPC
  // Get MSB
  RPCRxChar+=(RPC_D0 ? 0x10:0) + (RPC_D1 ? 0x20:0) + (RPC_D2 ? 0x40:0) + (RPC_D3 ? 0x80:0);
  IE0=0;     // Clear pending int's from the MSB part RPC_RxR signal
  RPC_RxA=1; // Ready for next byte
 
  // If we already got the length byte, (ie this is a data byte)
  // go send it to the HOST
  if (Count) {
    RxBuffer[RxIndex++]=RPCRxChar;
    Count--;
    // Check if last byte received
    if (Count==0)
      RxAvail=TRUE;
  } else {
    // This is the first byte we are receiving, so it must be the length
    Count=RPCRxChar-1;
    RxIndex=0;
  }
}

//----------------------------------------------------------------------------
// Wait for RPC transmitter empty, and send one byte.
// Returns: Data sent 
//----------------------------------------------------------------------------
static unsigned char SendRPC(unsigned char Data) {
  // Send the LSB part...
  RPC_TxR=0; // Initiate transfer to RPC module
  while (RPC_TxA==1); // Wait for RPC to signal it's ready for transfer
  // Put out LSB data
  RPC_D0=(Data & 0x01) ? 1:0; RPC_D1=(Data & 0x02) ? 1:0;
  RPC_D2=(Data & 0x04) ? 1:0; RPC_D3=(Data & 0x08) ? 1:0;
  RPC_TxR=1; // Tell RPC that data is present
  while (RPC_TxA==0); // Wait until RPC has accepted the data
  // Send the MSB part...
  RPC_TxR=0; // Initiate transfer to RPC module
  while (RPC_TxA==1); // Wait for RPC to signal it's ready for transfer
  // Put out MSB data
  RPC_D0=(Data & 0x10) ? 1:0; RPC_D1=(Data & 0x20) ? 1:0;
  RPC_D2=(Data & 0x40) ? 1:0; RPC_D3=(Data & 0x80) ? 1:0;
  RPC_TxR=1; // Tell RPC that data is present
  while (RPC_TxA==0); // Wait until RPC has accepted the data
  RPC_D0=RPC_D1=RPC_D2=RPC_D3=1; // Turn bus into input state...
  // And return the same data (for checksum etc)
  return Data;
}
//лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл


//----------------------------------------------------------------------------
// Main part
//----------------------------------------------------------------------------
void main() {
 //---------------------------------
 // Initialize outputs...
 //---------------------------------
  // Reset RPC module
  Delay(50);
  RPC_Reset=0;
  Delay(50);
  RPC_Reset=1;

  //------------------------------
  // Configure onchip resources...
  //------------------------------
  TMOD |= 0x01;               // TMOD: timer 0, mode 1, 16 timer
  TH0   = 0xDC;               // Set timeout period for Timer 0 
  TL0   = 0x00;               // to 10 mSec timeout
  ET0   = 1;                  // Enable Timer 0 interrupts
  TR0   = 1;                  // Start timer 0

  EX0   = 1;                  // External interrupt 0 enable (RPC interrupt)
  IT0   = 1;                  // External interrupt 0 Edge sesitive

  EA    = 1;                  // Global int enable

  // Set timer to random value between 0.05 and 0.15 Sec
  Timer10mSec=(rand() % 10) + 5;

  tNOCOM=tNOCOMPre; // Preset timer
  //----------------------------------------------------------------------------
  // Forever
  //----------------------------------------------------------------------------
  while(1) {
    rand();
    // If the timer times out, send frame, and set random timeout value
    if (Timer10mSec==0) {
      SendRPC(0x00 + 2);
      SendRPC(nIn);
      // Set timer to random value between 0.05 and 0.15 Sec
      Timer10mSec=(rand() % 10) + 5;
    }
    
    if (tNOCOM==0) nOut=0xFF; // Kill output if we havn't had any comm for 2 Sec's

    // If we receive a frame, send a frame, and set random timeout value
    if (RxAvail) {
      tNOCOM=tNOCOMPre; // Preset timer
      nOut=RxBuffer[0];
      SendRPC(0x00 + 2);
      SendRPC(nIn);
      // Set timer to random value between 0.05 and 0.15 Sec
      Timer10mSec=(rand() % 10) + 5;
      RxAvail=0;
    }
  }
}
