/* -*-	Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */

/* By Pablo Martin and Paula Ballester,
 * Strathclyde University, Glasgow.
 * June, 2003.
*/

/* Copyright (c) 2003 Strathclyde University of Glasgow, Scotland.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code and binary code must contain
 * the above copyright notice, this list of conditions and the following
 * disclaimer.
 *
 * 2. All advertising materials mentioning features or use of this software
 * must display the following acknowledgement:
 * This product includes software developed at Strathclyde University of
 * Glasgow, Scotland.
 *
 * 3. The name of the University may not be used to endorse or promote
 * products derived from this software without specific prior written
 * permission.
 * STRATHCLYDE UNIVERSITY OF GLASGOW, MAKES NO REPRESENTATIONS
 * CONCERNING EITHER THE MERCHANTABILITY OF THIS SOFTWARE OR THE
 * SUITABILITY OF THIS SOFTWARE FOR ANY PARTICULAR PURPOSE.  The software
 * is provided "as is" without express or implied warranty of any kind.
*/

#ifndef ns_phy_umts_h
#define ns_phy_umts_h

#include "marshall.h"
#include <delay.h>
#include <connector.h>
#include <packet.h>
#include <random.h>
#include <arp.h>
#include <mac.h>
#include <phy.h>
#include <phy-timers.h>
#include "mac-umts.h"

#define UMTS_FrameTime		0.010			// 10 ms
#define UMTS_TBLength		2560			// 2560 chips
#define UMTS_SlotTime		0.0006666667	// 0.667 ms
#define CHIP_RATE			3840000		// 3.84 Mcps
#define Pn				6.1e-14		// Noise Power (Thermal and Equipment)
								// Nrf*ChipRate
								// Nrf = k*T + NF (NF aprox 6dB)
#define BROADCAST	-1
#define PHY_BROADCAST -2

#define MAX_NUM_FREQ 12  //maximum number of frequencies permissiblein the cell
#define MAX_NUM_UE 50    //maximum number of UE's permissible in the cell
#define MAX_NUM_BS 10    //maximum number of NodeB's permissible in the simulation
#define MAX_NUM_NODES (MAX_NUM_UE * MAX_NUM_BS) // maximum number of Nodes permissible in the simulation
#define SLOTS_PER_FRAME 15 // number of slots in evry WCDMA frame
#define MAX_NUM_DPDCH 6  // maximum number of DPDCH
#define MAX_NUM_SCRAM 16  // maximum number of scrambling codes in a group/cell
#define MAX_NUM_RACH 16  // maximum number of RACH in a group/cell
#define MAX_NUM_SIG 16  // maximum number of signatures
#define MAX_NUM_PREAMBLE 8 // maximum number of preamble tx.
#define MAX_NUM_FLOWS 5 // maximum number of flows.
#define MAX_NUM_BYTES_PER_SLOT 80 // maximum number of bytes per slot.
#define MAX_NUM_BYTES_PER_SLOT_DL 160 // maximum number of bytes per slot in dl.

#define PHY_HDR_SZ 2 // physical header size in bytes.

// To indicate whether the radio's ON or OFF
#define ON                       1
#define OFF                      0

struct dpcch_contr {
	int n_dpdch_;  		// number of DPDCHs multiplexed with DPCCH
  	double dpdch_rate_; 	// rate tx in DPDCHs
};

enum Chan_Coding {
	TURBO,	// Turbo Coding 1/3 rate
	CONV_HALF,	// Convolutional Coding 1/2 rate
	CONV_THIRD	// Convolutional Coding 1/3 rate
};

struct hdr_phy {
	// physical addressing
	int sa_;		// source address
	int da_;		// destination address

	double data_size_;	// user data size

	int first_access_;	// for initial access to a cell

	// codification information
	Chan_Coding c_coding_;	// channel coding
	int scrambling_c_;	// scrambling code
	int sf_;			// spreading factor
	int k_;			// k for the channelisation code
	int f_;			// freq

	// information in the packet
	double rx_power_;		// tx power
	int signature_;		// signature
	int p_scrambling_c_;	// primary scrambling code (only SCH)
	int pi_;			// paging indicator
	int used_rach_;		// rach used
	int ue_sf_;			// SF given to the UE
	int freq_;			// freq given to the UE
	int bofsec_;		// begin of sequence
	int seqno_;			// sequence number
	int eofsec_;		// end of sequence
	int paging_group_;		// for paging procedure
	// Used in the Handover Procedure to inform the new NodeB about the current aplications
	int* flows_[MAX_NUM_FLOWS][3];
		// for broadcast
		int free_resources_[MAX_NUM_SCRAM][MAX_NUM_SIG + 1];   // array with the available ul scrambling codes
									// and signatures
//		int used_dl_scramb_[MAX_NUM_SCRAM - 1];   // array with the used dl secondary scrambling codes
		int rach_[MAX_NUM_RACH];	   // available RACH

	// for DPCCH
	dpcch_contr dpcch_control_;	// control information in DPCCH

	// for DPDCH
	PacketQueue* dpdch_control_; // control information in DPDCH;
	int n_dpdch_;		// number id of DPDCH

	inline int& sa() { return sa_; }
	inline int& da() { return da_; }
	inline double& size() { return data_size_; }
	inline double& rx_power() { return rx_power_; }
	inline int& scrambling_c() { return scrambling_c_; }
	inline int& p_scrambling_c() { return p_scrambling_c_; }
	inline int& sf() { return sf_; }
	inline int& f() { return f_; }
	inline int& freq() { return freq_; }
	inline int& ue_sf() { return ue_sf_; }
	inline int& k() { return k_; }
	inline int& signature() { return signature_; }
	inline int& pi() { return pi_; }
	inline int& used_rach() { return used_rach_; }
	inline dpcch_contr& dpcch_control() { return dpcch_control_; }
	inline Chan_Coding& c_coding() { return c_coding_; }

	// Header access methods
	static int offset_;
	inline static int& offset() { return offset_; }
	inline static hdr_phy* access(const Packet* p) {
		return (hdr_phy*) p->access(offset_);
	}
};

/* ======================================================================
   Frame Formats
   ====================================================================== */

struct wcdma_control {
	int p_scrambling_; // primary scrambling code
  	int signature_; // signature used in the last RACH access
	int scram_tx_;  // scrambling code used in the las RACH access
	int rach_tx_;	// rach used
	int free_res_[MAX_NUM_SCRAM][MAX_NUM_SIG + 1];  // array with the available ul scrambling codes (0 available)
							// and signatures
//	int dl_scramb_[MAX_NUM_SCRAM-1];  // array with the used dl secondary scrambling codes
	int free_rach_[MAX_NUM_RACH];	// available RACHs
};

// flows and their SF and Rates
struct flow_rate {
	int flow_id_; 	// flow id
	int sf_;	// Spreading Factor
	double rate_;	// Rate
};

// definition of bler Table ///////////////////////////////////
class BlerTable {
public:
	BlerTable();
	double getbler(double ebno);

	static double table[2][8];	// 1 row: Eb/No
						// 2 row: BLER
};
///////////////////////////////////

/* Umts Phy layer. */
class PhyUmts : public LinkDelay {

  friend class PreambleTimer;
  friend class UpSlotUmtsTimer;
  friend class RachUpSlotUmtsTimer;
  friend class TxPktUmtsTimer;
  friend class RxPktUmtsTimer;
  friend class BlerTimer;
  friend class CellTimer;

public:

  PhyUmts();

  void recv(Packet *p, Handler *h);

  // Timer handlers
  void PreambleHandler (void);
  void upslotHandler(Event *e);
  void rachupslotHandler(Event *e);
  void recvHandler(Event *e);
  void sendHandler(Event *e);
  void cellHandler(void);
  void blerHandler(Event *e);

  int ue_address_;
  int nodeb_address_;
  nsaddr_t ip_nodeb_;
  nsaddr_t ip_ue_;
  int ue_state_; 		// UE state, 0 OFF, 1 waiting to turn on, 2 ON
  int paging_group_;
  int handover_;			// 1 if is in the handover procedure, else 0
  int dlfreq;				// DownLink frequence
  int ulfreq;				// UpLink frequence

  Phy *netif_;            // network interface

  inline double& tti() { return tti_;}
  double bytes_slot;

 protected:

  LL* ll_;		// ll
  Mac* mac_;

  NsObject* downtarget_;		// for outgoing packet
  NsObject* uptarget_;		// for incoming packet

  PacketQueue* prach_temp_; //temporary storage for a PRACH pkt while waiting for AICH

  int num_preambles_;   // number of RACH tx. retries
  int wait_;		// wait to tx the next preamble

  // user defined variables
  static int max_num_freq_;    // num of frequencies to be permitted inthe cell

  wcdma_control w_control;	// control parameters for wcdma coding
  int listen_sccpch_;		// for detecting if a paging procedure has started
  int listen_sch_; 		// for cell selection (handover & initial access)
  int selected_sc_;			// primary scrambling code selected
  int selected_p_;			// physical address of new NodeB selected

  // for monitoring the transmission/reception power
  int tx_power_;		// power to tx
  double rx_power_;	// power in rx
  double threshold_;	// for power reception (for set-up and handover procedure)

  double power_sch_;

  dpcch_contr d_control;	// control parameters for DPDCH multiplexing

  static int verbose_;   // to include a verbose output ..

  PacketQueue* pkttoTx_;	// packets to tx in the current slot
  PacketQueue* rachtoTx_; 	// rach to tx
  Packet * rach_recv_;		// packet rach received from RRC
  PacketQueue* data_temp_;	// packet received in the current tti from MAC
  Packet * rx_dpdch[MAX_NUM_DPDCH];	  // dpdch packets in a slot

  double tti_;
  int tx_rate;
  int d_sc_;			// ul scrambling code used in dedicated channels during a frame
  flow_rate flow_rates_[MAX_NUM_FLOWS];  	// flows and their sf's and rates

  // Interference Model
  unsigned long dl_ErrorRate;		// 1 / BLER per frequence
  double lastRate;			// last rate arrived
  double Prx;				// Power received from NodeB
  double Ioth;				// Interference power receceived from other NodeB
  int noIoth;				// Number of samples of Ioth
  BlerTable* BTable;

  Event intr_;
  Event intr1_; //
  Event intr; //
  Event intrb;

  int up_slot_;
  int count;			// counter for multiplexing
  int in_seq_;			// counter for decoding
  int hin_seq_;			// counter for decoding during handover procedure
  int hnodeb_;			// last nodeb before handover

 private:
  int command(int argc, const char*const* argv);

  void radioSwitch(int i);

  // Packet Transmission Functions.

//  int detect_sc(int scode);
  void recv_from_phy(Packet* p, Handler *h);
  void tx_preamble(void);
  void c_coding(Packet* p);
  void c_decoding(Packet* p);
  void ul_mux(Packet* p);
  void dl_demux(Packet* p);
  void mk_dpxch(void);
  void decode(void);
  void send_msg(Packet* p, int scram_c, int sf, int k);
  void mk_msg_rach(void);
  void mk_msg_rach(Packet* p);
  void send_to_rrc(Packet* p);
  int scrambling_allot(void);
  int n_rx_dpdch(void);
  void tx_to_nodeb(Packet* p);
  void cell_selection(Packet* p);

  // to calculate tx time for a packet
  double TX_Time(Packet *p);

  static double start_time_; // The start time for whole WCDMA scheduling.
  static double slot_time_;  // The duration of each WCDMA slot
  static double rach_slot_time_;  // The duration of each RACH slot

  // indicates whether the radio is active or not. Each MS has a seperate radio
  int radio_active_;

  int error_rate_;			// Error rate = 1/BLER

  // Timers
  PreambleTimer pPreamble_;
  UpSlotUmtsTimer pUpSlot_;
  RachUpSlotUmtsTimer pRachUpSlot_;
  TxPktUmtsTimer pTxPkt_;
  RxPktUmtsTimer pRxPkt_;
  CellTimer pCell_;
  BlerTimer pBler_;

  NsObject*	logtarget_;
};

#endif /* __phy_Umts_h__ */
