#include "serial_communications.h"

/** @name user.c 

    This file contains functions that will be used by any programming accessing the communciations system.

    @author Daniel Storey, UWA, 1998
    @version 1.0   */

/*@{*/

/** Global Variable for storing channel information */
Channel radio_channel; 

/** Global semaphore */
bool radio_sema;

/** Global indicators of transmission state */
bool radio_send;
bool radio_begin_send;

/** Global value of timer id for low-level network */ 
TimerHandle time_id;

/*************************************************************************/
/** Initiate the communications system.
    Called by the user to initiate the communications system.

    @param baudrate int, the baud rate of the link.
    @param next_address char, the address of the next machine in the control loop.
    @return int, 0 if the transmission was sucessful. */
/*************************************************************************/
int RadioInit(char number)
{
  char my_address[2], n_a[2], broadcast_address[2];
  int next_address, baudrate = SER19200, wireless = TRUE;
  bool master = FALSE;
  
  /* Use robot identification number as address */
  my_address[0] = (char) OSMachineID(); 
  my_address[1] = '\0';

  /* Check station status.  ID = 1 -> Master station */
  if(my_address[0]==1)
    master = TRUE;
  
  /* Set next address */
  if(my_address[0]==(char) number)
    next_address = 1;
  else
    next_address = my_address[0] + 1;

  /* offset address for easy reading */
  my_address[0] += 48; /* move to ASCII Number range */
  
  /* Write next address */
  n_a[0] = next_address + 48; /* move to ASCII Number range */
  n_a[1] = '\0';

  /* Write to broadcast address */
  broadcast_address[0] = 0 + 48; /* ASCII zero */
  broadcast_address[1] = '\0';
    
  radio_channel =  initiate_serial_communications(my_address, n_a, broadcast_address, baudrate, wireless, master);
    
#if DEBUG 
  LCDPrintf("Initialise\n");
#endif

  if(master==TRUE) {
#if DEBUG
    LCDPrintf("Master\n");
#endif
    tx_send();
    OSWait(2);
    LOWSEND();
    write_serial_data(EYEBOT_SERIAL_PORT);
    while(OSCheckOutRS232(EYEBOT_SERIAL_PORT)!=0);/* is o/p buffer empty? */
    OSWait(1);
    tx_receive();
    OSWait(2);
  }

  else {
#if DEBUG 
    LCDPrintf("Slave\n");
#endif
  }

  time_id = OSAttachTimer(CYCLE_TIME, RadioCheck);
  
  radio_send = FALSE;
  radio_begin_send = FALSE;
  radio_sema = FALSE;
  
  return 0;
}

/*************************************************************************/
/** Release Communications.
    Close the communications channel by removing the low-level function calls.

    @return void. */
/*************************************************************************/
void RadioRelease()
{
  OSDetachTimer(time_id);
}

/*************************************************************************/
/** Transmit a message.
    Called by the user to transmit a data array.

    @param id int, the number of the station to send to.
    @param message *char, the message to be sent.
    @param length int, the length of the message to be sent.
    @return int, 0 if the transmission was sucessful, -1 if not. */
/*************************************************************************/
int RadioTx(char id, char *message, int length)
{
  char address[2];
  int a;

  radio_sema=TRUE;
  address[0] = id + 48;
  address[1] = '\0';
  a = comms_send(message, address, length, &radio_channel);

  radio_sema=FALSE;

  return a;
}

/*************************************************************************/
/** Receive a message (Non-blocking).
    Check the incoming queue for a message.  If there are no messages, return -1.

    @param message char*, The received message.
    @return int, the sender ID, or -1 for an error. */
/*************************************************************************/
int RadioRx(char *message)
{
  int a = 0;
  char address[2];

  radio_sema=TRUE;
  
  a = comms_receive(message, address, &radio_channel);

  radio_sema=FALSE;
  
  /* No Packet present */
  if(a==-1)
    return -1;

  /* Return the address */
  return (int) (address[1] - 48);
}

/*************************************************************************/
/** Receive a message (Blocking).
    Wait until there is a message in the receive queue, then get it.

    @param message char*, The received message.
    @return int, the sender ID. */
/*************************************************************************/
int RadioRxB(char *message)
{
  char address[2];
  
  while(RadioRx(message)==-1)
    OSWait(10); /* Wait for some action */
  
  /* Return the address */
  return (int) (address[1] - 48);
}

/*************************************************************************/
/** Low level send & receive.
    Send and receive at the lowest level.  This is a multitasking routine
    that is to be run in the background.  Its priority represents the speed
    at which data will be transmitted through the network as well as the amount of processing resources it will consume.

    @param void.
    @return void.*/
/*************************************************************************/
void RadioCheck()
{
#if TIMERS
  LCDPrintf("Radio Check\n");
#endif
  BufferCheck();

  /* Check to see if the transmitter must be switched */ 
  if(radio_send==TRUE) {
    if(OSCheckOutRS232(EYEBOT_SERIAL_PORT)==0) { /* is o/p buffer empty? */
      WL_RECV();
      radio_send = FALSE;
    }
    return;
  }

  /* Check to see if the pseudo semaphore is occupied */
  if(radio_sema==TRUE)
    return;
  
  /* Check if we need to switch to transmit mode */
  if((can_send(&radio_channel))&&(radio_begin_send==TRUE)) {
    WL_SEND();
    radio_begin_send=FALSE;
    return;
  }
  
  /* Check if we can send */
  if((can_send(&radio_channel))&&(radio_begin_send==FALSE)) {
    LOWSEND();
    write_serial_data(EYEBOT_SERIAL_PORT);
    radio_send = TRUE;
    return;
  }

  /* If we can't do any of these things, read serial port data */
  LOWRECEIVE();
  /* Change mode if a token has been received */
  if(can_send(&radio_channel)) {
    radio_begin_send=TRUE;
  }
  
  return;
}

/*************************************************************************/
/** Low level send.
    Explicitly call a low level send.

    @param void.
    @return void.*/
/*************************************************************************/
void LOWSEND()
{
  low_send(&radio_channel);
}

/*************************************************************************/
/** Low level receive.
    Explicitly call a low level receive.

    @param void.
    @return void.*/
/*************************************************************************/
void LOWRECEIVE()
{
  low_receive(&radio_channel);
}

void BufferCheck()
{
  read_serial_data(EYEBOT_SERIAL_PORT);
}










