# CHIP Linux Bridge Example
An example demonstrating a simple lighting bridge and the use of dynamic
endpoints. The document will describe the theory of operation and how to build
and run CHIP Linux Bridge Example on Raspberry Pi. This doc is tested on
**Ubuntu for Raspberry Pi Server 20.04 LTS (aarch64)** and **Ubuntu for
Raspberry Pi Desktop 20.10 (aarch64)**
- [CHIP Linux Bridge Example](#chip-linux-bridge-example)
- [Theory of Operation](#theory-of-operation)
- [Building](#building)
- [Running the Complete Example on Raspberry Pi 4](#running-the-complete-example-on-raspberry-pi-4)
## Theory of Operation
### Dynamic Endpoints
The Bridge Example makes use of Dynamic Endpoints. Current SDK support is
limited for dynamic endpoints, since endpoints are typically defined (along with
the clusters and attributes they contain) in a .zap file which then generates
code and static structures to define the endpoints.
To support endpoints that are not statically defined, the ZCL attribute storage
mechanisms will hold additional endpoint information for `NUM_DYNAMIC_ENDPOINTS`
additional endpoints. These additional endpoint structures must be defined by
the application and can change at runtime.
To facilitate the creation of these endpoint structures, several macros are
defined:
`DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(attrListName)`
`DECLARE_DYNAMIC_ATTRIBUTE(attId, attType, attSizeBytes, attrMask)`
`DECLARE_DYNAMIC_ATTRIBUTE_LIST_END(clusterRevision)`
- These three macros are used to declare a list of attributes for use within a
cluster. The declaration must begin with the
`DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN` macro which will define the name of
the allocated attribute structure. Each attribute is then added by the
`DECLARE_DYNAMIC_ATTRIBUTE` macro. Finally,
`DECLARE_DYNAMIC_ATTRIBUTE_LIST_END` macro should be used to close the
definition.
- All attributes defined with these macros will be configured as
`ATTRIBUTE_MASK_EXTERNAL_STORAGE` in the ZCL database and therefore will
rely on the application to maintain storage for the attribute. Consequently,
reads or writes to these attributes must be handled within the application
by the `emberAfExternalAttributeWriteCallback` and
`emberAfExternalAttributeReadCallback` functions. See the bridge
application's `main.cpp` for an example of this implementation.
`DECLARE_DYNAMIC_CLUSTER_LIST_BEGIN(clusterListName)`
`DECLARE_DYNAMIC_CLUSTER(clusterId, clusterAttrs, incomingCommands, outgoingCommands)`
`DECLARE_DYNAMIC_CLUSTER_LIST_END`
- These three macros are used to declare a list of clusters for use within a
endpoint. The declaration must begin with the
`DECLARE_DYNAMIC_CLUSTER_LIST_BEGIN` macro which will define the name of the
allocated cluster structure. Each cluster is then added by the
`DECLARE_DYNAMIC_CLUSTER` macro referencing attribute list previously
defined by the `DECLARE_DYNAMIC_ATTRIBUTE...` macros and the lists of
incoming/outgoing commands terminated by kInvalidCommandId (or nullptr if
there aren't any commands in the list). Finally,
`DECLARE_DYNAMIC_CLUSTER_LIST_END` macro should be used to close the
definition.
`DECLARE_DYNAMIC_ENDPOINT(endpointName, clusterList)`
- This macro is used to declare an endpoint and its associated cluster list,
which must be previously defined by the `DECLARE_DYNAMIC_CLUSTER...` macros.
### Limitations
Because code generation is dependent upon the clusters and attributes defined in
the .zap file (for static endpoint generation), it is necessary to include a
defined endpoint within the .zap that contains _all_ the clusters that may be
used on dynamic endpoints. On the bridge example, this is done on endpoint 1,
which is used as a 'dummy' endpoint that will be disabled at runtime. Endpoint 0
is also defined in the .zap and contains the bridge basic and configuration
clusters as well as the root descriptor cluster.
### Bridge Implementation Example
The example demonstrates the use of dynamic endpoints and the concept of adding
and removing endpoints at runtime. First, the example declares a
`bridgedLightEndpoint` data structure for a Light endpoint with `OnOff`,
`Descriptor`, `BridgedDeviceBasic`, and `FixedLabel` clusters.
Using this declared endpoint structure, three endpoints for three bridged lights
are dynamically added at endpoint ID's `2`, `3`, and `4`, representing
`Light 1`, `Light 2`, and `Light 3` respectively.
Then, endpoint `3` is removed, simulating the deletion of `Light 2`.
A fourth light, `Light 4`, is then added occupying endpoint ID `5`.
Finally, `Light 2` is re-added, and will occupy endpoint ID `6`.
All endpoints populate the `Bridged Device Basic` and `Fixed Label` clusters. In
the `Bridged Device Basic` cluster, the `reachable` attribute is simulated. In
the `Fixed Label` cluster, the `LabelList` attribute is simulated with the
value/label pair `"room"`/`[light name]`.
## Building
- Install tool chain
```
$ sudo apt-get install git gcc g++ python pkg-config libssl-dev libdbus-1-dev libglib2.0-dev ninja-build python3-venv python3-dev unzip
```
- Build the example application:
```
$ cd ~/connectedhomeip/examples/dynamic-bridge-app/linux
$ git submodule update --init
$ source third_party/connectedhomeip/scripts/activate.sh
$ gn gen out/debug
$ ninja -C out/debug
```
- To delete generated executable, libraries and object files use:
```
$ cd ~/connectedhomeip/examples/dynamic-bridge-app/linux
$ rm -rf out/
```
## Running the Complete Example on Raspberry Pi 4
- Prerequisites
1. A Raspberry Pi 4 board
2. A USB Bluetooth Dongle, Ubuntu desktop will send Bluetooth advertisement,
which will block CHIP from connecting via BLE. On Ubuntu server, you need
to install `pi-bluetooth` via APT.
3. Ubuntu 20.04 or newer image for ARM64 platform.
- Building
Follow [Building](#building) section of this document.
- Running
- [Optional] Plug USB Bluetooth dongle
- Plug USB Bluetooth dongle and find its bluetooth device number. The
number after `hci` is the bluetooth device number, `1` in this
example.
```
$ hciconfig
hci1: Type: Primary Bus: USB
BD Address: 00:1A:7D:AA:BB:CC ACL MTU: 310:10 SCO MTU: 64:8
UP RUNNING PSCAN ISCAN
RX bytes:20942 acl:1023 sco:0 events:1140 errors:0
TX bytes:16559 acl:1011 sco:0 commands:121 errors:0
hci0: Type: Primary Bus: UART
BD Address: B8:27:EB:AA:BB:CC ACL MTU: 1021:8 SCO MTU: 64:1
UP RUNNING PSCAN ISCAN
RX bytes:8609495 acl:14 sco:0 events:217484 errors:0
TX bytes:92185 acl:20 sco:0 commands:5259 errors:0
```
- Run Linux Bridge Example App
```
$ cd ~/connectedhomeip/examples/dynamic-bridge-app/linux
$ sudo out/debug/dynamic-chip-bridge-app --ble-device [bluetooth device number]
# In this example, the device we want to use is hci1
$ sudo out/debug/chip-bridge-app --ble-device 1
```
- Test the device using ChipDeviceController on your laptop /
workstation etc.