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; }
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; } } }