Vendor hooks

Vendor hooks are a software mechanism that allows adding custom Spinel commands. Such vendor-specific commands can be used to add support for enhanced application features. For example, they allow you to add radio or crypto functionalities, whose settings are managed from the host device.

In nRF Connect SDK, your implementation of the vendor hooks file is compiled by OpenThread within the NCP component. The only information needed for compilation is the file location. In this way, you can implement new features in the application or elsewhere without having to modify OpenThread components.

Vendor hooks are strictly connected to the Spinel protocol used in serial communication between host device and the MCU board working in Thread NCP or RCP architecture. Spinel uses serial frames with commands that describe the activity to perform (for example, get or set), and with properties that define the object on which the activity is to be performed. You can use the available commands and properties, but also define your set of instructions to provide new features by using the vendor hooks.

Note

Both devices used for communication must support user-defined commands and properties to achieve the expected result. See the following sections for information about how to add your features on the host and the NCP/RCP devices.

ID range of general vendor properties

The Spinel protocol associates specific properties with numeric identifiers. The ID range reserved for the vendor properties spans from 0x3c00 to 0x4000.

You are not allowed to use IDs from outside this range for your properties, as this might negatively affect the Spinel protocol operation, and the vendor hooks mechanism will not work.

Host device configuration

In most cases, the host device uses tools that support the Spinel protocol (like wpantund or Pyspinel) to communicate with the NCP/RCP device. You can, however, use another tool as long as it supports the Spinel protocol.

Adding properties in Pyspinel

Pyspinel is the recommended tool for adding properties, given its ease-of-use.

To configure new properties in Pyspinel, you must update the following files:

  • const.py - This file contains the VENDOR_SPINEL class, which stores definitions of the identifier values of vendor properties. Use this file to add properties.

  • codec.py - This file contains definitions of handler methods called on property detection. Use this file to add definitions of handlers for your properties.

  • vendor.py - This file contains methods to capture property occurrences from the console and call proper handlers.

These files are located in the vendor directory, which can be found in the main project directory.

Complete the following steps to add a property in Pyspinel:

  1. Clone the Pyspinel respository and install the tool.

  2. Navigate to the vendor directory that contains the codec.py, const.py, and vendor.py files. This directory is located in the main project directory.

  3. Open the const.py file for editing.

  4. Add properties to the const.py file. For example, add the following properties:

    • PROP_VENDOR_NAME, which is used to get the vendor name from the device.

    • PROP_VENDOR_AUTO_ACK_ENABLED, which is used to get or set the auto ACK mode state.

    The class should contain code similar to the following:

    class VENDOR_SPINEL(object):
      """
      Class to extend SPINEL constant variables for example:
          PROP_VENDOR__BEGIN = 0x3C00
    
          PROP_VENDOR_HOOK = PROP_VENDOR__BEGIN + 0
          PROP_VENDOR__END = 0x4000
      """
      PROP_VENDOR__BEGIN = 0x3C00
    
      PROP_VENDOR_NAME = PROP_VENDOR__BEGIN
      PROP_VENDOR_AUTO_ACK_ENABLED = PROP_VENDOR__BEGIN + 1
      PROP_VENDOR_HW_CAPABILITIES = PROP_VENDOR__BEGIN + 2
    
      PROP_VENDOR__END = 0x4000
      pass
    

    You can also add your own properties, but you must assign them IDs from the proper vendor range.

  5. Open the codec.py file for editing.

  6. In the codec.py file, add definitions of handlers. For example, for the properties added in the const.py file:

    class VendorSpinelPropertyHandler(SpinelCodec):
      """
      Class to extend Spinel property Handler with new methods.
      Methods define parsers for Vendor Hooks for example:
      `def VENDOR_HOOK_PROPERTY(self, _wpan_api, payload): return self.parse_C(payload)`
      """
      def NAME(self, _, payload):
          return self.parse_U(payload)
    
      def AUTO_ACK(self, _, payload):
          return self.parse_C(payload)
      pass
    
    
    WPAN_PROP_HANDLER = VendorSpinelPropertyHandler()
    
    # Parameter to extend SPINEL_PREP_DISPATCH with Vendor properties for example:
    #   `VENDOR_SPINEL_PROP_DISPATCH = {VENDOR_SPINEL.PROP_VENDOR_HOOK: WPAN_PROP_HANDLER.VENDOR_HOOK_PROPERTY}`
    VENDOR_SPINEL_PROP_DISPATCH = {
        VENDOR_SPINEL.PROP_VENDOR_NAME:
          WPAN_PROP_HANDLER.NAME,
        VENDOR_SPINEL.PROP_VENDOR_AUTO_ACK_ENABLED:
          WPAN_PROP_HANDLER.AUTO_ACK}
    

    Note

    Handlers call different parsing methods depending on the type of data passed with the property. In this case, NAME is of string type and AUTO_ACK is of uint8 type, so methods parse_U and parse_C should be used. For details, see the SpinelCodec class in spinel/codec.py.

  7. Open the vendor.py file for editing.

  8. Extend the list of command names with the new properties and make sure they are included in the do_vendor method:

    class VendorSpinelCliCmd():
      """
      Extended Vendor Spinel Cli with vendor hooks commands.
      INPUT:
          spinel-cli > vendor help
      OUTPUT:
          Available vendor commands:
          ==============================================
          help
      """
      vendor_command_names = ['help', 'name', 'auto_ack']
    
      def do_vendor(self, line):
          params = line.split(" ")
          if params[0] == 'help':
              self.print_topics("\nAvailable vendor commands:",
                                VendorSpinelCliCmd.vendor_command_names, 15, 30)
          elif params[0] == 'name':
              self.handle_property(None, VENDOR_SPINEL.PROP_VENDOR_NAME)
          elif params[0] == 'auto_ack':
              if len(params) > 1:
                  self.handle_property(params[1], VENDOR_SPINEL.PROP_VENDOR_AUTO_ACK_ENABLED)
              else:
                  self.handle_property(None, VENDOR_SPINEL.PROP_VENDOR_AUTO_ACK_ENABLED)
    

NCP/RCP device configuration

In nRF Connect SDK, the OpenThread NCP base component is responsible for processing Spinel frames and performing appropriate operations. If it finds a frame with an unknown property ID, but one that fits the vendor ID range, it calls vendor handler methods. You must define these methods beforehand.

Handler methods can check the property ID and perform different actions depending on its value. They can also ignore the value, for example, if the property was defined by another vendor and you want to filter it out.

For a detailed description of how to enable the vendor hook feature in a sample, see the Thread: Co-processor sample documentation.

Testing vendor hooks after configuration

To test the vendor hook feature, you need a development kit that is programmed with either the Thread: Co-processor sample or another compatible sample.

Complete the following steps:

  1. Connect the development kit’s SEGGER J-Link USB port to the USB port on your PC with an USB cable.

  2. Get the development kit’s serial port name (for example, /dev/ttyACM0).

  3. Open a shell and run Pyspinel by using the following command, with baud_rate set to 1000000 and serial_port_name set to the port name from the previous step:

    python3 spinel-cli.py -u serial_port_name -b baud_rate
  4. In the Pyspinel shell, run the following command to check the list of available vendor properties:

    spinel-cli > vendor help
    

    The output looks similar to the following:

    Available vendor commands:
    ===========================
    help  name  auto_ack
    
  5. In the Pyspinel shell, run the following command to get the device vendor name:

    spinel-cli > vendor name
    

    The output looks similar to the following:

    Nordic Semiconductor
    Done
    
  6. In the Pyspinel shell, run the auto_ack command to get the current state of the device auto ACK mode:

    spinel-cli > vendor auto_ack
    

    The output looks similar to the following:

    1
    Done
    
  7. In the Pyspinel shell, run the auto_ack command with a value to change the current state of the device auto ACK mode:

    spinel-cli > vendor auto_ack 0
    

    The output looks similar to the following:

    0
    Done