Skip to content
hedy edited this page Jan 4, 2017 · 5 revisions

1. Overview

cc-bnp allows you to interact with TI's CC254X BLE network processor (BNP) on node.js via TI BLE Vendor-Specific HCI Command APIs. Each Command API is in an asynchronous manner and supports both err-back callback style and promise-style.

cc-bnp let you get rid of multiple Vendor-Specific Events handling of each command. cc-bnp gathers the multiple responses up, and finally passes the result to the Command API callback. With cc-bnp, it's easy and fun in designing BLE applications on node.js.


## 2. BLE Network Processor (BNP)

The following diagram shows the scenario when CC254X operates as a BNP. In this case, the controller and host are implemented together on CC2540/41, and the application can be externally developed on an application processor (e.g., another mcu or PC). The application and profiles can communicate with BNP through TI's vendor-specific HCI commands upon an UART interface.

Network Processor Configuration


## 3. Installation

$ npm install cc-bnp --save


## 4. Usage

To begin with cc-bnp, you must firstly set up the serial port and initialize the BNP with a given role. To do this, simply call the .init() method:

    var ccbnp = require('cc-bnp');
    var cfg = {
        path: '/dev/ttyUSB0'
    };

    ccbnp.on('ready', function () {
        console.log('Initialization completes.');
    });

    ccbnp.init(cfg, 'central');

Here are some examples.


## 5. Basic APIs

The basic APIs are about how to initialize the BNP with a given role and how to close connection from the processor. cc-bnp also allows you to define your own characteristics with registration methods. After the BNP accomplishes its initializing procedure, a 'ready' event will be fired by cc-bnp. When there comes a BLE indication message, cc-bnp will fire an 'ind' event along with the message content.



.init(config, role, [callback])

Connect to CC254X SoC upon a serial port as well as initialize the BNP with a given role.

Arguments

  • config (Object): This value-object has two properties path and options to configure the serial port.

    • path - A string that refers to the serial-port system path, e.g., '/dev/ttyUSB0'.
    • options - A value-object to set up the seiralport instance. Its default value is shown in the following example.
  • role (String): Device role. cc-bnp supports four types of single role and two types of multi-roles:

    • 'broadcaster' - Single role. An advertiser that is non-connectable.
    • 'observer' - Single role. An observer that scans for advertisements. It can not initiate connections.
    • 'peripheral' - Single role. An advertiser that operates as a slave in a single link layer connection.
    • 'central' - Single role. A central that scans for advertisements and operates as a master in a single or multiple link layer connections.
    • 'central_broadcaster' - Multi-roles. The processor plays as a central and a broadcaster.
    • 'peripheral_observer' - Multi-roles. The processor plays as a peripheral and an observer.
  • callback(err, result)

    • 'err' (Error) - Error Message
    • 'result' (Object) - Device information. It has the following properties:
{
    devAddr: '0x78c5e59b5ef8',  // Device public address
    irk: <Buffer 72 74 73 20 3d 20 44 75 70 6c 65 78 3b 0a 0a 2f>, // 16 bytes IRK (Identity Resolving Key)  
    csrk: <Buffer 2a 3c 72 65 70 6c 61 63 65 6d 65 6e 74 3e 2a 2f> // 16 bytes CSRK (Connection Signature Resolving Key)
}

Returns

  • (Promise)

Example

var ccbnp = require('cc-bnp'),
    role = 'broadcaster',
    cfg = {
        path: '/dev/ttyUSB0',
        options: {
            baudRate: 115200,   // default value
            rtscts: true,       // default value
            flowControl: true   // default value
        }
    };

// init() example: callback-style
ccbnp.init(cfg, role, function (err, result) {
    if (err)
        console.log(err);
    else
        console.log(result);
});

// init() example: promise-style
ccbnp.init(cfg, role).then(function (result) {
    console.log(result);
}).fail(function (err) {
    console.log(err);
}).done();



.close([callback])

Close the opened serial port.

Arguments

Returns

  • (Promise)

Example

ccbnp.close(function (err) {
    if (err)
        console.log(err);
});



.regChar(regObj)

Register a characteristic UUID and its value format.

If a characteristic UUID is defined by GATT Specifications or BIPSO Specifications, cc-bnp will automatically parse it. If you have a private characteristic (defined by yourself, not by SIG or BIPSO), please use this method to register your characteristic to cc-bnp. This will tell cc-bnp how to parse private characteristics from the received messages.

[WARNING]: This method can overwrite a public UUID definition (GATT Specifications). It is better to choose a private UUID different from public-defined ones.

Arguments

  • regObj (Object): The object should be given with the following properties

    • uuid (Hex string) - Characteristic UUID to register (e.g., '0xaaa0', '0xaac2').
    • params (Array) - Field names in the characteristic value.
    • types (Array) - Data type of each parameter in params array.

    Note: The order of entries in types and params array should be exactly matched.

Returns

  • (none)

Example

var regObj = {
    uuid: '0xfff1',
    params: [ 'foo', 'bar', 'certainName' ],
    types: [ 'uint8', 'uint16', 'float' ]
};
ccbnp.regChar(regObj);



.regUuidHdlTable(connHdl, uuidHdlTable)

Register a table that maps each characteristic handle to its characteristic UUID under a connection. cc-bnp will use this table to find out the characteristic UUID when you use the characteristic handle to operate upon a characteristic.

Arguments

  • connHdl (Number): Connection handle that identifies a connection.
  • uuidHdlTable (Object): Characteristic handle-to-UUID mapping table (key-value pairs). Key is characteristic handle and value is characteristic UUID.

Returns

  • (none)

Example

var myCharUuidHdlTable1 = {
    // handle: uuid
        3: '0x2a00',
        5: '0x2a01',
        7: '0x2a02',
        9: '0x2a03',
        11: '0x2a04',
        14: '0x2a05'
    },
    myCharUuidHdlTable2 = {
        4: '0x2a00',
        6: '0x2a01',
        8: '0x2a02',
        10: '0x2a03',
        12: '0x2a04',
        16: '0x2a05'
    };

ccbnp.regUuidHdlTable(0, myCharUuidHdlTable1);    // under connection handle 0
ccbnp.regUuidHdlTable(1, myCharUuidHdlTable2);    // under connection handle 1



.regTimeoutConfig(connHdl, timeoutConfig)

Register the timeout configuration of HCI commands. This will tell cc-bnp of how long time it should wait for the response.

Arguments

  • connHdl (Number): Connection handle that identifies a connection

  • timeoutConfig (Object): Timeout configuration. The following table shows the details of each property

    Property Type Mandatory Description Default Value
    level1 Number Optional Timeout of remote control commands (mSec) 3000
    level2 Number Optional Timeout of remote control and operating many characteristics commands (mSec) 10000
    scan Number Optional Timeout of gap.deviceDiscReq command (mSec) 15000

Returns

  • (none)

Example

var timeoutConfig1 = {
        level1: 2000,
        level2: 5000,
        scan: 3000
    },
    timeoutConfig2 = {
        scan: 5000
    };

ccbnp.regTimeoutConfig(0, timeoutConfig1);     // for connection handle 0
ccbnp.regTimeoutConfig(1, timeoutConfig2);     // for connection handle 1

## 6. TI's BLE Vendor-Specific HCI Command APIs

TI's BLE Vendor-Specific HCI Commands are organized in subgroups: hci, l2cap, att, gatt, gap, and util. The description of each command is documented in TI_BLE_Vendor_Specific_HCI_Guide.pdf.

Command SubGroup (CSG) Namespace Number of Commands
hci ccbnp.hci 32
l2cap ccbnp.l2cap 1
att ccbnp.att 26
gatt ccbnp.gatt 25
gap ccbnp.gap 24
util ccbnp.util 3

To call the Command API:

ccbnp[subGroup][cmdName](..., callback);  

, where cmdName is the Command API function name which can be found from this reference table.

For example:

ccbnp.gap.deviceDiscReq(..., function (err, result) { });  

Here is an example of calling deviceDiscReq() in subgroup gap:

// Please see Section 12.3 in TI BLE Vendor Specific HCI Reference Guide for API details.
// arguments: (mode, activeScan, whiteList, callback)

ccbnp.gap.deviceDiscReq(3, 1, 0, function (err, result) {
    if (err)
        console.log(err);
    else
        console.log(result);
};

Here is another example of calling writeCharValue() in subgroup gatt:

// Please see Section 18.14 in TI BLE Vendor Specific HCI Reference Guide for API details.
// arguments: (connHandle, handle, value, [uuid], callback)

var valObj = {   // value object for this command
    flags: 15,   // bit0 = 1, bit1 = 1, bit2 = 1, bit3 = 1
    sequenceNum: 1, 
    year: 2015, 
    month: 12, 
    day: 22, 
    hours: 18, 
    minutes: 37, 
    seconds: 41,
    timeOffset: 0,
    glucoseMol: 0.0068,
    type: 1,
    sampleLocation: 1, 
    sensorStatus: 0
};

// If _uuid_ is not given, ccbnp will automatically initiate a request to ask characteristic uuid to build value packet.
ccbnp.gatt.writeCharValue(0, 37, valObj, '0x2a18', function (err, result) {
    if (err)
        console.log(err);
    else
        console.log(result);
});

The 'uuid' of a public characteristic value can be found in GATT Specifications and Bipso characteristic value can be found in BIPSO Specifications. If you are using a private characteristic, please use .regChar() to register your uuid first.


## 7. Events

.on('ready', function (msg) { ... })

The 'ready' event is fired when the initializing procedure completes, where msg is object of device information with the following properties

{
    devAddr: '0x78c5e59b5ef8',  // Device public address
    irk: <Buffer 72 74 73 20 38 20 44 75 70 63 65 78 31 00 09 25>,  // 16 bytes IRK
    csrk: <Buffer 21 33 72 65 70 63 61 63 65 64 65 62 74 34 20 27>  // 16 bytes CSRK
}

Examples:

ccbnp.on('ready', function (msg) {
    console.log(msg);
});



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

The 'error' event is fired when when an error occurs

Examples:

ccbnp.on('error', function (err) {
    console.log(err);
});



.on('ind', function(msg) { ... })

When there is an incoming BLE indication message, cc-bnp fires an 'ind' event along with the message object. The msg is an object with the properties given in the table:

Property Type Description
type String Indication type, can be 'linkEstablished', 'linkTerminated', 'linkParamUpdate', 'attNoti','attInd', 'authenComplete', 'passkeyNeeded' and 'bondComplete'.
data Object Data along with the indication, which depends on the type of indication
  • linkEstablished

    A connection is established with another device.

    • msg.type (String): 'linkEstablished'
    • msg.data (Object): Content of the 'linkEstablished' type event.
    msg.data = {
        addr: '0x9059af0b8159',   // Address of the connected device
        connHandle: 0,            // Handle of the connection
        connInterval: 80,         // Connection interval used on this connection, time = 80 * 1.25 msec
        connLatency: 0,           // Connection latency used on this connection
        connTimeout: 2000,        // Connection supervision timeout, time = 2000 * 10 msec
        clockAccuracy: 0,         // The accuracy of clock 
    }

  • linkTerminated

    A link is terminated.

    • msg.type (String): 'linkTerminated'
    • msg.data (Object): Content of the 'linkTerminated' type event.
    msg.data = {
        connHandle: 0,      // Connection Handle of the terminated link
        reason: 8,          // The reason of termination
    }

  • linkParamUpdate

    Connection parameter update is completed.

    • msg.type (String): 'linkParamUpdate'
    • msg.data (Object): Content of the 'linkParamUpdate' type event.
    msg.data = {
        connHandle: 0,
        connInterval: 80,
        connLatency: 0,
        connTimeout: 2000
    }

  • attNoti

    A notification of an remote attribute’s value.

    • msg.type (String): 'attNoti'
    • msg.data (Object): Content of the 'attNoti' type event.
    msg.data = {
        connHandle: 0,
        authenticated: 0,       // Whether or not an authenticated link is required
        handle: 93,             // The handle of the attribute
        value: <Buffer C3 01>   // The value of the attribute 
    }

  • attInd

    An indication of an remote attribute’s value.

    • msg.type (String): 'attInd'
    • msg.data (Object): Content of the 'attInd' type event.
    msg.data = {
        connHandle: 0,
        authenticated: 0,
        handle: 94,
        value: <Buffer 08 00>
    }  

  • authenComplete

    The pairing process is completed (pass or fail).

    • msg.type (String): 'authenComplete'
    • msg.data (Object): Content of the 'authenComplete' type event.
    msg.data = {
        connHandle: 0,
        mitm: 1,    // 0 or 1 means true or false
        bond: 1,    // 0 or 1 means true or false
        ltk: <Buffer 23 84 11 48 95 39 54 36 26 54 47 64 44 63 54 73>,  // 16 bytes LTK
        div: 0x668b,                                                    // The DIV used with this LTK.
        rand: <Buffer 56 68 35 55 43 46 59 99>                          // 8 bytes random number generated for this LTK.
    }    

  • passkeyNeeded

    A connection is requesting for a passkey during the pairing process .

    • msg.type (String): 'passkeyNeeded'
    • msg.data (Object): Content of the 'passkeyNeeded' type event.
    msg.data = {
        devAddr: '0x78c5e570796e',
        connHandle: 0,
        uiInput: 1,   // Whether to ask user to input a passcode, 0 or 1 means no or yes
        uiOutput: 0   // Whether to display a passcode, 0 or 1 means no or yes
    }     

  • bondComplete

    A bond is complete and the connection is encrypted.

    • msg.type (String): 'bondComplete'
    • msg.data (Object): Content of the 'bondComplete' type event.
    msg.data = {
        connHandle: 0
    }      

Examples:

ccbnp.on('ind', function (msg) {
    console.log(msg);
});