// receive_functions.c

#include "1394.h"
#include "data_structures.h"
#include "phy_services.h"
#include "arb.h"
#include "shared.h"

ArbState portR_next_arb(int port_num) { // return next arb state (only called in packet context)
  ArbState arb;
  next_arb[port_num] = FALSE;
  advance_OK[port_num] = TRUE;          // OK to get the next symbol from the FIFO
  while (!next_arb[port_num])           // port has not advanced to the next item yet
    ;
  arb = portRarb[port_num];
  if (packet_ending[port_num]) {        // does this arb state terminate the packet?
    next_arb[port_num] = FALSE;         // if so, then let the FIFO advance to the next 
    advance_OK[port_num] = TRUE;        // arb state and then advance eagerly
  }
  return (arb);
}

float Legacy_time(int n) {              // returns the duration (in seconds) of a specified number 
                                        // of _exact_ S400 byte times (each approx 20ns)
  return((2 * n)/(BASE_RATE * 1000000));
}       

void wait_Legacy_time(int n) {          // waits a specified number of _exact_ S400 byte times
                                        // (each approx 20ns)
  wait_time(Legacy_time(n));
}       

void wait_symbol_time(speedCode symbol_speed) {  // waits the _exact_ duration of a symbol at the 
                                                 // specified speed
                                                 // i.e. approx 80ns for S100, 40ns for S200, etc.
  wait_time(8/(BASE_RATE * 1000000 * (1 << symbol_speed)));
}

void tx_control(ArbState control, int r_port) { // Transmit a control symbol, but not on r.port
  int i;
  for (i = 0; i < NPORT; i++) { 
    if (i != r_port)
      portTarb(i, control);             // timing will be ensured by context
  }
}

void start_rx_packet() {                // Send data prefix and do speed signaling
                                        // receive on DS or Beta, repeat to both
  int i;
  ArbState arb, previous_arb;
  boolean prefix_complete;              // TRUE if no longer receiving valid packet starting symbols:
                                        // DATA_PREFIX, DATA_NULL, or SPEED
  int fifo_backlog;                     // Current number of symbols queued in the receive FIFO
  int must_delete;                      // High level watermark allowing data repeating to begin
                                        // without the insertion of additional deletable symbols
  int non_deletable_time;               // Duration of mandatory symbols in a packet prefix
  int deletable_time;                   // Duration of deletable symbols to be inserted after the
                                        // packet prefix, assuming the FIFO isn't critically behind
  arb_timer = 0;
  non_deletable_time = 0;
  deletable_time = 0;
  non_null_packet = FALSE;              // Reset data payload indicator at beginning of each new packet

  if (!DS_stuck) {
    max_beta_timer = 0;                 // timer only needs to be implemented in border capable nodes
    DS_stuck = TRUE;                    // and note that this will have to be released by sending
                                        // a Legacy format packet
  }

  portTarb(receive_port, IDLE);         // Immediately begin sending requests on a beta receive port
                                        // and remove grant, if any, on a Legacy receive port
  prefix_complete = FALSE;              // still in valid packet beginning sequence
  format_committed = FALSE;             // start out not knowing received packet format
  cur_speed = S100;                     // Assume S100 speed until proven otherwise.
  cur_format = BETA;                    // Assume Beta format until proven otherwise.
  arb = portRarb[receive_port];         // arb state on entry
  previous_arb = IDLE;

  // Wait for incoming packet prefix to complete. While waiting, process any speed-signaling
  // received, cycle start tokens received, or any gap events (subaction gap or arb-reset gap)
  // which occur. Upon entry into start_rx_packet, the incoming arb state on the receive_port
  // will be either DATA_PREFIX, DATA_NULL, SPEED, CYCLE_START_ODD, or CYCLE_START_EVEN.
  // Furthermore, requests to process gap events are initially FALSE as they are processed with 
  // priority in idle_actions().
  // Also ensure that the min packet prefix requirements are met for all packets formats and
  // insert the requisite number of deletable symbols prior to repeating data payloads
  while (!prefix_complete || 
         (arb_timer < non_deletable_time) || 
         ((arb_timer < non_deletable_time + deletable_time) && !(fifo_backlog > must_delete))) {

    switch (arb) {
      // Process DATA_PREFIX and DATA_NULL states first, partly to ensure
      // Legacy ports are busied as soon as possible
      case DATA_PREFIX:
        if (!format_committed) {       // DATA_PREFIX before any speed code signifies Legacy format
          cur_format = LEGACY;
          format_committed = TRUE;
          non_deletable_time = Legacy_time(SPEED_SIGNAL_LENGTH + DATA_PREFIX_HOLD);
          received_speed_signal = FALSE;
        }
        tx_control(arb, receive_port); // Repeat the arb state
        break;
      case DATA_NULL:
        if (!format_committed)           // DATA_NULL's received before the format are considered
          tx_control(arb, receive_port); // starting symbols and are repeated
        else                             // DATA_NULL after the format has been repeated indicates
          prefix_complete = TRUE;        // a packet ending state and is treated as such to
        break;                           // guarantee packet timings for concatenations
      case SPEED:
        cur_speed = portRspeed[receive_port];
        cur_format = current_pkt[receive_port];
        format_committed = TRUE;
        received_speed_signal = TRUE;
        arb_timer = 0;                   // case of long DP or DN followed by real packet prefix
                                         // reset so that deletable symbols are inserted properly

        // common code for signaling speed on both port types
        for (i = 0; i < NPORT; i++)
          if (i != receive_port) {            // Repeat the speed signal
            speed_OK[i] = (cur_speed <= port_speed[i]) && (Beta_mode[i] || cur_format == LEGACY);
            if (speed_OK[i]) 
              portTspeed(i, cur_speed, cur_format); // format only needed for Beta mode ports
            else portTarb(i, DATA_NULL);
          }
        wait_symbol_time(cur_speed);
        for (i = 0; i < NPORT; i++)
          // now send the next symbol on the Beta mode ports
          if (i != receive_port && Beta_mode[i])
            portTarb(i, speed_OK[i] ? DATA_PREFIX: DATA_NULL);
        if (cur_format == LEGACY) { // therefore cur_speed < S800
          // extend the speed signal
          // waited 1, 2 or 4 Legacy_time units
          wait_Legacy_time(SPEED_SIGNAL_LENGTH - symbol_time(cur_speed));
          // now send the next symbol on the DS ports
          for (i = 0; i < NPORT; i++)
            if (i != receive_port)
              // harmless writing this to the beta mode ports as well
              portTarb(i, speed_OK[i] ? DATA_PREFIX: DATA_NULL);
          // ensure entire packet prefix time consumes 2 symbol times or 
          // (SPEED_SIGNAL_LENGTH+DATA_PREFIX_HOLD), whichever is longer
          if (2*symbol_time(cur_speed) > SPEED_SIGNAL_LENGTH+DATA_PREFIX_HOLD)
            non_deletable_time = Legacy_time(2*symbol_time(cur_speed));
          else
            non_deletable_time = Legacy_time(SPEED_SIGNAL_LENGTH + DATA_PREFIX_HOLD);
        } else  // not Legacy format
            non_deletable_time = Legacy_time(2*symbol_time(cur_speed));
        break;
      case CYCLE_START_ODD:
      case CYCLE_START_EVEN:
        if (!format_committed) { // always expect cycle start token before format indication
          odd_isoch_phase = (arb == CYCLE_START_ODD);
          if (link == B_Link)           // Alert link
            PH_DATA_indication(odd_isoch_phase ? PH_ISOCH_ODD: PH_ISOCH_EVEN, 0, 0, 0); 
          for (i = 0; i < NPORT; i++)                   // Cycle start tokens are not sent on DS ports,
            if (!Beta_mode[i]) portTarb(i, DATA_NULL);  // send DATA_NULL instead to prevent idle gap
          send_control(odd_isoch_phase ? CYCLE_START_ODD: CYCLE_START_EVEN, FALSE, receive_port);
          iso_cycle = TRUE;
          // After repeating cycle start token, treat as if a DATA_NULL had been received
          tx_control(DATA_NULL, receive_port);
          arb_timer = 0;             // so that CST symbols are not treated as packet prefix symbols 
        } else                       // error case, token received after packet formatting
          prefix_complete = TRUE;    // treat as ending symbol of mal-formed packet
        break;
      case DATA_BYTE:
        prefix_complete = TRUE;
        // When sending data, requirement is to send deletable symbols for at least one packet symbol
        // or 20 ns, whichever is greater (provided the FIFO isn't in a critical state).  Since, the
        // underflow prevention logic used to center the FIFO unconditionally inserts 20ns of time,
        // additional time is only provided within this loop for packet symbol times which are larger
        // than 20 ns: namely, S100 and S200 speeds.
        if ((cur_speed == S100) || (cur_speed == S200))
          deletable_time = Legacy_time(symbol_time(cur_speed) - symbol_time(S400));
        must_delete = cur_speed == S3200 ? 16 : cur_speed == S1600 ? 8 : 
                      cur_speed == S800 ? 4 : 2; // nominal 40 ns, or two symbol for S200 and S100
        break;

      case ASYNC_START:
      case ARB_RESET_EVEN:
      case ARB_RESET_ODD:
		    if (gap_token(receive_port)) { // over the top processing, should see a token only once at most
		      gap_repeat_actions(FALSE, receive_port);
		      portTarb(receive_port, IDLE); // restore the ports to previous state
		      arb = previous_arb;           // and prevent the code below picking up the token
		      tx_control(arb, receive_port); 
		    }
        break;
      default:                   // any other arb signal indicates packet prefix has concluded,
        prefix_complete = TRUE;  // exit loop after prefix timings have been met
        break;
    }

    // if still in the packet prefix, advance the FIFO to the next arbitration indication
    if (!prefix_complete) {
      previous_arb = arb;        // arb has been backed off if a token
      arb = portR_next_arb(receive_port);
    }
    
    fifo_backlog = (FIFO_DEPTH + fifo_wr_ptr[receive_port] - fifo_rd_ptr[receive_port]) % FIFO_DEPTH;

  }
  if (arb == DATA_BYTE) {               // Actually receiving a packet?
    sent_async_start_token = sent_arb_reset = FALSE;
    arb_timer = 0;
	  while (!(fifo_backlog > must_delete) && (arb_timer < Legacy_time(symbol_time(S400)))) {
	    // Allow time for the FIFO to load, but start repeat immediately if critical
	    fifo_backlog = (FIFO_DEPTH + fifo_wr_ptr[receive_port] - fifo_rd_ptr[receive_port]) % FIFO_DEPTH;
	  }
  }
}

