blob: 00ea5991ff9265128bec5a6730aab8069bddf1c1 [file] [log] [blame]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- This is broken by doc revisioning.
-->
<link rel="shortcut icon" href="../../../img/favicon.ico">
<title>Add an Analog Sensor - Apache Mynewt</title>
<link href="../../../css/bootstrap-3.0.3.min.css" rel="stylesheet">
<link rel="stylesheet" href="../../../css/highlight.css">
<link href="../../../css/base.css" rel="stylesheet">
<link href="../../../css/custom.css" rel="stylesheet">
<link href="../../../css/v2.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Lato" rel="stylesheet">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css">
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
<script src="https://oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
<![endif]-->
<script>
(function(i, s, o, g, r, a, m) {
i["GoogleAnalyticsObject"] = r;
(i[r] =
i[r] ||
function() {
(i[r].q = i[r].q || []).push(arguments);
}),
(i[r].l = 1 * new Date());
(a = s.createElement(o)), (m = s.getElementsByTagName(o)[0]);
a.async = 1;
a.src = g;
m.parentNode.insertBefore(a, m);
})(window, document, "script", "//www.google-analytics.com/analytics.js", "ga");
ga("create", "UA-72162311-1", "auto");
ga("send", "pageview");
</script>
</head>
<body class="Add an Analog Sensor">
<div class="container">
<div class="row v2-main-banner">
<a class="logo-cell" href="/">
<img class="logo" src="/img/logo.png">
</a>
<div class="tagline-cell">
<h4 class="tagline">An OS to build, deploy and securely manage billions of devices</h4>
</div>
<div class="news-cell">
<div class="well">
<h4>Latest News:</h4> <a href="/download">Apache Mynewt 1.12.0, Apache NimBLE 1.7.0 </a> released (April 4, 2024)
</div>
</div>
</div>
</div>
<nav id="navbar" class="navbar navbar-inverse affix-top" data-spy="affix" data-offset-top="150" role="navigation">
<div class="container">
<!-- Collapsed navigation -->
<div class="navbar-header">
<!-- Expander button -->
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
</div>
<!-- Expanded navigation -->
<div class="navbar-collapse collapse">
<!-- Main navigation -->
<ul class="nav navbar-nav navbar-right">
<li
class=""
>
<a href="/"><i class="fa fa-home" style="font-size: larger;"></i></a>
</li>
<li
class="important"
>
<a href="/quick-start/">Quick Start</a>
</li>
<li
class=""
>
<a href="/about/">About</a>
</li>
<li
class=""
>
<a href="/talks/">Talks</a>
</li>
<li
class="active"
>
<a href="/documentation/">Documentation</a>
</li>
<li
class=""
>
<a href="/download/">Download</a>
</li>
<li
class=""
>
<a href="/community/">Community</a>
</li>
<li
class=""
>
<a href="/events/">Events</a>
</li>
</ul>
</div>
</div>
</nav>
<div class="container">
<div class="row">
<div class="col-md-3 v2-sidebar sidebar-container"><div id="docSidebar" class="hidden-print" role="complementary">
<div class="top">
<div role="search">
<form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get">
<div class="form-group">
<input type="text" name="q" class="form-control" placeholder="Search documentation" />
</div>
</form>
</div>
</div>
<ul class="toc-nav">
<li class="doc-version"><select class="form-control" onchange="if (this.value) window.location.href=this.value">
<option value="/latest">
Version: master
</option>
<option value="/v1_12_0/" >
Version: 1.12.0
</option>
<option value="/v1_11_0/" >
Version: 1.11.0
</option>
<option value="/v1_10_0/" >
Version: 1.10.0
</option>
<option value="/v1_9_0/" >
Version: 1.9.0
</option>
<option value="/v1_8_0/" >
Version: 1.8.0
</option>
<option value="/v1_7_0/" >
Version: 1.7.0
</option>
<option value="/v1_6_0/" >
Version: 1.6.0
</option>
<option value="/v1_5_0/" >
Version: 1.5.0
</option>
<option value="/v1_4_0/" >
Version: 1.4.0
</option>
<option value="/v1_3_0/os/introduction" >
Version: 1.3.0
</option>
<option value="/v1_2_0/os/introduction" >
Version: 1.2.0
</option>
<option value="/v1_1_0/os/introduction" >
Version: 1.1.0
</option>
<option value="/v1_0_0/os/introduction" selected="selected" >
Version: 1.0.0
</option>
<option value="/v0_9_0/os/introduction" >
Version: 0.9.0
</option>
</select></li>
<li ><a href="../../introduction/">Mynewt Documentation</a>
<ul>
<li ><a href="../../get_started/get_started/">Basic Setup</a>
</li>
<li >
<a href="../../get_started/vocabulary/">Concepts</a>
</li>
<li ><a href="../tutorials/">Tutorials</a>
<ul>
<li ><a href="../blinky/">Project Blinky</a>
</li>
<li ><a href="../repo/add_repos/">Work with repositories</a>
</li>
<li ><a href="../project-slinky/">Project Slinky for Remote Comms</a>
</li>
<li >
<a href="../ibeacon/">BLE iBeacon</a>
</li>
<li >
<a href="../eddystone/">BLE Eddystone</a>
</li>
<li >
<a href="../add_newtmgr/">Enable Newt Manager in any app</a>
</li>
<li >
<a href="../add_shell/">Enable the OS Shell and Console</a>
</li>
<li >
<a href="../tasks_lesson/">Tasks and Priority Management</a>
</li>
<li >
<a href="../wi-fi_on_arduino/">Enable Wi-Fi on Arduino MKR1000</a>
</li>
<li >
<a href="../unit_test/">Write a Test Suite for a Package</a>
</li>
<li >
<a href="../event_queue/">Events and Event Queues</a>
</li>
<li >
<a href="../bletiny_project/">BLE app to check stats via console</a>
</li>
<li ><a href="../bleprph/bleprph-intro/">BLE peripheral project</a>
</li>
<li >
<a href="../blehci_project/">BLE HCI interface</a>
</li>
<li><a href="
../air_quality_sensor/
">Air-quality Sensor project</a>
</li>
<li class="active">
<a href="./">Add an Analog Sensor</a>
</li>
</ul>
</li>
<li ><a href="../../os_user_guide/">OS User Guide</a>
</li>
<li><a href="
../../../network/ble/ble_intro/
">BLE User Guide</a>
</li>
<li ><a href="../../../newt/newt_intro/">Newt Tool Guide</a>
</li>
<li ><a href="../../../newtmgr/overview/">Newt Manager Guide</a>
</li>
<li >
<a href="../../../known_issues/">Known Issues</a>
</li>
</ul>
</li>
<li><a href="
../../../faq/go_env/
">Appendix</a>
</li>
</ul>
</div></div>
<div class="col-md-9" role="main">
<div class="doc-header">
<div role="navigation" aria-label="breadcrumbs navigation">
<ul class="wy-breadcrumbs">
<li><a href="/documentation/">Docs</a></li>
<li>&raquo; <a href="os/tutorials/tutorials/">Tutorials</a></li>
<li>&raquo; <a href="os/introduction/">Mynewt Documentation</a></li>
<li>&raquo; Add an Analog Sensor</li>
</ul>
</div>
</div>
<div class="alert alert-warning">
<p>
Version 1.0.0 is not the most recent version of the Apache Mynewt
documentation. Click <a href="/latest">here</a> to read the latest
version.
</p>
</div>
<h2 id="adding-an-analog-sensor-on-nrf52">Adding an Analog Sensor on nRF52</h2>
<p><br></p>
<h3 id="objective">Objective</h3>
<p>We will be adding an analog sensor to the NRF52DK development board and using the Analog to Digital Converter
(ADC) to read the values from the sensor. It's also using Bluetooth to allow you to connect to the app and
read the value of the sensor. Please see the following section for the required hardware
in order to complete this tutorial.</p>
<p><br></p>
<h3 id="hardware-needed">Hardware needed</h3>
<ul>
<li>nRF52 Development Kit (one of the following)<ul>
<li>Dev Kit from Nordic - PCA 10040</li>
<li>Eval Kit from Rigado - BMD-300-EVAL-ES</li>
</ul>
</li>
<li>eTape Liquid Sensor -- buy from <a href="https://www.adafruit.com/products/1786">Adafruit</a></li>
<li>Laptop running Mac OS</li>
<li>It is assumed you have already installed newt tool. </li>
<li>It is assumed you already installed native tools as described <a href="../../get_started/native_tools/">here</a></li>
</ul>
<p><br></p>
<h3 id="create-a-project">Create a project.</h3>
<p>Create a new project to hold your work. For a deeper understanding, you can read about project creation in
<a href="../../get_started/project_create/">Get Started -- Creating Your First Project</a>
or just follow the commands below.</p>
<div class="codehilite" style="background: #ffffff"><pre style="line-height: 125%;"><span></span><code> $ mkdir ~/dev
$ cd ~/dev
$ newt new myadc
Downloading project skeleton from apache/incubator-mynewt-blinky...
Installing skeleton in myadc...
Project myadc successfully created.
$ cd myadc
</code></pre></div>
<p><br></p>
<h3 id="add-additional-repositories">Add Additional Repositories</h3>
<p>The board-specific libraries for the NRF52dk board are in an external repository at present, so
you'll need to include that remote repository and install it as well. If you're not familiar
with using repositories, see the section on <a href="../repo/add_repos/">repositories</a> before
continuing. Or just copy and paste the following.</p>
<p>In your <code>project.yml</code> file, add <code>mynewt_nordic</code> to the <code>project.repositories</code> section, and
then add the proper repository definition. When you're done, your <code>project.yml</code> file
should look like this:</p>
<div class="codehilite" style="background: #ffffff"><pre style="line-height: 125%;"><span></span><code>project.name: &quot;my_project&quot;
project.repositories:
- apache-mynewt-core
<span style="background-color: #ffffcc"> - mynewt_nordic
</span>
# Use github&#39;s distribution mechanism for core ASF libraries.
# This provides mirroring automatically for us.
#
repository.apache-mynewt-core:
type: github
vers: 1-latest
user: apache
repo: incubator-mynewt-core
<span style="background-color: #ffffcc">repository.mynewt_nordic:
</span><span style="background-color: #ffffcc"> type: github
</span><span style="background-color: #ffffcc"> vers: 1-latest
</span><span style="background-color: #ffffcc"> user: runtimeco
</span><span style="background-color: #ffffcc"> repo: mynewt_nordic
</span></code></pre></div>
<p><br></p>
<h3 id="install-everything">Install Everything</h3>
<p>Now that you have defined the needed repositories, it's time to install everything so
that you can get started.</p>
<div class="codehilite" style="background: #ffffff"><pre style="line-height: 125%;"><span></span><code> $ newt install -v
apache-mynewt-core
Downloading repository description for apache-mynewt-core... success!
...
apache-mynewt-core successfully installed version 0.9.0-none
...
mynewt_nordic
Downloading repository description for mynewt_nordic... success!
...
mynewt_nordic successfully installed version 0.9.9-none
</code></pre></div>
<p><br></p>
<h3 id="create-the-targets">Create the targets</h3>
<p>Create two targets - one for the bootloader and one for the nrf52 board. </p>
<p><font color="#F2853F">
Note: The correct bsp must be chosen for the board you are using. </font></p>
<ul>
<li>For the Nordic Dev Kit choose @apache-mynewt-core/hw/bsp/nrf52dk instead (in the highlighted lines)</li>
<li>For the Rigado Eval Kit choose @apache-mynewt-core/hw/bsp/bmd300eval instead (in the highlighted lines)</li>
</ul>
<p>For the app itself we're going to extend the <a href="belpprph/bleprph-app.md">bleprph</a> app so that we
get the Bluetooth communications built in, so the first thing we'll need to do is copy that app
into our own app directory:</p>
<div class="codehilite" style="background: #ffffff"><pre style="line-height: 125%;"><span></span><code>$ mkdir -p apps/nrf52_adc
$ cp -Rp repos/apache-mynewt-core/apps/bleprph/* apps/nrf52_adc
</code></pre></div>
<p>Next, you'll modify the <code>pkg.yml</code> file for your app. Note the change in <code>pkg.name</code> and <code>pkg.description</code>. Also make sure that you specify the full path of all the packages with the prefix <code>@apache-mynewt-core/</code> as shown in the third highlighted line.</p>
<div class="codehilite" style="background: #ffffff"><pre style="line-height: 125%;"><span></span><code>$ cat apps/nrf52_adc/pkg.yml
...
<span style="background-color: #ffffcc">pkg.name: apps/nrf52_adc
</span>pkg.type: app
<span style="background-color: #ffffcc">pkg.description: Simple BLE peripheral application for ADC Sensors.
</span>pkg.author: &quot;Apache Mynewt &lt;dev@mynewt.incubator.apache.org&gt;&quot;
pkg.homepage: &quot;http://mynewt.apache.org/&quot;
pkg.keywords:
pkg.deps:
<span style="background-color: #ffffcc"> - &quot;@apache-mynewt-core/boot/split&quot;
</span> - &quot;@apache-mynewt-core/kernel/os&quot;
- &quot;@apache-mynewt-core/mgmt/imgmgr&quot;
- &quot;@apache-mynewt-core/mgmt/newtmgr&quot;
- &quot;@apache-mynewt-core/mgmt/newtmgr/transport/ble&quot;
- &quot;@apache-mynewt-core/net/nimble/controller&quot;
- &quot;@apache-mynewt-core/net/nimble/host&quot;
- &quot;@apache-mynewt-core/net/nimble/host/services/ans&quot;
- &quot;@apache-mynewt-core/net/nimble/host/services/gap&quot;
- &quot;@apache-mynewt-core/net/nimble/host/services/gatt&quot;
- &quot;@apache-mynewt-core/net/nimble/host/store/ram&quot;
- &quot;@apache-mynewt-core/net/nimble/transport/ram&quot;
- &quot;@apache-mynewt-core/sys/console/full&quot;
- &quot;@apache-mynewt-core/sys/log/full&quot;
- &quot;@apache-mynewt-core/sys/stats/full&quot;
- &quot;@apache-mynewt-core/sys/sysinit&quot;
- &quot;@apache-mynewt-core/sys/id&quot;
</code></pre></div>
<p>Great! We have our very own app so let's make sure we have all of our targets set
correctly:</p>
<div class="codehilite" style="background: #ffffff"><pre style="line-height: 125%;"><span></span><code>$ newt target create nrf52_adc
$ newt target set nrf52_adc app=apps/nrf52_adc
<span style="background-color: #ffffcc">Target targets/nrf52_adc successfully set target.app to apps/nrf52_adc
</span>$ newt target set nrf52_adc bsp=@apache-mynewt-core/hw/bsp/nrf52dk
$ newt target set nrf52_adc build_profile=debug
$ newt target create nrf52_boot
<span style="background-color: #ffffcc">$ newt target set nrf52_boot app=@apache-mynewt-core/apps/boot
</span>$ newt target set nrf52_boot bsp=@apache-mynewt-core/hw/bsp/nrf52dk
$ newt target set nrf52_boot build_profile=optimized
$ newt target show
targets/nrf52_adc
app=apps/nrf52_adc
bsp=@apache-mynewt-core/hw/bsp/nrf52dk
build_profile=debug
targets/nrf52_boot
app=@apache-mynewt-core/apps/boot
bsp=@apache-mynewt-core/hw/bsp/nrf52dk
build_profile=optimized
</code></pre></div>
<p><font color="#F2853F">
Note: If you've already built and installed a bootloader for your NRF52dk then you do
not need to create a target for it here, or build and load it as below. </font>
<br></p>
<h3 id="build-the-target-executables">Build the target executables</h3>
<div class="codehilite" style="background: #ffffff"><pre style="line-height: 125%;"><span></span><code>$ newt build nrf52_boot
...
Compiling boot.c
Archiving boot.a
Linking boot.elf
App successfully built: ~/dev/myadc/bin/nrf52_boot/apps/boot/boot.elf
</code></pre></div>
<div class="codehilite" style="background: #ffffff"><pre style="line-height: 125%;"><span></span><code>$ newt build nrf52_adc
...
Compiling main.c
Archiving nrf52_adc.a
Linking nrf52_adc.elf
App successfully built: ~/dev/myadc/bin/nrf52_adc/apps/nrf52_adc/nrf52_adc.elf
</code></pre></div>
<p><br></p>
<h3 id="sign-and-create-the-nrf52_adc-application-image">Sign and create the nrf52_adc application image</h3>
<p>You must sign and version your application image to download it using newt to the board.
Use the newt create-image command to perform this action. You may assign an arbitrary
version (e.g. 1.0.0) to the image.</p>
<div class="codehilite" style="background: #ffffff"><pre style="line-height: 125%;"><span></span><code>$ newt create-image nrf52_adc 1.0.0
App image successfully generated: ~/dev/myadc/bin/nrf52_adc/apps/nrf52_adc/nrf52_adc.img
Build manifest: ~/dev/myadc/bin/nrf52_adc/apps/nrf52_adc/manifest.json
</code></pre></div>
<p><br></p>
<h3 id="connect-the-board">Connect the board</h3>
<p>Connect the evaluation board via micro-USB to your PC via USB cable.</p>
<p><br></p>
<h3 id="download-to-the-target">Download to the target</h3>
<p>Download the bootloader first and then the nrf52_adc executable to the target platform.
Don't forget to reset the board if you don't see the LED blinking right away!</p>
<div class="codehilite" style="background: #ffffff"><pre style="line-height: 125%;"><span></span><code>$ newt load nrf52_boot
$ newt load nrf52_adc
</code></pre></div>
<p><br></p>
<p><strong>Note:</strong> If you want to erase the flash and load the image again, you can use JLinkExe to issue an <code>erase</code> command.</p>
<div class="codehilite" style="background: #ffffff"><pre style="line-height: 125%;"><span></span><code>$ JLinkExe -device nRF52 -speed 4000 -if SWD
SEGGER J-Link Commander V5.12c (Compiled Apr 21 2016 16:05:51)
DLL version V5.12c, compiled Apr 21 2016 16:05:45
Connecting to J-Link via USB...O.K.
Firmware: J-Link OB-SAM3U128-V2-NordicSemi compiled Mar 15 2016 18:03:17
Hardware version: V1.00
S/N: 682863966
VTref = 3.300V
Type &quot;connect&quot; to establish a target connection, &#39;?&#39; for help
J-Link&gt;erase
Cortex-M4 identified.
Erasing device (0;?i?)...
Comparing flash [100%] Done.
Erasing flash [100%] Done.
Verifying flash [100%] Done.
J-Link: Flash download: Total time needed: 0.363s (Prepare: 0.093s, Compare: 0.000s, Erase: 0.262s, Program: 0.000s, Verify: 0.000s, Restore: 0.008s)
Erasing done.
J-Link&gt;exit
$
</code></pre></div>
<p><br></p>
<p>So you have a BLE app, but really all you've done is change the name of the <strong>bleprph</strong> app to <strong>nrf52_adc</strong> and load that.
Not all that impressive, and it certainly won't read an Analog Sensor right now. So let's do that next. In order to
read an ADC sensor, and since the ADC package is in an external, licensed, repository, we'll create a driver for it
here in our app that will leverage the existing driver in the external repository. It adds another layer of
indirection, but it will also give us a look at building our own driver, so we'll do it this way. </p>
<p><br></p>
<h3 id="building-a-driver">Building a Driver</h3>
<p>The first thing to do is to create the directory structure for your driver:</p>
<div class="codehilite" style="background: #ffffff"><pre style="line-height: 125%;"><span></span><code>[user@IsMyLaptop:~/src/air_quality]$ mkdir -p libs/my_drivers/myadc/include/myadc
[user@IsMyLaptop:~/src/air_quality]$ mkdir -p libs/my_drivers/myadc/src
</code></pre></div>
<p>Now you can add the files you need. You'll need a pkg.yml to describe the driver, and then header stub followed by source stub.</p>
<div class="codehilite" style="background: #ffffff"><pre style="line-height: 125%;"><span></span><code>[user@IsMyLaptop:~/src/air_quality]$ cat libs/my_drivers/myadc/pkg.yml
</code></pre></div>
<div class="codehilite" style="background: #ffffff"><pre style="line-height: 125%;"><span></span><code><span style="color: #633820">#</span>
<span style="color: #633820"># Licensed to the Apache Software Foundation (ASF) under one</span>
<span style="color: #633820"># or more contributor license agreements. See the NOTICE file</span>
<span style="color: #633820"># distributed with this work for additional information</span>
<span style="color: #633820"># regarding copyright ownership. The ASF licenses this file</span>
<span style="color: #633820"># to you under the Apache License, Version 2.0 (the</span>
<span style="color: #633820"># &quot;License&quot;); you may not use this file except in compliance</span>
<span style="color: #633820"># with the License. You may obtain a copy of the License at</span>
<span style="color: #633820"># </span>
<span style="color: #633820"># http:</span><span style="color: #177500">//www.apache.org/licenses/LICENSE-2.0</span>
<span style="color: #633820">#</span>
<span style="color: #633820"># Unless required by applicable law or agreed to in writing,</span>
<span style="color: #633820"># software distributed under the License is distributed on an</span>
<span style="color: #633820"># &quot;AS IS&quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY</span>
<span style="color: #633820"># KIND, either express or implied. See the License for the</span>
<span style="color: #633820"># specific language governing permissions and limitations</span>
<span style="color: #633820"># under the License.</span>
<span style="color: #633820">#</span>
<span style="color: #000000">pkg</span>.<span style="color: #000000">name:</span> <span style="color: #000000">libs/my_drivers/myadc</span>
<span style="color: #000000">pkg</span>.<span style="color: #000000">deps:</span>
<span style="color: #000000">-</span> <span style="color: #C41A16">&quot;@apache-mynewt-core/hw/hal&quot;</span>
<span style="color: #000000">-</span> <span style="color: #C41A16">&quot;@mynewt_nordic/hw/drivers/adc/adc_nrf52&quot;</span>
</code></pre></div>
<p>First, let's create the required header file <code>myadc.h</code> in the includes directory i.e. <code>libs/my_drivers/myadc/include/myadc/myadc.h</code>.
It's a pretty straightforward header file, since we only need to do 2 things:</p>
<ul>
<li>Initialize the ADC device</li>
<li>Read ADC Values</li>
</ul>
<div class="codehilite" style="background: #ffffff"><pre style="line-height: 125%;"><span></span><code><span style="color: #633820">#ifndef _NRF52_ADC_H_</span>
<span style="color: #633820">#define _NRF52_ADC_H_</span>
<span style="color: #A90D91">void</span> <span style="color: #000000">*</span> <span style="color: #000000">adc_init</span>(<span style="color: #A90D91">void</span>);
<span style="color: #A90D91">int</span> <span style="color: #000000">adc_read</span>(<span style="color: #A90D91">void</span> <span style="color: #000000">*buffer</span>, <span style="color: #A90D91">int</span> <span style="color: #000000">buffer_len</span>);
<span style="color: #633820">#endif </span><span style="color: #177500">/* _NRF52_ADC_H_ */</span>
</code></pre></div>
<p>Next we'll need a corresponding source file <code>myadc.c</code> in the src directory. This is where
we'll implement the specifics of the driver:</p>
<div class="codehilite" style="background: #ffffff"><pre style="line-height: 125%;"><span></span><code><span style="color: #633820">#include</span> <span style="color: #177500">&lt;assert.h&gt;</span>
<span style="color: #633820">#include</span> <span style="color: #177500">&lt;os/os.h&gt;</span>
<span style="color: #177500">/* ADC */</span>
<span style="color: #633820">#include</span> <span style="color: #177500">&quot;myadc/myadc.h&quot;</span>
<span style="color: #633820">#include</span> <span style="color: #177500">&quot;nrf.h&quot;</span>
<span style="color: #633820">#include</span> <span style="color: #177500">&quot;app_util_platform.h&quot;</span>
<span style="color: #633820">#include</span> <span style="color: #177500">&quot;app_error.h&quot;</span>
<span style="color: #633820">#include</span> <span style="color: #177500">&lt;adc/adc.h&gt;</span>
<span style="color: #633820">#include</span> <span style="color: #177500">&lt;adc_nrf52/adc_nrf52.h&gt;</span>
<span style="color: #633820">#include</span> <span style="color: #177500">&quot;nrf_drv_saadc.h&quot;</span>
<span style="color: #633820">#define ADC_NUMBER_SAMPLES (2)</span>
<span style="color: #633820">#define ADC_NUMBER_CHANNELS (1)</span>
<span style="color: #000000">nrf_drv_saadc_config_t</span> <span style="color: #000000">adc_config</span> <span style="color: #000000">=</span> <span style="color: #000000">NRF_DRV_SAADC_DEFAULT_CONFIG</span>;
<span style="color: #A90D91">struct</span> <span style="color: #3F6E75">adc_dev</span> <span style="color: #000000">*adc</span>;
<span style="color: #A90D91">uint8_t</span> <span style="color: #000000">*sample_buffer1</span>;
<span style="color: #A90D91">uint8_t</span> <span style="color: #000000">*sample_buffer2</span>;
<span style="color: #A90D91">static</span> <span style="color: #A90D91">struct</span> <span style="color: #3F6E75">adc_dev</span> <span style="color: #000000">os_bsp_adc0</span>;
<span style="color: #A90D91">static</span> <span style="color: #000000">nrf_drv_saadc_config_t</span> <span style="color: #000000">os_bsp_adc0_config</span> <span style="color: #000000">=</span> {
.<span style="color: #000000">resolution</span> <span style="color: #000000">=</span> <span style="color: #000000">MYNEWT_VAL</span>(<span style="color: #000000">ADC_0_RESOLUTION</span>),
.<span style="color: #000000">oversample</span> <span style="color: #000000">=</span> <span style="color: #000000">MYNEWT_VAL</span>(<span style="color: #000000">ADC_0_OVERSAMPLE</span>),
.<span style="color: #000000">interrupt_priority</span> <span style="color: #000000">=</span> <span style="color: #000000">MYNEWT_VAL</span>(<span style="color: #000000">ADC_0_INTERRUPT_PRIORITY</span>),
};
<span style="color: #A90D91">void</span> <span style="color: #000000">*</span>
<span style="color: #000000">adc_init</span>(<span style="color: #A90D91">void</span>)
{
<span style="color: #A90D91">int</span> <span style="color: #000000">rc</span> <span style="color: #000000">=</span> <span style="color: #1C01CE">0</span>;
<span style="color: #000000">rc</span> <span style="color: #000000">=</span> <span style="color: #000000">os_dev_create</span>((<span style="color: #A90D91">struct</span> <span style="color: #3F6E75">os_dev</span> <span style="color: #000000">*</span>) <span style="color: #000000">&amp;os_bsp_adc0</span>, <span style="color: #C41A16">&quot;adc0&quot;</span>,
<span style="color: #000000">OS_DEV_INIT_KERNEL</span>, <span style="color: #000000">OS_DEV_INIT_PRIO_DEFAULT</span>,
<span style="color: #000000">nrf52_adc_dev_init</span>, <span style="color: #000000">&amp;os_bsp_adc0_config</span>);
<span style="color: #000000">assert</span>(<span style="color: #000000">rc</span> <span style="color: #000000">==</span> <span style="color: #1C01CE">0</span>);
<span style="color: #000000">nrf_saadc_channel_config_t</span> <span style="color: #000000">cc</span> <span style="color: #000000">=</span> <span style="color: #000000">NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE</span>(<span style="color: #000000">NRF_SAADC_INPUT_AIN1</span>);
<span style="color: #000000">cc</span>.<span style="color: #000000">gain</span> <span style="color: #000000">=</span> <span style="color: #000000">NRF_SAADC_GAIN1_6</span>;
<span style="color: #000000">cc</span>.<span style="color: #000000">reference</span> <span style="color: #000000">=</span> <span style="color: #000000">NRF_SAADC_REFERENCE_INTERNAL</span>;
<span style="color: #000000">adc</span> <span style="color: #000000">=</span> (<span style="color: #A90D91">struct</span> <span style="color: #3F6E75">adc_dev</span> <span style="color: #000000">*</span>) <span style="color: #000000">os_dev_open</span>(<span style="color: #C41A16">&quot;adc0&quot;</span>, <span style="color: #1C01CE">0</span>, <span style="color: #000000">&amp;adc_config</span>);
<span style="color: #000000">assert</span>(<span style="color: #000000">adc</span> <span style="color: #000000">!=</span> <span style="color: #A90D91">NULL</span>);
<span style="color: #000000">adc_chan_config</span>(<span style="color: #000000">adc</span>, <span style="color: #1C01CE">0</span>, <span style="color: #000000">&amp;cc</span>);
<span style="color: #000000">sample_buffer1</span> <span style="color: #000000">=</span> <span style="color: #000000">malloc</span>(<span style="color: #000000">adc_buf_size</span>(<span style="color: #000000">adc</span>, <span style="color: #000000">ADC_NUMBER_CHANNELS</span>, <span style="color: #000000">ADC_NUMBER_SAMPLES</span>));
<span style="color: #000000">sample_buffer2</span> <span style="color: #000000">=</span> <span style="color: #000000">malloc</span>(<span style="color: #000000">adc_buf_size</span>(<span style="color: #000000">adc</span>, <span style="color: #000000">ADC_NUMBER_CHANNELS</span>, <span style="color: #000000">ADC_NUMBER_SAMPLES</span>));
<span style="color: #000000">memset</span>(<span style="color: #000000">sample_buffer1</span>, <span style="color: #1C01CE">0</span>, <span style="color: #000000">adc_buf_size</span>(<span style="color: #000000">adc</span>, <span style="color: #000000">ADC_NUMBER_CHANNELS</span>, <span style="color: #000000">ADC_NUMBER_SAMPLES</span>));
<span style="color: #000000">memset</span>(<span style="color: #000000">sample_buffer2</span>, <span style="color: #1C01CE">0</span>, <span style="color: #000000">adc_buf_size</span>(<span style="color: #000000">adc</span>, <span style="color: #000000">ADC_NUMBER_CHANNELS</span>, <span style="color: #000000">ADC_NUMBER_SAMPLES</span>));
<span style="color: #000000">adc_buf_set</span>(<span style="color: #000000">adc</span>, <span style="color: #000000">sample_buffer1</span>, <span style="color: #000000">sample_buffer2</span>,
<span style="color: #000000">adc_buf_size</span>(<span style="color: #000000">adc</span>, <span style="color: #000000">ADC_NUMBER_CHANNELS</span>, <span style="color: #000000">ADC_NUMBER_SAMPLES</span>));
<span style="color: #A90D91">return</span> <span style="color: #000000">adc</span>;
}
<span style="color: #A90D91">int</span>
<span style="color: #000000">adc_read</span>(<span style="color: #A90D91">void</span> <span style="color: #000000">*buffer</span>, <span style="color: #A90D91">int</span> <span style="color: #000000">buffer_len</span>)
{
<span style="color: #A90D91">int</span> <span style="color: #000000">i</span>;
<span style="color: #A90D91">int</span> <span style="color: #000000">adc_result</span>;
<span style="color: #A90D91">int</span> <span style="color: #000000">my_result_mv</span> <span style="color: #000000">=</span> <span style="color: #1C01CE">0</span>;
<span style="color: #A90D91">int</span> <span style="color: #000000">rc</span>;
<span style="color: #A90D91">for</span> (<span style="color: #000000">i</span> <span style="color: #000000">=</span> <span style="color: #1C01CE">0</span>; <span style="color: #000000">i</span> <span style="color: #000000">&lt;</span> <span style="color: #000000">ADC_NUMBER_SAMPLES</span>; <span style="color: #000000">i++</span>) {
<span style="color: #000000">rc</span> <span style="color: #000000">=</span> <span style="color: #000000">adc_buf_read</span>(<span style="color: #000000">adc</span>, <span style="color: #000000">buffer</span>, <span style="color: #000000">buffer_len</span>, <span style="color: #000000">i</span>, <span style="color: #000000">&amp;adc_result</span>);
<span style="color: #A90D91">if</span> (<span style="color: #000000">rc</span> <span style="color: #000000">!=</span> <span style="color: #1C01CE">0</span>) {
<span style="color: #A90D91">goto</span> <span style="color: #000000">err</span>;
}
<span style="color: #000000">my_result_mv</span> <span style="color: #000000">=</span> <span style="color: #000000">adc_result_mv</span>(<span style="color: #000000">adc</span>, <span style="color: #1C01CE">0</span>, <span style="color: #000000">adc_result</span>);
}
<span style="color: #000000">adc_buf_release</span>(<span style="color: #000000">adc</span>, <span style="color: #000000">buffer</span>, <span style="color: #000000">buffer_len</span>);
<span style="color: #A90D91">return</span> <span style="color: #000000">my_result_mv</span>;
<span style="color: #000000">err</span>:
<span style="color: #A90D91">return</span> (<span style="color: #000000">rc</span>);
}
</code></pre></div>
<p>There's a lot going on in here, so let's walk through it step by step. </p>
<p>First, we define a default configuration, with the resolution, oversample and interrupt priority. You'll see
that these are <code>MYNEWT_VAL</code> values, which means that we'll define them shortly in
a <code>syscfg.yml</code> file to be passed to the compiler at build time. </p>
<div class="codehilite" style="background: #ffffff"><pre style="line-height: 125%;"><span></span><code><span style="color: #A90D91">static</span> <span style="color: #A90D91">struct</span> <span style="color: #3F6E75">adc_dev</span> <span style="color: #000000">os_bsp_adc0</span>;
<span style="color: #A90D91">static</span> <span style="color: #000000">nrf_drv_saadc_config_t</span> <span style="color: #000000">os_bsp_adc0_config</span> <span style="color: #000000">=</span> {
.<span style="color: #000000">resolution</span> <span style="color: #000000">=</span> <span style="color: #000000">MYNEWT_VAL</span>(<span style="color: #000000">ADC_0_RESOLUTION</span>),
.<span style="color: #000000">oversample</span> <span style="color: #000000">=</span> <span style="color: #000000">MYNEWT_VAL</span>(<span style="color: #000000">ADC_0_OVERSAMPLE</span>),
.<span style="color: #000000">interrupt_priority</span> <span style="color: #000000">=</span> <span style="color: #000000">MYNEWT_VAL</span>(<span style="color: #000000">ADC_0_INTERRUPT_PRIORITY</span>),
};
</code></pre></div>
<p>Next, in <code>adc_init()</code> , we need to tell the OS to create the device.</p>
<div class="codehilite" style="background: #ffffff"><pre style="line-height: 125%;"><span></span><code><span style="color: #A90D91">void</span> <span style="color: #000000">*</span>
<span style="color: #000000">adc_init</span>(<span style="color: #A90D91">void</span>)
{
<span style="color: #A90D91">int</span> <span style="color: #000000">rc</span> <span style="color: #000000">=</span> <span style="color: #1C01CE">0</span>;
<span style="color: #000000">rc</span> <span style="color: #000000">=</span> <span style="color: #000000">os_dev_create</span>((<span style="color: #A90D91">struct</span> <span style="color: #3F6E75">os_dev</span> <span style="color: #000000">*</span>) <span style="color: #000000">&amp;os_bsp_adc0</span>, <span style="color: #C41A16">&quot;adc0&quot;</span>,
<span style="color: #000000">OS_DEV_INIT_KERNEL</span>, <span style="color: #000000">OS_DEV_INIT_PRIO_DEFAULT</span>,
<span style="color: #000000">nrf52_adc_dev_init</span>, <span style="color: #000000">&amp;os_bsp_adc0_config</span>);
<span style="color: #000000">assert</span>(<span style="color: #000000">rc</span> <span style="color: #000000">==</span> <span style="color: #1C01CE">0</span>);
<span style="color: #000000">nrf_saadc_channel_config_t</span> <span style="color: #000000">cc</span> <span style="color: #000000">=</span> <span style="color: #000000">NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE</span>(<span style="color: #000000">NRF_SAADC_INPUT_AIN1</span>);
<span style="color: #000000">cc</span>.<span style="color: #000000">gain</span> <span style="color: #000000">=</span> <span style="color: #000000">NRF_SAADC_GAIN1_6</span>;
<span style="color: #000000">cc</span>.<span style="color: #000000">reference</span> <span style="color: #000000">=</span> <span style="color: #000000">NRF_SAADC_REFERENCE_INTERNAL</span>;
<span style="color: #000000">adc</span> <span style="color: #000000">=</span> (<span style="color: #A90D91">struct</span> <span style="color: #3F6E75">adc_dev</span> <span style="color: #000000">*</span>) <span style="color: #000000">os_dev_open</span>(<span style="color: #C41A16">&quot;adc0&quot;</span>, <span style="color: #1C01CE">0</span>, <span style="color: #000000">&amp;adc_config</span>);
<span style="color: #000000">assert</span>(<span style="color: #000000">adc</span> <span style="color: #000000">!=</span> <span style="color: #A90D91">NULL</span>);
<span style="color: #000000">adc_chan_config</span>(<span style="color: #000000">adc</span>, <span style="color: #1C01CE">0</span>, <span style="color: #000000">&amp;cc</span>);
<span style="color: #000000">sample_buffer1</span> <span style="color: #000000">=</span> <span style="color: #000000">malloc</span>(<span style="color: #000000">adc_buf_size</span>(<span style="color: #000000">adc</span>, <span style="color: #000000">ADC_NUMBER_CHANNELS</span>, <span style="color: #000000">ADC_NUMBER_SAMPLES</span>));
<span style="color: #000000">sample_buffer2</span> <span style="color: #000000">=</span> <span style="color: #000000">malloc</span>(<span style="color: #000000">adc_buf_size</span>(<span style="color: #000000">adc</span>, <span style="color: #000000">ADC_NUMBER_CHANNELS</span>, <span style="color: #000000">ADC_NUMBER_SAMPLES</span>));
<span style="color: #000000">memset</span>(<span style="color: #000000">sample_buffer1</span>, <span style="color: #1C01CE">0</span>, <span style="color: #000000">adc_buf_size</span>(<span style="color: #000000">adc</span>, <span style="color: #000000">ADC_NUMBER_CHANNELS</span>, <span style="color: #000000">ADC_NUMBER_SAMPLES</span>));
<span style="color: #000000">memset</span>(<span style="color: #000000">sample_buffer2</span>, <span style="color: #1C01CE">0</span>, <span style="color: #000000">adc_buf_size</span>(<span style="color: #000000">adc</span>, <span style="color: #000000">ADC_NUMBER_CHANNELS</span>, <span style="color: #000000">ADC_NUMBER_SAMPLES</span>));
<span style="color: #000000">adc_buf_set</span>(<span style="color: #000000">adc</span>, <span style="color: #000000">sample_buffer1</span>, <span style="color: #000000">sample_buffer2</span>,
<span style="color: #000000">adc_buf_size</span>(<span style="color: #000000">adc</span>, <span style="color: #000000">ADC_NUMBER_CHANNELS</span>, <span style="color: #000000">ADC_NUMBER_SAMPLES</span>));
<span style="color: #A90D91">return</span> <span style="color: #000000">adc</span>;
}
</code></pre></div>
<p>A few things need to be said about this part, as it is the most confusing. First,
we're using a <strong>default</strong> configuration for the ADC Channel via the <code>NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE</code>
macro. The important part here is that we're actually using <code>AIN1</code>. I know what you're thinking, "But
we want ADC-0!" and that's true. The board is actually labelled 'A0, A1, A2' etc., and the actual pin
numbers are also listed on the board, which seems handy. At first. But it gets messy very quickly.</p>
<p>If you try to use AIN0, and then go poke around in the registers while this is running, </p>
<div class="codehilite" style="background: #ffffff"><pre style="line-height: 125%;"><span></span><code>(gdb) p/x {NRF_SAADC_Type}0x40007000
...
CH = {{
PSELP = 0x1,
PSELN = 0x0,
CONFIG = 0x20000,
LIMIT = 0x7fff8000
},
</code></pre></div>
<p>You'll see that the pin for channel 0 is set to 1, which corresponds to AIN0, but that's <strong>NOT</strong>
the same as A0 -- pin P0.03, the one we're using. For that, you use AIN1, which would set the
pin value to 2. Messy. Someone, somewhere, thought this made sense. </p>
<p>The only other thing to note here is that we're using the internal reference voltage, rather than
setting our own. There's nothing wrong with that, but since we are, we'll have to crank up
the gain a bit by using <code>NRF_SAADC_GAIN1_6</code>.</p>
<p>Then, in <code>adc_read()</code> we will take readings, convert the raw readings to
a millivolt equivalent, and return the result. </p>
<div class="codehilite" style="background: #ffffff"><pre style="line-height: 125%;"><span></span><code><span style="color: #A90D91">int</span>
<span style="color: #000000">adc_read</span>(<span style="color: #A90D91">void</span> <span style="color: #000000">*buffer</span>, <span style="color: #A90D91">int</span> <span style="color: #000000">buffer_len</span>)
{
<span style="color: #A90D91">int</span> <span style="color: #000000">i</span>;
<span style="color: #A90D91">int</span> <span style="color: #000000">adc_result</span>;
<span style="color: #A90D91">int</span> <span style="color: #000000">my_result_mv</span> <span style="color: #000000">=</span> <span style="color: #1C01CE">0</span>;
<span style="color: #A90D91">int</span> <span style="color: #000000">rc</span>;
<span style="color: #A90D91">for</span> (<span style="color: #000000">i</span> <span style="color: #000000">=</span> <span style="color: #1C01CE">0</span>; <span style="color: #000000">i</span> <span style="color: #000000">&lt;</span> <span style="color: #000000">ADC_NUMBER_SAMPLES</span>; <span style="color: #000000">i++</span>) {
<span style="color: #000000">rc</span> <span style="color: #000000">=</span> <span style="color: #000000">adc_buf_read</span>(<span style="color: #000000">adc</span>, <span style="color: #000000">buffer</span>, <span style="color: #000000">buffer_len</span>, <span style="color: #000000">i</span>, <span style="color: #000000">&amp;adc_result</span>);
<span style="color: #A90D91">if</span> (<span style="color: #000000">rc</span> <span style="color: #000000">!=</span> <span style="color: #1C01CE">0</span>) {
<span style="color: #A90D91">goto</span> <span style="color: #000000">err</span>;
}
<span style="color: #000000">my_result_mv</span> <span style="color: #000000">=</span> <span style="color: #000000">adc_result_mv</span>(<span style="color: #000000">adc</span>, <span style="color: #1C01CE">0</span>, <span style="color: #000000">adc_result</span>);
}
<span style="color: #000000">adc_buf_release</span>(<span style="color: #000000">adc</span>, <span style="color: #000000">buffer</span>, <span style="color: #000000">buffer_len</span>);
<span style="color: #A90D91">return</span> <span style="color: #000000">my_result_mv</span>;
<span style="color: #000000">err</span>:
<span style="color: #A90D91">return</span> (<span style="color: #000000">rc</span>);
}
</code></pre></div>
<p>Finally, we'll need some settings for our driver, as mentioned earlier. In the <code>myadc</code> directory
you'll need to add a <code>syscfg.yml</code> file:</p>
<div class="codehilite" style="background: #ffffff"><pre style="line-height: 125%;"><span></span><code># Package: libs/my_driver/myadc
syscfg.defs:
ADC_0:
description: &#39;TBD&#39;
value: 1
ADC_0_RESOLUTION:
description: &#39;TBD&#39;
value: &#39;SAADC_CONFIG_RESOLUTION&#39;
ADC_0_OVERSAMPLE:
description: &#39;TBD&#39;
value: &#39;SAADC_CONFIG_OVERSAMPLE&#39;
ADC_0_INTERRUPT_PRIORITY:
description: &#39;TBD&#39;
value: &#39;SAADC_CONFIG_IRQ_PRIORITY&#39;
</code></pre></div>
<p>Once that's all done, you should have a working ADC Driver for your NRF52DK board. The last step in getting the driver set up is to include it in the package dependency defined by <code>pkg.deps</code> in the <code>pkg.yml</code> file of your app. Add it in <code>apps/nrf52_adc/pkg.yml</code> as shown by the highlighted line below.</p>
<div class="codehilite" style="background: #ffffff"><pre style="line-height: 125%;"><span></span><code># Licensed to the Apache Software Foundation (ASF) under one
# &lt;snip&gt;
pkg.name: apps/nrf52_adc
pkg.type: app
pkg.description: Simple BLE peripheral application for ADC sensor.
pkg.author: &quot;Apache Mynewt &lt;dev@mynewt.incubator.apache.org&gt;&quot;
pkg.homepage: &quot;http://mynewt.apache.org/&quot;
pkg.keywords:
pkg.deps:
- &quot;@apache-mynewt-core/boot/split&quot;
- &quot;@apache-mynewt-core/kernel/os&quot;
- &quot;@apache-mynewt-core/mgmt/imgmgr&quot;
- &quot;@apache-mynewt-core/mgmt/newtmgr&quot;
- &quot;@apache-mynewt-core/mgmt/newtmgr/transport/ble&quot;
- &quot;@apache-mynewt-core/net/nimble/controller&quot;
- &quot;@apache-mynewt-core/net/nimble/host&quot;
- &quot;@apache-mynewt-core/net/nimble/host/services/ans&quot;
- &quot;@apache-mynewt-core/net/nimble/host/services/gap&quot;
- &quot;@apache-mynewt-core/net/nimble/host/services/gatt&quot;
- &quot;@apache-mynewt-core/net/nimble/host/store/ram&quot;
- &quot;@apache-mynewt-core/net/nimble/transport/ram&quot;
- &quot;@apache-mynewt-core/sys/console/full&quot;
- &quot;@apache-mynewt-core/sys/log/full&quot;
- &quot;@apache-mynewt-core/sys/stats/full&quot;
- &quot;@apache-mynewt-core/sys/sysinit&quot;
- &quot;@apache-mynewt-core/sys/id&quot;
<span style="background-color: #ffffcc"> - libs/my_drivers/myadc
</span></code></pre></div>
<p><br></p>
<h3 id="creating-the-adc-task">Creating the ADC Task</h3>
<p>Now that the driver is done, we'll need to add calls to the main app's <code>main.c</code> file, as well
as a few other things. First, we'll need to update the includes, and add a task for our ADC
sampling.</p>
<div class="codehilite" style="background: #ffffff"><pre style="line-height: 125%;"><span></span><code><span style="color: #633820">#include</span> <span style="color: #177500">&quot;myadc/myadc.h&quot;</span>
...
<span style="color: #177500">/* ADC Task settings */</span>
<span style="color: #633820">#define ADC_TASK_PRIO 5</span>
<span style="color: #633820">#define ADC_STACK_SIZE (OS_STACK_ALIGN(336))</span>
<span style="color: #A90D91">struct</span> <span style="color: #3F6E75">os_eventq</span> <span style="color: #000000">adc_evq</span>;
<span style="color: #A90D91">struct</span> <span style="color: #3F6E75">os_task</span> <span style="color: #000000">adc_task</span>;
<span style="color: #000000">bssnz_t</span> <span style="color: #000000">os_stack_t</span> <span style="color: #000000">adc_stack</span>[<span style="color: #000000">ADC_STACK_SIZE</span>];
</code></pre></div>
<p>Next we'll need o initialize the task <code>event_q</code> so we'll add the highlighted code to <code>main()</code> as shown below:</p>
<div class="codehilite" style="background: #ffffff"><pre style="line-height: 125%;"><span></span><code> <span style="color: #177500">/* Set the default device name. */</span>
<span style="color: #000000">rc</span> <span style="color: #000000">=</span> <span style="color: #000000">ble_svc_gap_device_name_set</span>(<span style="color: #C41A16">&quot;nimble-adc&quot;</span>);
<span style="color: #000000">assert</span>(<span style="color: #000000">rc</span> <span style="color: #000000">==</span> <span style="color: #1C01CE">0</span>);
<span style="color: #000000">conf_load</span>();
<span style="background-color: #ffffcc"> <span style="color: #177500">/* Initialize adc sensor task eventq */</span>
</span><span style="background-color: #ffffcc"> <span style="color: #000000">os_eventq_init</span>(<span style="color: #000000">&amp;adc_evq</span>);
</span><span style="background-color: #ffffcc">
</span><span style="background-color: #ffffcc"> <span style="color: #177500">/* Create the ADC reader task. </span>
</span><span style="background-color: #ffffcc"><span style="color: #177500"> * All sensor operations are performed in this task.</span>
</span><span style="background-color: #ffffcc"><span style="color: #177500"> */</span>
</span><span style="background-color: #ffffcc"> <span style="color: #000000">os_task_init</span>(<span style="color: #000000">&amp;adc_task</span>, <span style="color: #C41A16">&quot;sensor&quot;</span>, <span style="color: #000000">adc_task_handler</span>,
</span><span style="background-color: #ffffcc"> <span style="color: #A90D91">NULL</span>, <span style="color: #000000">ADC_TASK_PRIO</span>, <span style="color: #000000">OS_WAIT_FOREVER</span>,
</span><span style="background-color: #ffffcc"> <span style="color: #000000">adc_stack</span>, <span style="color: #000000">ADC_STACK_SIZE</span>);
</span></code></pre></div>
<p>We'll need that <code>adc_task_handler()</code> function to exist, and that's where we'll initialize the ADC Device
and set the event handler. In the task's while() loop, we'll just make a call to <code>adc_sample()</code> to cause
the ADC driver to sample the adc device.</p>
<div class="codehilite" style="background: #ffffff"><pre style="line-height: 125%;"><span></span><code><span style="color: #177500">/**</span>
<span style="color: #177500"> * Event loop for the sensor task.</span>
<span style="color: #177500"> */</span>
<span style="color: #A90D91">static</span> <span style="color: #A90D91">void</span>
<span style="color: #000000">adc_task_handler</span>(<span style="color: #A90D91">void</span> <span style="color: #000000">*unused</span>)
{
<span style="color: #A90D91">struct</span> <span style="color: #3F6E75">adc_dev</span> <span style="color: #000000">*adc</span>;
<span style="color: #A90D91">int</span> <span style="color: #000000">rc</span>;
<span style="color: #177500">/* ADC init */</span>
<span style="color: #000000">adc</span> <span style="color: #000000">=</span> <span style="color: #000000">adc_init</span>();
<span style="color: #000000">rc</span> <span style="color: #000000">=</span> <span style="color: #000000">adc_event_handler_set</span>(<span style="color: #000000">adc</span>, <span style="color: #000000">adc_read_event</span>, (<span style="color: #A90D91">void</span> <span style="color: #000000">*</span>) <span style="color: #A90D91">NULL</span>);
<span style="color: #000000">assert</span>(<span style="color: #000000">rc</span> <span style="color: #000000">==</span> <span style="color: #1C01CE">0</span>);
<span style="color: #A90D91">while</span> (<span style="color: #1C01CE">1</span>) {
<span style="color: #000000">adc_sample</span>(<span style="color: #000000">adc</span>);
<span style="color: #177500">/* Wait 2 second */</span>
<span style="color: #000000">os_time_delay</span>(<span style="color: #000000">OS_TICKS_PER_SEC</span> <span style="color: #000000">*</span> <span style="color: #1C01CE">2</span>);
}
}
</code></pre></div>
<p>Above the <code>adc_task_handler</code>, add code to handle the <code>adc_read_event()</code> calls:</p>
<div class="codehilite" style="background: #ffffff"><pre style="line-height: 125%;"><span></span><code><span style="color: #A90D91">int</span>
<span style="color: #000000">adc_read_event</span>(<span style="color: #A90D91">struct</span> <span style="color: #3F6E75">adc_dev</span> <span style="color: #000000">*dev</span>, <span style="color: #A90D91">void</span> <span style="color: #000000">*arg</span>, <span style="color: #A90D91">uint8_t</span> <span style="color: #000000">etype</span>,
<span style="color: #A90D91">void</span> <span style="color: #000000">*buffer</span>, <span style="color: #A90D91">int</span> <span style="color: #000000">buffer_len</span>)
{
<span style="color: #A90D91">int</span> <span style="color: #000000">value</span>;
<span style="color: #A90D91">uint16_t</span> <span style="color: #000000">chr_val_handle</span>;
<span style="color: #A90D91">int</span> <span style="color: #000000">rc</span>;
<span style="color: #000000">value</span> <span style="color: #000000">=</span> <span style="color: #000000">adc_read</span>(<span style="color: #000000">buffer</span>, <span style="color: #000000">buffer_len</span>);
<span style="color: #A90D91">if</span> (<span style="color: #000000">value</span> <span style="color: #000000">&gt;=</span> <span style="color: #1C01CE">0</span>) {
<span style="color: #000000">console_printf</span>(<span style="color: #C41A16">&quot;Got %d\n&quot;</span>, <span style="color: #000000">value</span>);
} <span style="color: #A90D91">else</span> {
<span style="color: #000000">console_printf</span>(<span style="color: #C41A16">&quot;Error while reading: %d\n&quot;</span>, <span style="color: #000000">value</span>);
<span style="color: #A90D91">goto</span> <span style="color: #000000">err</span>;
}
<span style="color: #000000">gatt_adc_val</span> <span style="color: #000000">=</span> <span style="color: #000000">value</span>;
<span style="color: #000000">rc</span> <span style="color: #000000">=</span> <span style="color: #000000">ble_gatts_find_chr</span>(<span style="color: #000000">&amp;gatt_svr_svc_adc_uuid</span>.<span style="color: #000000">u</span>, <span style="color: #000000">BLE_UUID16_DECLARE</span>(<span style="color: #000000">ADC_SNS_VAL</span>), <span style="color: #A90D91">NULL</span>, <span style="color: #000000">&amp;chr_val_handle</span>);
<span style="color: #000000">assert</span>(<span style="color: #000000">rc</span> <span style="color: #000000">==</span> <span style="color: #1C01CE">0</span>);
<span style="color: #000000">ble_gatts_chr_updated</span>(<span style="color: #000000">chr_val_handle</span>);
<span style="color: #A90D91">return</span> (<span style="color: #1C01CE">0</span>);
<span style="color: #000000">err</span>:
<span style="color: #A90D91">return</span> (<span style="color: #000000">rc</span>);
}
</code></pre></div>
<p>This is where we actually read the ADC value and then update the BLE Characteristic for that value. </p>
<p>But wait, we haven't defined those BLE services and characteristics yet! Right, so don't try to build and run this
app just yet or it will surely fail. Instead, move on to the next section and get all of those services
defined.</p>
<p><br></p>
<h3 id="building-the-ble-services">Building the BLE Services</h3>
<p>If the nrf52_adc app is going to be a Bluetooth-enabled sensor app that will allow you to read the value of the eTape Water Level Sensor
via Bluetooth we'll need to actually define those Services and Characteristics.</p>
<p>As with the <a href="../bleprph/bleprph-app/">ble peripheral</a> app, we will advertise a couple of values from our app. The first is
not strictly necessary, but it will help us build an iOS app later. We've defined a service and the characteristics in
that service in <code>bleadc.h</code> in the <code>apps/nrf52_adc/src/</code> directory as follows:</p>
<div class="codehilite" style="background: #ffffff"><pre style="line-height: 125%;"><span></span><code><span style="color: #177500">/* Sensor Data */</span>
<span style="color: #177500">/* e761d2af-1c15-4fa7-af80-b5729002b340 */</span>
<span style="color: #A90D91">static</span> <span style="color: #A90D91">const</span> <span style="color: #000000">ble_uuid128_t</span> <span style="color: #000000">gatt_svr_svc_adc_uuid</span> <span style="color: #000000">=</span>
<span style="color: #000000">BLE_UUID128_INIT</span>(<span style="color: #1C01CE">0x40</span>, <span style="color: #1C01CE">0xb3</span>, <span style="color: #1C01CE">0x20</span>, <span style="color: #1C01CE">0x90</span>, <span style="color: #1C01CE">0x72</span>, <span style="color: #1C01CE">0xb5</span>, <span style="color: #1C01CE">0x80</span>, <span style="color: #1C01CE">0xaf</span>,
<span style="color: #1C01CE">0xa7</span>, <span style="color: #1C01CE">0x4f</span>, <span style="color: #1C01CE">0x15</span>, <span style="color: #1C01CE">0x1c</span>, <span style="color: #1C01CE">0xaf</span>, <span style="color: #1C01CE">0xd2</span>, <span style="color: #1C01CE">0x61</span>, <span style="color: #1C01CE">0xe7</span>);
<span style="color: #633820">#define ADC_SNS_TYPE 0xDEAD</span>
<span style="color: #633820">#define ADC_SNS_STRING &quot;eTape Liquid Level Sensor&quot;</span>
<span style="color: #633820">#define ADC_SNS_VAL 0xBEAD</span>
<span style="color: #A90D91">extern</span> <span style="color: #A90D91">uint16_t</span> <span style="color: #000000">gatt_adc_val</span>;
</code></pre></div>
<p>The first is the UUID of the service, followed by the 2 characteristics we are going to offer.
The first characteristic is going to advertise the <em>type</em> of sensor we are advertising, and
it will be a read-only characteristic. The second characteristic will be the sensor value
itself, and we will allow connected devices to 'subscribe' to it in order to get
constantly-updated values.</p>
<p><strong>Note:</strong> You can choose any valid Characteristic UUIDs to go here. We're using these values
for illustrative purposes only.</p>
<p>The value that we'll be updating is also defined here as <code>gatt_adc_val</code>.</p>
<p>If we then go look at <code>gatt_srv.c</code> we can see the structure of the service and
characteristic offering that we set up:</p>
<div class="codehilite" style="background: #ffffff"><pre style="line-height: 125%;"><span></span><code><span style="color: #A90D91">static</span> <span style="color: #A90D91">const</span> <span style="color: #A90D91">struct</span> <span style="color: #3F6E75">ble_gatt_svc_def</span> <span style="color: #000000">gatt_svr_svcs</span>[] <span style="color: #000000">=</span> {
{
<span style="color: #177500">/*** Service: Security test. */</span>
.<span style="color: #000000">type</span> <span style="color: #000000">=</span> <span style="color: #000000">BLE_GATT_SVC_TYPE_PRIMARY</span>,
.<span style="color: #000000">uuid</span> <span style="color: #000000">=</span> <span style="color: #000000">&amp;gatt_svr_svc_sec_test_uuid</span>.<span style="color: #000000">u</span>,
.<span style="color: #000000">characteristics</span> <span style="color: #000000">=</span> (<span style="color: #A90D91">struct</span> <span style="color: #3F6E75">ble_gatt_chr_def</span>[]) { {
<span style="color: #177500">/*** Characteristic: Random number generator. */</span>
.<span style="color: #000000">uuid</span> <span style="color: #000000">=</span> <span style="color: #000000">&amp;gatt_svr_chr_sec_test_rand_uuid</span>.<span style="color: #000000">u</span>,
.<span style="color: #000000">access_cb</span> <span style="color: #000000">=</span> <span style="color: #000000">gatt_svr_chr_access_sec_test</span>,
.<span style="color: #000000">flags</span> <span style="color: #000000">=</span> <span style="color: #000000">BLE_GATT_CHR_F_READ</span> <span style="color: #000000">|</span> <span style="color: #000000">BLE_GATT_CHR_F_READ_ENC</span>,
}, {
<span style="color: #177500">/*** Characteristic: Static value. */</span>
.<span style="color: #000000">uuid</span> <span style="color: #000000">=</span> <span style="color: #000000">&amp;gatt_svr_chr_sec_test_static_uuid</span>.<span style="color: #000000">u</span>,
.<span style="color: #000000">access_cb</span> <span style="color: #000000">=</span> <span style="color: #000000">gatt_svr_chr_access_sec_test</span>,
.<span style="color: #000000">flags</span> <span style="color: #000000">=</span> <span style="color: #000000">BLE_GATT_CHR_F_READ</span> <span style="color: #000000">|</span>
<span style="color: #000000">BLE_GATT_CHR_F_WRITE</span> <span style="color: #000000">|</span> <span style="color: #000000">BLE_GATT_CHR_F_WRITE_ENC</span>,
}, {
<span style="color: #1C01CE">0</span>, <span style="color: #177500">/* No more characteristics in this service. */</span>
} },
},
<span style="background-color: #ffffcc"> {
</span><span style="background-color: #ffffcc"> <span style="color: #177500">/*** ADC Level Notification Service. */</span>
</span><span style="background-color: #ffffcc"> .<span style="color: #000000">type</span> <span style="color: #000000">=</span> <span style="color: #000000">BLE_GATT_SVC_TYPE_PRIMARY</span>,
</span><span style="background-color: #ffffcc"> .<span style="color: #000000">uuid</span> <span style="color: #000000">=</span> <span style="color: #000000">&amp;gatt_svr_svc_adc_uuid</span>.<span style="color: #000000">u</span>,
</span><span style="background-color: #ffffcc"> .<span style="color: #000000">characteristics</span> <span style="color: #000000">=</span> (<span style="color: #A90D91">struct</span> <span style="color: #3F6E75">ble_gatt_chr_def</span>[]) { {
</span><span style="background-color: #ffffcc"> .<span style="color: #000000">uuid</span> <span style="color: #000000">=</span> <span style="color: #000000">BLE_UUID16_DECLARE</span>(<span style="color: #000000">ADC_SNS_TYPE</span>),
</span><span style="background-color: #ffffcc"> .<span style="color: #000000">access_cb</span> <span style="color: #000000">=</span> <span style="color: #000000">gatt_svr_sns_access</span>,
</span><span style="background-color: #ffffcc"> .<span style="color: #000000">flags</span> <span style="color: #000000">=</span> <span style="color: #000000">BLE_GATT_CHR_F_READ</span>,
</span><span style="background-color: #ffffcc"> }, {
</span><span style="background-color: #ffffcc"> .<span style="color: #000000">uuid</span> <span style="color: #000000">=</span> <span style="color: #000000">BLE_UUID16_DECLARE</span>(<span style="color: #000000">ADC_SNS_VAL</span>),
</span><span style="background-color: #ffffcc"> .<span style="color: #000000">access_cb</span> <span style="color: #000000">=</span> <span style="color: #000000">gatt_svr_sns_access</span>,
</span><span style="background-color: #ffffcc"> .<span style="color: #000000">flags</span> <span style="color: #000000">=</span> <span style="color: #000000">BLE_GATT_CHR_F_NOTIFY</span>,
</span><span style="background-color: #ffffcc"> }, {
</span><span style="background-color: #ffffcc"> <span style="color: #1C01CE">0</span>, <span style="color: #177500">/* No more characteristics in this service. */</span>
</span><span style="background-color: #ffffcc"> } },
</span><span style="background-color: #ffffcc"> },
</span><span style="background-color: #ffffcc">
</span> {
<span style="color: #1C01CE">0</span>, <span style="color: #177500">/* No more services. */</span>
},
};
</code></pre></div>
<p>You should recognize the first services from the <a href="../bleprph/bleprph-intro/">BLE Peripheral</a>
tutorial earlier. We're just adding another Service, with 2 new Characteristics, to
that application.</p>
<p>We'll need to fill in the function that will be called for this service, <code>gatt_srv_sns_access</code>
next so that the service knows what to do.</p>
<div class="codehilite" style="background: #ffffff"><pre style="line-height: 125%;"><span></span><code><span style="color: #A90D91">static</span> <span style="color: #A90D91">int</span>
<span style="color: #000000">gatt_svr_sns_access</span>(<span style="color: #A90D91">uint16_t</span> <span style="color: #000000">conn_handle</span>, <span style="color: #A90D91">uint16_t</span> <span style="color: #000000">attr_handle</span>,
<span style="color: #A90D91">struct</span> <span style="color: #3F6E75">ble_gatt_access_ctxt</span> <span style="color: #000000">*ctxt</span>,
<span style="color: #A90D91">void</span> <span style="color: #000000">*arg</span>)
{
<span style="color: #A90D91">uint16_t</span> <span style="color: #000000">uuid16</span>;
<span style="color: #A90D91">int</span> <span style="color: #000000">rc</span>;
<span style="color: #000000">uuid16</span> <span style="color: #000000">=</span> <span style="color: #000000">ble_uuid_u16</span>(<span style="color: #000000">ctxt-&gt;chr-&gt;uuid</span>);
<span style="color: #A90D91">switch</span> (<span style="color: #000000">uuid16</span>) {
<span style="color: #A90D91">case</span> <span style="color: #000000">ADC_SNS_TYPE</span>:
<span style="color: #000000">assert</span>(<span style="color: #000000">ctxt-&gt;op</span> <span style="color: #000000">==</span> <span style="color: #000000">BLE_GATT_ACCESS_OP_READ_CHR</span>);
<span style="color: #000000">rc</span> <span style="color: #000000">=</span> <span style="color: #000000">os_mbuf_append</span>(<span style="color: #000000">ctxt-&gt;om</span>, <span style="color: #000000">ADC_SNS_STRING</span>, <span style="color: #A90D91">sizeof</span> <span style="color: #000000">ADC_SNS_STRING</span>);
<span style="color: #000000">BLEPRPH_LOG</span>(<span style="color: #000000">INFO</span>, <span style="color: #C41A16">&quot;ADC SENSOR TYPE READ: %s\n&quot;</span>, <span style="color: #000000">ADC_SNS_STRING</span>);
<span style="color: #A90D91">return</span> <span style="color: #000000">rc</span> <span style="color: #000000">==</span> <span style="color: #1C01CE">0</span> <span style="color: #000000">?</span> <span style="color: #1C01CE">0</span> <span style="color: #000000">:</span> <span style="color: #000000">BLE_ATT_ERR_INSUFFICIENT_RES</span>;
<span style="color: #A90D91">case</span> <span style="color: #000000">ADC_SNS_VAL</span>:
<span style="color: #A90D91">if</span> (<span style="color: #000000">ctxt-&gt;op</span> <span style="color: #000000">==</span> <span style="color: #000000">BLE_GATT_ACCESS_OP_WRITE_CHR</span>) {
<span style="color: #000000">rc</span> <span style="color: #000000">=</span> <span style="color: #000000">gatt_svr_chr_write</span>(<span style="color: #000000">ctxt-&gt;om</span>, <span style="color: #1C01CE">0</span>,
<span style="color: #A90D91">sizeof</span> <span style="color: #000000">gatt_adc_val</span>,
<span style="color: #000000">&amp;gatt_adc_val</span>,
<span style="color: #A90D91">NULL</span>);
<span style="color: #A90D91">return</span> <span style="color: #000000">rc</span>;
} <span style="color: #A90D91">else</span> <span style="color: #A90D91">if</span> (<span style="color: #000000">ctxt-&gt;op</span> <span style="color: #000000">==</span> <span style="color: #000000">BLE_GATT_ACCESS_OP_READ_CHR</span>) {
<span style="color: #000000">rc</span> <span style="color: #000000">=</span> <span style="color: #000000">os_mbuf_append</span>(<span style="color: #000000">ctxt-&gt;om</span>, <span style="color: #000000">&amp;gatt_adc_val</span>,
<span style="color: #A90D91">sizeof</span> <span style="color: #000000">gatt_adc_val</span>);
<span style="color: #A90D91">return</span> <span style="color: #000000">rc</span> <span style="color: #000000">==</span> <span style="color: #1C01CE">0</span> <span style="color: #000000">?</span> <span style="color: #1C01CE">0</span> <span style="color: #000000">:</span> <span style="color: #000000">BLE_ATT_ERR_INSUFFICIENT_RES</span>;
}
<span style="color: #A90D91">default</span><span style="color: #000000">:</span>
<span style="color: #000000">assert</span>(<span style="color: #1C01CE">0</span>);
<span style="color: #A90D91">return</span> <span style="color: #000000">BLE_ATT_ERR_UNLIKELY</span>;
}
}
</code></pre></div>
<p>You can see that when request is for the <code>ADC_SNS_TYPE</code>, we return the
Sensor Type we defined earlier. If the request if for <code>ADC_SNS_VAL</code> we'll return the
<code>gatt_adc_val</code> value. </p>
<p>Don't forget to include the <code>bleadc.h</code> include file at the top of the <code>gatt_svr.c</code> file!</p>
<div class="codehilite" style="background: #ffffff"><pre style="line-height: 125%;"><span></span><code>#include &lt;assert.h&gt;
#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#include &quot;bsp/bsp.h&quot;
#include &quot;host/ble_hs.h&quot;
#include &quot;host/ble_uuid.h&quot;
#include &quot;bleprph.h&quot;
<span style="background-color: #ffffcc">#include &quot;bleadc.h&quot;
</span></code></pre></div>
<p>If you build, load and run this application now, you will see all those Services and Characteristics
advertised, and you will even be able to read the "Sensor Type" String via the ADC_SNS_TYPE
Characteristic.</p>
<p><br></p>
<h3 id="adding-the-etape-water-sensor">Adding the eTape Water Sensor</h3>
<p>Now that we have a fully functioning BLE App that we can subscribe to sensor
values from, it's time to actually wire up the sensor!</p>
<p>As previously mentioned, we're going to be using an eTape Water Level Sensor. You can
get one from <a href="https://www.adafruit.com/products/1786">Adafruit</a>. </p>
<p>We're going to use the sensor as a resistive sensor, and the setup is very simple.
I'll be using a 'breadboard` to put this all together for illustrative purposes.
First, attach a jumper-wire from Vdd on the board to the breadboard.
Next, attach a jumper wire from pin P0.03 on the board to the breadboard. This will be
our ADC-in. The sensor should have come with a 560 ohm resistor, so plug that
into the board between Vdd and ADC-in holes. Finally, attach a jumper from
GND on the board to your breadboard. At this point, your breadboard should look
like this:</p>
<p><img alt="Bread Board Setup" src="../pics/breadboard.png" /></p>
<p>Now attach one of the middle 2 leads from the sensor to ground on the breadboard and
the other middle lead to the ADC-in on the breadboard. Your breadboard should now look
like this:</p>
<p><img alt="Bread Board Final" src="../pics/adc-demo-1.png" /></p>
<p>And your eTape Sensor should look like this (at least if you have it mounted in a
graduated cylinder as I do).</p>
<p><img alt="eTape Sensor Setup" src="../pics/adc-demo-2.png" /></p>
<p>That concludes the hardware portion. Easy!</p>
<p>At this point you should be able to build, create-image and load your application and see it properly
sending readings. </p>
<p><br></p>
<h3 id="conclusion">Conclusion</h3>
<p>Congratulations, you've now completed both a hardware project and a software project by connecting a
sensor to your device and using Mynewt to read data from that sensor and send it via Bluetooth
to a connected device. That's no small feat!</p>
<p>If you see anything missing or want to send us feedback, please do so by signing up for
appropriate mailing lists on our <a href="../../../community/">Community Page</a>.</p>
<p>Keep on hacking and sensing!</p>
<p><br></p>
<h3 id="note">Note</h3>
<p>If you're wondering how to actually view these sensor readings via Bluetooth, you have a couple of
options. On Mac OS or iOS you can download the <a href="https://itunes.apple.com/us/app/lightblue-explorer-bluetooth/id557428110?mt=8">LightBlue app</a>.
This app lets you connect to, and interrogate, BLE devices like the one you just built. </p>
<p>If you used the BLE Service and Characteristic UUIDs used in this tutorial, you can also download
and use a Mac OS <a href="https://dragonflyiot.com/MyNewtSensorReader.zip">MyNewt Sensor Reader App</a> (Zip Archive) that allows
you to graph your data, etc. An iOS version is in Beta testing and should be available soon.</p>
<p><img alt="My Newt Sensor Reader" src="../pics/MyNewtSensorReader006.jpg" /></p>
<p>Enjoy!</p>
<div class="row">
<ul class="nav nav-pills" style="margin-bottom: 10px">
<li>
</li>
<li class="pull-right">
</li>
</ul>
</div>
<footer class="row">
<div class="col-xs-12">
<p class="copyright">Apache Mynewt (incubating) is available under Apache License, version 2.0.</p>
</div>
<div class="col-xs-12">
<div class="logos">
<a href="https://www.apache.org/">
<img src="/img/asf_logo_wide_small.png" alt="Apache" title="Apache">
</a>
<p>
Copyright © 2015-2021 The Apache Software Foundation.<br>
<small class="footnote">
Apache Mynewt, Mynewt, Apache, the Apache feather logo, and the Apache Mynewt
project logo are either registered trademarks or trademarks of the Apache
Software Foundation in the United States and other countries.
</small>
</p>
<a href="">
<img src="https://www.countit.com/images/add_to_slack.png" alt="Slack Icon" title="Join our Slack Community" />
</a>
</div>
</div>
<a href="https://www.apache.org/licenses/">
<button class="button-footer-asf">
License
</button>
</a>
<a href="https://www.apache.org/foundation/sponsorship.html">
<button class="button-footer-asf">
Sponsorship
</button>
</a>
<a href="https://www.apache.org/foundation/thanks.html">
<button class="button-footer-asf">
Thanks
</button>
</a>
<a href="https://www.apache.org/security/">
<button class="button-footer-asf">
Security
</button>
</a>
<a href="https://apache.org/events/current-event">
<button class="button-footer-asf">
ASF Events
</button>
</a>
</footer>
</div>
</div>
</div>
<script src="../../../js/jquery-1.10.2.min.js"></script>
<script src="../../../js/bootstrap-3.0.3.min.js"></script>
<script src="../../../js/highlight.pack.js"></script>
<script src="../../../js/base.js"></script>
<script src="../../../js/custom.js"></script>
<script src="search/main.js"></script>
</body>
</html>