blob: 93a2a2d0946bc08c41926629967007080604f87a [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">
<title>Air Quality Sensor Project via Bluetooth &mdash; Apache Mynewt latest documentation</title>
<link rel="shortcut icon" href="../../_static/mynewt-logo-only-newt32x32.png"/>
<link rel="stylesheet" href="../../_static/css/theme.css" type="text/css" />
<link rel="stylesheet" href="../../_static/css/sphinx_theme.css" type="text/css" />
<link rel="stylesheet" href="../../_static/css/bootstrap-3.0.3.min.css" type="text/css" />
<link rel="stylesheet" href="../../_static/css/v2.css" type="text/css" />
<link rel="stylesheet" href="../../_static/css/custom.css" type="text/css" />
<link rel="stylesheet" href="../../_static/css/restructuredtext.css" type="text/css" />
<link rel="stylesheet" href="../../_static/css/overrides.css" type="text/css" />
<link rel="index" title="Index"
href="../../genindex.html"/>
<link rel="search" title="Search" href="../../search.html"/>
<link rel="top" title="Apache Mynewt latest documentation" href="../../index.html"/>
<link rel="up" title="Air Quality Sensor Project" href="air_quality.html"/>
<link rel="next" title="Adding an Analog Sensor on nRF52" href="nrf52_adc.html"/>
<link rel="prev" title="Air Quality Sensor Project" href="air_quality_sensor.html"/>
<script src="../../_static/js/modernizr.min.js"></script>
<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="not-front page-documentation" role="document" >
<div id="wrapper">
<div class="container">
<div id="banner" class="row v2-main-banner">
<a class="logo-cell" href="/">
<img class="logo" src="../../_static/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>
<header>
<nav id="navbar" class="navbar navbar-inverse" 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>
<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>
<a href="/about/">About</a>
</li>
<li>
<a href="/talks/">Talks</a>
</li>
<li class="active">
<a href="/documentation/">Documentation</a>
</li>
<li>
<a href="/download/">Download</a>
</li>
<li>
<a href="/community/">Community</a>
</li>
<li>
<a href="/events/">Events</a>
</li>
</ul>
<!-- Search, Navigation and Repo links -->
<ul class="nav navbar-nav navbar-right">
</ul>
</div>
</div>
</nav>
</header>
<!-- STARTS MAIN CONTENT -->
<div id="main-content">
<div id="breadcrumb">
<div class="container">
<a href="/documentation/">Docs</a> /
<a href="../tutorials.html">Tutorials</a> /
<a href="sensors.html">Sensors</a> /
<a href="air_quality.html">Air Quality Sensor Project</a> /
Air Quality Sensor Project via Bluetooth
<div class="sourcelink">
<a href="https://github.com/apache/mynewt-documentation/edit/master/docs/tutorials/sensors/air_quality_ble.rst" class="icon icon-github"
rel="nofollow"> Edit on GitHub</a>
</div>
</div>
</div>
<!-- STARTS CONTAINER -->
<div class="container">
<!-- STARTS .content -->
<div id="content" class="row">
<!-- STARTS .container-sidebar -->
<div class="container-sidebar col-xs-12 col-sm-3">
<div id="docSidebar" class="sticky-container">
<div role="search" class="sphinx-search">
<form id="rtd-search-form" class="wy-form" action="../../search.html" method="get">
<input type="text" name="q" placeholder="Search documentation" class="search-documentation" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
<!-- Note: only works when deployed -->
<select class="form-control" onchange="if (this.value) window.location.href=this.value">
<option value="/latest" selected>
Version: latest
</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" selected="selected" >
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" >
Version: 0.9.0
</option>
</select>
<div class="region region-sidebar">
<div class="docs-menu">
<ul class="current">
<li class="toctree-l1"><a class="reference internal" href="../../index.html">Introduction</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../get_started/index.html">Setup &amp; Get Started</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../concepts.html">Concepts</a></li>
<li class="toctree-l1 current"><a class="reference internal" href="../tutorials.html">Tutorials</a><ul class="current">
<li class="toctree-l2"><a class="reference internal" href="../blinky/blinky.html">Project Blinky</a></li>
<li class="toctree-l2"><a class="reference internal" href="../repo/add_repos.html">Working with repositories</a></li>
<li class="toctree-l2"><a class="reference internal" href="../slinky/project-slinky.html">Project Slinky for Remote Comms</a></li>
<li class="toctree-l2"><a class="reference internal" href="../ble/ble.html">Bluetooth Low Energy</a></li>
<li class="toctree-l2"><a class="reference internal" href="../lora/lorawanapp.html">LoRa</a></li>
<li class="toctree-l2"><a class="reference internal" href="../os_fundamentals/os_fundamentals.html">OS Fundamentals</a></li>
<li class="toctree-l2"><a class="reference internal" href="../devmgmt/devmgmt.html">Remote Device Management</a></li>
<li class="toctree-l2 current"><a class="reference internal" href="sensors.html">Sensors</a><ul class="current">
<li class="toctree-l3"><a class="reference internal" href="sensors_framework.html">Sensor Framework</a></li>
<li class="toctree-l3 current"><a class="reference internal" href="air_quality.html">Air Quality Sensor Project</a><ul class="current">
<li class="toctree-l4"><a class="reference internal" href="air_quality_sensor.html"> Basic Air Quality Sensor</a></li>
<li class="toctree-l4 current"><a class="current reference internal" href="#"> BLE-enabled Air Quality Sensor</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="nrf52_adc.html">Add an Analog Sensor</a></li>
<li class="toctree-l3"><a class="reference internal" href="sensor_nrf52_drv2605.html">Connect a DRV2605 actuator device</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="../tooling/tooling.html">Tooling</a></li>
<li class="toctree-l2"><a class="reference internal" href="../other/other.html">Other</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../../external_links.html">Third-party Resources</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../os/os_user_guide.html">OS User Guide</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../network/index.html">BLE User Guide</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../newt/index.html">Newt Tool Guide</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../newtmgr/index.html">Newt Manager Guide</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../mynewt_faq/index.html">Mynewt FAQ</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../misc/index.html">Appendix</a></li>
</ul>
</div>
</div>
</div>
<!-- ENDS STICKY CONTAINER -->
</div>
<!-- ENDS .container-sidebar -->
<div class="col-xs-12 col-sm-9">
<div class="alert alert-warning">
<p>
Version 1.7.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>
<div class="">
<div class="rst-content">
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<div class="section" id="air-quality-sensor-project-via-bluetooth">
<h1>Air Quality Sensor Project via Bluetooth<a class="headerlink" href="#air-quality-sensor-project-via-bluetooth" title="Permalink to this headline"></a></h1>
<p>This is a follow-on project to the <a class="reference internal" href="air_quality_sensor.html"><span class="doc">Basic Air Quality Sensor</span></a> project; so it is assumed that you have worked through that project and have your CO2 sensor working properly with your nRF52DK board.</p>
<p>So let’s get started making this thing Bluetooth enabled!</p>
<div class="section" id="add-bluetooth-gatt-services">
<h2>Add Bluetooth GATT Services<a class="headerlink" href="#add-bluetooth-gatt-services" title="Permalink to this headline"></a></h2>
<p>Since we already built the previous demo on the <span class="xref std std-doc">bluetooth peripheral</span> basic app most of the Bluetooth plumbing has already been taken care of for us. What’s left is for us to add the required GATT services for advertising the Carbon Dioxide sensor so that other devices can get those values.</p>
<p>First, we’ll define the GATT Services in <code class="docutils literal notranslate"><span class="pre">apps/air_quality/src/bleprph.h</span></code>. Be sure to include the header files as well.</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="cp">#include</span><span class="w"> </span><span class="cpf">&quot;host/ble_hs.h&quot;</span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf">&quot;host/ble_uuid.h&quot;</span>
<span class="p">....</span>
<span class="cm">/* Sensor Data */</span>
<span class="cm">/* e761d2af-1c15-4fa7-af80-b5729002b340 */</span>
<span class="k">static</span><span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="n">ble_uuid128_t</span><span class="w"> </span><span class="n">gatt_svr_svc_co2_uuid</span><span class="w"> </span><span class="o">=</span>
<span class="w"> </span><span class="n">BLE_UUID128_INIT</span><span class="p">(</span><span class="mh">0x40</span><span class="p">,</span><span class="w"> </span><span class="mh">0xb3</span><span class="p">,</span><span class="w"> </span><span class="mh">0x20</span><span class="p">,</span><span class="w"> </span><span class="mh">0x90</span><span class="p">,</span><span class="w"> </span><span class="mh">0x72</span><span class="p">,</span><span class="w"> </span><span class="mh">0xb5</span><span class="p">,</span><span class="w"> </span><span class="mh">0x80</span><span class="p">,</span><span class="w"> </span><span class="mh">0xaf</span><span class="p">,</span>
<span class="w"> </span><span class="mh">0xa7</span><span class="p">,</span><span class="w"> </span><span class="mh">0x4f</span><span class="p">,</span><span class="w"> </span><span class="mh">0x15</span><span class="p">,</span><span class="w"> </span><span class="mh">0x1c</span><span class="p">,</span><span class="w"> </span><span class="mh">0xaf</span><span class="p">,</span><span class="w"> </span><span class="mh">0xd2</span><span class="p">,</span><span class="w"> </span><span class="mh">0x61</span><span class="p">,</span><span class="w"> </span><span class="mh">0xe7</span><span class="p">);</span>
<span class="cp">#define CO2_SNS_TYPE 0xDEAD</span>
<span class="cp">#define CO2_SNS_STRING &quot;SenseAir K30 CO2 Sensor&quot;</span>
<span class="cp">#define CO2_SNS_VAL 0xBEAD</span>
<span class="kt">uint16_t</span><span class="w"> </span><span class="n">gatt_co2_val</span><span class="p">;</span>
</pre></div>
</div>
<p>You can use any hex values you choose for the sensor type and sensor values, and you can even forget the sensor type and sensor string definitions altogether but they make the results look nice in our Bluetooth App for Mac OS X and iOS.</p>
<p>Next we’ll add those services to <code class="docutils literal notranslate"><span class="pre">apps/air_quality/src/gatt_svr.c</span></code>.</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span><span class="w"> </span><span class="kt">int</span>
<span class="nf">gatt_svr_sns_access</span><span class="p">(</span><span class="kt">uint16_t</span><span class="w"> </span><span class="n">conn_handle</span><span class="p">,</span><span class="w"> </span><span class="kt">uint16_t</span><span class="w"> </span><span class="n">attr_handle</span><span class="p">,</span>
<span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">ble_gatt_access_ctxt</span><span class="w"> </span><span class="o">*</span><span class="n">ctxt</span><span class="p">,</span>
<span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="o">*</span><span class="n">arg</span><span class="p">);</span>
<span class="k">static</span><span class="w"> </span><span class="kt">uint16_t</span><span class="w"> </span><span class="n">gatt_co2_val_len</span><span class="p">;</span>
</pre></div>
</div>
<p>Make sure it is added as <em>primary</em> service.</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span><span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">ble_gatt_svc_def</span><span class="w"> </span><span class="n">gatt_svr_svcs</span><span class="p">[]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="cm">/*** Service: Security test. */</span>
<span class="w"> </span><span class="p">.</span><span class="n">type</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">BLE_GATT_SVC_TYPE_PRIMARY</span><span class="p">,</span>
<span class="w"> </span><span class="p">.</span><span class="n">uuid</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">&amp;</span><span class="n">gatt_svr_svc_sec_test_uuid</span><span class="p">.</span><span class="n">u</span><span class="p">,</span>
<span class="w"> </span><span class="p">.</span><span class="n">characteristics</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="k">struct</span><span class="w"> </span><span class="nc">ble_gatt_chr_def</span><span class="p">[])</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="cm">/*** Characteristic: Random number generator. */</span>
<span class="w"> </span><span class="p">.</span><span class="n">uuid</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">&amp;</span><span class="n">gatt_svr_chr_sec_test_rand_uuid</span><span class="p">.</span><span class="n">u</span><span class="p">,</span>
<span class="w"> </span><span class="p">.</span><span class="n">access_cb</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">gatt_svr_chr_access_sec_test</span><span class="p">,</span>
<span class="w"> </span><span class="p">.</span><span class="n">flags</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">BLE_GATT_CHR_F_READ</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">BLE_GATT_CHR_F_READ_ENC</span><span class="p">,</span>
<span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="cm">/*** Characteristic: Static value. */</span>
<span class="w"> </span><span class="p">.</span><span class="n">uuid</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">&amp;</span><span class="n">gatt_svr_chr_sec_test_static_uuid</span><span class="p">,.</span><span class="n">u</span>
<span class="w"> </span><span class="p">.</span><span class="n">access_cb</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">gatt_svr_chr_access_sec_test</span><span class="p">,</span>
<span class="w"> </span><span class="p">.</span><span class="n">flags</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">BLE_GATT_CHR_F_READ</span><span class="w"> </span><span class="o">|</span>
<span class="w"> </span><span class="n">BLE_GATT_CHR_F_WRITE</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">BLE_GATT_CHR_F_WRITE_ENC</span><span class="p">,</span>
<span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="cm">/* No more characteristics in this service. */</span>
<span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="cm">/*** CO2 Level Notification Service. */</span>
<span class="w"> </span><span class="p">.</span><span class="n">type</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">BLE_GATT_SVC_TYPE_PRIMARY</span><span class="p">,</span>
<span class="w"> </span><span class="p">.</span><span class="n">uuid</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">&amp;</span><span class="n">gatt_svr_svc_co2_uuid</span><span class="p">.</span><span class="n">u</span><span class="p">,</span>
<span class="w"> </span><span class="p">.</span><span class="n">characteristics</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="k">struct</span><span class="w"> </span><span class="nc">ble_gatt_chr_def</span><span class="p">[])</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="p">.</span><span class="n">uuid</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">BLE_UUID16_DECLARE</span><span class="p">(</span><span class="n">CO2_SNS_TYPE</span><span class="p">),</span>
<span class="w"> </span><span class="p">.</span><span class="n">access_cb</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">gatt_svr_sns_access</span><span class="p">,</span>
<span class="w"> </span><span class="p">.</span><span class="n">flags</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">BLE_GATT_CHR_F_READ</span><span class="p">,</span>
<span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="p">.</span><span class="n">uuid</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">BLE_UUID16_DECLARE</span><span class="p">(</span><span class="n">CO2_SNS_VAL</span><span class="p">),</span>
<span class="w"> </span><span class="p">.</span><span class="n">access_cb</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">gatt_svr_sns_access</span><span class="p">,</span>
<span class="w"> </span><span class="p">.</span><span class="n">flags</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">BLE_GATT_CHR_F_NOTIFY</span><span class="p">,</span>
<span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="cm">/* No more characteristics in this service. */</span>
<span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="cm">/* No more services. */</span>
<span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="p">};</span>
</pre></div>
</div>
<p>Next we need to tell the GATT Server how to handle requests for CO2 readings :</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span><span class="w"> </span><span class="kt">int</span>
<span class="nf">gatt_svr_sns_access</span><span class="p">(</span><span class="kt">uint16_t</span><span class="w"> </span><span class="n">conn_handle</span><span class="p">,</span><span class="w"> </span><span class="kt">uint16_t</span><span class="w"> </span><span class="n">attr_handle</span><span class="p">,</span>
<span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">ble_gatt_access_ctxt</span><span class="w"> </span><span class="o">*</span><span class="n">ctxt</span><span class="p">,</span>
<span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="o">*</span><span class="n">arg</span><span class="p">)</span>
<span class="p">{</span>
<span class="w"> </span><span class="kt">uint16_t</span><span class="w"> </span><span class="n">uuid16</span><span class="p">;</span>
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">rc</span><span class="p">;</span>
<span class="w"> </span><span class="n">uuid16</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ble_uuid_u16</span><span class="p">(</span><span class="n">ctxt</span><span class="o">-&gt;</span><span class="n">chr</span><span class="o">-&gt;</span><span class="n">uuid</span><span class="p">);</span>
<span class="w"> </span><span class="k">switch</span><span class="w"> </span><span class="p">(</span><span class="n">uuid16</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="no">CO2_SNS_TYPE</span><span class="p">:</span>
<span class="w"> </span><span class="n">assert</span><span class="p">(</span><span class="n">ctxt</span><span class="o">-&gt;</span><span class="n">op</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="n">BLE_GATT_ACCESS_OP_READ_CHR</span><span class="p">);</span>
<span class="w"> </span><span class="n">rc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">os_mbuf_append</span><span class="p">(</span><span class="n">ctxt</span><span class="o">-&gt;</span><span class="n">om</span><span class="p">,</span><span class="w"> </span><span class="n">CO2_SNS_STRING</span><span class="p">,</span><span class="w"> </span><span class="k">sizeof</span><span class="w"> </span><span class="n">CO2_SNS_STRING</span><span class="p">);</span>
<span class="w"> </span><span class="n">BLEPRPH_LOG</span><span class="p">(</span><span class="n">INFO</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;CO2 SENSOR TYPE READ: %s</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">CO2_SNS_STRING</span><span class="p">);</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">rc</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="o">?</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">BLE_ATT_ERR_INSUFFICIENT_RES</span><span class="p">;</span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="no">CO2_SNS_VAL</span><span class="p">:</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">ctxt</span><span class="o">-&gt;</span><span class="n">op</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="n">BLE_GATT_ACCESS_OP_WRITE_CHR</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">rc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">gatt_svr_chr_write</span><span class="p">(</span><span class="n">ctxt</span><span class="o">-&gt;</span><span class="n">om</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span>
<span class="w"> </span><span class="k">sizeof</span><span class="w"> </span><span class="n">gatt_co2_val</span><span class="p">,</span>
<span class="w"> </span><span class="o">&amp;</span><span class="n">gatt_co2_val</span><span class="p">,</span>
<span class="w"> </span><span class="o">&amp;</span><span class="n">gatt_co2_val_len</span><span class="p">);</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">rc</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">ctxt</span><span class="o">-&gt;</span><span class="n">op</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="n">BLE_GATT_ACCESS_OP_READ_CHR</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">rc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">os_mbuf_append</span><span class="p">(</span><span class="n">ctxt</span><span class="o">-&gt;</span><span class="n">om</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="n">gatt_co2_val</span><span class="p">,</span>
<span class="w"> </span><span class="k">sizeof</span><span class="w"> </span><span class="n">gatt_co2_val</span><span class="p">);</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">rc</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="o">?</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">BLE_ATT_ERR_INSUFFICIENT_RES</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="k">default</span><span class="o">:</span>
<span class="w"> </span><span class="n">assert</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">BLE_ATT_ERR_UNLIKELY</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p>Now it’s time to go into our <code class="docutils literal notranslate"><span class="pre">apps/air_quality/src/main.c</span></code> and change how we read CO2 readings and respond to requests.</p>
<p>We’ll need a task handler with an event queue for the CO2 readings.</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="cm">/* CO2 Task settings */</span>
<span class="cp">#define CO2_TASK_PRIO 128</span>
<span class="cp">#define CO2_STACK_SIZE (OS_STACK_ALIGN(336))</span>
<span class="k">struct</span><span class="w"> </span><span class="nc">os_eventq</span><span class="w"> </span><span class="n">co2_evq</span><span class="p">;</span>
<span class="k">struct</span><span class="w"> </span><span class="nc">os_task</span><span class="w"> </span><span class="n">co2_task</span><span class="p">;</span>
<span class="n">bssnz_t</span><span class="w"> </span><span class="n">os_stack_t</span><span class="w"> </span><span class="n">co2_stack</span><span class="p">[</span><span class="n">CO2_STACK_SIZE</span><span class="p">];</span>
</pre></div>
</div>
<p>And of course we’ll need to go to our <code class="docutils literal notranslate"><span class="pre">main()</span></code> and do all the standard task and event setup we normally do by adding the following:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="cm">/* Initialize sensor eventq */</span>
<span class="n">os_eventq_init</span><span class="p">(</span><span class="o">&amp;</span><span class="n">co2_evq</span><span class="p">);</span>
<span class="cm">/* Create the CO2 reader task.</span>
<span class="cm"> * All sensor reading operations are performed in this task.</span>
<span class="cm"> */</span>
<span class="n">os_task_init</span><span class="p">(</span><span class="o">&amp;</span><span class="n">co2_task</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;sensor&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">co2_task_handler</span><span class="p">,</span>
<span class="w"> </span><span class="nb">NULL</span><span class="p">,</span><span class="w"> </span><span class="n">CO2_TASK_PRIO</span><span class="p">,</span><span class="w"> </span><span class="n">OS_WAIT_FOREVER</span><span class="p">,</span>
<span class="w"> </span><span class="n">co2_stack</span><span class="p">,</span><span class="w"> </span><span class="n">CO2_STACK_SIZE</span><span class="p">);</span>
</pre></div>
</div>
<p>We’ll also need to add a task handler – since we initialized it above:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="cm">/**</span>
<span class="cm"> * Event loop for the sensor task.</span>
<span class="cm"> */</span>
<span class="k">static</span><span class="w"> </span><span class="kt">void</span>
<span class="nf">co2_task_handler</span><span class="p">(</span><span class="kt">void</span><span class="w"> </span><span class="o">*</span><span class="n">unused</span><span class="p">)</span>
<span class="p">{</span>
<span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">co2_read_event</span><span class="p">();</span>
<span class="w"> </span><span class="cm">/* Wait 2 second */</span>
<span class="w"> </span><span class="n">os_time_delay</span><span class="p">(</span><span class="n">OS_TICKS_PER_SEC</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mi">2</span><span class="p">);</span>
<span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p>And finally, we’ll take care of that <code class="docutils literal notranslate"><span class="pre">co2_read_event()</span></code> function:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="kt">int</span>
<span class="nf">co2_read_event</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">value</span><span class="p">;</span>
<span class="w"> </span><span class="k">enum</span><span class="w"> </span><span class="n">senseair_read_type</span><span class="w"> </span><span class="n">type</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">SENSEAIR_CO2</span><span class="p">;</span>
<span class="w"> </span><span class="kt">uint16_t</span><span class="w"> </span><span class="n">chr_val_handle</span><span class="p">;</span>
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">rc</span><span class="p">;</span>
<span class="w"> </span><span class="n">value</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">senseair_read</span><span class="p">(</span><span class="n">type</span><span class="p">);</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">value</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">console_printf</span><span class="p">(</span><span class="s">&quot;Got %d</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">value</span><span class="p">);</span>
<span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">console_printf</span><span class="p">(</span><span class="s">&quot;Error while reading: %d</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">value</span><span class="p">);</span>
<span class="w"> </span><span class="k">goto</span><span class="w"> </span><span class="n">err</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="n">gatt_co2_val</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">value</span><span class="p">;</span>
<span class="w"> </span><span class="n">rc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ble_gatts_find_chr</span><span class="p">(</span><span class="o">&amp;</span><span class="n">gatt_svr_svc_co2_uuid</span><span class="p">.</span><span class="n">u</span><span class="p">,</span><span class="w"> </span><span class="n">BLE_UUID16_DECLARE</span><span class="p">(</span><span class="n">CO2_SNS_VAL</span><span class="p">),</span><span class="w"> </span><span class="nb">NULL</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="n">chr_val_handle</span><span class="p">);</span>
<span class="w"> </span><span class="n">assert</span><span class="p">(</span><span class="n">rc</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="p">);</span>
<span class="w"> </span><span class="n">ble_gatts_chr_updated</span><span class="p">(</span><span class="n">chr_val_handle</span><span class="p">);</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
<span class="nl">err</span><span class="p">:</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="p">(</span><span class="n">rc</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
</div>
<p>This one simply reads and updates the CO2 value and sends that over BLE to any connected clients instead.</p>
<p>We can now build, create-image and load the app onto our nRF52DK board, and then connect and see the updated values! To view the results over Bluetooth, you can use LightBlue or any other application that can connect to, and read, Bluetooth data. By default, the device will show up as nimble-bleprph, since we used the <code class="docutils literal notranslate"><span class="pre">bleprph</span></code> app as our template. I’ve changed mine to something a bit more applicable: BLE CO2 Sensor.</p>
<div class="figure align-default" id="id1">
<img alt="../../_images/airquality_lightblue.png" src="../../_images/airquality_lightblue.png" />
<p class="caption"><span class="caption-text">LightBlue app connected to BLE CO2 Sensor</span><a class="headerlink" href="#id1" title="Permalink to this image"></a></p>
</div>
<p>Congratulations!!</p>
</div>
</div>
</div>
</div>
<div class="rst-footer-buttons row" role="navigation" aria-label="footer navigation">
<a href="nrf52_adc.html" class="btn btn-neutral float-right" title="Adding an Analog Sensor on nRF52" accesskey="n">Next: Adding an Analog Sensor on nRF52 <span class="fa fa-arrow-circle-right"></span></a>
<a href="air_quality_sensor.html" class="btn btn-neutral" title="Air Quality Sensor Project" accesskey="p"><span class="fa fa-arrow-circle-left"></span> Previous: Air Quality Sensor Project</a>
</div>
</div>
</div>
</div>
<!-- ENDS CONTENT SECTION -->
</div>
<!-- ENDS .content -->
</div>
</div>
<footer>
<div class="container">
<div class="row">
<div class="col-xs-12">
<p class="copyright">Apache Mynewt is available under Apache License, version 2.0.</p>
</div>
<div class="col-xs-12">
<div class="logos">
<img src="../../_static/img/asf_logo_wide_small.png" alt="Apache" title="Apache">
<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>
<a href="">
<img src="../../_static/img/add_to_slack.png" alt="Slack Icon" title="Join our Slack Community" />
</a>
</div>
</div>
</div>
</div>
</footer>
</div>
<!-- ENDS #wrapper -->
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT:'../../',
VERSION:'latest',
COLLAPSE_INDEX:false,
FILE_SUFFIX:'.html',
HAS_SOURCE: true,
SOURCELINK_SUFFIX: '.txt',
LINK_SUFFIX: '.html'
};
</script>
<script type="text/javascript" src="../../_static/jquery.js"></script>
<script type="text/javascript" src="../../_static/underscore.js"></script>
<script type="text/javascript" src="../../_static/doctools.js"></script>
<script type="text/javascript" src="../../_static/js/bootstrap-3.0.3.min.js"></script>
<script type="text/javascript" src="../../_static/js/affix.js"></script>
<script type="text/javascript" src="../../_static/js/main.js"></script>
</body>
</html>