static void stateMachine()
{
    while (1)
    {
        if (zigbeeNetworkStatus == NWK_ONLINE)
        {
            if(moduleHasMessageWaiting())      //wait until SRDY goes low indicating a message has been received.   
                displayMessages();
        }

        switch (state)
        {
        case STATE_IDLE:
        {
            /* process command line commands only if not doing anything else: */
            if (command != NO_CHARACTER_RECEIVED)
            {
                /* parse the command entered, and go to the required state */
                state = processCommand(command);

                command = NO_CHARACTER_RECEIVED;
            }
            /* note: other flags (for different messages or events) can be added here */
            break;
        }
        case STATE_INIT:
        {
            printf("Starting State Machine\r\n");
            state = STATE_GET_DEVICE_TYPE;
            break;
        }
        /* A button press during startup will cause the application to prompt for device type */
        case STATE_GET_DEVICE_TYPE: 
        {
            //printf("Current Configured DeviceType: %s\r\n", getDeviceTypeName());
            set_type:                
            /* if saving device type to flash memory:
                printf("Any other key to exit. Timeout in 5 seconds.\r\n");
                / long wait = 0;
                long timeout = TICKS_IN_ONE_MS * 5000l;
                while ((command == NO_CHARACTER_RECEIVED) && (wait != timeout))
                wait++;
             */
            while (command == NO_CHARACTER_RECEIVED)
            {
                printf("Setting Device Type: Press C for Coordinator, R for Router, or E for End Device.\r\n");
                delayMs(2000);
            }

            switch (command)
            {
            case 'C':
            case 'c':
                printf("Coordinator it is...\r\n");
                zigbeeDeviceType = COORDINATOR;
                break;
            case 'R':
            case 'r':
                printf("Router it is...\r\n");
                zigbeeDeviceType = ROUTER;
                break;

            case 'E':
            case 'e':
                printf("End Device it is...\r\n");
                zigbeeDeviceType = END_DEVICE;
                break;
            default:
                command = NO_CHARACTER_RECEIVED;
                goto set_type;

            }
            command = NO_CHARACTER_RECEIVED;
            state = STATE_MODULE_STARTUP;
            break;
        }
        case STATE_MODULE_STARTUP:
        {
#define MODULE_START_DELAY_IF_FAIL_MS 5000
            moduleResult_t result;
            /* Start with the default module configuration */
            struct moduleConfiguration defaultConfiguration = DEFAULT_MODULE_CONFIGURATION_COORDINATOR;
            /* Make any changes needed here (channel list, PAN ID, etc.)
                   We Configure the Zigbee Device Type (Router, Coordinator, End Device) based on what user selected */
            defaultConfiguration.deviceType = zigbeeDeviceType;
            while ((result = startModule(&defaultConfiguration, GENERIC_APPLICATION_CONFIGURATION)) != MODULE_SUCCESS)
            {
                printf("Module start unsuccessful. Error Code 0x%02X. Retrying...\r\n", result);
                delayMs(MODULE_START_DELAY_IF_FAIL_MS);
            }
            printf("Success\r\n");
            state = STATE_DISPLAY_NETWORK_INFORMATION;
            zigbeeNetworkStatus = NWK_ONLINE;
            break;
        }
        case STATE_DISPLAY_NETWORK_INFORMATION:                 
        {
            printf("Module Information:\r\n");
            /* On network, display info about this network */
            displayNetworkConfigurationParameters();
            displayDeviceInformation();
            displayCommandLineInterfaceHelp();
            state = STATE_IDLE;   //startup is done!
            break;
        }
        case STATE_VALID_SHORT_ADDRESS_ENTERED:  //command line processor has a valid shortAddressEntered
        {
            printf("Valid Short Address Entered\r\n");
            state = pendingState;
            break;
        }
        case STATE_VALID_LONG_ADDRESS_ENTERED:
        {
            /* flip byte order */
            int8_t temp[8];
            int i;
            for (i=0; i<8; i++)
                temp[7-i] = longAddressEntered[i];

            memcpy(longAddressEntered, temp, 8);  //Store LSB first since that is how it will be sent:
            state = pendingState;
            break;
        }
        case STATE_SEND_MESSAGE_VIA_SHORT_ADDRESS:
        {
            printf("Send via short address to %04X\r\n", shortAddressEntered);
            moduleResult_t result = afSendData(DEFAULT_ENDPOINT,DEFAULT_ENDPOINT,shortAddressEntered, TEST_CLUSTER, testMessage, 5);
            if (result == MODULE_SUCCESS)
            {
                printf("Success\r\n");
            } else {
                printf("Could not send to that device (Error Code 0x%02X)\r\n", result);

#ifdef RESTART_AFTER_ZM_FAILURE
                printf("\r\nRestarting\r\n");
                state = STATE_MODULE_STARTUP;
                continue;
#endif
            }
            state = STATE_IDLE;
            break;
        }
        case STATE_SEND_MESSAGE_VIA_LONG_ADDRESS:
        {
            printf("Send via long address to (LSB first)");
            printHexBytes(longAddressEntered, 8);
            moduleResult_t result = afSendDataExtended(DEFAULT_ENDPOINT, DEFAULT_ENDPOINT, longAddressEntered,
                    DESTINATION_ADDRESS_MODE_LONG, TEST_CLUSTER, testMessage, 5);
            if (result == MODULE_SUCCESS)
            {
                printf("Success\r\n");
            } else {
                printf("Could not send to that device (Error Code 0x%02X)\r\n", result);
#ifdef RESTART_AFTER_ZM_FAILURE
                printf("\r\nRestarting\r\n");
                state = STATE_MODULE_STARTUP;
                continue;
#endif
            }
            state = STATE_IDLE;
            break;
        }
        case STATE_FIND_VIA_SHORT_ADDRESS:
        {
            printf("Looking for that device...\r\n");
            moduleResult_t result = zdoRequestIeeeAddress(shortAddressEntered, SINGLE_DEVICE_RESPONSE, 0);
            if (result == MODULE_SUCCESS)
            {
#ifndef ZDO_NWK_ADDR_RSP_HANDLED_BY_APPLICATION
                displayZdoAddressResponse(zmBuf + SRSP_PAYLOAD_START);
#endif
            } else {
                printf("Could not locate that device (Error Code 0x%02X)\r\n", result);
            }
            state = STATE_IDLE;
            break;
        }
        case STATE_FIND_VIA_LONG_ADDRESS:
        {
            printf("Looking for that device...\r\n");
            moduleResult_t result = zdoNetworkAddressRequest(longAddressEntered, SINGLE_DEVICE_RESPONSE, 0);
            if (result == MODULE_SUCCESS)
            {
#ifndef ZDO_NWK_ADDR_RSP_HANDLED_BY_APPLICATION
                displayZdoAddressResponse(zmBuf + SRSP_PAYLOAD_START);
#endif
            } else {
                printf("Could not locate that device (Error Code 0x%02X)\r\n", result);
            }
            state = STATE_IDLE;
            break;
        }
        default:     //should never happen
        {
            printf("UNKNOWN STATE (%u)\r\n", state);
            state = STATE_IDLE;
        }
        break;
        }
    }
}
/** Process characters typed in by the user. Normally this will fire off a menu command, unless
we are awaiting the user to enter a two-byte (four ascii character) short address or eight byte
(16 ascii character) long address.
@note: processCommand modifies variables shortAddressEntered and longAddressEntered
 @return the state to transition to next
 */
enum STATE processCommand(char cmd)
{
#define ESCAPE_KEY 0x1B
    if (cmd == ESCAPE_KEY)
    {
        printf("Resetting Command Line Interpreter\r\n");
        commandLineInterfaceMode = CLI_MODE_NORMAL;
        cliInputBufferIndex = 0;
        pendingState = STATE_IDLE;
        displayCommandLineInterfaceHelp();
        return STATE_IDLE;
    }

    if (cmd == '\r')
    {
        printf("\r\n");
        return STATE_IDLE;
    }

    if (commandLineInterfaceMode == CLI_MODE_NORMAL)
    {
        switch (cmd)
        {
        case '?':
            displayCommandLineInterfaceHelp();
            return STATE_IDLE;
        case 'n':
        case 'N':
            return STATE_DISPLAY_NETWORK_INFORMATION;
        case 'r':
        case 'R':
            return STATE_INIT;
        case 'S':
        case 's':
        {
            printf("Enter short address of destination, for example '2F6B' or Escape key to exit\r\n");
            commandLineInterfaceMode = CLI_MODE_ENTER_SHORT_ADDRESS;    // Next, get a short address typed by the user
            pendingState = STATE_SEND_MESSAGE_VIA_SHORT_ADDRESS;  // After a full short address has been entered
            return STATE_IDLE;
        }
        case 'L':
        case 'l':
        {
            printf("Enter long (MAC) address of destination, for example '00124B0012345678' or Escape key to exit\r\n");
            commandLineInterfaceMode = CLI_MODE_ENTER_LONG_ADDRESS;
            pendingState = STATE_SEND_MESSAGE_VIA_LONG_ADDRESS;  //when a full long address has been entered
            return STATE_IDLE;
        }
        case 'h':
        case 'H':
        {
            printf("Enter two byte short address to find, for example '2F6B' or press Escape key to exit\r\n");
            commandLineInterfaceMode = CLI_MODE_ENTER_SHORT_ADDRESS;
            pendingState = STATE_FIND_VIA_SHORT_ADDRESS;  //when a full short address has been entered
            return STATE_IDLE;
        }
        case 'j':
        case 'J':
        {
            printf("Enter eight byte long (MAC) address to find, for example '00124B0012345678' or press Escape key to exit\r\n");
            commandLineInterfaceMode = CLI_MODE_ENTER_LONG_ADDRESS;
            pendingState = STATE_FIND_VIA_LONG_ADDRESS;  //when a full long address has been entered
            return STATE_IDLE;
        }
        case 'v':
        case 'V':
        {
            printf("Module Version Information:\r\n");
            if (sysVersion() == MODULE_SUCCESS)                  //gets the version string
            {
                displaySysVersion();  // Display the contents of the received SYS_VERSION
            } else {
                printf("ERROR\r\n");
            }
            return STATE_IDLE;
        }

        /* Note: more commands can be added here */

        default:
            printf("Unknown command %c\r\n", cmd);
        }
        return STATE_IDLE;

    } else if (commandLineInterfaceMode == CLI_MODE_ENTER_SHORT_ADDRESS)    //accepts two hex numbers (4 ASCII characters)
    {
        if (IS_VALID_HEXADECIMAL_CHARACTER(cmd))
        {
            TO_UPPER_CASE(cmd);
            printf("%c", cmd);  //echo output
            cliInputBuffer[cliInputBufferIndex++] = (char) cmd;
            if (cliInputBufferIndex == 4)  
            {
                cliInputBuffer[4] = 0; //null terminate it so we can treat it as a string
                //now attempt to convert it:
                long val = 0;
                errno = 0;      // used in stdlib.h
                val = strtol(cliInputBuffer, NULL, 16);    // Interpret the string as a hex number
                if (errno != 0) // Should have already been error checked, but validate anyway
                {
                    printf("strtol parse error\r\n");
                } else { //no errors
                    shortAddressEntered = (uint16_t) val;
                    printf("Short Address = 0x%04X\r\n", shortAddressEntered);
                    //we're all done, so clear out buffers:
                    commandLineInterfaceMode = CLI_MODE_NORMAL;
                    cliInputBufferIndex = 0;
                    return STATE_VALID_SHORT_ADDRESS_ENTERED;
                }
                commandLineInterfaceMode = CLI_MODE_NORMAL;
                cliInputBufferIndex = 0;
                return STATE_IDLE;
            }
            /* Continue, since our buffer isn't full yet - leave settings alone */

        } else {
            /* not a hex number! */
            printf("\r\nNumber must be in hex: 0..9 or a..f inclusive\r\nAborting\r\n");
            displayCommandLineInterfaceHelp();
            commandLineInterfaceMode = CLI_MODE_NORMAL;
            cliInputBufferIndex = 0;
        }
        return STATE_IDLE;

    } else if (commandLineInterfaceMode == CLI_MODE_ENTER_LONG_ADDRESS)  //accepts eight hex numbers (16 ASCII characters)
    {

        if (IS_VALID_HEXADECIMAL_CHARACTER(cmd))
        {
            TO_UPPER_CASE(cmd);
            printf("%c", cmd);  //echo output

            cliInputBuffer[cliInputBufferIndex++] = (char) cmd;

            /* To used a tokenized substring splitter method, add a '-' at the end of each 2 characters. */
            if ((cliInputBufferIndex != 0) && ((cliInputBufferIndex+1) % 3 == 0) && (cliInputBufferIndex != 23))
            {
                cliInputBuffer[cliInputBufferIndex++] = '-';
                printf("-");
            }

            if (cliInputBufferIndex == 23)
            {
                printf("\r\nParsed '%s' into:", cliInputBuffer);

                /* now attempt to convert it: */
                char *substr = NULL;
                substr = strtok(cliInputBuffer,"-");    // Initialize string splitter

                /* Loops until there are no more substrings*/
                uint8_t parsedMacIndex = 0;
                while(substr!=NULL)
                {
                    /* Process the substring */
                    long val = 0;
                    /* errno is used in stdlib.h to indicate a parse error */
                    errno = 0;     
                    val = strtol(substr, NULL, 16);    // Interpret the string as a hex number
                    if (errno != 0) // Should have already been error checked, but validate anyway
                    {
                        printf("strtol parse error\r\n");
                        commandLineInterfaceMode = CLI_MODE_NORMAL;
                        cliInputBufferIndex = 0;
                        return STATE_IDLE;

                    } else { //no errors
                        longAddressEntered[parsedMacIndex] = (uint16_t) val;
                        printf("%02X ", longAddressEntered[parsedMacIndex]);
                    }
                    parsedMacIndex++;

                    substr = strtok(NULL,"-");  //Get the next substring
                }
                printf("\r\n");

                /* Now we have the mac address */
                if (!((longAddressEntered[0] == 0x00) &&
                        (longAddressEntered[1] == 0x12) &&
                        (longAddressEntered[2] == 0x4b)))
                    printf("Warning - MAC does not have 00-12-4B as first three bytes!\r\n");
                commandLineInterfaceMode = CLI_MODE_NORMAL;
                cliInputBufferIndex = 0;
                return STATE_VALID_LONG_ADDRESS_ENTERED;
            }

            /* continue, since our buffer isn't full yet - leave settings alone */
        } else {  //not a hex number!
            printf("Number must be in hex: 0..9 or a..f inclusive\r\nAborting\r\n");
            displayCommandLineInterfaceHelp();
            commandLineInterfaceMode = CLI_MODE_NORMAL;
            cliInputBufferIndex = 0;
        }  

        return STATE_IDLE;
    }

    return STATE_IDLE;
}
Ejemplo n.º 3
0
static void stateMachine()
{
    while (1)
    {
        if (zigbeeNetworkStatus == NWK_ONLINE)
        {
            if(moduleHasMessageWaiting())      //wait until SRDY goes low indicating a message has been received.
            {
                getMessage();                 
                displayMessage();          
            }   
        }
        
        switch (state)
        {
        case STATE_IDLE:
            {
                /* process command line commands only if not doing anything else: */
                if (command != NO_CHARACTER_RECEIVED)
                {
                    /* parse the command entered, and go to the required state */
                    state = processCommand(command);                    
                    command = NO_CHARACTER_RECEIVED;
                }
                /* note: other flags (for different messages or events) can be added here */
                break;
            }
        case STATE_INIT:
            {
                printf("Starting State Machine\r\n");
                state = STATE_GET_DEVICE_TYPE;
                break;
            }
            /* A button press during startup will cause the application to prompt for device type */
        case STATE_GET_DEVICE_TYPE: 
            {
            set_type:                
                while (command == NO_CHARACTER_RECEIVED)
                {
                    printf("Setting Device Type: Press C for Coordinator, R for Router, or E for End Device.\r\n");
#define DEVICE_TYPE_DELAY_MS    2000
#define DEVICE_TYPE_DELAY_PER_CYCLE_MS  100
                    uint16_t delayCycles = DEVICE_TYPE_DELAY_MS / DEVICE_TYPE_DELAY_PER_CYCLE_MS;
                    while ((command == NO_CHARACTER_RECEIVED) && (delayCycles--) > 0)
                        delayMs(DEVICE_TYPE_DELAY_PER_CYCLE_MS);
                }
                
                switch (command)
                {
                case 'C':
                case 'c':
                    printf("Coordinator it is...\r\n");
                    zigbeeDeviceType = COORDINATOR;
                    break;
                case 'R':
                case 'r':
                    printf("Router it is...\r\n");
                    zigbeeDeviceType = ROUTER;
                    break;
                    
                case 'E':
                case 'e':
                    printf("End Device it is...\r\n");
                    zigbeeDeviceType = END_DEVICE;
                    break;
                default:
                    command = NO_CHARACTER_RECEIVED;
                    goto set_type;
                    
                }
                command = NO_CHARACTER_RECEIVED;
                state = STATE_MODULE_STARTUP;
                break;
            }
        case STATE_MODULE_STARTUP:
            {
#define MODULE_START_DELAY_IF_FAIL_MS 5000
                moduleResult_t result;
                /* Start with the default module configuration */
                struct moduleConfiguration defaultConfiguration = DEFAULT_MODULE_CONFIGURATION_COORDINATOR;
                /* Make any changes needed here (channel list, PAN ID, etc.)
                We Configure the Zigbee Device Type (Router, Coordinator, End Device) based on what user selected */
                defaultConfiguration.deviceType = zigbeeDeviceType;
                
                /* Change this below to be your operating region - MODULE_REGION_NORTH_AMERICA or MODULE_REGION_EUROPE */
#define OPERATING_REGION    (MODULE_REGION_NORTH_AMERICA) // or MODULE_REGION_EUROPE
                
                while ((result = expressStartModule(&defaultConfiguration, GENERIC_APPLICATION_CONFIGURATION, OPERATING_REGION)) != MODULE_SUCCESS)
                {
                    SET_NETWORK_FAILURE_LED_ON();          // Turn on the LED to show failure
                    handleModuleError(result);
                    printf("Retrying...\r\n");
                    delayMs(MODULE_START_DELAY_IF_FAIL_MS/2);                    
                    SET_NETWORK_FAILURE_LED_OFF();
                    delayMs(MODULE_START_DELAY_IF_FAIL_MS/2);
                }                
                printf("Success\r\n");
                state = STATE_DISPLAY_NETWORK_INFORMATION;
                zigbeeNetworkStatus = NWK_ONLINE;
                break;
            }
        case STATE_DISPLAY_NETWORK_INFORMATION:                 
            {
                printf("Module Information:\r\n");
                /* On network, display info about this network */
                displayNetworkConfigurationParameters();
                displayDeviceInformation();
                displayCommandLineInterfaceHelp();
                state = STATE_IDLE;   //startup is done!
                break;
            }
        case STATE_VALID_SHORT_ADDRESS_ENTERED:  //command line processor has a valid shortAddressEntered
            {
                state = pendingState;
                break;
            }
        case STATE_VALID_LONG_ADDRESS_ENTERED:
            {
                /* Flip byte order because we need to send it LSB first */
                int8_t temp[8];
                int i;
                for (i=0; i<8; i++)
                    temp[7-i] = longAddressEntered[i];
                
                memcpy(longAddressEntered, temp, 8);  //Store LSB first since that is how it will be sent:
                state = pendingState;
                break;
            }
        case STATE_SEND_MESSAGE_VIA_SHORT_ADDRESS:
            {
                printf("Send to 0x%04X\r\n", shortAddressEntered);
                moduleResult_t result = afSendData(DEFAULT_ENDPOINT,DEFAULT_ENDPOINT,shortAddressEntered, TEST_CLUSTER, testMessage, 5);
                if (result == MODULE_SUCCESS)
                {
                    printf("Success\r\n");
                } else {
                    handleModuleError(result);                    
#ifdef RESTART_AFTER_ZM_FAILURE
                    printf("\r\nRestarting\r\n");
                    state = STATE_MODULE_STARTUP;
                    continue;
#endif
                }
                state = STATE_IDLE;
                break;
            }
        case STATE_SEND_MESSAGE_VIA_LONG_ADDRESS:
            {
                printf("Send to (LSB first)");
                printHexBytes(longAddressEntered, 8);
                moduleResult_t result = afSendDataExtended(DEFAULT_ENDPOINT, DEFAULT_ENDPOINT, longAddressEntered,
                                                           DESTINATION_ADDRESS_MODE_LONG, TEST_CLUSTER, testMessage, 5);
                if (result == MODULE_SUCCESS)
                {
                    printf("Success\r\n");
                } else {
                    handleModuleError(result);
#ifdef RESTART_AFTER_ZM_FAILURE
                    printf("\r\nRestarting\r\n");
                    state = STATE_MODULE_STARTUP;
                    continue;
#endif
                }
                state = STATE_IDLE;
                break;
            }
            
#ifdef LEAVE_REQUEST            
        case STATE_MANAGEMENT_LEAVE_REQUEST:
            {
                printf("Sending Leave Request for MAC (LSB first)");
                printHexBytes(longAddressEntered, 8);
                moduleResult_t result = zdoManagementLeaveRequest(longAddressEntered, 0);
                
                if (result == MODULE_SUCCESS)
                {
                    printf("Success\r\n");
                } else {
                    handleModuleError(result);
                }
                state = STATE_IDLE;
                break;
            }
#endif
            
        case STATE_FIND_VIA_SHORT_ADDRESS:
            {
                printf("Looking for that device...\r\n");
                moduleResult_t result = zdoRequestIeeeAddress(shortAddressEntered, INCLUDE_ASSOCIATED_DEVICES, 0);
                if (result == MODULE_SUCCESS)
                {
#ifndef ZDO_NWK_ADDR_RSP_HANDLED_BY_APPLICATION
                    displayZdoAddressResponse(zmBuf + SRSP_PAYLOAD_START);
#endif
                } else {
                    handleModuleError(result);
                }
                state = STATE_IDLE;
                break;
            }
            
        case STATE_FIND_VIA_LONG_ADDRESS:
            {
                printf("Looking for that device...\r\n");
                moduleResult_t result = zdoNetworkAddressRequest(longAddressEntered, INCLUDE_ASSOCIATED_DEVICES, 0);
                if (result == MODULE_SUCCESS)
                {
#ifndef ZDO_NWK_ADDR_RSP_HANDLED_BY_APPLICATION
                    displayZdoAddressResponse(zmBuf + SRSP_PAYLOAD_START);
#endif
                } else {
                    handleModuleError(result);
                }
                state = STATE_IDLE;
                break;
            }
            
#ifdef INCLUDE_PERMIT_JOIN        
        case STATE_SET_PERMIT_JOIN_ON:
            {
                printf("Turning joining ON...\r\n");
                moduleResult_t result = zdoManagementPermitJoinRequest(shortAddressEntered, PERMIT_JOIN_ON_INDEFINITELY, 0);
                if (result == MODULE_SUCCESS)
                {
                    printf("Success\r\n");
                } else {
                    handleModuleError(result);
                }
                state = STATE_IDLE;
                break; 
            }
            
        case STATE_SET_PERMIT_JOIN_OFF:
            {
                printf("Turning joining OFF...\r\n");
                moduleResult_t result = zdoManagementPermitJoinRequest(shortAddressEntered, PERMIT_JOIN_OFF, 0);
                if (result == MODULE_SUCCESS)
                {
                    printf("Success\r\n");
                } else {
                    handleModuleError(result);
                }
                state = STATE_IDLE;
                break; 
            }   
#endif
            
#ifdef DISCOVER_NETWORKS             
        case STATE_NETWORK_DISCOVERY_REQUEST:
            {
                printf("Scanning...\r\n");
                moduleResult_t result = zdoNetworkDiscoveryRequest(ANY_CHANNEL_MASK, BEACON_ORDER_480_MSEC);
                if (result == MODULE_SUCCESS)
                {
                    printf("Success\r\n");
                } else {
                    handleModuleError(result);
                }
                state = STATE_IDLE;
                break; 
            }
#endif
            
#ifdef INCLUDE_NETWORK_TOPOLOGY
        case STATE_GET_NETWORK_TOPOLOGY:
            {
                printf("Displaying NWK Topology...........\r\n");                
                initSet(&searchedSet);
                // Start the recursive search for all children of the short address
                //removeAllFromSet();
                int8_t numChildren = displayChildren(shortAddressEntered);
                state = STATE_IDLE;
                break;
            }
#endif
            
        default:     //should never happen
            {
                printf("UNKNOWN STATE (%u)\r\n", state);
                state = STATE_IDLE;
            }
            break;
        }
    }
}