module chan_fifo_reader 
   (reset, tx_clock, tx_strobe, adc_time, samples_format,
    fifodata, pkt_waiting, rdreq, skip, tx_q, tx_i,
    underrun, tx_empty, debug, rssi, threshhold, rssi_wait) ;

   input   wire                     reset ;
   input   wire                     tx_clock ;
   input   wire                     tx_strobe ; //signal to output tx_i and tx_q
   input   wire              [31:0] adc_time ; //current time
   input   wire               [3:0] samples_format ;// not useful at this point
   input   wire              [31:0] fifodata ; //the data input
   input   wire                     pkt_waiting ; //signal the next packet is ready
   output  reg                      rdreq ; //actually an ack to the current fifodata
   output  reg                      skip ; //finish reading current packet
   output  reg               [15:0] tx_q ; //top 16 bit output of fifodata
   output  reg               [15:0] tx_i ; //bottom 16 bit output of fifodata
   output  reg                      underrun ; 
   output  reg                      tx_empty ; //cause 0 to be the output
   input   wire		     [31:0] rssi;
   input   wire		     [31:0] threshhold;
   input   wire		     [31:0] rssi_wait;

   output wire [14:0] debug;
   
   // Should not be needed if adc clock rate < tx clock rate
   // Used only to debug
   `define JITTER                   5
    
   //Samples format
   // 16 bits interleaved complex samples
   `define QI16                     4'b0
    
   // States
   parameter IDLE           =     3'd0;    
   parameter HEADER         =     3'd1;
   parameter TIMESTAMP      =     3'd2;
   parameter WAIT           =     3'd3;
   parameter WAITSTROBE     =     3'd4;
   parameter SEND           =     3'd5;

   // Header format
   `define PAYLOAD                  8:2
   `define ENDOFBURST               27
   `define STARTOFBURST             28
   `define RSSI_FLAG                26
	

   /* State registers */
   reg                        [2:0] reader_state;
   /* Local registers */  
   reg                        [6:0] payload_len;
   reg                        [6:0] read_len;
   reg                       [31:0] timestamp;
   reg                              burst;
   reg                              trash;
   reg                              rssi_flag;
   reg			     [31:0] time_wait;
   
   assign debug = {7'd0, rdreq, skip, reader_state, pkt_waiting, tx_strobe, tx_clock};
   always @(posedge tx_clock)
     begin
       if (reset) 
         begin
           reader_state <= IDLE;
           rdreq <= 0;
           skip <= 0;
           underrun <= 0;
           burst <= 0;
           tx_empty <= 1;
           tx_q <= 0;
           tx_i <= 0;
           trash <= 0;
           rssi_flag <= 0;
           time_wait <= 0;
         end
       else 
         begin
           case (reader_state)
             IDLE:
               begin
               /*
		* reset all the variables and wait for a tx_strobe
		* it is assumed that the ram connected to this fifo_reader 
		* is a short hand fifo meaning that the header to the next packet
		* is already available to this fifo_reader when pkt_waiting is on
		*/
                 skip <=0;
                 time_wait <= 0;
                 if (pkt_waiting == 1)
                   begin
                     reader_state <= HEADER;
                     rdreq <= 1;
                     underrun <= 0;
                   end
                 if (burst == 1 && pkt_waiting == 0)
                     underrun <= 1;
                 if (tx_strobe == 1)
                     tx_empty <= 1 ;
               end

               /* Process header */
               HEADER:
                 begin
                   if (tx_strobe == 1)
                       tx_empty <= 1 ;
                   
                   rssi_flag <= fifodata[`RSSI_FLAG]&fifodata[`STARTOFBURST];
                   //Check Start/End burst flag
                   if  (fifodata[`STARTOFBURST] == 1 
                       && fifodata[`ENDOFBURST] == 1)
                       burst <= 0;
                   else if (fifodata[`STARTOFBURST] == 1)
                       burst <= 1;
                   else if (fifodata[`ENDOFBURST] == 1)
                       burst <= 0;

                   if (trash == 1 && fifodata[`STARTOFBURST] == 0)
                     begin
                       skip <= 1;
                       reader_state <= IDLE;
                       rdreq <= 0;
                     end 
                   else
                     begin   
                       payload_len <= fifodata[`PAYLOAD] ;
                       read_len <= 0;
                       rdreq <= 1;
                       reader_state <= TIMESTAMP;
                     end
                 end

               TIMESTAMP: 
                 begin
                   timestamp <= fifodata;
                   reader_state <= WAIT;
                   if (tx_strobe == 1)
                       tx_empty <= 1 ;
                   rdreq <= 0;
                 end
				
               // Decide if we wait, send or discard samples
               WAIT: 
                 begin
                   if (tx_strobe == 1)
                       tx_empty <= 1 ;
                    
                   time_wait <= time_wait + 32'd1;
                   // Outdated
                   if ((timestamp < adc_time) ||
                      (time_wait >= rssi_wait && rssi_wait != 0 && rssi_flag))
                     begin
                       trash <= 1;
                       reader_state <= IDLE;
                       skip <= 1;
                     end  
                   // Let's send it					
                   else if ((timestamp <= adc_time + `JITTER 
                             && timestamp > adc_time)
                             || timestamp == 32'hFFFFFFFF)
                     begin
                       if (rssi <= threshhold || rssi_flag == 0)
                         begin
                           trash <= 0;
                           reader_state <= WAITSTROBE; 
                         end
                       else
                         reader_state <= WAIT;
                     end
                   else
                       reader_state <= WAIT;
                 end
                 
               // Wait for the transmit chain to be ready
               WAITSTROBE:
                 begin
                   // If end of payload...
                   if (read_len == payload_len)
                     begin
                       reader_state <= IDLE;
                       skip <= 1;
                       if (tx_strobe == 1)
                           tx_empty <= 1 ;
                     end  
                   else if (tx_strobe == 1)
                     begin
                       reader_state <= SEND;
                       rdreq <= 1;
                     end
                 end
               
               // Send the samples to the tx_chain
               SEND:
                 begin
                   reader_state <= WAITSTROBE; 
                   read_len <= read_len + 7'd1;
                   tx_empty <= 0;
                   rdreq <= 0;
                   
                   case(samples_format)
                       `QI16:
                        begin
                            tx_i <= fifodata[15:0];
                            tx_q <= fifodata[31:16];
                        end
                        
                        // Assume 16 bits complex samples by default
                        default:
                        begin
                            tx_i <= fifodata[15:0];
                            tx_q <= fifodata[31:16];
                        end 
                   endcase
                 end
               
               default:
                 begin
                   //error handling
                   reader_state <= IDLE;
                 end
           endcase
       end
   end
 
endmodule
