// receive_actions.c

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

void receive_actions() {

  int byte_count = 0, i;
  PHY_PKT rx_phy_pkt;
  boolean end_of_data = FALSE;
  ArbState rx_arb_state;
  ack = concatenated_packet = isbr_OK = fly_by_OK = FALSE;
  requesting_port = NPORT;

  if (!enab_accel && ((breq == FAIR_REQ) || (breq == PRIORITY_REQ))) {
    breq = NO_REQ;                      // Cancel the request
    PH_ARB_confirmation(PH_LOST, 0, 0); // And let the link know
  }
  PH_DATA_indication(PH_DATA_PREFIX, 0, 0, 0); // Send notification of bus activity

  fork
    {
      start_rx_packet();                // Start up receiver and repeater and repeat data prefix
                                        // requests on receive_port
      rx_arb_state=portRarb[receive_port]; // last thing read
      if (rx_arb_state == DATA_BYTE) {
        if ((link != Legacy_Link) || (cur_format == LEGACY))  // Filter Beta formats from Legacy link
          PH_DATA_indication(PH_DATA_START, cur_speed, 0, cur_format); // Send speed indication
      }
      do {
        if (rx_arb_state == DATA_BYTE) {
          //get data byte and repeat out other ports
          if ((link != Legacy_Link) || (cur_format == LEGACY))  // Filter Beta formats from Legacy link
            PH_DATA_indication(PH_DATA_BYTE, 0, current_data[receive_port], 0);
          tx_byte(current_data[receive_port]);
          if (byte_count < 8)           // Accumulate first 8 bytes
            rx_phy_pkt.dataBytes[byte_count] = current_data[receive_port];
          byte_count++;
          ack = (byte_count == 1);      // For acceleration, any 8-bit packet is an ack
          if ((cur_format == LEGACY) && (byte_count > 1) && 
              ((breq == FAIR_REQ) || (breq == PRIORITY_REQ))) {
            breq = NO_REQ;              // Fly-by impossible so cancel requests, but only
                                        // if link isn't filtered and can recognize cancellation
            PH_ARB_confirmation(PH_LOST, 0, 0); 
            // Let the link know (immediately) on 2nd byte (or 9th bit!)
          }
          if (fifo_rd_ptr[receive_port] == fifo_wr_ptr[receive_port]) {
            // FIFO underrun 
            // - just emptied the FIFO, and a new byte has not come in!!
            end_of_data = TRUE;
            rx_arb_state = IDLE;        // assume
            packet_ending[receive_port] = TRUE;  // inform process_requests() that packet has concluded
            next_arb[receive_port] = FALSE;      // and let the FIFO advance eagerly
            advance_OK[receive_port] = TRUE;
          } else rx_arb_state=portR_next_arb(receive_port);
        } else end_of_data = TRUE;
      } while (!end_of_data);
      if ((cur_format == LEGACY) && !ack && ((breq == FAIR_REQ) || (breq == PRIORITY_REQ))) {
        breq = NO_REQ;                  // Fly-by impossible so cancel requests, but only
                                        // if link isn't filtered and can recognize cancellation
        PH_ARB_confirmation(PH_LOST, 0, 0); // Advise the link
      }
    
      // send packet ending, depends on the received packet ending    
      switch (rx_arb_state) {
        case DATA_PREFIX:
        case DATA_NULL:
          concatenated_packet = TRUE;
          if ((link != Legacy_Link) || (cur_format == LEGACY))  // Don't send redundant indication if
            PH_DATA_indication(PH_DATA_PREFIX, 0, 0, 0);           // Legacy link is already in DATA_PREFIX
          stop_tx_packet(rx_arb_state, NPORT);
          break;
        case GRANT:
        case GRANT_ISOCH:
        case DATA_END:
          if ((link != Legacy_Link) || (cur_format == LEGACY))  // Filter Beta formats from Legacy link
            PH_DATA_indication(PH_DATA_END, 0, 0, 0);
          // Test for fly-by possibility for Legacy link requests, remembering not to attempt fly-by
          // if the link is currently being filtered from reception of a BETA format packet 
          fly_by_OK = (cur_format == LEGACY) && fly_by_permitted();
          if (fly_by_OK) {
            grant_to_give = (breq == ISOCH_REQ ? GRANT_ISOCH : GRANT);
            stop_tx_packet(grant_to_give, NPORT); 
          } else {
            if (ack && (receive_port != senior_port))
              rx_arb_state = GRANT;  // ACK packet from a junior port can always be
                                     // converted to an explicit asynchronous grant
            if ((rx_arb_state == GRANT) || (rx_arb_state == GRANT_ISOCH) ||      // explicit grants
                ((rx_arb_state == DATA_END) && (receive_port != senior_port)))   // implicit grant
              boss_end_packet_actions(receive_port == senior_port, rx_arb_state);
            else // not BOSS, repeat end of packet normally
              stop_tx_packet(DATA_END, NPORT);
          }
          break;
        case BUS_RESET:
          PH_DATA_indication(PH_DATA_END, 0, 0, 0);
          stop_tx_packet(BUS_RESET, NPORT);
          break;
        case IDLE:               // DP directly to IDLE from a Legacy PHY
        case ARB_CONTEXT:
          if ((link != Legacy_Link) || (cur_format == LEGACY))  // Filter Beta formats from Legacy link
            PH_DATA_indication(PH_DATA_END, 0, 0, 0); // clean up for the link
          if (non_null_packet) {  // Unexpected end of data...
            non_null_packet = FALSE;          // With unexpected end of data, don't add dribble bits
            stop_tx_packet(DATA_END, NPORT);  // and try to clean up gracefully
          } else if (format_committed)             // Already in packet context?
            stop_tx_packet(ARB_CONTEXT, NPORT);    // If so, set arb context before heading to IDLE
          else
            stop_tx_packet(IDLE, NPORT);
          ack = FALSE;                  // Disable fly-by acceleration
          break;
        default:                        // Unexpected end of data...
          if ((link != Legacy_Link) || (cur_format == LEGACY))  // Filter Beta formats from Legacy link
            PH_DATA_indication(PH_DATA_END, 0, 0, 0); // clean up for the link
          non_null_packet = FALSE;          // With unexpected end of data, don't add dribble bits
          stop_tx_packet(DATA_END, NPORT);  // and try to clean up gracefully
          ack = FALSE;                  // Disable fly-by acceleration
          return;
      }
    }
    { // requirement is to ensure that enough time is allowed for at least
      // one symbol to be transmitted on every port
      // (critical issue is DN on a slower port)
      // but early exit if the next packet is already being received
      if (!B_bus) {
        speedCode slowest_port_speed = cur_speed;
        for (i = 0; i < NPORT; i++) {
          if (active[i] && Beta_mode[i])
            if (port_speed[i] < slowest_port_speed)
              slowest_port_speed = port_speed[i];
        }
        // wait long enough to send one more character at the slowest port speed
        // check for data_coming once per character at the fastest speed
        for (i = 0; i<(1<<(PHY_SPEED - slowest_port_speed)); i++) {
          if (concatenated_packet || (end_of_data && data_coming()))
            break;
          wait_symbol_time(PHY_SPEED);
        }
      }
    }
  join
  if ((byte_count == 8)&&(rx_phy_pkt.dataQuadlet == ~rx_phy_pkt.checkQuadlet))
      // Check PHY packet for good format
    decode_phy_packet(rx_phy_pkt);      // Parse valid phy packets
  else HR_mode = LTP_TEST;              // for all non-PHY packets
}
