# Develop sensors

## QSH client API workflow

The QSH-exposed APIs are called QSH client APIs for
applications. The client applications interact with the QSH framework available on the
low-power processor. The following figure shows the detailed breakdown and
usage of the QSH client APIs:

<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" width="768" height="801.47" viewbox="0 0 768 801.47" aria-label="Figure : QSH client API workflow">
  <defs>
    <style>.svg-1 .cls-1 { letter-spacing: 0em }
.svg-1 .cls-2,.svg-1 .cls-3,.svg-1 .cls-4 { font-family: Roboto-Bold, Roboto; font-weight: 700 }
.svg-1 .cls-2,.svg-1 .cls-4,.svg-1 .cls-5 { font-size: 15px }
.svg-1 .cls-2,.svg-1 .cls-6 { letter-spacing: .06em }
.svg-1 .cls-7,.svg-1 .cls-8,.svg-1 .cls-9,.svg-1 .cls-10,.svg-1 .cls-11 { stroke-miterlimit: 10 }
.svg-1 .cls-7,.svg-1 .cls-8,.svg-1 .cls-11 { stroke: #000 }
.svg-1 .cls-7,.svg-1 .cls-10,.svg-1 .cls-11 { fill: none }
.svg-1 .cls-3 { font-size: 16px }
.svg-1 .cls-12 { letter-spacing: -.01em }
.svg-1 .cls-13 { font-size: 18.58px }
.svg-1 .cls-13,.svg-1 .cls-5 { font-family: Roboto-Regular, Roboto }
.svg-1 .cls-14 { letter-spacing: .05em }
.svg-1 .cls-8 { fill: #fff; stroke-width: 2px }
.svg-1 .cls-9 { stroke: #d2d7e1 }
.svg-1 .cls-9,.svg-1 .cls-15 { fill: #fafafa }
.svg-1 .cls-10 { stroke: #7c8aa3; stroke-width: 1.5px }
.svg-1 .cls-11 { stroke-dasharray: 4.98 4.98 }
.svg-1 .cls-16 { letter-spacing: .05em }
.svg-1 .cls-17 { letter-spacing: 0em }</style>
  </defs>
  <rect class="cls-9" x="9.27" y="8.38" width="749.47" height="784.62" rx="2.21" ry="2.21"></rect>
  <text class="cls-2" transform="translate(103.97 286.25)"><tspan x="0" y="0">[perSUID]</tspan></text>
  <text class="cls-4" transform="translate(107.6 462.31)"><tspan class="cls-6" x="0" y="0">[sensor</tspan><tspan class="cls-16" x="56.35" y="0">E</tspan><tspan class="cls-14" x="65.5" y="0">v</tspan><tspan class="cls-6" x="73.89" y="0">ent]</tspan></text>
  <text class="cls-3" transform="translate(46.79 286.85)"><tspan x="0" y="0">Opt</tspan></text>
  <rect class="cls-10" x="29.91" y="267.21" width="712.67" height="260.91" rx="1.91" ry="1.91"></rect>
  <rect class="cls-10" x="47.4" y="443.57" width="677.68" height="68.38" rx=".95" ry=".95"></rect>
  <polyline class="cls-10" points="94.92 267.21 94.92 287.73 84.6 298.05 29.91 298.05"></polyline>
  <text class="cls-3" transform="translate(57.57 462.91)"><tspan x="0" y="0">loop</tspan></text>
  <polyline class="cls-10" points="99.91 443.57 99.91 463.03 91.52 473.35 47.07 473.35"></polyline>
  <rect class="cls-8" x="152.26" y="19.37" width="144.4" height="49.54" rx="4.13" ry="4.13"></rect>
  <rect class="cls-8" x="514.16" y="19.37" width="228.42" height="49.54" rx="5.19" ry="5.19"></rect>
  <line class="cls-7" x1="224.46" y1="68.9" x2="224.46" y2="727.66"></line>
  <line class="cls-7" x1="628.36" y1="68.9" x2="628.36" y2="727.66"></line>
  <text class="cls-13" transform="translate(177.85 48.96)"><tspan x="0" y="0">Application</tspan></text>
  <text class="cls-13" transform="translate(536.07 48.96)"><tspan x="0" y="0">libSensingHubSession</tspan></text>
  <rect class="cls-8" x="152.26" y="727.66" width="144.4" height="49.54" rx="4.13" ry="4.13"></rect>
  <rect class="cls-8" x="514.16" y="727.66" width="228.42" height="49.54" rx="5.19" ry="5.19"></rect>
  <text class="cls-13" transform="translate(177.85 757.25)"><tspan x="0" y="0">Application</tspan></text>
  <text class="cls-13" transform="translate(536.07 757.25)"><tspan x="0" y="0">libSensingHubSession</tspan></text>
  <g>
    <line class="cls-7" x1="224.46" y1="112.63" x2="622.62" y2="112.63"></line>
    <polygon points="621.46 116.62 628.36 112.63 621.46 108.64 621.46 116.62"></polygon>
  </g>
  <g>
    <line class="cls-7" x1="224.46" y1="202.12" x2="622.62" y2="202.12"></line>
    <polygon points="621.46 206.11 628.36 202.12 621.46 198.14 621.46 206.11"></polygon>
  </g>
  <g>
    <line class="cls-7" x1="224.46" y1="556.68" x2="622.62" y2="556.68"></line>
    <polygon points="621.46 560.67 628.36 556.68 621.46 552.69 621.46 560.67"></polygon>
  </g>
  <g>
    <line class="cls-7" x1="224.46" y1="291.62" x2="622.62" y2="291.62"></line>
    <polygon points="621.46 295.61 628.36 291.62 621.46 287.63 621.46 295.61"></polygon>
  </g>
  <g>
    <line class="cls-7" x1="224.46" y1="381.12" x2="622.62" y2="381.12"></line>
    <polygon points="621.46 385.11 628.36 381.12 621.46 377.13 621.46 385.11"></polygon>
  </g>
  <g>
    <line class="cls-7" x1="230.2" y1="157.38" x2="232.7" y2="157.38"></line>
    <line class="cls-11" x1="237.68" y1="157.38" x2="623.38" y2="157.38"></line>
    <line class="cls-7" x1="625.86" y1="157.38" x2="628.36" y2="157.38"></line>
    <polygon points="231.37 161.37 224.46 157.38 231.37 153.39 231.37 161.37"></polygon>
  </g>
  <g>
    <line class="cls-7" x1="230.2" y1="246.87" x2="232.7" y2="246.87"></line>
    <line class="cls-11" x1="237.68" y1="246.87" x2="623.38" y2="246.87"></line>
    <line class="cls-7" x1="625.86" y1="246.87" x2="628.36" y2="246.87"></line>
    <polygon points="231.37 250.86 224.46 246.87 231.37 242.88 231.37 250.86"></polygon>
  </g>
  <g>
    <line class="cls-7" x1="230.2" y1="336.37" x2="232.7" y2="336.37"></line>
    <line class="cls-11" x1="237.68" y1="336.37" x2="623.38" y2="336.37"></line>
    <line class="cls-7" x1="625.86" y1="336.37" x2="628.36" y2="336.37"></line>
    <polygon points="231.37 340.36 224.46 336.37 231.37 332.38 231.37 340.36"></polygon>
  </g>
  <g>
    <line class="cls-7" x1="230.2" y1="425.87" x2="232.7" y2="425.87"></line>
    <line class="cls-11" x1="237.68" y1="425.87" x2="623.38" y2="425.87"></line>
    <line class="cls-7" x1="625.86" y1="425.87" x2="628.36" y2="425.87"></line>
    <polygon points="231.37 429.86 224.46 425.87 231.37 421.88 231.37 429.86"></polygon>
  </g>
  <g>
    <line class="cls-7" x1="230.2" y1="477.76" x2="232.7" y2="477.76"></line>
    <line class="cls-11" x1="237.68" y1="477.76" x2="623.38" y2="477.76"></line>
    <line class="cls-7" x1="625.86" y1="477.76" x2="628.36" y2="477.76"></line>
    <polygon points="231.37 481.75 224.46 477.76 231.37 473.77 231.37 481.75"></polygon>
  </g>
  <g>
    <line class="cls-7" x1="230.2" y1="601.43" x2="232.7" y2="601.43"></line>
    <line class="cls-11" x1="237.68" y1="601.43" x2="623.38" y2="601.43"></line>
    <line class="cls-7" x1="625.86" y1="601.43" x2="628.36" y2="601.43"></line>
    <polygon points="231.37 605.42 224.46 601.43 231.37 597.44 231.37 605.42"></polygon>
  </g>
  <g>
    <path class="cls-7" d="M224.46,646.18h66.78c11.02,0,19.95,8.93,19.95,19.95h0c0,11.02-8.93,19.95-19.95,19.95h-59.6"></path>
    <polygon points="233.1 681.09 224.46 686.08 233.1 691.07 233.1 681.09"></polygon>
  </g>
  <rect class="cls-15" x="385" y="103.06" width="82.83" height="19.14"></rect>
  <rect class="cls-15" x="387.87" y="147.8" width="77.1" height="19.14"></rect>
  <rect class="cls-15" x="399.56" y="192.55" width="53.71" height="19.14"></rect>
  <rect class="cls-15" x="380.3" y="237.3" width="92.23" height="19.14"></rect>
  <rect class="cls-15" x="378.23" y="282.05" width="96.36" height="19.14"></rect>
  <rect class="cls-15" x="382.02" y="326.8" width="88.79" height="19.14"></rect>
  <rect class="cls-15" x="378.23" y="371.55" width="96.36" height="19.14"></rect>
  <rect class="cls-15" x="382.02" y="416.3" width="88.79" height="19.14"></rect>
  <rect class="cls-15" x="380.3" y="468.19" width="92.23" height="19.14"></rect>
  <rect class="cls-15" x="399.91" y="547.11" width="53.02" height="19.14"></rect>
  <text class="cls-5" transform="translate(389.39 116.85)"><tspan x="0" y="0">getSession</tspan></text>
  <text class="cls-5" transform="translate(395.33 161.6)"><tspan x="0" y="0">Isession*</tspan></text>
  <text class="cls-5" transform="translate(408.94 206.35)"><tspan x="0" y="0">Open</tspan></text>
  <text class="cls-5" transform="translate(402.42 560.9)"><tspan x="0" y="0">Close()</tspan></text>
  <text class="cls-5" transform="translate(383.18 295.84)"><tspan x="0" y="0">setCallBacks</tspan></text>
  <text class="cls-5" transform="translate(382.93 385.34)"><tspan x="0" y="0">sendRequest</tspan></text>
  <text class="cls-5" transform="translate(385.44 251.1)"><tspan x="0" y="0">success/fail</tspan></text>
  <text class="cls-5" transform="translate(385.44 340.59)"><tspan x="0" y="0">success/fail</tspan></text>
  <text class="cls-5" transform="translate(385.44 430.09)"><tspan x="0" y="0">success/fail</tspan></text>
  <text class="cls-5" transform="translate(385.44 481.98)"><tspan x="0" y="0">sensor</tspan><tspan class="cls-12" x="45.32" y="0">E</tspan><tspan class="cls-1" x="53.66" y="0">v</tspan><tspan class="cls-17" x="60.83" y="0">ent</tspan></text>
  <text class="cls-5" transform="translate(109.72 649.57)"><tspan x="0" y="0">delete ISession*</tspan></text>
</svg>

**Figure: QSH client API workflow**

The following list describes the QSH client APIs:

- **getSession**

    To interact with the QSH, the sensor application client must create
an interface session by invoking the `getSession()` API. Successful creation of the interface session returns an
`ISession*` object to the client.
- **Open, Close, SetCallback, and SendRequest**

    The interface created using the `getSession()` API operates on a
*once\_per\_session* basis. This interface allows the client application to
use the QSH client APIs, such as `open()`, `close()`,
`setCallback()`, and `sendRequest()`, until the session is
explicitly deleted using the `close()` and `delete()` APIs.

    After the interface session establishes, the client application or the
client code can open a sensor session by calling the `open()` API.
Similar to `getSession()`, the `open()` API is also invoked on a
*once\_per\_session* basis. Additionally, the `setCallback()` and
`sendRequest()` APIs are invoked once for a specified SUID.

### Messages

The sensor client applications sends and receives the following request and response messages:

1. Sends a `sns_client_request_msg` request message through the
`sendRequest()` API.

    - The sole field of this message is the payload, which is an opaque
byte array. This field is populated with the protocol
buffer-encoded `sns_client_request_msg` message.
2. Receives a `sns_client_resp_msg` response message.

    - The client manager performs minimal task of determining if the `sns_client_request_msg`
message is appropriately encoded and the destination SUID is
available. A minimal amount of processing is performed on the request.
    - The client manager sends this response message immediately after receiving the request.
3. Receives one or more events of `sns_client_event_msg` message type.

    - The event callback function receives the event messages, as specified in the `setCallback` API.
    - Each event message has a SUID.
    - An event message may contain one or more logical sensor samples
that are all encoded in the single `sns_client_event_msg`
message.

### Protocol buffers

The QSH client request and event messages are opaque memory buffers that
contain the protocol buffer-encoded messages. Clients can generate these
messages in several programming languages and then copy the encoded byte
stream into a `sns_client_request_msg` message. Similarly, clients can
copy the encoded message from within the `sns_client_report_ind_msg`
message and decode it separately.

For more information about protocol buffers, see
[Protocol-buffers](https://developers.google.com/protocol-buffers/)
and [nanopb](https://github.com/nanopb/nanopb).

### Client manager

The sensor client manager, housed within the QSH, oversees all
communication processes and performs the following responsibilities:

- **Translate incoming requests**: The client manager receives incoming
requests and translates them to a format that the QSH can
understand. The translation involves converting the requests into
specific request messages.
- **Translate outgoing indications**: After receiving the event messages from QSH, the client manager translates the
event messages into outgoing indications. The translation ensures
that the messages are in a format that’s understandable outside the
QSH.
- **Ensure batching options**: If a client specifies certain
batching options, then the client manager ensures
that these options are met. It checks that the data is grouped and
sent in the way the client has specified.

    For more information about the client manager, see the
`<workspace>/build-qcom-wayland/workspace/sources/sensinghub/sensing-hub/apis/proto/sns_client.proto`
file.
- **SUID**: The SUID is an integer that uniquely identifies a single
sensor available from the QSH. Clients consider this ID as generated
randomly upon boot. Clients don’t assume that the ID repeats or
derives any information from the number itself. The client manager reads the SUID from the request and routes the request to the sensor identified by the SUID.

    For example, if there are two gravity algorithms available from the
QSH, then each has its own unique SUID. This unique ID assignment is
true for physical sensors too. If the hardware for a physical
sensor model is present many times on the device, then each has its
own SUID.

    For a complete list of sensors available on the system, the client
can send a request to the SUID sensor.
- **Client requests**: All incoming requests to the client manager use
`sns_client_request_msg` as the outermost protocol buffer message.
This message has the following fields:

    - SUID: Serves as the destination address of the request message.
Send all request messages to a valid SUID for processing;
otherwise, the client manager rejects them.
    - msg\_id: A numeric identifier for the encoded request contained
in the `sns_std_request::payload` message.

        For example, a sensor may support an enable streaming request message, and an initiated
data flush request. The formats of these two messages are
different, and this field indicates the destination sensor on how
to interpret the request. Message IDs are always unique among all
messages supported by a sensor. However, two different sensors may
use a particular ID for different message types.

        For example,
    - **Message types**—there are two types of messages:

        - `SNS_STD_SENSOR_MSGID_SNS_STD_SENSOR_CONFIG`: Denotes
standard streaming request from a client to a sensor.
        - `SNS_STD_SENSOR_MSGID_SNS_STD_SENSOR_EVENT`: Denotes a
standard sensor event from a data source sensor.
    - **Request**—is the information package that the client sends to the sensor. It has all the details required by the sensor. The `sns_std_request::payload` field corresponds to the message ID and has the sensor-specific configuration. For more information, see the sensor-specific proto.
    - **Resampler configuration**—is used when the client wants to
change the rate at which the sensor samples the data. Use the
following options for resampler configuration:

        - `SNS_RESAMPLER_RATE_FIXED`: The client wants data at a
specific rate. For example, if the client wants to get data at
200 Hz, whereas the physical sensor supports streaming at
240 Hz, then the samples are interpolated to 200 Hz.
        - `SNS_RESAMPLER_RATE_MINIMUM`: The client wants data at a
certain least rate. For example, if the client wants to get
data at 200 Hz, whereas the physical sensor supports streaming
at 240 Hz, then the samples are sent at 240 Hz.
    - **Threshold configuration**—is used when the client wants the
data only when certain conditions are met. There are four types of
conditions:

        - `SNS_THRESHOLD_TYPE_RELATIVE_VALUE` provides thresholding as
a delta between the current value and the last reported value
that exceeds above the configured threshold.
        - `SNS_THRESHOLD_TYPE_RELATIVE_PERCENT` provides thresholding based on the difference between the current value and the last reported value. It’s a percentage of the last reported value, with the percentage representing the configured threshold.
        - `SNS_THRESHOLD_TYPE_ABSOLUTE` provides thresholding of the
current value against a fixed configured threshold value.
        - `SNS_THRESHOLD_TYPE_ANGLE` provides a thresholding of the
angle between the current and the last reported quaternion for
the quaternion sensors (in radians).
    - **Suspend configuration**—specifies how the system behaves when
the processor suspends.

        - `client_proc_type` is the processor where the client is
located. If any client on this processor asks for a flush (a
complete send out of data), all clients on that processor get a
flush of data.
        - `delivery_type` is about whether to send events while the
processor suspends.

            - `SNS_STD_DELIVERY_WAKEUP`: Sends events whenever they
become available (at sample rate or batch period). If a
`batch_period` larger than the system capacity is
requested, all the data is sent upon capacity exhaustion.
With this option, the `flush_period` is effectively
ignored, as unsent batched data that doesn’t have the
opportunity to accrue in the buffer.
            - `SNS_STD_DELIVERY_NO_WAKEUP`: Sends events only when the
client processor isn’t suspended; otherwise, batches the
data until the flush period. After the target processor
exits suspend, all the pending events are sent.
        - `nowakeup_msg_ids` is a list of message IDs for which the
client processor must not be woken up. The message IDs
mentioned aren’t wake-up capable. They’re only sent if any
other wake-up capable events are present.

        For more information, see the `<workspace>/build-qcom-wayland/workspace/sources/sensinghub/sensing-hub/apis/proto/sns_client.proto` file.
- **Batching**: Within the `sns_client_request_msg::sns_std_request`
message, the client can specify how and when it receives the
requested data. `sns_std_request` has the following fields:

    - `batching::batch_period`: An unsigned integer value that denotes
the batch time in microseconds. A client can assume that a timer
is registered for the given `batch_period`. All
events generated since the last timer expiration are saved until
the next timer is fired. This period is interpreted as the maximum
period specified by the client. Events are delivered to the
client at a faster rate (smaller batch period) in some concurrency
scenarios. A client may send a flush request at any time to
instruct the client manager to send all the batched data. By
default, batching is disabled.
    - `batching::flush_period`: An unsigned integer value measured in microseconds. This field provides a hint to the client
manager or physical sensor regarding the quantity of historical data that must
be batched if the data is not sent to the client. In other words,
the client manager may drop the data that is older than the
`flush_period` in microseconds. The effective flush period can
be smaller due to the system memory constraints or larger in
concurrency cases. This field is optional and if not set, defaults
to `batch_period`, that is, only a single batch of data is
maintained. If this field is set, then the `flush_period` must
be greater than or equal to `batch_period`.
    - `batching::flush_only`: If set to `True`, the client manager sends
events only upon a client-initiated flush. Otherwise, it continues
batching until `flush_period` is reached (at which time,
batching continues, but the oldest data are dropped).
    - `batching::max_batch`: If set to `True`, it directs the sensor to
operate at maximum batching capacity. If a request has both
`flush_only = true` and `max_batch = true`, then
`flush_only` takes precedence.
- **Client event**: All outgoing indications from the client manager
use `sns_client_event_msg` as the outermost protocol buffer-encoded
message, within the payload field of `sns_client_report_ind_msg`. The `sns_client_event_msg` message has several fields:

    - SUID: it’s associated with the data source event. If a client sends
requests to many SUIDs on a single connection, then this
message has only the events for one SUID. Events from other
SUIDs are delivered in separate indication messages.
    - `events::msg_id`: Uniquely identifies the associated event
message.
    - `events::timestamp`: The timestamp associated with this event
in the QTimer clock ticks. For most events, the sensor sets the
timestamp, which refers to the time when the physical sample was
created in the sensor hardware. For events generated by the
framework (such as configuration updates or error events), this
timestamp refers to the time at which the event was created.
    - `events::payload`: Dynamic length payload, containing the actual
data/event from the sensor. Decode this payload separately using
the sensor-specific proto buffer.
- **Message payloads**: The sensor-specific request or event is
referred in `sns_client_request_msg::sns_std_request::payload` and
`sns_client_event_msg::sns_client_event::payload` messages. These
message fields may contain a protocol buffer-encoded message with fields
specific to that message ID or may be empty and have no fields.

    Clients use the `.proto` file associated with the sensor to which
they communicate. Each sensor type has a corresponding `.proto`
file. For example, `sns_accel.proto` describes how to enable an
accelerometer stream. Also, every sensor publishes its list of
`.proto` files as a part of its attributes. For more information,
see table\_sensor\_attribute.

    - **Data types**: Each sensor advertises a data type attribute. Each
data type is associated with a unique set of `*.proto` files
that make up the sensor-specific API for that sensor. All sensors
of the same type must support a minimum set of requests and event
messages. They may define and use more optional messages that are
specific to that sensor implementation. Each sensor publishes a
complete list of `.proto` files as part of its attributes.
    - **Standardized messages**: A client can send a set of standardized Qualcomm-defined messages to any sensor. These
messages are defined in the `sns_std.proto` file.

        - `SNS_STD_MSGID_SNS_STD_ATTR_REQ`: Queries a sensor for the
list of attributes. It returns an event with an
`SNS_STD_MSGID_SNS_STD_ATTR_EVENT` ID that has a list of
all the published attributes, see table\_sensor\_attribute.
Clients can also register for notification when a new or
updated attribute is published.

            - The `sns_std_attr_req` has the `register_updates` field. If set to `True`, the client receives notifications whenever there is a change in the sensor attributes through `sns_std_attr_event`.
            - The `sns_std_attr_event` has the `attributes` field, which lists all the attributes published by a sensor sent in response to `sns_std_attr_req`, or on an attribute change to a registered sensor.
        - `SNS_STD_MSGID_SNS_STD_FLUSH_REQ`: Forces all the batch data
from this sensor to be immediately sent to the client. This
command forces the applicable hardware and software buffers on
the system to flush all the data present.

            For example, sending this request to an accelerometer sensor
causes the physical FIFO flush, as well as any samples
currently held by the client manager. If the flush request is
to an algorithm, such as a GRV, which
internally uses accelerometer and gyroscope data, then both the
accelerometer and gyroscope hardware FIFOs are flushed.
        - `SNS_CLIENT_MSGID_SNS_CLIENT_DISABLE_REQ`: Disables the
active request for this sensor. For example, the client sends a
`SNS_STD_SENSOR_MSGID_SNS_STD_SENSOR_CONFIG` message to the
accelerometer sensor to enable streaming. Later, sending a
`DISABLE_REQ` cancels the streaming request, and
accelerometer streaming ceases for this client.
        - `SNS_STD_MSGID_SNS_STD_FLUSH–EVENT`: Response to a flush
request. It indicates no further events corresponding to the
flush request.
        - `SNS_STD_MSGID_SNS_STD_ERROR–EVENT`: An error event generated
by a sensor/instance or the framework.

            For more information, see the
`<workspace>/build-qcom-wayland/workspace/sources/sensinghub/sensing-hub/apis/proto/sns_client.proto`
file.
    - **Standardized sensor messages**: The messages described in the
client request are applicable to all the sensors. In addition to
the messages described in the client request, you can use
Qualcomm-recommended standardized messages. These recommendations
are optional, and you may instead choose to define your own
request and event messages.

        - `SNS_STD_SENSOR_MSGID_SNS_STD_SENSOR_CONFIG`: Request message
that allows streaming for:

            - Any physical sensor, for example, accelerometer, gyroscope,
and magnetometer.
            - Some algorithms, for example, rotation vector, gravity, and
linear acceleration.
        - `SNS_STD_SENSOR_MSGID_SNS_STD_ON_CHANGE_CONFIG`: Request
message that allows streaming for an on-change type sensor.
For example, proximity, ambient\_light, and step\_detect.
        - `SNS_STD_SENSOR_MSGID_SNS_STD_SENSOR_PHYSICAL_CONFIG_EVENT`:
Event sent by all the physical sensors after processing a client
request. It indicates the data stream client’s expectation, such as
the rate at which the sensor produces samples.
        - `SNS_STD_SENSOR_MSGID_SNS_STD_SENSOR_EVENT`: Data sample
produced by the sensor.

        For more information, see the `sns_std_sensor.proto` file.
    - **SUID lookup sensor**: Clients may query the SUID lookup sensor
for the list of SUIDs associated with a specific data type. The
`sns_suid_req` message specifies a data type, and the client
receives all matching SUIDs. An empty data type string results in
the receipt of the list of all SUIDs on the system.

        For example, if a client specifies *accel* as the data type, then
the client receives a list of all SUIDs whose sensors provide data of
type *accel*. Additionally, if the client wants to receive
notifications for a new match, then they can indicate it
through the `register_updates` field. The `sns_suid_req`
message can be followed up by an attribute request
(`sns_std_attr_req`) by the client to decide which of the
available *accel* sensors are appropriate for this client.

        The SUID lookup sensor has its own SUID, which is constant and is
published in a `sns_suid.proto` file (making it unique among all
other sensors).

        The `sns_suid_req` message has the following fields:

Table : SUID request

        | Field | Mandatory or optional | Data type | Description |
        | --- | --- | --- | --- |
        | `data_type` | Mandatory | String | Data type of the sensor for which SUID is to be queried. |
        | `register_updates` | Optional | Boolean | Register for updates to the list of SUIDs advertising the `data_type` field. |
        | `default_only` | Optional | Boolean | Each data type may have one sensor configured to be default through the registry.<br><br><br><br>> <br>> <br>> <ul class="simple"><br>> <li><p>If the <code class="docutils literal notranslate"><span class="pre">default_only</span></code> field is set to True and:</p><ul><br>> <li><p>A default for the data type is explicitly configured, then only the SUID of the default sensor is sent through the SUID event when available.</p></li><br>> <li><p>A default for the data type is not explicitly configured, then the SUID of the first sensor with the matching data type is sent through the SUID event.</p></li><br>> </ul><br>> </li><br>> <li><p>If the <code class="docutils literal notranslate"><span class="pre">default_only</span></code> field is set to False, then all the sensors with the matching data type are sent as and when they become available.</p></li><br>> </ul> |

> 
> 
> For more information, see the `sns_suid.proto` file and example code.
- **Sensor attributes**: Every sensor publishes a list of attributes,
representing each attribute with a numeric identifier. These
attributes provide information regarding the sensor capabilities and
the range of values that it accepts as an input.

    The following table lists a few important attributes:

> 
> 
> > 
> > 
> > Table : Sensor attribute
> > 
> > 
> > | Attribute ID | Attribute name | Mandatory? | Data type | Description |
> > | --- | --- | --- | --- | --- |
> > | 0 | `SNS_STD_SENSOR_ATTRID_NAME` | Yes | String | Human-readable sensor name. |
> > | 1 | `SNS_STD_SENSOR_ATTRID_VENDOR` | Yes | String | Human-readable vendor name. |
> > | 2 | `SNS_STD_SENSOR_ATTRID_TYPE` | Yes | String | The data type used by this sensor, as defined in the sensor proto file. |
> > | 3 | `SNS_STD_SENSOR_ATTRID_AVAILABLE` | Yes | Boolean | Indicates whether this sensor is available for the clients or not. |
> > | 4 | `SNS_STD_SENSOR_ATTRID_VERSION` | Yes | Integer | <ul class="simple"><br><li><p>64‑bit integer value represented as <code class="docutils literal notranslate"><span class="pre">major[31:16].minor[15:8].revision[7:0]</span></code>, denoting the sensor version.</p></li><br><li><p>Example in hexadecimal: major: 0x0002 minor: 0x00 revision: 0x36.</p></li><br><li><p>DRIVER_VERSION 0x00020036.</p></li><br></ul> |
> > | 5 | `SNS_STD_SENSOR_ATTRID_API` | Yes | String | List of the `.proto` filenames used by this sensor; more `.proto` dependencies may be specified as imports within the same proto file used primarily for the test automation. |
> > | 6 | `SNS_STD_SENSOR_ATTRID_RATES` | No | Float | List of sample rates supported by the sensor. |
> > | 7 | `SNS_STD_SENSOR_ATTRID_RESOLUTIONS` | No | Float | List of sample resolutions supported by the sensor. |
> > | 8 | `SNS_STD_SENSOR_ATTRID_FIFO_SIZE` | No | Integer | Supported FIFO depth (in number of samples). |
> > | 9 | `SNS_STD_SENSOR_ATTRID_ACTIVE_CURRENT` | No | Integer | Array of active currents (in µA). |
> > | 10 | `SNS_STD_SENSOR_ATTRID_SLEEP_CURRENT` | No | Integer | Inactive current (in µA). |
> > | 11 | `SNS_STD_SENSOR_ATTRID_RANGES` | No | Float | Supported operating ranges by the sensor. |
> > | 12 | `SNS_STD_SENSOR_ATTRID_OP_MODES` | No | String | An array of strings defines operating modes supported by the sensor.<br><br><br>For example, [LPM, HIGH\_PERF, NORMAL, OFF]. |
> > | 13 | `SNS_STD_SENSOR_ATTRID_DRI` | No | Boolean | Denotes whether the sensor supports the DRI or IBI:<br><br><br><br>> <br>> <br>> <ul class="simple"><br>> <li><p>True = DRI</p></li><br>> <li><p>False = IBI</p></li><br>> </ul> |
> > | 14 | `SNS_STD_SENSOR_ATTRID_STREAM_SYNC` | No | Boolean | Denotes whether a sensor supports synchronized streaming. |
> > | 15 | `SNS_STD_SENSOR_ATTRID_EVENT_SIZE` | No | Integer | <ul class="simple"><br><li><p>The size (in bytes) of the data event (protocol-buffer-encoded) produced by this sensor.</p></li><br><li><p>For physical and virtual sensors, this value refers to the size of their sensor sample</p></li><br><li><p>Used by the HAL for maximum batching capacity determination.</p></li><br></ul> |
> > | 16 | `SNS_STD_SENSOR_ATTRID_STREAM_TYPE` | Yes | Integer | Denotes the streaming type supported by the sensor:<br><br><br><br>> <br>> <br>> <ul class="simple"><br>> <li><p>0 = continuous periodic sampling</p></li><br>> <li><p>1 = on-change</p></li><br>> <li><p>2 = single output (one-shot)</p></li><br>> </ul> |
> > | 17 | `SNS_STD_SENSOR_ATTRID_DYNAMIC` | No | Boolean | Specifies if this sensor is dynamic (connected/disconnected at runtime). |
> > | 18 | `SNS_STD_SENSOR_ATTRID_HW_ID` | No | Integer | Differentiates multiple sensors of the same hardware. |
> > | 19 | `SNS_STD_SENSOR_ATTRID_RIGID_BODY` | No | Integer | The rigid body on which the sensor is placed.<br><br><br><br>> <br>> <br>> <ul class="simple"><br>> <li><p>0 = sensor hardware is on the display side</p></li><br>> <li><p>1 = sensor hardware is on the keyboard side</p></li><br>> <li><p>2 = sensor hardware is mounted on an external device</p></li><br>> </ul> |
> > | 21 | `SNS_STD_SENSOR_ATTRID_PHYSICAL_SENSOR` | No | Boolean | <ul class="simple"><br><li><p><code class="docutils literal notranslate"><span class="pre">True</span></code>, if physical sensor.</p></li><br><li><p><code class="docutils literal notranslate"><span class="pre">False</span></code>, if virtual sensor.</p></li><br></ul> |
> > | 22 | `SNS_STD_SENSOR_ATTRID_PHYSICAL_SENSOR_TESTS` | No | Integer | List of supported physical sensor tests using enum values in `sns_physical_sensor_test_type`. |
> > | 23 | `SNS_STD_SENSOR_ATTRID_SELECTED_RESOLUTION` | No | Float | Measurement resolution for each dynamic range value. |
> > | 24 | `SNS_STD_SENSOR_ATTRID_SELECTED_RANGE` | No | Float[2] | Dynamic range options supported by the sensor. For the default option, see the requirement specification. |
> > | 25 | `SNS_STD_SENSOR_ATTRID_ADDITIONAL_LOW_LATENCY_RATES` | No | Float | List of additional sample rates for low-latency operation, in Hz. These sample rates are for dedicated low-latency clients, extending the list of rates published in the `SNS_STD_SENSOR_ATTRID_RATES` attribute.<br><br><br>Dedicated internal clients must use these higher data rates, as they may impact system performance. |
> > | 26 | `SNS_STD_SENSOR_ATTRID_PASSIVE_REQUEST` | No | Boolean | `True` if the sensor supports passive requests, `False` otherwise. If a sensor does not support passive requests, then all the requests must be treated as active. |
> > | 29 | `SNS_STD_SENSOR_ATTRID_TRANSPORT_MTU_SIZE` | No | Integers | MTU size for a transport sensor, in bytes. |
> > | 30 | `SNS_STD_SENSOR_ATTRID_HLOS_INCOMPATIBLE` | No | Boolean | `True` if the sensor is not compatible with the high-level operating system (HLOS) specification for the supported data type. |
> > | 31 | `SNS_STD_SENSOR_ATTRID_SERIAL_NUM` | No | String | Sensor serial number. |
> > | 32 | `SNS_STD_SENSOR_ATTRID_TECH_USED` | No | Integer array | List of technologies used. For more information see, `sns_tech` in the `sns_std_type.proto` file. |
> 
> 
> 
> For more information, see the `sns_std_sensor.proto` file and example code. Proto files are in the  `/etc/sensors/proto/` directory on the device.

## Develop applications using QSH client APIs

The `SessionClient` sample application shows the usage of QSH client API to develop applications. By default, this sample application is built in the `/usr/bin` directory on the device. For complete sample code, see the
`<workspace>/build-qcom-wayland/workspace/sources/sensinghub/sensing-hub/examples/SessionClient/SessionClient.cpp`
file.

The following figure shows the call flow for streaming the accelerometer
sensor and the usage of the QSH client APIs.

<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" width="801" height="683" viewbox="0 0 801 683" aria-label="Figure : Call flow to stream a specified sensor">
  <defs>
    <style>.svg-2 .cls-1 { letter-spacing: 0em }
.svg-2 .cls-2,.svg-2 .cls-3,.svg-2 .cls-4,.svg-2 .cls-5,.svg-2 .cls-6 { stroke-miterlimit: 10 }
.svg-2 .cls-2,.svg-2 .cls-3,.svg-2 .cls-6 { stroke: #000 }
.svg-2 .cls-2,.svg-2 .cls-5,.svg-2 .cls-6 { fill: none }
.svg-2 .cls-7 { font-size: 16px }
.svg-2 .cls-7,.svg-2 .cls-8 { font-family: Roboto-Bold, Roboto; font-weight: 700 }
.svg-2 .cls-9 { letter-spacing: -.01em }
.svg-2 .cls-10 { letter-spacing: .05em }
.svg-2 .cls-11 { font-size: 18.58px }
.svg-2 .cls-11,.svg-2 .cls-12 { font-family: Roboto-Regular, Roboto }
.svg-2 .cls-13 { letter-spacing: 0em }
.svg-2 .cls-14 { letter-spacing: .06em }
.svg-2 .cls-8,.svg-2 .cls-12 { font-size: 15px }
.svg-2 .cls-15 { letter-spacing: .07em }
.svg-2 .cls-16 { letter-spacing: .02em }
.svg-2 .cls-3 { fill: #fff; stroke-width: 2px }
.svg-2 .cls-17 { letter-spacing: 0em }
.svg-2 .cls-4 { stroke: #d2d7e1 }
.svg-2 .cls-4,.svg-2 .cls-18 { fill: #fafafa }
.svg-2 .cls-5 { stroke: #7c8aa3; stroke-width: 1.5px }
.svg-2 .cls-6 { stroke-dasharray: 4.98 4.98 }
.svg-2 .cls-19 { letter-spacing: .05em }
.svg-2 .cls-20 { letter-spacing: .06em }
.svg-2 .cls-21 { letter-spacing: 0em }
.svg-2 .cls-22 { letter-spacing: 0em }</style>
  </defs>
  <rect class="cls-4" x="8.19" y="8.85" width="784.62" height="666.82" rx="2.09" ry="2.09"></rect>
  <g>
    <text class="cls-8" transform="translate(87.12 190.08)"><tspan class="cls-20" x="0" y="0">[</tspan><tspan class="cls-19" x="5.07" y="0">r</tspan><tspan class="cls-14" x="11.3" y="0">e</tspan><tspan class="cls-10" x="20.31" y="0">f</tspan><tspan class="cls-20" x="26.41" y="0">er QSH Inte</tspan><tspan class="cls-15" x="113.48" y="0">r</tspan><tspan class="cls-20" x="120" y="0">face]</tspan></text>
    <rect class="cls-5" x="23.69" y="171.34" width="753.96" height="92.36" rx="1.1" ry="1.1"></rect>
    <text class="cls-7" transform="translate(33.86 190.68)"><tspan x="0" y="0">loop</tspan></text>
    <polyline class="cls-5" points="76.2 171.34 76.2 190.8 67.81 201.12 23.36 201.12"></polyline>
    <text class="cls-8" transform="translate(87.12 306.9)"><tspan class="cls-20" x="0" y="0">[</tspan><tspan class="cls-19" x="5.07" y="0">r</tspan><tspan class="cls-14" x="11.3" y="0">e</tspan><tspan class="cls-10" x="20.31" y="0">f</tspan><tspan class="cls-20" x="26.41" y="0">er QSH Inte</tspan><tspan class="cls-15" x="113.48" y="0">r</tspan><tspan class="cls-20" x="120" y="0">face]</tspan></text>
    <rect class="cls-5" x="23.69" y="288.16" width="753.96" height="92.36" rx="1.1" ry="1.1"></rect>
    <text class="cls-7" transform="translate(33.86 307.5)"><tspan x="0" y="0">loop</tspan></text>
    <polyline class="cls-5" points="76.2 288.16 76.2 307.62 67.81 317.94 23.36 317.94"></polyline>
    <text class="cls-8" transform="translate(87.12 423.85)"><tspan class="cls-20" x="0" y="0">[</tspan><tspan class="cls-19" x="5.07" y="0">r</tspan><tspan class="cls-14" x="11.3" y="0">e</tspan><tspan class="cls-10" x="20.31" y="0">f</tspan><tspan class="cls-20" x="26.41" y="0">er QSH Inte</tspan><tspan class="cls-15" x="113.48" y="0">r</tspan><tspan class="cls-20" x="120" y="0">face]</tspan></text>
    <rect class="cls-5" x="23.69" y="405.11" width="753.96" height="92.36" rx="1.1" ry="1.1"></rect>
    <text class="cls-7" transform="translate(33.86 424.46)"><tspan x="0" y="0">loop</tspan></text>
    <polyline class="cls-5" points="76.2 405.11 76.2 424.57 67.81 434.89 23.36 434.89"></polyline>
    <rect class="cls-3" x="186.78" y="23.21" width="144.4" height="49.54" rx="4.13" ry="4.13"></rect>
    <rect class="cls-3" x="548.67" y="23.21" width="228.42" height="49.54" rx="5.19" ry="5.19"></rect>
    <line class="cls-2" x1="258.98" y1="72.74" x2="258.98" y2="621.78"></line>
    <line class="cls-2" x1="662.88" y1="72.74" x2="662.88" y2="621.78"></line>
    <text class="cls-11" transform="translate(212.37 52.8)"><tspan x="0" y="0">Application</tspan></text>
    <text class="cls-11" transform="translate(570.59 52.8)"><tspan x="0" y="0">libSensingHubSession</tspan></text>
    <rect class="cls-3" x="186.78" y="611.77" width="144.4" height="49.54" rx="4.13" ry="4.13"></rect>
    <rect class="cls-3" x="548.67" y="611.77" width="228.42" height="49.54" rx="5.19" ry="5.19"></rect>
    <text class="cls-11" transform="translate(212.37 641.36)"><tspan x="0" y="0">Application</tspan></text>
    <text class="cls-11" transform="translate(570.59 641.36)"><tspan x="0" y="0">libSensingHubSession</tspan></text>
    <g>
      <line class="cls-2" x1="258.98" y1="116.47" x2="657.14" y2="116.47"></line>
      <polygon points="655.98 120.46 662.88 116.47 655.98 112.48 655.98 120.46"></polygon>
    </g>
    <g>
      <line class="cls-2" x1="258.98" y1="200.31" x2="657.14" y2="200.31"></line>
      <polygon points="655.98 204.3 662.88 200.31 655.98 196.32 655.98 204.3"></polygon>
    </g>
    <g>
      <line class="cls-2" x1="258.98" y1="314.97" x2="657.14" y2="314.97"></line>
      <polygon points="655.98 318.95 662.88 314.97 655.98 310.98 655.98 318.95"></polygon>
    </g>
    <g>
      <line class="cls-2" x1="258.98" y1="431.92" x2="657.14" y2="431.92"></line>
      <polygon points="655.98 435.91 662.88 431.92 655.98 427.93 655.98 435.91"></polygon>
    </g>
    <g>
      <line class="cls-2" x1="264.72" y1="151.21" x2="267.22" y2="151.21"></line>
      <line class="cls-6" x1="272.2" y1="151.21" x2="657.89" y2="151.21"></line>
      <line class="cls-2" x1="660.38" y1="151.21" x2="662.88" y2="151.21"></line>
      <polygon points="265.89 155.2 258.98 151.21 265.89 147.22 265.89 155.2"></polygon>
    </g>
    <g>
      <line class="cls-2" x1="264.72" y1="239.06" x2="267.22" y2="239.06"></line>
      <line class="cls-6" x1="272.2" y1="239.06" x2="657.89" y2="239.06"></line>
      <line class="cls-2" x1="660.38" y1="239.06" x2="662.88" y2="239.06"></line>
      <polygon points="265.89 243.04 258.98 239.06 265.89 235.07 265.89 243.04"></polygon>
    </g>
    <g>
      <line class="cls-2" x1="264.72" y1="353.71" x2="267.22" y2="353.71"></line>
      <line class="cls-6" x1="272.2" y1="353.71" x2="657.89" y2="353.71"></line>
      <line class="cls-2" x1="660.38" y1="353.71" x2="662.88" y2="353.71"></line>
      <polygon points="265.89 357.7 258.98 353.71 265.89 349.72 265.89 357.7"></polygon>
    </g>
    <g>
      <line class="cls-2" x1="264.72" y1="470.67" x2="267.22" y2="470.67"></line>
      <line class="cls-6" x1="272.2" y1="470.67" x2="657.89" y2="470.67"></line>
      <line class="cls-2" x1="660.38" y1="470.67" x2="662.88" y2="470.67"></line>
      <polygon points="265.89 474.66 258.98 470.67 265.89 466.68 265.89 474.66"></polygon>
    </g>
    <g>
      <path class="cls-2" d="M258.98,536.3h66.78c11.02,0,19.95,8.93,19.95,19.95s-8.93,19.95-19.95,19.95h-59.6"></path>
      <polygon points="267.62 571.22 258.98 576.21 267.62 581.2 267.62 571.22"></polygon>
    </g>
    <rect class="cls-18" x="419.52" y="106.9" width="82.83" height="19.14"></rect>
    <rect class="cls-18" x="422.38" y="141.64" width="77.1" height="19.14"></rect>
    <rect class="cls-18" x="370.57" y="190.74" width="180.73" height="19.14"></rect>
    <rect class="cls-18" x="436.35" y="229.48" width="49.17" height="19.14"></rect>
    <rect class="cls-18" x="355.68" y="305.39" width="210.51" height="19.14"></rect>
    <rect class="cls-18" x="422.01" y="344.14" width="77.84" height="19.14"></rect>
    <rect class="cls-18" x="365.9" y="422.35" width="190.06" height="19.14"></rect>
    <rect class="cls-18" x="413.68" y="461.09" width="94.51" height="19.14"></rect>
    <text class="cls-12" transform="translate(423.91 120.69)"><tspan x="0" y="0">getSession</tspan></text>
    <text class="cls-12" transform="translate(429.85 155.43)"><tspan x="0" y="0">Isession*</tspan></text>
    <text class="cls-12" transform="translate(378.63 204.53)"><tspan x="0" y="0">get SUID using ISession*</tspan></text>
    <text class="cls-12" transform="translate(362.18 319.19)"><tspan x="0" y="0">get </tspan><tspan class="cls-17" x="24.98" y="0">A</tspan><tspan x="34.64" y="0">ttributes using ISession*</tspan></text>
    <text class="cls-12" transform="translate(370.61 436.14)"><tspan x="0" y="0">Sta</tspan><tspan class="cls-16" x="21.96" y="0">r</tspan><tspan x="27.4" y="0">t St</tspan><tspan class="cls-21" x="49.81" y="0">r</tspan><tspan class="cls-22" x="54.75" y="0">eaming using SUID</tspan></text>
    <text class="cls-12" transform="translate(444.66 243.28)"><tspan x="0" y="0">SUID</tspan></text>
    <text class="cls-12" transform="translate(428.21 357.93)"><tspan class="cls-13" x="0" y="0">A</tspan><tspan x="9.66" y="0">ttributes</tspan></text>
    <text class="cls-12" transform="translate(419.96 474.89)"><tspan x="0" y="0">sensor</tspan><tspan class="cls-9" x="45.32" y="0">E</tspan><tspan class="cls-1" x="53.66" y="0">v</tspan><tspan class="cls-22" x="60.83" y="0">ent</tspan></text>
    <text class="cls-12" transform="translate(144.24 539.7)"><tspan x="0" y="0">delete ISession*</tspan></text>
  </g>
</svg>

**Figure: Call flow to stream a specified sensor**

In this example, the client application can use different sensor sessions for the SUID query,
attribute query, and streaming activity. It can also use the same session for all the activities; however, synchronization must be handled
appropriately.
The client application can send various requests to the aDSP as follows.

1. **SUID query** retrieves SUIDs for the specified sensor:

    1. Create an interface for SUID by calling the `getSession()` API with the new `sessionFactory()` class. Requesting the SUID is the first and important request to get SUID of the requested data type for any use case.

/* Create a new ISession for UID discovery */
             sessionFactory* factory = new sessionFactory();
             if(nullptr == factory){
               printf("failed to create factory instance");
               return false;
             }
             ISession* suidSession = factory->getSession();
             if(nullptr == suidSession){
               printf("failed to create uid session");
               return false;
             }
            Copy to clipboard
    2. Open a created session interface by calling the `open()` API.

/* Open the suidSession */
              int ret = suidSession->open();
              if(-1 == ret){
                printf("failed to open ISession for uid query");
                return false;
              }
            Copy to clipboard
    3. Set callbacks by calling the `setCallBacks()` API and handling
the response, event, or error for the SUID activity.

/* Set callbacks for the session for 'uid' */
              ret = suidSession->setCallBacks(uid, suidResp, nullptr, suidEvent);
              if(-1 == ret)
                 printf("all callbacks are null, no need to register it");
            Copy to clipboard
    4. Create and send a Pb-encoded request message for SUID of a specified
data type by calling the `sendRequest()` API.

/*
               * Create SUID request message
               * (Please refer sns_client.proto and sns_suid.proto for more details)
               * */
              string pb_req_encoded = "";
              sns_suid_req pb_suid_req;
              pb_suid_req.set_data_type(sensorName);
              pb_suid_req.set_register_updates(true);
            sns_client_request_msg pb_req_msg;
            pb_req_msg.set_msg_id(SNS_SUID_MSGID_SNS_SUID_REQ);
            ..
            string pb_req_msg_encoded;
              pb_req_msg.SerializeToString(&pb_req_msg_encoded);
              /* send proto encoded message to sensing-hub using the opened session */
              unique_lock<mutex> respLock(respMutex);
              ret = suidSession->sendRequest(uid, pb_req_msg_encoded);
              if(0 != ret){
                printf("Error in sending uid discovery request");
                return false;
              }
            Copy to clipboard
    5. Close the session by calling the `close()` API and delete it
after the SUID events for the requested data type are received.

/* Close and delete the session once SUIDs are received */
              suidSession->close();
              delete suidSession;
              delete factory;
            Copy to clipboard
2. **Attribute request** retrieves attributes for the specified sensor:

    1. Create an interface session for an attribute by calling
`getSession()` with the new `sessionFactory()` class.
Requesting the attributes is important to get the capabilities of
the requested data type for any use case.

/* Create a new ISession for attribute query */
              sessionFactory* factory = new sessionFactory();
              if(nullptr == factory){
                printf("failed to create factory instance");
                return false;
              }
            
               ISession* attributeSession = factory->getSession();
              if(nullptr == attributeSession){
                printf("failed to create attribute session");
                return false;
              }
            Copy to clipboard
    2. Open a created session interface by calling the `open()` API.

/* open the attributeSession session */
              int ret = attributeSession->open();
              if(-1 == ret){
                printf("failed to open ISession for attribute query");
                return false;
            Copy to clipboard
    3. Set callbacks by calling `setCallBacks()` and handling the
response, event, or error for the attribute activity.

for (const suid& uid : suidList) {
                /* set callbacks for the session for 'uid' */
                int ret = attributeSession->setCallBacks(uid, attributeResp, nullptr, attributeEvent);
                if(-1 == ret)
                     printf("all callbacks are null, no need to register it");
            Copy to clipboard
    4. Create and send a Pb-encoded configuration request for an
attribute of a specified data type by calling the `sendRequest()`
API.

/* create pb-encoded config request message to be sent for attribute query */
                sns_client_request_msg pb_req_msg;
                pb_req_msg.set_msg_id(SNS_STD_MSGID_SNS_STD_ATTR_REQ);
                pb_req_msg.mutable_request()->clear_payload();
                pb_req_msg.mutable_suid()->set_suid_high(uid.high);
            ..
            ..
            /* send proto encoded message to sensing-hub using the opened session */
                unique_lock<mutex> respLock(respMutex);
                ret = attributeSession->sendRequest(uid, pb_req_msg_encoded);
            Copy to clipboard
    5. Close the session by calling the `close()` API after the
attribute events for the requested data type is received.

/* close and delete the session once all attributes are received */
              attributeSession->close();
              delete attributeSession;
              delete factory;
            Copy to clipboard
3. **Sensor streaming** streams the sensor and receives the data events:

    1. Create an interface session for streaming the sensor by calling
`getSession()` with the new `sessionFactory()` class.
Here, requesting sensor data is the final stage of a requested
data type for any use case.

sessionFactory()class.
            
            /* create a new ISession for streaming activity */
              sessionFactory* factory = new sessionFactory();
              if(nullptr == factory){
                printf("failed to create factory instance");
                return false;
              }
              ISession* streamingSession = factory->getSession();
              if(nullptr == streamingSession){
                printf("failed to create streaming session");
                return false;
              }
            Copy to clipboard
    2. Open a created session interface by calling the `open()` API.

/* open the streamingSession session */
            int ret = streamingSession->open();
            if(-1 == ret){
              printf("failed to open ISession for attribute query");
              return false;
            Copy to clipboard
    3. Set callbacks by calling `setCallBacks()` and handling the
response, event, or error for streaming the activity.

for (const suid& uid : suidList){
                /* set callbacks for the session for 'uid' */
                int ret = streamingSession->setCallBacks(uid, dataResp, dataError, dataEvent);
                if(-1 == ret)
                  printf("all callbacks are null, no need to register it");
            Copy to clipboard
    4. Create and send a Pb-encoded configuration request for streaming
the sensor of a specified data type by calling the `sendRequest()`
API, which eventually allows the requested sensor.

/* create pb-encoded config request message to be sent for streaming request */
                string pb_req_encoded = "";
                sns_std_sensor_config pb_stream_cfg;
                pb_stream_cfg.set_sample_rate(sampleRate);
                pb_stream_cfg.SerializeToString(&pb_req_encoded);
                sns_client_request_msg pb_req_msg;
                pb_req_msg.mutable_request()->mutable_batching()->set_batch_period(batchPeriod);
                pb_req_msg.set_msg_id(SNS_STD_SENSOR_MSGID_SNS_STD_SENSOR_CONFIG);
            ..
            ..
            /* send proto encoded message to sensing-hub using the opened session */
                unique_lock<mutex> respLock(respMutex);
                ret = streamingSession->sendRequest(uid, pb_req_msg_encoded);
            Copy to clipboard
    5. Handle samples in the event callbacks and wait for the specified
duration of the test.

void handle_event_cb(const uint8_t *data, size_t size, uint64_t time_stamp){
            if(true == deletion_started){
            printf("\nEvent coming when deletion of qmi connection started");
            return;
            }
            sns_client_event_msg pb_event_msg;
            /* Parse the pb encoded event */
            pb_event_msg.ParseFromArray(data, size);
            /* Iterate over all events in the message */
            for (int i = 0; i < pb_event_msg.events_size(); i++) {
            auto& pb_event = pb_event_msg.events(i);
            Copy to clipboard
4. **Stop sensor streaming** client stops streaming by sending a disable request:

    1. Call the `sendRequest()` API.

pb_req_msg.set_msg_id(SNS_CLIENT_MSGID_SNS_CLIENT_DISABLE_REQ);
                pb_req_msg.mutable_suid()->set_suid_high(uid.high);
                pb_req_msg.mutable_suid()->set_suid_low(uid.low);
            ..
            ..
            /* send disable request to sensing-hub */
                int ret = streamingSession->sendRequest(uid, pb_req_msg_encoded);
            Copy to clipboard
    2. Close the session by calling the `close()` API after the
streaming events for the requested data type is received.

/* close and delete the streamingSession */
              streamingSession->close();
              delete streamingSession;
              delete factory;
            Copy to clipboard

The following snippet shows the `SessionClient` sample application
output. It allows an accelerometer sensor with 10 Hz sample rate and a
2-second batch period for 10 sec and prints the received sensor events.

[root@qcm6490](mailto:root&#37;&#52;&#48;qcm6490):~# SessionClient
Streaming configuration is as follows :

> 
> 
> Sensor name : accel     Sample rate : 10 Hz     Batch period : 2 sec    Test duration : 10 sec

SUID discovery response received.
Received SUIDs for accel, number of SUIDs received = 1

SUID received - suid\_low=6360260105974108950 suid\_high=7037810611998542250
Sensor suid list created

requesting attributes for - suid\_low=6360260105974108950 suid\_high=7037810611998542250

Attribute query response received.
Attributes for - suid\_low=6360260105974108950 suid\_high=7037810611998542250 are:
attribute count 0        and values are: attr\_id: 16     sint: 0
attribute count 1        and values are: attr\_id: 9      sint: 50sint: 240sint: 240
attribute count 2        and values are: attr\_id: 12     std: LPM std: NORMAL std: HIGH\_PERF
attribute count 3        and values are: attr\_id: 5      std: sns\_accel.proto
attribute count 4        and values are: attr\_id: 0      std: icm4x6xx
attribute count 5        and values are: attr\_id: 1      std: TDK-Invensense
attribute count 6        and values are: attr\_id: 26     boolean 1
attribute count 7        and values are: attr\_id: 17     boolean 0
attribute count 8        and values are: attr\_id: 10     sint: 6
attribute count 9        and values are: attr\_id: 15     sint: 16
attribute count 10       and values are: attr\_id: 21     boolean 1
attribute count 11       and values are: attr\_id: 22     sint: 3sint: 2sint: 1
attribute count 12       and values are: attr\_id: 2      std: accel
attribute count 13       and values are: attr\_id: 4      sint: 82179
attribute count 14       and values are: attr\_id: 13     boolean 1
attribute count 15       and values are: attr\_id: 14     boolean 0
attribute count 16       and values are: attr\_id: 18     sint: 0
attribute count 17       and values are: attr\_id: 20     flt: 0.000000  flt: 0.000000   flt: 0.000000   flt: 0.000000   flt: 0.000000   flt: 0.000000flt: 0.000000    flt: 0.000000   flt: 0.000000   flt: 0.000000   flt: 0.000000   flt: 0.000000
attribute count 18       and values are: attr\_id: 19     sint: 0
attribute count 19       and values are: attr\_id: 11
attribute count 20       and values are: attr\_id: 7      flt: 0.000019  flt: 0.000037   flt: 0.000075   flt: 0.000150   flt: 0.000299
attribute count 21       and values are: attr\_id: 24
attribute count 22       and values are: attr\_id: 23     flt: 0.000299
attribute count 23       and values are: attr\_id: 6      flt: 12.500000 flt: 25.000000  flt: 50.000000  flt: 100.000000 flt: 200.000000 flt: 500.000000
attribute count 24       and values are: attr\_id: 25     flt: 1000.000000       flt: 2000.000000
attribute count 25       and values are: attr\_id: 8      sint: 80
attribute count 26       and values are: attr\_id: 3      boolean 1

Attributes for all SUIDs received

Streaming started
sending request for - suid\_low=6360260105974108950 suid\_high=7037810611998542250
Data request response received.
Received re-configuration event
Cal event packet received
Received Samples:       [0.347159],     [-0.181959],    [9.450213],
Received Samples:       [0.102951],     [-0.183156],    [9.545981],
Received Samples:       [0.096965],     [-0.189142],    [9.550770],
Received Samples:       [0.092177],     [-0.192733],    [9.541193],
Received Samples:       [0.090980],     [-0.183156],    [9.555558],
Received Samples:       [0.093374],     [-0.185551],    [9.555558],
Received Samples:       [0.108936],     [-0.184354],    [9.541193],
Received Samples:       [0.098162],     [-0.185551],    [9.565135],
Received Samples:       [0.095768],     [-0.185551],    [9.550770],
Received Samples:       [0.100556],     [-0.193930],    [9.550770],
Received Samples:       [0.092177],     [-0.186748],    [9.550770],
Received Samples:       [0.094571],     [-0.199916],    [9.541193],
Received Samples:       [0.105345],     [-0.199916],    [9.550770],
Received Samples:       [0.098162],     [-0.185551],    [9.550770],

For troubleshooting common issues, see [Troubleshoot sensors](https://docs.qualcomm.com/doc/80-70020-7/topic/test_troubleshoot.html#debug).

For more information, see
[QSH direct channel API workflow](https://docs.qualcomm.com/bundle/resource/topics/80-70020-7A/develop_and_integrate.html#qsh_direct_channel_api_workflow)
in [Qualcomm Linux Sensors Guide -
Addendum](https://docs.qualcomm.com/bundle/resource/topics/80-70020-7A/overview.html). This information is available to licensed users with authorized access.

## Configure sensors

This information is available to licensed users with authorized access. For more
information, see
[Configure sensors](https://docs.qualcomm.com/bundle/resource/topics/80-70020-7A/configuration_customization.html)
in [Qualcomm Linux Sensors Guide -
Addendum](https://docs.qualcomm.com/bundle/resource/topics/80-70020-7A/overview.html).

## Develop and integrate sensor drivers

This information is available to licensed users with authorized access. For more
information, see
[Develop and integrate sensor drivers](https://docs.qualcomm.com/bundle/resource/topics/80-70020-7A/develop_and_integrate.html#develop-and-integrate-sensor-drivers)
in [Qualcomm Linux Sensors Guide -
Addendum](https://docs.qualcomm.com/bundle/resource/topics/80-70020-7A/overview.html).

## Develop and integrate custom sensor algorithms

This information is available to licensed users with authorized access. For more
information, see
[Develop and integrate custom sensor algorithms](https://docs.qualcomm.com/bundle/resource/topics/80-70020-7A/develop_and_integrate.html#developing_custom_algorithm_and_integrating_with_qsh)
in [Qualcomm Linux Sensors Guide -
Addendum](https://docs.qualcomm.com/bundle/resource/topics/80-70020-7A/overview.html).

## Calibrate sensors

Sensors that are sensitive to changes in the operating environment
produce inappropriate output values due to factors, such as temperature
variations, mechanical wear, or shift in the operating range. Sensor calibration allows to do the following:

- Adjust or fine-tune the sensor hardware to ensure accuracy and minimize the errors.
- Compare the expected output based on the theoretical models or standards with the actual measured output from the sensor.
- Enhance performance, accuracy, and reliability, which ensures that the sensor provides reliable data.

On successful calibration and the associated registry update (as described
in the following sections), the value of `ver` registry item increments.
For example, if the bias offset in registry item has `ver` value of 0,
then on a successful calibration and registry update, the registry item
is updated with the new bias offset and the `ver` value increments to 1.

Note

The `<registry_path>` referred in the following sections should be considered as one of the existing paths on the device: `/etc/sensors/registry/registry/` or `/var/cache/sensors/registry/registry/`.

### Perform factory sensor calibration

The factory sensor calibration is a process to adjust or fine-tune the sensors during the manufacturing phase.

#### Accelerometer factory calibration

The following table lists the accelerometer calibration procedure:

Table : Accelerometer calibration

| Command | Procedure | Bias values |
| --- | --- | --- |
| ssc_drva_test -sensor=accel -factory_test=2 -duration=10<br>    Copy to clipboard<br><br><br>Note<br><br><br>A test result (PASS or FAIL) indicates only the test execution status whether the test is completed or not. | Run the command while keeping the device stationary on a flat surface. | The following is the example of the QCS6490 device (ICM42688 sensor):<br>The `<registry_path>/qcs6490_rbx_icm4x6xx_0.json.icm4x6xx_0_platform.accel.fac_cal.bias`<br>file is created/updated automatically, and stores the bias offset after the calibration. |

#### Magnetometer factory calibration

The following table lists the magnetometer calibration procedure:

Table : Magnetometer calibration

| Command | Procedure | Bias values |
| --- | --- | --- |
| N.A. | <ol class="arabic simple"><br><li><p>Get <cite>/calculate corr_matrix</cite> and <cite>bias scale</cite> values (if applicable) for your device with the help of the sensor vendor.</p></li><br><li><p>Set these values in the <code class="docutils literal notranslate"><span class="pre">corr_matrix</span></code> section of the sensor’s platform-specific magnetometer JSON file.</p></li><br></ol> | The following is an example of the QCS6490 device (AK09915 sensor):<br><br><br>The `<registry_path>/qcs6490_rbx_navmez_ak991x_0.json.ak0991x_0_platform.mag.fac_cal.corr_mat` file is created/updated automatically, and stores the bias offset after the calibration. |

#### Proximity factory calibration

The following table lists the proximity calibration procedure:

Table : Proximity calibration

| Command | Procedure | Bias values |
| --- | --- | --- |
| ssc_drva_test -sensor=prox -factory_test=2 -duration=10<br>    Copy to clipboard | 1 Keep an obstacle/object at a required distance (for example, 5 cm or as mentioned in the specification) from the proximity sensor and run the command.<br><br><br>2 Verify that the test returns a PASS result.<br><br><br>3 This procedure uses 5 cm as the threshold and the distance within the threshold is considered as near and the distance more than the threshold is considered as far. | The following is an example of the TMD3702 sensor:<br><br><br>The `<registry_path>/tmd3702_platform.prox.fac_cal`<br>file is created/updated automatically, and stores the bias offset after the calibration. |

#### Ambient light factory calibration

The following table lists the ambient light calibration procedure:

Table : Ambient light calibration

| Command | Procedure | Bias values |
| --- | --- | --- |
| ssc_drva_test -sensor=als -factory_test=2 -duration=10<br>    Copy to clipboard | Confirm the test procedure specified by the sensor vendor and run the command. | The following is an example of the TMD3702 sensor: The<br><br><br>`<registry_path>/tmd3702_platform.als.fac_cal`<br>file is created/updated automatically, and stores the bias offset after the calibration. |

### Perform runtime sensor calibration

Runtime sensor calibration adjusts or fine-tunes the
sensors during their operational phase, rather than during the
manufacturing phase. It occurs dynamically while the sensor actively
collects the data in the real-world scenarios.

#### Gyroscope runtime calibration

The gyroscope calibration sensor `gyro_cal` is used for gyroscope
runtime calibration. The following table lists the gyroscope calibration
procedure:

Table : Gyroscope calibration

| Command | Procedure | Bias values |
| --- | --- | --- |
| Use `see_workhorse` to enable a gyroscope calibration sensor (`gyro_cal`).<br><br><br>see_workhorse -sensor=gyro_cal -on_change=1 -duration=120 -display_events=1<br>    Copy to clipboard | <ul class="simple"><br><li><p>While keeping the device stationary, request the gyroscope calibration sensor <code class="docutils literal notranslate"><span class="pre">gyro_cal</span></code> data for more than 120 sec and then stop.</p></li><br><li><p>After the command is executed, check the status field in the received event for the calibration accuracy status.</p></li><br></ul><br><br>Note<br><br><br>The gyroscope sensor always produces noncalibrated values. Hence, for the client/algorithm that needs the calibrated gyroscope values run the `gyro_cal` sensor to generate and provide calibration offset/bias. The bias received from the `gyro_cal` sensor can then be subtracted as shown in the following pseudocode:<br><br><br>calibrated_gyro_x_val = (gyro_data.x_val - gyro_cal.x_bias);<br>    Copy to clipboard<br><br><br>calibrated_gyro_y_val = (gyro_data.y_val - gyro_cal.y_bias);<br>    Copy to clipboard<br><br><br>calibrated_gyro_z_val = (gyro_data.z_val - gyro_cal.z_bias);<br>    Copy to clipboard | The `<registry_path>/sns_gyro_cal_persist_sX.bias` file (where, X = sensor index) is created/updated automatically, and stores the bias offset after the calibration:<br><br><br>Note<br><br><br>Gyroscope calibration runs approximately for every 60sec. The gyroscope bias is stored into the registry only after the existing streaming clients for the gyroscope are disabled. |

#### Magnetometer runtime calibration

The magnetometer calibration sensor `mag_cal` is used for the
magnetometer runtime calibration. The following table lists the
magnetometer calibration procedure:

Table : Magnetometer calibration

| Command | Procedure | Bias values |
| --- | --- | --- |
| Use `see_workhorse` to enable the magnetometer calibration sensor `mag_cal`.<br><br><br>see_workhorse -sensor=mag_cal -on_change=1 -duration=500 -display_events=1<br>    Copy to clipboard | <ul class="simple"><br><li><p>Bring the device to an open area where there is no magnetic field interference.</p></li><br><li><p>Stream the magnetometer data and move the device in motion <strong>8</strong> for more than 60sec. Moving the device in motion <strong>8</strong> is mandatory.</p></li><br><li><p>After the command is executed, check the status field in the received event for the calibration accuracy status.</p></li><br></ul> | The `<registry_path>/sns_mag_cal_persist_sXmY.bias` file (where, X = sensor index and Y = device mode index) is created/updated automatically, and stores the bias offset after the calibration. |

Last Published: Jun 26, 2025

[Previous Topic
Bring up sensors](https://docs.qualcomm.com/bundle/publicresource/80-70020-7/topics/bringup_sensors.md) [Next Topic
Test and troubleshoot](https://docs.qualcomm.com/bundle/publicresource/80-70020-7/topics/test_troubleshoot.md)