WARP Project Forums - Wireless Open-Access Research Platform

You are not logged in.

#1 2015-Apr-13 11:28:14

juvebogdan
Member
Registered: 2013-Sep-17
Posts: 76

OFDM reference design custom appplication

I'm trying to make two boards to communicate in a following way using OFDM reference design: prior to every packet transmission transmitter sends request packet that contains information on what channel data packet should be sent. Receiver responds with grant if that channel is idle and then data is sent followed with an ack packet. I wrote this program and it is very straightforward but it doesn't work. I cant figure out what is wrong with my program. Here are the key parts of my code:

Code:

void dataFromNetworkLayer_callback(Xuint32 length, char* payload){
	unsigned char destNode;
	//Disable further Ethernet packets
	warpmac_disableDataFromNetwork();

	//Update the Tx packet header with this packet's values
	txMacframe.header.length = length;
	txMacframe.header.pktType = PKTTYPE_DATA;
        txMacframe.header.fullRate = pktFullRate;

	//Set the code rate for the packet's payload
	txMacframe.header.codeRate = pktCodeRate;
	destNode = 3;

	//Copy in the packet's destination MAC address
	txMacframe.header.destAddr = (unsigned short int)(NODEID_TO_ADDR(destNode));
	//Send request packet
	        txRequest.header.length = 0;// no payload
		txRequest.header.pktType = PKTTYPE_REQ;

		//Use BPSK
		txRequest.header.fullRate = HDR_FULLRATE_BPSK;

		//Set the code rate for the packet's payload
		txRequest.header.codeRate = pktCodeRate;

		//Copy in the packet's destination MAC address
		txRequest.header.destAddr = (unsigned short int)(NODEID_TO_ADDR(destNode));



			index = rand() % 2;// randomly select 0 or 1 which are indexes of array that contains available channels.This array is channels = {1,7}

			chan = channels[index];
			chan=1;


		//Set the remaining Tx counter to the maximum number of transmissions
		txRequest.header.remainingTx = 2;//Two because if one channels fails try another and drop packet if that one fails
		txRequest.header.channelID = chan; //Information about channel to be used for data

		warpphy_setChannel(GHZ_2,14);//  Use channel 14 for request-grant

		warpmac_prepPhyForXmit(&txRequest, pktBuf_tx_Request);

				//Transmit the packet
		warpmac_startPhyXmit(pktBuf_tx_Request);
		warpmac_leftHex(0xF & (14));

		//Wait for it to finish
		warpmac_finishPhyXmit();

		//Start a timeout timer and wait for grant
		warpmac_setTimer(TIMEOUT_TIMER);
		warpmac_decrementRemainingReSend(&txRequest);

	return;
}

int phyRx_goodHeader_callback(Macframe* packet){

	unsigned char state = PHYRXSTATUS_INCOMPLETE;
	unsigned char srcNode;
	unsigned char shouldSend = 0;
	unsigned char channel_state;

	if(debug_goodHdrPrint) {
		xil_printf("GH: RSSI=%4d\tAGC=%d/%2d\r\n",
			ofdm_txrx_mimo_ReadReg_Rx_PktDet_midPktRSSI_antA(),
			OFDM_AGC_MIMO_ReadReg_GRF_A(0),
			OFDM_AGC_MIMO_ReadReg_GBB_A(0));
	}
		
	//Calculate the node ID from the packet's source MAC address
	srcNode = ADDR_TO_NODEID( (packet->header.srcAddr) );

	//If the packet is addressed to this node
	if( packet->header.destAddr == (NODEID_TO_ADDR(myID)) ) {
		switch(packet->header.pktType){
				case PKTTYPE_GRT:
						if(warpmac_inTimeout()){  
							//grant is received, extract channel information and send data
								warpmac_clearTimer(TIMEOUT_TIMER);
								chan = packet->header.channelID; //get the channel for data transmission
								warpphy_setChannel(GHZ_2,chan);
                                                                ////send data
                                                                                                warpmac_prepPhyForXmit(&txMacframe, pktBuf_tx_DATA);

												//Transmit the packet
												warpmac_startPhyXmit(pktBuf_tx_DATA);
												warpmac_leftHex(0xF & (chan));

												//Wait for it to finish
												warpmac_finishPhyXmit();

												warpmac_setTimer(TIMEOUT_TIMER); //wait for ack on the same channel
												warpmac_decrementRemainingReSend(&txRequest);
						}
						break;
				case PKTTYPE_ACK:
						if(warpmac_inTimeout()){ 
							warpmac_incrementLEDHigh();
							warpmac_clearTimer(TIMEOUT_TIMER);
							warpmac_enableDataFromNetwork();
						}
						else
						{
							retransmit_request(); //If ack doesn't come try with second channel; This function sends request again. If it is send twice already it just goes to channel 14 again and warpmac_enableDataFromNetwork();
						}
						break;
                              case PKTTYPE_REQ:
						   chan = packet->header.channelID;
						   warpphy_setChannel(GHZ_2,chan);
						   channel_state = warpmac_carrierSense();
						   if (channel_state)
						   {
							   //if the channel is idle send grant
							   unsigned char destNode;

		txGrant.header.length = 0;// no payload
		txGrant.header.pktType = PKTTYPE_GRT;

		//Set the modulation scheme for the packet's full-rate symbols
		txGrant.header.fullRate = HDR_FULLRATE_BPSK;

		//Set the code rate for the packet's payload
		txGrant.header.codeRate = pktCodeRate;
		destNode = 1;

		//Copy in the packet's destination MAC address
		txGrant.header.destAddr = (unsigned short int)(NODEID_TO_ADDR(destNode));

		txGrant.header.channelID = chan;

		warpphy_setChannel(GHZ_2,14); //use channel 14 for grant

		warpmac_prepPhyForXmit(&txGrant, pktBuf_tx_Grant);

				//Transmit the packet
		warpmac_startPhyXmit(pktBuf_tx_Grant);

		//Wait for it to finish
		warpmac_finishPhyXmit();

		//After sending grant go to the data channel that was specified in request packet and wait for data
		warpphy_setChannel(GHZ_2,chan);
		warpmac_setTimer(TIMEOUT_TIMER_RX); //Start receive timeout
						   }
						   else
						   {
                                                           //channel is not idle, go back to channel 14
							   warpphy_setChannel(GHZ_2,14);
						   }
						break;
				case PKTTYPE_DATA:
						if(warpmac_inTimeoutRX()){//Receive tiemout
											warpmac_clearTimer(TIMEOUT_TIMER_RX);
											state = warpmac_finishPhyRecv();

											if(state & PHYRXSTATUS_GOOD){
												//Toggle the top LEDs
												warpmac_incrementLEDHigh();


												//Starts the DMA transfer of the payload into the EMAC
				 warpmac_prepPktToNetwork((void*)warpphy_getBuffAddr(pktBuf_rx)+NUM_HEADER_BYTES, (packet->header.length));

												//Blocks until the PHY is finished sending and enables the receiver
												warpmac_finishPhyXmit();

												//Waits until the DMA transfer is complete, then starts the EMAC
                                                                                                 warpmac_startPktToNetwork((packet->header.length));

												//Send ack on the same channel
                                                                                              unsigned char destNode;


			                                                                   txACK.header.length = 0;// nema payload-a, handshake paket
			                                                                   txACK.header.pktType = PKTTYPE_ACK;

			                                                                   //Set the modulation scheme for the packet's full-rate symbols
			                                                                   txACK.header.fullRate = HDR_FULLRATE_BPSK;

			                                                                    //Set the code rate for the packet's payload
			                                                                       txACK.header.codeRate = pktCodeRate;

			                                                                 
			                                                                 destNode = 1;

			                                                                //Copy in the packet's destination MAC address
			                                                               txACK.header.destAddr = (unsigned short int)(NODEID_TO_ADDR(destNode));


			                                                                warpmac_prepPhyForXmit(&txACK, pktBuf_tx_ACK);

					                                                  //Transmit the packet
			                                                                  warpmac_startPhyXmit(pktBuf_tx_ACK);
			                                                                 warpmac_leftHex(0xF & (chan));

			                                                                //Wait for it to finish
			                                                                 warpmac_finishPhyXmit();

			                                                                  //after sending ack go back to channel 14 and wait for request or send request
			                                                               warpphy_setChannel(GHZ_2,14);
											}
											else
											{
												//also go back to channel 14 if the packet is not good
												warpphy_setChannel(GHZ_2,14);
											}

											if(state & PHYRXSTATUS_BAD) {
												warpmac_incrementLEDLow();
											}

						}
						else
						{

						}
						break;
		}
	}
	else {
		state = warpmac_finishPhyRecv();
	}
	//Return 0, indicating we didn't clear the PHY status bits (WARPMAC will handle it)
	return 0;
} 

void timer_callback(unsigned char timerType) {

	switch(timerType) {
		case TIMEOUT_TIMER:
			  //this timeout expires in situations when grant is not received or ack is not received after data is sent. On expiration try another channel or drop packet
				retransmit_request();
			break;
               case TIMEOUT_TIMER_RX:
                        //This timeout expires after the grant is sent and data does not come. In that case just go back to channel 14
			warpphy_setChannel(GHZ_2,14);
			break;
	}
}

As you can see it is straightforward. i set bot timeouts like this warpmac_setTimeout(10000000); so i can observe communication with putty. What i found is that ack never gets to transmitter. request and grant packets are exchanged like they should be. Data packets are also trasmitted and received but ack packets never reach transmitter. I cant see any logical error. Please if you can see something let me know.

Last edited by juvebogdan (2015-Apr-13 11:36:23)

Offline

 

#2 2015-Apr-14 09:33:46

chunter
Administrator
From: Mango Communications
Registered: 2006-Aug-24
Posts: 1212

Re: OFDM reference design custom appplication

juvebogdan wrote:

What i found is that ack never gets to transmitter. request and grant packets are exchanged like they should be. Data packets are also trasmitted and received but ack packets never reach transmitter. I cant see any logical error. Please if you can see something let me know.

How are you verifying that the ACK is never being transmitted as opposed to being transmitted but not being received?

One idea: The OFDM Reference Design has an "autoresponder" subsystem that transmits ACK frames automatically when certain pre-configured conditions are meant. This allows the design to transmit ACKs on a precise deterministic time boundary relative to the previous reception. Since your code snippet is transmitting an ACK frame manually, maybe you are somehow interfering with the ongoing automatic ACK transmission. If you haven't already, try disabling the autoresponder. The CSMA MAC configures the autoresponder on line 564. You can effectively disable the autoresponder by commenting out the line:

Code:

// mimo_ofdmTxRx_setAction0(autoResp_action);

Offline

 

#3 2015-Apr-29 13:18:45

juvebogdan
Member
Registered: 2013-Sep-17
Posts: 76

Re: OFDM reference design custom appplication

I already tried with disabling automatic ACKs. However i did it like this:

        //Match condition 1: received header's type is DATA
    autoResp_matchCond = PHY_AUTORESPONSE_MATCH_CONFIG(PKTHEADER_INDX_TYPE, 1, 6);

I've put here 6 because i have no packet with that ID(type). But i also tried your way but it didn't help.

As for your question how i verified that ACKs are trasmitted but never received:

I've put xil_printf statements after every transmission (after these lines warpmac_finishPhyXmit();) and inside every case inside this for loop

if( packet->header.destAddr == (NODEID_TO_ADDR(myID)) )

I'm observing functioning of code using putty on both sides. On the transmitting side i always have printfs that show that request is sent, after that grant is received (on the receiving side i see printf that shows receving of request and sending of grant), then packet is sent and timer is started for ack, on the receiving side i see that packet is received and that ack is sent but on the transmitting side timer always expires and ack never comes.

I can't spot the error. It is very frustrating:(.

Offline

 

#4 2015-May-04 13:32:49

chunter
Administrator
From: Mango Communications
Registered: 2006-Aug-24
Posts: 1212

Re: OFDM reference design custom appplication

I can't be sure what you are seeing. Conceptually, there isn't much different about a DATA frame or an ACK frame, so if you can successfully communicate one but not the other that should be debuggable.

One debugging step is to simplify and see what happens. What happens if you remove all channel tuning and just keep everything on the static data channel. Do you still see the same outages?

Offline

 

#5 2015-May-11 13:47:11

juvebogdan
Member
Registered: 2013-Sep-17
Posts: 76

Re: OFDM reference design custom appplication

Hello chunter,

Thank you for your reply. I thought that you guys abandoned me:). I already tried with static channel and same thing happens. If you look my snippet above you will see that after random selection of channel i set channel to 1 so it is always one.

Today i assigned my send_ack() function to middle button and tried to send acks by myself. That worked. First ack that is sent by the code above isnt received but after i send one by myself with middle button everything works. I cant explain this.

As you know i complained in earlier posts that i need very big timeout period for my code to work. Just request/grant communication needs to much time and as you can see there is no extensive computation. Can this be the problem? I don't know.

Is it to much to ask to try my code on your boards. I can send it to you. Complete project. Maybe i'm experiencing this strange behaviour because of some physical flaws


Thank you.

Offline

 

#6 2015-May-11 23:06:46

murphpo
Administrator
From: Mango Communications
Registered: 2006-Jul-03
Posts: 5159

Re: OFDM reference design custom appplication

We are not in a position to test your code on our hardware. If your boards are transmitting and receiving any packets, it is likely they are able to communicate fine and the underlying problem is with your protocol implementation.

Be careful with any print statements in critical code paths. Printing to the UART takes a very long time, and xil_printf (and printf) are blocking calls. You can use the GPIO (if you have an oscilloscope to observe voltages in real time) and LEDs to indicate state changes with minimal time penalty.

You need to start isolating variables. This is the first step of debugging- understand what variables you can control, change one at a time and observe the effects. It might be worth the time to rever to the reference code and begin adding your protocol's components one at a time. Choose a metric (PER is usually a good choice for packet-based systems), design a repeatable experiment to measure the metric, then use that experiment to observe good/bad behaviors as you introduce additional protocol changes.

Offline

 

#7 2015-May-27 02:30:03

juvebogdan
Member
Registered: 2013-Sep-17
Posts: 76

Re: OFDM reference design custom appplication

Hello all,

I would like to update the value of some variables and change channel via warpphy_setChannel after the ACK is sent. Can i do that with your automatic ACK?

Thank you

Offline

 

#8 2015-May-27 10:12:36

chunter
Administrator
From: Mango Communications
Registered: 2006-Aug-24
Posts: 1212

Re: OFDM reference design custom appplication

I want to make sure I'm understanding your question correctly. In a receive context, you've set up an autoresponder to send something should certain criteria be met about the reception. After the autoresponder sends the message, you want the code to perform some action (here, 'warpphy_setChannel').

I think the best way to wait for the completion of the auto transmission would be to:

1. Use warpmac_finishPhyRecv() after you've set up the autoresponder. This will block your code from any further executions until the reception has completed.

2. Wait for "a little bit" with usleep(). By default the CSMAMAC project is set to start the autoresponder immediately after a reception. The autoresponder can be configured to provide an extra delay after reception and prior to transmission. If you are using this extra delay, increase you usleep() accordingly.

3. Use warpmac_finishPhyXmit() to then block your code until the transmission is finished.

The reason you can't use only step 3 because warpmac_finishPhyXmit() will only work after the PHY Tx has started. Steps 1 and 2 ensure that code waits until the autoresponder has actually started. After completing warpmac_finishPhyXmit(), it is then safe to change channels.

Offline

 

#9 2015-May-27 16:38:22

juvebogdan
Member
Registered: 2013-Sep-17
Posts: 76

Re: OFDM reference design custom appplication

You understand correctly.

I haven't changed anything in autoresponder mechanism in CSMA reference code. In phyRx_goodHeader_callback of reference design in case PKTTYPE_DATA there is already warpmac_finishPhyRecv() call at the beggining, and the line 426 has warpmac_finishPhyXmit(). You say i should usleep somewhere in between. Why should i do that if at this point (after line 426) the ACK transmission should be over because all three conditions are met. Can change channel at the line 427 withou using usleep?

Thank you.

Offline

 

Board footer