//dsport_rx.c

#define unsubscripted

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

tpSig old_data, old_strobe;             // Memory of last signal received
byte current_byte;
int current_bit;
boolean pkt;                            // when true, port is receiving a packet
boolean found_clock;                    // shared signal to detect loss of recovered clock

// Decode data-strobe stream and load FIFO -- this routine is always running
// (speed code recording is also done here)

void decode_bit() {
  RX_signal new_signal;
  tpSig new_data, new_strobe;
  portSymbol last;
  portSymbol symbol;
  boolean bias_on;
  boolean OK_to_report_speed;
  boolean pkt_prefix;                   // when true, port is receiving packet prefix
  while (power_reset || !dsport_on) {
    last.tag = DS_RAW_ARB;
    last.rx_dsarb = RX_IDLE;
    last.speed = S100;
    bias_on = FALSE;
    OK_to_report_speed = TRUE;
    if (power_reset) fifo_wr_ptr = 0;
    pkt_prefix = FALSE;
  }
  if (bias) {
    bias_on = TRUE;
    if (ds_portRspeed > S100) {         // Look for speed signal received
      if (OK_to_report_speed) {
        last.tag = symbol.tag=ARB_STATE;
        last.arb = symbol.arb=SPEED; 
        last.speed = symbol.speed=ds_portRspeed;
        symbol.pkt=LEGACY;
        push(symbol);
        OK_to_report_speed = FALSE;     // avoid multiple reports of this speed
      }
    } else OK_to_report_speed = TRUE;   // when the speed detection has gone back to S100 levels
    new_signal = PMD_DSPORT_SIGNAL_request();              // Get signal
    if (pkt || pkt_prefix) { // expecting data, process data and strobe receivers
      new_data = new_signal.data.TpA; // Received data is on TPA
      new_strobe = new_signal.data.TpB; // Received strobe is on TPB
      if ((new_strobe != old_strobe) || (new_data != old_data)) {
        // Either data or strobe changed
        pkt_prefix = FALSE;  // found a recoverd clock edge, so prefix has ended
        pkt = TRUE;          // and data has nominally begun
        found_clock = TRUE;  // tell stopped clock detector that an edge was found
        if (current_bit == 8) {       // if already got a byte then it can't be a byte of dribble bits, so
          last.tag = symbol.tag = DATA;
          symbol.data=current_byte;
          push(symbol);               // Advance or wrap FIFO pointer
          current_bit = 0;
          current_byte = 0;
        }
        current_byte |= ((new_data == H)?1:0 << (7-current_bit++));
      }
      old_strobe = new_strobe;
      old_data = new_data;
    } else { 
      // not expecting data, process arb comparators
      // Note : While the local port is transmitting serial data, the arbitration
      // comparators are presumed to be disabled or ignored to prevent false queuing of
      // data patterns as received arbitration indications.  While not explicitly
      // described in the C code, such operation is presumed by this implementation.
      switch (new_signal.RX_arb) {
        case RX_DATA_PREFIX:
          // Note: Short periods of RX_DATA_PREFIX normally occur during tree-ID
          // (while in T1:Child_Handshake waiting for the peer port to transition to
          // the S0:Self_ID_Start state) and at the end of packet transmission when
          // the outbound TX_DATA_END is interpreted as an inbound RX_DATA_PREFIX.
          // Implementations are encouraged to implement filtering designed to
          // remove such false indications.  The method of such filtering is
          // beyond the scope of this C code but its presence is presumed by this
          // code to prevent the false arming of the clock extraction logic and to
          // prevent the false reporting of RX_DATA_PREFIX to process_requests()
          pkt_prefix = TRUE;  // Possible start of packet, enable recovered clock
          last.tag = symbol.tag = DS_RAW_ARB;
          last.rx_dsarb = symbol.rx_dsarb = RX_DATA_PREFIX;
          push(symbol);
          old_data = 1;
          old_strobe = 0;
          current_bit = 0;
          current_byte = 0;
          break;
        case RX_DATA_END:						// aka RX_PARENT_HANDSHAKE
        case RX_IDENT_DONE: 
        case RX_IDLE: 
        case RX_BUS_RESET:
        case RX_REQUEST:						// aka RX_SELF_ID_GRANT
        case RX_GRANT:							// aka RX_ROOT_CONTENTION, aka RX_SUSPEND
        case RX_PARENT_NOTIFY:			// aka RX_REQUEST_CANCEL
        case RX_CHILD_HANDSHAKE:		// aka RX_DISABLE_NOTIFY
          if (!((last.tag == DS_RAW_ARB) && (last.rx_dsarb == new_signal.RX_arb))) {
            last.tag = symbol.tag = DS_RAW_ARB;
            last.rx_dsarb = symbol.rx_dsarb = new_signal.RX_arb;
            push(symbol);
          }
          break;
      }
    }
  } else {  // no bias
    if (bias_on) {                      // detect falling edge of bias 
      last.tag = symbol.tag = DS_RAW_ARB;
      last.rx_dsarb = symbol.rx_dsarb = RX_IDLE;
      push(symbol);                     // ensure that FIFO is not stuck
    }
    bias_on = FALSE;
    OK_to_report_speed = TRUE;
  }
}

// Detect the absence of a recovered clock to determine when receipt of the data
// payload has concluded.  This implementation is informative only as many alternative
// methods for detecting the end of a packet are possible

void stopped_clock_detector() {
	int i;
  if (power_reset || !dsport_on) {
    found_clock = FALSE;
    pkt = FALSE;
  } else if (pkt) {
    found_clock = FALSE;  // clear indication of a recovered clock,
                          // and wait to see if another appears
    for (i = 0; i < (2<<DS_PHY_SPEED); i++) // Wait for 50 MHz clock
      wait_event(PH_DS_BIT_CLOCK);
    if (!found_clock) pkt = FALSE; 
  }
}
