blob: c58f65ac8e705d53e647c406b195d22ca84556df [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 &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="Air Quality Sensor Project via Bluetooth" href="air_quality_ble.html"/>
<link rel="prev" title="Air Quality Sensor Project" href="air_quality.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
<div class="sourcelink">
<a href="https://github.com/apache/mynewt-documentation/edit/master/docs/tutorials/sensors/air_quality_sensor.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" >
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 current"><a class="current reference internal" href="#"> Basic Air Quality Sensor</a></li>
<li class="toctree-l4"><a class="reference internal" href="air_quality_ble.html"> 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="">
<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">
<h1>Air Quality Sensor Project<a class="headerlink" href="#air-quality-sensor-project" title="Permalink to this headline"></a></h1>
<p>This tutorial will show you how to set up and use the Senseair K30 air quality sensor with the nRF52 Development Kit. Afterwards, you can set it up via Bluetooth so you can read values remotely.</p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><p><a class="reference internal" href="#prerequisites" id="id3">Prerequisites</a></p></li>
<li><p><a class="reference internal" href="#setting-up-the-source-tree" id="id4">Setting Up the Source Tree</a></p></li>
<li><p><a class="reference internal" href="#create-a-test-project" id="id5">Create a Test Project</a></p></li>
<li><p><a class="reference internal" href="#create-packages-for-drivers" id="id6">Create Packages For Drivers</a></p></li>
<li><p><a class="reference internal" href="#add-cli-commands-for-testing-drivers" id="id7">Add CLI Commands For Testing Drivers</a></p></li>
<li><p><a class="reference internal" href="#using-hal-for-drivers" id="id8">Using HAL for Drivers</a></p></li>
</ul>
</div>
<div class="section" id="prerequisites">
<h2><a class="toc-backref" href="#id3">Prerequisites</a><a class="headerlink" href="#prerequisites" title="Permalink to this headline"></a></h2>
<ul class="simple">
<li><p>Complete one of the other tutorials (e.g. <a class="reference internal" href="../blinky/blinky.html"><span class="doc">Project Blinky</span></a>) to famliarize yourself with Mynewt</p></li>
<li><p>Nordic nRF52 Development - PCA 10040</p></li>
<li><p>Senseair K30 CO2 Sensor</p></li>
</ul>
</div>
<div class="section" id="setting-up-the-source-tree">
<h2><a class="toc-backref" href="#id4">Setting Up the Source Tree</a><a class="headerlink" href="#setting-up-the-source-tree" title="Permalink to this headline"></a></h2>
<p>To start, create a new project under which you will do development for this application:</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>mkdir<span class="w"> </span><span class="nv">$HOME</span>/src
<span class="gp">$ </span><span class="nb">cd</span><span class="w"> </span><span class="nv">$HOME</span>/src
<span class="gp">$ </span>newt<span class="w"> </span>new<span class="w"> </span>air_quality
</pre></div>
</div>
<p>If you are using a different development board, you will need to know the board support package for that hardware. You can look up its location, add it your project, and fetch that along with the core OS components. Since the nRF52DK is supported in the Mynewt Core, we don’t need to do much here.</p>
<p>Your project.yml file should look like this:</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span>[user@IsMyLaptop:~/src/air_quality]$ emacs project.yml &amp;
[user@IsMyLaptop:~/src/air_quality]$ cat project.yml
project.name: &quot;air_quality&quot;
project.repositories:
- apache-mynewt-core
# Use github&#39;s distribution mechanism for core ASF libraries.
# This provides mirroring automatically for us.
#
repository.apache-mynewt-core:
type: github
vers: 0-latest
user: apache
repo: mynewt-core
[user@IsMyLaptop:~/src/air_quality]$ newt upgrade
Downloading repository mynewt-core (commit: master) ...
Downloading repository mynewt-nimble (commit: master) ...
apache-mynewt-core successfully upgraded to version 0.0.0
apache-mynewt-nimble successfully upgraded to version 0.0.0
[user@IsMyLaptop:~/src/air_quality]$ ls repos/
apache-mynewt-core
</pre></div>
</div>
<p>Next, create a target for the nRF52DK bootloader:</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">[user@IsMyLaptop:~/src/air_quality]$ </span>newt<span class="w"> </span>target<span class="w"> </span>create<span class="w"> </span>boot_nrf52dk
<span class="go">Target targets/boot_nrf52dk successfully created</span>
<span class="gp">[user@IsMyLaptop:~/src/air_quality]$ </span>newt<span class="w"> </span>target<span class="w"> </span><span class="nb">set</span><span class="w"> </span>boot_nrf52dk<span class="w"> </span><span class="nv">bsp</span><span class="o">=</span>@apache-mynewt-core/hw/bsp/nrf52dk
<span class="go">Target targets/boot_nrf52dk successfully set target.bsp to @apache-mynewt-core/hw/bsp/nrf52dk</span>
<span class="gp">[user@IsMyLaptop:~/src/air_quality]$ </span>newt<span class="w"> </span>target<span class="w"> </span><span class="nb">set</span><span class="w"> </span>boot_nrf52dk<span class="w"> </span><span class="nv">app</span><span class="o">=</span>@mcuboot/boot/mynewt
<span class="go">Target targets/boot_nrf52dk successfully set target.app to @mcuboot/boot/mynewt</span>
<span class="gp">[user@IsMyLaptop:~/src/air_quality]$ </span>newt<span class="w"> </span>target<span class="w"> </span><span class="nb">set</span><span class="w"> </span>boot_nrf52dk<span class="w"> </span><span class="nv">build_profile</span><span class="o">=</span>optimized
<span class="go">Target targets/boot_nrf52dk successfully set target.build_profile to optimized</span>
<span class="gp">[user@IsMyLaptop:~/src/air_quality]$ </span>newt<span class="w"> </span>target<span class="w"> </span>show
<span class="go">@apache-mynewt-core/targets/unittest</span>
<span class="go"> bsp=hw/bsp/native</span>
<span class="go"> build_profile=debug</span>
<span class="go"> compiler=compiler/sim</span>
<span class="go">targets/boot_nrf52dk</span>
<span class="go"> app=@mcuboot/boot/mynewt</span>
<span class="go"> bsp=@apache-mynewt-core/hw/bsp/nrf52dk</span>
<span class="go"> build_profile=optimized</span>
<span class="go">targets/my_blinky_sim</span>
<span class="go"> app=apps/blinky</span>
<span class="go"> bsp=@apache-mynewt-core/hw/bsp/native</span>
<span class="go"> build_profile=debug</span>
</pre></div>
</div>
<p>Build the bootloader target and load it onto the board:</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="go">newt build boot_nrf52dk</span>
<span class="go">....</span>
<span class="go">Linking boot.elf</span>
<span class="go">App successfully built: /Users/user/src/air_quality/bin/boot_nrf52dk/boot/mynewt/mynewt.elf</span>
<span class="go">[user@IsMyLaptop:~/src/air_quality]</span>
<span class="gp">$ </span>newt<span class="w"> </span>load<span class="w"> </span>boot_nrf52dk
</pre></div>
</div>
</div>
<div class="section" id="create-a-test-project">
<h2><a class="toc-backref" href="#id5">Create a Test Project</a><a class="headerlink" href="#create-a-test-project" title="Permalink to this headline"></a></h2>
<p>Now that you have your system setup, you can start building the application. First you want to create a project for yourself - since we’re eventually going to want to be able to access the data via Bluetooth, let’s use the <code class="docutils literal notranslate"><span class="pre">bleprph</span></code> Bluetooth Peripheral project as the project template.</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">[user@IsMyLaptop:~/src/air_quality]$ </span>mkdir<span class="w"> </span>apps/air_quality
<span class="gp">[user@IsMyLaptop:~/src/air_quality]$ </span>cp<span class="w"> </span>repos/apache-mynewt-core/apps/bleprph/pkg.yml<span class="w"> </span>apps/air_quality/
<span class="gp">[user@IsMyLaptop:~/src/air_quality]$ </span>cp<span class="w"> </span>-Rp<span class="w"> </span>repos/apache-mynewt-core/apps/bleprph/src<span class="w"> </span>apps/air_quality/
</pre></div>
</div>
<p>Modify the apps/air_quality/pkg.yml for air_quality in order to change the <em>pkg.name</em> to be <em>apps/air_quality</em>. You’ll need to add the <code class="docutils literal notranslate"><span class="pre">&#64;apache-mynewt-core/</span></code> path to all the package dependencies, since the app no longer resides within the apache-mynewt-core repository.</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">[user@IsMyLaptop:~/src/air_quality]$ </span>cat<span class="w"> </span>apps/air_quality/pkg.yml
<span class="go">pkg.name: apps/air_quality</span>
<span class="go">pkg.type: app</span>
<span class="go">pkg.description: BLE Air Quality application.</span>
<span class="go">pkg.author: &quot;Apache Mynewt &lt;dev@mynewt.apache.org&gt;&quot;</span>
<span class="go">pkg.homepage: &quot;http://mynewt.apache.org/&quot;</span>
<span class="go">pkg.keywords:</span>
<span class="go">pkg.deps:</span>
<span class="go"> - &quot;@apache-mynewt-core/boot/split&quot;</span>
<span class="go"> - &quot;@mcuboot/boot/bootutil&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/kernel/os&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/mgmt/imgmgr&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/mgmt/newtmgr&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/mgmt/newtmgr/transport/ble&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/net/nimble/controller&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/net/nimble/host&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/net/nimble/host/services/ans&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/net/nimble/host/services/gap&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/net/nimble/host/services/gatt&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/net/nimble/host/store/config&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/sys/console/full&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/sys/log/full&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/sys/stats/full&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/sys/sysinit&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/sys/id&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/net/nimble/transport/ram&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/sys/shell&quot;</span>
</pre></div>
</div>
<p>Next create a target for it:</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">[user@IsMyLaptop:~/src/air_quality]$ </span>newt<span class="w"> </span>target<span class="w"> </span>create<span class="w"> </span>air_q
<span class="go">Target targets/air_q successfully created</span>
<span class="gp">[user@IsMyLaptop:~/src/air_quality]$ </span>newt<span class="w"> </span>target<span class="w"> </span><span class="nb">set</span><span class="w"> </span>air_q<span class="w"> </span><span class="nv">bsp</span><span class="o">=</span>@apache-mynewt-core/hw/bsp/nrf52dk
<span class="go">Target targets/air_q successfully set target.bsp to @apache-mynewt-core/hw/bsp/nrf52dk</span>
<span class="gp">[user@IsMyLaptop:~/src/air_quality]$ </span>newt<span class="w"> </span>target<span class="w"> </span><span class="nb">set</span><span class="w"> </span>air_q<span class="w"> </span><span class="nv">app</span><span class="o">=</span>apps/air_quality
<span class="go">Target targets/air_q successfully set target.app to apps/air_quality</span>
<span class="gp">[user@IsMyLaptop:~/src/air_quality]$ </span>newt<span class="w"> </span>target<span class="w"> </span><span class="nb">set</span><span class="w"> </span>air_q<span class="w"> </span><span class="nv">build_profile</span><span class="o">=</span>debug
<span class="go">Target targets/air_q successfully set target.build_profile to debug</span>
<span class="gp">[user@IsMyLaptop:~/src/air_quality]$ </span>newt<span class="w"> </span>build<span class="w"> </span>air_q
<span class="go"> ....</span>
<span class="go">Linking /Users/users/dev/myproj/bin/targets/air_q/app/apps/air_quality/air_quality.elf</span>
<span class="go">Target successfully built: targets/air_q</span>
</pre></div>
</div>
</div>
<div class="section" id="create-packages-for-drivers">
<h2><a class="toc-backref" href="#id6">Create Packages For Drivers</a><a class="headerlink" href="#create-packages-for-drivers" title="Permalink to this headline"></a></h2>
<p>We need to enable the SenseAir K30 CO2 sensor, which will connect to the board over a serial port. To start development of the
driver, you first need to create a package description for it, and add stubs for sources.</p>
<p>The first thing to do is to create the directory structure for your
driver:</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">[user@IsMyLaptop:~/src/air_quality]$ </span>mkdir<span class="w"> </span>-p<span class="w"> </span>libs/my_drivers/senseair/include/senseair
<span class="gp">[user@IsMyLaptop:~/src/air_quality]$ </span>mkdir<span class="w"> </span>-p<span class="w"> </span>libs/my_drivers/senseair/src
</pre></div>
</div>
<p>Now you can add the files you need. You’ll need a <code class="docutils literal notranslate"><span class="pre">pkg.yml</span></code> to describe the driver, and then header stub followed by source stub.</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">[user@IsMyLaptop:~/src/air_quality]$ </span>cat<span class="w"> </span>libs/my_drivers/senseair/pkg.yml
</pre></div>
</div>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="cp">#</span>
<span class="cp"># Licensed to the Apache Software Foundation (ASF) under one</span>
<span class="cp"># or more contributor license agreements. See the NOTICE file</span>
<span class="cp"># distributed with this work for additional information</span>
<span class="cp"># regarding copyright ownership. The ASF licenses this file</span>
<span class="cp"># to you under the Apache License, Version 2.0 (the</span>
<span class="cp"># &quot;License&quot;); you may not use this file except in compliance</span>
<span class="cp"># with the License. You may obtain a copy of the License at</span>
<span class="cp">#</span>
<span class="cp"># http:</span><span class="c1">//www.apache.org/licenses/LICENSE-2.0</span>
<span class="cp">#</span>
<span class="cp"># Unless required by applicable law or agreed to in writing,</span>
<span class="cp"># software distributed under the License is distributed on an</span>
<span class="cp"># &quot;AS IS&quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY</span>
<span class="cp"># KIND, either express or implied. See the License for the</span>
<span class="cp"># specific language governing permissions and limitations</span>
<span class="cp"># under the License.</span>
<span class="cp">#</span>
<span class="n">pkg</span><span class="p">.</span><span class="n">name</span><span class="o">:</span><span class="w"> </span><span class="n">libs</span><span class="o">/</span><span class="n">my_drivers</span><span class="o">/</span><span class="n">senseair</span>
<span class="n">pkg</span><span class="p">.</span><span class="n">description</span><span class="o">:</span><span class="w"> </span><span class="n">Host</span><span class="w"> </span><span class="n">side</span><span class="w"> </span><span class="n">of</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">nimble</span><span class="w"> </span><span class="n">Bluetooth</span><span class="w"> </span><span class="n">Smart</span><span class="w"> </span><span class="n">stack</span><span class="p">.</span>
<span class="n">pkg</span><span class="p">.</span><span class="n">author</span><span class="o">:</span><span class="w"> </span><span class="s">&quot;Apache Mynewt &lt;dev@mynewt.apache.org&gt;&quot;</span>
<span class="n">pkg</span><span class="p">.</span><span class="n">homepage</span><span class="o">:</span><span class="w"> </span><span class="s">&quot;http://mynewt.apache.org/&quot;</span>
<span class="n">pkg</span><span class="p">.</span><span class="n">keywords</span><span class="o">:</span>
<span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">ble</span>
<span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">bluetooth</span>
<span class="n">pkg</span><span class="p">.</span><span class="n">deps</span><span class="o">:</span>
<span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="s">&quot;@apache-mynewt-core/kernel/os&quot;</span>
</pre></div>
</div>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">[user@IsMyLaptop:~/src/air_quality]$ </span>cat<span class="w"> </span>libs/my_drivers/senseair/include/senseair/senseair.h
</pre></div>
</div>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="cm">/*</span>
<span class="cm"> * Licensed to the Apache Software Foundation (ASF) under one</span>
<span class="cm"> * or more contributor license agreements. See the NOTICE file</span>
<span class="cm"> * distributed with this work for additional information</span>
<span class="cm"> * regarding copyright ownership. The ASF licenses this file</span>
<span class="cm"> * to you under the Apache License, Version 2.0 (the</span>
<span class="cm"> * &quot;License&quot;); you may not use this file except in compliance</span>
<span class="cm"> * with the License. You may obtain a copy of the License at</span>
<span class="cm"> *</span>
<span class="cm"> * http://www.apache.org/licenses/LICENSE-2.0</span>
<span class="cm"> *</span>
<span class="cm"> * Unless required by applicable law or agreed to in writing,</span>
<span class="cm"> * software distributed under the License is distributed on an</span>
<span class="cm"> * &quot;AS IS&quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY</span>
<span class="cm"> * KIND, either express or implied. See the License for the</span>
<span class="cm"> * specific language governing permissions and limitations</span>
<span class="cm"> * under the License.</span>
<span class="cm">*/</span>
<span class="cp">#ifndef _SENSEAIR_H_</span>
<span class="cp">#define _SENSEAIR_H_</span>
<span class="kt">void</span><span class="w"> </span><span class="nf">senseair_init</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span>
<span class="cp">#endif </span><span class="cm">/* _SENSEAIR_H_ */</span>
</pre></div>
</div>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">[user@IsMyLaptop:~/src/air_quality]$ </span>cat<span class="w"> </span>libs/my_drivers/senseair/src/senseair.c
</pre></div>
</div>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="cm">/**</span>
<span class="cm"> * Licensed to the Apache Software Foundation (ASF) under one</span>
<span class="cm"> * or more contributor license agreements. See the NOTICE file</span>
<span class="cm"> * distributed with this work for additional information</span>
<span class="cm"> * regarding copyright ownership. The ASF licenses this file</span>
<span class="cm"> * to you under the Apache License, Version 2.0 (the</span>
<span class="cm"> * &quot;License&quot;); you may not use this file except in compliance</span>
<span class="cm"> * with the License. You may obtain a copy of the License at</span>
<span class="cm"> *</span>
<span class="cm"> * http://www.apache.org/licenses/LICENSE-2.0</span>
<span class="cm"> *</span>
<span class="cm"> * Unless required by applicable law or agreed to in writing,</span>
<span class="cm"> * software distributed under the License is distributed on an</span>
<span class="cm"> * &quot;AS IS&quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY</span>
<span class="cm"> * KIND, either express or implied. See the License for the</span>
<span class="cm"> * specific language governing permissions and limitations</span>
<span class="cm"> * under the License.</span>
<span class="cm"> */</span>
<span class="kt">void</span>
<span class="nf">senseair_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
<span class="p">}</span>
</pre></div>
</div>
<p>And add a dependency to this package in your project.yml file.</p>
<p>Here’s the listing from apps/air_quality/pkg.yml:</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="go">pkg.name: apps/air_quality</span>
<span class="go">pkg.type: app</span>
<span class="go">pkg.description: Air quality sensor test</span>
<span class="go">pkg.keywords:</span>
<span class="go">pkg.deps:</span>
<span class="go"> - &quot;@apache-mynewt-core/boot/split&quot;</span>
<span class="go"> - &quot;@mcuboot/boot/bootutil&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/kernel/os&quot;</span>
<span class="go"> ....</span>
<span class="go"> - &quot;@apache-mynewt-core/sys/id&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/net/nimble/transport/ram&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/sys/shell&quot;</span>
<span class="go"> - libs/my_drivers/senseair</span>
</pre></div>
</div>
<p>Add a call to your <code class="docutils literal notranslate"><span class="pre">main()</span></code> to initialize this driver:</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">[user@IsMyLaptop:~/src/air_quality]$ </span>diff<span class="w"> </span>project/blinky/src/main.c<span class="w"> </span>project/air_quality/src/main.c
<span class="go">28a29</span>
<span class="go">&gt; #include &lt;senseair/senseair.h&gt;</span>
<span class="go">190a192</span>
<span class="go">&gt; senseair_init();</span>
<span class="go">[user@IsMyLaptop:~/src/air_quality</span>
</pre></div>
</div>
</div>
<div class="section" id="add-cli-commands-for-testing-drivers">
<h2><a class="toc-backref" href="#id7">Add CLI Commands For Testing Drivers</a><a class="headerlink" href="#add-cli-commands-for-testing-drivers" title="Permalink to this headline"></a></h2>
<p>While developing the driver, it would be helpful to issue operations from the console to verify the driver is responding correctly. Since the nRF52DK only has one UART, which will be used to connect to the CO2 sensor, the console we’ll use instead is the <a class="reference internal" href="../tooling/segger_rtt.html"><span class="doc">Segger RTT Console</span></a>. To configure this, make the following changes in your project’s <code class="docutils literal notranslate"><span class="pre">syscfg.yml</span></code> file:</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">[user@IsMyLaptop:~/src/air_quality]$ </span>cat<span class="w"> </span>targets/air_q/syscfg.yml
<span class="go">syscfg.vals:</span>
<span class="gp"> # </span>Enable<span class="w"> </span>the<span class="w"> </span>shell<span class="w"> </span>task.
<span class="go"> SHELL_TASK: 1</span>
<span class="gp"> # </span>Use<span class="w"> </span>the<span class="w"> </span>RTT<span class="w"> </span>Console
<span class="go"> CONSOLE_UART: 0</span>
<span class="go"> CONSOLE_RTT: 1</span>
</pre></div>
</div>
<p>Then register your senseair command with the shell by adding the following to <code class="docutils literal notranslate"><span class="pre">libs/my_drivers/senseair/src/senseair.c</span></code></p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;syscfg/syscfg.h&gt;</span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;shell/shell.h&gt;</span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;console/console.h&gt;</span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;assert.h&gt;</span>
<span class="k">static</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="nf">senseair_shell_func</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">argc</span><span class="p">,</span><span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="o">**</span><span class="n">argv</span><span class="p">);</span>
<span class="k">static</span><span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">shell_cmd</span><span class="w"> </span><span class="n">senseair_cmd</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="n">sc_cmd</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">&quot;senseair&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="p">.</span><span class="n">sc_cmd_func</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">senseair_shell_func</span><span class="p">,</span>
<span class="p">};</span>
<span class="kt">void</span>
<span class="nf">senseair_init</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">rc</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">shell_cmd_register</span><span class="p">(</span><span class="o">&amp;</span><span class="n">senseair_cmd</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="p">}</span>
<span class="k">static</span><span class="w"> </span><span class="kt">int</span>
<span class="nf">senseair_shell_func</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">argc</span><span class="p">,</span><span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="o">**</span><span class="n">argv</span><span class="p">)</span>
<span class="p">{</span>
<span class="w"> </span><span class="n">console_printf</span><span class="p">(</span><span class="s">&quot;Yay! Somebody called!</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">);</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<p>Build the target, create an image, and load it onto your board. Then run <code class="docutils literal notranslate"><span class="pre">telnet</span> <span class="pre">localhost</span> <span class="pre">19021</span></code> to start the RTT Console.</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">[user@IsMyLaptop:~]$ </span>telnet<span class="w"> </span>localhost<span class="w"> </span><span class="m">19021</span>
<span class="go">Trying 127.0.0.1...</span>
<span class="go">Connected to localhost.</span>
<span class="go">Escape character is &#39;^]&#39;.</span>
<span class="go">SEGGER J-Link V6.30j - Real time terminal output</span>
<span class="go">J-Link OB-SAM3U128-V2-NordicSemi compiled Jan 12 2018 16:05:20 V1.0, SN=682771074</span>
<span class="go">Process: JLinkGDBServerCLExe</span>
<span class="go">x03 0x03 0x11 0x18 0x0f 0x09 0x6e 0x69 0x6d 0x62 0x6c 0x65 0x2d 0x62 0x6c 0x65 0x70 0x72 0x70 0x68 0x02 0x0a 0x00 0x00 0x00 0x00 0x00 0x00</span>
<span class="go">000006 [ts=46872ssb, mod=4 level=0] Command complete: cmd_pkts=1 ogf=0x8 ocf=0x8 status=0</span>
<span class="go">000006 [ts=46872ssb, mod=4 level=1] GAP procedure initiated: advertise; disc_mode=2 adv_channel_map=0 own_addr_type=0 adv_filter_policy=0 adv_itvl_min=0 adv_itvl_max=0</span>
<span class="go">000006 [ts=46872ssb, mod=4 level=0] ble_hs_hci_cmd_send: ogf=0x08 ocf=0x0006 len=15</span>
<span class="go">000006 [ts=46872ssb, mod=4 level=0] 0x06 0x20 0x0f 0x30 0x00 0x60 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x07 0x00</span>
<span class="go">000006 [ts=46872ssb, mod=4 level=0] Command complete: cmd_pkts=1 ogf=0x8 ocf=0x6 status=0</span>
<span class="go">000006 [ts=46872ssb, mod=4 level=0] ble_hs_hci_cmd_send: ogf=0x08 ocf=0x000a len=1</span>
<span class="go">000006 [ts=46872ssb, mod=4 level=0] 0x0a 0x20 0x01 0x01</span>
<span class="go">000006 [ts=46872ssb, mod=4 level=0] Command complete: cmd_pkts=1 ogf=0x8 ocf=0xa status=0</span>
<span class="go">000006 [ts=46872ssb, mod=4 level=0] Command complete: cmd_pkts=1 ogf=0x0 ocf=0x0</span>
<span class="go">001215 compat&gt;</span>
<span class="go">001957 compat&gt; help</span>
<span class="go">help</span>
<span class="go">002162 help</span>
<span class="go">002162 tasks</span>
<span class="go">002162 mpool</span>
<span class="go">002162 date</span>
<span class="go">002162 senseair</span>
<span class="go">002162 compat&gt; senseair</span>
<span class="go">senseair</span>
<span class="go">002514 Yay! Somebody called!</span>
<span class="go">002514 compat&gt;</span>
</pre></div>
</div>
<p>If you can see the <code class="docutils literal notranslate"><span class="pre">senseair</span></code> command, and get the proper response, you can connect the hardware to your board and start
developing code for the driver itself.</p>
</div>
<div class="section" id="using-hal-for-drivers">
<h2><a class="toc-backref" href="#id8">Using HAL for Drivers</a><a class="headerlink" href="#using-hal-for-drivers" title="Permalink to this headline"></a></h2>
<p>We will connect the CO2 sensor using a serial port connection to the UART. We’ll also use the HAL UART abstraction to do the UART port setup and data transfer. That way you don’t need to have any platform dependent pieces within your little driver. Moreover, this also gives you the option to connect this sensor to another board, like Olimex or the Arduino Primo.</p>
<p>You will now see what the driver code ends up looking like. Here’s the header file, filled in from the stub you created earlier:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="cm">/*</span>
<span class="cm"> * Licensed to the Apache Software Foundation (ASF) under one</span>
<span class="cm"> * or more contributor license agreements. See the NOTICE file</span>
<span class="cm"> * distributed with this work for additional information</span>
<span class="cm"> * regarding copyright ownership. The ASF licenses this file</span>
<span class="cm"> * to you under the Apache License, Version 2.0 (the</span>
<span class="cm"> * &quot;License&quot;); you may not use this file except in compliance</span>
<span class="cm"> * with the License. You may obtain a copy of the License at</span>
<span class="cm"> *</span>
<span class="cm"> * http://www.apache.org/licenses/LICENSE-2.0</span>
<span class="cm"> *</span>
<span class="cm"> * Unless required by applicable law or agreed to in writing,</span>
<span class="cm"> * software distributed under the License is distributed on an</span>
<span class="cm"> * &quot;AS IS&quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY</span>
<span class="cm"> * KIND, either express or implied. See the License for the</span>
<span class="cm"> * specific language governing permissions and limitations</span>
<span class="cm"> * under the License.</span>
<span class="cm">*/</span>
<span class="cp">#ifndef _SENSEAIR_H_</span>
<span class="cp">#define _SENSEAIR_H_</span>
<span class="k">enum</span><span class="w"> </span><span class="n">senseair_read_type</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">SENSEAIR_CO2</span><span class="p">,</span>
<span class="p">};</span>
<span class="kt">int</span><span class="w"> </span><span class="nf">senseair_init</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">uartno</span><span class="p">);</span>
<span class="kt">int</span><span class="w"> </span><span class="nf">senseair_read</span><span class="p">(</span><span class="k">enum</span><span class="w"> </span><span class="n">senseair_read_type</span><span class="p">);</span>
<span class="cp">#endif </span><span class="cm">/* _SENSEAIR_H_ */</span>
</pre></div>
</div>
<p>As you can see, logical UART number has been added to the init routine. A ‘read’ function has also been added, which is a blocking read. If you were making a commercial product, you would probably have a callback for reporting the results.</p>
<p>And here is the source for the driver:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="cm">/**</span>
<span class="cm"> * Licensed to the Apache Software Foundation (ASF) under one</span>
<span class="cm"> * or more contributor license agreements. See the NOTICE file</span>
<span class="cm"> * distributed with this work for additional information</span>
<span class="cm"> * regarding copyright ownership. The ASF licenses this file</span>
<span class="cm"> * to you under the Apache License, Version 2.0 (the</span>
<span class="cm"> * &quot;License&quot;); you may not use this file except in compliance</span>
<span class="cm"> * with the License. You may obtain a copy of the License at</span>
<span class="cm"> *</span>
<span class="cm"> * http://www.apache.org/licenses/LICENSE-2.0</span>
<span class="cm"> *</span>
<span class="cm"> * Unless required by applicable law or agreed to in writing,</span>
<span class="cm"> * software distributed under the License is distributed on an</span>
<span class="cm"> * &quot;AS IS&quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY</span>
<span class="cm"> * KIND, either express or implied. See the License for the</span>
<span class="cm"> * specific language governing permissions and limitations</span>
<span class="cm"> * under the License.</span>
<span class="cm"> */</span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;string.h&gt;</span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;syscfg/syscfg.h&gt;</span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;shell/shell.h&gt;</span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;console/console.h&gt;</span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;os/os.h&gt;</span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;hal/hal_uart.h&gt;</span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf">&quot;senseair/senseair.h&quot;</span>
<span class="k">static</span><span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="kt">uint8_t</span><span class="w"> </span><span class="n">cmd_read_co2</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="mh">0xFE</span><span class="p">,</span><span class="w"> </span><span class="mh">0X44</span><span class="p">,</span><span class="w"> </span><span class="mh">0X00</span><span class="p">,</span><span class="w"> </span><span class="mh">0X08</span><span class="p">,</span><span class="w"> </span><span class="mh">0X02</span><span class="p">,</span><span class="w"> </span><span class="mh">0X9F</span><span class="p">,</span><span class="w"> </span><span class="mh">0X25</span>
<span class="p">};</span>
<span class="k">static</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="nf">senseair_shell_func</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">argc</span><span class="p">,</span><span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="o">**</span><span class="n">argv</span><span class="p">);</span>
<span class="k">static</span><span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">shell_cmd</span><span class="w"> </span><span class="n">senseair_cmd</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="n">sc_cmd</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">&quot;senseair&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="p">.</span><span class="n">sc_cmd_func</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">senseair_shell_func</span><span class="p">,</span>
<span class="p">};</span>
<span class="k">struct</span><span class="w"> </span><span class="nc">senseair</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">uart</span><span class="p">;</span>
<span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">os_sem</span><span class="w"> </span><span class="n">sema</span><span class="p">;</span>
<span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="kt">uint8_t</span><span class="w"> </span><span class="o">*</span><span class="n">tx_data</span><span class="p">;</span>
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">tx_off</span><span class="p">;</span>
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">tx_len</span><span class="p">;</span>
<span class="w"> </span><span class="kt">uint8_t</span><span class="w"> </span><span class="n">rx_data</span><span class="p">[</span><span class="mi">32</span><span class="p">];</span>
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">rx_off</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="p">}</span><span class="w"> </span><span class="n">senseair</span><span class="p">;</span>
<span class="k">static</span><span class="w"> </span><span class="kt">int</span>
<span class="nf">senseair_tx_char</span><span class="p">(</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="k">struct</span><span class="w"> </span><span class="nc">senseair</span><span class="w"> </span><span class="o">*</span><span class="n">s</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">&amp;</span><span class="n">senseair</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="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">s</span><span class="o">-&gt;</span><span class="n">tx_off</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="n">s</span><span class="o">-&gt;</span><span class="n">tx_len</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="cm">/*</span>
<span class="cm"> * Command tx finished.</span>
<span class="cm"> */</span>
<span class="w"> </span><span class="n">s</span><span class="o">-&gt;</span><span class="n">tx_data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">NULL</span><span class="p">;</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </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">rc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">s</span><span class="o">-&gt;</span><span class="n">tx_data</span><span class="p">[</span><span class="n">s</span><span class="o">-&gt;</span><span class="n">tx_off</span><span class="p">];</span>
<span class="w"> </span><span class="n">s</span><span class="o">-&gt;</span><span class="n">tx_off</span><span class="o">++</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="p">}</span>
<span class="cm">/*</span>
<span class="cm"> * CRC for modbus over serial port.</span>
<span class="cm"> */</span>
<span class="k">static</span><span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="kt">uint16_t</span><span class="w"> </span><span class="n">mb_crc_tbl</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="mh">0x0000</span><span class="p">,</span><span class="w"> </span><span class="mh">0xcc01</span><span class="p">,</span><span class="w"> </span><span class="mh">0xd801</span><span class="p">,</span><span class="w"> </span><span class="mh">0x1400</span><span class="p">,</span><span class="w"> </span><span class="mh">0xf001</span><span class="p">,</span><span class="w"> </span><span class="mh">0x3c00</span><span class="p">,</span><span class="w"> </span><span class="mh">0x2800</span><span class="p">,</span><span class="w"> </span><span class="mh">0xe401</span><span class="p">,</span>
<span class="w"> </span><span class="mh">0xa001</span><span class="p">,</span><span class="w"> </span><span class="mh">0x6c00</span><span class="p">,</span><span class="w"> </span><span class="mh">0x7800</span><span class="p">,</span><span class="w"> </span><span class="mh">0xb401</span><span class="p">,</span><span class="w"> </span><span class="mh">0x5000</span><span class="p">,</span><span class="w"> </span><span class="mh">0x9c01</span><span class="p">,</span><span class="w"> </span><span class="mh">0x8801</span><span class="p">,</span><span class="w"> </span><span class="mh">0x4400</span>
<span class="p">};</span>
<span class="k">static</span><span class="w"> </span><span class="kt">uint16_t</span>
<span class="nf">mb_crc</span><span class="p">(</span><span class="k">const</span><span class="w"> </span><span class="kt">uint8_t</span><span class="w"> </span><span class="o">*</span><span class="n">data</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">len</span><span class="p">,</span><span class="w"> </span><span class="kt">uint16_t</span><span class="w"> </span><span class="n">crc</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="n">len</span><span class="o">--</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">crc</span><span class="w"> </span><span class="o">^=</span><span class="w"> </span><span class="o">*</span><span class="n">data</span><span class="o">++</span><span class="p">;</span>
<span class="w"> </span><span class="n">crc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">crc</span><span class="w"> </span><span class="o">&gt;&gt;</span><span class="w"> </span><span class="mi">4</span><span class="p">)</span><span class="w"> </span><span class="o">^</span><span class="w"> </span><span class="n">mb_crc_tbl</span><span class="p">[</span><span class="n">crc</span><span class="w"> </span><span class="o">&amp;</span><span class="w"> </span><span class="mh">0xf</span><span class="p">];</span>
<span class="w"> </span><span class="n">crc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">crc</span><span class="w"> </span><span class="o">&gt;&gt;</span><span class="w"> </span><span class="mi">4</span><span class="p">)</span><span class="w"> </span><span class="o">^</span><span class="w"> </span><span class="n">mb_crc_tbl</span><span class="p">[</span><span class="n">crc</span><span class="w"> </span><span class="o">&amp;</span><span class="w"> </span><span class="mh">0xf</span><span class="p">];</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">crc</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">static</span><span class="w"> </span><span class="kt">int</span>
<span class="nf">mb_crc_check</span><span class="p">(</span><span class="k">const</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="o">*</span><span class="n">pkt</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">len</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">crc</span><span class="p">,</span><span class="w"> </span><span class="n">cmp</span><span class="p">;</span>
<span class="w"> </span><span class="kt">uint8_t</span><span class="w"> </span><span class="o">*</span><span class="n">bp</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="kt">uint8_t</span><span class="w"> </span><span class="o">*</span><span class="p">)</span><span class="n">pkt</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">len</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="k">sizeof</span><span class="p">(</span><span class="n">crc</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </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">crc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">mb_crc</span><span class="p">(</span><span class="n">pkt</span><span class="p">,</span><span class="w"> </span><span class="n">len</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="mh">0xffff</span><span class="p">);</span>
<span class="w"> </span><span class="n">cmp</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">bp</span><span class="p">[</span><span class="n">len</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="o">|</span><span class="w"> </span><span class="p">(</span><span class="n">bp</span><span class="p">[</span><span class="n">len</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">1</span><span class="p">]</span><span class="w"> </span><span class="o">&lt;&lt;</span><span class="w"> </span><span class="mi">8</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">crc</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="n">cmp</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">-1</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="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
<span class="k">static</span><span class="w"> </span><span class="kt">int</span>
<span class="nf">senseair_rx_char</span><span class="p">(</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="w"> </span><span class="kt">uint8_t</span><span class="w"> </span><span class="n">data</span><span class="p">)</span>
<span class="p">{</span>
<span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">senseair</span><span class="w"> </span><span class="o">*</span><span class="n">s</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">senseair</span><span class="w"> </span><span class="o">*</span><span class="p">)</span><span class="n">arg</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="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">s</span><span class="o">-&gt;</span><span class="n">rx_off</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="k">sizeof</span><span class="p">(</span><span class="n">s</span><span class="o">-&gt;</span><span class="n">rx_data</span><span class="p">))</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">s</span><span class="o">-&gt;</span><span class="n">rx_off</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="p">}</span>
<span class="w"> </span><span class="n">s</span><span class="o">-&gt;</span><span class="n">rx_data</span><span class="p">[</span><span class="n">s</span><span class="o">-&gt;</span><span class="n">rx_off</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">data</span><span class="p">;</span>
<span class="w"> </span><span class="n">s</span><span class="o">-&gt;</span><span class="n">rx_off</span><span class="o">++</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">s</span><span class="o">-&gt;</span><span class="n">rx_off</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">7</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">mb_crc_check</span><span class="p">(</span><span class="n">s</span><span class="o">-&gt;</span><span class="n">rx_data</span><span class="p">,</span><span class="w"> </span><span class="n">s</span><span class="o">-&gt;</span><span class="n">rx_off</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">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="p">{</span>
<span class="w"> </span><span class="n">s</span><span class="o">-&gt;</span><span class="n">value</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">s</span><span class="o">-&gt;</span><span class="n">rx_data</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mi">256</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">s</span><span class="o">-&gt;</span><span class="n">rx_data</span><span class="p">[</span><span class="mi">4</span><span class="p">];</span>
<span class="w"> </span><span class="n">os_sem_release</span><span class="p">(</span><span class="o">&amp;</span><span class="n">s</span><span class="o">-&gt;</span><span class="n">sema</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="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">void</span>
<span class="nf">senseair_tx</span><span class="p">(</span><span class="k">struct</span><span class="w"> </span><span class="nc">senseair</span><span class="w"> </span><span class="o">*</span><span class="n">s</span><span class="p">,</span><span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="kt">uint8_t</span><span class="w"> </span><span class="o">*</span><span class="n">tx_data</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">data_len</span><span class="p">)</span>
<span class="p">{</span>
<span class="w"> </span><span class="n">s</span><span class="o">-&gt;</span><span class="n">tx_data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">tx_data</span><span class="p">;</span>
<span class="w"> </span><span class="n">s</span><span class="o">-&gt;</span><span class="n">tx_len</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">data_len</span><span class="p">;</span>
<span class="w"> </span><span class="n">s</span><span class="o">-&gt;</span><span class="n">tx_off</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">s</span><span class="o">-&gt;</span><span class="n">rx_off</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">hal_uart_start_tx</span><span class="p">(</span><span class="n">s</span><span class="o">-&gt;</span><span class="n">uart</span><span class="p">);</span>
<span class="p">}</span>
<span class="kt">int</span>
<span class="nf">senseair_read</span><span class="p">(</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="p">)</span>
<span class="p">{</span>
<span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">senseair</span><span class="w"> </span><span class="o">*</span><span class="n">s</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">&amp;</span><span class="n">senseair</span><span class="p">;</span>
<span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="kt">uint8_t</span><span class="w"> </span><span class="o">*</span><span class="n">cmd</span><span class="p">;</span>
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">cmd_len</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="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">s</span><span class="o">-&gt;</span><span class="n">tx_data</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="cm">/*</span>
<span class="cm"> * busy</span>
<span class="cm"> */</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">-1</span><span class="p">;</span>
<span class="w"> </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">type</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">SENSEAIR_CO2</span><span class="p">:</span>
<span class="w"> </span><span class="n">cmd</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">cmd_read_co2</span><span class="p">;</span>
<span class="w"> </span><span class="n">cmd_len</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">sizeof</span><span class="p">(</span><span class="n">cmd_read_co2</span><span class="p">);</span>
<span class="w"> </span><span class="k">break</span><span class="p">;</span>
<span class="w"> </span><span class="k">default</span><span class="o">:</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </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">senseair_tx</span><span class="p">(</span><span class="n">s</span><span class="p">,</span><span class="w"> </span><span class="n">cmd</span><span class="p">,</span><span class="w"> </span><span class="n">cmd_len</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_sem_pend</span><span class="p">(</span><span class="o">&amp;</span><span class="n">s</span><span class="o">-&gt;</span><span class="n">sema</span><span class="p">,</span><span class="w"> </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="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">rc</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="n">OS_TIMEOUT</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="cm">/*</span>
<span class="cm"> * timeout</span>
<span class="cm"> */</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">-2</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">s</span><span class="o">-&gt;</span><span class="n">value</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">static</span><span class="w"> </span><span class="kt">int</span>
<span class="nf">senseair_shell_func</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">argc</span><span class="p">,</span><span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="o">**</span><span class="n">argv</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="p">;</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">argc</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="mi">2</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="nl">usage</span><span class="p">:</span>
<span class="w"> </span><span class="n">console_printf</span><span class="p">(</span><span class="s">&quot;%s co2</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">argv</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="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="o">!</span><span class="n">strcmp</span><span class="p">(</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span><span class="w"> </span><span class="s">&quot;co2&quot;</span><span class="p">))</span><span class="w"> </span><span class="p">{</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="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="k">goto</span><span class="w"> </span><span class="n">usage</span><span class="p">;</span>
<span class="w"> </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="p">}</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">int</span>
<span class="nf">senseair_init</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">uartno</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">rc</span><span class="p">;</span>
<span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">senseair</span><span class="w"> </span><span class="o">*</span><span class="n">s</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">&amp;</span><span class="n">senseair</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">shell_cmd_register</span><span class="p">(</span><span class="o">&amp;</span><span class="n">senseair_cmd</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">rc</span><span class="p">)</span><span class="w"> </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="n">rc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">os_sem_init</span><span class="p">(</span><span class="o">&amp;</span><span class="n">s</span><span class="o">-&gt;</span><span class="n">sema</span><span class="p">,</span><span class="w"> </span><span class="mi">1</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">rc</span><span class="p">)</span><span class="w"> </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="n">rc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">hal_uart_init_cbs</span><span class="p">(</span><span class="n">uartno</span><span class="p">,</span><span class="w"> </span><span class="n">senseair_tx_char</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">senseair_rx_char</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="n">senseair</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">rc</span><span class="p">)</span><span class="w"> </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="n">rc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">hal_uart_config</span><span class="p">(</span><span class="n">uartno</span><span class="p">,</span><span class="w"> </span><span class="mi">9600</span><span class="p">,</span><span class="w"> </span><span class="mi">8</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">HAL_UART_PARITY_NONE</span><span class="p">,</span>
<span class="w"> </span><span class="n">HAL_UART_FLOW_CTL_NONE</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">rc</span><span class="p">)</span><span class="w"> </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="n">s</span><span class="o">-&gt;</span><span class="n">uart</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">uartno</span><span class="p">;</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<p>And your modified main() for senseair driver init.</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="kt">int</span>
<span class="nf">main</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">argc</span><span class="p">,</span><span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="o">**</span><span class="n">argv</span><span class="p">)</span>
<span class="p">{</span>
<span class="w"> </span><span class="p">....</span>
<span class="w"> </span><span class="n">senseair_init</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
<span class="w"> </span><span class="p">....</span>
<span class="w"> </span><span class="p">}</span>
</pre></div>
</div>
<p>You can see from the code that you are using the HAL interface to open a UART port, and using OS semaphore as a way of blocking the task when waiting for read response to come back from the sensor.</p>
<p>Now comes the fun part: Hooking up the sensor! It’s fun because a) hooking up a sensor is always fun and b) the SenseAir sensor’s PCB is entirely unlabeled, so you’ll have to trust us on how to hook it up.</p>
<p>You’ll have to do a little soldering. I soldered some header pins to the SenseAir K30 board to make connecting wires easier using standard jumper wires, but you can also just solder wires straight to the board if you prefer.</p>
<p>Here’s what your SenseAir board should look like once it’s wired up:</p>
<div class="figure align-default" id="id1">
<img alt="SenseAir Wiring" src="../../_images/K30labeled.JPG" />
<p class="caption"><span class="caption-text">SenseAir Wiring</span><a class="headerlink" href="#id1" title="Permalink to this image"></a></p>
</div>
<p>Now that you have that wired up, let’s connect it to the nRF52DK board. Since we will be using the built-in UART, we can simply connect it to the pre-configured pins for TX (P.06) and RX (P.08). Here’s what your board should look like once everything is connected:</p>
<div class="figure align-default" id="id2">
<img alt="SenseAir and nRF52DK Wiring" src="../../_images/nrf52labeled.JPG" />
<p class="caption"><span class="caption-text">SenseAir and nRF52DK Wiring</span><a class="headerlink" href="#id2" title="Permalink to this image"></a></p>
</div>
<p>Everything is wired and you’re ready to go! Build and load your new app:</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>newt<span class="w"> </span>build<span class="w"> </span>air_q
<span class="go">Building target targets/air_q</span>
<span class="go">Compiling apps/air_quality/src/main.c</span>
<span class="go">Archiving apps_air_quality.a</span>
<span class="go">Linking myproj/bin/targets/air_q/app/apps/air_quality/air_quality.elf</span>
<span class="go">Target successfully built: targets/air_q</span>
<span class="gp">$ </span>newt<span class="w"> </span>create-image<span class="w"> </span>air_q<span class="w"> </span><span class="m">1</span>.0.0
<span class="go">App image succesfully generated: myproj/bin/targets/air_q/app/apps/air_quality/air_quality.img</span>
<span class="gp">$ </span>newt<span class="w"> </span>load<span class="w"> </span>air_q
<span class="go">Loading app image into slot 1</span>
</pre></div>
</div>
<p>Now, you should be able to connect to your serial port and read values:</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">user@IsMyLaptop:~]$ </span>telnet<span class="w"> </span>localhost<span class="w"> </span><span class="m">19021</span>
<span class="go">Trying 127.0.0.1...</span>
<span class="go">Connected to localhost.</span>
<span class="go">Escape character is &#39;^]&#39;.</span>
<span class="go">SEGGER J-Link V6.30j - Real time terminal output</span>
<span class="go">J-Link OB-SAM3U128-V2-NordicSemi compiled Jan 12 2018 16:05:20 V1.0, SN=682771074</span>
<span class="go">Process: JLinkGDBServerCLExe</span>
<span class="go">x03 0x03 0x11 0x18 0x0f 0x09 0x6e 0x69 0x6d 0x62 0x6c 0x65 0x2d 0x62 0x6c 0x65 0x70 0x72 0x70 0x68 0x02 0x0a 0x00 0x00 0x00 0x00 0x00 0x00</span>
<span class="go">000006 [ts=46872ssb, mod=4 level=0] Command complete: cmd_pkts=1 ogf=0x8 ocf=0x8 status=0</span>
<span class="go">000006 [ts=46872ssb, mod=4 level=1] GAP procedure initiated: advertise; disc_mode=2 adv_channel_map=0 own_addr_type=0 adv_filter_policy=0 adv_itvl_min=0 adv_itvl_max=0</span>
<span class="go">000006 [ts=46872ssb, mod=4 level=0] ble_hs_hci_cmd_send: ogf=0x08 ocf=0x0006 len=15</span>
<span class="go">000006 [ts=46872ssb, mod=4 level=0] 0x06 0x20 0x0f 0x30 0x00 0x60 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x07 0x00</span>
<span class="go">000006 [ts=46872ssb, mod=4 level=0] Command complete: cmd_pkts=1 ogf=0x8 ocf=0x6 status=0</span>
<span class="go">000006 [ts=46872ssb, mod=4 level=0] ble_hs_hci_cmd_send: ogf=0x08 ocf=0x000a len=1</span>
<span class="go">000006 [ts=46872ssb, mod=4 level=0] 0x0a 0x20 0x01 0x01</span>
<span class="go">000007 [ts=54684ssb, mod=4 level=0] Command complete: cmd_pkts=1 ogf=0x8 ocf=0xa status=0</span>
<span class="go">000007 [ts=54684ssb, mod=4 level=0] Command complete: cmd_pkts=1 ogf=0x0 ocf=0x0</span>
<span class="go">000895 compat&gt;</span>
<span class="go">000998 compat&gt; help</span>
<span class="go">help</span>
<span class="go">001414 help</span>
<span class="go">001414 tasks</span>
<span class="go">001414 mpool</span>
<span class="go">001414 date</span>
<span class="go">001414 senseair</span>
<span class="go">001414 compat&gt; senseair</span>
<span class="go">senseair</span>
<span class="go">001714 senseair co2</span>
<span class="go">001714 compat&gt; senseair co2</span>
<span class="go">senseair co2</span>
<span class="go">002098 Got 0</span>
<span class="go">002098 compat&gt; senseair co2</span>
<span class="go">senseair co2</span>
<span class="go">002719 Got 1168</span>
</pre></div>
</div>
<p>And you’re getting valid readings! Congratulations!</p>
<p>Next we’ll hook this all up via Bluetooth so that you can read those
values remotely.</p>
</div>
</div>
</div>
</div>
<div class="rst-footer-buttons row" role="navigation" aria-label="footer navigation">
<a href="air_quality_ble.html" class="btn btn-neutral float-right" title="Air Quality Sensor Project via Bluetooth" accesskey="n">Next: Air Quality Sensor Project via Bluetooth <span class="fa fa-arrow-circle-right"></span></a>
<a href="air_quality.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>