
/* These routines work together to send and receive data packets of */
/*  any size between two systems.  They can be turned into a file   */
/*  xfer protocol if need be.                                       */


#define PROTOCOL_PACKET_MAX  10000
#define PROTOCOL_BUFFER_SIZE 10000
#define SYNC_CHAR  85

#include "crctable.h"

unsigned char protocol_byte_to_xor_with;  /* This is set in the send function */
      /* and used in the receive function.  It is gotten by time(NULL) % 256. */
      /*  Most all packet chars are XORd.  This is supposed to be a random    */
      /*  byte which kind of obscures the program's mechanism of operation.   */
char protocol_buffer(PROTOCOL_BUFFER_SIZE);
unsigned short protocol_buffer_pointer_start=0,  /* These two variables are equal only when the buffer is empty. */
         protocol_buffer_pointer_end=PROTOCOL_BUFFER_SIZE - 1,  /* Convert to offset. */
         protocol_buffer_pointer_temp,protocol_buffer_pointer_2nd_sync_byte;


/*----------  Receive any characters into our own receive buffer  ------------*/

/* Here we must detect if the packet type of 'e'of was received and zap our  */
/*  buffer if it's detected.  Only leave the buffer pointing to the 'e'of    */
/*  packet itself.                                                           */

int protocol_receive_any_chars(int detect_packet_flag)
{   /* Characters are always appended to the end of the buffer and taken from the start of it. */
while (1)
  {
  protocol_buffer_pointer_temp = protocol_buffer_pointer_end + 1;  /* Compute which byte offset would hold the next character so we can decide if buffer is full. */
  if (protocol_buffer_pointer_temp == PROTOCOL_BUFFER_SIZE)
    protocol_buffer_pointer_temp = 0;
  if (protocol_buffer_pointer_temp == protocol_buffer_start)  /* Buffer full? */
    break;   /* Just don't do anything and return success code. */
  if (!fossil_available(fossil_current_port))    /* Nothing waiting from port? */
    break;   /* Nothing to do; return success code. */
  protocol_buffer[++protocol_buffer_pointer_end] = fossil_receive(fossil_current_port);
  }
/* All available characters received; check if 'e'of signal was received  */
/*  in this data somewhere.                                               */
/* LATER! */
return(0);
}


/*----------------------------------------------------------------------------*/

int protocol_send_packet(int modem_port_no,char the_packet[],unsigned short packet_length,int common_debug_level_current)
{   /* Max. packet length passed is restricted to PROTOCOL_PACKET_MAX, which is defined above. */
div_t result;       /* For outputting "unsigned short"s in two separate bytes. */
unsigned short current_character_pointer=0;  /* Position in packet data we're processing. */
long computed_crc=0;
char char_to_send;

computed_crc = modem_port_no;  /* These 2 lines are to eliminate warning message. */
computed_crc = 0;              /* NOTE: They may be commented out for speed. */

if (packet_length > PROTOCOL_PACKET_MAX)   /* NOTE: Try to comment this out for speed. */
  return(1);  /* ...indicating failure to send as requested; too long. */
fossil_write(fossil_current_port,SYNC_CHAR); /* Send two bytes which signal start of packet. */
fossil_write(fossil_current_port,SYNC_CHAR);
result = div(packet_length,256);  /* Output the packet length, MSB, then LSB. */
fossil_write(fossil_current_port,result.quot);  /* Send out the 2 length bytes. */
fossil_write(fossil_current_port,result.rem);
while (current_character_pointer < packet_length)   /* Write out the packet information. */
  {
  char_to_send = the_packet[current_character_pointer];
  computed_crc = update_crc32(char_to_send,computed_crc);
  fossil_write(fossil_current_port,char_to_send);
  current_character_pointer++;
  }
fossil_write(fossil_current_port,((computed_crc >> 24) & 255));  /* CRC bytes.*/
fossil_write(fossil_current_port,((computed_crc >> 16) & 255));
fossil_write(fossil_current_port,((computed_crc >>  8) & 255));
fossil_write(fossil_current_port,( computed_crc        & 255));
return(0);
}


/*----------------------------------------------------------------------------*/

unsigned short protocol_get_packet(int modem_port_no,char the_packet[],int common_debug_level_current)
{       /* Returns 0 if no good packet has been received at the present time, */
        /* even if one is currently in the process of being received (we have */
        /* received the start of a packet but not its end).  We keep track of */
        /* whether we're in a packet or not by a state variable.              */
static unsigned short packet_length,current_character_pointer=0;
static long computed_crc=0,received_crc,crc_msb,crc_msb2,crc_lsb2,crc_lsb;
int char_from_modem,temp_int;
unsigned char temp_unsigned_char;
static int receiving_packet_state=0;  /* 0 = not receiving a packet, 1 is next step, etc.... */

protocol_receive_any_chars();  /* First receive any characters into our own buffer. */
if (receiving_packet_state == 0)   /* NOTE: Turn this into a case statement? */
  goto sync_byte_loop;
if (receiving_packet_state == 1)
  goto check_for_second_sync_byte;
if (receiving_packet_state == 2)
  goto get_packet_length_msb;
if (receiving_packet_state == 3)
  goto get_packet_length_lsb;
if (receiving_packet_state == 4)
  goto get_packet_data;
if (receiving_packet_state == 5)
  goto get_crc_msb_1;
if (receiving_packet_state == 6)
  goto get_crc_msb_2;
if (receiving_packet_state == 7)
  goto get_crc_lsb_2;
if (receiving_packet_state == 8)
  goto get_crc_lsb_1;


sync_byte_loop:   /* Keep coming back to here until we get a sync byte. */
receiving_packet_state = 0;
if (protocol_buffer_pointer_start == protocol_buffer_pointer_end)  /* End of buffer without seeing any sync bytes? */
  return(0);
char_from_modem = protocol_buffer(protocol_buffer_pointer_start++);
if (protocol_buffer_pointer_start == PROTOCOL_BUFFER_SIZE)
  protocol_buffer_pointer_start = 0;
if (char_from_modem != SYNC_CHAR)   /* Did we receive a sync character? */
  goto sync_byte_loop;

check_for_second_sync_byte:
receiving_packet_state = 1;
if (protocol_buffer_pointer_start == protocol_buffer_pointer_end)
  return(0);
protocol_buffer_pointer_2nd_sync_byte = protocol_buffer_pointer_start;
char_from_modem = protocol_buffer(protocol_buffer_pointer_start++);
if (protocol_buffer_pointer_start == PROTOCOL_BUFFER_SIZE)
  protocol_buffer_pointer_start = 0;
if (char_from_modem != SYNC_CHAR)
  goto sync_byte_loop;

/* The 2 sync characters have been received.  Now get packet length bytes. */
get_packet_length_msb:
receiving_packet_state = 2;
if (protocol_buffer_pointer_start == protocol_buffer_pointer_end)
  return(0);
char_from_modem = protocol_buffer(protocol_buffer_pointer_start++);
if (protocol_buffer_pointer_start == PROTOCOL_BUFFER_SIZE)
  protocol_buffer_pointer_start = 0;
packet_length = char_from_modem * 256;

get_packet_length_lsb:
receiving_packet_state = 3;
if (protocol_buffer_pointer_start == protocol_buffer_pointer_end)
  return(0);
char_from_modem = protocol_buffer(protocol_buffer_pointer_start++);
if (protocol_buffer_pointer_start == PROTOCOL_BUFFER_SIZE)
  protocol_buffer_pointer_start = 0;
packet_length += char_from_modem;
if (packet_length > PROTOCOL_PACKET_MAX)
  goto sync_byte_loop;  /* This shouldn't happen, so must be a bad packet. */

get_packet_data:
receiving_packet_state = 4;
while (current_character_pointer < packet_length)
  {
  if (protocol_buffer_pointer_start == protocol_buffer_pointer_end)
    return(0);
  char_from_modem = protocol_buffer(protocol_buffer_pointer_start++);
  if (protocol_buffer_pointer_start == PROTOCOL_BUFFER_SIZE)
    protocol_buffer_pointer_start = 0;
  the_packet[current_character_pointer] = (char)char_from_modem;
  computed_crc = update_crc32(the_packet[current_character_pointer],computed_crc);
  current_character_pointer++;
  }

get_crc_msb_1:
receiving_packet_state = 5;
if (protocol_buffer_pointer_start == protocol_buffer_pointer_end)
  return(0);
char_from_modem = protocol_buffer(protocol_buffer_pointer_start++);
if (protocol_buffer_pointer_start == PROTOCOL_BUFFER_SIZE)
  protocol_buffer_pointer_start = 0;
crc_msb = char_from_modem;

get_crc_msb_2:
receiving_packet_state = 6;
if (protocol_buffer_pointer_start == protocol_buffer_pointer_end)
  return(0);
char_from_modem = protocol_buffer(protocol_buffer_pointer_start++);
if (protocol_buffer_pointer_start == PROTOCOL_BUFFER_SIZE)
  protocol_buffer_pointer_start = 0;
crc_msb2 = char_from_modem;

get_crc_lsb_2:
receiving_packet_state = 7;
if (protocol_buffer_pointer_start == protocol_buffer_pointer_end)
  return(0);
char_from_modem = protocol_buffer(protocol_buffer_pointer_start++);
if (protocol_buffer_pointer_start == PROTOCOL_BUFFER_SIZE)
  protocol_buffer_pointer_start = 0;
crc_lsb2 = char_from_modem;

get_crc_lsb_1:
receiving_packet_state = 8;
if (protocol_buffer_pointer_start == protocol_buffer_pointer_end)
  return(0);
char_from_modem = protocol_buffer(protocol_buffer_pointer_start++);
if (protocol_buffer_pointer_start == PROTOCOL_BUFFER_SIZE)
  protocol_buffer_pointer_start = 0;
crc_lsb = char_from_modem;

receiving_packet_state = 0;  /* Reset to start looking for the beginning of a packet again, no matter what this packet turns out like. */

received_crc = ((crc_msb & 255) << 24) | ((crc_msb2 & 255) << 16) | ((crc_lsb2 & 255) << 8) | (crc_lsb & 255);
if (received_crc != computed_crc)
  {
  protocol_buffer_pointer_start = protocol_buffer_pointer_2nd_sync_byte;
  goto sync_byte_loop;   /* Start checking for a packet at this particular null. */
  }
return(packet_length);
}


