bool wpan_mlme_associate_req(uint8_t LogicalChannel, uint8_t ChannelPage, wpan_addr_spec_t *CoordAddrSpec, uint8_t CapabilityInformation) { buffer_t *buffer_header; mlme_associate_req_t *mlme_associate_req; /* Allocate a buffer for mlme associate request */ buffer_header = bmm_buffer_alloc(LARGE_BUFFER_SIZE); /* Check for buffer availability */ if (NULL == buffer_header) { return false; } /* Get the buffer body from buffer header */ mlme_associate_req = (mlme_associate_req_t *)BMM_BUFFER_POINTER( buffer_header); /* Construct mlme_associate_req_t message */ mlme_associate_req->cmdcode = MLME_ASSOCIATE_REQUEST; /* Operating channel */ mlme_associate_req->LogicalChannel = LogicalChannel; /* Coordinator address spec */ mlme_associate_req->CoordAddrMode = CoordAddrSpec->AddrMode; #ifdef TEST_HARNESS_BIG_ENDIAN mlme_associate_req->CoordPANId = CPU_ENDIAN_TO_LE16(CoordAddrSpec->PANId); #else mlme_associate_req->CoordPANId = CoordAddrSpec->PANId; #endif ADDR_COPY_DST_SRC_64(mlme_associate_req->CoordAddress.long_address, CoordAddrSpec->Addr.long_address); /* Other fields */ mlme_associate_req->CapabilityInformation = CapabilityInformation; mlme_associate_req->ChannelPage = ChannelPage; /* Insert service message into NHLE MLME queue */ #ifdef ENABLE_QUEUE_CAPACITY if (MAC_SUCCESS != qmm_queue_append(&nhle_mac_q, buffer_header)) { /* * MLME-ASSOCIATE.request is not appended into NHLE MAC * queue, hence free the buffer allocated */ bmm_buffer_free(buffer_header); return false; } #else qmm_queue_append(&nhle_mac_q, buffer_header); #endif /* ENABLE_QUEUE_CAPACITY */ return true; }
/** * @brief Cleanup TAL * * @param trx_id Transceiver identifier */ static void cleanup_tal(trx_id_t trx_id) { /* Clear all running TAL timers. */ ENTER_CRITICAL_REGION(); stop_tal_timer(trx_id); LEAVE_CRITICAL_REGION(); /* Clear TAL Incoming Frame queue and free used buffers. */ while (tal_incoming_frame_queue[trx_id].size > 0) { buffer_t *frame = qmm_queue_remove( &tal_incoming_frame_queue[trx_id], NULL); if (NULL != frame) { bmm_buffer_free(frame); } } /* Get new TAL Rx buffer if necessary */ if (tal_rx_buffer[trx_id] == NULL) { tal_rx_buffer[trx_id] = bmm_buffer_alloc(LARGE_BUFFER_SIZE); } /* Handle buffer shortage */ if (tal_rx_buffer[trx_id] == NULL) { tal_buf_shortage[trx_id] = true; } else { tal_buf_shortage[trx_id] = false; } }
uint8_t pal_sio_init(uint8_t UARTx) { buffer_t *buffer_header; NWK_DataReq_t *nlde_data_req; buffer_header = bmm_buffer_alloc(LARGE_BUFFER_SIZE); nlde_data_req = (NWK_DataReq_t *)BMM_BUFFER_POINTER(buffer_header); uart_0_buffer.rx_buf_head = ((uint8_t *)nlde_data_req) + (LARGE_BUFFER_SIZE - FCS_LEN - TRANSPARENT_IO_BUF_SIZE); uart_0_buffer.rx_buf[0] = (uint8_t *)buffer_header; UARTx = UARTx; return 0; }
void mac_gts_table_update(void) { uint8_t table_index; for (table_index = 0; table_index < mac_pan_gts_table_len; table_index++) { if (mac_pan_gts_table[table_index].ExpiryCount > 0 && --mac_pan_gts_table[table_index].ExpiryCount == 0) { gts_char_t gts_char; uint16_t dev_addr = mac_pan_gts_table[table_index].DevShortAddr; gts_char.GtsDirection = mac_pan_gts_table[table_index].GtsDesc .GtsDirection; gts_char.GtsLength = mac_pan_gts_table[table_index].GtsDesc .GtsLength; gts_char.GtsCharType = GTS_DEALLOCATE; gts_char.Reserved = 0; if (mac_gts_deallocate(gts_char, mac_pan_gts_table[table_index]. DevShortAddr, true)) { buffer_t *buffer_header; mlme_gts_ind_t *mgi; buffer_header = bmm_buffer_alloc( LARGE_BUFFER_SIZE); if (NULL == buffer_header) { /* Buffer is not available */ return; } mgi = (mlme_gts_ind_t *)BMM_BUFFER_POINTER( buffer_header); mgi->DeviceAddr = dev_addr; mgi->GtsChar = gts_char; mgi->cmdcode = MLME_GTS_INDICATION; /* Append the MLME GTS indication to the *MAC-NHLE queue. */ qmm_queue_append(&mac_nhle_q, buffer_header); --table_index; } } } }
bool wpan_mlme_associate_resp(uint64_t DeviceAddress, uint16_t AssocShortAddress, uint8_t status) { buffer_t *buffer_header; mlme_associate_resp_t *mlme_associate_resp; /* Allocate a small buffer for association response */ buffer_header = bmm_buffer_alloc(LARGE_BUFFER_SIZE); if (NULL == buffer_header) { /* Buffer is not available */ return false; } /* Get the buffer body from buffer header */ mlme_associate_resp = (mlme_associate_resp_t *)BMM_BUFFER_POINTER( buffer_header); /* Construct mlme_associate_resp_t message */ mlme_associate_resp->cmdcode = MLME_ASSOCIATE_RESPONSE; /* Other fields */ #ifdef TEST_HARNESS_BIG_ENDIAN mlme_associate_resp->DeviceAddress = CPU_ENDIAN_TO_LE64(DeviceAddress); mlme_associate_resp->AssocShortAddress = CPU_ENDIAN_TO_LE16( AssocShortAddress); #else mlme_associate_resp->DeviceAddress = DeviceAddress; mlme_associate_resp->AssocShortAddress = AssocShortAddress; #endif mlme_associate_resp->status = status; /* Insert mlme_associate_resp_t into NHLE MAC queue */ #ifdef ENABLE_QUEUE_CAPACITY if (MAC_SUCCESS != qmm_queue_append(&nhle_mac_q, buffer_header)) { /* * MLME-ASSOCIATE.response is not appended into NHLE MAC * queue, hence free the buffer allocated */ bmm_buffer_free(buffer_header); return false; } #else qmm_queue_append(&nhle_mac_q, buffer_header); #endif /* ENABLE_QUEUE_CAPACITY */ return true; }
bool wpan_mlme_poll_req(wpan_addr_spec_t *CoordAddrSpec) { buffer_t *buffer_header; mlme_poll_req_t *mlme_poll_req; /* Allocate a small buffer for poll request */ buffer_header = bmm_buffer_alloc(LARGE_BUFFER_SIZE); if (NULL == buffer_header) { /* Buffer is not available */ return false; } /* Get the buffer body from buffer header */ mlme_poll_req = (mlme_poll_req_t *)BMM_BUFFER_POINTER(buffer_header); /* construct mlme_poll_req_t message */ mlme_poll_req->cmdcode = MLME_POLL_REQUEST; /* Other fileds. */ mlme_poll_req->CoordAddrMode = CoordAddrSpec->AddrMode; #ifdef TEST_HARNESS_BIG_ENDIAN mlme_poll_req->CoordPANId = CPU_ENDIAN_TO_LE16(CoordAddrSpec->PANId); #else mlme_poll_req->CoordPANId = CoordAddrSpec->PANId; #endif if (WPAN_ADDRMODE_SHORT == CoordAddrSpec->AddrMode) { ADDR_COPY_DST_SRC_16(mlme_poll_req->CoordAddress, CoordAddrSpec->Addr.short_address); } else { ADDR_COPY_DST_SRC_64(mlme_poll_req->CoordAddress, CoordAddrSpec->Addr.long_address); } #ifdef ENABLE_QUEUE_CAPACITY if (MAC_SUCCESS != qmm_queue_append(&nhle_mac_q, buffer_header)) { /* * MLME-POLL.request is not appended into NHLE MAC * queue, hence free the buffer allocated and return false */ bmm_buffer_free(buffer_header); return false; } #else qmm_queue_append(&nhle_mac_q, buffer_header); #endif /* ENABLE_QUEUE_CAPACITY */ return true; }
bool wpan_mlme_disassociate_req(wpan_addr_spec_t *DeviceAddrSpec, uint8_t DisassociateReason, bool TxIndirect) { buffer_t *buffer_header; mlme_disassociate_req_t *mlme_disassociate_req; /* Allocate a small buffer for disassociation request */ buffer_header = bmm_buffer_alloc(LARGE_BUFFER_SIZE); if (NULL == buffer_header) { /* Buffer is not available */ return false; } /* Get the buffer body from buffer header */ mlme_disassociate_req = (mlme_disassociate_req_t *)BMM_BUFFER_POINTER( buffer_header); /* Update the disassociate request structure */ mlme_disassociate_req->cmdcode = MLME_DISASSOCIATE_REQUEST; mlme_disassociate_req->DisassociateReason = DisassociateReason; mlme_disassociate_req->DeviceAddrMode = DeviceAddrSpec->AddrMode; #ifdef TEST_HARNESS_BIG_ENDIAN mlme_disassociate_req->DevicePANId = CPU_ENDIAN_TO_LE16( DeviceAddrSpec->PANId); #else mlme_disassociate_req->DevicePANId = DeviceAddrSpec->PANId; #endif ADDR_COPY_DST_SRC_64(mlme_disassociate_req->DeviceAddress, DeviceAddrSpec->Addr.long_address); mlme_disassociate_req->TxIndirect = TxIndirect; #ifdef ENABLE_QUEUE_CAPACITY if (MAC_SUCCESS != qmm_queue_append(&nhle_mac_q, buffer_header)) { /* * MLME-DISASSOCIATE.request is not appended into NHLE MAC * queue, hence free the buffer allocated and return false */ bmm_buffer_free(buffer_header); return false; } #else qmm_queue_append(&nhle_mac_q, buffer_header); #endif /* ENABLE_QUEUE_CAPACITY */ return true; }
// Target function to timer, sends ping packet after a delay void mp(void) { uint8_t* pFrame = bmm_buffer_alloc(); if(pFrame != NULL) { ftPing *frame = (ftPing*)(((rx_frame_t*)pFrame)->data); frame->fcf = FCF_DATA; frame->seq = macConfig.dsn++; frame->panid = macConfig.panId; frame->srcAddr = macConfig.shortAddress; frame->originAddr = macConfig.shortAddress; frame->finalDestAddr = pingAddr; frame->type = pingType; frame->rssi = radioGetSavedRssiValue(); frame->lqi = radioGetSavedLqiValue(); ((rx_frame_t*)pFrame)->length = sizeof(ftPing); if (NODETYPE == COORD) { // Find the top parent u8 addr = macGetTopParent(pingAddr); frame->destAddr = addr; // See if the child is sleeping (only the coord sends directly to a child node) if (RUMSLEEP && macIsChild(addr) && macIsChildSleeping(addr)) { // Send it later, after child is awake macHoldFrame(addr, pFrame); // buffer is freed inside macHoldFrame() // Don't send frame right now return; } } else // End/router nodes { frame->destAddr = macConfig.parentShortAddress; } event_object_t event; event.event = MAC_EVENT_SEND; event.data = pFrame; event.callback = 0; // save Event mac_put_event(&event); } }
bool wpan_mlme_orphan_resp(uint64_t OrphanAddress, uint16_t ShortAddress, bool AssociatedMember) { buffer_t *buffer_header; mlme_orphan_resp_t *mlme_orphan_resp; /* Allocate a small buffer for orphan response */ buffer_header = bmm_buffer_alloc(LARGE_BUFFER_SIZE); if (NULL == buffer_header) { /* Buffer is not available */ return false; } /* Get the buffer body from buffer header */ mlme_orphan_resp = (mlme_orphan_resp_t *)BMM_BUFFER_POINTER( buffer_header); /* Update the orphan response structure */ mlme_orphan_resp->cmdcode = MLME_ORPHAN_RESPONSE; #ifdef TEST_HARNESS_BIG_ENDIAN mlme_orphan_resp->OrphanAddress = CPU_ENDIAN_TO_LE64(OrphanAddress); mlme_orphan_resp->ShortAddress = CPU_ENDIAN_TO_LE16(ShortAddress); #else mlme_orphan_resp->OrphanAddress = OrphanAddress; mlme_orphan_resp->ShortAddress = ShortAddress; #endif mlme_orphan_resp->AssociatedMember = AssociatedMember; #ifdef ENABLE_QUEUE_CAPACITY if (MAC_SUCCESS != qmm_queue_append(&nhle_mac_q, buffer_header)) { /* * MLME-ORPHAN.response is not appended into NHLE MAC * queue, hence free the buffer allocated and return false */ bmm_buffer_free(buffer_header); return false; } #else qmm_queue_append(&nhle_mac_q, buffer_header); #endif /* ENABLE_QUEUE_CAPACITY */ return true; }
int32_t wnet_dataframe_send(rcp_txinfo_t *txinfo, uint8_t *databuf, uint32_t datalen) { buffer_t *buffer_header; uint8_t *nlde_data_req; if (uart_0_buffer.rx_buf_head == NULL) return -1; AppFrameHeader_t *app = (AppFrameHeader_t *)uart_0_buffer.rx_buf_head; *uart_0_buffer.rx_buf_head = 0xF1; *(uart_0_buffer.rx_buf_head+1) = 0x00; app->AppSequenceNumber = gNwk_nib.sequenceNumber; app->DstAddress = 0xFFFF; app->length = datalen; memcpy(app->AppPayload,databuf,datalen); uart_0_buffer.rx_buf_head[app->length +7] = XORSUM((uint8_t *)app,app->length +7); wpan_nlde_data_req( NWK_DSTADDRMODE_RESPONSE, app->DstAddress, app->length +8, uart_0_buffer.rx_buf_head, uart_0_buffer.rx_buf[0], txinfo->hops, 0, true, UART_ALLOC, APP_ROUTE_MESH); buffer_header = bmm_buffer_alloc(LARGE_BUFFER_SIZE); if (buffer_header == NULL) { uart_0_buffer.rx_buf_head = NULL; return -1; } nlde_data_req = BMM_BUFFER_POINTER(buffer_header); uart_0_buffer.rx_buf_head = (nlde_data_req) + (LARGE_BUFFER_SIZE - FCS_LEN - TRANSPARENT_IO_BUF_SIZE); uart_0_buffer.rx_buf[0] = (uint8_t *)buffer_header; return 1; }
/** * @brief Completes Rx transaction * * @param trx_id Transceiver identifier */ void complete_rx_transaction(trx_id_t trx_id) { /* Get energy of received frame */ uint16_t reg_offset = RF_BASE_ADDR_OFFSET * trx_id; uint8_t ed = trx_reg_read(reg_offset + RG_RF09_EDV); uint16_t ed_pos = rx_frm_info[trx_id]->len_no_crc + 1 + tal_pib[trx_id].FCSLen; rx_frm_info[trx_id]->mpdu[ed_pos] = ed; /* PSDU, LQI, ED */ /* Append received frame to incoming_frame_queue and get new rx buffer. **/ qmm_queue_append(&tal_incoming_frame_queue[trx_id], tal_rx_buffer[trx_id]); /* The previous buffer is eaten up and a new buffer is not assigned yet. **/ tal_rx_buffer[trx_id] = bmm_buffer_alloc(LARGE_BUFFER_SIZE); /* Switch to rx again to handle buffer shortage */ switch_to_rx(trx_id); }
bool wpan_mlme_scan_req(uint8_t ScanType, uint32_t ScanChannels, uint8_t ScanDuration, uint8_t ChannelPage) { buffer_t *buffer_header; mlme_scan_req_t *mlme_scan_req; /* Allocate a small buffer for scan request */ buffer_header = bmm_buffer_alloc(LARGE_BUFFER_SIZE); if (NULL == buffer_header) { /* Buffer is not available */ return false; } /* Get the buffer body from buffer header */ mlme_scan_req = (mlme_scan_req_t *)BMM_BUFFER_POINTER(buffer_header); /* Update the scan request structure */ mlme_scan_req->cmdcode = MLME_SCAN_REQUEST; mlme_scan_req->ScanType = ScanType; mlme_scan_req->ScanChannels = ScanChannels; mlme_scan_req->ScanDuration = ScanDuration; mlme_scan_req->ChannelPage = ChannelPage; #ifdef ENABLE_QUEUE_CAPACITY if (MAC_SUCCESS != qmm_queue_append(&nhle_mac_q, buffer_header)) { /* * MLME-SCAN.request is not appended into NHLE MAC * queue, hence free the buffer allocated and return false */ bmm_buffer_free(buffer_header); return false; } #else qmm_queue_append(&nhle_mac_q, buffer_header); #endif /* ENABLE_QUEUE_CAPACITY */ return true; }
bool wpan_mlme_get_req(uint8_t PIBAttribute) #endif /* (MAC_SECURITY_ZIP || MAC_SECURITY_2006) */ { buffer_t *buffer_header; mlme_get_req_t *mlme_get_req; /* Allocate a large buffer for get request as maximum beacon payload * should be accommodated */ buffer_header = bmm_buffer_alloc(LARGE_BUFFER_SIZE); /* Check for buffer availability */ if (NULL == buffer_header) { return false; } /* Get the buffer body from buffer header */ mlme_get_req = (mlme_get_req_t *)BMM_BUFFER_POINTER(buffer_header); /* Update the get request structure */ mlme_get_req->cmdcode = MLME_GET_REQUEST; mlme_get_req->PIBAttribute = PIBAttribute; #if ((defined MAC_SECURITY_ZIP) || (defined MAC_SECURITY_2006)) mlme_get_req->PIBAttributeIndex = PIBAttributeIndex; #endif /* (MAC_SECURITY_ZIP || MAC_SECURITY_2006) */ #ifdef ENABLE_QUEUE_CAPACITY if (MAC_SUCCESS != qmm_queue_append(&nhle_mac_q, buffer_header)) { /* * MLME-GET.request is not appended into NHLE MAC * queue, hence free the buffer allocated and return false */ bmm_buffer_free(buffer_header); return false; } #else qmm_queue_append(&nhle_mac_q, buffer_header); #endif /* ENABLE_QUEUE_CAPACITY */ return true; }
bool wpan_mlme_rx_enable_req(bool DeferPermit, uint32_t RxOnTime, uint32_t RxOnDuration) { buffer_t *buffer_header; mlme_rx_enable_req_t *mlme_rx_enable_req; /* Allocate a small buffer for rx enable request */ buffer_header = bmm_buffer_alloc(LARGE_BUFFER_SIZE); if (NULL == buffer_header) { /* Buffer is not available */ return false; } /* Get the buffer body from buffer header */ mlme_rx_enable_req = (mlme_rx_enable_req_t *)BMM_BUFFER_POINTER( buffer_header); /* Update the rx enable request structure */ mlme_rx_enable_req->cmdcode = MLME_RX_ENABLE_REQUEST; mlme_rx_enable_req->DeferPermit = DeferPermit; mlme_rx_enable_req->RxOnTime = RxOnTime; mlme_rx_enable_req->RxOnDuration = RxOnDuration; #ifdef ENABLE_QUEUE_CAPACITY if (MAC_SUCCESS != qmm_queue_append(&nhle_mac_q, buffer_header)) { /* * MLME-RX-ENABLE.request is not appended into NHLE MAC * queue, hence free the buffer allocated and return false */ bmm_buffer_free(buffer_header); return false; } #else qmm_queue_append(&nhle_mac_q, buffer_header); #endif /* ENABLE_QUEUE_CAPACITY */ return true; }
bool wpan_mlme_sync_req(uint8_t LogicalChannel, uint8_t ChannelPage, bool TrackBeacon) { buffer_t *buffer_header; mlme_sync_req_t *mlme_sync_req; /* Allocate a small buffer for sync request */ buffer_header = bmm_buffer_alloc(LARGE_BUFFER_SIZE); if (NULL == buffer_header) { /* Buffer is not available */ return false; } /* Get the buffer body from buffer header */ mlme_sync_req = (mlme_sync_req_t *)BMM_BUFFER_POINTER(buffer_header); /* Update the sync request structure */ mlme_sync_req->cmdcode = MLME_SYNC_REQUEST; mlme_sync_req->LogicalChannel = LogicalChannel; mlme_sync_req->ChannelPage = ChannelPage; mlme_sync_req->TrackBeacon = TrackBeacon; #ifdef ENABLE_QUEUE_CAPACITY if (MAC_SUCCESS != qmm_queue_append(&nhle_mac_q, buffer_header)) { /* * MLME-SYNC.request is not appended into NHLE MAC * queue, hence free the buffer allocated and return false */ bmm_buffer_free(buffer_header); return false; } #else qmm_queue_append(&nhle_mac_q, buffer_header); #endif /* ENABLE_QUEUE_CAPACITY */ return true; }
bool wpan_mlme_gts_req(uint16_t DevShortAddr, gts_char_t GtsChar) { #ifdef GTS_SUPPORT buffer_t *buffer_header; mlme_gts_req_t *mlme_gts_req; /* Allocate a small buffer for gts request */ buffer_header = bmm_buffer_alloc(LARGE_BUFFER_SIZE); if (NULL == buffer_header) { /* Buffer is not available */ return false; } /* Get the buffer body from buffer header */ mlme_gts_req = (mlme_gts_req_t *)BMM_BUFFER_POINTER(buffer_header); /* construct mlme_gts_req_t message */ mlme_gts_req->cmdcode = MLME_GTS_REQUEST; mlme_gts_req->DeviceShortAddr = CPU_ENDIAN_TO_LE16(DevShortAddr); /* Other fields. */ mlme_gts_req->GtsChar = GtsChar; #ifdef ENABLE_QUEUE_CAPACITY if (MAC_SUCCESS != qmm_queue_append(&nhle_mac_q, buffer_header)) { /* * MLME-POLL.request is not appended into NHLE MAC * queue, hence free the buffer allocated and return false */ bmm_buffer_free(buffer_header); return false; } #else qmm_queue_append(&nhle_mac_q, buffer_header); #endif /* ENABLE_QUEUE_CAPACITY */ return true; #endif /* GTS_SUPPORT */ }
/** Send a frame that has been stored for a child node. This is meant to be called immediately upon receiving a packet from a sleeping child node. */ void macSendStoredFrame(u16 addr) { if (NODETYPE != ENDDEVICE && RUMSLEEP && VLP) { u8 i; // See if a frame is stored for this node for (i=0;i<STORED_FRAMES;i++) { if (storedFrames[i].len && storedFrames[i].addr == addr) { // Send this frame, remove checksum uint8_t* pFrame = bmm_buffer_alloc(); if(pFrame != NULL) { // restore stored frame memcpy(((rx_frame_t*)pFrame)->data, storedFrames[i].buf, storedFrames[i].len); ((rx_frame_t*)pFrame)->length = storedFrames[i].len; event_object_t event; event.event = MAC_EVENT_SEND; event.data = pFrame; event.callback = 0; // save Event mac_put_event(&event); // Clear out this frame storedFrames[i].len = 0; } } } } }
bool wpan_mlme_reset_req(bool SetDefaultPib) { buffer_t *buffer_header; mlme_reset_req_t *mlme_reset_req; /* Allocate a small buffer for reset request */ buffer_header = bmm_buffer_alloc(LARGE_BUFFER_SIZE); if (NULL == buffer_header) { /* Buffer is not available */ return false; } /* Get the buffer body from buffer header */ mlme_reset_req = (mlme_reset_req_t *)BMM_BUFFER_POINTER(buffer_header); /* Update the reset request structure */ mlme_reset_req->cmdcode = MLME_RESET_REQUEST; mlme_reset_req->SetDefaultPIB = SetDefaultPib; #ifdef ENABLE_QUEUE_CAPACITY if (MAC_SUCCESS != qmm_queue_append(&nhle_mac_q, buffer_header)) { /* * MLME-RESET.request is not appended into NHLE MAC * queue, hence free the buffer allocated and return false */ bmm_buffer_free(buffer_header); return false; } #else qmm_queue_append(&nhle_mac_q, buffer_header); #endif /* ENABLE_QUEUE_CAPACITY */ return true; }
bool wpan_mcps_purge_req(uint8_t msduHandle) { buffer_t *buffer_header; mcps_purge_req_t *mcps_purge_req; /* Allocate small buffer for mcps purge request */ buffer_header = bmm_buffer_alloc(LARGE_BUFFER_SIZE); if (NULL == buffer_header) { /* Buffer is not available */ return false; } /* Get the buffer body from buffer header */ mcps_purge_req = (mcps_purge_req_t *)BMM_BUFFER_POINTER(buffer_header); /* Update the purge request structure */ mcps_purge_req->cmdcode = MCPS_PURGE_REQUEST; mcps_purge_req->msduHandle = msduHandle; #ifdef ENABLE_QUEUE_CAPACITY if (MAC_SUCCESS != qmm_queue_append(&nhle_mac_q, buffer_header)) { /* * MCPS-PURGE.request is not appended into NHLE MAC * queue, hence free the buffer allocated and return false */ bmm_buffer_free(buffer_header); return false; } #else qmm_queue_append(&nhle_mac_q, buffer_header); #endif /* ENABLE_QUEUE_CAPACITY */ return true; }
/** * @brief Initializes the TAL * * This function is called to initialize the TAL. The transceiver is * initialized, the TAL PIBs are set to their default values, and the TAL state * machine is set to TAL_IDLE state. * * @return MAC_SUCCESS if the transceiver state is changed to TRX_OFF and the * current device part number and version number are correct; * FAILURE otherwise */ retval_t tal_init(void) { /* Init the PAL and by this means also the transceiver interface */ if (pal_init() != MAC_SUCCESS) { return FAILURE; } if (trx_init() != MAC_SUCCESS) { return FAILURE; } #if (EXTERN_EEPROM_AVAILABLE == 1) pal_ps_get(EXTERN_EEPROM, EE_IEEE_ADDR, 8, &tal_pib.IeeeAddress); #else pal_ps_get(INTERN_EEPROM, EE_IEEE_ADDR, 8, &tal_pib.IeeeAddress); #endif /* * Do the reset stuff. * Set the default PIBs. * Generate random seed. */ if (internal_tal_reset(true) != MAC_SUCCESS) { return FAILURE; } #ifndef DISABLE_IEEE_ADDR_CHECK /* Check if a valid IEEE address is available. */ /* * This while loop is on purpose, since just in the * rare case that such an address is randomly * generated again, we must repeat this. */ while ((tal_pib.IeeeAddress == 0x0000000000000000) || (tal_pib.IeeeAddress == 0xFFFFFFFFFFFFFFFF) ) { /* * In case no valid IEEE address is available, a random * IEEE address will be generated to be able to run the * applications for demonstration purposes. * In production code this can be omitted. */ /* * The proper seed for function rand() has already been generated * in function tal_generate_rand_seed(). */ uint8_t *ptr_pib = (uint8_t *)&tal_pib.IeeeAddress; for (uint8_t i = 0; i < 8; i++) { *ptr_pib++ = (uint8_t)rand(); /* * Note: * Even if casting the 16 bit rand value back to 8 bit, * and running the loop 8 timers (instead of only 4 times) * may look cumbersome, it turns out that the code gets * smaller using 8-bit here. * And timing is not an issue at this place... */ } } #endif /* #ifndef DISABLE_IEEE_ADDR_CHECK */ /* * Configure interrupt handling. * Install handlers for the transceiver interrupts. */ pal_trx_irq_init_rx_end((FUNC_PTR)trx_rx_end_handler_cb); pal_trx_irq_init_tx_end((FUNC_PTR)trx_tx_end_handler_cb); pal_trx_irq_init_awake((FUNC_PTR)trx_awake_handler_cb); #if (defined BEACON_SUPPORT) || (defined ENABLE_TSTAMP) /* Configure time stamp interrupt. */ pal_trx_irq_init_tstamp((FUNC_PTR)trx_irq_timestamp_handler_cb); #endif /* (defined BEACON_SUPPORT) || (defined ENABLE_TSTAMP) */ /* Initialize the buffer management module and get a buffer to store reveived frames. */ bmm_buffer_init(); tal_rx_buffer = bmm_buffer_alloc(LARGE_BUFFER_SIZE); /* Init incoming frame queue */ #ifdef ENABLE_QUEUE_CAPACITY qmm_queue_init(&tal_incoming_frame_queue, TAL_INCOMING_FRAME_QUEUE_CAPACITY); #else qmm_queue_init(&tal_incoming_frame_queue); #endif /* ENABLE_QUEUE_CAPACITY */ #ifdef ENABLE_TFA tfa_init(); #endif return MAC_SUCCESS; } /* tal_init() */
/** * @brief TAL task handling * * This function * - Checks and allocates the receive buffer. * - Processes the TAL incoming frame queue. * - Implements the TAL state machine. */ void tal_task(void) { /* Check if the receiver needs to be switched on. */ if (tal_rx_on_required && (tal_state == TAL_IDLE)) { /* Check if a receive buffer has not been available before. */ if (tal_rx_buffer == NULL) { tal_rx_buffer = bmm_buffer_alloc(LARGE_BUFFER_SIZE); } /* Check if buffer could be allocated */ if (NULL != tal_rx_buffer) { /* * Note: * This flag needs to be reset BEFORE the received is switched on. */ tal_rx_on_required = false; #ifdef PROMISCUOUS_MODE if (tal_pib.PromiscuousMode) { set_trx_state(CMD_RX_ON); } else { set_trx_state(CMD_RX_AACK_ON); } #else /* Normal operation */ set_trx_state(CMD_RX_AACK_ON); #endif } } else { /* no free buffer is available; try next time again */ } /* * If the transceiver has received a frame and it has been placed * into the queue of the TAL, the frame needs to be processed further. */ if (tal_incoming_frame_queue.size > 0) { buffer_t *rx_frame; /* Check if there are any pending data in the incoming_frame_queue. */ rx_frame = qmm_queue_remove(&tal_incoming_frame_queue, NULL); if (NULL != rx_frame) { process_incoming_frame(rx_frame); } } /* Handle the TAL state machines */ switch (tal_state) { case TAL_IDLE: /* Do nothing, but fall through... */ case TAL_TX_AUTO: /* Wait until state is changed to TAL_TX_DONE inside tx end ISR */ break; case TAL_TX_DONE: tx_done_handling(); // see tal_tx.c break; #ifdef BEACON_SUPPORT case TAL_SLOTTED_CSMA: slotted_csma_state_handling(); // see tal_slotted_csma.c break; #endif /* BEACON_SUPPORT */ #if (MAC_SCAN_ED_REQUEST_CONFIRM == 1) case TAL_ED_RUNNING: /* Do nothing here. Wait until ED is completed. */ break; case TAL_ED_DONE: ed_scan_done(); break; #endif /* (MAC_SCAN_ED_REQUEST_CONFIRM == 1) */ default: ASSERT("tal_state is not handled" == 0); break; } } /* tal_task() */
/* * \brief Handle received frame interrupt * * This function handles transceiver interrupts for received frames and * uploads the frames from the trx. */ void handle_received_frame_irq(void) { uint8_t ed_value; /* Actual frame length of received frame. */ uint8_t phy_frame_len; /* Extended frame length appended by LQI and ED. */ uint8_t ext_frame_length; frame_info_t *receive_frame; uint8_t *frame_ptr; if (tal_rx_buffer == NULL) { Assert("no tal_rx_buffer available" == 0); /* * Although the buffer protection mode is enabled and the receiver has * been switched to PLL_ON, the next incoming frame was faster. * It cannot be handled and is discarded. */ pal_trx_bit_write(SR_RX_SAFE_MODE, RX_SAFE_MODE_DISABLE); /* Disable buffer protection mode */ pal_timer_delay(2); // Allow pin change to get effective pal_trx_bit_write(SR_RX_SAFE_MODE, RX_SAFE_MODE_ENABLE); /* Enable buffer protection mode */ return; } receive_frame = (frame_info_t *)BMM_BUFFER_POINTER(tal_rx_buffer); #ifdef PROMISCUOUS_MODE if (tal_pib.PromiscuousMode) { /* Check for valid FCS */ if (pal_trx_bit_read(SR_RX_CRC_VALID) == CRC16_NOT_VALID) { return; } } #endif /* Get ED value; needed to normalize LQI. */ ed_value = pal_trx_reg_read(RG_PHY_ED_LEVEL); /* Get frame length from transceiver. */ phy_frame_len = ext_frame_length = pal_trx_reg_read(RG_TST_RX_LENGTH); /* Check for valid frame length. */ if (phy_frame_len > 127) { return; } /* * The PHY header is also included in the frame (length field), hence the frame length * is incremented. * In addition to that, the LQI and ED value are uploaded, too. */ ext_frame_length += LQI_LEN + ED_VAL_LEN; /* Update payload pointer to store received frame. */ frame_ptr = (uint8_t *)receive_frame + LARGE_BUFFER_SIZE - ext_frame_length; /* * Note: The following code is different from other non-single chip * transceivers, where reading the frame via SPI contains the length field * in the first octet. */ pal_trx_frame_read(frame_ptr, phy_frame_len + LQI_LEN); frame_ptr--; *frame_ptr = phy_frame_len; receive_frame->mpdu = frame_ptr; /* Add ED value at the end of the frame buffer. */ receive_frame->mpdu[phy_frame_len + LQI_LEN + ED_VAL_LEN] = ed_value; #if (defined BEACON_SUPPORT) || (defined ENABLE_TSTAMP) /* * Store the timestamp. * The timestamping is only required for beaconing networks * or if timestamping is explicitly enabled. */ receive_frame->time_stamp = tal_rx_timestamp; #endif /* #if (defined BEACON_SUPPORT) || (defined ENABLE_TSTAMP) */ /* Append received frame to incoming_frame_queue and get new rx buffer. */ qmm_queue_append(&tal_incoming_frame_queue, tal_rx_buffer); /* The previous buffer is eaten up and a new buffer is not assigned yet. */ tal_rx_buffer = bmm_buffer_alloc(LARGE_BUFFER_SIZE); /* Check if receive buffer is available */ if (NULL == tal_rx_buffer) { /* * Turn off the receiver until a buffer is available again. * tal_task() will take care of eventually reactivating it. * Due to ongoing ACK transmission do not force to switch it off. */ /* Do not change the state since buffer protection mode is not re-enabled yet. * Buffer protection will be re-enabled after buffer becomes available */ //set_trx_state(CMD_PLL_ON); tal_rx_on_required = true; } else { /* * Trx returns to RX_AACK_ON automatically, if this was its previous state. * Keep the following as a reminder, if receiver is used with RX_ON instead. */ //pal_trx_reg_write(RG_TRX_STATE, CMD_RX_AACK_ON); /* * Release the protected buffer and set it again for further protection since * the buffer is available */ pal_trx_bit_write(SR_RX_SAFE_MODE, RX_SAFE_MODE_DISABLE); /* Disable buffer protection mode */ pal_timer_delay(2); // Allow pin change to get effective pal_trx_bit_write(SR_RX_SAFE_MODE, RX_SAFE_MODE_ENABLE); /* Enable buffer protection mode */ } /* * Clear pending TX_END IRQ: The TX_END IRQ is envoked for the transmission * end of an automatically sent ACK frame. This implementation does not use * this feature. */ pal_trx_irq_flag_clr_tx_end(); }
/* * @brief Continues handling of MLME_SCAN.request once the radio is awake * * @param scan_buf Pointer to Scan request buffer. */ static void mac_awake_scan(buffer_t *scan_buf) { mlme_scan_conf_t *msc; msc = (mlme_scan_conf_t *)BMM_BUFFER_POINTER(scan_buf); /* Set the first channel at which the scan is started */ scan_curr_channel = MIN_CHANNEL; switch (scan_type) { #if (MAC_SCAN_ED_REQUEST_CONFIRM == 1) case MLME_SCAN_TYPE_ED: msc->scan_result_list[0].ed_value[1] = 0; /* First channel's * accumulated energy * level */ mac_scan_state = MAC_SCAN_ED; scan_proceed(MLME_SCAN_TYPE_ED, (buffer_t *)scan_buf); break; #endif /* (MAC_SCAN_ED_REQUEST_CONFIRM == 1) */ #if ((MAC_SCAN_ACTIVE_REQUEST_CONFIRM == 1) || \ (MAC_SCAN_PASSIVE_REQUEST_CONFIRM == 1)) case MLME_SCAN_TYPE_ACTIVE: case MLME_SCAN_TYPE_PASSIVE: { /* * Before commencing an active or passive scan, the MAC sublayer * shall store the value of macPANId and then set it to 0cFFFF * for * the duration of the scan. This enables the receive filter to * accept all beacons rather than just the beacons from its * current PAN (see 7.5.6.2). On completion of the scan, the * MAC sublayer shall restore the value of macPANId to the * value stored before the scan began. */ uint16_t broadcast_panid = BROADCAST; mac_scan_orig_panid = tal_pib.PANId; #if (_DEBUG_ > 0) retval_t set_status = #endif set_tal_pib_internal(macPANId, (void *)&broadcast_panid); #if (_DEBUG_ > 0) Assert(MAC_SUCCESS == set_status); set_status = set_status; #endif if (MLME_SCAN_TYPE_ACTIVE == scan_type) { /* * In active scan reuse the scan request buffer for * sending beacon request. */ mac_scan_cmd_buf_ptr = (uint8_t *)scan_buf; } /* Allocate a large size buffer for scan confirm. */ mac_conf_buf_ptr = (uint8_t *)bmm_buffer_alloc(LARGE_BUFFER_SIZE); if (NULL == mac_conf_buf_ptr) { /* * Large buffer is not available for sending scan * confirmation, * hence the scan request buffer (small buffer) is used * to send * the scan confirmation. */ msc->status = MAC_INVALID_PARAMETER; /* Append scan confirm message to the MAC-NHLE queue */ qmm_queue_append(&mac_nhle_q, scan_buf); /* Set radio to sleep if allowed */ mac_sleep_trans(); return; } if (MLME_SCAN_TYPE_PASSIVE == scan_type) { /* Free the scan request buffer when in passive scan. */ bmm_buffer_free(scan_buf); } msc = (mlme_scan_conf_t *)BMM_BUFFER_POINTER( (buffer_t *)mac_conf_buf_ptr); msc->cmdcode = MLME_SCAN_CONFIRM; msc->ScanType = scan_type; msc->ChannelPage = scan_curr_page; msc->UnscannedChannels = scan_channels; msc->ResultListSize = 0; msc->scan_result_list[0].ed_value[0] = 0; scan_proceed(scan_type, (buffer_t *)mac_conf_buf_ptr); break; } #endif /* ((MAC_SCAN_ACTIVE_REQUEST_CONFIRM == 1) || *(MAC_SCAN_PASSIVE_REQUEST_CONFIRM == 1)) */ #if (MAC_SCAN_ORPHAN_REQUEST_CONFIRM == 1) case MLME_SCAN_TYPE_ORPHAN: /* Buffer allocated for orphan notification command */ mac_scan_cmd_buf_ptr = (uint8_t *)bmm_buffer_alloc(LARGE_BUFFER_SIZE); if (NULL == mac_scan_cmd_buf_ptr) { msc->status = MAC_INVALID_PARAMETER; /* Append scan confirm message to the MAC-NHLE queue */ qmm_queue_append(&mac_nhle_q, scan_buf); /* Set radio to sleep if allowed */ mac_sleep_trans(); return; } scan_proceed(MLME_SCAN_TYPE_ORPHAN, (buffer_t *)mac_conf_buf_ptr); break; #endif /* (MAC_SCAN_ORPHAN_REQUEST_CONFIRM == 1) */ default: msc->status = MAC_INVALID_PARAMETER; /* Append scan confirm message to the MAC-NHLE queue */ qmm_queue_append(&mac_nhle_q, scan_buf); /* Set radio to sleep if allowed */ mac_sleep_trans(); break; } } /* mac_awake_scan() */
/* * @brief Constructs a null data frame * * @return Pointer to the created null data frame, NULL otherwise. */ static buffer_t *build_null_data_frame(void) { bool use_long_addr_dest; frame_info_t *transmit_frame; uint8_t frame_len; uint8_t *frame_ptr; uint16_t fcf = 0; buffer_t *buf_ptr = bmm_buffer_alloc(LARGE_BUFFER_SIZE); if (NULL == buf_ptr) { return NULL; } transmit_frame = (frame_info_t *)BMM_BUFFER_POINTER(buf_ptr); /* No data payload, this is a null packet.*/ transmit_frame->msg_type = NULL_FRAME; transmit_frame->buffer_header = buf_ptr; /* No indirect transmission. */ transmit_frame->indirect_in_transit = false; /* Update the payload length. */ frame_len = 2 + // Add 2 octets for FCS 2 + // 2 octets for short Destination Address 2 + // 2 octets for Destination PAN-Id 2 + // 2 octets for short Source Address 3; // 3 octets DSN and FCF /* Get the payload pointer. */ frame_ptr = (uint8_t *)transmit_frame + LARGE_BUFFER_SIZE - 2; /* Add 2 octets for FCS. */ /* * Set Source Address. */ if ((BROADCAST == tal_pib.ShortAddress) || (MAC_NO_SHORT_ADDR_VALUE == tal_pib.ShortAddress) ) { /* Use long address as source address. */ frame_ptr -= 8; frame_len += 6; convert_64_bit_to_byte_array(tal_pib.IeeeAddress, frame_ptr); fcf |= FCF_SET_SOURCE_ADDR_MODE(FCF_LONG_ADDR); } else { /* Use short address as source address. */ frame_ptr -= 2; convert_16_bit_to_byte_array(tal_pib.ShortAddress, frame_ptr); fcf |= FCF_SET_SOURCE_ADDR_MODE(FCF_SHORT_ADDR); } /* Shall the Intra-PAN bit set? */ if (tal_pib.PANId == mac_parse_data.src_panid) { /* * Both PAN-Ids are identical. * Set intra-PAN bit. */ fcf |= FCF_PAN_ID_COMPRESSION; } else { /* Set Source PAN-Id. */ frame_ptr -= 2; frame_len += 2; convert_16_bit_to_byte_array(tal_pib.PANId, frame_ptr); } /* Set Destination Address. */ use_long_addr_dest = (FCF_LONG_ADDR == mac_parse_data.src_addr_mode); /* Destination address is set from source address of received frame. */ if (use_long_addr_dest) { frame_ptr -= 8; frame_len += 6; convert_64_bit_to_byte_array(mac_parse_data.src_addr.long_address, frame_ptr); fcf |= FCF_SET_DEST_ADDR_MODE(FCF_LONG_ADDR) | FCF_SET_FRAMETYPE(FCF_FRAMETYPE_DATA); } else { frame_ptr -= 2; convert_16_bit_to_byte_array(mac_parse_data.src_addr.short_address, frame_ptr); fcf |= FCF_SET_DEST_ADDR_MODE(FCF_SHORT_ADDR) | FCF_SET_FRAMETYPE(FCF_FRAMETYPE_DATA); } /* Destination PANId is set from source PANId of received frame. */ frame_ptr -= 2; convert_16_bit_to_byte_array(mac_parse_data.src_panid, frame_ptr); /* Set DSN. */ frame_ptr--; *frame_ptr = mac_pib.mac_DSN++; /* Set the FCF. */ frame_ptr -= 2; convert_spec_16_bit_to_byte_array(fcf, frame_ptr); /* First element shall be length of PHY frame. */ frame_ptr--; *frame_ptr = frame_len; /* Finished building of frame. */ transmit_frame->mpdu = frame_ptr; return buf_ptr; } /* build_null_data_frame() */
/** * @brief Build and transmits data request command frame * * This function builds and tranmits a data request command frame. * * * @param expl_poll Data request due to explicit MLME poll request * @param force_own_long_addr Forces the usage of the Extended Address as * Source Address. This a allows for implicitly * poll for pending data at the coordinator if * the Extended Address was used in the Beacon frame. * @param expl_dest_addr_mode Mode of subsequent destination address to be used * explicitly (0/2/3). * 0: No explicit destination address attached, * use either macCoordShortAddress or * macCoordExtendedAddress * 2: Use explicitly attached address in parameter * expl_dest_addr as destination address as * short address * 3: Use explicitly attached address in parameter * expl_dest_addr as destination address as * extended address * @param expl_dest_addr Explicitly attached destination address for data * request frame. This is to be treated as either not * present, short or extended address, depending on * parameter expl_dest_addr_mode. * @param expl_dest_pan_id Explicitly attached destination PAN-Id (Coordinator * PAN-Id) for data request frame. * This is to be treated only as present, depending on * parameter expl_dest_addr_mode. * * @return True if data request command frame was created and sent to * the TAL successfully, false otherwise. */ bool mac_build_and_tx_data_req(bool expl_poll, bool force_own_long_addr, uint8_t expl_dest_addr_mode, address_field_t *expl_dest_addr, uint16_t expl_dest_pan_id) { retval_t tal_tx_status; bool intrabit = false; uint8_t frame_len; uint8_t *frame_ptr; uint16_t fcf; buffer_t *buf_ptr = bmm_buffer_alloc(LARGE_BUFFER_SIZE); if (NULL == buf_ptr) { return false; } frame_info_t *transmit_frame = (frame_info_t *)BMM_BUFFER_POINTER(buf_ptr); /* * If this data request cmd frame was initiated by a device due to implicit * poll, set msgtype to DATAREQUEST_IMPL_POLL. * If this data request cmd frame was initiated by a MLME poll request, * set msgtype to DATAREQUEST. */ if (expl_poll) { transmit_frame->msg_type = DATAREQUEST; } else { transmit_frame->msg_type = DATAREQUEST_IMPL_POLL; } /* * The buffer header is stored as a part of frame_info_t structure before the * frame is given to the TAL. After the transmission of the frame, reuse * the buffer using this pointer. */ transmit_frame->buffer_header = buf_ptr; /* Update the payload length. */ frame_len = DATA_REQ_PAYLOAD_LEN + 2 + // Add 2 octets for FCS 2 + // 2 octets for short Source Address 2 + // 2 octets for short Destination Address 2 + // 2 octets for Destination PAN-Id 3; // 3 octets DSN and FCF /* Get the payload pointer. */ frame_ptr = (uint8_t *)transmit_frame + LARGE_BUFFER_SIZE - DATA_REQ_PAYLOAD_LEN - 2; /* Add 2 octets for FCS. */ /* * Build the command frame id. * This is actually being written into "transmit_frame->layload[0]". */ *frame_ptr = DATAREQUEST; /* Source Address */ /* * Long address needs to be used if a short address is not present * or if we are forced to use the long address. * * This is used for example in cases where the coordinator indicates * pending data for us using our extended address. * * This is also used for transmitting a data request frame * during association, since here we always need to use our * extended address. */ if ((BROADCAST == tal_pib.ShortAddress) || (CCPU_ENDIAN_TO_LE16(MAC_NO_SHORT_ADDR_VALUE) == tal_pib.ShortAddress) || force_own_long_addr) { frame_ptr -= 8; frame_len += 6; // Add further 6 octets for long Source Address /* Build the Source address. */ convert_64_bit_to_byte_array(tal_pib.IeeeAddress, frame_ptr); fcf = FCF_SET_FRAMETYPE(FCF_FRAMETYPE_MAC_CMD) | FCF_SET_SOURCE_ADDR_MODE(FCF_LONG_ADDR) | FCF_ACK_REQUEST; } else { frame_ptr -= 2; /* Build the Source address. */ convert_16_bit_to_byte_array(tal_pib.ShortAddress, frame_ptr); fcf = FCF_SET_FRAMETYPE(FCF_FRAMETYPE_MAC_CMD) | FCF_SET_SOURCE_ADDR_MODE(FCF_SHORT_ADDR) | FCF_ACK_REQUEST; } /* Source PAN-Id */ /* * In IEEE 802.15.4 the PAN ID Compression bit may always be set. * See page 154: * If the data request command is being sent in response to the receipt * of a beacon frame indicating that data are pending for that device, * the Destination Addressing Mode subfield of the Frame Control field * may be set to zero ..." * In order to keep the implementation simple the address info is also in * this case 2 or 3, i.e. the destination address info is present. * This in return means that the PAN ID Compression bit is always set for * data request frames, except the expl_dest_pan_id parameter is different from * our own PAN-Id PIB attribute. */ if ((expl_dest_addr_mode != FCF_NO_ADDR) && (expl_dest_pan_id != tal_pib.PANId) ) { frame_ptr -= 2; frame_len += 2; // Add further 6 octets for long Source Pan-Id convert_16_bit_to_byte_array(tal_pib.PANId, frame_ptr); } else { /* * The source PAN Id is not present since the PAN ID * Compression bit is set. */ /* Set intra-PAN bit. */ intrabit = true; fcf |= FCF_PAN_ID_COMPRESSION; } /* Destination Address */ if (FCF_SHORT_ADDR == expl_dest_addr_mode) { /* An explicit short destination address is requested. */ fcf |= FCF_SET_DEST_ADDR_MODE(FCF_SHORT_ADDR); frame_ptr -= 2; convert_16_bit_to_byte_array(expl_dest_addr->short_address, frame_ptr); } else if (FCF_LONG_ADDR == expl_dest_addr_mode) { /* An explicit long destination address is requested. */ fcf |= FCF_SET_DEST_ADDR_MODE(FCF_LONG_ADDR); frame_ptr -= 8; frame_len += 6; // Add further 6 octets for long Destination Address convert_64_bit_to_byte_array(expl_dest_addr->long_address, frame_ptr); } else { /* No explicit destination address is requested. */ if (CCPU_ENDIAN_TO_LE16(MAC_NO_SHORT_ADDR_VALUE) != mac_pib.mac_CoordShortAddress) { /* * If current value of short address for coordinator PIB is * NOT 0xFFFE, the current value of the short address for * coordinator shall be used as desination address. */ fcf |= FCF_SET_DEST_ADDR_MODE(FCF_SHORT_ADDR); frame_ptr -= 2; convert_16_bit_to_byte_array(mac_pib.mac_CoordShortAddress, frame_ptr); } else { /* * If current value of short address for coordinator PIB is 0xFFFE, * the current value of the extended address for coordinator * shall be used as desination address. */ fcf |= FCF_SET_DEST_ADDR_MODE(FCF_LONG_ADDR); frame_ptr -= 8; frame_len += 6; // Add further 6 octets for long Destination Address convert_64_bit_to_byte_array(mac_pib.mac_CoordExtendedAddress, frame_ptr); } } /* Destination PAN-Id */ frame_ptr -= 2; if (intrabit) { /* Add our PAN-Id. */ convert_16_bit_to_byte_array(tal_pib.PANId, frame_ptr); } else { /* * There is an expclicit destination address present AND * the destination PAN-Id is different from our own PAN-ID, * so include the source PAN-id into the frame. */ convert_16_bit_to_byte_array(expl_dest_pan_id, frame_ptr); } /* Set DSN. */ frame_ptr--; *frame_ptr = mac_pib.mac_DSN++; /* Set the FCF. */ frame_ptr -= 2; convert_spec_16_bit_to_byte_array(fcf, frame_ptr); /* First element shall be length of PHY frame. */ frame_ptr--; *frame_ptr = frame_len; /* Finished building of frame. */ transmit_frame->mpdu = frame_ptr; /* Transmission should be done with CSMA-CA and frame retries. */ #ifdef BEACON_SUPPORT /* * Now it gets tricky: * In Beacon network the frame is sent with slotted CSMA-CA only if: * 1) the node is associated, or * 2) the node is idle, but synced before association, * 3) the node is a Coordinator (we assume, that coordinators are always * in sync with their parents). * * In all other cases, the frame has to be sent using unslotted CSMA-CA. */ csma_mode_t cur_csma_mode; if (NON_BEACON_NWK != tal_pib.BeaconOrder) { if ( ((MAC_IDLE == mac_state) && (MAC_SYNC_BEFORE_ASSOC == mac_sync_state)) || #if (MAC_START_REQUEST_CONFIRM == 1) (MAC_ASSOCIATED == mac_state) || (MAC_COORDINATOR == mac_state) #else (MAC_ASSOCIATED == mac_state) #endif /* MAC_START_REQUEST_CONFIRM */ ) { cur_csma_mode = CSMA_SLOTTED; } else { cur_csma_mode = CSMA_UNSLOTTED; } } else { /* In Nonbeacon network the frame is sent with unslotted CSMA-CA. */ cur_csma_mode = CSMA_UNSLOTTED; } tal_tx_status = tal_tx_frame(transmit_frame, cur_csma_mode, true); #else /* No BEACON_SUPPORT */ /* In Nonbeacon build the frame is sent with unslotted CSMA-CA. */ tal_tx_status = tal_tx_frame(transmit_frame, CSMA_UNSLOTTED, true); #endif /* BEACON_SUPPORT */ if (MAC_SUCCESS == tal_tx_status) { MAKE_MAC_BUSY(); return true; } else { /* TAL is busy, hence the data request could not be transmitted */ bmm_buffer_free(buf_ptr); return false; } } /* mac_build_and_tx_data_req() */
/* * \brief Handle received frame interrupt * * This function handles transceiver interrupts for received frames and * uploads the frames from the trx. */ void handle_received_frame_irq(void) { /* Actual frame length of received frame. */ uint8_t phy_frame_len; /* Extended frame length appended by LQI and ED. */ uint8_t ext_frame_length; frame_info_t *receive_frame; uint8_t *frame_ptr; if (tal_rx_buffer == NULL) { Assert("no tal_rx_buffer available" == 0); /* * Although the buffer protection mode is enabled and the *receiver has * been switched to PLL_ON, the next incoming frame was faster. * It cannot be handled and is discarded. Reading anything from *the * frame resets the buffer protection mode. */ uint8_t dummy; trx_frame_read(&dummy, 1); return; } receive_frame = (frame_info_t *)BMM_BUFFER_POINTER(tal_rx_buffer); #ifdef PROMISCUOUS_MODE if (tal_pib.PromiscuousMode) { /* Check for valid FCS */ if (trx_bit_read(SR_RX_CRC_VALID) == CRC16_NOT_VALID) { return; } } #endif #if (defined ENABLE_TRX_SRAM) || defined(ENABLE_TRX_SRAM_READ) /* Use SRAM read to keep rx safe mode armed. */ trx_sram_read(0x00, &phy_frame_len, LENGTH_FIELD_LEN); /* 0x00: SRAM * offset address */ #else /* Get frame length from transceiver. */ trx_frame_read(&phy_frame_len, LENGTH_FIELD_LEN); #endif /* Check for valid frame length. */ if (phy_frame_len > 127) { return; } /* * The PHY header is also included in the frame (length field), hence *the frame length * is incremented. * In addition to that, the LQI and ED value are uploaded, too. */ ext_frame_length = phy_frame_len + LENGTH_FIELD_LEN + LQI_LEN + ED_VAL_LEN; /* Update payload pointer to store received frame. */ frame_ptr = (uint8_t *)receive_frame + LARGE_BUFFER_SIZE - ext_frame_length; /* * Note: The following code is different from single chip * transceivers, since reading the frame via SPI contains the length *field * in the first octet. RF232's frame buffer includes ED value too. */ trx_frame_read(frame_ptr, LENGTH_FIELD_LEN + phy_frame_len + LQI_LEN + ED_VAL_LEN); receive_frame->mpdu = frame_ptr; #if (defined BEACON_SUPPORT) || (defined ENABLE_TSTAMP) /* * Store the timestamp. * The timestamping is only required for beaconing networks * or if timestamping is explicitly enabled. */ receive_frame->time_stamp = tal_timestamp; #endif /* #if (defined BEACON_SUPPORT) || (defined ENABLE_TSTAMP) */ /* Append received frame to incoming_frame_queue and get new rx buffer. **/ qmm_queue_append(&tal_incoming_frame_queue, tal_rx_buffer); /* The previous buffer is eaten up and a new buffer is not assigned yet. **/ tal_rx_buffer = bmm_buffer_alloc(LARGE_BUFFER_SIZE); /* Check if receive buffer is available */ if (NULL == tal_rx_buffer) { /* * Turn off the receiver until a buffer is available again. * tal_task() will take care of eventually reactivating it. * Due to ongoing ACK transmission do not force to switch it *off. */ set_trx_state(CMD_PLL_ON); tal_rx_on_required = true; } else { /* * Trx returns to RX_AACK_ON automatically, if this was its *previous state. * Keep the following as a reminder, if receiver is used with *RX_ON instead. */ /* trx_reg_write(RG_TRX_STATE, CMD_RX_AACK_ON); */ } }
/** * @brief Initializes the TAL * * This function is called to initialize the TAL. The transceiver is * initialized, the TAL PIBs are set to their default values, and the TAL state * machine is set to TAL_IDLE state. * * @return MAC_SUCCESS if the transceiver state is changed to TRX_OFF and the * current device part number and version number are correct; * FAILURE otherwise */ retval_t tal_init(void) { /* Init the PAL and by this means also the transceiver interface */ #ifdef ENABLE_RP /* * The ranging processor (RP) only performs a minimalistic * initialization here. */ pal_basic_init(); #else /* !ENABLE_RP */ if (pal_init() != MAC_SUCCESS) { return FAILURE; } if (trx_init() != MAC_SUCCESS) { return FAILURE; } #if (EXTERN_EEPROM_AVAILABLE == 1) pal_ps_get(EXTERN_EEPROM, EE_IEEE_ADDR, 8, &tal_pib.IeeeAddress); #else #if (USER_SIGN_AVAILABLE == 1) pal_ps_get(USER_SIGNATURE, USER_SIGNATURES_START + 2, 8, &tal_pib.IeeeAddress); //http://www.atmel.com/Images/Atmel-42172-Wireless-ZigBit-ATZB-X0-256-3-0-C_Datasheet.pdf #else pal_ps_get(INTERN_EEPROM, EE_IEEE_ADDR, 8, &tal_pib.IeeeAddress); #endif #endif /* * Do the reset stuff. * Set the default PIBs. * Generate random seed. */ if (internal_tal_reset(true) != MAC_SUCCESS) { return FAILURE; } #ifndef DISABLE_IEEE_ADDR_CHECK /* Check if a valid IEEE address is available. */ /* * This while loop is on purpose, since just in the * rare case that such an address is randomly * generated again, we must repeat this. */ while ((tal_pib.IeeeAddress == 0x0000000000000000) || (tal_pib.IeeeAddress == 0xFFFFFFFFFFFFFFFF)) { /* * In case no valid IEEE address is available, a random * IEEE address will be generated to be able to run the * applications for demonstration purposes. * In production code this can be omitted. */ /* * The proper seed for function rand() has already been generated * in function tal_generate_rand_seed(). */ uint8_t *ptr_pib = (uint8_t *)&tal_pib.IeeeAddress; for (uint8_t i = 0; i < 8; i++) { *ptr_pib++ = (uint8_t)rand(); /* * Note: * Even if casting the 16 bit rand value back to 8 bit, * and running the loop 8 timers (instead of only 4 times) * may look cumbersome, it turns out that the code gets * smaller using 8-bit here. * And timing is not an issue at this place... */ } } #endif /* #ifndef DISABLE_IEEE_ADDR_CHECK */ #endif /* ENABLE_RP */ /* * Configure interrupt handling. * Install a handler for the transceiver interrupt. */ pal_trx_irq_init(trx_irq_handler_cb); #ifndef ENABLE_RP pal_trx_irq_en(); /* Enable transceiver main interrupt. */ #endif #if ((defined BEACON_SUPPORT) || (defined ENABLE_TSTAMP)) && (DISABLE_TSTAMP_IRQ == 0) /* Configure time stamp interrupt. */ pal_trx_irq_init_tstamp(trx_irq_timestamp_handler_cb); #ifndef ENABLE_RP pal_trx_irq_en_tstamp(); /* Enable timestamp interrupt. */ #endif #endif /* Initialize the buffer management module and get a buffer to store received frames. */ bmm_buffer_init(); tal_rx_buffer = bmm_buffer_alloc(LARGE_BUFFER_SIZE); #if DEBUG > 0 if (tal_rx_buffer == NULL) { return FAILURE; } #endif /* Init incoming frame queue */ #ifdef ENABLE_QUEUE_CAPACITY qmm_queue_init(&tal_incoming_frame_queue, TAL_INCOMING_FRAME_QUEUE_CAPACITY); #else qmm_queue_init(&tal_incoming_frame_queue); #endif /* ENABLE_QUEUE_CAPACITY */ #ifdef ENABLE_TFA tfa_init(); #endif return MAC_SUCCESS; } /* tal_init() */
/*! \brief This function will upload a frame from the radio transceiver's frame * buffer. * * If the frame currently available in the radio transceiver's frame buffer * is out of the defined bounds. Then the frame length, lqi value and crc * be set to zero. This is done to indicate an error. * */ uint8_t* hal_frame_read(void) { uint8_t* pFrame = bmm_buffer_alloc(); if(pFrame != NULL) { rx_frame_t *rx_frame = (rx_frame_t*)pFrame; #ifdef SINGLE_CHIP AVR_ENTER_CRITICAL_REGION(); volatile uint8_t *pSrc = (volatile uint8_t *)0x180; uint8_t frame_length = hal_register_read(RG_TST_RX_LENGTH); if ((frame_length >= HAL_MIN_FRAME_LENGTH) && (frame_length <= HAL_MAX_FRAME_LENGTH)) { // read length and save frame content -> lqi is NOT included in frame length byte rx_frame->length = frame_length; //memcpy(rx_data, (void *)pSrc, frame_length); memcpy(rx_frame->data, (void *)pSrc, frame_length-1); // save LQI / //rx_frame->lqi = *(pSrc + (frame_length + 1)); rx_frame->lqi = *(pSrc + frame_length); } else { rx_frame->length = 0; rx_frame->lqi = 0; rx_frame->crc = false; bmm_buffer_free(pFrame); // free allcoated buffer pFrame = NULL; // set buffer pointer to NULL, that next app do not use it } AVR_LEAVE_CRITICAL_REGION(); #else uint8_t* rx_data = &rx_frame->data[0]; AVR_ENTER_CRITICAL_REGION(); HAL_SS_LOW(); //Send frame read command. SPDR = HAL_TRX_CMD_FR; while ((SPSR & (1 << SPIF)) == 0) {;} u8 frame_length = SPDR; //Read frame length. SPDR = frame_length; while ((SPSR & (1 << SPIF)) == 0) {;} frame_length = SPDR; //Check for correct frame length. if ((frame_length >= HAL_MIN_FRAME_LENGTH) && (frame_length <= HAL_MAX_FRAME_LENGTH)) { rx_frame->length = frame_length; //Store frame length. //Upload frame buffer to data pointer. Calculate CRC. SPDR = frame_length; while ((SPSR & (1 << SPIF)) == 0) ; do { u8 tempData = SPDR; SPDR = 0; // dummy write //*rx_data++ = tempData; *rx_data = tempData; rx_data++; while ((SPSR & (1 << SPIF)) == 0) ; } while (--frame_length > 0); //Read LQI value for this frame. rx_frame->lqi = SPDR; HAL_SS_HIGH(); } else { HAL_SS_HIGH(); if (rx_frame) { rx_frame->length = 0; rx_frame->lqi = 0; rx_frame->crc = false; bmm_buffer_free(pFrame); // free allocated buffer pFrame = NULL; // set buffer pointer to NULL, that next app do not use it } } AVR_LEAVE_CRITICAL_REGION(); #endif // SINGLE_CHIP } return pFrame; }
/* * \brief Initializes the TAL * * This function is called to initialize the TAL. The transceiver is * initialized, the TAL PIBs are set to their default values, and the TAL state * machine is set to TAL_IDLE state. * * \return MAC_SUCCESS if the transceiver state is changed to TRX_OFF and the * current device part number and version number are correct; * FAILURE otherwise */ retval_t tal_init(void) { /* Init the PAL and by this means also the transceiver interface */ if (pal_init() != MAC_SUCCESS) { return FAILURE; } if (trx_init() != MAC_SUCCESS) { return FAILURE; } if (tal_timer_init() != MAC_SUCCESS) { return FAILURE; } #ifdef ENABLE_STACK_NVM pal_ps_get(INTERN_EEPROM, EE_IEEE_ADDR, 8, &tal_pib.IeeeAddress); #endif /* * For systems including the AT86RF230B the random seed generation * cannot be done using a dedicated hardware feature. * Therefore all random seed generation needs to be done by special * means (e.g. utilization of ADC) that generate a random value only * within a certain range. * * In case the node already has a valid IEEE address (i.e. an IEEE * address which is different from 0x0000000000000000 or * 0xFFFFFFFFFFFFFFFF), this IEEE address (the lower 16 bit) * shall be used as seed for srand(), since each node should have a *unique * IEEE address. * In this case srand() is called directly and function *tal_generate_rand_seed() * is not called. * * Note: This behaviour is different in all other TALs, since in these * cases the seed for srand() is always generated based on transceiver * hardware support. */ #ifndef DISABLE_IEEE_ADDR_CHECK if ((tal_pib.IeeeAddress == 0x0000000000000000) || (tal_pib.IeeeAddress == 0xFFFFFFFFFFFFFFFF) ) { /* * Generate a seed for the random number generator in function *rand(). * This is required (for example) as seed for the CSMA-CA *algorithm. */ tal_generate_rand_seed(); /* * Now that we have generated a random seed, we can generate a *random * IEEE address for this node. */ do { /* * In case no valid IEEE address is available, a random * IEEE address will be generated to be able to run the * applications for demonstration purposes. * In production code this can be omitted. */ /* * The proper seed for function rand() has already been *generated * in function tal_generate_rand_seed(). */ uint8_t *ptr_pib = (uint8_t *)&tal_pib.IeeeAddress; for (uint8_t i = 0; i < 8; i++) { *ptr_pib++ = (uint8_t)rand(); /* * Note: * Even if casting the 16 bit rand value back to *8 bit, * and running the loop 8 timers (instead of *only 4 times) * may look cumbersome, it turns out that the *code gets * smaller using 8-bit here. * And timing is not an issue at this place... */ } } /* Check if a valid IEEE address is available. */ while ((tal_pib.IeeeAddress == 0x0000000000000000) || (tal_pib.IeeeAddress == 0xFFFFFFFFFFFFFFFF) ); } else { /* Valid IEEE address, so no need to generate a new random seed. **/ uint16_t cur_rand_seed = (uint16_t)tal_pib.IeeeAddress; srand(cur_rand_seed); } #else /* * No check for a valid IEEE address done, so directly create a seed * for srand(). */ tal_generate_rand_seed(); #endif /* * Do the reset stuff. * Set the default PIBs. */ if (internal_tal_reset(true) != MAC_SUCCESS) { return FAILURE; } pal_trx_reg_read(RG_IRQ_STATUS); /* clear pending irqs, dummy read */ /* * Configure interrupt handling. * Install a handler for the transceiver interrupt. */ pal_trx_irq_init((FUNC_PTR)trx_irq_handler_cb); pal_trx_irq_en(); /* Enable transceiver main interrupt. */ /* Initialize the buffer management module and get a buffer to store *reveived frames. */ bmm_buffer_init(); tal_rx_buffer = bmm_buffer_alloc(LARGE_BUFFER_SIZE); /* Init incoming frame queue */ #ifdef ENABLE_QUEUE_CAPACITY qmm_queue_init(&tal_incoming_frame_queue, TAL_INCOMING_FRAME_QUEUE_CAPACITY); #else qmm_queue_init(&tal_incoming_frame_queue); #endif /* ENABLE_QUEUE_CAPACITY */ return MAC_SUCCESS; } /* tal_init() */
/** @brief The macsixlowpanDataRequest function is used to send a frame over the air to another node. Any node type can call this function. @param addr Short address of the destination node. @param len The length of the packet in bytes. @param data Pointer to the data to be sent. @param type Type of frame to be sent */ static void macDataRequestInt(u16 addr, u8 len, u8 * data, u8 type) { u8 rpSent; // Was a routing packet sent? // Don't send to self if (addr == macConfig.shortAddress || addr == BROADCASTADDR) { return; } // This node has no short address if (!macConfig.associated) { return; } uint8_t* pFrame = bmm_buffer_alloc(); if(pFrame != NULL) { // Create a struct pointer to the global variable... //ftData *data_frame = (ftData*)(mac_buffer_tx+1); ftData *data_frame = (ftData*)(((rx_frame_t*)pFrame)->data); // Build the frame. data_frame->fcf = FCF_DATA; data_frame->seq = macConfig.dsn++; data_frame->panid = macConfig.panId; data_frame->srcAddr = macConfig.shortAddress; data_frame->finalDestAddr = addr; data_frame->originAddr = macConfig.shortAddress; // send a routing packet if necessary rpSent = macSendRoutingPacket(addr); if (NODETYPE == COORD) { // Find the child node that can route this packet u16 child = addr; u16 parent = macGetParent(child); while (parent != DEFAULT_COORD_ADDR) { child = parent; parent = macGetParent(child); } // send to child node that can route this packet data_frame->destAddr = child; } else // All data is send to parent, unless this is a wakeup frame if (type == WAKE_NODE) data_frame->destAddr = addr; else data_frame->destAddr = macConfig.parentShortAddress; // Frame type is data if (macConfig.sleeping && NODETYPE == ENDDEVICE && RUMSLEEP) { type |= 0x80; // Set high bit of type if we're sleeping } data_frame->type = type; // Copy the payload data to frame. (note: this creates smaller code than using memcpy!!) u8 i; for(i=0; i<len; i++){ ((u8*)&data_frame->payload)[i] = *data++; } // Check addresses again - addr will be different now -> Don't send to self if (data_frame->destAddr == macConfig.shortAddress || data_frame->destAddr == BROADCASTADDR) { bmm_buffer_free(pFrame); return; } ((rx_frame_t*)pFrame)->length = len + ftDataHeaderSize; // save length away if (NODETYPE == COORD) { // See if the child is sleeping (only the coord sends directly to a child node) if (RUMSLEEP && macIsChild(addr) && macIsChildSleeping(addr) && VLP) // Send it later, after child is awake { macHoldFrame(addr, pFrame); // buffer is freed inside macHoldFrame() } else // Node is not sleeping child, send it now. { event_object_t event; event.event = MAC_EVENT_SEND; event.data = pFrame; event.callback = 0; // save Event mac_put_event(&event); } } else { event_object_t event; event.event = MAC_EVENT_SEND; event.data = pFrame; event.callback = 0; // save Event mac_put_event(&event); } macConfig.busy = true; } }