///@brief Main function
///
///This function configures MAC parameters, enables the underlying frameworks, and then loops forever.
int main()
{
	xil_printf("HALFMAC Client v16.1: Software-driven Acknowledgments\r\n");


	//Assign the packet buffers in the PHY
	pktBuf_rx = 1;
	pktBuf_tx_DATA = 2;
	pktBuf_tx_ACK = 3;

	//Initialize the framework
	// This function sets safe defaults for many parameters in the MAC/PHY frameworks
	// Many of these can be changed with other warpmac_ and warpphy_ calls
	//  or by customizing the warpmac.c/warpphy.c source
	warpmac_init();

	//Read Dip Switch value from FPGA board.
	//This value will be used as an index into the routing table for other nodes
	myID = (unsigned short int)warpmac_getMyId();
	warpmac_rightHex(myID);

	//Set the PHY for SISO using just the radio in slot 2
	warpphy_setAntennaMode(TX_ANTMODE_SISO_ANTA, RX_ANTMODE_SISO_ANTA);

	//Set the packet detection thresholds
	warpphy_setEnergyDetThresh(7000);		//Min RSSI (in [0,16368])
	warpphy_setAutoCorrDetParams(90, 0);	//Min auto-correlation (in [0,2047])
	warpphy_setLongCorrThresh(8000);		//Min cross-correlation (in [0,45e3])
	
	//Rx buffer is where the EMAC will DMA Wireless payloads from
	warpmac_setRxBuffers(&rxMacframe, pktBuf_rx);

	//Tx buffer is where the EMAC will DMA Ethernet payloads to
	warpmac_setPHYTxBuffer(pktBuf_tx_DATA);
	warpmac_setEMACRxBuffer(pktBuf_tx_DATA);

	//Connect the various user-level callbacks
	warpmac_setCallback(EVENT_DATAFROMNETWORK, (void *)dataFromNetworkLayer_callback);
	warpmac_setCallback(EVENT_PHYGOODHEADER, (void *)phyRx_goodHeader_callback);
	warpmac_setCallback(EVENT_PHYBADHEADER, (void *)phyRx_badHeader_callback);

	//Set the default center frequency
	warpphy_setChannel(GHZ_2, 4);

	lastRxSeqNum = 0;

	//Enable Ethernet
	warpmac_enableDataFromNetwork();

	while(1)
	{
		//Poll the timer, PHY and user I/O forever; actual processing will happen via callbacks above
		warpmac_pollPeripherals();
	}

	return;
}
void processControl(warpnetControl* controlStruct) {
	unsigned char newMod, newCode;

	newMod = ((controlStruct->modOrderPayload) & 0xF);
	newCode = ((controlStruct->codeRatePayload) & 0xF);

	pktGen_length = (controlStruct->pktGen_length);
	pktGen_period = (controlStruct->pktGen_period);

	txPower = ((controlStruct->txPower) & 0x3F);
	warpphy_setTxPower(txPower);
	
	chan = controlStruct->channel;

	xil_printf("Ctrl struct: mod=%d, code=%d, hdr=%d, pktLen=%d, pktPeriod=%d, chan=%d\n", newMod, newCode, controlStruct->modOrderHeader, pktGen_length, pktGen_period, chan);

	switch(newMod) {
		case 1: pktFullRate = HDR_FULLRATE_BPSK; break;
		case 2:	pktFullRate = HDR_FULLRATE_QPSK; break;
		case 4:	pktFullRate = HDR_FULLRATE_QAM_16; break;
		case 6:	pktFullRate = HDR_FULLRATE_QAM_64; break;
		default: pktFullRate = HDR_FULLRATE_QPSK; break;
	}
	
	switch(newCode) {
		case HDR_CODE_RATE_12: pktCodeRate = HDR_CODE_RATE_12; break;
		case HDR_CODE_RATE_23: pktCodeRate = HDR_CODE_RATE_23; break;
		case HDR_CODE_RATE_34: pktCodeRate = HDR_CODE_RATE_34; break;
		case HDR_CODE_RATE_NONE: pktCodeRate = HDR_CODE_RATE_NONE; break;
		default: pktCodeRate = HDR_CODE_RATE_NONE; break;
	}
	
	switch(controlStruct->modOrderHeader) {
		case 1: warpmac_setBaseRate(BPSK); break;
		case 2:	warpmac_setBaseRate(QPSK); break;
		default: warpmac_setBaseRate(QPSK); break;
	}
	
	warpphy_setChannel(GHZ_2, chan);
}
///@brief Callback for the reception of UART bytes
///@param uartByte ASCII byte received from UART
///
///Provides the user with the bytes that was received over the serial port. This is useful for configuring
///PHY and MAC parameters in real time on a board.
void uartRecv_callback(unsigned char uartByte)
{
	if(uartByte != 0x0)
	{
		xil_printf("(%c)\t", uartByte);
		
		switch(uartByte)
		{
			case ASCII_1:
				pktFullRate = HDR_FULLRATE_BPSK;
				xil_printf("Tx Full Rate = BPSK\r\n");
				break;
				
			case ASCII_2:
				pktFullRate = HDR_FULLRATE_QPSK;
				xil_printf("Tx Full Rate = QPSK\r\n");
				break;
				
			case ASCII_4:
				pktFullRate = HDR_FULLRATE_QAM_16;
				xil_printf("Tx Full Rate = 16-QAM\r\n");
				break;
				
			case ASCII_6:
				pktFullRate = HDR_FULLRATE_QAM_64;
				xil_printf("Tx Full Rate = 64-QAM\r\n");
				break;
				
			case ASCII_7:
				pktCodeRate = HDR_CODE_RATE_12;
				xil_printf("Coding Rate = 1/2\r\n");
				break;
			case ASCII_8:
				pktCodeRate = HDR_CODE_RATE_23;
				xil_printf("Coding Rate = 2/3\r\n");
				break;
			case ASCII_9:
				pktCodeRate = HDR_CODE_RATE_34;
				xil_printf("Coding Rate = 3/4\r\n");
				break;
			case ASCII_0:
				pktCodeRate = HDR_CODE_RATE_NONE;
				xil_printf("Coding Rate = 1 (no coding)\r\n");
				break;
			case ASCII_F:
				if(chan<14) chan++;
				warpphy_setChannel(GHZ_2, chan);
				xil_printf("Current channel: %d\r\n",chan);
				break;
			case ASCII_f:
				if(chan>1) chan--;
				warpphy_setChannel(GHZ_2, chan);
				xil_printf("Current channel: %d\r\n",chan);
				break;

			default:
				xil_printf("Undefined command\r\n");
				break;
		}
	}
	
	return;
}
///@brief Main function
///
///This function configures MAC parameters, enables the underlying frameworks, and then loops forever.
int main(){
	
	//Initialize global variables
	chan = 4;
	
	//Assign the packet buffers in the PHY
	// The auto responder can't transmit from buffer 0, so we use it for Rx packets
	// The other assignments (DATA/ACK) are arbitrary; any buffer in [1,30] will work
	pktBuf_rx = 1;
	pktBuf_tx_DATA = 2;
	
	//Set the full-rate modulation to QPSK by default
//	pktFullRate = HDR_FULLRATE_QPSK;
	pktFullRate = HDR_FULLRATE_QAM_16;
	
	//Set the payload coding rate to 3/4 rate by default
	pktCodeRate = HDR_CODE_RATE_34;
	
	//Initialize the MAC/PHY frameworks
	warpmac_init();
	maximumReSend = 8;
	warpmac_setMaxResend(maximumReSend);
	warpmac_setMaxCW(5);
	warpmac_setTimeout(120);
	warpmac_setSlotTime(22);
	
	//Read Dip Switch value from FPGA board.
	//This value will be used as an index into the routing table for other nodes
	myID = (unsigned short int)warpmac_getMyId();
	warpmac_rightHex(myID);
	
	//Configure the PHY and radios for single antenna (SISO) mode
	warpphy_setAntennaMode(TX_ANTMODE_SISO_ANTA, RX_ANTMODE_SISO_ANTA);
	//warpphy_setAntennaMode(TX_ANTMODE_MULTPLX, RX_ANTMODE_MULTPLX);
	//warpphy_setAntennaMode(TX_ANTMODE_ALAMOUTI_ANTA, RX_ANTMODE_ALAMOUTI_ANTA);
	
	//Set the packet detection thresholds
	warpphy_setEnergyDetThresh(7000);		//Min RSSI (in [0,16368])
	warpphy_setAutoCorrDetParams(90, 0);	//Min auto-correlation (in [0,2047])
	warpphy_setLongCorrThresh(8000);		//Min cross-correlation (in [0,45e3])
	
	//Rx buffer is where the EMAC will DMA Wireless payloads from
	warpmac_setRxBuffers(&rxMacframe, pktBuf_rx);
	
	//Tx buffer is where the EMAC will DMA Ethernet payloads to
	warpmac_setPHYTxBuffer(pktBuf_tx_DATA);
	warpmac_setEMACRxBuffer(pktBuf_tx_DATA);
	
	//Set the modulation scheme use for base rate (header) symbols
	warpmac_setBaseRate(QPSK);
	
	//Copy this node's MAC address into the Tx buffer's source address field
	txMacframe.header.srcAddr = (unsigned short int)(NODEID_TO_ADDR(myID));
	
	//Register callbacks
	warpmac_setCallback(EVENT_TIMER, (void *)timer_callback);
	warpmac_setCallback(EVENT_DATAFROMNETWORK, (void *)dataFromNetworkLayer_callback);
	warpmac_setCallback(EVENT_PHYGOODHEADER, (void *)phyRx_goodHeader_callback);
	warpmac_setCallback(EVENT_PHYBADHEADER, (void *)phyRx_badHeader_callback);
	warpmac_setCallback(EVENT_UARTRX, (void *)uartRecv_callback);
	
	//Set the default center frequency
	warpphy_setChannel(GHZ_2, chan);
	
	//Enable carrier sensing
	warpmac_setCSMA(1);
	
	txSeqNum = 0;
	
	//halfmac_server doesn't send ACKs, so skip autoResponder setup
	
	//Listen for new packets to send (either from Ethernet or local dummy packets)
	warpmac_enableDataFromNetwork();
	
	xil_printf("Reference Design v16.1 HALFMAC SERVER\r\n");
	
	xil_printf("Beginning main loop\r\n");
	
	while(1)
	{
		//Poll the timer, PHY and user I/O forever; actual processing will happen via callbacks above
		warpmac_pollPeripherals();
	}
	
	return 0;
}
///@brief Main function
///
///This function configures MAC parameters, enables the underlying frameworks, and then loops forever.
int main()
{
	xil_printf("HALFMAC Client v16.1: AutoResponder-driven Acknowledgments\r\n");

	//Assign the packet buffers in the PHY
	// The auto responder can't transmit from buffer 0, so we use it for Rx packets
	// The other assignments (DATA/ACK) are arbitrary; any buffer in [1,30] will work
	pktBuf_rx = 1;
	pktBuf_tx_DATA = 2;
	pktBuf_tx_ACK = 3;

	//Initialize the framework
	// This function sets safe defaults for many parameters in the MAC/PHY frameworks
	// Many of these can be changed with other warpmac_ and warpphy_ calls
	//  or by customizing the warpmac.c/warpphy.c source
	warpmac_init();

	//Read Dip Switch value from FPGA board.
	//This value will be used as an index into the routing table for other nodes
	myID = (unsigned short int)warpmac_getMyId();
	warpmac_rightHex(myID);

	//Set the PHY for SISO using just the radio in slot 2
	warpphy_setAntennaMode(TX_ANTMODE_SISO_ANTA, RX_ANTMODE_SISO_ANTA);

	//Set the packet detection thresholds
	warpphy_setEnergyDetThresh(7000);		//Min RSSI (in [0,16368])
	warpphy_setAutoCorrDetParams(90, 0);	//Min auto-correlation (in [0,2047])
	warpphy_setLongCorrThresh(8000);		//Min cross-correlation (in [0,45e3])
	
	//Rx buffer is where the EMAC will DMA Wireless payloads from
	warpmac_setRxBuffers(&rxMacframe, pktBuf_rx);

	//Tx buffer is where the EMAC will DMA Ethernet payloads to
	warpmac_setPHYTxBuffer(pktBuf_tx_DATA);
	warpmac_setEMACRxBuffer(pktBuf_tx_DATA);

	//Connect the various user-level callbacks
	warpmac_setCallback(EVENT_DATAFROMNETWORK, (void *)dataFromNetworkLayer_callback);
	warpmac_setCallback(EVENT_PHYGOODHEADER, (void *)phyRx_goodHeader_callback);
	warpmac_setCallback(EVENT_PHYBADHEADER, (void *)phyRx_badHeader_callback);
	warpmac_setCallback(EVENT_UARTRX, (void *)uartRecv_callback);

	//Set the default center frequency
	warpphy_setChannel(GHZ_2, 4);

	lastRxSeqNum = 0;
	
	Macframe templatePkt;
	

/************************************/
/***** AUTO RESPONDER CONFIG *******/
/************************************/
	//WORKSHOP PSEUDOCODE: Note, autoresponder functions are not currently part of the API. They are
	//documented separately at http://warp.rice.edu/trac/wiki/OFDM/MIMO/Docs/AutoResponse
	//1) Use the PHY_AUTORESPONSE_MATCH_CONFIG macro to make sure that it is only engaged when a 
	//	 received packet's destination address matches 'myID'
	//		NOTE: Addresses are 2-bytes wide and are located at addr PKTHEADER_INDX_DSTADDR
	//2) Use the PHY_AUTORESPONSE_MATCH_CONFIG macro to make sure that it is only engaged when a 
	//	 received packet's type is a DATAPACKET

/**********************USER CODE STARTS HERE***************************/
	//Setup the PHY's autoResponse system
	
	unsigned int autoResp_matchCond;
	
	// For CSMA, it is configured to send pktBuf pktBuf_tx_ACK when a good DATA packet is received addressed to this node
	//Match condition 0: received header's destination address is this node's address
	autoResp_matchCond = PHY_AUTORESPONSE_MATCH_CONFIG(PKTHEADER_INDX_DSTADDR, 2, htons(NODEID_TO_ADDR(myID)));
	mimo_ofdmTxRx_setMatch0(autoResp_matchCond);

	//Match condition 1: received header's type is PKTTYPE_DATA
	autoResp_matchCond = PHY_AUTORESPONSE_MATCH_CONFIG(PKTHEADER_INDX_TYPE, 1, PKTTYPE_DATA);
	mimo_ofdmTxRx_setMatch1(autoResp_matchCond);
/**********************USER CODE ENDS HERE***************************/

	//Configure the header translator to use the Rx pkt's src address as the outgoing pkt's dst address
	// Addresses are two bytes, so two entries in the header translator need to be overridden
	// Except for these bytes, the ACK pktBuf's contents will be sent unaltered
	// PHY_HEADERTRANSLATE_SET(templatePktBuf, byteAddrToOverwrite, srcPktBuf, srcByteAddr)
	PHY_HEADERTRANSLATE_SET(pktBuf_tx_ACK, (PKTHEADER_INDX_DSTADDR+0), pktBuf_rx, (PKTHEADER_INDX_SRCADDR+0));
	PHY_HEADERTRANSLATE_SET(pktBuf_tx_ACK, (PKTHEADER_INDX_DSTADDR+1), pktBuf_rx, (PKTHEADER_INDX_SRCADDR+1));

	//Create a template ACK packet
	templatePkt.header.fullRate = HDR_FULLRATE_QPSK;
	templatePkt.header.codeRate = HDR_CODE_RATE_34;
	templatePkt.header.length = 0;
	templatePkt.header.srcAddr = (unsigned short)(NODEID_TO_ADDR(myID));
	templatePkt.header.pktType = PKTTYPE_ACK;

	//Copy the header down to the PHY's packet buffer
	// This doesn't actually send anything; the autoResponse system will use this template when sending ACKs
	warpmac_prepPhyForXmit(&templatePkt, pktBuf_tx_ACK);

	//Action defitions come last; bad things might happen if an action is enabled (set non-zero) before the template pkt is ready.
	//All actors are disabled during warpphy_init; only load non-zero configurations for actors you intend to use
	autoResp_delay = 0;

	//Action 0: send pkt from buf pktBuf_tx_ACK when match0 & match1 & goodPkt, using header translation
	autoResp_action = PHY_AUTORESPONSE_TXACTION_CONFIG(pktBuf_tx_ACK, PHY_AUTORESPONSE_ACT_TRANS_HDR, autoResp_delay, (PHY_AUTORESPONSE_REQ_MATCH0 | PHY_AUTORESPONSE_REQ_MATCH1 | PHY_AUTORESPONSE_REQ_GOODHDR | PHY_AUTORESPONSE_REQ_GOODPKT));

	//Write the configuration word to the PHY's autoResponder
	mimo_ofdmTxRx_setAction0(autoResp_action);

	//Enable Ethernet
	warpmac_enableDataFromNetwork();

	while(1)
	{
		//Poll the timer, PHY and user I/O forever; actual processing will happen via callbacks above
		warpmac_pollPeripherals();
	}

	return;
}
///@brief Main function
///
///This function configures MAC parameters, enables the underlying frameworks, and then loops forever.
int main()
{
	xil_printf("\fWARPNET Example v18.0\r\n");


	//Assign Tx/Rx to packet buffers in the PHY
	pktBuf_rx = 1;
	pktBuf_tx = 2;
	pktBuf_emac_rx = 3;
	
	//Set the center frequency
	chan = 3;
	
	//Initialize the sequence number for outgoing packets
	seqNum = 0;
	
	//Set the default full-rate modulation rate
	pktFullRate = HDR_FULLRATE_QPSK;
	pktCodeRate = HDR_CODE_RATE_34;
	
	//Initialize the framework
	// This function sets safe defaults for many parameters in the MAC/PHY frameworks
	// Many of these can be changed with other warpmac_ and warpphy_ calls
	//  or by customizing the warpmac.c/warpphy.c source
	warpmac_init();

	//Read Dip Switch value from FPGA board.
	//This value will be used as an index into the routing table for other nodes
	myID = (unsigned short int)warpmac_getMyId();
	warpmac_rightHex(myID);
	
	//Choose the antnenna mode
	warpphy_setAntennaMode(TX_ANTMODE_SISO_ANTA, RX_ANTMODE_SISO_ANTA);
	//warpphy_setAntennaMode(TX_ANTMODE_ALAMOUTI_ANTA, RX_ANTMODE_ALAMOUTI_ANTA);
	//warpphy_setAntennaMode(TX_ANTMODE_MULTPLX, RX_ANTMODE_MULTPLX);

	//Rx buffer is where the EMAC will DMA Wireless payloads from
	warpmac_setRxBuffers(&rxFrame, pktBuf_rx);

	//Tx buffer is where the EMAC will DMA Ethernet payloads to
	warpmac_setEMACRxBuffer(pktBuf_emac_rx);
	warpmac_setPHYTxBuffer(pktBuf_tx);

	//Connect the various user-level callbacks
	warpmac_setCallback(EVENT_DATAFROMNETWORK, (void *)dataFromNetworkLayer_callback);
	warpmac_setCallback(EVENT_MGMTPKT, (void *)mgmtFromNetworkLayer_callback);
	warpmac_setCallback(EVENT_PHYGOODHEADER, (void *)phyRx_goodHeader_callback);
	warpmac_setCallback(EVENT_PHYBADHEADER, (void *)phyRx_badHeader_callback);

#ifdef WARP_HW_VER_v3
	//Set the OFDM Rx detection thresholds
	warpphy_setCarrierSenseThresh(4000); //Carrier sense thresh (in [0,16368])
	warpphy_setEnergyDetThresh(6500);		//Min RSSI (in [0,16368])
	warpphy_setAutoCorrDetParams(50, 20);	//Min auto-correlation (UFix8_7) and min energy (UFix16_8)
	warpphy_setLongCorrThresh(10000);		//Min cross-correlation (in [0,45e3])

	//Set the default Tx gain (in [0,63])
	warpphy_setTxPower(50);
#else
	//Set the OFDM Rx detection thresholds (copied from OFDM ref des v17 for now)
	warpphy_setCarrierSenseThresh(12000); //Carrier sense thresh (in [0,16368])
	warpphy_setEnergyDetThresh(7000);		//Min RSSI (in [0,16368])
	warpphy_setAutoCorrDetParams(90, 20);	//Min auto-correlation (UFix8_7) and min energy (UFix16_8)
	warpphy_setLongCorrThresh(8000);		//Min cross-correlation (in [0,45e3])

	//Set the default Tx gain (in [0,63])
	warpphy_setTxPower(55);
#endif

	//Set the default center frequency
	warpphy_setChannel(GHZ_2, 11);

	//Enable dummy packet mode; data packets will only be generated locally
	warpmac_setDummyPacketMode(1);

	//Set safe default dummy packet length/intervals; WARPnet will override these per-experiment
	pktGen_length = 1412;
	pktGen_period = 10000;

	//Enable the OFDM Tx random payload generator (so locally generated packets have some non-zero payloads)
	mimo_ofdmTx_setControlBits(mimo_ofdmTx_getOptions() | (TX_RANDOM_PAYLOAD | TX_CAPTURE_RANDOM_PAYLOAD));

	//Listen for new packets to send (either from Ethernet or local dummy packets)
	warpmac_enableDataFromNetwork();
	
	/*** WARPnet Measurement/Control Setup ***/
	//Fill in the server/group struct with sane defaults
	groupStruct.controllerID = 0;
	groupStruct.controllerGrp = 0;
	groupStruct.access = 1;
	groupStruct.reserved0 = 0;
	
	perStruct.structID = STRUCTID_OBSERVE_PER;
	perStruct.nodeID = myID;
	perStruct.reqNum = 0;
	perStruct.reqType = 0;
	perStruct.numPkts_tx = 0;
	perStruct.numPkts_rx_good = 0;
	perStruct.numPkts_rx_goodHdrBadPyld = 0;
	perStruct.numPkts_rx_badHdr = 0;
	
	//Disable reporting of packets for BER testing (WARPnet may enable at runtime)
	reportBERviaWarpnet = 0;

	//Fill in the Ethernet packet header templates
	txEthPktHeader.ethType = WARPNET_ETHTYPE_NODE2SVR;
	txEthPktHeader.srcAddr[0]=0x00;
	txEthPktHeader.srcAddr[1]=0x50;
	txEthPktHeader.srcAddr[2]=0xC2;
	txEthPktHeader.srcAddr[3]=0x63;
	txEthPktHeader.srcAddr[4]=0x3F;
	txEthPktHeader.srcAddr[5]=0x80+myID;
	
	/****************************** NOTE ********************************/
	/* You should fill in the MAC address of your WARPnet server here! */
	/*******************************************************************/
	txEthPktHeader.dstAddr[0]=0xff;
	txEthPktHeader.dstAddr[1]=0xff;
	txEthPktHeader.dstAddr[2]=0xff;
	txEthPktHeader.dstAddr[3]=0xff;
	txEthPktHeader.dstAddr[4]=0xff;
	txEthPktHeader.dstAddr[5]=0xff;
	txEthPktHeader.numStructs = 1;

	coprocEthPktHeader.ethType = WARPNET_ETHTYPE_NODE2BER;
	coprocEthPktHeader.srcAddr[0]=0x00;
	coprocEthPktHeader.srcAddr[1]=0x50;
	coprocEthPktHeader.srcAddr[2]=0xC2;
	coprocEthPktHeader.srcAddr[3]=0x63;
	coprocEthPktHeader.srcAddr[4]=0x3F;
	coprocEthPktHeader.srcAddr[5]=0x80+myID;

	/****************************** NOTE ********************************/
	/* You should fill in the MAC address of your WARPnet server here! */
	/*******************************************************************/
	coprocEthPktHeader.dstAddr[0]=0xff;
	coprocEthPktHeader.dstAddr[1]=0xff;
	coprocEthPktHeader.dstAddr[2]=0xff;
	coprocEthPktHeader.dstAddr[3]=0xff;
	coprocEthPktHeader.dstAddr[4]=0xff;
	coprocEthPktHeader.dstAddr[5]=0xff;
	coprocEthPktHeader.numStructs = 1;
	
	while(1)
	{
		//Poll the timer, PHY and user I/O forever; actual processing will happen via callbacks above
		warpmac_pollPeripherals();
	}

	return 0;
}