UWB Data Exchange

APP Data Encapsulation

Over-the-air payload is encapsulated in compact binary TLV encoding. The payload structure is displayed below.

Data encapsulation is designed as follows:

msgType (1B)


APP1 TLV structure

APP2 TLV structure

APP_ID (2B)

length [B] (1B)

data (up to 100B)*

……

0x64

id of the application

length of data for the application in bytes

application data

…….

All multi bytes data types within the app protocol are in Little-endian if not mentioned explicitly different.

  • msgType: 0x64 is dedicated to user applications.

  • APP_ID: The range for custom APP ID is <4096;16565>. APP ID is used in all OTA messages.

  • Data: The maximal data length that can be sent from the application to the server (and vice versa) in one blink period is limited to 100B of payload. Moreover, the application should assume that other applications and the system also need to send some content. So if the sum of data sent from all applications is greater than 100B per period over a long period of time, buffer congestion may occur.


Send Data from Server to Tag (Backchannel)

The server user interface is based on REST API in the RTLS Manager.

The documentation of those APIs can be found here:

Interactive API via available at http://[RTLS STUDIO IP]/documentation/api-rtlsmanager

Requests listed above can take from milliseconds to minutes, depending on Tag settings. Therefore there is a JOB approach used to handle HTTP requests with a long response time. So, firstly user gets an immediate answer about the job acceptance (HTTP 202 JOB_ID) and later he can poll for job status via HTTP GET JOB_ID request.

Send Data from Server

  • HTTP POST method /tags/{id or mac}/backchannel, that allows sending arbitrary data to the selected tag.

  • Required fields in the HTTP request: X-Apikey, id, body

  • Required field in the request body

  • Payload REQUIRED

  • Timeout OPTIONAL

    • Maximal time to trying to deliver the backchannel request from anchor to the tag. If the anchor is not able to do it in a defined time the job will be canceled with status failed (message: timeout occurred). The timeout value is set in seconds. If it will be set to null, the timeout will be set automatically by the server, based on the tag settings.

  • Anchor OPTIONAL
    • Define which anchor should be used to send backchannel requests. Anchors MAC address in the hexadecimal form must be used (without 0x prefix). If null, the anchor will be chosen automatically by the server.
Request (via Swagger):

Request (via CURL):
curl -X POST "http://172.16.18.20/rtlsmanager/api/tags/0x24025e4e8949/backchannel" -H "accept: application/json" -H "X-ApiKey: 17254faec6a60f58458308763" -H "Content-Type: application/json" -d "{ \"payload\": \"6400040301F401\", \"timeout\": 10}"
  • The job is received and it returns an immediate response 202 with JOB ID, in our case 896215.

  • If the job responds to code 202, the data was successfully received by the server.

Response:
Response body
{
  "id": 896215
}

Response headers
 access-control-allow-origin: * 
 cache-control: no-cache, private 
 connection: Keep-Alive 
 content-length: 13 
 content-type: application/json 
 date: Tue, 25 Jan 2022 16:19:22 GMT 
 keep-alive: timeout=5, max=52 
 location: /rtlsmanager/api/jobs/896215 
 server: Apache/2.4.29 (Ubuntu) 
 strict-transport-security: max-age=63072000; includeSubdomains 
 x-content-type-options: nosniff 


Check Data Request State

  • HTTP GET /jobs/{id}

  • The user then receives if the data was delivered to the tag via job id GET /jobs/{id}.

Request (via Swagger):

Request (via CURL):
curl -X GET "http://172.16.18.20/rtlsmanager/api/jobs/896215" -H "accept: application/json" -H "X-ApiKey: 17254faec6a60f58458308763"
Response:

If the data was successfully delivered to the tag the job status returns completed. There are just two other states that can happen: in-progress or failed. The reason is provided in the message field i.e Timeout occurred, Transaction was canceled, or successfully completed.

  • Timeout occurred:

    1. The tag is in the Sleep Mode and it has disabled Refresh Interval in Sleep Mode. In this case, the tag does not send the blink pool messages, thus it is also not able to receive any backchannel requests. Solution: Disable the Sleep Mode, or set some non-zero Refresh Interval in sleep mode, see more Tag Settings Backchannel Considerations.

    2. The tag got out of range of the selected anchor before the request was sent to it.

Response body
{
  "id": "896215",
  "at": "2022-01-25T16:19:22Z",
  "request": "rtlsmanager/api/tags/0x24025e4e8949/backchannel",
  "job": {
    "status": "completed",
    "details": {
      "end": "2022-01-25T16:19:23.064Z",
      "durationMs": 39
    },
    "message": "successfully completed",
    "parameters": {
      "tag": "24025e4e8949",
      "jobId": "896215",
      "start": "2022-01-25T16:19:23.025Z",
      "action": "reqStart",
      "anchor": "6827198f5eef",
      "payload": "6400040301F401",
      "numOfAcks": 3,
      "timeoutMs": 10000,
      "syncEnabled": true,
      "immediateAck": true,
      "transactionId": "61f0230b06"
    }
  }
}

Response headers
 access-control-allow-origin: * 
 cache-control: no-cache, private 
 connection: Keep-Alive 
 content-length: 487 
 content-type: application/json 
 date: Tue, 25 Jan 2022 16:21:08 GMT 
 keep-alive: timeout=5, max=87 
 server: Apache/2.4.29 (Ubuntu) 
 strict-transport-security: max-age=63072000; includeSubdomains 
 x-content-type-options: nosniff 

Receive Data from Server on Tag

  • Tag polls for the data from the server each blink period

  • The data for the application that was received from the server is passed to the APP's callback function in the following structure:

  • If len is non zero, there is a new payload within the data buffer

typedef struct {
    uint16_t app_id;
    uint8_t len;
    uint8_t data[100];
}app_data_t;



Send Data from Tag to Server

Data_Req()

  • The payload is stored to transmit buffer via function prepare_response declared in app_data_handlig.h
    bool Data_Req(uint16_t app_id, uint8_t len, uint8_t* data, uint8_t priority, data_confirm_cb_t confirm_cb)

    • app_id - ID of given application

    • len - payload size in bytes

    • data - pointer to buffer to be sent via UWB

    • app_priority - The priority value can have the following values: 0, 1, 2, 3, 4, 5, 6. The lower number has a higher priority. Priorities 0, 1, 3, and 5 are reserved for applications that have been implemented by Sewio, other priorities can be freely used.

    • data_confirm - optionally there is the possibility to pass a callback function data_confirm_cb_t to get a confirmation once the data are sent. If this feature is not used the NULL must be passed instead of a callback function.

  • IF there is a payload with a higher priority the payload will be copied into the internal buffer, but it will not be sent in the next blink because of other applications with higher priority. In this case, our payload will be sent in the next blink after a higher priority payload is served.

  • IF return true

    • The payload was successfully received and it is ready for asynchronous transmission via the UWB channel

  • IF return false

    • Buffer is full, the APP must wait until the next period and try it again.

Data_Conf()

  • This confirmation callback is called just after sending the UWB frame.

Throughput limitations

  • The amount of data that can be sent by applications is limited by throughput. The maximal length of payload that can be sent in one blink is limited to 100B. So the average sum of data length from all apps should not exceed this value.

  • We do not recommend a data payload longer than 50B. The longer payload the higher the packet error rate.

  • Be careful, if some application will generate too much data, it can fill the entire buffer and prevent other applications from sending their data. It can cause congestion or malfunctions of the system. The Sewio core positioning metadata information like tag info, battery level, or sensors data is sent in the same way as user APPS data.

Receive Data from Tag on Server

  • Application is represented in REST API as datastream named: bc_datastream_APP_ID

  • Whenever the server receives any UWB frame from the anchor which contains the APP payload it immediately exposes the given payload to the corresponding bc_datastream_APP_ID.

  • In order to get a payload for a given application and given tag, we need to know the unique FeedID of the given tag.


This job allows the user to get a listing of all tags. In this list can be found the MAC address of the required tag and found out his feed ID, which is necessary to get his datastreams.

In the REST API documentation go to the GET /tags job and click Execute.

In the response, the body list required a tag and finding out his id. This id will be used to get the tag datastreams from the Pick-by-light application.

Get Payload from APP

  • REST API: GET/tags/{id}/datastreams/{datastreams_id}

  • FeedID: required unique ID of Tag feed

  • DatastreamID: required unique ID of APP

Request (via Swagger):

Request (via CURL):
curl -X GET "http://172.16.18.20/sensmapserver/api/feeds/32/datastreams/bc_payload_1024" -H "accept: application/json" -H "X-ApiKey: 17254faec6a60f58458308763"

REST API response contains payloads with timestamps that were received for the given application ID.

Response:
Response headers
 access-control-allow-origin: * 
 cache-control: no-cache, private 
 connection: Keep-Alive 
 content-length: 346 
 content-type: application/json 
 date: Tue, 25 Jan 2022 16:14:24 GMT 
 keep-alive: timeout=5, max=88 
 server: Apache/2.4.29 (Ubuntu) 
 strict-transport-security: max-age=63072000; includeSubdomains 
 x-content-type-options: nosniff 


Response body
Download
{
  "id": "bc_payload_1024",
  "current_value": "00",
  "at": "2022-01-25 15:54:29.870000",
  "unit": {
    "symbol": "",
    "label": ""
  },
  "datapoints": [
    {
      "value": "026f170f0010",
      "at": "2022-01-25T15:50:41.341000Z"
    },
    {
      "value": "00",
      "at": "2022-01-25T15:50:42.447000Z"
    },
...

On this page: