📄 common.c
字号:
// and then bitwise AND to clear from the jitMask jitMaskSinkAdvertise = jitMaskSinkAdvertise & (BIT(childIndex) ^ 0xFFFF); } // This application only sends 1 message per poll. If the sleepy child gets // data from a poll it will nap and poll again (not hibernate) until it // doesn't get any data from a poll. In order to send more than one message // in response to a single poll, the parent needs to be sure to clear the // message flag (emberClearMessageFlag) after the first message has been // put into the message queue. If the flag is cleared before that, then // the first message will have framePending=false and the child will not // be awake to hear the second message. The best way to handle this is // to keep track of the number of messages sent to each child, decrement // this for each emberUnicastSent callback, and then clear the message // flag (in emberUnicastSent) when the number of outstanding messages go // to zero. This application doesn't do this and instead sends one // JIT message at a time. If there is a second JIT message on the parent // it will be picked up on the next nap cycle, set for 1 second. if (!sentSinkAdv) { // check if this child has already polled for the message if (BIT(childIndex) & jitMaskMulticastHello) { jitMessageApsFrame.clusterId = MSG_MULTICAST_HELLO; /*mcastHelloStatus = */ emberSendUnicast(childId, &jitMessageApsFrame, jitMessageMulticastHello); // sentMcastHello = TRUE; // clear the bit - invert the number that has the child index'th bit set (xor) // and then bitwise AND to clear from the jitMask jitMaskMulticastHello = jitMaskMulticastHello & (BIT(childIndex) ^ 0xFFFF); } } // The next section of code is used for debugging and is commented out. // Serial characters are dropped when there are a bunch of these messages // going out at the same time so it's not very useful with more than one // or two children, but can be helpful when initially testing modifications // to this code (for instance, adding another JIT type) // // if (sentSinkAdv) { // emberSerialPrintf(APP_SERIAL, "TX JIT [adv]:%2x(%x)\r\n", // childId, sinkAdvStatus); // } // if (sentMcastHello) { // emberSerialPrintf(APP_SERIAL, "TX JIT [hello]:%2x(%x)\r\n", // childId, mcastHelloStatus); // } // clear the message flag if there are no msgs waiting for this node if ((!(BIT(childIndex) & jitMaskSinkAdvertise )) && (!(BIT(childIndex) & jitMaskMulticastHello))) { status = emberClearMessageFlag(childId); if (status != EMBER_SUCCESS) { emberSerialPrintf(APP_SERIAL, "ERROR: %x, clear flag %2x\r\n", status, childId); } // The next three lines are commented out but may be useful when // modifying and then debugging this code. //else { // emberSerialPrintf(APP_SERIAL, "JIT: clear flag %2x\r\n", childId); //} }}// This is called by the stack when a device polls. When// transmitExpected is true, this means the message flag is set for// this child.//void emberPollHandler(EmberNodeId childId, boolean transmitExpected){ // functions called from within this should not contain actions that // could take a long time. The messages sent in response to the poll // have to be within 15ms. Doing a emberSerialWaitSend in here, for // example would cause the sleepy end device to go back to sleep // before the parent was able to send any messages at all. if (transmitExpected) { // Check if we need to send the initial bootload launch message. // In addition don't call appSendJitToChild if we have bootload process // pending since it could confuse the bootload by sending other JIT message // and also could clear the message flag #ifdef USE_BOOTLOADER_LIB // Check if the child that polls is the node to be bootloaded. if(bootloadInProgressChildId == childId) { if (parentLaunchBootload) { sendBootloaderLaunchMessage(bootloadInProgressEui); parentLaunchBootload = FALSE; // Do not try to send any other JIT message when starting // bootload process. return; } else if (blState == BOOTLOAD_STATE_DELAY_BEFORE_START) { // We have received the authentication challenge. bootloadUtilSendAuthResponse(bootloadInProgressEui); emberClearMessageFlag(childId); // Do not try to send any other JIT message when starting // bootload process. return; } } if(!IS_BOOTLOADING) { // take care of all the sending of JIT messages to the child appSendJitToChild(childId); } #else appSendJitToChild(childId); #endif }}// this function is called from jitMessageStatus to print the contents // of a JIT buffer. Useful in making sure the correct data is being// copied into the JIT buffer.void jitMessageStatusPrintMessageData(EmberMessageBuffer bufferToPrint){ int8u i; if (bufferToPrint != EMBER_NULL_MESSAGE_BUFFER) { emberSerialPrintf(APP_SERIAL, " data: "); for (i=0; i< emberMessageBufferLength(bufferToPrint); i++) { emberSerialPrintf(APP_SERIAL, "%x ", emberGetLinkedBuffersByte(bufferToPrint, i)); } emberSerialPrintf(APP_SERIAL, "\r\n"); emberSerialWaitSend(APP_SERIAL); }}// This is called to print the status of the JIT storage on a parent node// (sink or line powered sensor)void jitMessageStatus(void){ halResetWatchdog(); // bitmasks emberSerialPrintf(APP_SERIAL, "bitmask for Sink_Advertise message.: %2x\r\n", jitMaskSinkAdvertise); emberSerialPrintf(APP_SERIAL, "bitmask for Multicast_Hello message: %2x\r\n", jitMaskMulticastHello); emberSerialWaitSend(APP_SERIAL); // sink adv packet buffer emberSerialPrintf(APP_SERIAL, "packet buffer for Sink_Advertise: %x\r\n", jitMessageSinkAdvertise); emberSerialWaitSend(APP_SERIAL); jitMessageStatusPrintMessageData(jitMessageSinkAdvertise); // mcast hello packet buffer emberSerialPrintf(APP_SERIAL, "packet buffer for Multicast_Hello: %x\r\n", jitMessageMulticastHello); emberSerialWaitSend(APP_SERIAL); jitMessageStatusPrintMessageData(jitMessageMulticastHello);}// this is called to print the child tablevoid printChildTable(void){ int8u i; EmberStatus status; EmberEUI64 eui; EmberNodeType type; for (i=0; i<emberMaxChildCount(); i++) { status = emberGetChildData(i, eui, &type); emberSerialPrintf(APP_SERIAL, "%x:", i); if (status == EMBER_SUCCESS) { printEUI64(APP_SERIAL, (EmberEUI64*)eui); switch (type){ case EMBER_SLEEPY_END_DEVICE: emberSerialPrintf(APP_SERIAL, " sleepy"); break; case EMBER_MOBILE_END_DEVICE: emberSerialPrintf(APP_SERIAL, " mobile"); break; default: emberSerialPrintf(APP_SERIAL, " ??????"); break; } } emberSerialPrintf(APP_SERIAL, "\r\n"); }}void emberChildJoinHandler(int8u index, boolean joining){ EmberStatus status; EmberEUI64 eui; EmberNodeType type; // if the node is joining... if (joining == TRUE) { status = emberGetChildData(index, eui, &type); // ...and the type is mobile... if ((status == EMBER_SUCCESS) && (type == EMBER_MOBILE_END_DEVICE)) { // ...set the message flag so it gets any messages right // away, since the node will not be in the child table // (and not have it's message flag set) whenever it // hibernates status = emberSetMessageFlag(emberChildId(index)); } }}#endif // defined(SENSOR_APP) || defined(SINK_APP)// **************************************************// utility calls to support the EM250 Bootloader//// **************************************************#ifdef USE_BOOTLOADER_LIB// this is called by the sensor or sink -- applications that act// as parents. This is called with the EUI of the child that the// parents wants to bootload. Since the sleepy device may not be// awake (likely not), this function sets the message flag of the// child and remembers which child needs to be bootloaded. When the// child wakes up and polls, the initial bootloader launch message // is sent -- see emberPollHandlervoid bootloadMySleepyChild(EmberEUI64 targetEui){ int8u index; // message for the user emberSerialPrintf(APP_SERIAL, "INFO: attempt child bootload, eui "); printEUI64(APP_SERIAL, (EmberEUI64*)targetEui); emberSerialPrintf(APP_SERIAL, "\r\n"); emberSerialWaitSend(APP_SERIAL); // make sure the EUI is a child of this parent if (!(isMyChild(targetEui, &index))) { return; } // set the message flag for the child emberSetMessageFlag(emberChildId(index)); // remember the EUI and shortId for the child we are bootloading bootloadInProgressChildId = emberChildId(index); MEMCOPY(bootloadInProgressEui, targetEui, EUI64_SIZE); // the bootload util library tells us if a bootload is in progres // with the IS_BOOTLOADING macro. We need to set a flag to send the // bootload launch message. Only want to do this once. parentLaunchBootload = TRUE; // print a message explaining that passthru is initiating // and there is a few seconds before the xmodem ('C' characters // printing) starts. emberSerialPrintf(APP_SERIAL, "If a bootload response is seen, xmodem "); emberSerialPrintf(APP_SERIAL, "will start in 30 seconds\r\n"); emberSerialPrintf(APP_SERIAL, "If xmodem does not start, the bootload failed\r\n");}// called by a sensor or sink when bootloading a neighbor device is// desired. This function just prints a bunch of information for the// user's benefit and calls a function that sends the initial bootload// launch message.void bootloadMyNeighborRouter(EmberEUI64 targetEui){ // message for the user emberSerialPrintf(APP_SERIAL, "INFO: attempt neighbor bootload, eui "); printEUI64(APP_SERIAL, (EmberEUI64*)targetEui); emberSerialPrintf(APP_SERIAL, "\r\n"); emberSerialWaitSend(APP_SERIAL); // print a message explaining that passthru is initiating // and there is a few seconds before the xmodem ('C' characters // printing) starts. emberSerialPrintf(APP_SERIAL, "If a bootload response is seen, xmodem "); emberSerialPrintf(APP_SERIAL, "will start in 10 seconds\r\n"); emberSerialPrintf(APP_SERIAL, "If xmodem does not start, the bootload failed\r\n"); sendBootloaderLaunchMessage(targetEui);}// does the sending of the bootloader launch message. This is really// just setting up the parameters and making a call to bootloadUtilSendRequestvoid sendBootloaderLaunchMessage(EmberEUI64 targetEui){ // encryptKey has to match the token TOKEN_MFG_BOOTLOADER_AES_KEY // on the target device or the bootload will not start int8u encryptKey[16] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}; // mfgId and hardwareTag have to match what the target device is // checking for in bootloadUtilRequestHandler. These values are meant // to be stored in the manufacturing tokens TOKEN_MFG_MANUF_ID (mfgId) // and TOKEN_MFG_BOARD_NAME (hardwareTag). int16u mfgId = 0xE250; int8u hardwareTag[8] = {'D', 'E', 'V', ' ', '0', '4', '5', '5'}; bootloadUtilSendRequest(targetEui, mfgId, hardwareTag, encryptKey, BOOTLOAD_MODE_PASSTHRU); }// determines if the EUI passed in is in this device's child table// return of true means the EUI is in the child table// return of false means the EUI is not in the child table// if the EUI is in the child table, then childIndex is set to the// index in the child table of the EUI.boolean isMyChild(EmberEUI64 candidateEui, int8u* childIndex){ int8u i; EmberEUI64 childEui; EmberNodeType type; EmberStatus status; // go through whole child table for (i=0; i<emberMaxChildCount(); i++) { status = emberGetChildData(i, childEui, &type); if ((status == EMBER_SUCCESS) && (MEMCOMPARE(candidateEui, childEui, EUI64_SIZE)==0)) { // we found a match (*childIndex) = i; return TRUE; } } // didn't match any entry in my child table return FALSE; }// no check for now. If an attempt is made to bootload a device // that is not a neighbor the initial launch will fail.boolean isMyNeighbor(EmberEUI64 eui){ return TRUE; }// get the eui from a unicast binding. The return value is FALSE // if the binding couldn't be read or the binding is not unicast.// This is used by sensor or sink to pick an EUI from the binding// table to then bootload.boolean getEuiFromUnicastBinding(int8u bindingIndex, EmberEUI64* eui){ EmberBindingTableEntry result; EmberStatus status = emberGetBinding(bindingIndex, &result); // binding must be in use.and be unicast if ((status == EMBER_SUCCESS) && (result.type == EMBER_UNICAST_BINDING)) { MEMCOPY(eui, result.identifier, EUI64_SIZE); return TRUE; } return FALSE; }#endif //USE_BOOTLOADER_LIB
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -