/usr/share/qt5/doc/qtbluetooth/qtbluetooth-le-overview.html is in qtconnectivity5-doc-html 5.7.1~20161021-2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 | <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<!-- bluetooth-le-overview.qdoc -->
<title>Bluetooth Low Energy Overview | Qt Bluetooth 5.7</title>
<link rel="stylesheet" type="text/css" href="style/offline-simple.css" />
<script type="text/javascript">
window.onload = function(){document.getElementsByTagName("link").item(0).setAttribute("href", "style/offline.css");};
</script>
</head>
<body>
<div class="header" id="qtdocheader">
<div class="main">
<div class="main-rounded">
<div class="navigationbar">
<table><tr>
<td >Qt 5.7</td><td ><a href="qtbluetooth-index.html">Qt Bluetooth</a></td><td >Bluetooth Low Energy Overview</td></tr></table><table class="buildversion"><tr>
<td id="buildversion" width="100%" align="right">Qt 5.7.1 Reference Documentation</td>
</tr></table>
</div>
</div>
<div class="content">
<div class="line">
<div class="content mainContent">
<div class="sidebar">
<div class="toc">
<h3><a name="toc">Contents</a></h3>
<ul>
<li class="level1"><a href="#what-is-bluetooth-low-energy">What Is Bluetooth Low Energy</a></li>
<li class="level1"><a href="#basic-service-structure">Basic Service Structure</a></li>
<li class="level2"><a href="#att-protocol">ATT Protocol</a></li>
<li class="level2"><a href="#gatt-profile">GATT Profile</a></li>
<li class="level1"><a href="#using-qt-bluetooth-low-energy-api">Using Qt Bluetooth Low Energy API</a></li>
<li class="level2"><a href="#establishing-a-connection">Establishing a Connection</a></li>
<li class="level2"><a href="#service-search">Service Search</a></li>
<li class="level2"><a href="#interaction-with-the-peripheral-device">Interaction with the Peripheral Device</a></li>
<li class="level2"><a href="#advertising-services">Advertising Services</a></li>
<li class="level2"><a href="#implementing-a-service-on-the-peripheral-device">Implementing a Service on the Peripheral Device</a></li>
</ul>
</div>
<div class="sidebar-content" id="sidebar-content"></div></div>
<h1 class="title">Bluetooth Low Energy Overview</h1>
<span class="subtitle"></span>
<!-- $$$qtbluetooth-le-overview.html-description -->
<div class="descr"> <a name="details"></a>
<p>The Qt Bluetooth Low Energy API for the central role was introduced by Qt 5.4. Since Qt 5.5 that part of the API is final and a compatibility guarantee is given for future releases. In Qt 5.7, additional API supporting the peripheral role was added as a Technology Preview, with the backend only implemented for Linux/BlueZ.</p>
<a name="what-is-bluetooth-low-energy"></a>
<h2 id="what-is-bluetooth-low-energy">What Is Bluetooth Low Energy</h2>
<p>Bluetooth Low Energy, also known as Bluetooth Smart, is a wireless computer network technology, which was officially introduced in 2011. It works on the same 2.4 GHz frequency as ”classic” Bluetooth. The main difference is, as stated by its technology name, low energy consumption. It provides an opportunity for Bluetooth Low Energy devices to operate for months, even years, on coin-cell batteries. The technology was introduced by <a href="https://www.bluetooth.org/en-us/specification/adopted-specifications">Bluetooth v4.0</a>. Devices which support this technology are called Bluetooth Smart Ready Devices. The key features of the technology are:</p>
<ul>
<li>Ultra-low peak, average and idle mode power consumption</li>
<li>Ability to run for years on standard, coin-cell batteries</li>
<li>Low cost</li>
<li>Multi-vendor interoperability</li>
<li>Enhanced range</li>
</ul>
<p>Bluetooth Low Energy uses a client-server architecture. The server (also known as peripheral) offers services such as temperature or heart rate and advertises them. The client (known as central device) connects to the server and reads the values advertised by the server. An example might be an apartment with Bluetooth Smart Ready sensors such as a thermostat, humidity or pressure sensor. Those sensors are peripheral devices advertising the environment values of the apartment. At the same time a mobile phone or computer might connect to those sensors, retrieve their values and present them as part of a larger environment control application to the user.</p>
<a name="basic-service-structure"></a>
<h2 id="basic-service-structure">Basic Service Structure</h2>
<p>Bluetooth Low Energy is based on two protocols: ATT (Attribute Protocol) and GATT (Generic Attribute Profile). They specify the communication layers used by every Bluetooth Smart Ready device.</p>
<a name="att-protocol"></a>
<h3 >ATT Protocol</h3>
<p>The basic building block of ATT is an <i>attribute</i>. Each attribute consists of three elements:</p>
<ul>
<li>a value - the payload or desirable piece of information</li>
<li>a UUID - the type of attribute (used by GATT)</li>
<li>a 16-bit handle - a unique identifier for the attribute</li>
</ul>
<p>The server stores the attributes and the client uses the ATT protocol to read and write values on the server.</p>
<a name="gatt-profile"></a>
<h3 >GATT Profile</h3>
<p>GATT defines grouping for a set of attributes by applying a meaning to predefined UUIDs. The table below shows an example service exposing a heart rate on a particular day. The actual values are stored inside the two characteristics:</p>
<div class="table"><table class="generic">
<thead><tr class="qt-style"><th >Handle</th><th >UUID</th><th >Value</th><th >Description</th></tr></thead>
<tr valign="top" class="odd"><td >0x0001</td><td >0x2800</td><td >UUID 0x180D</td><td >Begin Heart Rate service</td></tr>
<tr valign="top" class="even"><td >0x0002</td><td >0x2803</td><td >UUID 0x2A37, Value handle: 0x0003</td><td >Characteristic of type <i>Heart Rate Measurement (HRM)</i></td></tr>
<tr valign="top" class="odd"><td >0x0003</td><td >0x2A37</td><td >65 bpm</td><td >Heart rate value</td></tr>
<tr valign="top" class="even"><td >0x0004</td><td >0x2803</td><td >UUID 0x2A08, Value handle: 0x0006</td><td >Characteristic of type Date Time</td></tr>
<tr valign="top" class="odd"><td >0x0005</td><td >0x2A08</td><td >18/08/2014 11:00</td><td >Date and Time of the measurement</td></tr>
<tr valign="top" class="even"><td >0x0006</td><td >0x2800</td><td >UUID xxxxxx</td><td >Begin next service</td></tr>
<tr valign="top" class="odd"><td >...</td><td >...</td><td >...</td><td >...</td></tr>
</table></div>
<p>GATT specifies that the above used UUID <code>0x2800</code> marks the begin of a service definition. Every attribute following <code>0x2800</code> is part of the service until the next <code>0x2800</code> or the end is encountered. In similar ways the well known UUID <code>0x2803</code> states that a characteristic is to be found and each of the characteristics has a type defining the nature of the value. The example above uses the UUIDs <code>0x2A08</code> (Date Time) and <code>0x2A37</code> (Heart Rate Measurement). Each of the above UUIDs is defined by the <a href="https://bluetooth.org">Bluetooth Special Interest Group</a>. and can be found in the <a href="https://developer.bluetooth.org/gatt/Pages/default.aspx">GATT specification</a>. While it is advisable to use pre-defined UUIDs where available it is entirely possible to use new and not yet used UUIDs for characteristic and service types.</p>
<p>In general, each service may consist of one or more characteristics. A characteristic contains data and can be further described by descriptors, which provide additional information or means of manipulating the characteristic. All services, characteristics and descriptors are recognized by their 128-bit UUID. Finally, it is possible to include services inside of services (see picture below).</p>
<p class="centerAlign"><img src="images/peripheral-structure.png" alt="" /></p><a name="using-qt-bluetooth-low-energy-api"></a>
<h2 id="using-qt-bluetooth-low-energy-api">Using Qt Bluetooth Low Energy API</h2>
<p>This section describes how to use the Bluetooth Low Energy API provided by Qt. On the client side, the API permits creating connections to peripheral devices, discovering their services, as well as reading and writing data stored on the device. On the server side, it allows to set up services, advertise them, and get notified when the client writes characteristics. The example code below is taken from the <a href="qtbluetooth-heartlistener-example.html">Heart Listener</a> and <a href="qtbluetooth-heartrate-server-example.html">Heart Rate Server</a> examples.</p>
<a name="establishing-a-connection"></a>
<h3 >Establishing a Connection</h3>
<p>To be able to read and write the characteristics of the Bluetooth Low Energy peripheral device, it is necessary to find and connect the device. This requires the peripheral device to advertise its presence and services. We start the device discovery with the help of the <a href="qbluetoothdevicediscoveryagent.html">QBluetoothDeviceDiscoveryAgent</a> class. We connect to its <a href="qbluetoothdevicediscoveryagent.html#deviceDiscovered">QBluetoothDeviceDiscoveryAgent::deviceDiscovered</a>() signal and start the search with <a href="qbluetoothdevicediscoveryagent.html#start">start()</a>:</p>
<pre class="cpp">
m_deviceDiscoveryAgent <span class="operator">=</span> <span class="keyword">new</span> <span class="type">QBluetoothDeviceDiscoveryAgent</span>(<span class="keyword">this</span>);
connect(m_deviceDiscoveryAgent<span class="operator">,</span> SIGNAL(deviceDiscovered(<span class="keyword">const</span> <span class="type">QBluetoothDeviceInfo</span><span class="operator">&</span>))<span class="operator">,</span>
<span class="keyword">this</span><span class="operator">,</span> SLOT(addDevice(<span class="keyword">const</span> <span class="type">QBluetoothDeviceInfo</span><span class="operator">&</span>)));
connect(m_deviceDiscoveryAgent<span class="operator">,</span> SIGNAL(error(<span class="type">QBluetoothDeviceDiscoveryAgent</span><span class="operator">::</span>Error))<span class="operator">,</span>
<span class="keyword">this</span><span class="operator">,</span> SLOT(deviceScanError(<span class="type">QBluetoothDeviceDiscoveryAgent</span><span class="operator">::</span>Error)));
connect(m_deviceDiscoveryAgent<span class="operator">,</span> SIGNAL(finished())<span class="operator">,</span> <span class="keyword">this</span><span class="operator">,</span> SLOT(scanFinished()));
m_deviceDiscoveryAgent<span class="operator">-</span><span class="operator">></span>start();
</pre>
<p>Since we are only interested in Low Energy devices we filter the device type within the receiving slot. The device type can be ascertained using the <a href="qbluetoothdeviceinfo.html#coreConfigurations">QBluetoothDeviceInfo::coreConfigurations</a>() flag:</p>
<pre class="cpp">
<span class="type">void</span> HeartRate<span class="operator">::</span>addDevice(<span class="keyword">const</span> <span class="type">QBluetoothDeviceInfo</span> <span class="operator">&</span>device)
{
<span class="keyword">if</span> (device<span class="operator">.</span>coreConfigurations() <span class="operator">&</span> <span class="type">QBluetoothDeviceInfo</span><span class="operator">::</span>LowEnergyCoreConfiguration) {
<a href="../qtcore/qtglobal.html#qWarning">qWarning</a>() <span class="operator"><</span><span class="operator"><</span> <span class="string">"Discovered LE Device name: "</span> <span class="operator"><</span><span class="operator"><</span> device<span class="operator">.</span>name() <span class="operator"><</span><span class="operator"><</span> <span class="string">" Address: "</span>
<span class="operator"><</span><span class="operator"><</span> device<span class="operator">.</span>address()<span class="operator">.</span>toString();
}
<span class="comment">//...</span>
}
</pre>
<p>Once the address of the peripheral device is known we use the <a href="qlowenergycontroller.html">QLowEnergyController</a> class. This class is the entry point for all Bluetooth Low Energy development. The constructor of the class accepts the remote device's <a href="qbluetoothaddress.html">QBluetoothAddress</a>. Finally we set up the customary slots and directly connect to the device using <a href="qlowenergycontroller.html#connectToDevice">connectToDevice()</a>:</p>
<pre class="cpp">
m_control <span class="operator">=</span> <span class="keyword">new</span> <span class="type">QLowEnergyController</span>(m_currentDevice<span class="operator">.</span>getDevice()<span class="operator">,</span> <span class="keyword">this</span>);
connect(m_control<span class="operator">,</span> SIGNAL(serviceDiscovered(<span class="type">QBluetoothUuid</span>))<span class="operator">,</span>
<span class="keyword">this</span><span class="operator">,</span> SLOT(serviceDiscovered(<span class="type">QBluetoothUuid</span>)));
connect(m_control<span class="operator">,</span> SIGNAL(discoveryFinished())<span class="operator">,</span>
<span class="keyword">this</span><span class="operator">,</span> SLOT(serviceScanDone()));
connect(m_control<span class="operator">,</span> SIGNAL(error(<span class="type">QLowEnergyController</span><span class="operator">::</span>Error))<span class="operator">,</span>
<span class="keyword">this</span><span class="operator">,</span> SLOT(controllerError(<span class="type">QLowEnergyController</span><span class="operator">::</span>Error)));
connect(m_control<span class="operator">,</span> SIGNAL(connected())<span class="operator">,</span>
<span class="keyword">this</span><span class="operator">,</span> SLOT(deviceConnected()));
connect(m_control<span class="operator">,</span> SIGNAL(disconnected())<span class="operator">,</span>
<span class="keyword">this</span><span class="operator">,</span> SLOT(deviceDisconnected()));
m_control<span class="operator">-</span><span class="operator">></span>connectToDevice();
</pre>
<a name="service-search"></a>
<h3 >Service Search</h3>
<p>As soon as the connection is established we initiate the service discovery:</p>
<pre class="cpp">
<span class="type">void</span> HeartRate<span class="operator">::</span>deviceConnected()
{
m_control<span class="operator">-</span><span class="operator">></span>discoverServices();
}
<span class="type">void</span> HeartRate<span class="operator">::</span>deviceDisconnected()
{
setMessage(<span class="string">"Heart Rate service disconnected"</span>);
<a href="../qtcore/qtglobal.html#qWarning">qWarning</a>() <span class="operator"><</span><span class="operator"><</span> <span class="string">"Remote device disconnected"</span>;
}
</pre>
<p>The <code>serviceDiscovered()</code> slot below is triggered as a result of the <a href="qlowenergycontroller.html#serviceDiscovered">QLowEnergyController::serviceDiscovered</a>() signal and provides an intermittent progress report. Since we are talking about the heart listener app which monitors HeartRate devices in the vicinity we ignore any service that is not of type <a href="qbluetoothuuid.html#ServiceClassUuid-enum">QBluetoothUuid::HeartRate</a>.</p>
<pre class="cpp">
<span class="type">void</span> HeartRate<span class="operator">::</span>serviceDiscovered(<span class="keyword">const</span> <span class="type">QBluetoothUuid</span> <span class="operator">&</span>gatt)
{
<span class="keyword">if</span> (gatt <span class="operator">=</span><span class="operator">=</span> <span class="type">QBluetoothUuid</span>(<span class="type">QBluetoothUuid</span><span class="operator">::</span>HeartRate)) {
setMessage(<span class="string">"Heart Rate service discovered. Waiting for service scan to be done..."</span>);
foundHeartRateService <span class="operator">=</span> <span class="keyword">true</span>;
}
}
</pre>
<p>Eventually the <a href="qlowenergycontroller.html#discoveryFinished">QLowEnergyController::discoveryFinished</a>() signal is emitted to indicate the successful completion of the service discovery. Provided a HeartRate service was found, a <a href="qlowenergyservice.html">QLowEnergyService</a> instance is created to represent the service. The returned service object provides the required signals for update notifications and the discovery of service details is triggered using <a href="qlowenergyservice.html#discoverDetails">QLowEnergyService::discoverDetails</a>():</p>
<pre class="cpp">
<span class="keyword">if</span> (foundHeartRateService) {
setMessage(<span class="string">"Connecting to service..."</span>);
m_service <span class="operator">=</span> m_control<span class="operator">-</span><span class="operator">></span>createServiceObject(
<span class="type">QBluetoothUuid</span>(<span class="type">QBluetoothUuid</span><span class="operator">::</span>HeartRate)<span class="operator">,</span> <span class="keyword">this</span>);
}
<span class="keyword">if</span> (<span class="operator">!</span>m_service) {
setMessage(<span class="string">"Heart Rate Service not found."</span>);
<span class="keyword">return</span>;
}
connect(m_service<span class="operator">,</span> SIGNAL(stateChanged(<span class="type">QLowEnergyService</span><span class="operator">::</span>ServiceState))<span class="operator">,</span>
<span class="keyword">this</span><span class="operator">,</span> SLOT(serviceStateChanged(<span class="type">QLowEnergyService</span><span class="operator">::</span>ServiceState)));
connect(m_service<span class="operator">,</span> SIGNAL(characteristicChanged(<span class="type">QLowEnergyCharacteristic</span><span class="operator">,</span><span class="type">QByteArray</span>))<span class="operator">,</span>
<span class="keyword">this</span><span class="operator">,</span> SLOT(updateHeartRateValue(<span class="type">QLowEnergyCharacteristic</span><span class="operator">,</span><span class="type">QByteArray</span>)));
connect(m_service<span class="operator">,</span> SIGNAL(descriptorWritten(<span class="type">QLowEnergyDescriptor</span><span class="operator">,</span><span class="type">QByteArray</span>))<span class="operator">,</span>
<span class="keyword">this</span><span class="operator">,</span> SLOT(confirmedDescriptorWrite(<span class="type">QLowEnergyDescriptor</span><span class="operator">,</span><span class="type">QByteArray</span>)));
m_service<span class="operator">-</span><span class="operator">></span>discoverDetails();
</pre>
<p>During the detail search the service's <a href="qlowenergyservice.html#state">state()</a> transitions from <a href="qlowenergyservice.html#ServiceState-enum">DiscoveryRequired</a> to <a href="qlowenergyservice.html#ServiceState-enum">DiscoveringServices</a> and eventually ends with <a href="qlowenergyservice.html#ServiceState-enum">ServiceDiscovered</a>:</p>
<pre class="cpp">
<span class="type">void</span> HeartRate<span class="operator">::</span>serviceStateChanged(<span class="type">QLowEnergyService</span><span class="operator">::</span>ServiceState s)
{
<span class="keyword">switch</span> (s) {
<span class="keyword">case</span> <span class="type">QLowEnergyService</span><span class="operator">::</span>ServiceDiscovered:
{
<span class="keyword">const</span> <span class="type">QLowEnergyCharacteristic</span> hrChar <span class="operator">=</span> m_service<span class="operator">-</span><span class="operator">></span>characteristic(
<span class="type">QBluetoothUuid</span>(<span class="type">QBluetoothUuid</span><span class="operator">::</span>HeartRateMeasurement));
<span class="keyword">if</span> (<span class="operator">!</span>hrChar<span class="operator">.</span>isValid()) {
setMessage(<span class="string">"HR Data not found."</span>);
<span class="keyword">break</span>;
}
m_notificationDesc <span class="operator">=</span> hrChar<span class="operator">.</span>descriptor(
<span class="type">QBluetoothUuid</span><span class="operator">::</span>ClientCharacteristicConfiguration);
<span class="keyword">if</span> (m_notificationDesc<span class="operator">.</span>isValid()) {
m_service<span class="operator">-</span><span class="operator">></span>writeDescriptor(m_notificationDesc<span class="operator">,</span> <span class="type">QByteArray</span><span class="operator">::</span>fromHex(<span class="string">"0100"</span>));
setMessage(<span class="string">"Measuring"</span>);
m_start <span class="operator">=</span> <span class="type">QDateTime</span><span class="operator">::</span>currentDateTime();
}
<span class="keyword">break</span>;
}
<span class="keyword">default</span>:
<span class="comment">//nothing for now</span>
<span class="keyword">break</span>;
}
}
</pre>
<a name="interaction-with-the-peripheral-device"></a>
<h3 >Interaction with the Peripheral Device</h3>
<p>In the code example above, the desired characteristic is of type <a href="qbluetoothuuid.html#CharacteristicType-enum">HeartRateMeasurement</a>. Since the application measures the heart rate changes, it must enable change notifications for the characteristic. Note that not all characteristics provide change notifications. Since the HeartRate characteristic has been standardized it is possible to assume that notifications can be received. Ultimately <a href="qlowenergycharacteristic.html#properties">QLowEnergyCharacteristic::properties</a>() must have the <a href="qlowenergycharacteristic.html#PropertyType-enum">QLowEnergyCharacteristic::Notify</a> flag set and a descriptor of type <a href="qbluetoothuuid.html#DescriptorType-enum">QBluetoothUuid::ClientCharacteristicConfiguration</a> must exist to confirm the availability of an appropriate notification.</p>
<p>Finally, we process the value of the HeartRate characteristic, as per Bluetooth Low Energy standard:</p>
<pre class="cpp">
<span class="type">void</span> HeartRate<span class="operator">::</span>updateHeartRateValue(<span class="keyword">const</span> <span class="type">QLowEnergyCharacteristic</span> <span class="operator">&</span>c<span class="operator">,</span>
<span class="keyword">const</span> <span class="type">QByteArray</span> <span class="operator">&</span>value)
{
<span class="comment">// ignore any other characteristic change -> shouldn't really happen though</span>
<span class="keyword">if</span> (c<span class="operator">.</span>uuid() <span class="operator">!</span><span class="operator">=</span> <span class="type">QBluetoothUuid</span>(<span class="type">QBluetoothUuid</span><span class="operator">::</span>HeartRateMeasurement))
<span class="keyword">return</span>;
<span class="keyword">const</span> <span class="type">quint8</span> <span class="operator">*</span>data <span class="operator">=</span> <span class="keyword">reinterpret_cast</span><span class="operator"><</span><span class="keyword">const</span> <span class="type">quint8</span> <span class="operator">*</span><span class="operator">></span>(value<span class="operator">.</span>constData());
<span class="type">quint8</span> flags <span class="operator">=</span> data<span class="operator">[</span><span class="number">0</span><span class="operator">]</span>;
<span class="comment">//Heart Rate</span>
<span class="keyword">if</span> (flags <span class="operator">&</span> <span class="number">0x1</span>) { <span class="comment">// HR 16 bit? otherwise 8 bit</span>
<span class="keyword">const</span> <span class="type">quint16</span> heartRate <span class="operator">=</span> <a href="../qtcore/qtendian.html#qFromLittleEndian">qFromLittleEndian</a><span class="operator"><</span><span class="type">quint16</span><span class="operator">></span>(data<span class="operator">[</span><span class="number">1</span><span class="operator">]</span>);
<span class="comment">//qDebug() << "16 bit HR value:" << heartRate;</span>
m_measurements<span class="operator">.</span>append(heartRate);
} <span class="keyword">else</span> {
<span class="keyword">const</span> <span class="type">quint8</span> <span class="operator">*</span>heartRate <span class="operator">=</span> <span class="operator">&</span>data<span class="operator">[</span><span class="number">1</span><span class="operator">]</span>;
m_measurements<span class="operator">.</span>append(<span class="operator">*</span>heartRate);
<span class="comment">//qDebug() << "8 bit HR value:" << *heartRate;</span>
}
<span class="comment">//Energy Expended</span>
<span class="keyword">if</span> (flags <span class="operator">&</span> <span class="number">0x8</span>) {
<span class="type">int</span> index <span class="operator">=</span> (flags <span class="operator">&</span> <span class="number">0x1</span>) <span class="operator">?</span> <span class="number">5</span> : <span class="number">3</span>;
<span class="keyword">const</span> <span class="type">quint16</span> energy <span class="operator">=</span> <a href="../qtcore/qtendian.html#qFromLittleEndian">qFromLittleEndian</a><span class="operator"><</span><span class="type">quint16</span><span class="operator">></span>(data<span class="operator">[</span>index<span class="operator">]</span>);
<a href="../qtcore/qtglobal.html#qDebug">qDebug</a>() <span class="operator"><</span><span class="operator"><</span> <span class="string">"Used Energy:"</span> <span class="operator"><</span><span class="operator"><</span> energy;
}
}
</pre>
<p>In general a characteristic value is a series of bytes. The precise interpretation of those bytes depends on the characteristic type and value structure. A significant number has been standardized by the <a href="https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx">Bluetooth SIG</a> whereas others may follow a custom protocol. The above code snippet demonstrates how to the read the standardized HeartRate value.</p>
<a name="advertising-services"></a>
<h3 >Advertising Services</h3>
<p>If we are implementing a GATT server application on a peripheral device, we need to define the services we want to offer to central devices and advertise them:</p>
<pre class="cpp">
<span class="type">QLowEnergyAdvertisingData</span> advertisingData;
advertisingData<span class="operator">.</span>setDiscoverability(<span class="type">QLowEnergyAdvertisingData</span><span class="operator">::</span>DiscoverabilityGeneral);
advertisingData<span class="operator">.</span>setIncludePowerLevel(<span class="keyword">true</span>);
advertisingData<span class="operator">.</span>setLocalName(<span class="string">"HeartRateServer"</span>);
advertisingData<span class="operator">.</span>setServices(<span class="type">QList</span><span class="operator"><</span><span class="type">QBluetoothUuid</span><span class="operator">></span>() <span class="operator"><</span><span class="operator"><</span> <span class="type">QBluetoothUuid</span><span class="operator">::</span>HeartRate);
<span class="keyword">const</span> <span class="type">QScopedPointer</span><span class="operator"><</span><span class="type">QLowEnergyController</span><span class="operator">></span> leController(<span class="type">QLowEnergyController</span><span class="operator">::</span>createPeripheral());
<span class="keyword">const</span> <span class="type">QScopedPointer</span><span class="operator"><</span><span class="type">QLowEnergyService</span><span class="operator">></span> service(leController<span class="operator">-</span><span class="operator">></span>addService(serviceData));
leController<span class="operator">-</span><span class="operator">></span>startAdvertising(<span class="type">QLowEnergyAdvertisingParameters</span>()<span class="operator">,</span> advertisingData<span class="operator">,</span>
advertisingData);
</pre>
<p>Now potential clients can connect to our device, discover the provided service and register themselves to get notified of changes to the characteristic value. This part of the API was already covered by the above sections.</p>
<a name="implementing-a-service-on-the-peripheral-device"></a>
<h3 >Implementing a Service on the Peripheral Device</h3>
<p>The first step is to define the service, its characteristics and descriptors. This is achieved using the <a href="qlowenergyservicedata.html">QLowEnergyServiceData</a>, <a href="qlowenergycharacteristicdata.html">QLowEnergyCharacteristicData</a> and <a href="qlowenergydescriptordata.html">QLowEnergyDescriptorData</a> classes. These classes act as containers or building blocks for the essential information that comprises the to-be-defined Bluetooth Low Energy service. The code snippet below defines a simple HeartRate service which publishes the measured beats per minute. An example where such a service could be used is a wrist watch.</p>
<pre class="cpp">
<span class="type">QLowEnergyCharacteristicData</span> charData;
charData<span class="operator">.</span>setUuid(<span class="type">QBluetoothUuid</span><span class="operator">::</span>HeartRateMeasurement);
charData<span class="operator">.</span>setValue(<span class="type">QByteArray</span>(<span class="number">2</span><span class="operator">,</span> <span class="number">0</span>));
charData<span class="operator">.</span>setProperties(<span class="type">QLowEnergyCharacteristic</span><span class="operator">::</span>Notify);
<span class="keyword">const</span> <span class="type">QLowEnergyDescriptorData</span> clientConfig(<span class="type">QBluetoothUuid</span><span class="operator">::</span>ClientCharacteristicConfiguration<span class="operator">,</span>
<span class="type">QByteArray</span>(<span class="number">2</span><span class="operator">,</span> <span class="number">0</span>));
charData<span class="operator">.</span>addDescriptor(clientConfig);
<span class="type">QLowEnergyServiceData</span> serviceData;
serviceData<span class="operator">.</span>setType(<span class="type">QLowEnergyServiceData</span><span class="operator">::</span>ServiceTypePrimary);
serviceData<span class="operator">.</span>setUuid(<span class="type">QBluetoothUuid</span><span class="operator">::</span>HeartRate);
serviceData<span class="operator">.</span>addCharacteristic(charData);
</pre>
<p>The resulting <code>serviceData</code> object can be published as described in the <a href="qtbluetooth-le-overview.html#advertising-services">Advertising Services</a> section above. Despite the partial information overlap between the information wrapped by <a href="qlowenergyservicedata.html">QLowEnergyServiceData</a> and <a href="qlowenergyadvertisingdata.html">QLowEnergyAdvertisingData</a> the two classes serve two very different tasks. The advertising data is published to nearby devices and often limited in scope due to its size restriction of 29 bytes. Therefore they are not always 100% complete. By comparison the service data contained inside of <a href="qlowenergyservicedata.html">QLowEnergyServiceData</a> provides the complete set of service data and only becomes visible to the connecting client when a connection with an active service discovery has been performed.</p>
<p>The next section demonstrates how the service can update the heart rate value. Depending on the nature of the service it may have to comply with the official service definition as defined on <a href="https://www.bluetooth.org">https://www.bluetooth.org</a>. Other services may be completely custom. The heart rate service was adopted and its specification can be found under <a href="https://www.bluetooth.com/specifications/adopted-specifications">https://www.bluetooth.com/specifications/adopted-specifications</a>.</p>
<pre class="cpp">
<span class="type">QTimer</span> heartbeatTimer;
<span class="type">quint8</span> currentHeartRate <span class="operator">=</span> <span class="number">60</span>;
<span class="keyword">enum</span> ValueChange { ValueUp<span class="operator">,</span> ValueDown } valueChange <span class="operator">=</span> ValueUp;
<span class="keyword">const</span> <span class="keyword">auto</span> heartbeatProvider <span class="operator">=</span> <span class="operator">[</span><span class="operator">&</span>service<span class="operator">,</span> <span class="operator">&</span>currentHeartRate<span class="operator">,</span> <span class="operator">&</span>valueChange<span class="operator">]</span>() {
<span class="type">QByteArray</span> value;
value<span class="operator">.</span>append(<span class="type">char</span>(<span class="number">0</span>)); <span class="comment">// Flags that specify the format of the value.</span>
value<span class="operator">.</span>append(<span class="type">char</span>(currentHeartRate)); <span class="comment">// Actual value.</span>
<span class="type">QLowEnergyCharacteristic</span> characteristic
<span class="operator">=</span> service<span class="operator">-</span><span class="operator">></span>characteristic(<span class="type">QBluetoothUuid</span><span class="operator">::</span>HeartRateMeasurement);
Q_ASSERT(characteristic<span class="operator">.</span>isValid());
service<span class="operator">-</span><span class="operator">></span>writeCharacteristic(characteristic<span class="operator">,</span> value); <span class="comment">// Potentially causes notification.</span>
<span class="keyword">if</span> (currentHeartRate <span class="operator">=</span><span class="operator">=</span> <span class="number">60</span>)
valueChange <span class="operator">=</span> ValueUp;
<span class="keyword">else</span> <span class="keyword">if</span> (currentHeartRate <span class="operator">=</span><span class="operator">=</span> <span class="number">100</span>)
valueChange <span class="operator">=</span> ValueDown;
<span class="keyword">if</span> (valueChange <span class="operator">=</span><span class="operator">=</span> ValueUp)
<span class="operator">+</span><span class="operator">+</span>currentHeartRate;
<span class="keyword">else</span>
<span class="operator">-</span><span class="operator">-</span>currentHeartRate;
};
<span class="type">QObject</span><span class="operator">::</span>connect(<span class="operator">&</span>heartbeatTimer<span class="operator">,</span> <span class="operator">&</span><span class="type">QTimer</span><span class="operator">::</span>timeout<span class="operator">,</span> heartbeatProvider);
heartbeatTimer<span class="operator">.</span>start(<span class="number">1000</span>);
</pre>
<p>In general characteristic and descriptor value updates on the peripheral device use the same methods as connecting Bluetooth Low Energy devices.</p>
</div>
<!-- @@@qtbluetooth-le-overview.html -->
</div>
</div>
</div>
</div>
</div>
<div class="footer">
<p>
<acronym title="Copyright">©</acronym> 2016 The Qt Company Ltd.
Documentation contributions included herein are the copyrights of
their respective owners.<br> The documentation provided herein is licensed under the terms of the <a href="http://www.gnu.org/licenses/fdl.html">GNU Free Documentation License version 1.3</a> as published by the Free Software Foundation.<br> Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property
of their respective owners. </p>
</div>
</body>
</html>
|