/************************************************ * Description: The mac layer service FSM. * * Arguments: * None. * Return: * None. * * Date: 2010-05-20 ***********************************************/ void mac_FSM() { phy_FSM(); // Check new data from radio if ( mac_check_new_frame() ) mac_analyse_new_frame(); // If Tx FSM is busy we need to call it if (mac_tx_busy()) mac_tx_handler(); // If the mac layer idle if (mac_tx_idle() && new_mhr_filled == FALSE) load_queue_data(); //check background tasks here switch (mac_state) { case MAC_STATE_IDLE: break; case MAC_STATE_COMMAND_START: switch(a_mac_service.cmd) { case LRWPAN_SVC_MAC_ERROR: //dummy service, just return the status that was passed in mac_state = MAC_STATE_IDLE; break; case LRWPAN_SVC_MAC_GENERIC_TX: //send a generic packet with arguments specified by upper level mac_tx_data(); mac_state = MAC_STATE_GENERIC_TX_WAIT; break; case LRWPAN_SVC_MAC_RETRANSMIT: //retransmit the last packet used for frames that are //only transmitted once because of no ACK request //assumes the TX lock is grabbed, and the TX buffer formatted. break; default: break; } //end switch cmd break; case MAC_STATE_GENERIC_TX_WAIT: // Just return; break; //this is used by MAC CMDs in general which send a packet with no ACK. case MAC_STATE_GENERIC_TX_WAIT_AND_UNLOCK: if (!mac_tx_idle()) break; mac_state = MAC_STATE_IDLE; break; default: break; }// end for switch(mac_state) }
void mac_data_req(mac_data_req_t *req) { mac_hdr_t hdr; bool indirect; memset(&hdr, 0, sizeof(mac_hdr_t)); hdr.mac_frm_ctrl.frame_type = MAC_DATA; hdr.mac_frm_ctrl.ack_req = (bool)(req->tx_options & MAC_ACK_REQUEST); hdr.mac_frm_ctrl.frame_ver = MAC_802_15_4_2006; hdr.dsn = pib.dsn++; hdr.dest_pan_id = req->dest_pan_id; hdr.src_pan_id = req->src_pan_id; memcpy(&hdr.src_addr, &req->src_addr, sizeof(address_t)); memcpy(&hdr.dest_addr, &req->dest_addr, sizeof(address_t)); // generate the header mac_gen_header(req->buf, &hdr); DBG_PRINT_RAW("\n<OUTGOING>\n"); debug_dump_mac_hdr(&hdr); // send the frame to the tx handler for processing indirect = (req->tx_options & MAC_INDIRECT_TRANS); mac_tx_handler(req->buf, &hdr.dest_addr, indirect, hdr.mac_frm_ctrl.ack_req, hdr.dsn, req->msdu_handle); }
void mac_cmd_handler(mac_cmd_t *cmd, mac_hdr_t *hdr) { buffer_t *buf_out; mac_hdr_t hdr_out; nwk_nib_t *nib = nwk_nib_get(); DBG_PRINT_SIMONLY("\n<INCOMING>"); debug_dump_mac_cmd(cmd); switch (cmd->cmd_id) { case MAC_ASSOC_REQ: if (nib->joined) { DBG_PRINT_SIMONLY("MAC: MAC Association Request Command Received.\n"); // check to make sure that association is permitted and the src address is the correct mode if ((pib.assoc_permit) && (hdr->src_addr.mode == LONG_ADDR)) { mac_assoc_ind_t assoc_args; assoc_args.capability = cmd->assoc_req.cap_info; memcpy(&assoc_args.dev_addr, &hdr->src_addr, sizeof(address_t)); mac_assoc_ind(&assoc_args); } else { mac_assoc_resp_t resp_args; memcpy(&resp_args.dev_addr, &hdr->src_addr, sizeof(address_t)); resp_args.assoc_short_addr = 0xFFFF; resp_args.status = MAC_INVALID_PARAMETER; mac_assoc_resp(&resp_args); } } break; case MAC_ASSOC_RESP: if ((pcb.mac_state == MLME_DATA_REQ) || (pcb.mac_state == MLME_ASSOC_REQ)) { pcb.mac_state = MLME_IDLE; } mac_assoc_conf(cmd->assoc_resp.short_addr, cmd->assoc_resp.assoc_status); break; case MAC_DATA_REQ: if (nib->joined) { DBG_PRINT("MAC: MAC Data Request Command Received.\n"); mac_indir_data_req_handler(&hdr->src_addr); } break; case MAC_BEACON_REQ: if (nib->joined) { DBG_PRINT("MAC: MAC Beacon Request Command Received.\n"); BUF_ALLOC(buf_out, TX); mac_gen_beacon_frm(buf_out, &hdr_out); mac_tx_handler(buf_out, &hdr_out.dest_addr, false, false, hdr_out.dsn, 0); } break; case MAC_ORPHAN_NOT: if (hdr->src_addr.mode == LONG_ADDR) { mac_orphan_ind(hdr->src_addr.long_addr); } break; case MAC_COORD_REALIGN: // check over the coord realign frame to make sure that the data is what we had previously if ((cmd->coord_realign.pan_id == pib.pan_id) && (cmd->coord_realign.short_addr == pib.short_addr)) { if ((pib.coord_addr.mode == SHORT_ADDR) && (cmd->coord_realign.coord_short_addr == pib.coord_addr.short_addr)) { pcb.coor_realign_rcvd = true; } else if ((pib.coord_addr.mode == LONG_ADDR) && (hdr->src_addr.mode == LONG_ADDR) && (hdr->src_addr.long_addr == pib.coord_addr.long_addr)) { pcb.coor_realign_rcvd = true; } else { return; } } else { return; } // stop the scan once we get a valid coord realignment command frame // the scan will end once the channel is beyond the channel range pcb.curr_scan_channel = MAC_PHY_CHANNEL_OFFSET + MAC_MAX_CHANNELS; ctimer_stop(&pcb.mlme_tmr); mac_scan(NULL); break; default: break; } }
//lint -e{715} Info 715: Symbol 'ptr' not referenced //lint -e{818} Info 818: Pointer parameter ptr' could be declared as pointing to const void mac_scan(void *ptr) { mac_cmd_t cmd; mac_hdr_t hdr; buffer_t *buf; address_t src_addr, dest_addr; mac_scan_conf_t scan_conf; U32 duration; mac_pcb_t *pcb = mac_pcb_get(); mac_pib_t *pib = mac_pib_get(); // increment the current scan channel on entry into this function. pcb->curr_scan_channel++; // check if we are initializing the scan. if so, then start the init procedure. if (pcb->mac_state != MLME_SCAN) { // on a new scan, first save the original pan id pcb->original_pan_id = pib->pan_id; // then set the pan id to the broadcast pan id. // NOTE: the broadcast addr is same as broadcast pan id pib->pan_id = MAC_BROADCAST_ADDR; // init the curr scan channel to the first one pcb->curr_scan_channel = MAC_PHY_CHANNEL_OFFSET; pcb->mac_state = MLME_SCAN; pcb->nwk_cnt = 0; } // search the channel mask to find the next allowable channel. // if the curr scan channel is not in the mask, then increment the channel and check again. keep doing // it until we either find an allowable channel or we exceed the max channels that are supported. for (;pcb->curr_scan_channel < (MAC_PHY_CHANNEL_OFFSET + MAC_MAX_CHANNELS); pcb->curr_scan_channel++) { //lint -e{701} Info 701: Shift left of signed quantity (int) // shift the bitmask and compare to the channel mask if (pcb->channel_mask & (1 << pcb->curr_scan_channel)) { break; } } // we may get here if the curr scan channel exceeds the max channels. if thats the case, then we will // automatically end the active scan. if (pcb->curr_scan_channel < (MAC_PHY_CHANNEL_OFFSET + MAC_MAX_CHANNELS)) { // set the channel on the radio mac_set_channel(pcb->curr_scan_channel); // generate and send the beacon request // get a free buffer, build the beacon request command, and then // send it using the mac_data_req service. BUF_ALLOC(buf, TX); dest_addr.mode = SHORT_ADDR; dest_addr.short_addr = MAC_BROADCAST_ADDR; if (pcb->scan_type == MAC_ACTIVE_SCAN) { cmd.cmd_id = MAC_BEACON_REQ; src_addr.mode = NO_PAN_ID_ADDR; } else if (pcb->scan_type == MAC_ORPHAN_SCAN) { cmd.cmd_id = MAC_ORPHAN_NOT; src_addr.mode = LONG_ADDR; src_addr.long_addr = pib->ext_addr; } mac_gen_cmd(buf, &cmd); mac_gen_cmd_header(buf, &hdr, false, &src_addr, &dest_addr); mac_tx_handler(buf, &hdr.dest_addr, false, false, hdr.dsn, ZIGBEE_INVALID_HANDLE); // set the callback timer duration = (pcb->scan_type == MAC_ACTIVE_SCAN) ? MAC_SCAN_TIME(pcb->duration) : aMacResponseWaitTime; ctimer_set(&pcb->mlme_tmr, duration, mac_scan, NULL); } else { pcb->mac_state = MLME_IDLE; // Send the nwk scan confirm scan_conf.scan_type = pcb->scan_type; scan_conf.energy_list = NULL; if (pcb->scan_type == MAC_ACTIVE_SCAN) { scan_conf.status = MAC_SUCCESS; } else if (pcb->scan_type == MAC_ORPHAN_SCAN) { scan_conf.status = (pcb->coor_realign_rcvd) ? MAC_SUCCESS : MAC_NO_BEACON; pcb->coor_realign_rcvd = false; } // restore the original pan ID. pib->pan_id = pcb->original_pan_id; mac_scan_conf(&scan_conf); } }