blob: bfb29b4080f84e364848e4169d71c65178cd7bcc [file] [log] [blame]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- This is broken by doc revisioning.
-->
<link rel="shortcut icon" href="../../../../img/favicon.ico">
<title>Service Registration - Apache Mynewt</title>
<link href="../../../../css/bootstrap-3.0.3.min.css" rel="stylesheet">
<link rel="stylesheet" href="../../../../css/highlight.css">
<link href="../../../../css/base.css" rel="stylesheet">
<link href="../../../../css/custom.css" rel="stylesheet">
<link href="../../../../css/v2.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Lato" rel="stylesheet">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css">
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
<script src="https://oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
<![endif]-->
<script>
(function(i, s, o, g, r, a, m) {
i["GoogleAnalyticsObject"] = r;
(i[r] =
i[r] ||
function() {
(i[r].q = i[r].q || []).push(arguments);
}),
(i[r].l = 1 * new Date());
(a = s.createElement(o)), (m = s.getElementsByTagName(o)[0]);
a.async = 1;
a.src = g;
m.parentNode.insertBefore(a, m);
})(window, document, "script", "//www.google-analytics.com/analytics.js", "ga");
ga("create", "UA-72162311-1", "auto");
ga("send", "pageview");
</script>
</head>
<body class="Service Registration">
<div class="container">
<div class="row v2-main-banner">
<a class="logo-cell" href="/">
<img class="logo" src="/img/logo.png">
</a>
<div class="tagline-cell">
<h4 class="tagline">An OS to build, deploy and securely manage billions of devices</h4>
</div>
<div class="news-cell">
<div class="well">
<h4>Latest News:</h4> <a href="/download">Apache Mynewt 1.12.0, Apache NimBLE 1.7.0 </a> released (April 4, 2024)
</div>
</div>
</div>
</div>
<nav id="navbar" class="navbar navbar-inverse affix-top" data-spy="affix" data-offset-top="150" role="navigation">
<div class="container">
<!-- Collapsed navigation -->
<div class="navbar-header">
<!-- Expander button -->
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
</div>
<!-- Expanded navigation -->
<div class="navbar-collapse collapse">
<!-- Main navigation -->
<ul class="nav navbar-nav navbar-right">
<li
class=""
>
<a href="/"><i class="fa fa-home" style="font-size: larger;"></i></a>
</li>
<li
class="important"
>
<a href="/quick-start/">Quick Start</a>
</li>
<li
class=""
>
<a href="/about/">About</a>
</li>
<li
class=""
>
<a href="/talks/">Talks</a>
</li>
<li
class="active"
>
<a href="/documentation/">Documentation</a>
</li>
<li
class=""
>
<a href="/download/">Download</a>
</li>
<li
class=""
>
<a href="/community/">Community</a>
</li>
<li
class=""
>
<a href="/events/">Events</a>
</li>
</ul>
</div>
</div>
</nav>
<div class="container">
<div class="row">
<div class="col-md-3 v2-sidebar sidebar-container"><div id="docSidebar" class="hidden-print" role="complementary">
<div class="top">
<div role="search">
<form id="rtd-search-form" class="wy-form" action="../../../../search.html" method="get">
<div class="form-group">
<input type="text" name="q" class="form-control" placeholder="Search documentation" />
</div>
</form>
</div>
</div>
<ul class="toc-nav">
<li class="doc-version"><select class="form-control" onchange="if (this.value) window.location.href=this.value">
<option value="/latest">
Version: master
</option>
<option value="/v1_12_0/" >
Version: 1.12.0
</option>
<option value="/v1_11_0/" >
Version: 1.11.0
</option>
<option value="/v1_10_0/" >
Version: 1.10.0
</option>
<option value="/v1_9_0/" >
Version: 1.9.0
</option>
<option value="/v1_8_0/" >
Version: 1.8.0
</option>
<option value="/v1_7_0/" >
Version: 1.7.0
</option>
<option value="/v1_6_0/" >
Version: 1.6.0
</option>
<option value="/v1_5_0/" >
Version: 1.5.0
</option>
<option value="/v1_4_0/" >
Version: 1.4.0
</option>
<option value="/v1_3_0/os/introduction" >
Version: 1.3.0
</option>
<option value="/v1_2_0/os/introduction" >
Version: 1.2.0
</option>
<option value="/v1_1_0/os/introduction" >
Version: 1.1.0
</option>
<option value="/v1_0_0/os/introduction" >
Version: 1.0.0
</option>
<option value="/v0_9_0/os/introduction" selected="selected" >
Version: 0.9.0
</option>
</select></li>
<li ><a href="../../../introduction/">Mynewt Documentation</a>
<ul>
<li ><a href="../../../get_started/get_started/">Basic Setup</a>
</li>
<li >
<a href="../../../get_started/vocabulary/">Concepts</a>
</li>
<li ><a href="../../tutorials/">Tutorials</a>
<ul>
<li><a href="
../../arduino_zero/
">Project Blinky</a>
</li>
<li ><a href="../../repo/add_repos/">Work with repositories</a>
</li>
<li >
<a href="../../unit_test/">Write a Test Suite for a Package</a>
</li>
<li >
<a href="../../air_quality_sensor/">Air-quality Sensor project</a>
</li>
<li >
<a href="../../event_queue/">Add task to manage multiple events</a>
</li>
<li >
<a href="../../project-slinky/">Enable remote comms on sim device</a>
</li>
<li >
<a href="../../project-target-slinky/">Enable remote comms on STM32 board</a>
</li>
<li >
<a href="../../bletiny_project/">BLE app to check stats via console</a>
</li>
<li ><a href="../bleprph-intro/">BLE peripheral project</a>
<ul>
<li class="active">
<a href="./">Service Registration</a>
</li>
<li >
<a href="../bleprph-chr-access/">Characteristic Access</a>
</li>
<li >
<a href="../bleprph-adv/">Advertising</a>
</li>
<li >
<a href="../bleprph-conn/">Connection Callbacks</a>
</li>
</ul>
</li>
<li >
<a href="../../ibeacon/">BLE iBeacon</a>
</li>
<li >
<a href="../../blehci_project/">BLE HCI interface</a>
</li>
</ul>
</li>
<li ><a href="../../../os_user_guide/">OS User Guide</a>
</li>
<li><a href="
../../../../network/ble/ble_intro/
">BLE User Guide</a>
</li>
<li ><a href="../../../../newt/newt_intro/">Newt Tool Guide</a>
</li>
<li ><a href="../../../../newtmgr/overview/">Newt Manager Guide</a>
</li>
<li >
<a href="../../../../known_issues/">Known Issues</a>
</li>
</ul>
</li>
<li><a href="
../../../../faq/how_to_edit_docs/
">Appendix</a>
</li>
</ul>
</div></div>
<div class="col-md-9" role="main">
<div class="doc-header">
<div role="navigation" aria-label="breadcrumbs navigation">
<ul class="wy-breadcrumbs">
<li><a href="/documentation/">Docs</a></li>
<li>&raquo; <a href="os/tutorials/bleprph/bleprph-intro/">BLE peripheral project</a></li>
<li>&raquo; <a href="os/tutorials/tutorials/">Tutorials</a></li>
<li>&raquo; <a href="os/introduction/">Mynewt Documentation</a></li>
<li>&raquo; Service Registration</li>
</ul>
</div>
</div>
<div class="alert alert-warning">
<p>
Version 0.9.0 is not the most recent version of the Apache Mynewt
documentation. Click <a href="/latest">here</a> to read the latest
version.
</p>
</div>
<h2 id="ble-peripheral-project">BLE Peripheral Project</h2>
<h3 id="service-registration">Service Registration</h3>
<p><br></p>
<h4 id="attribute-set">Attribute Set</h4>
<p>The NimBLE host uses a table-based design for GATT server configuration. The
set of supported attributes are expressed as a series of tables that resides in
your C code. When possible, we recommend using a single monolithic table, as
it results in code that is simpler and less error prone. Multiple tables
can be used if it is impractical for the entire attribute set to live in one
place in your code.</p>
<p><em>bleprph</em> uses a single attribute table located in the <em>gatt_svr.c</em> file,
so let's take a look at that now. The attribute table is called
<code>gatt_svr_svcs</code>; here are the first several lines from this table:</p>
<p><br></p>
<div class="codehilite" style="background: #ffffff"><pre style="line-height: 125%;"><span></span><code><span style="color: #A90D91">static</span> <span style="color: #A90D91">const</span> <span style="color: #A90D91">struct</span> <span style="color: #3F6E75">ble_gatt_svc_def</span> <span style="color: #000000">gatt_svr_svcs</span>[] <span style="color: #000000">=</span> {
{
<span style="color: #177500">/*** Service: GAP. */</span>
.<span style="color: #000000">type</span> <span style="color: #000000">=</span> <span style="color: #000000">BLE_GATT_SVC_TYPE_PRIMARY</span>,
.<span style="color: #000000">uuid128</span> <span style="color: #000000">=</span> <span style="color: #000000">BLE_UUID16</span>(<span style="color: #000000">BLE_GAP_SVC_UUID16</span>),
.<span style="color: #000000">characteristics</span> <span style="color: #000000">=</span> (<span style="color: #A90D91">struct</span> <span style="color: #3F6E75">ble_gatt_chr_def</span>[]) { {
<span style="color: #177500">/*** Characteristic: Device Name. */</span>
.<span style="color: #000000">uuid128</span> <span style="color: #000000">=</span> <span style="color: #000000">BLE_UUID16</span>(<span style="color: #000000">BLE_GAP_CHR_UUID16_DEVICE_NAME</span>),
.<span style="color: #000000">access_cb</span> <span style="color: #000000">=</span> <span style="color: #000000">gatt_svr_chr_access_gap</span>,
.<span style="color: #000000">flags</span> <span style="color: #000000">=</span> <span style="color: #000000">BLE_GATT_CHR_F_READ</span>,
}, {
<span style="color: #177500">/*** Characteristic: Appearance. */</span>
.<span style="color: #000000">uuid128</span> <span style="color: #000000">=</span> <span style="color: #000000">BLE_UUID16</span>(<span style="color: #000000">BLE_GAP_CHR_UUID16_APPEARANCE</span>),
.<span style="color: #000000">access_cb</span> <span style="color: #000000">=</span> <span style="color: #000000">gatt_svr_chr_access_gap</span>,
.<span style="color: #000000">flags</span> <span style="color: #000000">=</span> <span style="color: #000000">BLE_GATT_CHR_F_READ</span>,
}, {
<span style="color: #177500">// [...]</span>
</code></pre></div>
<p><br></p>
<p>As you can see, the table is an array of service definitions (
<code>struct ble_gatt_svc_def</code>). This code excerpt contains a small part of the
<em>GAP service</em>. The GAP service exposes generic information about a device,
such as its name and appearance. Support for the GAP service is mandatory for
all BLE peripherals. Let's now consider the contents of this table in more
detail.</p>
<p>A service definition consists of the following fields:</p>
<table>
<thead>
<tr>
<th><em>Field</em></th>
<th><em>Meaning</em></th>
<th><em>Notes</em></th>
</tr>
</thead>
<tbody>
<tr>
<td>type</td>
<td>Specifies whether this is a primary or secondary service.</td>
<td>Secondary services are not very common. When in doubt, specify <em>BLE_GATT_SVC_TYPE_PRIMARY</em> for new services.</td>
</tr>
<tr>
<td>uuid128</td>
<td>The 128-bit UUID of this service.</td>
<td>If the service has a 16-bit UUID, you can convert it to its corresponding 128-bit UUID with the <code>BLE_UUID16()</code> macro.</td>
</tr>
<tr>
<td>characteristics</td>
<td>The array of characteristics that belong to this service.</td>
<td></td>
</tr>
</tbody>
</table>
<p><br></p>
<p>A service is little more than a container of characteristics; the
characteristics themselves are where the real action happens. A characteristic
definition consists of the following fields:</p>
<table>
<thead>
<tr>
<th><em>Field</em></th>
<th><em>Meaning</em></th>
<th><em>Notes</em></th>
</tr>
</thead>
<tbody>
<tr>
<td>uuid128</td>
<td>The 128-bit UUID of this characteristic.</td>
<td>If the characteristic has a 16-bit UUID, you can convert it to its corresponding 128-bit UUID with the <code>BLE_UUID16()</code> macro.</td>
</tr>
<tr>
<td>access_cb</td>
<td>A callback function that gets executed whenever a peer device accesses this characteristic.</td>
<td><em>For reads:</em> this function generates the value that gets sent back to the peer.<br><em>For writes:</em> this function provides the written value as an argument.</td>
</tr>
<tr>
<td>flags</td>
<td>Indicates which operations are permitted for this characteristic. The NimBLE stack responds negatively when a peer attempts an unsupported operation.</td>
<td>The full list of flags can be found under <code>ble_gatt_chr_flags</code> in <a href="https://github.com/apache/incubator-mynewt-core/blob/master/net/nimble/host/include/host/ble_gatt.h">net/nimble/host/include/host/ble_gatt.h</a>.</td>
</tr>
</tbody>
</table>
<p>The access callback is what implements the characteristic's behavior. Access
callbacks are described in detail in the next section:
<a href="bleprph-chr-access/">BLE Peripheral - Characteristic Access</a>.</p>
<p>The service definition array and each characteristic definition array is
terminated with an empty entry, represented with a 0. The below code listing
shows the last service in the array, including terminating zeros for the
characteristic array and service array.</p>
<p><br></p>
<div class="codehilite" style="background: #ffffff"><pre style="line-height: 125%;"><span></span><code> {
<span style="color: #177500">/*** Alert Notification Service. */</span>
.<span style="color: #000000">type</span> <span style="color: #000000">=</span> <span style="color: #000000">BLE_GATT_SVC_TYPE_PRIMARY</span>,
.<span style="color: #000000">uuid128</span> <span style="color: #000000">=</span> <span style="color: #000000">BLE_UUID16</span>(<span style="color: #000000">GATT_SVR_SVC_ALERT_UUID</span>),
.<span style="color: #000000">characteristics</span> <span style="color: #000000">=</span> (<span style="color: #A90D91">struct</span> <span style="color: #3F6E75">ble_gatt_chr_def</span>[]) { {
.<span style="color: #000000">uuid128</span> <span style="color: #000000">=</span> <span style="color: #000000">BLE_UUID16</span>(<span style="color: #000000">GATT_SVR_CHR_SUP_NEW_ALERT_CAT_UUID</span>),
.<span style="color: #000000">access_cb</span> <span style="color: #000000">=</span> <span style="color: #000000">gatt_svr_chr_access_alert</span>,
.<span style="color: #000000">flags</span> <span style="color: #000000">=</span> <span style="color: #000000">BLE_GATT_CHR_F_READ</span>,
}, {
.<span style="color: #000000">uuid128</span> <span style="color: #000000">=</span> <span style="color: #000000">BLE_UUID16</span>(<span style="color: #000000">GATT_SVR_CHR_NEW_ALERT</span>),
.<span style="color: #000000">access_cb</span> <span style="color: #000000">=</span> <span style="color: #000000">gatt_svr_chr_access_alert</span>,
.<span style="color: #000000">flags</span> <span style="color: #000000">=</span> <span style="color: #000000">BLE_GATT_CHR_F_NOTIFY</span>,
}, {
.<span style="color: #000000">uuid128</span> <span style="color: #000000">=</span> <span style="color: #000000">BLE_UUID16</span>(<span style="color: #000000">GATT_SVR_CHR_SUP_UNR_ALERT_CAT_UUID</span>),
.<span style="color: #000000">access_cb</span> <span style="color: #000000">=</span> <span style="color: #000000">gatt_svr_chr_access_alert</span>,
.<span style="color: #000000">flags</span> <span style="color: #000000">=</span> <span style="color: #000000">BLE_GATT_CHR_F_READ</span>,
}, {
.<span style="color: #000000">uuid128</span> <span style="color: #000000">=</span> <span style="color: #000000">BLE_UUID16</span>(<span style="color: #000000">GATT_SVR_CHR_UNR_ALERT_STAT_UUID</span>),
.<span style="color: #000000">access_cb</span> <span style="color: #000000">=</span> <span style="color: #000000">gatt_svr_chr_access_alert</span>,
.<span style="color: #000000">flags</span> <span style="color: #000000">=</span> <span style="color: #000000">BLE_GATT_CHR_F_NOTIFY</span>,
}, {
.<span style="color: #000000">uuid128</span> <span style="color: #000000">=</span> <span style="color: #000000">BLE_UUID16</span>(<span style="color: #000000">GATT_SVR_CHR_ALERT_NOT_CTRL_PT</span>),
.<span style="color: #000000">access_cb</span> <span style="color: #000000">=</span> <span style="color: #000000">gatt_svr_chr_access_alert</span>,
.<span style="color: #000000">flags</span> <span style="color: #000000">=</span> <span style="color: #000000">BLE_GATT_CHR_F_WRITE</span>,
}, {
<span style="background-color: #ffffcc"> <span style="color: #1C01CE">0</span>, <span style="color: #177500">/* No more characteristics in this service. */</span>
</span> } },
},
{
<span style="background-color: #ffffcc"> <span style="color: #1C01CE">0</span>, <span style="color: #177500">/* No more services. */</span>
</span> },
</code></pre></div>
<p><br></p>
<h4 id="registration-function">Registration function</h4>
<p>After you have created your service table, your app needs to register it with the NimBLE stack. This is done by calling the following function:</p>
<div class="codehilite" style="background: #ffffff"><pre style="line-height: 125%;"><span></span><code><span style="color: #A90D91">int</span>
<span style="color: #000000">ble_gatts_register_svcs</span>(<span style="color: #A90D91">const</span> <span style="color: #A90D91">struct</span> <span style="color: #3F6E75">ble_gatt_svc_def</span> <span style="color: #000000">*svcs</span>,
<span style="color: #000000">ble_gatt_register_fn</span> <span style="color: #000000">*cb</span>, <span style="color: #A90D91">void</span> <span style="color: #000000">*cb_arg</span>)
</code></pre></div>
<p>The function parameters are documented below.</p>
<table>
<thead>
<tr>
<th><em>Parameter</em></th>
<th><em>Meaning</em></th>
<th><em>Notes</em></th>
</tr>
</thead>
<tbody>
<tr>
<td>svcs</td>
<td>The table of services to register.</td>
<td></td>
</tr>
<tr>
<td>cb</td>
<td>A callback that gets executed each time a service, characteristic, or descriptor is registered.</td>
<td>Optional; pass NULL if you don't want to be notified.</td>
</tr>
<tr>
<td>cb_arg</td>
<td>An argument that gets passed to the callback function on each invocation.</td>
<td>Optional; pass NULL if there is no callback or if you don't need a special argument.</td>
</tr>
</tbody>
</table>
<p>The <code>ble_gatts_register_svcs()</code> function returns 0 on success, or a
<em>BLE_HS_E[...]</em> error code on failure.</p>
<p>More detailed information about the registration callback function can be found
in the <a href="../../../network/ble/ble_intro/">BLE User Guide</a> (TBD).</p>
<p>The <em>bleprph</em> app registers its services as follows:</p>
<div class="codehilite" style="background: #ffffff"><pre style="line-height: 125%;"><span></span><code> <span style="color: #000000">rc</span> <span style="color: #000000">=</span> <span style="color: #000000">ble_gatts_register_svcs</span>(<span style="color: #000000">gatt_svr_svcs</span>, <span style="color: #000000">gatt_svr_register_cb</span>, <span style="color: #A90D91">NULL</span>);
<span style="color: #000000">assert</span>(<span style="color: #000000">rc</span> <span style="color: #000000">==</span> <span style="color: #1C01CE">0</span>);
</code></pre></div>
<p><br></p>
<h4 id="descriptors-and-included-services">Descriptors and Included Services</h4>
<p>Your peripheral can also expose descriptors and included services. These are
less common, so they are not covered in this tutorial. For more information,
see the <a href="../../../network/ble/ble_intro/">BLE User Guide</a>.</p>
<div class="row">
<ul class="nav nav-pills" style="margin-bottom: 10px">
<li>
</li>
<li class="pull-right">
</li>
</ul>
</div>
<footer class="row">
<div class="col-xs-12">
<p class="copyright">Apache Mynewt (incubating) is available under Apache License, version 2.0.</p>
</div>
<div class="col-xs-12">
<div class="logos">
<a href="https://www.apache.org/">
<img src="/img/asf_logo_wide_small.png" alt="Apache" title="Apache">
</a>
<p>
Copyright © 2015-2021 The Apache Software Foundation.<br>
<small class="footnote">
Apache Mynewt, Mynewt, Apache, the Apache feather logo, and the Apache Mynewt
project logo are either registered trademarks or trademarks of the Apache
Software Foundation in the United States and other countries.
</small>
</p>
<a href="">
<img src="https://www.countit.com/images/add_to_slack.png" alt="Slack Icon" title="Join our Slack Community" />
</a>
</div>
</div>
<a href="https://www.apache.org/licenses/">
<button class="button-footer-asf">
License
</button>
</a>
<a href="https://www.apache.org/foundation/sponsorship.html">
<button class="button-footer-asf">
Sponsorship
</button>
</a>
<a href="https://www.apache.org/foundation/thanks.html">
<button class="button-footer-asf">
Thanks
</button>
</a>
<a href="https://www.apache.org/security/">
<button class="button-footer-asf">
Security
</button>
</a>
<a href="https://apache.org/events/current-event">
<button class="button-footer-asf">
ASF Events
</button>
</a>
</footer>
</div>
</div>
</div>
<script src="../../../../js/jquery-1.10.2.min.js"></script>
<script src="../../../../js/bootstrap-3.0.3.min.js"></script>
<script src="../../../../js/highlight.pack.js"></script>
<script src="../../../../js/base.js"></script>
<script src="../../../../js/custom.js"></script>
<script src="search/main.js"></script>
</body>
</html>