| 266 | |
| 267 | First, we need to modify [browser:ReferenceDesigns/w3_802.11/c/wlan_mac_low_nomac/include/wlan_mac_nomac.h wlan_mac_nomac.h] with a few new definitions. |
| 268 | |
| 269 | {{{ |
| 270 | #!c |
| 271 | |
| 272 | #define TX_PKT_BUF_TOKEN 7 |
| 273 | |
| 274 | #define MAC_HW_LASTBYTE_TOKEN (sizeof(mac_frame_custom_token)+3) |
| 275 | |
| 276 | typedef struct{ |
| 277 | u8 frame_control_1; |
| 278 | u8 frame_control_2; |
| 279 | u16 duration_id; |
| 280 | u8 address_ra[6]; |
| 281 | u8 address_ta[6]; |
| 282 | u32 res_duration_usec; |
| 283 | } mac_frame_custom_token; |
| 284 | }}} |
| 285 | |
| 286 | We will use {{{TX_PKT_BUF_TOKEN}}} as a hardcoded packet buffer index that is dedicated to transmitting our new token frames. {{{mac_frame_custom_token}}} is a struct that is our new custom token frame. It's format is inspired by 802.11 frames in order to allow nearby commercial Wi-Fi devices to decode and ignore these frames. We'll set the {{{frame_control_1}}} field to an invalid value to make ensure this. |
| 287 | |
| 288 | ---- |
| 289 | |
| 290 | Next, we will perform a little bit of bookkeeping and declare two new global variables we will need at the top of [browser:ReferenceDesigns/w3_802.11/c/wlan_mac_low_nomac/wlan_mac_nomac.c wlan_mac_nomac.c]: |
| 291 | |
| 292 | {{{ |
| 293 | #!c |
| 294 | |
| 295 | u8 in_reservation; |
| 296 | u64 reservation_ts_end; |
| 297 | }}} |
| 298 | |
| 299 | We will explain how we will use these new variables in the next sections. In {{{main()}}}, we also need to set some sane defaults: |
| 300 | |
| 301 | {{{ |
| 302 | #!c |
| 303 | |
| 304 | in_reservation = 0; |
| 305 | wlan_mac_low_set_new_reservation_callback((void*)token_new_reservation); |
| 306 | wlan_mac_low_set_adjust_reservation_ts_callback((void*)adjust_reservation_ts_end); |
| 307 | }}} |
| 308 | |
| 309 | We have not created the {{{token_new_reservation()}}} or {{{adjust_reservation_ts_end()}}} functions yet. We will add those in the coming sections. |
| 310 | |
| 311 | ---- |
| 312 | The first substantive addition we will make to the NoMAC project is a function to deal with the IPC from CPU_HIGH that says we are now entering a new token reservation period for some given address and for some given duration of time. Add the following function to NoMAC: |
| 313 | |
| 314 | {{{ |
| 315 | #!c |
| 316 | |
| 317 | void token_new_reservation(ipc_token_new_reservation* new_reservation){ |
| 318 | |
| 319 | u8 mac_cfg_rate; |
| 320 | u16 mac_cfg_length; |
| 321 | int curr_tx_pow; |
| 322 | u32 mac_hw_status; |
| 323 | u32 rx_status; |
| 324 | |
| 325 | wlan_ipc_msg ipc_msg_to_high_start; |
| 326 | ipc_token_new_reservation ipc_payload_start; |
| 327 | wlan_ipc_msg ipc_msg_to_high_end; |
| 328 | ipc_token_end_reservation ipc_payload_end; |
| 329 | |
| 330 | |
| 331 | ipc_msg_to_high_start.msg_id = IPC_MBOX_MSG_ID(IPC_MBOX_TOKEN_NEW_RESERVATION); |
| 332 | |
| 333 | if( (sizeof(u32)*(sizeof(ipc_token_new_reservation)/sizeof(u32))) == sizeof(ipc_token_new_reservation) ){ |
| 334 | ipc_msg_to_high_start.num_payload_words = (sizeof(ipc_token_new_reservation)/sizeof(u32)); |
| 335 | } else { |
| 336 | ipc_msg_to_high_start.num_payload_words = (sizeof(ipc_token_new_reservation)/sizeof(u32)) + 1; |
| 337 | } |
| 338 | |
| 339 | ipc_msg_to_high_start.payload_ptr = (u32*)(&ipc_payload_start); |
| 340 | |
| 341 | ipc_msg_to_high_end.msg_id = IPC_MBOX_MSG_ID(IPC_MBOX_TOKEN_END_RESERVATION); |
| 342 | |
| 343 | if( (sizeof(u32)*(sizeof(ipc_token_end_reservation)/sizeof(u32))) == sizeof(ipc_token_end_reservation) ){ |
| 344 | ipc_msg_to_high_end.num_payload_words = (sizeof(ipc_token_end_reservation)/sizeof(u32)); |
| 345 | } else { |
| 346 | ipc_msg_to_high_end.num_payload_words = (sizeof(ipc_token_end_reservation)/sizeof(u32)) + 1; |
| 347 | } |
| 348 | |
| 349 | ipc_msg_to_high_end.payload_ptr = (u32*)(&ipc_payload_end); |
| 350 | |
| 351 | mac_cfg_rate = WLAN_PHY_RATE_BPSK12; |
| 352 | |
| 353 | if(wlan_addr_eq(new_reservation->addr, eeprom_addr)){ |
| 354 | //This is my reservation |
| 355 | in_reservation = 1; |
| 356 | wlan_mac_low_enable_new_mpdu_tx(); |
| 357 | reservation_ts_end = get_usec_timestamp() + ((u64)new_reservation->res_duration); |
| 358 | |
| 359 | memcpy( ipc_payload_start.addr, new_reservation->addr, 6 ); |
| 360 | ipc_payload_start.res_duration = new_reservation->res_duration; |
| 361 | ipc_mailbox_write_msg(&ipc_msg_to_high_start); |
| 362 | |
| 363 | } else { |
| 364 | //This is someone else's reservation |
| 365 | mac_cfg_length = wlan_create_token_offer_frame((void*)(TX_PKT_BUF_TO_ADDR(TX_PKT_BUF_TOKEN) + PHY_TX_PKT_BUF_MPDU_OFFSET), |
| 366 | new_reservation->addr, |
| 367 | eeprom_addr, |
| 368 | 0, |
| 369 | new_reservation->res_duration); //TODO: Calculate appropriate duration |
| 370 | |
| 371 | |
| 372 | |
| 373 | wlan_phy_set_tx_signal(TX_PKT_BUF_TOKEN, mac_cfg_rate, mac_cfg_length); // Write SIGNAL for RTS |
| 374 | |
| 375 | curr_tx_pow = wlan_mac_low_dbm_to_gain_target(15); |
| 376 | wlan_mac_tx_ctrl_A_gains(curr_tx_pow, curr_tx_pow, curr_tx_pow, curr_tx_pow); |
| 377 | |
| 378 | //wlan_mac_tx_ctrl_A_params(pktBuf, antMask, preTx_backoff_slots, preWait_postRxTimer1, preWait_postTxTimer1, postWait_postTxTimer2) |
| 379 | //postTxTimer2 is a timeout. We'll use that to wait for a token response |
| 380 | wlan_mac_tx_ctrl_A_params(TX_PKT_BUF_TOKEN, 0x1, 0, 0, 0, 1); |
| 381 | |
| 382 | //Start the Tx state machine |
| 383 | wlan_mac_tx_ctrl_A_start(1); |
| 384 | wlan_mac_tx_ctrl_A_start(0); |
| 385 | |
| 386 | //Wait for the MPDU Tx to finish |
| 387 | do { //while(tx_status & WLAN_MAC_STATUS_MASK_TX_A_PENDING) |
| 388 | |
| 389 | //Poll the DCF core status register |
| 390 | mac_hw_status = wlan_mac_get_status(); |
| 391 | |
| 392 | if( mac_hw_status & WLAN_MAC_STATUS_MASK_TX_A_DONE ) { |
| 393 | //Transmission is complete |
| 394 | |
| 395 | memcpy( ipc_payload_start.addr, new_reservation->addr, 6 ); |
| 396 | ipc_payload_start.res_duration = new_reservation->res_duration; |
| 397 | ipc_mailbox_write_msg(&ipc_msg_to_high_start); |
| 398 | |
| 399 | //Switch on the result of the transmission attempt |
| 400 | switch( mac_hw_status & WLAN_MAC_STATUS_MASK_TX_A_RESULT ) { |
| 401 | case WLAN_MAC_STATUS_TX_A_RESULT_RX_STARTED: |
| 402 | //Transmission ended, followed by a new reception (hopefully a token response) |
| 403 | |
| 404 | //Handle the new reception |
| 405 | rx_status = wlan_mac_low_poll_frame_rx(); |
| 406 | |
| 407 | //Check if the reception is an ACK addressed to this node, received with a valid checksum |
| 408 | if( (rx_status & POLL_MAC_STATUS_TOKEN_OFFER_ACCEPTED)) { |
| 409 | |
| 410 | //We are now in a new reservation state for this user |
| 411 | in_reservation = 1; |
| 412 | reservation_ts_end = get_usec_timestamp() + ((u64)new_reservation->res_duration); |
| 413 | } else { |
| 414 | //Received a packet immediately after transmitting, but it wasn't the offer response we wanted |
| 415 | //This is equivalent to a timeout. Let CPU_HIGH know that this reservation period is over |
| 416 | in_reservation = 0; |
| 417 | ipc_payload_end.reason = TOKEN_TIMEOUT; |
| 418 | //ipc_payload.low_tx_details; //TODO |
| 419 | ipc_mailbox_write_msg(&ipc_msg_to_high_end); |
| 420 | } |
| 421 | break; |
| 422 | case WLAN_MAC_STATUS_TX_A_RESULT_TIMEOUT: |
| 423 | in_reservation = 0; |
| 424 | ipc_payload_end.reason = TOKEN_TIMEOUT; |
| 425 | //ipc_payload.low_tx_details; //TODO |
| 426 | ipc_mailbox_write_msg(&ipc_msg_to_high_end); |
| 427 | break; |
| 428 | } |
| 429 | } else { //else for if(mac_hw_status & WLAN_MAC_STATUS_MASK_TX_A_DONE) |
| 430 | //Poll the MAC Rx state to check if a packet was received while our Tx was deferring |
| 431 | |
| 432 | if( mac_hw_status & (WLAN_MAC_STATUS_MASK_RX_PHY_ACTIVE | WLAN_MAC_STATUS_MASK_RX_PHY_BLOCKED_FCS_GOOD | WLAN_MAC_STATUS_MASK_RX_PHY_BLOCKED) ) { |
| 433 | rx_status = wlan_mac_low_poll_frame_rx(); |
| 434 | } |
| 435 | }//END if(Tx A state machine done) |
| 436 | } while( mac_hw_status & WLAN_MAC_STATUS_MASK_TX_A_PENDING ); |
| 437 | } |
| 438 | } |
| 439 | }}} |
| 440 | |
| 441 | ---- |