Skip to content
simen edited this page Dec 21, 2016 · 3 revisions

1. Overview

The unpi is the packet builder and parser for Texas Instruments Unified Network Processor Interface (UNPI) used in RF4CE, BluetoothSmart, and ZigBee wireless SoCs. As stated in TI's wiki page:

TI's Unified Network Processor Interface (NPI) is used for establishing a serial data link between a TI SoC and external MCUs or PCs. This is mainly used by TI's network processor solutions.

The UNPI packet consists of sof, length, cmd0, cmd1, payload, and fcs fields. The description of each field can be found in Unified Network Processor Interface.

It is noted that UNPI defines the length field with 2 bytes wide, but some SoCs use NPI in their real transmission (physical layer), the length field just occupies a single byte. (The length field will be normalized to 2 bytes in the transportation layer of NPI stack.)


2. Installation

$ npm install unpi --save


3. Usage

To use unpi, just new an instance from the Unpi class. The Unpi constructor accepts an optional parameter config object. If config is not given, a default value of { lenBytes: 2 } will be used internally. The property lenBytes indicates the width of the length field.

Since the transmission should be accomplished upon an UART or a SPI physical interface, you can pass the physical transceiver to your unpi by attach it to config.phy property, i.e., { phy: sp } where sp is a serialport instance. The phy instance should be a Stream.

Here is an quick example and the parsed data format can be found in the 'data' event section.

var Unpi = require('unpi'),
    SerialPort = require("serialport").SerialPort;

var sp = new SerialPort("/dev/ttyUSB0", {
        baudrate: 57600
    }),
    unpi = new Unpi({
        lenBytes: 1
        phy: sp
    });

unpi.on('data', function (data) {
    console.log(data);  // The parsed data receiving from the serial port
});

4. APIs

Unpi Class

Exposed by require('unpi')

Unpi class also exports its dependencies DChunks and Concentrate for your convenient.

Examples:

var Unpi = require('unpi');
var DChunks = Unpi.DChunks;
var Concentrate = Unpi.Concentrate;

var myBuffer = Concentrate().uint8(1).uint8(20).uint16(100).result();



new Unpi([config])

Create a new instance of the Unpi class.

Arguments:

  1. config (Object, optional): Configuration of the unpi instance. Accepted properties of config are listed in the following table.
Property Type Description
lenBytes Number 1 or 2 to indicate the width of length field. Default is 2.
phy Stream The transceiver instance, i.e. serial port, spi. It should be a duplex stream.

Returns:

  • (Object): unpi, an instance of Unpi

Examples:

  • Create an unpi instance without physical transceiver
var Unpi = require('unpi');
var unpi = new Unpi({
        lenBytes: 1
    });

unpi.on('data', function (data) {
    console.log(data);  // The parsed data
});

// You can use .receive(buffer) to test it
unpi.receive(new Buffer([
    0xFE, 0x01, 0x41, 0x00, 0x00, 0x40
]));
  • Create an unpi instance with a serialport transceiver. The unpi will internally pipe from and to it.
var SerialPort = require("serialport").SerialPort
var sp = new SerialPort("/dev/ttyUSB0", {
  baudrate: 57600
});

var Unpi = require('unpi');
var unpi = new Unpi({
        lenBytes: 1
        phy: sp
    });

unpi.on('data', function (data) {
    console.log(data);  // The parsed data receiving from the serial port
});



.receive(buf)

Feeds the unpi with some binary raw data. You can take the unpi as a generic parser if you don't have any physical transceiver.

Arguments:

  1. buf (Buffer): An UNPI raw packet.

Returns:

  • (Object): this (unpi instance itself)

Examples:

unpi.receive(new Buffer([
    0xFE, 0x01, 0x41, 0x00, 0x00, 0x40
]));



.send(type, subsys, cmdId, payload)

Send the binaries out through the physical transmitter if there is a phy transceiver. The API will return a raw buffer of the packet, you can take it as a generic packet builder. If the phy exists, unpi will fire an 'flushed' event after each command packet flushed to the phy transceiver.

Arguments:

  1. type (Number | String): The command type. For exmaple, set type to 1 or 'SREQ' to send a synchronous command.
  2. subsys (Number | String): The subsystem. For example, send a command of subsystem 'RPC_SYS_UTIL', you can set subsys to 7, 'RPC_SYS_UTIL', or simply 'UTIL' (the prefix 'RPC_SYS_' can be ignored).
  3. cmdId (Number): The command id which is a number according to which subsystem you are using.
  4. payload (Buffer): The data payload.

Returns:

  • (Buffer): Buffer of the built command packet.

Examples:

// The following calls do the same thing
unpi.send('AREQ', 'SYS', 0, new Buffer([ 0 ]));
unpi.send('AREQ', 1, 0, new Buffer([ 0 ]));
unpi.send(2, 'SYS', 0, new Buffer([ 0 ]));
unpi.send(2, 1, 0, new Buffer([ 0 ]));

## 5. Events

unpi.on('data', function (data) { ... })

The 'data' event will be fired along with the parsed result. Here is an example of the parsed data to show you the format. The csum is the checksum calculated from the received binaries. You can use it to check that if the received packet is corrupted.

{ 
    sof: 254,
    len: 6,
    type: 2,
    subsys: 1,
    cmd: 128,
    payload: <Buffer 02 02 00 02 06 02>,
    fcs: 193,   // this is the checksum originated from the sender
    csum: 193   // this is the checksum calculated from the received binaries
}

Examples:

unpi.on('data', function (data) {
    console.log(data);  // The parsed data
});



unpi.on('flushed', function (cmdInfo) { ... })

After each command packet is sending out to phy transceiver, a 'flushed' event will be fired along with the data of command information. The cmdInfo object has three properties of type, subsys, and cmdId to indicate which command was send.

Examples:

unpi.on('flushed', function (cmdInfo) {
    console.log(cmdInfo);  // { type: 1 , subsys: 2, cmdId: 10 }
});



unpi.on('error', function (err) { ... })

Fired when any error occurs. Each time unpi finds that there is a corrupted packet with a bad checksum, both an data event and an error event will be fired along with the parsed result.

Examples:

unpi.on('error', function (err, parsedData) {
    console.log(err);   // for example: [Error: Invalid checksum.]
});

## 6. Appendix
  • Command Type
{
    "POLL": 0,
    "SREQ": 1,
    "AREQ": 2,
    "SRSP": 3,
    "RES0": 4,
    "RES1": 5,
    "RES2": 6,
    "RES3": 7
}
  • Subsystem
{
    "RPC_SYS_RES0": 0,
    "RPC_SYS_SYS": 1,
    "RPC_SYS_MAC": 2,
    "RPC_SYS_NWK": 3,
    "RPC_SYS_AF": 4,
    "RPC_SYS_ZDO": 5,
    "RPC_SYS_SAPI": 6,
    "RPC_SYS_UTIL": 7,
    "RPC_SYS_DBG": 8,
    "RPC_SYS_APP": 9,
    "RPC_SYS_RCAF": 10,
    "RPC_SYS_RCN": 11,
    "RPC_SYS_RCN_CLIENT": 12,
    "RPC_SYS_BOOT": 13,
    "RPC_SYS_ZIPTEST": 14,
    "RPC_SYS_DEBUG": 15,
    "RPC_SYS_PERIPHERALS": 16,
    "RPC_SYS_NFC": 17,
    "RPC_SYS_PB_NWK_MGR": 18,
    "RPC_SYS_PB_GW": 19,
    "RPC_SYS_PB_OTA_MGR": 20,
    "RPC_SYS_BLE_SPNP": 21,
    "RPC_SYS_BLE_HCI": 22,
    "RPC_SYS_RESV01": 23,
    "RPC_SYS_RESV02": 24,
    "RPC_SYS_RESV03": 25,
    "RPC_SYS_RESV04": 26,
    "RPC_SYS_RESV05": 27,
    "RPC_SYS_RESV06": 28,
    "RPC_SYS_RESV07": 29,
    "RPC_SYS_RESV08": 30,
    "RPC_SYS_SRV_CTR": 31
}