112 | | |
113 | | and |
114 | | |
115 | | void sendStatsPacket() |
116 | | |
117 | | void processControlStruct(warpnodeControl* ctrlStruct) |
118 | | |
119 | | |
120 | | In previous designs of warnet, the emacRx_callback was called when data was specified for the node and when it was specified for transmission over the air. The new design splits |
121 | | mgmtFromNetworkLayer_callback |
122 | | |
123 | | |
124 | | |
125 | | |
126 | | Whenever phyRx_badHeader_callback is called, we need to update all otherBadPackets in myStats. We do this by looping over the number of WARPNET_NUMNODES |
| 123 | { |
| 124 | //Initialize Payload Address |
| 125 | int pktBuf_payloadAddr; |
| 126 | |
| 127 | //Fill in a node command reply pkt |
| 128 | myNodeCmd.structType = STRUCTID_NODECOMMAND; |
| 129 | myNodeCmd.nodeID = myID; |
| 130 | myNodeCmd.cmdID = NODECMD_NODEACK; |
| 131 | myNodeCmd.cmdParam = rxSeqNum; |
| 132 | |
| 133 | //Fill in the ethernet packet's header info |
| 134 | txEthPktHeader.ethType = WARPNET_ETHTYPE_NODE2SVR; |
| 135 | memset(&(txEthPktHeader.srcAddr), (unsigned char)myID, 6); //Generic source address; ignored throughout |
| 136 | memset(&(txEthPktHeader.dstAddr), (unsigned char)0xFF, 6); //Broadcast destination address |
| 137 | |
| 138 | //Fill in the ethernet packet's header info |
| 139 | txEthPktHeader.pktLength = sizeof(warpnetEthernetPktHeader) + sizeof(warpnodeCommand); |
| 140 | txEthPktHeader.numStructs = 1; |
| 141 | txEthPktHeader.seqNum = rxSeqNum; |
| 142 | |
| 143 | //Copy over data for transmission over wire |
| 144 | pktBuf_payloadAddr = warpphy_getBuffAddr(WARPNET_PKTBUFFINDEX); |
| 145 | memcpy((void *)pktBuf_payloadAddr, &(txEthPktHeader), sizeof(warpnetEthernetPktHeader)); |
| 146 | memcpy((void *)pktBuf_payloadAddr+sizeof(warpnetEthernetPktHeader), &(myNodeCmd), sizeof(warpnodeCommand)); |
| 147 | |
| 148 | //Send the packet over the wire |
| 149 | warpmac_sendRawEthernetPacket((void *)pktBuf_payloadAddr, txEthPktHeader.pktLength); |
| 150 | return; |
| 151 | } |
| 152 | |
| 153 | }}} |
| 154 | |
| 155 | The design of sendStatPacket requires a few small modifications: |
| 156 | {{{ |
| 157 | void sendStatsPacket(char rxSeqNum) |
| 158 | { |
| 159 | //Initialize Payload Address |
| 160 | unsigned int pktBuf_payloadAddr; |
| 161 | |
| 162 | //Fill in the ethernet packet's header info |
| 163 | txEthPktHeader.pktLength = sizeof(warpnetEthernetPktHeader) + (WARPNET_NUMNODES*sizeof(warpnodeStats)); |
| 164 | txEthPktHeader.numStructs = WARPNET_NUMNODES; |
| 165 | txEthPktHeader.seqNum = rxSeqNum; |
| 166 | |
| 167 | //Copy the ethernet header and stats payload to a memroy buffer |
| 168 | pktBuf_payloadAddr = warpphy_getBuffAddr(WARPNET_PKTBUFFINDEX); |
| 169 | memcpy((void *)pktBuf_payloadAddr, &(txEthPktHeader), sizeof(warpnetEthernetPktHeader)); |
| 170 | |
| 171 | //Copy each stats struct (one per partner) |
| 172 | memcpy((void *)pktBuf_payloadAddr+sizeof(warpnetEthernetPktHeader), &myStats, WARPNET_NUMNODES*sizeof(warpnodeStats)); |
| 173 | |
| 174 | //Send the packet over the wire |
| 175 | warpmac_sendRawEthernetPacket((void *)pktBuf_payloadAddr, txEthPktHeader.pktLength); |
| 176 | |
| 177 | return; |
| 178 | } |
| 179 | }}} |
| 180 | |
| 181 | |
| 182 | When a warpnodeControl struct is received the function processControlStruct updates the node with the parameters in the warpnodeControl struct. |
| 183 | |
| 184 | In previous designs of warpnet, the emacRx_callback was called when data was specified for the node and when it was specified for transmission over the air. The new design makes a distinction between these two types through mgmtFromNetworkLayer_callback and dataFromNetworkLayer_callback |
| 185 | |
| 186 | The mgmtFromNetworkLayer_callback extends previous codes that have processed mangement structures because this callback process the traffic struct and the new node commands. |
| 187 | |
| 188 | Because the nodes are on the same ethernet network, the managmenet callback checks if the ethernet type is from the server to node or vice-versa. |
| 189 | If a packet is a NODE2SVR, the node has received an ack packet or stat packet from the other node. |
| 190 | |
| 191 | |
| 192 | Whenever phyRx_badHeader_callback is called, the otherBadPackets count should be incremented: |
| 193 | {{{ |
133 | | |
134 | | |
135 | | |
136 | | When phyRx_goodHeader_callback is called, two types of updates need to occur if myStats. |
137 | | If the callback enters the if(state&GOOD) we need to update the goodPacket count, rxBytes and txBytes as follows: |
138 | | myStats[srcNode].goodPackets++; |
139 | | myStats[srcNode].rxBytes += (packet->header.length + NUM_HEADER_BYTES + NUM_PAYLOAD_CRC_BYTES + NUM_PAYLOAD_TAIL_BYTES); |
140 | | myStats[srcNode].txBytes += NUM_HEADER_BYTES; |
141 | | If the callback enters the if(state&BAD) we need to update the partnerBadPackets: |
| 200 | }}} |
| 201 | |
| 202 | |
| 203 | When phyRx_goodHeader_callback is called, depending on the type, the count for goodPackets or partnerBadPackets is incremented |
| 204 | If the callback enters the if(state&GOOD) update the goodPacket count, rxBytes and txBytes as follows: |
| 205 | {{{ |
| 206 | myStats[srcNode].goodPackets++; |
| 207 | myStats[srcNode].rxBytes += (packet->header.length + NUM_HEADER_BYTES + NUM_PAYLOAD_CRC_BYTES + NUM_PAYLOAD_TAIL_BYTES); |
| 208 | myStats[srcNode].txBytes += NUM_HEADER_BYTES; |
| 209 | }}} |
| 210 | If the callback enters the if(state&BAD) update the partnerBadPackets: |
| 211 | {{{ |
143 | | |
144 | | |
145 | | In the main function, a couple values need to be initialized. |
146 | | |
147 | | |
148 | | |
| 213 | }}} |
| 214 | |
| 215 | In the main function, global values need to be initialized. |
| 216 | First, warpmac_enableDataFromNetwork, warpmac_setBaseRate, and warpmac_enableDummyPacketMode. For this application, the boards will be left in DummyPacketMode because to prevent them from transmitting information from the wire. (Due to the nature of the set up with routers, the TCP ack packets sent from the TCL-client computer to the server computer will be sent over the wireless channel. This can create problem because the computers will retransmit the data when they don't receive TCP-acks) |
| 217 | |
| 218 | Certain global variables need to be set to default values: |
| 219 | {{{ |
| 220 | Mode=0; |
| 221 | sendStats=0; |
| 222 | Time=0; |
| 223 | packetlength=1470; |
| 224 | |
| 225 | int i; |
| 226 | //Initialize the Stats Structs |
| 227 | for(i=0; i<WARPNET_NUMNODES; i++) |
| 228 | { |
| 229 | txSequences[i] = 1; |
| 230 | rxSequences[i] = 0; |
| 231 | myStats[i].structType = STRUCTID_NODESTATS; |
| 232 | myStats[i].nodeID = myID; |
| 233 | myStats[i].partnerID = i; |
| 234 | myStats[i].goodPackets = 0; |
| 235 | myStats[i].otherBadPackets = 0; |
| 236 | myStats[i].partnerBadPackets = 0; |
| 237 | myStats[i].rxBytes = 0; |
| 238 | myStats[i].txBytes = 0; |
| 239 | myStats[i].reserved0 = 0; |
| 240 | } |
| 241 | }}} |
| 242 | |
| 243 | Because csmaMac uses randomization to offset packet transmission, the random number generators need to be seeded to different values. Although multiple methods can be used to seed the random number generator, one method uses the xor of the bytes of the node ID with a random clock cycle input and WarpRadio_v1_RSSIData: |
| 244 | {{{ |
| 245 | (myID ^ ((int) rand_time) ^ WarpRadio_v1_RSSIData(RADIO2_ADDR)); |
| 246 | }}} |
| 247 | |
| 248 | Lastly, the Ethernet Packet Header is Initaliezd wit the Source Address and Destination Address: |
| 249 | {{{ |
| 250 | txEthPktHeader.ethType = WARPNET_ETHTYPE_NODE2SVR; |
| 251 | memset(&(txEthPktHeader.srcAddr), (unsigned char)myID, 6); //Generic source address; ignored throughout |
| 252 | memset(&(txEthPktHeader.dstAddr), (unsigned char)0xFF, 6); //Broadcast destination address |
| 253 | }}} |