// Target function to timer, sends ping packet after a delay // note that arguments are via static vars due to the indirect nature of the call static void macDoPingRequest(void) { ftPing frame; frame.fcf = FCF_DATA; frame.seq = macConfig.dsn++; frame.panid = macConfig.panId; frame.srcAddr = macConfig.shortAddress; frame.originAddr = macConfig.shortAddress; frame.finalDestAddr = pingAddr; frame.rssi = radioGetSavedRssiValue(); frame.lqi = radioGetSavedLqiValue(); frame.type = pingType; // Set high bit of type if we're sleeping if (macConfig.sleeping && NODE_TYPE == ENDDEVICE && NODE_SLEEP) frame.type |= 0x80; #if (NODE_TYPE == COORD) { #if DEBUG==2 debugMsgStr("\r\nin macDoPingRequest"); #endif // Find the top parentpin u8 addr = macGetTopParent(pingAddr); frame.destAddr = addr; // See if the child is sleeping (only the coord sends directly to a child node) if (NODE_SLEEP && macIsChild(addr)&& macIsChildSleeping(addr)) { // Send it later, after child is awake #if DEBUG==2 debugMsgStr("\r\ncalling macHoldFrame for ping response"); #endif macHoldFrame(addr, (u8*)&frame, sizeof(ftPing)); // Don't send frame right now return; } else { #if DEBUG==2 debugMsgStr("\r\n child: "); debugMsgInt(addr); debugMsgStr(" not sleeping"); #endif } } #else // End/router nodes frame.destAddr = macConfig.parentShortAddress; #endif #if DEBUG==2 debugMsgStr(" sending Ping Response now\n\r"); #endif radioSendData(sizeof(ftPing), (u8*)&frame); }
void macData_BC_Request( u8 len, u8 * data) { ftData *data_frame = (ftData*)(mac_buffer_tx+1); // Create a struct pointer to the global variable... // if we have not found a channel to broadcast on do nothing if (panDescriptor.logicalChannel == 0xff) return; Led1_on(); debugMsgStr("\r\nmacData_BC_Request->"); // Build the frame. data_frame->fcf=FCF_DATA_NOACK; //FCF Data frame no ACK -- to prevent multiple acks data_frame->seq = macConfig.dsn++; data_frame->panid = macConfig.panId; data_frame->srcAddr = macConfig.shortAddress; data_frame->originAddr = macConfig.shortAddress; data_frame->finalDestAddr = BROADCASTADDR; data_frame->destAddr = BROADCASTADDR; data_frame->type =DATA_FRAME; u8 i; for(i=0; i<len; i++) ((u8*)&data_frame->payload)[i] = *data++; *mac_buffer_tx = len + ftDataHeaderSize; // save length away macConfig.busy = true; // this locks out debug tasks radioSendData(*mac_buffer_tx, (u8*)data_frame); Led1_off(); }
/** Send a ping packet (either request or response) to another node. param: pingTypeArg Which type of ping to send, either PING_REQ_FRAME or PING_RSP_FRAME. param: addr Short address of node to send ping */ void macPing(u8 pingTypeArg, u16 addr) { if (addr == macConfig.shortAddress) // Don't send to self return; if (!macConfig.associated) // Broadcast addr return; pingAddr = addr; pingType = pingTypeArg; debugMsgStr("\r\nmacPing to: "); debugMsgInt(pingAddr); debugMsgStr(" type: "); debugMsgInt(pingType); // 2 == request 3== response debugMsgStr("\r\n"); # if (NODE_TYPE == COORD) { u8 rpSent; rpSent = macSendRoutingPacket(addr); // First send a routing packet #if DEBUG==2 debugMsgStr("\r\nsetting up Alarm for ping response"); #endif macSetAlarm(rpSent ? MAC_RP_DELAY : 0, macDoPingRequest); // Then send the Ping (response) macConfig.busy = true; } # else { // End/router nodes macDoPingRequest(); macConfig.busy = true; } # endif }
/** Save a frame for transmission later. Used to store frames for sleeping children. param: addr Short address of recipient node param: len Length of the frame to store param: buf Pointer to buffer containing the frame to save */ void macHoldFrame(u16 addr, u8 *buf, u8 len) { # if ((NODE_TYPE == ROUTER || NODE_TYPE == COORD) && NODE_SLEEP ) { u8 i,done=0; for (i=0;i<STORED_FRAMES;i++) { if (!storedFrames[i].len) { if (!done) // Only store once { #if DEBUG debugMsgStr("\r\nHolding frame for sleeping child"); #endif // This one's free, use it storedFrames[i].len = len; storedFrames[i].addr = addr; memcpy(storedFrames[i].buf, buf, len); // Don't store this frame twice done = 1; } } else { // This item is used, make sure it isn't for this address, // since we only want to store one pending frame for each // sleeping node. if (storedFrames[i].addr == addr) // Delete this frame storedFrames[i].len = 0; } } } # endif }
/** Save a frame for transmission later. Used to store frames for sleeping children. @param addr Short address of recipient node @param pFrame Pointer to buffer containing the frame and length information */ void macHoldFrame(u16 addr, u8 *pFrame) { if (NODETYPE != ENDDEVICE && RUMSLEEP && VLP) { u8 i,done=0; for (i=0;i<STORED_FRAMES;i++) { if (!storedFrames[i].len) { if (!done) // Only store once { debugMsgStr("\r\nHolding frame"); // This one's free, use it storedFrames[i].len = ((rx_frame_t*)pFrame)->length; storedFrames[i].addr = addr; //memcpy(storedFrames[i].buf, buf, len); memcpy(storedFrames[i].buf, ((rx_frame_t*)pFrame)->data, ((rx_frame_t*)pFrame)->length); // Don't store this frame twice done = 1; } } else { // This item is used, make sure it isn't for this address, // since we only want to store one pending frame for each // sleeping node. if (storedFrames[i].addr == addr) // Delete this frame storedFrames[i].len = 0; } } } bmm_buffer_free(pFrame); // free buffer }
/** 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 ((NODE_TYPE == ROUTER || NODE_TYPE == COORD) && NODE_SLEEP ) { 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) { #if DEBUG debugMsgStr("\r\nMac sending postponed frame \r\n"); #endif // Send this frame, remove checksum radioSendData(storedFrames[i].len, storedFrames[i].buf); // Clear out this frame storedFrames[i].len = 0; } } } # endif }
/** This function is called when the MAC receives a packet that is addressed to this node. The packet is dispatched according to its contents. */ void macDataIndication(uint8_t* pFrame) { // Sort out the different types of data packets. ftData *frame = (ftData*)(((rx_frame_t*)pFrame)->data); /* #if (__arm__) volatile s16 queue; if(fnGetTCP_state(host_socket) == TCP_STATE_ESTABLISHED) { if( (frame->fcf != FCF_BEACONREQ) && (frame->fcf != FCF_ASSOC_REQ_DIRECT) && (frame->fcf != FCF_ASSOC_REQ_IND) ) { // ACK handling should occur in the tcpListener function in // rumtask.c. // fnSendBufTCP returns the number of bytes buffered if successful... queue = fnSendBufTCP(host_socket, (u8 *)"WIRELESSD", 9, TCP_BUF_SEND); if(telPrintReading && (queue > 0)) fnDebugMsg("\r\nWIRELESSD buffered for TCP"); else fnDebugMsg("\r\nWIRELESSD buffer problem"); queue = fnSendBufTCP(host_socket, mac_buffer_rx, mac_buffer_rx[0]+1, TCP_BUF_SEND); if(telPrintReading && (queue > 0)) fnDebugMsg("\r\nData indication buffered for TCP"); else fnDebugMsg("\r\nData indication buffer problem"); } } #endif */ switch (frame->type & 0x7f) // Mask high bit just in case it was somehow missed { case DATA_FRAME: // Plain old data, send it up the chain appDataIndication(); break; case DEBUG_FRAME: // Frame containing debug message, print it on coord if (NODETYPE == COORD && OTA_DEBUG && DEBUG) { debugMsgStr("\r\nNode "); debugMsgInt(frame->originAddr); debugMsgStr(": "); // Remove leading cr/lf's from string u8 *p = frame->payload; while (*p) { if (*p > ' ') break; p++; } debugMsgStr((char *)p); } break; case WAKE_NODE: // Wake up the end node. if (NODETYPE == ROUTER) { u8 addr = ((ftWake*)frame)->addr; // See if this is from parent or child if ((((ftWake*)frame)->srcAddr) == macConfig.parentShortAddress) // Set the flag to wake up the end node when it sends a packet macWakeChildNode(addr); } if (NODETYPE == ENDDEVICE) { // Wake yourself up now macConfig.sleeping = false; // Send parent a confirmation that we are awake macDataRequestInt(macConfig.parentShortAddress, 2, (u8*)&macConfig.shortAddress, WAKE_NODE); debugMsgStr("\r\nAwake"); } break; case PING_REQ_FRAME: // We got a ping request, let the app handle that appPingReq(frame->originAddr); break; case PING_RSP_FRAME: // We got a ping response, app will handle it appPingRsp(frame->originAddr); break; case DROP_CHILD_FRAME: // Coordinator is telling us to drop a child if (NODETYPE == ROUTER) macRemoveChild(*(u16*)(&frame->payload)); break; case DATA_FRAME_6LOWPAN: //6lowpan data indication if (IPV6LOWPAN == 1) //sixlowpan_DataIndication(frame, *mac_buffer_rx - 16); sixlowpan_DataIndication(frame, (((rx_frame_t*)pFrame)->length) - 16); break; default: break; } }
/** This function is called when the MAC receives a packet that is addressed to this node. The packet is dispatched according to its contents. */ void macDataIndication(u16 dest) { // Sort out the different types of data packets. ftData *frame = (ftData*)(mac_buffer_rx+1); u8 pl_len = *mac_buffer_rx - 16; #if DEBUG==2 debugMsgStr("\r\nmacDataIndication<-"); #endif switch (frame->type & 0x7f) // Mask high bit just in case it was somehow missed { case DATA_FRAME: // Data, send it up the chain appDataIndication(frame->payload, pl_len, (dest == BROADCASTADDR)); break; case DEBUG_FRAME: // Frame containing debug message, print it on coord if (NODE_TYPE == COORD && OTA_DEBUG && DEBUG) { debugMsgStr("\r\nNode "); debugMsgInt(frame->originAddr); debugMsgStr(": "); // Remove leading cr/lf's from string u8 *p = frame->payload; while (*p) { if (*p > ' ') break; p++; } debugMsgStr_d((char *)p); } break; case WAKE_NODE: // Wake up the end node. #if (NODE_TYPE == ROUTER) { u8 addr = ((ftWake*)frame)->addr; // See if this is from parent or child if ((((ftWake*)frame)->srcAddr) == macConfig.parentShortAddress) // Set the flag to wake up the end node when it sends a packet macWakeChildNode(addr); } #endif #if (NODE_TYPE == ENDDEVICE) /* also include BC_ENDDEVICE ?*/ { // Wake yourself up now macConfig.sleeping = false; // Send parent a confirmation that we are awake macDataRequestInt(macConfig.parentShortAddress,2, (u8*)&macConfig.shortAddress,WAKE_NODE); debugMsgStr("\r\nAwake"); } #endif break; case PING_REQ_FRAME: // We got a ping request, let the app handle that appPingReq((ftPing *) (mac_buffer_rx+1)); break; case PING_RSP_FRAME: // We got a ping response, app will handle it appPingRsp((ftPing *) (mac_buffer_rx+1)); break; #if (NODE_TYPE == ROUTER) case DROP_CHILD_FRAME: // Coordinator is telling us to drop a child macRemoveChild(*(u16*)(&frame->payload)); break; #endif default: break; } }
/** 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) { // Create a struct pointer to the global variable... ftData *data_frame = (ftData*)(mac_buffer_tx+1); u8 rpSent; // Was a routing packet sent? if (addr == macConfig.shortAddress || addr == BROADCASTADDR) { // Don't send to self debugMsgStr("\r\nSelf addressed or Brodcast: nothing sent!"); return; } if (!macConfig.associated) // This node has no short address return; #if DEBUG==2 debugMsgStr("\r\nmacDataRequest->"); #endif // 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 (NODE_TYPE == 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; } #endif // Frame type is data data_frame->type = type; // Set high bit of type if we're sleeping if (macConfig.sleeping && NODE_TYPE == ENDDEVICE && NODE_SLEEP) data_frame->type |= 0x80; // Indicate that this ENDdevice is sleeping // 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 if (data_frame->destAddr == macConfig.shortAddress || data_frame->destAddr == BROADCASTADDR) // Don't send to self return; // send data to radio, after some time delay *mac_buffer_tx = len + ftDataHeaderSize; // save length away #if (NODE_TYPE == COORD) { // See if the child is sleeping (only the coord sends directly to a child node) if (NODE_SLEEP && macIsChild(addr) && macIsChildSleeping(addr) ) // Send it later, after child is awake macHoldFrame(addr, (u8*)data_frame, (u8)*mac_buffer_tx); else { // Node is not sleeping child, send it now. #if DEBUG==2 debugMsgStr("-- macSetAlarm set"); #endif macSetAlarm(rpSent ? MAC_RP_DELAY : MAC_DATA_DELAY, mdr_timer); } } # else macSetAlarm((type==WAKE_NODE || type == DEBUG_FRAME) ? 0 : MAC_DATA_DELAY, mdr_timer); #endif macConfig.busy = true; }
void nodeSleep(u16 tenthSeconds) { // ************** Power down the other board peripherals Leds_off(); // ************** Power down the radio // wait for radio to be done u8 state = BUSY_TX_ARET; while (state == BUSY_TX_ARET || state == BUSY_RX_AACK) state = radioGetTrxState(); // Now put radio to sleep radioEnterSleepMode(); // TODO: figure out what needs to be put to sleep to minimize current consumption // ************** Power down the on-chip modules // PRR = 0xbf; ??? // Disable ADC // ADCSRA &= ~(1 << ADEN); // Turn off comparator // ACSR |= (1 << // turn off ports etc // Turn off BOD // This should only be done once -- No need to do it over again /* AVR_ENTER_CRITICAL_REGION(); #define BODS 6 #define BODSE 5 MCUCR |= (1 << BODSE) | (1<< BODS); MCUCR &= ~(1 << BODSE); AVR_LEAVE_CRITICAL_REGION(); */ // ************** Set the timer to wake up // Set TIMER2 Asyncronous Mode. ASSR |= (1 << AS2); // Set TIMER2 Prescaler to 1024. TCCR2B |= ((1 << CS22)|(1 << CS21)|(1 << CS20)); // Wait for TCNT2 write to finish. while(ASSR & (1 << TCR2BUB)) ; // Sleep as many times as needed to sleep for the full time while (tenthSeconds) { // This is to get the node manually out of sleeping mode -- // Might take up to 7.5Sec to detect button press // if (BUTTON_PRESSED() ) { Led1_on(); macConfig.sleeping = false; while (BUTTON_PRESSED()) ; Led1_off(); break; // exit the Sleeping loop } // Set TIMER2 output compare register from user. if (tenthSeconds > 75) { // Just decrement by the max timeout OCR2A = 240; // 7.5 seconds, max timeout tenthSeconds -= 75; } else { // Can measure the remaining time in one timer cycle tenthSeconds = tenthSeconds * 16 / 5; if (!tenthSeconds) tenthSeconds++; OCR2A = tenthSeconds; tenthSeconds = 0; } // Wait for OCR2 write to finish. while(ASSR & (1 << OCR2AUB)) ; // Reset TIMER2 timer counter value. TCNT2 = 0; // Wait for TCNT2 write to finish before entering sleep. while(ASSR & (1 << TCN2UB)) ; // Clear interrupt flag TIFR2 |= (1 << OCF2A); // Enable TIMER2 output compare interrupt. TIMSK2 |= (1 << OCIE2A); // ************** Go to sleep AVR_ENTER_CRITICAL_REGION(); set_sleep_mode( SLEEP_MODE_PWR_SAVE); sleep_enable(); sei(); sleep_cpu(); // sleeping right here sleep_disable(); AVR_LEAVE_CRITICAL_REGION(); wdt_disable(); } // ************** Awake now, wake up everything // PRR = 0x03; ?? if (SERIAL) serial_init(NULL); debugMsgStr("\r\nNode slept"); if ( macConfig.associated) HAL_ADC_INIT(); // Bring SPI port back up (must re-init after sleep) radio_spi_init(); // Wake up radio. radioLeaveSleepMode(); // Set RF212 to 250KB mode. // TODO: do I need to call this?? //radioSetup900(); radioSetTrxState(PLL_ON); }