示例#1
0
/** Waits for the specified type of message. Silently discards any other messages received.
Received message will be in znpBuf[]. If the specified type of message isn't received then returns error code.
@return 0 if success, -21 if timeout, -31 if received a message but it wasn't the type we're expecting.
*/
signed int waitForMessage(unsigned int messageType, unsigned char timeoutSecs)
{
    unsigned long counter = 0;
    unsigned long timeout = (timeoutSecs / 2) * XTAL; //since loop takes more than 1 clock cycle
    
    while (SRDY_IS_HIGH() && (counter != timeout))
        counter++;   
    if (counter == timeout)
        return -21;
    spiPoll();
    if ((znpBuf[SRSP_LENGTH_FIELD] > 0) && (CONVERT_TO_INT(znpBuf[2], znpBuf[1]) == messageType))
    {
#ifdef ZNP_INTERFACE_VERBOSE
        printf("Received expected message %04X\r\n", messageType);
#endif
        return 0;
    } else {                    //unexpected message received
        //#ifdef ZNP_INTERFACE_VERBOSE
        printf("waitForMessage Unexpected Message: L%u, messageType = %04X\r\n", 
               znpBuf[SRSP_LENGTH_FIELD] , (CONVERT_TO_INT(znpBuf[2], znpBuf[1])));
        //#endif
        return -31;
    }
    
}
示例#2
0
/** Prints out the returned value of zdoNetworkAddressRequest() */
void printZdoNetworkAddressResponse(unsigned char* rsp)
{
    printf("Status = %u; MAC:", rsp[0]);
    for (int i=1; i<9; i++)
        printf("%02X ", rsp[i]);
    printf("NwkAddr:%04X; StartIdx:%u, numAssocDev:%u\r\n", CONVERT_TO_INT(rsp[9], rsp[10]), rsp[11],rsp[12]);
    for (int j=0; j<rsp[12]; j++)
        printf("%04X ", CONVERT_TO_INT(rsp[(j+13)], rsp[(j+14)]));
    printf("\r\n");
}
示例#3
0
/** Displays the header information in an AF_INCOMING_MSG.
@param srsp a pointer to the buffer containing the message
@return 0 if success, -1 if not a AF_INCOMING_MSG.
*/
signed int printAfIncomingMsgHeader(unsigned char* srsp)
{
    if (CONVERT_TO_INT(srsp[SRSP_CMD_LSB_FIELD], srsp[SRSP_CMD_MSB_FIELD]) == AF_INCOMING_MSG)
    {
        printf("#%02u: Grp%04x Clus%04x, SrcAd%04x, SrcEnd%02x DestEnd%02x Bc%02x Lqi%02x Sec%02x Len%02u", 
               srsp[SRSP_HEADER_SIZE+15],
               CONVERT_TO_INT(srsp[SRSP_HEADER_SIZE], srsp[SRSP_HEADER_SIZE+1]), 
               CONVERT_TO_INT(srsp[SRSP_HEADER_SIZE+2], srsp[SRSP_HEADER_SIZE+3]),
               CONVERT_TO_INT(srsp[SRSP_HEADER_SIZE+4], srsp[SRSP_HEADER_SIZE+5]), 
               srsp[SRSP_HEADER_SIZE+6], srsp[SRSP_HEADER_SIZE+7], srsp[SRSP_HEADER_SIZE+8], 
               srsp[SRSP_HEADER_SIZE+9], srsp[SRSP_HEADER_SIZE+10], srsp[SRSP_HEADER_SIZE+16]);
        return 0;
    } else {
        return -1;
    }
}
/** 
Private method used to wait until a message is received indicating that we are on the network. 
Exits if received message is a ZDO_STATE_CHANGE_IND and the state matches what we want. 
Else loops until timeout. 
@note Since this is basically a blocking wait, you can also implement this in your application.
@param expectedState the deviceState we are expecting - DEV_ZB_COORD etc.
@param timeoutMs the amount of milliseconds to wait before returning an error. Should be an integer
multiple of WFDS_POLL_INTERVAL_MS.
@todo modify this if using UART.
*/
static moduleResult_t waitForDeviceState(unsigned char expectedState, uint16_t timeoutMs)
{
  RETURN_INVALID_PARAMETER_IF_TRUE( ((!(IS_VALID_DEVICE_STATE(expectedState))) || (timeoutMs < WFDS_POLL_INTERVAL_MS)), METHOD_WAIT_FOR_DEVICE_STATE);
  
  uint16_t intervals = timeoutMs / WFDS_POLL_INTERVAL_MS;                   // how many times to check
  uint8_t state = 0xFF;

  while (intervals--)
  {
    if (moduleHasMessageWaiting())                                          // If there's a message waiting for us
    {
      getMessage();

      if (CONVERT_TO_INT(zmBuf[2], zmBuf[1]) == ZDO_STATE_CHANGE_IND)       // if it's a state change message
      {
        state = zmBuf[SRSP_PAYLOAD_START];
        printf("%s, ", getDeviceStateName(state));                          // display the name of the state in the message
        if (state == expectedState)                                         // if it's the state we're expecting
          return MODULE_SUCCESS;                                                //Then we're done!
      } //else we received a different type of message so we just ignore it
    }
    delayMs(WFDS_POLL_INTERVAL_MS);
  }
  // We've completed the loop without receiving the sate that we want; so therefore we've timed out.
  RETURN_RESULT(TIMEOUT, METHOD_WAIT_FOR_DEVICE_STATE);
}
示例#5
0
/** Utility method to display stored network configuration parameters. These are the configuration
parameters stored in NV memory and are used to initialize the ZNP.
@post znpResult contains the error code, or ZNP_SUCCESS if success.
*/
void getNetworkConfigurationParameters()
{
    printf("ZNP Configuration Parameters\r\n");
    unsigned char* param;
    
    param = getConfigurationParameter(ZCD_NV_PANID);
    if (znpResult != 0) return;
    printf("    ZCD_NV_PANID                %04X\r\n", (CONVERT_TO_INT(param[0], param[1])));
    
    param = getConfigurationParameter(ZCD_NV_CHANLIST);
    if (znpResult != 0) return;
    printf("    ZCD_NV_CHANLIST             %02X %02X %02X %02X\r\n", param[0], param[1], param[2], param[3]);
    
    param = getConfigurationParameter(ZCD_NV_SECURITY_MODE);
    if (znpResult != 0) return;
    printf("    ZCD_NV_SECURITY_MODE        %02X\r\n", param[0]);
    
    param = getConfigurationParameter(ZCD_NV_PRECFGKEYS_ENABLE);
    if (znpResult != 0) return;
    printf("    ZCD_NV_PRECFGKEYS_ENABLE    %02X\r\n", param[0]);    
    
    param = getConfigurationParameter(ZCD_NV_PRECFGKEY);
    if (znpResult != 0) return;
    printf("    ZCD_NV_PRECFGKEY            ");    
    printHexBytes(param, ZCD_NV_PRECFGKEY_LEN);
    
}
示例#6
0
/** Retrieves a random number from the ZNP using SYS_RANDOM command.
@post znpResult contains the error code, or ZNP_SUCCESS if success.
@return the random number, or indeterminate data if error.
*/
unsigned int getRandom()
{
    znpBuf[0] = SYS_RANDOM_PAYLOAD_LEN;
    znpBuf[1] = MSB(SYS_RANDOM);
    znpBuf[2] = LSB(SYS_RANDOM);  
    znpResult = sendMessage(); 
    return (CONVERT_TO_INT(znpBuf[SRSP_PAYLOAD_START], znpBuf[SRSP_PAYLOAD_START+1]));
}
示例#7
0
/** Displays the radio's device Information Properties. Device Information Properties include: 
- Device State indicates whether the ZNP is on a network or not, and what type of device it is. 
This is a handy thing to check if things aren't operating correctly. 
If the device is starting as a coordinator, you'll see states of 01, 08, 08, then 09 once it has fully started.
- MAC Address (aka IEEE Address) is a globally unique serial number for this IC.
- Device Short Address is a network address assigned by the coordinator, similar to an IP Address in DHCP. 
The Coordinator always has a Short Address of 0.
- Parent MAC Address is the IEEE Address of this device's "parent", i.e. which device was used to join the network. 
For a router, once joined this parent MAC address is irrelevant. This DIP will NOT be updated if the network reforms.
For an end-device then this parent MAC address will always specify which router the end-device is joined to.
- Channel is which frequency channel the device is operating on.
- PAN ID (Personal Area Network Identifier) of the network is a unique number shared for all devices on the same network.
- Extended PAN ID of the network is the coordinator's MAC Address.

If device is not connected to a network then the Short Address fields will be 0xFEFF, 
the Parent MAC Address and channel will be 0, and the Extended PAN ID will be this device's MAC Address.
@post znpResult contains the error code, or ZNP_SUCCESS if success.
*/
void getDeviceInformation()
{
    printf("Device Information Properties (MSB first)\r\n");
    getDeviceInformationProperty(DIP_STATE);
    if (znpResult != 0) return;
    printf("    Device State:               %s (%u)\r\n", getDeviceStateName(znpBuf[SRSP_DIP_VALUE_FIELD]), (znpBuf[SRSP_DIP_VALUE_FIELD])); 
    
    getDeviceInformationProperty(DIP_MAC_ADDRESS);
    printf("    MAC Address:                ");
    if (znpResult != 0) return;
    for (int i = SRSP_DIP_VALUE_FIELD+7; i>=SRSP_DIP_VALUE_FIELD; i--)
        printf("%02X ", znpBuf[i]);
    printf("\r\n");
    
    getDeviceInformationProperty(DIP_SHORT_ADDRESS);
    if (znpResult != 0) return;
    printf("    Short Address:              %04X\r\n", CONVERT_TO_INT(znpBuf[SRSP_DIP_VALUE_FIELD] , znpBuf[SRSP_DIP_VALUE_FIELD+1]));
    
    getDeviceInformationProperty(DIP_PARENT_SHORT_ADDRESS);
    if (znpResult != 0) return;
    printf("    Parent Short Address:       %04X\r\n", CONVERT_TO_INT(znpBuf[SRSP_DIP_VALUE_FIELD] , znpBuf[SRSP_DIP_VALUE_FIELD+1]));
    
    getDeviceInformationProperty(DIP_PARENT_MAC_ADDRESS);
    if (znpResult != 0) return;
    printf("    Parent MAC Address:         ");
    for (int i = SRSP_DIP_VALUE_FIELD+7; i>=SRSP_DIP_VALUE_FIELD; i--)
        printf("%02X ", znpBuf[i]);
    printf("\r\n");
    
    getDeviceInformationProperty(DIP_CHANNEL);
    if (znpResult != 0) return;
    printf("    Device Channel:             %u\r\n", znpBuf[SRSP_DIP_VALUE_FIELD]);
    
    getDeviceInformationProperty(DIP_PANID);
    if (znpResult != 0) return;
    printf("    PAN ID:                     %04X\r\n", CONVERT_TO_INT(znpBuf[SRSP_DIP_VALUE_FIELD], znpBuf[SRSP_DIP_VALUE_FIELD+1]));
    
    getDeviceInformationProperty(DIP_EXTENDED_PANID);
    if (znpResult != 0) return;
    printf("    Extended PAN ID:            ");
    for (int i = SRSP_DIP_VALUE_FIELD+7; i>=SRSP_DIP_VALUE_FIELD; i--)
        printf("%02X ", znpBuf[i]);
    printf("\r\n");
}
/** Blocking wait until a message is received. Exits if received message is a ZDO_STATE_CHANGE_IND
and the state matches what we want. Else loops. 
@param expectedState the deviceState we are expecting - DEV_ZB_COORD etc.*/
void waitForDeviceState(unsigned char expectedState)
{
    unsigned char state = 0xFF;
    while (state != expectedState)
    {
        while (SRDY_IS_HIGH());         
        pollAndDisplay();
        if (CONVERT_TO_INT(znpBuf[2], znpBuf[1]) == ZDO_STATE_CHANGE_IND)
            state = znpBuf[SRSP_PAYLOAD_START];
    }
}
/** Waits for SRDY to go low, indicating a message has arrived. Displays the msg to console, 
and find the device's MAC address using ZDO_IEEE_ADDR_REQ.
Then, if FIND_NWK_ADDRESS was defined, uses the received MAC address to find the device's short address.
The two should match.
@pre callbacks have been enabled with enableCallbacks() - otherwise you will never receive the ZDO_IEEE_ADDR_RSP message.
*/
void displayReceivedMessagesAndFindDevice()
{
    znpBuf[0] = 0;  
    unsigned int shortAddress;
    while (1) 
    {
        while (SRDY_IS_HIGH());         
        pollAndDisplay();
        if (CONVERT_TO_INT(znpBuf[2], znpBuf[1]) == AF_INCOMING_MSG)
        {
            shortAddress = CONVERT_TO_INT(znpBuf[7], znpBuf[8]);     
            zdoRequestIeeeAddress(shortAddress, SINGLE_DEVICE_RESPONSE, 0); 
            if (znpResult == 0)
            {
                printf("MAC Address (LSB first) of sender is :");
                printHexBytes(znpBuf+4, 8);
            } else {
                printf("IEEE Request Failed (%d)\r\n", znpResult);
                continue;
            }

#ifdef FIND_NWK_ADDRESS
            /** Very simple example of zdoNetworkAddressRequest() */
            unsigned char* response = zdoNetworkAddressRequest(znpBuf+4, SINGLE_DEVICE_RESPONSE, 0);  //was SINGLE_DEVICE_RESPONSE

            if (znpResult == 0)
            {
                unsigned int sa = CONVERT_TO_INT(znpBuf[12], znpBuf[13]);
                printf("Short Address = %04X\r\n", sa);
            } else {
                printf("NWK Request Failed (%d)\r\n", znpResult);
                continue;
            } 
            printZdoNetworkAddressResponse(response);
#endif            
        }
    }
}
示例#10
0
/**
 * Crea un message_t a partir de un stream de bytes apuntado por source.
 * @param   source  puntero al comienzo del mensaje serializado
 * @return  un message_t con los datos parseados.
 * @todo verificar que lenData < MAX_DATA_MESSAGE
 */
struct message_t deserializeMessage(unsigned char* source) {
    unsigned char* sourcePtr = source;
    struct message_t im;
    // header
    im.sequence = CONVERT_TO_INT( (*sourcePtr), (*(sourcePtr+1)) );
    sourcePtr += 2;
    for (int i = 0; i < 8; i++)
        im.mac[i] = *sourcePtr++;
    im.msgType = *sourcePtr++;
    im.lenData = *sourcePtr++;
    // data
    for (int i = 0; i < im.lenData; i++)
        im.data[i] = *sourcePtr++;

    return im;
}
/** 
* Utility function only used when displaying the network topology.
* Recursively iterates through the network and displays the children of a node and then the children
* of those children, and then the children of those children, etc. using recursion.
* @param shortAddress the root at which to start getting the topology. Use 0000 for the Coordinator.
* @note does not retrieve children for the same node twice. Uses a Set to keep track of which nodes
* have been searched. This is done because occasionally two nodes will list the same child.
* @see http://en.wikipedia.org/wiki/Recursion_%28computer_science%29
* @return the number of children
* @todo handle case where starting index != 0. We will have to keep track of which nodes had
* additional children, and then call zdoRequestIeeeAddress() for the next group.
*/
static uint8_t displayChildren(uint16_t shortAddress)
{
    printf("Device %04X has ", shortAddress);
    
    moduleResult_t result = zdoRequestIeeeAddress(shortAddress, INCLUDE_ASSOCIATED_DEVICES, 0);
#define MAX_CHILDREN 5  // Max of 20 from Z-Stack. Of these 20, 7 can be routers, the rest end devices. 
                        // We reduce to fit in RAM on the LaunchPad since this is called recursively
    uint8_t childCount = 0;
    uint16_t children[MAX_CHILDREN];
    
    if (result == MODULE_SUCCESS)
    {
        if (!(addToSet(&searchedSet, shortAddress)))
        {
            printf("[addToSet failed for 0x%04X\r\n]", shortAddress);
        }
        
        childCount = zmBuf[SRSP_PAYLOAD_START + ZDO_IEEE_ADDR_RSP_NUMBER_OF_ASSOCIATED_DEVICES_FIELD];
        
        if (childCount > 0)
        {
            printf("%u children, starting with #%u:", childCount, zmBuf[SRSP_PAYLOAD_START + ZDO_IEEE_ADDR_RSP_START_INDEX_FIELD]);
            int i=0;
            int j;
            for (j = 0; j < (childCount*2) - 1; j += 2) // Iterate through all the children. Each is a 2B integer
            {
                children[i] = CONVERT_TO_INT(zmBuf[(j + SRSP_PAYLOAD_START + ZDO_IEEE_ADDR_RSP_ASSOCIATED_DEVICE_FIELD_START)], zmBuf[( j + SRSP_PAYLOAD_START + ZDO_IEEE_ADDR_RSP_ASSOCIATED_DEVICE_FIELD_START + 1)]);
                printf("<%04X> ", children[i]);
                i++;
            }
            printf("\r\n");
            
            for (i=0; i<childCount; i++)                     // Iterate through all children
            {
                if (!setContains(&searchedSet, children[i])) // Don't process the same short address twice!
                {
                    displayChildren(children[i]);            // Note use of recursion here
                }
            }
        } else {
            printf("no children\r\n");
        }
    } else {
        printf("Could not locate that device (Error Code 0x%02X)\r\n", result);
    }
    return childCount;
}
示例#12
0
/** 
Creates an infoMessage from the stream of bytes starting at source
@param source the beginning of the serialized Info Message
@param info the infoMessage to create
@return the number of bytes deserialized if success, or else an error code < 0
*/
int16_t deserializeInfoMessage(unsigned char* source, struct infoMessage* info)
{
    unsigned char* sourcePtr = source;    
    info->header = deserializeHeader(sourcePtr);    // First, deserialize the header
    sourcePtr += (HEADER_SIZE);
    info->deviceType = *sourcePtr++;                // Get the deviceType
    info->numParameters = *sourcePtr++;             // ... and the number of Parameters
    if (info->numParameters > MAX_KVPS_IN_STATUS_MESSAGE)
        return -1;
    int i;
    for (i=0; i < info->numParameters; i++)  //for each Parameter:
    {
        info->kvps[i].oid = *sourcePtr++;
        info->kvps[i].value = CONVERT_TO_INT( (*sourcePtr), (*(sourcePtr+1)) );
        sourcePtr += 2;
    }
    return (sourcePtr - source);
}
示例#13
0
/** Wait until a message is received. Exits if received message is a ZDO_STATE_CHANGE_IND
and the state matches what we want. Else loops. 
@param expectedState the deviceState we are expecting - DEV_ZB_COORD etc.
@return 0 if success, -1 if timeout
*/
signed int waitForDeviceState(unsigned char expectedState)
{
    printf("Waiting for network... ");
    unsigned char state = 0xFF;
    unsigned long timeout = WAIT_FOR_DEVICE_STATE_TIMEOUT;
    while (state != expectedState)
    {
        while ((SRDY_IS_HIGH()) && (timeout > 0))
            timeout--;
        if (timeout == 0)
            return -1;  //error
        
        spiPoll();
        if (CONVERT_TO_INT(znpBuf[2], znpBuf[1]) == ZDO_STATE_CHANGE_IND)
        {
            state = znpBuf[SRSP_PAYLOAD_START];
            printf("%s ", getDeviceStateName(state));   
        }
    }
    printf("\r\n");
    return 0;
}
/** 
Displays the type of message in zmBuf.
Ignores the message if length = 0.
@pre moduleHasMessageWaiting() is true
@pre getMessage() called to get message into zmBuf
@post zmBuf Length field = 0
 */
void displayMessage()
{
	if (zmBuf[SRSP_LENGTH_FIELD] > 0)
	{
		switch ( (CONVERT_TO_INT(zmBuf[SRSP_CMD_LSB_FIELD], zmBuf[SRSP_CMD_MSB_FIELD])) )
		{
		case AF_DATA_CONFIRM:
		{
			printf("AF_DATA_CONFIRM\r\n");
			break;
		}
		case AF_INCOMING_MSG:
		{
			printf("AF_INCOMING_MSG ");
			printAfIncomingMsgHeader(zmBuf);
			printf("\r\n");
#ifdef VERBOSE_MESSAGE_DISPLAY  
			printf("Payload: ");
			printHexBytes(zmBuf+SRSP_HEADER_SIZE+17, zmBuf[SRSP_HEADER_SIZE+16]);   //print out message payload
#endif
			break;
		}
		case AF_INCOMING_MSG_EXT:
		{
			printf("AF_INCOMING_MSG_EXT\r\n");
			uint16_t len = AF_INCOMING_MESSAGE_EXT_LENGTH();
			printf("Extended Message Received, L%u ", len);
			break;
		}
		case ZDO_IEEE_ADDR_RSP:
		{
			printf("ZDO_IEEE_ADDR_RSP\r\n");
			displayZdoAddressResponse(zmBuf + SRSP_PAYLOAD_START);
			break;
		}
		case ZDO_NWK_ADDR_RSP:
		{
			printf("ZDO_NWK_ADDR_RSP\r\n");
			displayZdoAddressResponse(zmBuf + SRSP_PAYLOAD_START);
			break;
		}
		case ZDO_END_DEVICE_ANNCE_IND:
		{
			printf("ZDO_END_DEVICE_ANNCE_IND\r\n");
			displayZdoEndDeviceAnnounce(zmBuf);
			break;
		}
		case ZB_FIND_DEVICE_CONFIRM:
		{
			printf("ZB_FIND_DEVICE_CONFIRM\r\n");
			break;
		}
		case ZDO_MGMT_NWK_DISCOVERY_RSP:
		{
			printf("ZDO_MGMT_NWK_DISCOVERY_RSP\r\n");
			displayZdoNetworkDiscoveryResponse(zmBuf + SRSP_PAYLOAD_START);
			break;
		}
		case ZDO_MGMT_LEAVE_RSP:
		{
			printf("ZDO_MGMT_LEAVE_RSP\r\n");
			displayZdoManagementLeaveResponse(zmBuf);
			break;
		}
		case ZDO_JOIN_CNF:
		{
			printf("ZDO_JOIN_CNF\r\n");
			displayZdoJoinConfirm(zmBuf);
			break;
		}
		case ZDO_STATE_CHANGE_IND:
		{
			printf("ZDO_STATE_CHANGE_IND\r\n");
			displayZdoStateChangeInd(zmBuf);
			break;
		}
		default:
		{
			printf("Message received, type 0x%04X\r\n", (CONVERT_TO_INT(zmBuf[SRSP_CMD_LSB_FIELD], zmBuf[SRSP_CMD_MSB_FIELD])));
			printHexBytes(zmBuf, (zmBuf[SRSP_LENGTH_FIELD] + SRSP_HEADER_SIZE));
		}
		}
		zmBuf[SRSP_LENGTH_FIELD] = 0;
	} //ignore messages with length == 0
}
void stateMachine()
{
    while (1)
    {
        switch (state)
        {
        case STATE_IDLE:
            {
                if (stateFlags & STATE_FLAG_SEND_INFO_MESSAGE)  //if there is a pending info message to be sent
                {
                    state = STATE_SEND_INFO_MESSAGE;            //then send the message and clear the flag
                    stateFlags &= ~STATE_FLAG_SEND_INFO_MESSAGE;
                }
                //note: other flags (for different messages or events) can be added here
                break;
            }
            
        case STATE_ZNP_STARTUP:
            {
#define ZNP_START_DELAY_IF_FAIL_MS 5000
                /* Start the network; if fails then wait a second and try again. */
                signed int startResult = startZnp(END_DEVICE);
                while (startResult != ZNP_SUCCESS)
                {
                    printf("FAILED. Error Code %i, ZNP Result %i. Retrying...\r\n", startResult, znpResult);
                    delayMs(ZNP_START_DELAY_IF_FAIL_MS);
                    startResult = startZnp(END_DEVICE);
                }
                printf("Success\r\n"); 
                
                //ZNP Initialized so store MAC Address
                memcpy(hdr.mac, getMacAddress(), 8); 
#ifdef SEND_MESSAGE_ON_TIMER
                signed int timerResult = initTimer(4, WAKEUP_AFTER_TIMER);
                if (timerResult != 0)
                {
                    printf("timerResult Error %i, STOPPING\r\n", timerResult);
                    while (1);   
                }
#endif
                state = STATE_DISPLAY_NETWORK_INFORMATION;
                break;
            }
        case STATE_DISPLAY_NETWORK_INFORMATION:
            {
                printf("~ni~");
                /* On network, display info about this network */              
                getNetworkConfigurationParameters();                
                getDeviceInformation();    
                state = STATE_SEND_INFO_MESSAGE;
                break;   
            }
        case STATE_SEND_INFO_MESSAGE:
            {
                printf("~im~");
                setLed(1);
                im.header->sequence = sequenceNumber++;                
                im.cause = infoMessageCause;
                unsigned char* panid = getDeviceInformationProperty(DIP_PANID);
                im.parameters[0] = CONVERT_TO_INT(*panid, *(panid+1));      //PAN ID
                im.parameters[1] = getVcc3();                               //VCC
                im.parameters[2] = getLightSensor();                        //Light Sensor
                printInfoMessage(&im);
#define ZNP_RESTART_DELAY_IF_MESSAGE_FAIL_MS 5000
                unsigned char msgBuf[100];
                serializeInfoMessage(&im, msgBuf);
                afSendData(DEFAULT_ENDPOINT,DEFAULT_ENDPOINT,0, INFO_MESSAGE_CLUSTER, msgBuf, getSizeOfInfoMessage(&im));
                if (znpResult != ZNP_SUCCESS)
                {
                    printf("afSendData error %i; restarting...\r\n", znpResult);
                    delayMs(ZNP_RESTART_DELAY_IF_MESSAGE_FAIL_MS);  //allow enough time for coordinator to fully restart, if that caused our problem
                    state = STATE_ZNP_STARTUP;
                } else {      
                    state = STATE_IDLE;
                    clearLeds();        
                    HAL_SLEEP();                    
                }
                break;   
            }
        default:     //should never happen
            {
                printf("UNKNOWN STATE\r\n");
                state = STATE_ZNP_STARTUP;
            }
            break;
        }
    } 
}