/* $Id: coord.c,v 1.12 2006/11/28 09:44:29 awachtle Exp $ */ /*--------------------------------------------------------------------------- PROPRIETARY INFORMATION OF ATMEL CORPORATION Copyright (c) 2006 Atmel Corporation The scope of use of the material contained herein is limited strictly to the terms of the LICENSE which grants permission for the use of the material. Distribution of this material and all copies thereof to any entity other than to the EMPLOYEES of the Licensee, as the term is defined in the LICENSE, is strictly forbidden without a prior written consent of Atmel Corporation. ---------------------------------------------------------------------------- */ /* === Includes ============================================================ */ #include #include #if defined (__GNUC__) # include #elif defined(__ICCAVR__) # include # include # include # define sei() __enable_interrupt() # define _BV(x) (1<<(x)) #endif #include "wpan_defines.h" #include "ieee_const.h" #include "wpan_mac.h" /* ==== Macros ============================================================= */ #ifndef RF_CHANNEL # define RF_CHANNEL (18) # warning "RF channel undefined, using channel 18 as default" #endif #define PANCOORD_SHORT_ADD (0xBABE) #define BROADCAST_SHORT_ADD (0xFFFF) #define PANID (0xCAFE) #define PANCOORD_SCAN_CHANNELS ((uint32_t)0x00000000) #define SCANDURATION (3) #define BEACON_ORDER (15) /* NO Beacon */ #define SUPERFRAME_ORDER (15) #define EMPTY_LONG_ADDRESS (~(uint64_t)0) #define MAX_ENTRIES (8) #define NO_ENTRY (0xFF) /* macro stores the state value and sets the state led to 0 */ #define SET_STATE(x) do { c_status.state=(x); \ PORTE |= (_BV((uint8_t)(x)));} while(0) /* === Typedefs ============================================================ */ typedef struct { bool associated; uint64_t long_addr; } association_entry_t; typedef enum { INIT_DONE, PEND_RESET, PEND_SET_SHORT_ADDR, PEND_INITIAL_SCAN, PEND_START, PEND_ASSOC_PERMIT, RUN, } coord_state_t; typedef struct { uint8_t handle; uint8_t led_value; coord_state_t state; } coord_status_t; /* === Static Variables ==================================================== */ static coord_status_t c_status; static association_entry_t association_table[MAX_ENTRIES]; uint8_t data_buffer[127]; /* === Prototypes ========================================================== */ void application_init(void); void mac_do_reset(void); void mac_active_scan(void); void mac_start_pan(void); void mac_set_short_addr(uint16_t addr); void mac_set_assoc_permit(uint8_t permit); void mac_register_device(uint64_t DeviceAddress); void mac_send_data(void); static void association_table_init(void); static uint8_t get_empty_association_slot(void); static uint8_t search_association_entry(uint64_t addr); /* === Implementation ====================================================== */ int main(void) { application_init(); mac_do_reset(); while(1) { while(wpan_task()) { } } } void application_init(void) { c_status.led_value = 0; c_status.handle = 0; association_table_init(); /* init IO ports */ DDRE = 0xFF; /* all bits of PORT E are outputs */ PORTE = 0x00; /* all LED's ON */ /* init mac layer */ wpan_init(); SET_STATE(INIT_DONE); /* enable interrupts */ sei(); return; } void mac_do_reset() { wpan_mlme_reset_request( true ); SET_STATE( PEND_RESET ); } void mac_set_short_addr(uint16_t addr) { wpan_mlme_set_request (macShortAddress, &addr, sizeof(addr)); SET_STATE ( PEND_SET_SHORT_ADDR ); } void mac_set_assoc_permit(uint8_t permit) { wpan_mlme_set_request (macAssociationPermit, &permit, sizeof(permit)); SET_STATE( PEND_ASSOC_PERMIT ); } void usr_mlme_reset_conf (uint8_t status) { if ((status == MAC_SUCCESS) && (c_status.state == PEND_RESET)) { mac_set_short_addr(PANCOORD_SHORT_ADD); } else { mac_do_reset(); } return; } void usr_mlme_set_conf(uint8_t status, uint8_t PIBAttribute ) { switch (c_status.state) { case PEND_SET_SHORT_ADDR: if ((status == MAC_SUCCESS) && (PIBAttribute == macShortAddress)) { mac_active_scan(); } break; case PEND_ASSOC_PERMIT: if ((status == MAC_SUCCESS) && (PIBAttribute == macAssociationPermit)) { SET_STATE( RUN ); PORTE = 0xff; /* LED's off if we come to here */ } default: break; } return; } void mac_active_scan(void) { wpan_mlme_scan_request (MLME_SCAN_TYPE_ACTIVE, PANCOORD_SCAN_CHANNELS, SCANDURATION); SET_STATE(PEND_INITIAL_SCAN); return; } void usr_mlme_scan_conf(uint8_t status, uint8_t ScanType, uint32_t UnscannedChannels, uint8_t ResultListSize, uint8_t *data, uint8_t data_length) { if (c_status.state == PEND_INITIAL_SCAN) { /* We don't care about the confirm of the scan request because the scan */ /* request just puts the MAC into the correct state for a pancoord. */ mac_start_pan(); } return; } void mac_start_pan(void) { wpan_mlme_start_request ( PANID, RF_CHANNEL, BEACON_ORDER, SUPERFRAME_ORDER, true, false, false, false); SET_STATE(PEND_START); return; } void usr_mlme_start_conf(uint8_t status) { if (c_status.state == PEND_START) { if (status == MAC_SUCCESS) { mac_set_assoc_permit( 1 ); } else { mac_start_pan(); } } return; } void association_table_init(void) { for(uint16_t i = 0; i < MAX_ENTRIES; i++) { association_table[i].associated = false; association_table[i].long_addr = EMPTY_LONG_ADDRESS; } return; } uint8_t get_empty_association_slot(void) { uint8_t ret = NO_ENTRY, idx; for(idx = 0; idx < MAX_ENTRIES; idx++) { if(association_table[idx].long_addr == EMPTY_LONG_ADDRESS) { ret = idx; break; } } return ret; } uint8_t search_association_entry(uint64_t addr) { uint8_t ret = NO_ENTRY, idx; /* Look for the address in the table. */ for(idx = 0; idx < MAX_ENTRIES; idx++) { if(association_table[idx].long_addr == addr) { ret = idx; break; } } return ret; } void usr_mlme_associate_ind (uint64_t DeviceAddress, uint8_t CapabilityInformation, uint8_t SecurityUse, uint8_t ACLEntry) { if (c_status.state == RUN) { mac_register_device(DeviceAddress); } } void mac_register_device(uint64_t DeviceAddress) { uint8_t entry_index; /* Search if device is already associated. */ entry_index = search_association_entry(DeviceAddress); if(entry_index == NO_ENTRY) { entry_index = get_empty_association_slot(); } if (entry_index == NO_ENTRY) { wpan_mlme_associate_response (DeviceAddress, 0, PAN_AT_CAPACITY, false); } else { association_table[entry_index].long_addr = DeviceAddress; wpan_mlme_associate_response(DeviceAddress, entry_index, ASSOCIATION_SUCCESSFUL, false); } return; } void usr_mlme_comm_status_ind(wpan_commstatus_addr_t *pAddrInfo, uint8_t status) { uint16_t assoc_idx = NO_ENTRY; if (pAddrInfo->PANId == PANID) /* if it is our PAN */ { if (pAddrInfo->DstAddrMode == WPAN_ADDRMODE_SHORT) { assoc_idx = pAddrInfo->DstAddr; } else if (pAddrInfo->DstAddrMode == WPAN_ADDRMODE_LONG) { assoc_idx = search_association_entry(pAddrInfo->DstAddr); } if ((status == MAC_SUCCESS) && (assoc_idx < MAX_ENTRIES)) { association_table[assoc_idx].associated = true; } } } void usr_mcps_data_ind (wpan_mcpsdata_addr_t *addrInfo, uint8_t mpduLinkQuality, uint8_t SecurityUse, uint8_t ACLEntry, uint8_t msduLength, uint8_t *msdu) { /* Determine if the indication comes from a device, * that has previously associated. */ if (addrInfo->SrcAddrMode == WPAN_ADDRMODE_SHORT && association_table[(uint8_t)addrInfo->SrcAddr].associated) { /* Mask the data byte with the address info. */ if(msdu[0]) { c_status.led_value |= (1 << (uint8_t)addrInfo->SrcAddr); } else { c_status.led_value &= ~(1 << (uint8_t)addrInfo->SrcAddr); } /* Show the address of the device on our LEDs. */ PORTE = ~c_status.led_value; /* Start sending data to all associated devices. */ mac_send_data(); } return; } void mac_send_data(void) { wpan_mcpsdata_addr_t addr_info; addr_info.SrcAddrMode = WPAN_ADDRMODE_SHORT; addr_info.SrcPANId = PANID; addr_info.SrcAddr = PANCOORD_SHORT_ADD; addr_info.DstAddrMode = WPAN_ADDRMODE_SHORT; addr_info.DstPANId = PANID; addr_info.DstAddr = BROADCAST_SHORT_ADD; wpan_mcps_data_request( &addr_info, c_status.handle++, WPAN_TXOPT_OFF, (void *)&c_status.led_value, sizeof(c_status.led_value)); return; }