CLI commands various options.

License#

Copyright 2018 Silicon Laboratories Inc. www.silabs.com

The licensor of this software is Silicon Laboratories Inc. Your use of this software is governed by the terms of Silicon Labs Master Software License Agreement (MSLA) available at www.silabs.com/about-us/legal/master-software-license-agreement. This software is distributed to you in Source Code format and is governed by the sections of the MSLA applicable to Source Code.

/***************************************************************************/
// Common include files:
#include "app/framework/util/common.h"

#include "app/framework/security/af-security.h"
#include "app/framework/util/af-main.h"
#include "app/framework/util/service-discovery.h"
#include "app/util/serial/command-interpreter2.h"

// *****************************************************************************
// Forward Declarations
// *****************************************************************************

void optionPrintRxCommand(void);
void optionRegisterCommand(void);
void optionDiscoverCommand(void);
void optionBindingTablePrintCommand(void);
void optionBindingTableClearCommand(void);
void optionEndDeviceBindCommand(void);
void optionApsRetryCommand(void);
void optionApsSecurityCommand(void);
void optionLinkCommand(void);
void optionBindingTableSetCommand(void);
void optionPrintRouteCommand(void);
void optionInstallCodeCommand(void);
void optionDiscoveryTargetCommand(void);

// *****************************************************************************
// Globals
// *****************************************************************************

#ifndef EMBER_AF_GENERATE_CLI

// option print-rx-msgs enable
// option print-rx-msgs disable
static EmberCommandEntry optionPrintRxCommands[] = {
  { "enable", optionPrintRxCommand, "" },
  { "disable", optionPrintRxCommand, "" },
  { NULL }
};

// option binding-table print
// option binding-table clear
// option binding-table set <index> <cluster> <local ep> <remote ep> <EUI>
static EmberCommandEntry optionBindingCommands[] = {
  { "print", optionBindingTablePrintCommand, "" },
  { "clear", optionBindingTableClearCommand, "" },
  { "set", optionBindingTableSetCommand, "uvuub" },
  { NULL }
};

// option security aps [off|on]
static EmberCommandEntry optionApsSecurityCommands[] = {
  { "on", optionApsSecurityCommand, "" },
  { "off", optionApsSecurityCommand, "" },
  { NULL }
};

static EmberCommandEntry apsRetryCommands[] = {
  { "on", optionApsRetryCommand, "" },
  { "off", optionApsRetryCommand, "" },
  { "def", optionApsRetryCommand, "" },
  { NULL }
};

static EmberCommandEntry optionSecurityCommands[] = {
  { "aps", NULL, (const char *)optionApsSecurityCommands },
  { NULL }
};

EmberCommandEntry emAfOptionCommands[] = {
  { "print-rx-msgs", NULL, (const char *)optionPrintRxCommands },
  { "register", optionRegisterCommand, "" },

  emberCommandEntryAction("disc", optionDiscoverCommand, "vv",
                          "Perform a match descriptor request"),
  emberCommandEntryAction("target", optionDiscoveryTargetCommand, "v",
                          "Set the target address of the CLI discovery"),

  { "binding-table", NULL, (const char *)optionBindingCommands },

  { "edb", optionEndDeviceBindCommand, "u" },
  { "security", NULL, (const char *)optionSecurityCommands },
  { "apsretry", NULL, (const char *)apsRetryCommands },

#ifdef DEBUG_PRINT_FOR_ROUTING_TABLE
  { "route", optionPrintRouteCommand, "" },
#endif

#if EMBER_KEY_TABLE_SIZE > 0
  { "link", optionLinkCommand, "ubb" },
  { "install-code", optionInstallCodeCommand, "ubb" },
#endif
  { NULL }
};

#endif // EMBER_AF_GENERATE_CLI

static EmberNodeId discoveryTargetNodeId = EMBER_RX_ON_WHEN_IDLE_BROADCAST_ADDRESS;

// *****************************************************************************
// Functions
// *****************************************************************************

void emAfCliServiceDiscoveryCallback(const EmberAfServiceDiscoveryResult* result)
{
#if defined(EMBER_AF_PRINT_ENABLE) && defined(EMBER_AF_PRINT_APP)
  if (!emberAfHaveDiscoveryResponseStatus(result->status)) {
    // Do nothing
  } else if (result->zdoRequestClusterId == MATCH_DESCRIPTORS_REQUEST) {
    const EmberAfEndpointList* epList = (const EmberAfEndpointList*)result->responseData;
    emberAfAppPrintln("Match %py from 0x%2X, ep %d",
                      "discover",
                      result->matchAddress,
                      epList->list[0]);
  } else if (result->zdoRequestClusterId == NETWORK_ADDRESS_REQUEST) {
    emberAfAppPrintln("NWK Address response: 0x%2X", result->matchAddress);
  } else if (result->zdoRequestClusterId == IEEE_ADDRESS_REQUEST) {
    const uint8_t* eui64ptr = (uint8_t*)(result->responseData);
    emberAfAppPrint("IEEE Address response: ");
    emberAfPrintBigEndianEui64(eui64ptr);
    emberAfAppPrintln("");
  } else {
    // MISRA requires ..else if.. to have a terminating else.
  }

  if (result->status != EMBER_AF_BROADCAST_SERVICE_DISCOVERY_RESPONSE_RECEIVED) {
    emberAfAppPrintln("Service %py done.",
                      "discover");
  }
#endif //defined(EMBER_AF_PRINT_ENABLE) && defined(EMBER_AF_PRINT_APP)
}

// option print-rx-msgs [enable | disable]
void optionPrintRxCommand(void)
{
  if (emberCurrentCommand->name[0] == 'e') {
    emberAfPrintReceivedMessages = true;
  } else {
    emberAfPrintReceivedMessages = false;
  }
  emberAfAppPrintln("%pd print",
                    (emberAfPrintReceivedMessages
                     ? "enable"
                     : "disable"));
}

// option register
void optionRegisterCommand(void)
{
  emberAfRegistrationStartCallback();
}

void optionDiscoveryTargetCommand(void)
{
  discoveryTargetNodeId = (uint16_t)emberUnsignedCommandArgument(0);
}

// option disc <profileId> <clusterId>
void optionDiscoverCommand(void)
{
  EmberAfProfileId profileId = (uint16_t)emberUnsignedCommandArgument(0);
  EmberAfClusterId clusterId = (uint16_t)emberUnsignedCommandArgument(1);
  emberAfFindDevicesByProfileAndCluster(discoveryTargetNodeId,
                                        profileId,
                                        clusterId,
                                        EMBER_AF_SERVER_CLUSTER_DISCOVERY,
                                        emAfCliServiceDiscoveryCallback);
}

// option binding-table print
void optionBindingTablePrintCommand(void)
{
#if defined(EMBER_AF_PRINT_ENABLE) && defined(EMBER_AF_PRINT_APP)
  uint8_t i;
  EmberBindingTableEntry result;

  const char * typeStrings[] = {
    "EMPTY",
    "UNICA",
    "M2ONE",
    "MULTI",
    "?    ",
  };
  uint8_t bindings = 0;

  emberAfAppPrintln("#  type   nwk  loc   rem   clus   node   eui");
  for (i = 0; i < emberAfGetBindingTableSize(); i++) {
    EmberStatus status = emberGetBinding(i, &result);
    if (status == EMBER_SUCCESS) {
      if (result.type > EMBER_MULTICAST_BINDING) {
        result.type = 4;  // last entry in the string list above
      }
      if (result.type != EMBER_UNUSED_BINDING) {
        bindings++;
        emberAfAppPrint("%d: ", i);
        emberAfAppPrint("%p", typeStrings[result.type]);
        emberAfAppPrint("  %d    0x%x  0x%x  0x%2x 0x%2x ",
                        result.networkIndex,
                        result.local,
                        result.remote,
                        result.clusterId,
                        emberGetBindingRemoteNodeId(i));
        emberAfAppDebugExec(emberAfPrintBigEndianEui64(result.identifier));
        emberAfAppPrintln("");
      }
    } else {
      emberAfAppPrintln("0x%x: emberGetBinding Error: %x", status);
      emberAfAppFlush();
    }
    emberAfAppFlush();
  }
  emberAfAppPrintln("%d of %d bindings used",
                    bindings,
                    emberAfGetBindingTableSize());
#endif //defined(EMBER_AF_PRINT_ENABLE) && defined(EMBER_AF_PRINT_APP)
}

// option binding-table clear
void optionBindingTableClearCommand(void)
{
  emberClearBindingTable();
}

// option edb <endpoint>
void optionEndDeviceBindCommand(void)
{
  uint8_t endpoint = (uint8_t)emberUnsignedCommandArgument(0);
  emberAfSendEndDeviceBind(endpoint);
}

void optionApsRetryCommand(void)
{
  if ( emberCurrentCommand->name[1] == 'e' ) {
    emberAfSetRetryOverride(EMBER_AF_RETRY_OVERRIDE_NONE);
  } else if ( emberCurrentCommand->name[1] == 'n' ) {
    emberAfSetRetryOverride(EMBER_AF_RETRY_OVERRIDE_SET);
  } else if ( emberCurrentCommand->name[1] == 'f' ) {
    emberAfSetRetryOverride(EMBER_AF_RETRY_OVERRIDE_UNSET);
  } else {
    // MISRA requires ..else if.. to have a terminating else.
  }
}

// option security aps <off | on>
void optionApsSecurityCommand(void)
{
  emAfTestApsSecurityOverride = (emberCurrentCommand->name[1] == 'f'
                                 ? APS_TEST_SECURITY_DISABLED
                                 : APS_TEST_SECURITY_ENABLED);
}

// option link <index> <eui64 in big endian format> <key in big endian format>
void optionLinkCommand(void)
{
  EmberEUI64 partnerEUI64;
  EmberKeyData newKey;
  EmberStatus status;
  //uint8_t i;
  uint8_t index = (uint8_t)emberUnsignedCommandArgument(0);
  emberCopyBigEndianEui64Argument(1, partnerEUI64);
  emberCopyKeyArgument(2, &newKey);
  status = emberSetKeyTableEntry(index,
                                 partnerEUI64,
                                 true,
                                 &newKey);
  UNUSED_VAR(status);
  emberAfAppDebugExec(emAfPrintStatus("add link key", status));
  emberAfAppPrintln("");
  emberAfCoreFlush();
}

// option install-code <index> <eui64> <install code>
void optionInstallCodeCommand(void)
{
#if (defined(EMBER_AF_HAS_SECURITY_PROFILE_SE_TEST) \
  || defined(EMBER_AF_HAS_SECURITY_PROFILE_SE_FULL) \
  || defined (EMBER_AF_HAS_SECURITY_PROFILE_Z3))

  EmberEUI64 eui64;
  EmberKeyData key;
  EmberStatus status;
  uint8_t code[16 + 2]; // 6, 8, 12, or 16 bytes plus two-byte CRC
  uint8_t length;

  length = emberCopyStringArgument(2, code, sizeof(code), false);

  // Convert the install code to a key.
  status = emAfInstallCodeToKey(code, length, &key);

  if (EMBER_SUCCESS != status) {
    if (EMBER_SECURITY_DATA_INVALID == status) {
      emberAfAppPrintln("ERR: Calculated CRC does not match");
    } else if (EMBER_BAD_ARGUMENT == status) {
      emberAfAppPrintln("ERR: Install Code must be 8, 10, 14, or 18 bytes in "
                        "length");
    } else {
      emberAfAppPrintln("ERR: AES-MMO hash failed: 0x%x", status);
    }
    return;
  }

  emberCopyBigEndianEui64Argument(1, eui64);

  #ifndef EMBER_AF_HAS_SECURITY_PROFILE_Z3
  // Add the key to the link key table.
  status = emberSetKeyTableEntry((uint8_t)emberUnsignedCommandArgument(0),     // index
                                 eui64,
                                 true,                                       // link key
                                 &key);
  emberAfAppDebugExec(emAfPrintStatus("add link key", status));
  emberAfAppPrintln("");
  emberAfAppFlush();
  #else
  // Add the key to the transient key table.
  // This will be used while the DUT joins.
  if (EMBER_SUCCESS == status) {
    status = emberAddTransientLinkKey(eui64, &key);
    emberAfAppDebugExec(emAfPrintStatus("Set joining link key", status));
    emberAfAppPrintln("");
    emberAfAppFlush();
  }
  #endif

#else
  emberAfAppPrintln("This command only supports the Z3 or SE application profile.");
#endif
}

// option binding-table set <index> <cluster> <local ep> <remote ep> <EUI>
void optionBindingTableSetCommand(void)
{
  EmberBindingTableEntry entry;
  uint8_t index = (uint8_t)emberUnsignedCommandArgument(0);
  uint8_t endpoint = (uint8_t)emberUnsignedCommandArgument(2);
  EmberStatus status = emberAfPushEndpointNetworkIndex(endpoint);
  if (status == EMBER_SUCCESS) {
    entry.type = EMBER_UNICAST_BINDING;
    entry.clusterId = (EmberAfClusterId)emberUnsignedCommandArgument(1);
    entry.local = endpoint;
    entry.remote = (uint8_t)emberUnsignedCommandArgument(3);
    emberCopyBigEndianEui64Argument(4, entry.identifier);
    entry.networkIndex = emberGetCurrentNetwork();
    status = emberSetBinding(index, &entry);
    (void) emberAfPopNetworkIndex();
  }
  emberAfAppPrintln("set bind %d: 0x%x", index, status);
}

#ifdef DEBUG_PRINT_FOR_ROUTING_TABLE

void optionPrintRouteCommand(void)
{
  const char * statusText[] = {
    "active",
    "discov",
    "??    ",
    "unused",
  };

  const char * concentratorText[] = {
    "- ",
    "lo",
    "hi",
  };

  const char * routeRecordStateText[] = {
    "none",
    "sent",
    "need",
  };
  uint8_t i;

  emberAfAppPrintln("Routing Table\n-----------------");

  for (i = 0; i < EMBER_ROUTE_TABLE_SIZE; i++) {
    EmberRouteTableEntry entry;
    if (emberGetRouteTableEntry(i, &entry) == EMBER_SUCCESS) {
      emberAfAppPrintln("%d: dest:0x%2X next:0x%2X status:%p age:%d conc:%p rr-state:%p",
                        i,
                        entry.destination,
                        entry.nextHop,
                        statusText[entry.status],
                        entry.age,
                        concentratorText[entry.concentratorType],
                        routeRecordStateText[entry.routeRecordState]);
    }
    emberAfAppFlush();
  }
}
#endif //  DEBUG_PRINT_FOR_ROUTING_TABLE

Variables#

EmberCommandEntry
EmberCommandEntry
EmberCommandEntry
EmberCommandEntry
EmberCommandEntry
EmberCommandEntry

Variable Documentation#

optionPrintRxCommands#

EmberCommandEntry optionPrintRxCommands[]

Definition at line 52 of file ./app/framework/cli/option-cli.c

optionBindingCommands#

EmberCommandEntry optionBindingCommands[]

Definition at line 61 of file ./app/framework/cli/option-cli.c

optionApsSecurityCommands#

EmberCommandEntry optionApsSecurityCommands[]

Definition at line 69 of file ./app/framework/cli/option-cli.c

apsRetryCommands#

EmberCommandEntry apsRetryCommands[]

Definition at line 75 of file ./app/framework/cli/option-cli.c

optionSecurityCommands#

EmberCommandEntry optionSecurityCommands[]

Definition at line 82 of file ./app/framework/cli/option-cli.c

emAfOptionCommands#

EmberCommandEntry emAfOptionCommands[]

Definition at line 87 of file ./app/framework/cli/option-cli.c

discoveryTargetNodeId#

EmberNodeId discoveryTargetNodeId

Definition at line 115 of file ./app/framework/cli/option-cli.c

Function Documentation#

optionPrintRxCommand#

void optionPrintRxCommand (void )
Parameters
N/A

Definition at line 151 of file ./app/framework/cli/option-cli.c

optionRegisterCommand#

void optionRegisterCommand (void )
Parameters
N/A

Definition at line 165 of file ./app/framework/cli/option-cli.c

optionDiscoverCommand#

void optionDiscoverCommand (void )
Parameters
N/A

Definition at line 176 of file ./app/framework/cli/option-cli.c

optionBindingTablePrintCommand#

void optionBindingTablePrintCommand (void )
Parameters
N/A

Definition at line 188 of file ./app/framework/cli/option-cli.c

optionBindingTableClearCommand#

void optionBindingTableClearCommand (void )
Parameters
N/A

Definition at line 236 of file ./app/framework/cli/option-cli.c

optionEndDeviceBindCommand#

void optionEndDeviceBindCommand (void )
Parameters
N/A

Definition at line 242 of file ./app/framework/cli/option-cli.c

optionApsRetryCommand#

void optionApsRetryCommand (void )
Parameters
N/A

Definition at line 248 of file ./app/framework/cli/option-cli.c

optionApsSecurityCommand#

void optionApsSecurityCommand (void )
Parameters
N/A

Definition at line 262 of file ./app/framework/cli/option-cli.c

optionLinkCommand#

void optionLinkCommand (void )
Parameters
N/A

Definition at line 270 of file ./app/framework/cli/option-cli.c

optionBindingTableSetCommand#

void optionBindingTableSetCommand (void )
Parameters
N/A

Definition at line 347 of file ./app/framework/cli/option-cli.c

optionPrintRouteCommand#

void optionPrintRouteCommand (void )
Parameters
N/A

Definition at line 40 of file ./app/framework/cli/option-cli.c

optionInstallCodeCommand#

void optionInstallCodeCommand (void )
Parameters
N/A

Definition at line 290 of file ./app/framework/cli/option-cli.c

optionDiscoveryTargetCommand#

void optionDiscoveryTargetCommand (void )
Parameters
N/A

Definition at line 170 of file ./app/framework/cli/option-cli.c