http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/blob/7dc2cb54/latest/mkdocs/search_index.json
----------------------------------------------------------------------
diff --git a/latest/mkdocs/search_index.json b/latest/mkdocs/search_index.json
index 06a549a..c98271b 100644
--- a/latest/mkdocs/search_index.json
+++ b/latest/mkdocs/search_index.json
@@ -1267,7 +1267,7 @@
         }, 
         {
             "location": "/os/tutorials/air_quality_sensor/", 
-            "text": "Air quality sensor project\n\n\nSetting up source tree 
for stuff you need\n\n\nTo start with, you need to create a new project under 
which you will do this development. So you type in:\n\n\n    $ mkdir 
$HOME/src\n    $ cd $HOME/src\n    $ newt new air_quality\n\n\n\n\n\nLet's say 
you are using Arduino Primo -- which is based on the Nordic Semi NRF52 chip -- 
as the platform. \nYou know you need the board support package for that 
hardware. You can look up its location, add it your \nproject, and fetch that 
along with the core OS components. Luckily, the Arduino Primo is supported in 
the \nMynewt Core, so there's nothing much to do here. \n\n\nYour project.yml 
file should look like this:\n\n\n    [user@IsMyLaptop:~/src/air_quality]$ emacs 
project.yml \n\n    [user@IsMyLaptop:~/src/air_quality]$ cat project.yml\n    
project.name: \nair_quality\n\n\n    project.repositories:\n        - 
apache-mynewt-core\n\n    # Use github\ns distribution mechanism for core ASF 
libr
 aries.\n    # This provides mirroring automatically for us.\n    #\n    
repository.apache-mynewt-core:\n        type: github\n        vers: 0-latest\n  
      user: apache\n        repo: incubator-mynewt-core\n\n    
[user@IsMyLaptop:~/src/air_quality]$ newt install\n    apache-mynewt-core\n    
[user@IsMyLaptop:~/src/air_quality]$ ls repos/\n    
apache-mynewt-core\n\n\n\n\n\nGood. You want to make sure you have all the 
needed bits for supporting your board; \nso you decide to build the blinky 
project for the platform first.\n\n\nNow create a target for it and build it. 
Easiest way to proceed is to copy the existing target for blinky, and modify it 
to build for Arduino Primo board.\n\n\n[user@IsMyLaptop:~/src/air_quality]$ 
newt target copy my_blinky_sim blink_primo\nTarget successfully copied; 
targets/my_blinky_sim --\n 
targets/blink_primo\n[user@IsMyLaptop:~/src/air_quality]$ newt target set 
blink_primo bsp=@apache-mynewt-core/hw/bsp/arduino_primo_nrf52\nTarget 
targets/blink_nrf succe
 ssfully set target.bsp to 
@apache-mynewt-core/hw/bsp/arduino_primo_nrf52\n[user@IsMyLaptop:~/src/air_quality]$
 newt build blink_primo\nCompiling hal_bsp.c\n...\nLinking blinky.elf\nApp 
successfully built: 
/Users/user/src/air_quality/bin/blink_primo/apps/blinky/blinky.elf\n\n\n\n\n\nGood.\n\n\nYou
 know that this platform uses bootloader, which means you have to create a 
target for that too.\n\n\n[user@IsMyLaptop:~/src/air_quality]$ newt target 
create boot_primo\nTarget targets/boot_nrf successfully 
created\n[user@IsMyLaptop:~/src/air_quality]$ newt target 
show\n@apache-mynewt-core/targets/unittest\n    bsp=hw/bsp/native\n    
build_profile=debug\n    compiler=compiler/sim\ntargets/blink_primo\n    
app=apps/blinky\n    bsp=@apache-mynewt-core/hw/bsp/arduino_primo_nrf52\n    
build_profile=debug\ntargets/boot_primo\ntargets/my_blinky_sim\n    
app=apps/blinky\n    bsp=@apache-mynewt-core/hw/bsp/native\n    
build_profile=debug\n[user@IsMyLaptop:~/src/air_quality]$ newt target set 
boot_nrf 
 bsp=@apache-mynewt-core/hw/bsp/arduino_primo_nrf52\nTarget targets/boot_nrf 
successfully set target.bsp to 
@apache-mynewt-core/hw/bsp/arduino_primo_nrf52\n[user@IsMyLaptop:~/src/air_quality]$
 newt target set boot_nrf app=@apache-mynewt-core/apps/boot\nTarget 
targets/boot_nrf successfully set target.app to 
@apache-mynewt-core/apps/boot\n[user@IsMyLaptop:~/src/air_quality]$ newt target 
set boot_nrf build_profile=optimized\nTarget targets/boot_nrf successfully set 
target.build_profile to optimized\n\n\n\n\n\nAnd then build it, and load it 
onto the board.\n\n\nnewt build boot_primo\n....\nLinking boot.elf\nApp 
successfully built: 
/Users/user/src/air_quality/bin/boot_primo/apps/boot/boot.elf\n[user@IsMyLaptop:~/src/air_quality]\n$
 newt load boot_primo\n\n\n\n\n\nAt this point, you may (or may not) see a 
bunch of error messages about not being able to connect to\nyour board, not 
being able to load the image, etc. If that's the case, and you haven't already, 
you\nshould most definitely go 
 worth through the \nblinky_primo\n tutorial so that you\ncan properly 
communicate with your board.\n\n\nNext you must download the targets to board, 
and see that the LED actually blinks. You plug in the \nArduino Primo board to 
your laptop, and say:\n\n\n[user@IsMyLaptop:~/src/air_quality]$ newt load 
blink_primo\nLoading app image into slot 1\nError: couldn\nt open 
/Users/user/src/air_quality/bin/blink_primo/apps/blinky/blinky.img\n\nError: 
exit status 1\n\nload - Load app image to target for 
\ntarget-name\n.\n\nUsage:\n  newt load [flags]\n\nExamples:\n  newt load 
\ntarget-name\n\n\n\nGlobal Flags:\n  -l, --loglevel string   Log level, 
defaults to WARN. (default \nWARN\n)\n  -o, --outfile string    Filename to tee 
log output to\n  -q, --quiet             Be quiet; only display error output.\n 
 -s, --silent            Be silent; don\nt output anything.\n  -v, --verbose    
       Enable verbose output when executing commands.\nexit status 
1\n\n\n\n\n\nAh. Forgot to create an image ou
 t of the blinky binary. Note that every time you want to build and \nload a 
new firmware image to a target board, you need to run 'create-image' on 
it.\n\n\n[user@IsMyLaptop:~/src/air_quality]$ newt create-image blink_primo 
0.0.1\nApp image successfully generated: 
/Users/user/src/air_quality/bin/blink_primo/apps/blinky/blinky.img\nBuild 
manifest: 
/Users/user/src/air_quality/bin/blink_nrf/apps/blinky/manifest.json\n[user@IsMyLaptop:~/src/air_quality]$
 newt load blink_primo\n\n\n\n\n\nAnd it's blinking.\n\n\nShortcut for doing 
build/create-image/load/debug steps all in one is 'newt run' command. Check 
\nout the usage from command line help.\n\n\nCreate test project\n\n\nNow that 
you have your system setup, you can start creating your own stuff.\nFirst you 
want to create a project for yourself - you could start by using blinky as a 
project \ntemplate, but since we're going to want to be able to access the data 
via Bluetooth, let's \nuse the \nbleprph\n Bluetooth Peripheral project inst
 ead.\n\n\n    [user@IsMyLaptop:~/src/air_quality]$ mkdir apps/air_quality\n    
[user@IsMyLaptop:~/src/air_quality]$ cp 
repos/apache-mynewt-core/apps/bleprph/pkg.yml apps/air_quality/\n    
[user@IsMyLaptop:~/src/air_quality]$ cp -Rp 
repos/apache-mynewt-core/apps/bleprph/src apps/air_quality/\n\n\n\n\n\nThen you 
modify the apps/air_quality/pkg.yml for air_quality in order to change the 
\npkg.name\n to be \napps/air_quality\n.\nYou'll need to add the 
\n@apache-mynewt-core/\n path to all the package dependencies, since the app no 
longer\nresides within the apache-mynewt-core repository.\n\n\nThe Arduino 
Primo board has a limited amount of memory, so you must also switch your libc 
to be baselibc, instead of the standard 
one.\n\n\n[user@IsMyLaptop:~/src/air_quality]$ cat 
apps/air_quality/pkg.yml\npkg.name: apps/air_quality\npkg.type: 
app\npkg.description: BLE Air Quality application.\npkg.author: \nApache Mynewt 
\[email protected]\n\npkg.homepage: \nhttp://mynewt.apache.org
 /\n\npkg.keywords:\n\npkg.deps:\n    - \n@apache-mynewt-core/kernel/os\n\n    
- \n@apache-mynewt-core/sys/log\n\n    - \n@apache-mynewt-core/mgmt/newtmgr\n\n 
   - \n@apache-mynewt-core/mgmt/newtmgr/transport/ble\n\n    - 
\n@apache-mynewt-core/net/nimble/controller\n\n    - 
\n@apache-mynewt-core/net/nimble/host\n\n    - 
\n@apache-mynewt-core/net/nimble/host/services/ans\n\n    - 
\n@apache-mynewt-core/net/nimble/host/services/gap\n\n    - 
\n@apache-mynewt-core/net/nimble/host/services/gatt\n\n    - 
\n@apache-mynewt-core/net/nimble/host/store/ram\n\n    - 
\n@apache-mynewt-core/net/nimble/transport/ram\n\n    - 
\n@apache-mynewt-core/sys/console/full\n\n    - 
\n@apache-mynewt-core/libc/baselibc\n\n    - 
\n@apache-mynewt-core/sys/sysinit\n\n    - 
\n@apache-mynewt-core/sys/id\n\n\n\n\n\n\nAnd create a target for 
it:\n\n\n[user@IsMyLaptop:~/src/air_quality]$ newt target create air_q\nTarget 
targets/air_q successfully created\n[user@IsMyLaptop:~/src/air_quality]$ newt 
target set air_q bsp=@a
 pache-mynewt-core/hw/bsp/arduino_primo_nrf52\nTarget targets/air_q 
successfully set target.bsp to 
@apache-mynewt-core/hw/bsp/arduino_primo_nrf52\n[user@IsMyLaptop:~/src/air_quality]$
 newt target set air_q app=apps/air_quality \nTarget targets/air_q successfully 
set target.app to apps/air_quality\n[user@IsMyLaptop:~/src/air_quality]$ newt 
target set air_q build_profile=debug\nTarget targets/air_q successfully set 
target.build_profile to debug\n[user@IsMyLaptop:~/src/air_quality]$ newt build 
air_q\n ....\nLinking 
/Users/dsimmons/dev/myproj/bin/targets/air_q/app/apps/air_quality/air_quality.elf\nTarget
 successfully built: targets/air_q\n\n\n\n\n\nCreate packages for 
drivers\n\n\nOne of the sensors you want to enable is SenseAir K30, which will 
connect to the board over a serial port.\nTo start development of the driver, 
you first need to create a package description for it, and add stubs for 
sources.\n\n\nThe first thing to do is to create the directory structure for 
your driver:\n\n\n
 [user@IsMyLaptop:~/src/air_quality]$ mkdir -p 
libs/my_drivers/senseair/include/senseair\n[user@IsMyLaptop:~/src/air_quality]$ 
mkdir -p libs/my_drivers/senseair/src\n\n\n\n\n\nNow 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.\n\n\n[user@IsMyLaptop:~/src/air_quality]$ cat 
libs/my_drivers/senseair/pkg.yml\n\n\n\n\n\n#\n\n\n# Licensed to the Apache 
Software Foundation (ASF) under one\n\n\n# or more contributor license 
agreements.  See the NOTICE file\n\n\n# distributed with this work for 
additional information\n\n\n# regarding copyright ownership.  The ASF licenses 
this file\n\n\n# to you under the Apache License, Version 2.0 (the\n\n\n# 
\nLicense\n); you may not use this file except in compliance\n\n\n# with the 
License.  You may obtain a copy of the License at\n\n\n# \n\n\n#  
http:\n//www.apache.org/licenses/LICENSE-2.0\n\n\n#\n\n\n# Unless required by 
applicable law or agreed to in writing,\n\n\n# software 
 distributed under the License is distributed on an\n\n\n# \nAS IS\n BASIS, 
WITHOUT WARRANTIES OR CONDITIONS OF ANY\n\n\n# KIND, either express or implied. 
 See the License for the\n\n\n# specific language governing permissions and 
limitations\n\n\n# under the License.\n\n\n#\n\n\npkg\n.\nname\n: 
\nlibs/my_drivers/senseair\n\n\npkg\n.\ndeps\n:\n    \n-\n 
\n@apache-mynewt-core/hw/hal\n\n\n\n\n\n\n[user@IsMyLaptop:~/src/air_quality]$ 
cat libs/my_drivers/senseair/include/senseair/senseair.h\n\n\n\n\n\n/*\n\n\n * 
Licensed to the Apache Software Foundation (ASF) under one\n\n\n * or more 
contributor license agreements.  See the NOTICE file\n\n\n * distributed with 
this work for additional information\n\n\n * regarding copyright ownership.  
The ASF licenses this file\n\n\n * to you under the Apache License, Version 2.0 
(the\n\n\n * \nLicense\n); you may not use this file except in compliance\n\n\n 
* with the License.  You may obtain a copy of the License at\n\n\n * \n\n\n *  
http://www.apa
 che.org/licenses/LICENSE-2.0\n\n\n *\n\n\n * Unless required by applicable law 
or agreed to in writing,\n\n\n * software distributed under the License is 
distributed on an\n\n\n * \nAS IS\n BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 
ANY\n\n\n * KIND, either express or implied.  See the License for the\n\n\n * 
specific language governing permissions and limitations\n\n\n * under the 
License.\n\n\n*/\n\n\n#ifndef _SENSEAIR_H_\n\n\n#define 
_SENSEAIR_H_\n\n\n\nvoid\n \nsenseair_init\n(\nvoid\n);\n\n\n#endif \n/* 
_SENSEAIR_H_ */\n\n\n\n\n\n\n[user@IsMyLaptop:~/src/air_quality]$ cat 
libs/my_drivers/senseair/src/senseair.c\n\n\n\n\n\n/**\n\n\n * Licensed to the 
Apache Software Foundation (ASF) under one\n\n\n * or more contributor license 
agreements.  See the NOTICE file\n\n\n * distributed with this work for 
additional information\n\n\n * regarding copyright ownership.  The ASF licenses 
this file\n\n\n * to you under the Apache License, Version 2.0 (the\n\n\n * 
\nLicense\n); you may not u
 se this file except in compliance\n\n\n * with the License.  You may obtain a 
copy of the License at\n\n\n * \n\n\n *  
http://www.apache.org/licenses/LICENSE-2.0\n\n\n *\n\n\n * Unless required by 
applicable law or agreed to in writing,\n\n\n * software distributed under the 
License is distributed on an\n\n\n * \nAS IS\n BASIS, WITHOUT WARRANTIES OR 
CONDITIONS OF ANY\n\n\n * KIND, either express or implied.  See the License for 
the\n\n\n * specific language governing permissions and limitations\n\n\n * 
under the License.\n\n\n 
*/\n\n\n\nvoid\n\n\nsenseair_init\n(\nvoid\n)\n{\n}\n\n\n\n\n\nAnd add 
dependency to this package in your project yml file.\n\n\nHere's the listing 
from apps/air_quality/pkg.yml\n\n\npkg.name: apps/air_quality\npkg.type: 
app\npkg.description: Air quality sensor test\npkg.keywords:\n\npkg.deps:\n    
- \n@apache-mynewt-core/libs/console/full\n\n    - 
\n@apache-mynewt-core/libs/newtmgr\n\n    - \n@apache-mynewt-core/libs/os\n\n   
 - \n@apache-mynewt-core/libs/she
 ll\n\n    - \n@apache-mynewt-core/sys/config\n\n    - 
\n@apache-mynewt-core/sys/log\n\n    - \n@apache-mynewt-core/sys/stats\n\n    - 
\n@apache-mynewt-core/libs/baselibc\n\n    - 
libs/my_drivers/senseair\n\n\n\n\n\nAnd add a call to your main() to initialize 
this driver.\n\n\n    [user@IsMyLaptop:~/src/air_quality]$ diff 
project/blinky/src/main.c project/air_quality/src/main.c\n    28a29\n    \n 
#include \nsenseair/senseair.h\n\n    190a192\n    \n senseair_init();\n    
[user@IsMyLaptop:~/src/air_quality\n\n\n\n\n\nThe ble_prph app runs everything 
in one task handler. For this project, we're going to add a second\ntask 
handler to respond to the shell, and then handle communicating with the 
senseair sensor for us.\n\n\n/** shell task settings. */\n\n\n#define 
SHELL_TASK_PRIO           2\n\n\n#define SHELL_STACK_SIZE          
(OS_STACK_ALIGN(336))\n\n\n\nstruct\n \nos_eventq\n \nshell_evq\n;\n\nstruct\n 
\nos_task\n \nshell_task\n;\n\nbssnz_t\n \nos_stack_t\n 
\nshell_stack\n[\nSHELL_ST
 ACK_SIZE\n];\n\n\n\n\n\nThat defines the task, now we need to initialize it, 
add a task handler, and we're going to \nuse this task as our default task 
handler.\n\n\n/**\n\n\n * Event loop for the main shell task.\n\n\n 
*/\n\n\nstatic\n \nvoid\n\n\nshell_task_handler\n(\nvoid\n \n*unused\n)\n{\n    
\nwhile\n (\n1\n) {\n        \nos_eventq_run\n(\nshell_evq\n);\n    
}\n}\n\n\n\n\n\nAnd in your \nmain()\n add:\n\n\n    \n/* Initialize shell 
eventq */\n\n    \nos_eventq_init\n(\nshell_evq\n);\n\n    \n/* Create the 
shell task.  \n\n\n     * All shell operations are performed in this 
task.\n\n\n     */\n\n    \nos_task_init\n(\nshell_task\n, \nshell\n, 
\nshell_task_handler\n,\n                              \nNULL\n, 
\nSHELL_TASK_PRIO\n, \nOS_WAIT_FOREVER\n,\n                              
\nshell_stack\n, \nSHELL_STACK_SIZE\n);\n\n\n\n\n\nDon't forget to change your 
default task handler!\n\n\n    
\nos_eventq_dflt_set\n(\nshell_evq\n);\n\n\n\n\n\nAnd then build it to make 
sure all goes we
 ll.\n\n\n[user@IsMyLaptop:~/src/air_quality]$ newt build air_q\nCompiling 
senseair.c\nArchiving senseair.a\nLinking air_quality.elf\nApp successfully 
built: 
/Users/user/src/air_quality/bin/air_q/apps/air_quality/air_quality.elf\n\n\n\n\n\nAll
 looks good.\n\n\nAdd CLI commands for testing drivers\n\n\nWhile developing 
the driver, you want to issue operations from console asking it to do stuff. 
We'll assume that you've already worked through the tutorial \non how to 
\nenable the CLI\n, so all we'll need to do is add the propper values to the 
project's \nsyscfg.yml\n file:\n\n\n[user@IsMyLaptop:~/src/air_quality]$ cat 
targets/air_q/syscfg.yml\nsyscfg.vals:\n    # Set as per blinky_primo\n    
OPENOCD_DEBUG: 1\n    # Enable the shell task.\n    SHELL_TASK: 1\n    
STATS_CLI: 1\n    CONSOLE_TICKS: 1\n    CONSOLE_PROMPT: 1\n\n\n\n\n\nThen 
register your senseair command with the shell by adding the following to 
\nlibs/my_drivers/senseair/src/senseair.c\n\n\n#include 
\nshell/shell.h\n\n\n#inc
 lude \nconsole/console.h\n\n\n#include \nassert.h\n\n\n\n\nstatic\n \nint\n 
\nsenseair_shell_func\n(\nint\n \nargc\n, \nchar\n \n**argv\n);\n\nstatic\n 
\nstruct\n \nshell_cmd\n \nsenseair_cmd\n \n=\n {\n    .\nsc_cmd\n \n=\n 
\nsenseair\n,\n    .\nsc_cmd_func\n \n=\n 
\nsenseair_shell_func\n,\n};\n\n\nvoid\n\n\nsenseair_init\n(\nvoid\n)\n{\n    
\nint\n \nrc\n;\n\n    \nrc\n \n=\n \nshell_cmd_register\n(\nsenseair_cmd\n);\n 
   \nassert\n(\nrc\n \n==\n \n0\n);\n}\n\n\nstatic\n 
\nint\n\n\nsenseair_shell_func\n(\nint\n \nargc\n, \nchar\n \n**argv\n)\n{\n    
\nconsole_printf\n(\nYay! Somebody called!\\n\n);\n    \nreturn\n 
\n0\n;\n\n}\n\n\n\n\n\nNow you can you build this, download to target, and 
start minicom on your console port. If you haven't already, familiarize 
yourself with\nthe tutorial on how to connect a serial port to your board 
\nhere\n.\n\n\nYou'll need to wire up your Board to a Serial converter first. 
On the Arduino Primo Board pin 1 is TX and pin 0 is RX so wire 1 to RX on 
 your serial board, and 0 to TX on your serial board.\n\n\n    
[user@IsMyLaptop:~]$ minicom -D /dev/tty.usbserial-AH02MIE2\n\n\n    Welcome to 
minicom 2.7\n\n    OPTIONS: \n    Compiled on Oct 12 2015, 07:48:30.\n    Port 
/dev/tty.usbserial-AH02MIE2, 13:44:40\n\n    Press CTRL-X Z for help on special 
keys\n\n    ?\n    419: \n ?\n    Commands:\n    641:     stat      echo        
 ?    prompt     ticks     tasks\n    643: mempools      date  senseair\n    
644: \n senseair\n    Yay! Somebody called!\n    1125: \n\n    53611: \n 
tasks\n    Tasks:\n    54047:    task pri tid  runtime      csw    stksz   
stkuse   lcheck   ncheck flg\n    54057:    idle 255   0    54048    66890      
 64       30        0        0   0\n    54068:  ble_ll   0   1        9    
64986       80       58        0        0   0\n    54079: bleprph   1   2       
 0        1      336       32        0        0   0\n    54090:   shell   2   3 
       0     2077      336      262        0        0   0\n    54101: \n\n\n
 \n\n\n\nThat's great. Your shell task is running, and is responding 
appropriately!\nYou can connect the hardware to your board and start developing 
code for the driver itself.\n\n\nUse of HAL for drivers\n\n\nThe sensor has a 
serial port connection, and that's how you are going to connect to it. Your 
original BSP, hw/bsp/arduino_primo_nrf52, has two UARTs set up.\nWe're using 
one for our shell/console. It also has a second UART set up as a 'bit-bang' 
UART but since the SenseAir only needs to\ncommunicate at 9600 baud, this 
bit-banged uart is plenty fast enough.\n\n\nYou'll have to make a small change 
to the \nsyscfg.yml\n file in your project's target directory to chang the pin 
definitions \nfor this second UART. Those changes are as follows:\n\n\n    
UART_0_PIN_TX: 23\n    UART_0_PIN_RX: 24\n\n\n\n\n\nWith this in place, you can 
refer to serial port where your SenseAir sensor by a logical number. This makes 
the code more platform independent - you could connect this sensor to anoth
 er board, like Olimex. You will 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.\n\n\nYou will now see what the 
driver code ends up looking like. Here's the header file, filled in from the 
stub you created earlier.\n\n\n/*\n\n\n * Licensed to the Apache Software 
Foundation (ASF) under one\n\n\n * or more contributor license agreements.  See 
the NOTICE file\n\n\n * distributed with this work for additional 
information\n\n\n * regarding copyright ownership.  The ASF licenses this 
file\n\n\n * to you under the Apache License, Version 2.0 (the\n\n\n * 
\nLicense\n); you may not use this file except in compliance\n\n\n * with the 
License.  You may obtain a copy of the License at\n\n\n * \n\n\n *  
http://www.apache.org/licenses/LICENSE-2.0\n\n\n *\n\n\n * Unless required by 
applicable law or agreed to in writing,\n\n\n * software distributed under the 
License is distribute
 d on an\n\n\n * \nAS IS\n BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n\n\n 
* KIND, either express or implied.  See the License for the\n\n\n * specific 
language governing permissions and limitations\n\n\n * under the 
License.\n\n\n*/\n\n\n#ifndef _SENSEAIR_H_\n\n\n#define 
_SENSEAIR_H_\n\n\n\nenum\n \nsenseair_read_type\n {\n        
\nSENSEAIR_CO2\n,\n};\n\n\nint\n \nsenseair_init\n(\nint\n 
\nuartno\n);\n\n\nint\n \nsenseair_read\n(\nenum\n 
\nsenseair_read_type\n);\n\n\n#endif \n/* _SENSEAIR_H_ */\n\n\n\n\n\n\nAs you 
can see, logical UART number has been added to the init routine. A 'read' 
function has been added, \nwhich is a blocking read. If you were making a 
commercial product, you would probably have a callback for reporting the 
results.\n\n\nAnd here is the source for the driver.\n\n\n/**\n\n\n * Licensed 
to the Apache Software Foundation (ASF) under one\n\n\n * or more contributor 
license agreements.  See the NOTICE file\n\n\n * distributed with this work for 
additional in
 formation\n\n\n * regarding copyright ownership.  The ASF licenses this 
file\n\n\n * to you under the Apache License, Version 2.0 (the\n\n\n * 
\nLicense\n); you may not use this file except in compliance\n\n\n * with the 
License.  You may obtain a copy of the License at\n\n\n *\n\n\n *  
http://www.apache.org/licenses/LICENSE-2.0\n\n\n *\n\n\n * Unless required by 
applicable law or agreed to in writing,\n\n\n * software distributed under the 
License is distributed on an\n\n\n * \nAS IS\n BASIS, WITHOUT WARRANTIES OR 
CONDITIONS OF ANY\n\n\n * KIND, either express or implied.  See the License for 
the\n\n\n * specific language governing permissions and limitations\n\n\n * 
under the License.\n\n\n */\n\n\n#include \nstring.h\n\n\n\n#include 
\nshell/shell.h\n\n\n#include \nconsole/console.h\n\n\n#include 
\nos/os.h\n\n\n\n#include \nhal/hal_uart.h\n\n\n\n#include 
\nsenseair/senseair.h\n\n\n\nstatic\n \nconst\n \nuint8_t\n \ncmd_read_co2\n[] 
\n=\n {\n    \n0xFE\n, \n0\nX44\n, \n0\nX00\n, \n
 0\nX08\n, \n0\nX02\n, \n0\nX9F\n, \n0\nX25\n\n};\n\n\nstatic\n \nint\n 
\nsenseair_shell_func\n(\nint\n \nargc\n, \nchar\n \n**argv\n);\n\nstatic\n 
\nstruct\n \nshell_cmd\n \nsenseair_cmd\n \n=\n {\n    .\nsc_cmd\n \n=\n 
\nsenseair\n,\n    .\nsc_cmd_func\n \n=\n 
\nsenseair_shell_func\n,\n};\n\n\nstruct\n \nsenseair\n { \n    \nint\n 
\nuart\n;\n    \nstruct\n \nos_sem\n \nsema\n;\n    \nconst\n \nuint8_t\n 
\n*tx_data\n;\n    \nint\n \ntx_off\n;\n    \nint\n \ntx_len\n;\n    
\nuint8_t\n \nrx_data\n[\n32\n]; \n    \nint\n \nrx_off\n;\n    \nint\n 
\nvalue\n;\n} \nsenseair\n;\n\n\nstatic\n 
\nint\n\n\nsenseair_tx_char\n(\nvoid\n \n*arg\n)\n{\n    \nstruct\n 
\nsenseair\n \n*s\n \n=\n \nsenseair\n;\n    \nint\n \nrc\n;\n\n    \nif\n 
(\ns-\ntx_off\n \n=\n \ns-\ntx_len\n) {\n    \n/*\n\n\n         * Command tx 
finished.\n\n\n         */\n\n        \ns-\ntx_data\n \n=\n \nNULL\n;\n        
\nreturn\n \n-\n1\n;\n    }\n\n    \nrc\n \n=\n 
\ns-\ntx_data\n[\ns-\ntx_off\n];\n    \ns-\ntx_off++\n;\n  
   \nreturn\n \nrc\n;\n}\n\n\n/*\n\n\n * CRC for modbus over serial port.\n\n\n 
*/\n\n\nstatic\n \nconst\n \nuint16_t\n \nmb_crc_tbl\n[] \n=\n {\n    
\n0x0000\n, \n0xcc01\n, \n0xd801\n, \n0x1400\n, \n0xf001\n, \n0x3c00\n, 
\n0x2800\n, \n0xe401\n,\n    \n0xa001\n, \n0x6c00\n, \n0x7800\n, \n0xb401\n, 
\n0x5000\n, \n0x9c01\n, \n0x8801\n, \n0x4400\n\n};\n\n\nstatic\n 
\nuint16_t\n\n\nmb_crc\n(\nconst\n \nuint8_t\n \n*data\n, \nint\n \nlen\n, 
\nuint16_t\n \ncrc\n)\n{\n    \nwhile\n (\nlen--\n \n \n0\n) {\n        \ncrc\n 
\n^=\n \n*data++\n;\n        \ncrc\n \n=\n (\ncrc\n \n \n4\n) \n^\n 
\nmb_crc_tbl\n[\ncrc\n \n \n0xf\n];\n        \ncrc\n \n=\n (\ncrc\n \n \n4\n) 
\n^\n \nmb_crc_tbl\n[\ncrc\n \n \n0xf\n];\n    }\n    \nreturn\n 
\ncrc\n;\n}\n\n\nstatic\n \nint\n\n\nmb_crc_check\n(\nconst\n \nvoid\n 
\n*pkt\n, \nint\n \nlen\n)\n{\n    \nuint16_t\n \ncrc\n, \ncmp\n;\n    
\nuint8_t\n \n*bp\n \n=\n (\nuint8_t\n \n*\n)\npkt\n;\n\n    \nif\n (\nlen\n \n 
\nsizeof\n(\ncrc\n) \n+\n \n1\n) {\n        \n
 return\n \n-\n1\n;\n    }\n    \ncrc\n \n=\n \nmb_crc\n(\npkt\n, \nlen\n \n-\n 
\n2\n, \n0xffff\n);\n    \ncmp\n \n=\n \nbp\n[\nlen\n \n-\n \n2\n] \n|\n 
(\nbp\n[\nlen\n \n-\n \n1\n] \n \n8\n);\n    \nif\n (\ncrc\n \n!=\n \ncmp\n) 
{\n        \nreturn\n \n-\n1\n;\n    } \nelse\n {\n        \nreturn\n \n0\n;\n  
  }\n}\n\n\nstatic\n \nint\n\n\nsenseair_rx_char\n(\nvoid\n \n*arg\n, 
\nuint8_t\n \ndata\n)\n{\n    \nstruct\n \nsenseair\n \n*s\n \n=\n (\nstruct\n 
\nsenseair\n \n*\n)\narg\n;\n    \nint\n \nrc\n;\n\n    \nif\n (\ns-\nrx_off\n 
\n=\n \nsizeof\n(\ns-\nrx_data\n)) {\n        \ns-\nrx_off\n \n=\n \n0\n;\n    
}\n    \ns-\nrx_data\n[\ns-\nrx_off\n] \n=\n \ndata\n;\n    
\ns-\nrx_off++\n;\n\n    \nif\n (\ns-\nrx_off\n \n==\n \n7\n) {\n        \nrc\n 
\n=\n \nmb_crc_check\n(\ns-\nrx_data\n, \ns-\nrx_off\n);\n        \nif\n 
(\nrc\n \n==\n \n0\n) {\n            \ns-\nvalue\n \n=\n \ns-\nrx_data\n[\n3\n] 
\n*\n \n256\n \n+\n \ns-\nrx_data\n[\n4\n];\n            
\nos_sem_release\n(\ns-\nsema\n
 );\n        }\n    }\n    \nreturn\n 
\n0\n;\n}\n\n\nvoid\n\n\nsenseair_tx\n(\nstruct\n \nsenseair\n \n*s\n, 
\nconst\n \nuint8_t\n \n*tx_data\n, \nint\n \ndata_len\n)\n{\n    
\ns-\ntx_data\n \n=\n \ntx_data\n;\n    \ns-\ntx_len\n \n=\n \ndata_len\n;\n    
\ns-\ntx_off\n \n=\n \n0\n;\n    \ns-\nrx_off\n \n=\n \n0\n;\n\n    
\nhal_uart_start_tx\n(\ns-\nuart\n);\n}\n\n\nint\n\n\nsenseair_read\n(\nenum\n 
\nsenseair_read_type\n \ntype\n)\n{\n    \nstruct\n \nsenseair\n \n*s\n \n=\n 
\nsenseair\n;\n    \nconst\n \nuint8_t\n \n*cmd\n;\n    \nint\n \ncmd_len\n;\n  
  \nint\n \nrc\n;\n\n    \nif\n (\ns-\ntx_data\n) {\n        \n/*\n\n\n         
* busy\n\n\n         */\n\n        \nreturn\n \n-\n1\n;\n    }\n    \nswitch\n 
(\ntype\n) {\n    \ncase\n \nSENSEAIR_CO2\n:\n        \ncmd\n \n=\n 
\ncmd_read_co2\n;\n        \ncmd_len\n \n=\n \nsizeof\n(\ncmd_read_co2\n);\n    
    \nbreak\n;\n    \ndefault\n:\n\n        \nreturn\n \n-\n1\n;\n    }\n    
\nsenseair_tx\n(\ns\n, \ncmd\n, \ncmd_len\n);\n    \nr
 c\n \n=\n \nos_sem_pend\n(\ns-\nsema\n, \nOS_TICKS_PER_SEC\n \n/\n \n2\n);\n   
 \nif\n (\nrc\n \n==\n \nOS_TIMEOUT\n) {\n        \n/*\n\n\n         * 
timeout\n\n\n         */\n\n        \nreturn\n \n-\n2\n;\n    }\n    \nreturn\n 
\ns-\nvalue\n;\n}\n\n\nstatic\n \nint\n\n\nsenseair_shell_func\n(\nint\n 
\nargc\n, \nchar\n \n**argv\n)\n{\n    \nint\n \nvalue\n;\n    \nenum\n 
\nsenseair_read_type\n \ntype\n;\n\n    \nif\n (\nargc\n \n \n2\n) 
{\n\nusage\n:\n        \nconsole_printf\n(\n%s co2\\n\n, \nargv\n[\n0\n]);\n    
    \nreturn\n \n0\n;\n    }\n    \nif\n (\n!strcmp\n(\nargv\n[\n1\n], 
\nco2\n)) {\n        \ntype\n \n=\n \nSENSEAIR_CO2\n;\n    } \nelse\n {\n       
 \ngoto\n \nusage\n;\n    }\n    \nvalue\n \n=\n \nsenseair_read\n(\ntype\n);\n 
   \nif\n (\nvalue\n \n=\n \n0\n) {\n        \nconsole_printf\n(\nGot %d\\n\n, 
\nvalue\n);\n    } \nelse\n {\n        \nconsole_printf\n(\nError while 
reading: %d\\n\n, \nvalue\n);\n    }\n    \nreturn\n 
\n0\n;\n}\n\n\nint\n\n\nsenseair_init\n(
 \nint\n \nuartno\n)\n{\n    \nint\n \nrc\n;\n    \nstruct\n \nsenseair\n 
\n*s\n \n=\n \nsenseair\n;\n\n    \nrc\n \n=\n 
\nshell_cmd_register\n(\nsenseair_cmd\n);\n    \nif\n (\nrc\n) {\n        
\nreturn\n \nrc\n;\n    }\n\n    \nrc\n \n=\n \nos_sem_init\n(\ns-\nsema\n, 
\n1\n);\n    \nif\n (\nrc\n) {\n        \nreturn\n \nrc\n;\n    }\n    \nrc\n 
\n=\n \nhal_uart_init_cbs\n(\nuartno\n, \nsenseair_tx_char\n, \nNULL\n,\n      
\nsenseair_rx_char\n, \nsenseair\n);\n    \nif\n (\nrc\n) {\n        \nreturn\n 
\nrc\n;\n    }\n    \nrc\n \n=\n \nhal_uart_config\n(\nuartno\n, \n9600\n, 
\n8\n, \n1\n, \nHAL_UART_PARITY_NONE\n,\n      \nHAL_UART_FLOW_CTL_NONE\n);\n   
 \nif\n (\nrc\n) {\n        \nreturn\n \nrc\n;\n    }\n    \ns-\nuart\n \n=\n 
\nuartno\n;\n\n    \nreturn\n \n0\n;\n}\n\n\n\n\n\nAnd your modified your 
main() for senseair driver init.\n\n\nint\n\n\nmain\n(\nint\n \nargc\n, 
\nchar\n \n**argv\n)\n{\n    ....\n    \nsenseair_init\n(\n0\n);\n    ....\n    
}\n\n\n\n\n\nYou can see from t
 he code that you are using the HAL interface to open a UART port, and using OS 
\nsemaphore as a way of blocking the task when waiting for read response to 
come back from the sensor.\n\n\nNow comes the fun part: Hooking up the sensor! 
It's fun because a) hooking up a sensor is always \nfun and b) the SenseAir 
sensor's PCB is entirely unlabeled, so you'll have to trust us on how to hook 
it up. \n\n\nSo here we go. \n\n\nYou'll have to do a little soldering. I 
soldered some header pins to the SenseAir K30 board to\nmake connecting wires 
easier using standard jumper wires, but you can also just solder 
wires\nstraight to the board if you prefer.\n\n\nHere's what your SenseAir 
board should look like once it's wired up:\n\n\n\n\nNow that you have that 
wired up, let's get the Arduino Primo wired up. A couple of things to 
note:\n\n\n\n\nThe Arduino Primo's 'console' UART is actually UART1. The 
secondary (bit-banged) UART is \nUART0, so that's where we'll have to hook up 
the SenseAir.\n\n\n\n
 \nHere's what your Arduino Primo should now look like with everything wired 
in:\n\n\n\n\nEverything is wired and you're ready to go! Build and load your 
new app:\n\n\n$ newt build air_q\nBuilding target targets/air_q\nCompiling 
apps/air_quality/src/main.c\nArchiving apps_air_quality.a\nLinking 
myproj/bin/targets/air_q/app/apps/air_quality/air_quality.elf\nTarget 
successfully built: targets/air_q\n$ newt create-image air_q 1.0.0\nApp image 
succesfully generated: 
myproj/bin/targets/air_q/app/apps/air_quality/air_quality.img\n$ newt load 
air_q\nLoading app image into slot 1\n\n\n\n\n\nNow, you should be able to 
connect to your serial port and read values:\n\n\nuser@IsMyLaptop:~]$ minicom 
-D /dev/tty.usbserial-AH02MIE2\n\n\n    Welcome to minicom 2.7\n\n    OPTIONS: 
\n    Compiled on Oct 12 2015, 07:48:30.\n    Port /dev/tty.usbserial-AH02MIE2, 
13:44:40\n\n    Press CTRL-X Z for help on special keys\n\n    1185: \n ?\n    
Commands:\n    1382:     stat      echo         ?    prompt     t
 icks     tasks\n    1390: mempools      date  senseair\n    1395: \n 
senseair\n    senseair co2\n    2143: \n senseair co2\n    Got 
973\n\n\n\n\n\nAnd you're getting valid readings! Congratulations!\n\n\nNext 
we'll hook this all up via Bluetooth so that you can read those values 
remotely.", 
+            "text": "Air quality sensor project\n\n\nSetting up source tree 
for stuff you need\n\n\nTo start with, you need to create a new project under 
which you will do this development. So you type in:\n\n\n    $ mkdir 
$HOME/src\n    $ cd $HOME/src\n    $ newt new air_quality\n\n\n\n\n\nLet's say 
you are using Arduino Primo -- which is based on the Nordic Semi NRF52 chip -- 
as the platform. \nYou know you need the board support package for that 
hardware. You can look up its location, add it your \nproject, and fetch that 
along with the core OS components. Luckily, the Arduino Primo is supported in 
the \nMynewt Core, so there's nothing much to do here. \n\n\nYour project.yml 
file should look like this:\n\n\n    [user@IsMyLaptop:~/src/air_quality]$ emacs 
project.yml \n\n    [user@IsMyLaptop:~/src/air_quality]$ cat project.yml\n    
project.name: \nair_quality\n\n\n    project.repositories:\n        - 
apache-mynewt-core\n\n    # Use github\ns distribution mechanism for core ASF 
libr
 aries.\n    # This provides mirroring automatically for us.\n    #\n    
repository.apache-mynewt-core:\n        type: github\n        vers: 0-latest\n  
      user: apache\n        repo: incubator-mynewt-core\n\n    
[user@IsMyLaptop:~/src/air_quality]$ newt install\n    apache-mynewt-core\n    
[user@IsMyLaptop:~/src/air_quality]$ ls repos/\n    
apache-mynewt-core\n\n\n\n\n\nGood. You want to make sure you have all the 
needed bits for supporting your board; \nso you decide to build the blinky 
project for the platform first.\n\n\nNow create a target for it and build it. 
Easiest way to proceed is to copy the existing target for blinky, and modify it 
to build for Arduino Primo board.\n\n\n[user@IsMyLaptop:~/src/air_quality]$ 
newt target copy my_blinky_sim blink_primo\nTarget successfully copied; 
targets/my_blinky_sim --\n 
targets/blink_primo\n[user@IsMyLaptop:~/src/air_quality]$ newt target set 
blink_primo bsp=@apache-mynewt-core/hw/bsp/arduino_primo_nrf52\nTarget 
targets/blink_nrf succe
 ssfully set target.bsp to 
@apache-mynewt-core/hw/bsp/arduino_primo_nrf52\n[user@IsMyLaptop:~/src/air_quality]$
 newt build blink_primo\nCompiling hal_bsp.c\n...\nLinking blinky.elf\nApp 
successfully built: 
/Users/user/src/air_quality/bin/blink_primo/apps/blinky/blinky.elf\n\n\n\n\n\nGood.\n\n\nYou
 know that this platform uses bootloader, which means you have to create a 
target for that too.\n\n\n[user@IsMyLaptop:~/src/air_quality]$ newt target 
create boot_primo\nTarget targets/boot_nrf successfully 
created\n[user@IsMyLaptop:~/src/air_quality]$ newt target 
show\n@apache-mynewt-core/targets/unittest\n    bsp=hw/bsp/native\n    
build_profile=debug\n    compiler=compiler/sim\ntargets/blink_primo\n    
app=apps/blinky\n    bsp=@apache-mynewt-core/hw/bsp/arduino_primo_nrf52\n    
build_profile=debug\ntargets/boot_primo\ntargets/my_blinky_sim\n    
app=apps/blinky\n    bsp=@apache-mynewt-core/hw/bsp/native\n    
build_profile=debug\n[user@IsMyLaptop:~/src/air_quality]$ newt target set 
boot_nrf 
 bsp=@apache-mynewt-core/hw/bsp/arduino_primo_nrf52\nTarget targets/boot_nrf 
successfully set target.bsp to 
@apache-mynewt-core/hw/bsp/arduino_primo_nrf52\n[user@IsMyLaptop:~/src/air_quality]$
 newt target set boot_nrf app=@apache-mynewt-core/apps/boot\nTarget 
targets/boot_nrf successfully set target.app to 
@apache-mynewt-core/apps/boot\n[user@IsMyLaptop:~/src/air_quality]$ newt target 
set boot_nrf build_profile=optimized\nTarget targets/boot_nrf successfully set 
target.build_profile to optimized\n\n\n\n\n\nAnd then build it, and load it 
onto the board.\n\n\nnewt build boot_primo\n....\nLinking boot.elf\nApp 
successfully built: 
/Users/user/src/air_quality/bin/boot_primo/apps/boot/boot.elf\n[user@IsMyLaptop:~/src/air_quality]\n$
 newt load boot_primo\n\n\n\n\n\nAt this point, you may (or may not) see a 
bunch of error messages about not being able to connect to\nyour board, not 
being able to load the image, etc. If that's the case, and you haven't already, 
you\nshould most definitely go 
 worth through the \nblinky_primo\n tutorial so that you\ncan properly 
communicate with your board.\n\n\nNext you must download the targets to board, 
and see that the LED actually blinks. You plug in the \nArduino Primo board to 
your laptop, and say:\n\n\n[user@IsMyLaptop:~/src/air_quality]$ newt load 
blink_primo\nLoading app image into slot 1\nError: couldn\nt open 
/Users/user/src/air_quality/bin/blink_primo/apps/blinky/blinky.img\n\nError: 
exit status 1\n\nload - Load app image to target for 
\ntarget-name\n.\n\nUsage:\n  newt load [flags]\n\nExamples:\n  newt load 
\ntarget-name\n\n\n\nGlobal Flags:\n  -l, --loglevel string   Log level, 
defaults to WARN. (default \nWARN\n)\n  -o, --outfile string    Filename to tee 
log output to\n  -q, --quiet             Be quiet; only display error output.\n 
 -s, --silent            Be silent; don\nt output anything.\n  -v, --verbose    
       Enable verbose output when executing commands.\nexit status 
1\n\n\n\n\n\nAh. Forgot to create an image ou
 t of the blinky binary. Note that every time you want to build and \nload a 
new firmware image to a target board, you need to run 'create-image' on 
it.\n\n\n[user@IsMyLaptop:~/src/air_quality]$ newt create-image blink_primo 
0.0.1\nApp image successfully generated: 
/Users/user/src/air_quality/bin/blink_primo/apps/blinky/blinky.img\nBuild 
manifest: 
/Users/user/src/air_quality/bin/blink_nrf/apps/blinky/manifest.json\n[user@IsMyLaptop:~/src/air_quality]$
 newt load blink_primo\n\n\n\n\n\nAnd it's blinking.\n\n\nShortcut for doing 
build/create-image/load/debug steps all in one is 'newt run' command. Check 
\nout the usage from command line help.\n\n\nCreate test project\n\n\nNow that 
you have your system setup, you can start creating your own stuff.\nFirst you 
want to create a project for yourself - you could start by using blinky as a 
project \ntemplate, but since we're going to want to be able to access the data 
via Bluetooth, let's \nuse the \nbleprph\n Bluetooth Peripheral project inst
 ead.\n\n\n    [user@IsMyLaptop:~/src/air_quality]$ mkdir apps/air_quality\n    
[user@IsMyLaptop:~/src/air_quality]$ cp 
repos/apache-mynewt-core/apps/bleprph/pkg.yml apps/air_quality/\n    
[user@IsMyLaptop:~/src/air_quality]$ cp -Rp 
repos/apache-mynewt-core/apps/bleprph/src apps/air_quality/\n\n\n\n\n\nThen you 
modify the apps/air_quality/pkg.yml for air_quality in order to change the 
\npkg.name\n to be \napps/air_quality\n.\nYou'll need to add the 
\n@apache-mynewt-core/\n path to all the package dependencies, since the app no 
longer\nresides within the apache-mynewt-core repository.\n\n\nThe Arduino 
Primo board has a limited amount of memory, so you must also switch your libc 
to be baselibc, instead of the standard 
one.\n\n\n[user@IsMyLaptop:~/src/air_quality]$ cat 
apps/air_quality/pkg.yml\npkg.name: apps/air_quality\npkg.type: 
app\npkg.description: BLE Air Quality application.\npkg.author: \nApache Mynewt 
\[email protected]\n\npkg.homepage: \nhttp://mynewt.apache.org
 /\n\npkg.keywords:\n\npkg.deps: \n    - \n@apache-mynewt-core/kernel/os\n\n    
- \n@apache-mynewt-core/sys/shell\n\n    - 
\n@apache-mynewt-core/sys/stats/full\n\n    - 
\n@apache-mynewt-core/sys/log/full\n\n    - 
\n@apache-mynewt-core/mgmt/newtmgr\n\n    - 
\n@apache-mynewt-core/mgmt/newtmgr/transport/ble\n\n    - 
\n@apache-mynewt-core/net/nimble/controller\n\n    - 
\n@apache-mynewt-core/net/nimble/host\n\n    - 
\n@apache-mynewt-core/net/nimble/host/services/ans\n\n    - 
\n@apache-mynewt-core/net/nimble/host/services/gap\n\n    - 
\n@apache-mynewt-core/net/nimble/host/services/gatt\n\n    - 
\n@apache-mynewt-core/net/nimble/host/store/ram\n\n    - 
\n@apache-mynewt-core/net/nimble/transport/ram\n\n    - 
\n@apache-mynewt-core/sys/console/full\n\n    - 
\n@apache-mynewt-core/sys/sysinit\n\n    - 
\n@apache-mynewt-core/sys/id\n\n\n\n\n\n\nAnd create a target for 
it:\n\n\n[user@IsMyLaptop:~/src/air_quality]$ newt target create air_q\nTarget 
targets/air_q successfully created\n[user@IsMyLaptop:
 ~/src/air_quality]$ newt target set air_q 
bsp=@apache-mynewt-core/hw/bsp/arduino_primo_nrf52\nTarget targets/air_q 
successfully set target.bsp to 
@apache-mynewt-core/hw/bsp/arduino_primo_nrf52\n[user@IsMyLaptop:~/src/air_quality]$
 newt target set air_q app=apps/air_quality \nTarget targets/air_q successfully 
set target.app to apps/air_quality\n[user@IsMyLaptop:~/src/air_quality]$ newt 
target set air_q build_profile=debug\nTarget targets/air_q successfully set 
target.build_profile to debug\n[user@IsMyLaptop:~/src/air_quality]$ newt build 
air_q\n ....\nLinking 
/Users/dsimmons/dev/myproj/bin/targets/air_q/app/apps/air_quality/air_quality.elf\nTarget
 successfully built: targets/air_q\n\n\n\n\n\nCreate packages for 
drivers\n\n\nOne of the sensors you want to enable is SenseAir K30, which will 
connect to the board over a serial port.\nTo start development of the driver, 
you first need to create a package description for it, and add stubs for 
sources.\n\n\nThe first thing to do is to creat
 e the directory structure for your 
driver:\n\n\n[user@IsMyLaptop:~/src/air_quality]$ mkdir -p 
libs/my_drivers/senseair/include/senseair\n[user@IsMyLaptop:~/src/air_quality]$ 
mkdir -p libs/my_drivers/senseair/src\n\n\n\n\n\nNow 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.\n\n\n[user@IsMyLaptop:~/src/air_quality]$ cat 
libs/my_drivers/senseair/pkg.yml\n\n\n\n\n\n#\n\n\n# Licensed to the Apache 
Software Foundation (ASF) under one\n\n\n# or more contributor license 
agreements.  See the NOTICE file\n\n\n# distributed with this work for 
additional information\n\n\n# regarding copyright ownership.  The ASF licenses 
this file\n\n\n# to you under the Apache License, Version 2.0 (the\n\n\n# 
\nLicense\n); you may not use this file except in compliance\n\n\n# with the 
License.  You may obtain a copy of the License at\n\n\n# \n\n\n#  
http:\n//www.apache.org/licenses/LICENSE-2.0\n\n\n#\n\n\n# Unless required by 
applicab
 le law or agreed to in writing,\n\n\n# software distributed under the License 
is distributed on an\n\n\n# \nAS IS\n BASIS, WITHOUT WARRANTIES OR CONDITIONS 
OF ANY\n\n\n# KIND, either express or implied.  See the License for the\n\n\n# 
specific language governing permissions and limitations\n\n\n# under the 
License.\n\n\n#\n\n\npkg\n.\nname\n: 
\nlibs/my_drivers/senseair\n\n\npkg\n.\ndescription\n: \nHost\n \nside\n \nof\n 
\nthe\n \nnimble\n \nBluetooth\n \nSmart\n \nstack\n.\n\npkg\n.\nauthor\n: 
\nApache Mynewt \[email protected]\n\n\npkg\n.\nhomepage\n: 
\nhttp://mynewt.apache.org/\n\n\npkg\n.\nkeywords\n:\n    \n-\n \nble\n\n    
\n-\n \nbluetooth\n\n\n\npkg\n.\ndeps\n:\n    \n-\n 
\n@apache-mynewt-core/kernel/os\n\n\n\n\n\n\n[user@IsMyLaptop:~/src/air_quality]$
 cat libs/my_drivers/senseair/include/senseair/senseair.h\n\n\n\n\n\n/*\n\n\n * 
Licensed to the Apache Software Foundation (ASF) under one\n\n\n * or more 
contributor license agreements.  See the NOTICE file\n\n\
 n * distributed with this work for additional information\n\n\n * regarding 
copyright ownership.  The ASF licenses this file\n\n\n * to you under the 
Apache License, Version 2.0 (the\n\n\n * \nLicense\n); you may not use this 
file except in compliance\n\n\n * with the License.  You may obtain a copy of 
the License at\n\n\n * \n\n\n *  
http://www.apache.org/licenses/LICENSE-2.0\n\n\n *\n\n\n * Unless required by 
applicable law or agreed to in writing,\n\n\n * software distributed under the 
License is distributed on an\n\n\n * \nAS IS\n BASIS, WITHOUT WARRANTIES OR 
CONDITIONS OF ANY\n\n\n * KIND, either express or implied.  See the License for 
the\n\n\n * specific language governing permissions and limitations\n\n\n * 
under the License.\n\n\n*/\n\n\n#ifndef _SENSEAIR_H_\n\n\n#define 
_SENSEAIR_H_\n\n\n\nvoid\n \nsenseair_init\n(\nvoid\n);\n\n\n#endif \n/* 
_SENSEAIR_H_ */\n\n\n\n\n\n\n[user@IsMyLaptop:~/src/air_quality]$ cat 
libs/my_drivers/senseair/src/senseair.c\n\n\n\n\n\n/**\n\n\n *
  Licensed to the Apache Software Foundation (ASF) under one\n\n\n * or more 
contributor license agreements.  See the NOTICE file\n\n\n * distributed with 
this work for additional information\n\n\n * regarding copyright ownership.  
The ASF licenses this file\n\n\n * to you under the Apache License, Version 2.0 
(the\n\n\n * \nLicense\n); you may not use this file except in compliance\n\n\n 
* with the License.  You may obtain a copy of the License at\n\n\n * \n\n\n *  
http://www.apache.org/licenses/LICENSE-2.0\n\n\n *\n\n\n * Unless required by 
applicable law or agreed to in writing,\n\n\n * software distributed under the 
License is distributed on an\n\n\n * \nAS IS\n BASIS, WITHOUT WARRANTIES OR 
CONDITIONS OF ANY\n\n\n * KIND, either express or implied.  See the License for 
the\n\n\n * specific language governing permissions and limitations\n\n\n * 
under the License.\n\n\n 
*/\n\n\n\nvoid\n\n\nsenseair_init\n(\nvoid\n)\n{\n}\n\n\n\n\n\nAnd add 
dependency to this package in your project
  yml file.\n\n\nHere's the listing from 
apps/air_quality/pkg.yml\n\n\npkg.name: apps/air_quality\npkg.type: 
app\npkg.description: Air quality sensor test\npkg.keywords:\n\npkg.deps:\n    
- \n@apache-mynewt-core/libs/console/full\n\n    - 
\n@apache-mynewt-core/libs/newtmgr\n\n    - \n@apache-mynewt-core/libs/os\n\n   
 - \n@apache-mynewt-core/libs/shell\n\n    - 
\n@apache-mynewt-core/sys/config\n\n    - 
\n@apache-mynewt-core/sys/log/full\n\n    - 
\n@apache-mynewt-core/sys/stats/full\n\n    - 
\n@apache-mynewt-core/libs/baselibc\n\n    - 
libs/my_drivers/senseair\n\n\n\n\n\nAnd add a call to your main() to initialize 
this driver.\n\n\n    [user@IsMyLaptop:~/src/air_quality]$ diff 
project/blinky/src/main.c project/air_quality/src/main.c\n    28a29\n    \n 
#include \nsenseair/senseair.h\n\n    190a192\n    \n senseair_init();\n    
[user@IsMyLaptop:~/src/air_quality\n\n\n\n\n\nThe ble_prph app runs everything 
in one task handler. For this project, we're going to add a second\ntask 
handler t
 o respond to the shell, and then handle communicating with the senseair sensor 
for us.\n\n\n/** shell task settings. */\n\n\n#define SHELL_TASK_PRIO           
2\n\n\n#define SHELL_STACK_SIZE          (OS_STACK_ALIGN(336))\n\n\n\nstruct\n 
\nos_eventq\n \nshell_evq\n;\n\nstruct\n \nos_task\n 
\nshell_task\n;\n\nbssnz_t\n \nos_stack_t\n 
\nshell_stack\n[\nSHELL_STACK_SIZE\n];\n\n\n\n\n\nThat defines the task, now we 
need to initialize it, add a task handler, and we're going to \nuse this task 
as our default task handler.\n\n\n/**\n\n\n * Event loop for the main shell 
task.\n\n\n */\n\n\nstatic\n \nvoid\n\n\nshell_task_handler\n(\nvoid\n 
\n*unused\n)\n{\n    \nwhile\n (\n1\n) {\n        
\nos_eventq_run\n(\nshell_evq\n);\n    }\n}\n\n\n\n\n\nAnd in your \nmain()\n 
add:\n\n\n    \n/* Initialize shell eventq */\n\n    
\nos_eventq_init\n(\nshell_evq\n);\n\n    \n/* Create the shell task.  \n\n\n   
  * All shell operations are performed in this task.\n\n\n     */\n\n    
\nos_task_init\n(\nshel
 l_task\n, \nshell\n, \nshell_task_handler\n,\n                              
\nNULL\n, \nSHELL_TASK_PRIO\n, \nOS_WAIT_FOREVER\n,\n                           
   \nshell_stack\n, \nSHELL_STACK_SIZE\n);\n\n\n\n\n\nDon't forget to change 
your default task handler!\n\n\n    
\nos_eventq_dflt_set\n(\nshell_evq\n);\n\n\n\n\n\nAnd then build it to make 
sure all goes well.\n\n\n[user@IsMyLaptop:~/src/air_quality]$ newt build 
air_q\nCompiling senseair.c\nArchiving senseair.a\nLinking air_quality.elf\nApp 
successfully built: 
/Users/user/src/air_quality/bin/air_q/apps/air_quality/air_quality.elf\n\n\n\n\n\nAll
 looks good.\n\n\nAdd CLI commands for testing drivers\n\n\nWhile developing 
the driver, you want to issue operations from console asking it to do stuff. 
We'll assume that you've already worked through the tutorial \non how to 
\nenable the CLI\n, so all we'll need to do is add the propper values to the 
project's \nsyscfg.yml\n file:\n\n\n[user@IsMyLaptop:~/src/air_quality]$ cat 
targets/air_q
 /syscfg.yml\nsyscfg.vals:\n    # Set as per blinky_primo\n    OPENOCD_DEBUG: 
1\n    # Enable the shell task.\n    SHELL_TASK: 1\n    STATS_CLI: 1\n    
CONSOLE_TICKS: 1\n    CONSOLE_PROMPT: 1\n\n\n\n\n\nThen register your senseair 
command with the shell by adding the following to 
\nlibs/my_drivers/senseair/src/senseair.c\n\n\n#include 
\nshell/shell.h\n\n\n#include \nconsole/console.h\n\n\n#include 
\nassert.h\n\n\n\n\nstatic\n \nint\n \nsenseair_shell_func\n(\nint\n \nargc\n, 
\nchar\n \n**argv\n);\n\nstatic\n \nstruct\n \nshell_cmd\n \nsenseair_cmd\n 
\n=\n {\n    .\nsc_cmd\n \n=\n \nsenseair\n,\n    .\nsc_cmd_func\n \n=\n 
\nsenseair_shell_func\n,\n};\n\n\nvoid\n\n\nsenseair_init\n(\nvoid\n)\n{\n    
\nint\n \nrc\n;\n\n    \nrc\n \n=\n \nshell_cmd_register\n(\nsenseair_cmd\n);\n 
   \nassert\n(\nrc\n \n==\n \n0\n);\n}\n\n\nstatic\n 
\nint\n\n\nsenseair_shell_func\n(\nint\n \nargc\n, \nchar\n \n**argv\n)\n{\n    
\nconsole_printf\n(\nYay! Somebody called!\\n\n);\n    \nreturn\n \n0\n;\n\n}\
 n\n\n\n\n\nNow you can you build this, download to target, and start minicom 
on your console port. If you haven't already, familiarize yourself with\nthe 
tutorial on how to connect a serial port to your board \nhere\n.\n\n\nYou'll 
need to wire up your Board to a Serial converter first. On the Arduino Primo 
Board pin 1 is TX and pin 0 is RX so wire 1 to RX on your serial board, and 0 
to TX on your serial board.\n\n\n    [user@IsMyLaptop:~]$ minicom -D 
/dev/tty.usbserial-AH02MIE2\n\n\n    Welcome to minicom 2.7\n\n    OPTIONS: \n  
  Compiled on Oct 12 2015, 07:48:30.\n    Port /dev/tty.usbserial-AH02MIE2, 
13:44:40\n\n    Press CTRL-X Z for help on special keys\n\n    ?\n    419: \n 
?\n    Commands:\n    641:     stat      echo         ?    prompt     ticks     
tasks\n    643: mempools      date  senseair\n    644: \n senseair\n    Yay! 
Somebody called!\n    1125: \n\n    53611: \n tasks\n    Tasks:\n    54047:    
task pri tid  runtime      csw    stksz   stkuse   lcheck   ncheck flg\n
     54057:    idle 255   0    54048    66890       64       30        0        
0   0\n    54068:  ble_ll   0   1        9    64986       80       58        0  
      0   0\n    54079: bleprph   1   2        0        1      336       32     
   0        0   0\n    54090:   shell   2   3        0     2077      336      
262        0        0   0\n    54101: \n\n\n\n\n\n\nThat's great. Your shell 
task is running, and is responding appropriately!\nYou can connect the hardware 
to your board and start developing code for the driver itself.\n\n\nUse of HAL 
for drivers\n\n\nThe sensor has a serial port connection, and that's how you 
are going to connect to it. Your original BSP, hw/bsp/arduino_primo_nrf52, has 
two UARTs set up.\nWe're using one for our shell/console. It also has a second 
UART set up as a 'bit-bang' UART but since the SenseAir only needs 
to\ncommunicate at 9600 baud, this bit-banged uart is plenty fast 
enough.\n\n\nYou'll have to make a small change to the \nsyscfg.yml\n file i
 n your project's target directory to change  the pin definitions \nfor this 
second UART. Those changes are as follows:\n\n\n    UART_0_PIN_TX: 23\n    
UART_0_PIN_RX: 24\n\n\n\n\n\nWith this in place, you can refer to serial port 
where your SenseAir sensor by a logical number. This makes the code more 
platform independent - you could connect this sensor to another board, like 
Olimex. You will 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.\n\n\nYou will now see what the driver code 
ends up looking like. Here's the header file, filled in from the stub you 
created earlier.\n\n\n/*\n\n\n * Licensed to the Apache Software Foundation 
(ASF) under one\n\n\n * or more contributor license agreements.  See the NOTICE 
file\n\n\n * distributed with this work for additional information\n\n\n * 
regarding copyright ownership.  The ASF licenses this file\n\n\n * to you under 
the Ap
 ache License, Version 2.0 (the\n\n\n * \nLicense\n); you may not use this file 
except in compliance\n\n\n * with the License.  You may obtain a copy of the 
License at\n\n\n * \n\n\n *  http://www.apache.org/licenses/LICENSE-2.0\n\n\n 
*\n\n\n * Unless required by applicable law or agreed to in writing,\n\n\n * 
software distributed under the License is distributed on an\n\n\n * \nAS IS\n 
BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n\n\n * KIND, either express or 
implied.  See the License for the\n\n\n * specific language governing 
permissions and limitations\n\n\n * under the License.\n\n\n*/\n\n\n#ifndef 
_SENSEAIR_H_\n\n\n#define _SENSEAIR_H_\n\n\n\nenum\n \nsenseair_read_type\n {\n 
       \nSENSEAIR_CO2\n,\n};\n\n\nint\n \nsenseair_init\n(\nint\n 
\nuartno\n);\n\n\nint\n \nsenseair_read\n(\nenum\n 
\nsenseair_read_type\n);\n\n\n#endif \n/* _SENSEAIR_H_ */\n\n\n\n\n\n\nAs you 
can see, logical UART number has been added to the init routine. A 'read' 
function has been added, \nwhich i
 s a blocking read. If you were making a commercial product, you would probably 
have a callback for reporting the results.\n\n\nAnd here is the source for the 
driver.\n\n\n/**\n\n\n * Licensed to the Apache Software Foundation (ASF) under 
one\n\n\n * or more contributor license agreements.  See the NOTICE file\n\n\n 
* distributed with this work for additional information\n\n\n * regarding 
copyright ownership.  The ASF licenses this file\n\n\n * to you under the 
Apache License, Version 2.0 (the\n\n\n * \nLicense\n); you may not use this 
file except in compliance\n\n\n * with the License.  You may obtain a copy of 
the License at\n\n\n *\n\n\n *  
http://www.apache.org/licenses/LICENSE-2.0\n\n\n *\n\n\n * Unless required by 
applicable law or agreed to in writing,\n\n\n * software distributed under the 
License is distributed on an\n\n\n * \nAS IS\n BASIS, WITHOUT WARRANTIES OR 
CONDITIONS OF ANY\n\n\n * KIND, either express or implied.  See the License for 
the\n\n\n * specific language gov
 erning permissions and limitations\n\n\n * under the License.\n\n\n 
*/\n\n\n#include \nstring.h\n\n\n\n#include \nshell/shell.h\n\n\n#include 
\nconsole/console.h\n\n\n#include \nos/os.h\n\n\n\n#include 
\nhal/hal_uart.h\n\n\n\n#include \nsenseair/senseair.h\n\n\n\nstatic\n 
\nconst\n \nuint8_t\n \ncmd_read_co2\n[] \n=\n {\n    \n0xFE\n, \n0\nX44\n, 
\n0\nX00\n, \n0\nX08\n, \n0\nX02\n, \n0\nX9F\n, \n0\nX25\n\n};\n\n\nstatic\n 
\nint\n \nsenseair_shell_func\n(\nint\n \nargc\n, \nchar\n 
\n**argv\n);\n\nstatic\n \nstruct\n \nshell_cmd\n \nsenseair_cmd\n \n=\n {\n    
.\nsc_cmd\n \n=\n \nsenseair\n,\n    .\nsc_cmd_func\n \n=\n 
\nsenseair_shell_func\n,\n};\n\n\nstruct\n \nsenseair\n { \n    \nint\n 
\nuart\n;\n    \nstruct\n \nos_sem\n \nsema\n;\n    \nconst\n \nuint8_t\n 
\n*tx_data\n;\n    \nint\n \ntx_off\n;\n    \nint\n \ntx_len\n;\n    
\nuint8_t\n \nrx_data\n[\n32\n]; \n    \nint\n \nrx_off\n;\n    \nint\n 
\nvalue\n;\n} \nsenseair\n;\n\n\nstatic\n 
\nint\n\n\nsenseair_tx_char\n(\nvoid\n \n*a
 rg\n)\n{\n    \nstruct\n \nsenseair\n \n*s\n \n=\n \nsenseair\n;\n    \nint\n 
\nrc\n;\n\n    \nif\n (\ns-\ntx_off\n \n=\n \ns-\ntx_len\n) {\n    \n/*\n\n\n   
      * Command tx finished.\n\n\n         */\n\n        \ns-\ntx_data\n \n=\n 
\nNULL\n;\n        \nreturn\n \n-\n1\n;\n    }\n\n    \nrc\n \n=\n 
\ns-\ntx_data\n[\ns-\ntx_off\n];\n    \ns-\ntx_off++\n;\n    \nreturn\n 
\nrc\n;\n}\n\n\n/*\n\n\n * CRC for modbus over serial port.\n\n\n 
*/\n\n\nstatic\n \nconst\n \nuint16_t\n \nmb_crc_tbl\n[] \n=\n {\n    
\n0x0000\n, \n0xcc01\n, \n0xd801\n, \n0x1400\n, \n0xf001\n, \n0x3c00\n, 
\n0x2800\n, \n0xe401\n,\n    \n0xa001\n, \n0x6c00\n, \n0x7800\n, \n0xb401\n, 
\n0x5000\n, \n0x9c01\n, \n0x8801\n, \n0x4400\n\n};\n\n\nstatic\n 
\nuint16_t\n\n\nmb_crc\n(\nconst\n \nuint8_t\n \n*data\n, \nint\n \nlen\n, 
\nuint16_t\n \ncrc\n)\n{\n    \nwhile\n (\nlen--\n \n \n0\n) {\n        \ncrc\n 
\n^=\n \n*data++\n;\n        \ncrc\n \n=\n (\ncrc\n \n \n4\n) \n^\n 
\nmb_crc_tbl\n[\ncrc\n \n \n0xf\n];\n        \nc
 rc\n \n=\n (\ncrc\n \n \n4\n) \n^\n \nmb_crc_tbl\n[\ncrc\n \n \n0xf\n];\n    
}\n    \nreturn\n \ncrc\n;\n}\n\n\nstatic\n \nint\n\n\nmb_crc_check\n(\nconst\n 
\nvoid\n \n*pkt\n, \nint\n \nlen\n)\n{\n    \nuint16_t\n \ncrc\n, \ncmp\n;\n    
\nuint8_t\n \n*bp\n \n=\n (\nuint8_t\n \n*\n)\npkt\n;\n\n    \nif\n (\nlen\n \n 
\nsizeof\n(\ncrc\n) \n+\n \n1\n) {\n        \nreturn\n \n-\n1\n;\n    }\n    
\ncrc\n \n=\n \nmb_crc\n(\npkt\n, \nlen\n \n-\n \n2\n, \n0xffff\n);\n    
\ncmp\n \n=\n \nbp\n[\nlen\n \n-\n \n2\n] \n|\n (\nbp\n[\nlen\n \n-\n \n1\n] \n 
\n8\n);\n    \nif\n (\ncrc\n \n!=\n \ncmp\n) {\n        \nreturn\n \n-\n1\n;\n  
  } \nelse\n {\n        \nreturn\n \n0\n;\n    }\n}\n\n\nstatic\n 
\nint\n\n\nsenseair_rx_char\n(\nvoid\n \n*arg\n, \nuint8_t\n \ndata\n)\n{\n    
\nstruct\n \nsenseair\n \n*s\n \n=\n (\nstruct\n \nsenseair\n \n*\n)\narg\n;\n  
  \nint\n \nrc\n;\n\n    \nif\n (\ns-\nrx_off\n \n=\n 
\nsizeof\n(\ns-\nrx_data\n)) {\n        \ns-\nrx_off\n \n=\n \n0\n;\n    }\n    
\ns-\nrx_da
 ta\n[\ns-\nrx_off\n] \n=\n \ndata\n;\n    \ns-\nrx_off++\n;\n\n    \nif\n 
(\ns-\nrx_off\n \n==\n \n7\n) {\n        \nrc\n \n=\n 
\nmb_crc_check\n(\ns-\nrx_data\n, \ns-\nrx_off\n);\n        \nif\n (\nrc\n 
\n==\n \n0\n) {\n            \ns-\nvalue\n \n=\n \ns-\nrx_data\n[\n3\n] \n*\n 
\n256\n \n+\n \ns-\nrx_data\n[\n4\n];\n            
\nos_sem_release\n(\ns-\nsema\n);\n        }\n    }\n    \nreturn\n 
\n0\n;\n}\n\n\nvoid\n\n\nsenseair_tx\n(\nstruct\n \nsenseair\n \n*s\n, 
\nconst\n \nuint8_t\n \n*tx_data\n, \nint\n \ndata_len\n)\n{\n    
\ns-\ntx_data\n \n=\n \ntx_data\n;\n    \ns-\ntx_len\n \n=\n \ndata_len\n;\n    
\ns-\ntx_off\n \n=\n \n0\n;\n    \ns-\nrx_off\n \n=\n \n0\n;\n\n    
\nhal_uart_start_tx\n(\ns-\nuart\n);\n}\n\n\nint\n\n\nsenseair_read\n(\nenum\n 
\nsenseair_read_type\n \ntype\n)\n{\n    \nstruct\n \nsenseair\n \n*s\n \n=\n 
\nsenseair\n;\n    \nconst\n \nuint8_t\n \n*cmd\n;\n    \nint\n \ncmd_len\n;\n  
  \nint\n \nrc\n;\n\n    \nif\n (\ns-\ntx_data\n) {\n        \n/*\n\n\n    
      * busy\n\n\n         */\n\n        \nreturn\n \n-\n1\n;\n    }\n    
\nswitch\n (\ntype\n) {\n    \ncase\n \nSENSEAIR_CO2\n:\n        \ncmd\n \n=\n 
\ncmd_read_co2\n;\n        \ncmd_len\n \n=\n \nsizeof\n(\ncmd_read_co2\n);\n    
    \nbreak\n;\n    \ndefault\n:\n\n        \nreturn\n \n-\n1\n;\n    }\n    
\nsenseair_tx\n(\ns\n, \ncmd\n, \ncmd_len\n);\n    \nrc\n \n=\n 
\nos_sem_pend\n(\ns-\nsema\n, \nOS_TICKS_PER_SEC\n \n/\n \n2\n);\n    \nif\n 
(\nrc\n \n==\n \nOS_TIMEOUT\n) {\n        \n/*\n\n\n         * timeout\n\n\n    
     */\n\n        \nreturn\n \n-\n2\n;\n    }\n    \nreturn\n 
\ns-\nvalue\n;\n}\n\n\nstatic\n \nint\n\n\nsenseair_shell_func\n(\nint\n 
\nargc\n, \nchar\n \n**argv\n)\n{\n    \nint\n \nvalue\n;\n    \nenum\n 
\nsenseair_read_type\n \ntype\n;\n\n    \nif\n (\nargc\n \n \n2\n) 
{\n\nusage\n:\n        \nconsole_printf\n(\n%s co2\\n\n, \nargv\n[\n0\n]);\n    
    \nreturn\n \n0\n;\n    }\n    \nif\n (\n!strcmp\n(\nargv\n[\n1\n], 
\nco2\n)) {\n        \ntype\n \n=\n \nSEN
 SEAIR_CO2\n;\n    } \nelse\n {\n        \ngoto\n \nusage\n;\n    }\n    
\nvalue\n \n=\n \nsenseair_read\n(\ntype\n);\n    \nif\n (\nvalue\n \n=\n 
\n0\n) {\n        \nconsole_printf\n(\nGot %d\\n\n, \nvalue\n);\n    } \nelse\n 
{\n        \nconsole_printf\n(\nError while reading: %d\\n\n, \nvalue\n);\n    
}\n    \nreturn\n \n0\n;\n}\n\n\nint\n\n\nsenseair_init\n(\nint\n 
\nuartno\n)\n{\n    \nint\n \nrc\n;\n    \nstruct\n \nsenseair\n \n*s\n \n=\n 
\nsenseair\n;\n\n    \nrc\n \n=\n \nshell_cmd_register\n(\nsenseair_cmd\n);\n   
 \nif\n (\nrc\n) {\n        \nreturn\n \nrc\n;\n    }\n\n    \nrc\n \n=\n 
\nos_sem_init\n(\ns-\nsema\n, \n1\n);\n    \nif\n (\nrc\n) {\n        
\nreturn\n \nrc\n;\n    }\n    \nrc\n \n=\n \nhal_uart_init_cbs\n(\nuartno\n, 
\nsenseair_tx_char\n, \nNULL\n,\n      \nsenseair_rx_char\n, \nsenseair\n);\n   
 \nif\n (\nrc\n) {\n        \nreturn\n \nrc\n;\n    }\n    \nrc\n \n=\n 
\nhal_uart_config\n(\nuartno\n, \n9600\n, \n8\n, \n1\n, 
\nHAL_UART_PARITY_NONE\n,\n      \nHAL
 _UART_FLOW_CTL_NONE\n);\n    \nif\n (\nrc\n) {\n        \nreturn\n \nrc\n;\n   
 }\n    \ns-\nuart\n \n=\n \nuartno\n;\n\n    \nreturn\n 
\n0\n;\n}\n\n\n\n\n\nAnd your modified main() for senseair driver 
init.\n\n\nint\n\n\nmain\n(\nint\n \nargc\n, \nchar\n \n**argv\n)\n{\n    
....\n    \nsenseair_init\n(\n0\n);\n    ....\n    }\n\n\n\n\n\nYou can see 
from the code that you are using the HAL interface to open a UART port, and 
using OS \nsemaphore as a way of blocking the task when waiting for read 
response to come back from the sensor.\n\n\nNow comes the fun part: Hooking up 
the sensor! It's fun because a) hooking up a sensor is always \nfun and b) the 
SenseAir sensor's PCB is entirely unlabeled, so you'll have to trust us on how 
to hook it up. \n\n\nSo here we go. \n\n\nYou'll have to do a little soldering. 
I soldered some header pins to the SenseAir K30 board to\nmake connecting wires 
easier using standard jumper wires, but you can also just solder 
wires\nstraight to the board if yo
 u prefer.\n\n\nHere's what your SenseAir board should look like once it's 
wired up:\n\n\n\n\nNow that you have that wired up, let's get the Arduino Primo 
wired up. A couple of things to note:\n\n\n\n\nThe Arduino Primo's 'console' 
UART is actually UART1. \n\n\nThe secondary (bit-banged) UART is UART0, so 
that's where we'll have to hook up the SenseAir.\n\n\n\n\nHere's what your 
Arduino Primo should now look like with everything wired 
in:\n\n\n\n\nEverything is wired and you're ready to go! Build and load your 
new app:\n\n\n$ newt build air_q\nBuilding target targets/air_q\nCompiling 
apps/air_quality/src/main.c\nArchiving apps_air_quality.a\nLinking 
myproj/bin/targets/air_q/app/apps/air_quality/air_quality.elf\nTarget 
successfully built: targets/air_q\n$ newt create-image air_q 1.0.0\nApp image 
succesfully generated: 
myproj/bin/targets/air_q/app/apps/air_quality/air_quality.img\n$ newt load 
air_q\nLoading app image into slot 1\n\n\n\n\n\nNow, you should be able to 
connect to your ser
 ial port and read values:\n\n\nuser@IsMyLaptop:~]$ minicom -D 
/dev/tty.usbserial-AH02MIE2\n\n\n    Welcome to minicom 2.7\n\n    OPTIONS: \n  
  Compiled on Oct 12 2015, 07:48:30.\n    Port /dev/tty.usbserial-AH02MIE2, 
13:44:40\n\n    Press CTRL-X Z for help on special keys\n\n    1185: \n ?\n    
Commands:\n    1382:     stat      echo         ?    prompt     ticks     
tasks\n    1390: mempools      date  senseair\n    1395: \n senseair\n    
senseair co2\n    2143: \n senseair co2\n    Got 973\n\n\n\n\n\nAnd you're 
getting valid readings! Congratulations!\n\n\nNext we'll hook this all up via 
Bluetooth so that you can read those values remotely.", 
             "title": "Basic Air Quality Sensor"
         }, 
         {
@@ -1282,12 +1282,12 @@
         }, 
         {
             "location": 
"/os/tutorials/air_quality_sensor/#create-test-project", 
-            "text": "Now that you have your system setup, you can start 
creating your own stuff.\nFirst you want to create a project for yourself - you 
could start by using blinky as a project \ntemplate, but since we're going to 
want to be able to access the data via Bluetooth, let's \nuse the  bleprph  
Bluetooth Peripheral project instead.      [user@IsMyLaptop:~/src/air_quality]$ 
mkdir apps/air_quality\n    [user@IsMyLaptop:~/src/air_quality]$ cp 
repos/apache-mynewt-core/apps/bleprph/pkg.yml apps/air_quality/\n    
[user@IsMyLaptop:~/src/air_quality]$ cp -Rp 
repos/apache-mynewt-core/apps/bleprph/src apps/air_quality/  Then you modify 
the apps/air_quality/pkg.yml for air_quality in order to change the  pkg.name  
to be  apps/air_quality .\nYou'll need to add the  @apache-mynewt-core/  path 
to all the package dependencies, since the app no longer\nresides within the 
apache-mynewt-core repository.  The Arduino Primo board has a limited amount of 
memory, so you must also switch your li
 bc to be baselibc, instead of the standard one.  
[user@IsMyLaptop:~/src/air_quality]$ cat apps/air_quality/pkg.yml\npkg.name: 
apps/air_quality\npkg.type: app\npkg.description: BLE Air Quality 
application.\npkg.author:  Apache Mynewt  [email protected] 
\npkg.homepage:  http://mynewt.apache.org/ \npkg.keywords:\n\npkg.deps:\n    -  
@apache-mynewt-core/kernel/os \n    -  @apache-mynewt-core/sys/log \n    -  
@apache-mynewt-core/mgmt/newtmgr \n    -  
@apache-mynewt-core/mgmt/newtmgr/transport/ble \n    -  
@apache-mynewt-core/net/nimble/controller \n    -  
@apache-mynewt-core/net/nimble/host \n    -  
@apache-mynewt-core/net/nimble/host/services/ans \n    -  
@apache-mynewt-core/net/nimble/host/services/gap \n    -  
@apache-mynewt-core/net/nimble/host/services/gatt \n    -  
@apache-mynewt-core/net/nimble/host/store/ram \n    -  
@apache-mynewt-core/net/nimble/transport/ram \n    -  
@apache-mynewt-core/sys/console/full \n    -  @apache-mynewt-core/libc/baselibc 
\n    -  @apache-
 mynewt-core/sys/sysinit \n    -  @apache-mynewt-core/sys/id   And create a 
target for it:  [user@IsMyLaptop:~/src/air_quality]$ newt target create 
air_q\nTarget targets/air_q successfully 
created\n[user@IsMyLaptop:~/src/air_quality]$ newt target set air_q 
bsp=@apache-mynewt-core/hw/bsp/arduino_primo_nrf52\nTarget targets/air_q 
successfully set target.bsp to 
@apache-mynewt-core/hw/bsp/arduino_primo_nrf52\n[user@IsMyLaptop:~/src/air_quality]$
 newt target set air_q app=apps/air_quality \nTarget targets/air_q successfully 
set target.app to apps/air_quality\n[user@IsMyLaptop:~/src/air_quality]$ newt 
target set air_q build_profile=debug\nTarget targets/air_q successfully set 
target.build_profile to debug\n[user@IsMyLaptop:~/src/air_quality]$ newt build 
air_q\n ....\nLinking 
/Users/dsimmons/dev/myproj/bin/targets/air_q/app/apps/air_quality/air_quality.elf\nTarget
 successfully built: targets/air_q", 
+            "text": "Now that you have your system setup, you can start 
creating your own stuff.\nFirst you want to create a project for yourself - you 
could start by using blinky as a project \ntemplate, but since we're going to 
want to be able to access the data via Bluetooth, let's \nuse the  bleprph  
Bluetooth Peripheral project instead.      [user@IsMyLaptop:~/src/air_quality]$ 
mkdir apps/air_quality\n    [user@IsMyLaptop:~/src/air_quality]$ cp 
repos/apache-mynewt-core/apps/bleprph/pkg.yml apps/air_quality/\n    
[user@IsMyLaptop:~/src/air_quality]$ cp -Rp 
repos/apache-mynewt-core/apps/bleprph/src apps/air_quality/  Then you modify 
the apps/air_quality/pkg.yml for air_quality in order to change the  pkg.name  
to be  apps/air_quality .\nYou'll need to add the  @apache-mynewt-core/  path 
to all the package dependencies, since the app no longer\nresides within the 
apache-mynewt-core repository.  The Arduino Primo board has a limited amount of 
memory, so you must also switch your li
 bc to be baselibc, instead of the standard one.  
[user@IsMyLaptop:~/src/air_quality]$ cat apps/air_quality/pkg.yml\npkg.name: 
apps/air_quality\npkg.type: app\npkg.description: BLE Air Quality 
application.\npkg.author:  Apache Mynewt  [email protected] 
\npkg.homepage:  http://mynewt.apache.org/ \npkg.keywords:\n\npkg.deps: \n    - 
 @apache-mynewt-core/kernel/os \n    -  @apache-mynewt-core/sys/shell \n    -  
@apache-mynewt-core/sys/stats/full \n    -  @apache-mynewt-core/sys/log/full \n 
   -  @apache-mynewt-core/mgmt/newtmgr \n    -  
@apache-mynewt-core/mgmt/newtmgr/transport/ble \n    -  
@apache-mynewt-core/net/nimble/controller \n    -  
@apache-mynewt-core/net/nimble/host \n    -  
@apache-mynewt-core/net/nimble/host/services/ans \n    -  
@apache-mynewt-core/net/nimble/host/services/gap \n    -  
@apache-mynewt-core/net/nimble/host/services/gatt \n    -  
@apache-mynewt-core/net/nimble/host/store/ram \n    -  
@apache-mynewt-core/net/nimble/transport/ram \n    -  @apache-
 mynewt-core/sys/console/full \n    -  @apache-mynewt-core/sys/sysinit \n    -  
@apache-mynewt-core/sys/id   And create a target for it:  
[user@IsMyLaptop:~/src/air_quality]$ newt target create air_q\nTarget 
targets/air_q successfully created\n[user@IsMyLaptop:~/src/air_quality]$ newt 
target set air_q bsp=@apache-mynewt-core/hw/bsp/arduino_primo_nrf52\nTarget 
targets/air_q successfully set target.bsp to 
@apache-mynewt-core/hw/bsp/arduino_primo_nrf52\n[user@IsMyLaptop:~/src/air_quality]$
 newt target set air_q app=apps/air_quality \nTarget targets/air_q successfully 
set target.app to apps/air_quality\n[user@IsMyLaptop:~/src/air_quality]$ newt 
target set air_q build_profile=debug\nTarget targets/air_q successfully set 
target.build_profile to debug\n[user@IsMyLaptop:~/src/air_quality]$ newt build 
air_q\n ....\nLinking 
/Users/dsimmons/dev/myproj/bin/targets/air_q/app/apps/air_quality/air_quality.elf\nTarget
 successfully built: targets/air_q", 
             "title": "Create test project"
         }, 
         {
             "location": 
"/os/tutorials/air_quality_sensor/#create-packages-for-drivers", 
-            "text": "One of the sensors you want to enable is SenseAir K30, 
which will connect to the board over a serial port.\nTo start development of 
the driver, you first need to create a package description for it, and add 
stubs for sources.  The first thing to do is to create the directory structure 
for your driver:  [user@IsMyLaptop:~/src/air_quality]$ mkdir -p 
libs/my_drivers/senseair/include/senseair\n[user@IsMyLaptop:~/src/air_quality]$ 
mkdir -p libs/my_drivers/senseair/src  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.  [user@IsMyLaptop:~/src/air_quality]$ cat 
libs/my_drivers/senseair/pkg.yml  #  # Licensed to the Apache Software 
Foundation (ASF) under one  # or more contributor license agreements.  See the 
NOTICE file  # distributed with this work for additional information  # 
regarding copyright ownership.  The ASF licenses this file  # to you under the 
Apache License, Version 2.0 (the  # 
  License ); you may not use this file except in compliance  # with the 
License.  You may obtain a copy of the License at  #   #  http: 
//www.apache.org/licenses/LICENSE-2.0  #  # Unless required by applicable law 
or agreed to in writing,  # software distributed under the License is 
distributed on an  #  AS IS  BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY  # 
KIND, either express or implied.  See the License for the  # specific language 
governing permissions and limitations  # under the License.  #  pkg . name :  
libs/my_drivers/senseair  pkg . deps :\n     -   @apache-mynewt-core/hw/hal   
[user@IsMyLaptop:~/src/air_quality]$ cat 
libs/my_drivers/senseair/include/senseair/senseair.h  /*   * Licensed to the 
Apache Software Foundation (ASF) under one   * or more contributor license 
agreements.  See the NOTICE file   * distributed with this work for additional 
information   * regarding copyright ownership.  The ASF licenses this file   * 
to you under the Apache License, Version 2.0 (the
    *  License ); you may not use this file except in compliance   * with the 
License.  You may obtain a copy of the License at   *    *  
http://www.apache.org/licenses/LICENSE-2.0   *   * Unless required by 
applicable law or agreed to in writing,   * software distributed under the 
License is distributed on an   *  AS IS  BASIS, WITHOUT WARRANTIES OR 
CONDITIONS OF ANY   * KIND, either express or implied.  See the License for the 
  * specific language governing permissions and limitations   * under the 
License.  */  #ifndef _SENSEAIR_H_  #define _SENSEAIR_H_  void   senseair_init 
( void ); #endif  /* _SENSEAIR_H_ */   [user@IsMyLaptop:~/src/air_quality]$ cat 
libs/my_drivers/senseair/src/senseair.c  /**   * Licensed to the Apache 
Software Foundation (ASF) under one   * or more contributor license agreements. 
 See the NOTICE file   * distributed with this work for additional information  
 * regarding copyright ownership.  The ASF licenses this file   * to you under 
the Apache License, V
 ersion 2.0 (the   *  License ); you may not use this file except in compliance 
  * with the License.  You may obtain a copy of the License at   *    *  
http://www.apache.org/licenses/LICENSE-2.0   *   * Unless required by 
applicable law or agreed to in writing,   * software distributed under the 
License is distributed on an   *  AS IS  BASIS, WITHOUT WARRANTIES OR 
CONDITIONS OF ANY   * KIND, either express or implied.  See the License for the 
  * specific language governing permissions and limitations   * under the 
License.   */  void  senseair_init ( void )\n{\n}  And add dependency to this 
package in your project yml file.  Here's the listing from 
apps/air_quality/pkg.yml  pkg.name: apps/air_quality\npkg.type: 
app\npkg.description: Air quality sensor test\npkg.keywords:\n\npkg.deps:\n    
-  @apache-mynewt-core/libs/console/full \n    -  
@apache-mynewt-core/libs/newtmgr \n    -  @apache-mynewt-core/libs/os \n    -  
@apache-mynewt-core/libs/shell \n    -  @apache-mynewt-core/sys/con
 fig \n    -  @apache-mynewt-core/sys/log \n    -  
@apache-mynewt-core/sys/stats \n    -  @apache-mynewt-core/libs/baselibc \n    
- libs/my_drivers/senseair  And add a call to your main() to initialize this 
driver.      [user@IsMyLaptop:~/src/air_quality]$ diff 
project/blinky/src/main.c project/air_quality/src/main.c\n    28a29\n      
#include  senseair/senseair.h \n    190a192\n      senseair_init();\n    
[user@IsMyLaptop:~/src/air_quality  The ble_prph app runs everything in one 
task handler. For this project, we're going to add a second\ntask handler to 
respond to the shell, and then handle communicating with the senseair sensor 
for us.  /** shell task settings. */  #define SHELL_TASK_PRIO           2  
#define SHELL_STACK_SIZE          (OS_STACK_ALIGN(336))  struct   os_eventq   
shell_evq ; struct   os_task   shell_task ; bssnz_t   os_stack_t   shell_stack 
[ SHELL_STACK_SIZE ];  That defines the task, now we need to initialize it, add 
a task handler, and we're going to \nuse this 
 task as our default task handler.  /**   * Event loop for the main shell task. 
  */  static   void  shell_task_handler ( void   *unused )\n{\n     while  ( 1 
) {\n         os_eventq_run ( shell_evq );\n    }\n}  And in your  main()  add: 
      /* Initialize shell eventq */ \n     os_eventq_init ( shell_evq );\n\n    
 /* Create the shell task.         * All shell operations are performed in this 
task.       */ \n     os_task_init ( shell_task ,  shell ,  shell_task_handler 
,\n                               NULL ,  SHELL_TASK_PRIO ,  OS_WAIT_FOREVER 
,\n                               shell_stack ,  SHELL_STACK_SIZE );  Don't 
forget to change your default task handler!       os_eventq_dflt_set ( 
shell_evq );  And then build it to make sure all goes well.  
[user@IsMyLaptop:~/src/air_quality]$ newt build air_q\nCompiling 
senseair.c\nArchiving senseair.a\nLinking air_quality.elf\nApp successfully 
built: /Users/user/src/air_quality/bin/air_q/apps/air_quality/air_quality.elf  
All looks good.
 ", 
+            "text": "One of the sensors you want to enable is SenseAir K30, 
which will connect to the board over a serial port.\nTo start development of 
the driver, you first need to create a package description for it, and add 
stubs for sources.  The first thing to do is to create the directory structure 
for your driver:  [user@IsMyLaptop:~/src/air_quality]$ mkdir -p 
libs/my_drivers/senseair/include/senseair\n[user@IsMyLaptop:~/src/air_quality]$ 
mkdir -p libs/my_drivers/senseair/src  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.  [user@IsMyLaptop:~/src/air_quality]$ cat 
libs/my_drivers/senseair/pkg.yml  #  # Licensed to the Apache Software 
Foundation (ASF) under one  # or more contributor license agreements.  See the 
NOTICE file  # distributed with this work for additional information  # 
regarding copyright ownership.  The ASF licenses this file  # to you under the 
Apache License, Version 2.0 (the  # 
  License ); you may not use this file except in compliance  # with the 
License.  You may obtain a copy of the License at  #   #  http: 
//www.apache.org/licenses/LICENSE-2.0  #  # Unless required by applicable law 
or agreed to in writing,  # software distributed under the License is 
distributed on an  #  AS IS  BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY  # 
KIND, either express or implied.  See the License for the  # specific language 
governing permissions and limitations  # under the License.  #  pkg . name :  
libs/my_drivers/senseair  pkg . description :  Host   side   of   the   nimble  
 Bluetooth   Smart   stack . pkg . author :  Apache Mynewt  
[email protected]  pkg . homepage :  http://mynewt.apache.org/  
pkg . keywords :\n     -   ble \n     -   bluetooth  pkg . deps :\n     -   
@apache-mynewt-core/kernel/os   [user@IsMyLaptop:~/src/air_quality]$ cat 
libs/my_drivers/senseair/include/senseair/senseair.h  /*   * Licensed to the 
Apache Software Foundation (ASF) u
 nder one   * or more contributor license agreements.  See the NOTICE file   * 
distributed with this work for additional information   * regarding copyright 
ownership.  The ASF licenses this file   * to you under the Apache License, 
Version 2.0 (the   *  License ); you may not use this file except in compliance 
  * with the License.  You may obtain a copy of the License at   *    *  
http://www.apache.org/licenses/LICENSE-2.0   *   * Unless required by 
applicable law or agreed to in writing,   * software distributed under the 
License is distributed on an   *  AS IS  BASIS, WITHOUT WARRANTIES OR 
CONDITIONS OF ANY   * KIND, either express or implied.  See the License for the 
  * specific language governing permissions and limitations   * under the 
License.  */  #ifndef _SENSEAIR_H_  #define _SENSEAIR_H_  void   senseair_init 
( void ); #endif  /* _SENSEAIR_H_ */   [user@IsMyLaptop:~/src/air_quality]$ cat 
libs/my_drivers/senseair/src/senseair.c  /**   * Licensed to the Apache 
Software Fou
 ndation (ASF) under one   * or more contributor license agreements.  See the 
NOTICE file   * distributed with this work for additional information   * 
regarding copyright ownership.  The ASF licenses this file   * to you under the 
Apache License, Version 2.0 (the   *  License ); you may not use this file 
except in compliance   * with the License.  You may obtain a copy of the 
License at   *    *  http://www.apache.org/licenses/LICENSE-2.0   *   * Unless 
required by applicable law or agreed to in writing,   * software distributed 
under the License is distributed on an   *  AS IS  BASIS, WITHOUT WARRANTIES OR 
CONDITIONS OF ANY   * KIND, either express or implied.  See the License for the 
  * specific language governing permissions and limitations   * under the 
License.   */  void  senseair_init ( void )\n{\n}  And add dependency to this 
package in your project yml file.  Here's the listing from 
apps/air_quality/pkg.yml  pkg.name: apps/air_quality\npkg.type: 
app\npkg.description: Air q
 uality sensor test\npkg.keywords:\n\npkg.deps:\n    -  
@apache-mynewt-core/libs/console/full \n    -  @apache-mynewt-core/libs/newtmgr 
\n    -  @apache-mynewt-core/libs/os \n    -  @apache-mynewt-core/libs/shell \n 
   -  @apache-mynewt-core/sys/config \n    -  @apache-mynewt-core/sys/log/full 
\n    -  @apache-mynewt-core/sys/stats/full \n    -  
@apache-mynewt-core/libs/baselibc \n    - libs/my_drivers/senseair  And add a 
call to your main() to initialize this driver.      
[user@IsMyLaptop:~/src/air_quality]$ diff project/blinky/src/main.c 
project/air_quality/src/main.c\n    28a29\n      #include  senseair/senseair.h 
\n    190a192\n      senseair_init();\n    [user@IsMyLaptop:~/src/air_quality  
The ble_prph app runs everything in one task handler. For this project, we're 
going to add a second\ntask handler to respond to the shell, and then handle 
communicating with the senseair sensor for us.  /** shell task settings. */  
#define SHELL_TASK_PRIO           2  #define SHELL_STACK_SIZE 
          (OS_STACK_ALIGN(336))  struct   os_eventq   shell_evq ; struct   
os_task   shell_task ; bssnz_t   os_stack_t   shell_stack [ SHELL_STACK_SIZE ]; 
 That defines the task, now we need to initialize it, add a task handler, and 
we're going to \nuse this task as our default task handler.  /**   * Event loop 
for the main shell task.   */  static   void  shell_task_handler ( void   
*unused )\n{\n     while  ( 1 ) {\n         os_eventq_run ( shell_evq );\n    
}\n}  And in your  main()  add:       /* Initialize shell eventq */ \n     
os_eventq_init ( shell_evq );\n\n     /* Create the shell task.         * All 
shell operations are performed in this task.       */ \n     os_task_init ( 
shell_task ,  shell ,  shell_task_handler ,\n                               
NULL ,  SHELL_TASK_PRIO ,  OS_WAIT_FOREVER ,\n                               
shell_stack ,  SHELL_STACK_SIZE );  Don't forget to change your default task 
handler!       os_eventq_dflt_set ( shell_evq );  And then build it to mak
 e sure all goes well.  [user@IsMyLaptop:~/src/air_quality]$ newt build 
air_q\nCompiling senseair.c\nArchiving senseair.a\nLinking air_quality.elf\nApp 
successfully built: 
/Users/user/src/air_quality/bin/air_q/apps/air_quality/air_quality.elf  All 
looks good.", 
             "title": "Create packages for drivers"
         }, 
         {
@@ -1297,12 +1297,12 @@
         }, 
         {
             "location": 
"/os/tutorials/air_quality_sensor/#use-of-hal-for-drivers", 
-            "text": "The sensor has a serial port connection, and that's how 
you are going to connect to it. Your original BSP, hw/bsp/arduino_primo_nrf52, 
has two UARTs set up.\nWe're using one for our shell/console. It also has a 
second UART set up as a 'bit-bang' UART but since the SenseAir only needs 
to\ncommunicate at 9600 baud, this bit-banged uart is plenty fast enough.  
You'll have to make a small change to the  syscfg.yml  file in your project's 
target directory to chang the pin definitions \nfor this second UART. Those 
changes are as follows:      UART_0_PIN_TX: 23\n    UART_0_PIN_RX: 24  With 
this in place, you can refer to serial port where your SenseAir sensor by a 
logical number. This makes the code more platform independent - you could 
connect this sensor to another board, like Olimex. You will 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.  
You wil
 l now see what the driver code ends up looking like. Here's the header file, 
filled in from the stub you created earlier.  /*   * Licensed to the Apache 
Software Foundation (ASF) under one   * or more contributor license agreements. 
 See the NOTICE file   * distributed with this work for additional information  
 * regarding copyright ownership.  The ASF licenses this file   * to you under 
the Apache License, Version 2.0 (the   *  License ); you may not use this file 
except in compliance   * with the License.  You may obtain a copy of the 
License at   *    *  http://www.apache.org/licenses/LICENSE-2.0   *   * Unless 
required by applicable law or agreed to in writing,   * software distributed 
under the License is distributed on an   *  AS IS  BASIS, WITHOUT WARRANTIES OR 
CONDITIONS OF ANY   * KIND, either express or implied.  See the License for the 
  * specific language governing permissions and limitations   * under the 
License.  */  #ifndef _SENSEAIR_H_  #define _SENSEAIR_H_  enum 
   senseair_read_type  {\n         SENSEAIR_CO2 ,\n}; int   senseair_init ( int 
  uartno ); int   senseair_read ( enum   senseair_read_type ); #endif  /* 
_SENSEAIR_H_ */   As you can see, logical UART number has been added to the 
init routine. A 'read' function has been added, \nwhich is a blocking read. If 
you were making a commercial product, you would probably have a callback for 
reporting the results.  And here is the source for the driver.  /**   * 
Licensed to the Apache Software Foundation (ASF) under one   * or more 
contributor license agreements.  See the NOTICE file   * distributed with this 
work for additional information   * regarding copyright ownership.  The ASF 
licenses this file   * to you under the Apache License, Version 2.0 (the   *  
License ); you may not use this file except in compliance   * with the License. 
 You may obtain a copy of the License at   *   *  
http://www.apache.org/licenses/LICENSE-2.0   *   * Unless required by 
applicable law or agreed to in writi
 ng,   * software distributed under the License is distributed on an   *  AS IS 
 BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY   * KIND, either express or 
implied.  See the License for the   * specific language governing permissions 
and limitations   * under the License.   */  #include  string.h  #include  
shell/shell.h  #include  console/console.h  #include  os/os.h  #include  
hal/hal_uart.h  #include  senseair/senseair.h  static   const   uint8_t   
cmd_read_co2 []  =  {\n     0xFE ,  0 X44 ,  0 X00 ,  0 X08 ,  0 X02 ,  0 X9F , 
 0 X25 \n}; static   int   senseair_shell_func ( int   argc ,  char   **argv ); 
static   struct   shell_cmd   senseair_cmd   =  {\n    . sc_cmd   =   senseair 
,\n    . sc_cmd_func   =   senseair_shell_func ,\n}; struct   senseair  { \n    
 int   uart ;\n     struct   os_sem   sema ;\n     const   uint8_t   *tx_data 
;\n     int   tx_off ;\n     int   tx_len ;\n     uint8_t   rx_data [ 32 ]; \n  
   int   rx_off ;\n     int   value ;\n}  senseair ; static   int
   senseair_tx_char ( void   *arg )\n{\n     struct   senseair   *s   =   
senseair ;\n     int   rc ;\n\n     if  ( s- tx_off   =   s- tx_len ) {\n     
/*           * Command tx finished.           */ \n         s- tx_data   =   
NULL ;\n         return   - 1 ;\n    }\n\n     rc   =   s- tx_data [ s- tx_off 
];\n     s- tx_off++ ;\n     return   rc ;\n} /*   * CRC for modbus over serial 
port.   */  static   const   uint16_t   mb_crc_tbl []  =  {\n     0x0000 ,  
0xcc01 ,  0xd801 ,  0x1400 ,  0xf001 ,  0x3c00 ,  0x2800 ,  0xe401 ,\n     
0xa001 ,  0x6c00 ,  0x7800 ,  0xb401 ,  0x5000 ,  0x9c01 ,  0x8801 ,  0x4400 
\n}; static   uint16_t  mb_crc ( const   uint8_t   *data ,  int   len ,  
uint16_t   crc )\n{\n     while  ( len--     0 ) {\n         crc   ^=   *data++ 
;\n         crc   =  ( crc     4 )  ^   mb_crc_tbl [ crc     0xf ];\n         
crc   =  ( crc     4 )  ^   mb_crc_tbl [ crc     0xf ];\n    }\n     return   
crc ;\n} static   int  mb_crc_check ( const   void   *pkt ,  int   len )\
 n{\n     uint16_t   crc ,  cmp ;\n     uint8_t   *bp   =  ( uint8_t   * ) pkt 
;\n\n     if  ( len     sizeof ( crc )  +   1 ) {\n         return   - 1 ;\n    
}\n     crc   =   mb_crc ( pkt ,  len   -   2 ,  0xffff );\n     cmp   =   bp [ 
len   -   2 ]  |  ( bp [ len   -   1 ]    8 );\n     if  ( crc   !=   cmp ) {\n 
        return   - 1 ;\n    }  else  {\n         return   0 ;\n    }\n} static  
 int  senseair_rx_char ( void   *arg ,  uint8_t   data )\n{\n     struct   
senseair   *s   =  ( struct   senseair   * ) arg ;\n     int   rc ;\n\n     if  
( s- rx_off   =   sizeof ( s- rx_data )) {\n         s- rx_off   =   0 ;\n    
}\n     s- rx_data [ s- rx_off ]  =   data ;\n     s- rx_off++ ;\n\n     if  ( 
s- rx_off   ==   7 ) {\n         rc   =   mb_crc_check ( s- rx_data ,  s- 
rx_off );\n         if  ( rc   ==   0 ) {\n             s- value   =   s- 
rx_data [ 3 ]  *   256   +   s- rx_data [ 4 ];\n             os_sem_release ( 
s- sema );\n        }\n    }\n     return   0 ;\n} void  sens
 eair_tx ( struct   senseair   *s ,  const   uint8_t   *tx_data ,  int   
data_len )\n{\n     s- tx_data   =   tx_data ;\n     s- tx_len   =   data_len 
;\n     s- tx_off   =   0 ;\n     s- rx_off   =   0 ;\n\n     hal_uart_start_tx 
( s- uart );\n} int  senseair_read ( enum   senseair_read_type   type )\n{\n    
 struct   senseair   *s   =   senseair ;\n     const   uint8_t   *cmd ;\n     
int   cmd_len ;\n     int   rc ;\n\n     if  ( s- tx_data ) {\n         /*      
     * busy           */ \n         return   - 1 ;\n    }\n     switch  ( type 
) {\n     case   SENSEAIR_CO2 :\n         cmd   =   cmd_read_co2 ;\n         
cmd_len   =   sizeof ( cmd_read_co2 );\n         break ;\n     default : \n     
    return   - 1 ;\n    }\n     senseair_tx ( s ,  cmd ,  cmd_len );\n     rc   
=   os_sem_pend ( s- sema ,  OS_TICKS_PER_SEC   /   2 );\n     if  ( rc   ==   
OS_TIMEOUT ) {\n         /*           * timeout           */ \n         return  
 - 2 ;\n    }\n     return   s- value ;\n} static   in
 t  senseair_shell_func ( int   argc ,  char   **argv )\n{\n     int   value 
;\n     enum   senseair_read_type   type ;\n\n     if  ( argc     2 ) { usage 
:\n         console_printf ( %s co2\\n ,  argv [ 0 ]);\n         return   0 ;\n 
   }\n     if  ( !strcmp ( argv [ 1 ],  co2 )) {\n         type   =   
SENSEAIR_CO2 ;\n    }  else  {\n         goto   usage ;\n    }\n     value   =  
 senseair_read ( type );\n     if  ( value   =   0 ) {\n         console_printf 
( Got %d\\n ,  value );\n    }  else  {\n         console_printf ( Error while 
reading: %d\\n ,  value );\n    }\n     return   0 ;\n} int  senseair_init ( 
int   uartno )\n{\n     int   rc ;\n     struct   senseair   *s   =   senseair 
;\n\n     rc   =   shell_cmd_register ( senseair_cmd );\n     if  ( rc ) {\n    
     return   rc ;\n    }\n\n     rc   =   os_sem_init ( s- sema ,  1 );\n     
if  ( rc ) {\n         return   rc ;\n    }\n     rc   =   hal_uart_init_cbs ( 
uartno ,  senseair_tx_char ,  NULL ,\n       senseair_rx_cha
 r ,  senseair );\n     if  ( rc ) {\n         return   rc ;\n    }\n     rc   
=   hal_uart_config ( uartno ,  9600 ,  8 ,  1 ,  HAL_UART_PARITY_NONE ,\n      
 HAL_UART_FLOW_CTL_NONE );\n     if  ( rc ) {\n         return   rc ;\n    }\n  
   s- uart   =   uartno ;\n\n     return   0 ;\n}  And your modified your 
main() for senseair driver init.  int  main ( int   argc ,  char   **argv 
)\n{\n    ....\n     senseair_init ( 0 );\n    ....\n    }  You can see from 
the code that you are using the HAL interface to open a UART port, and using OS 
\nsemaphore as a way of blocking the task when waiting for read response to 
come back from the sensor.  Now comes the fun part: Hooking up the sensor! It's 
fun because a) hooking up a sensor is always \nfun and b) the SenseAir sensor's 
PCB is entirely unlabeled, so you'll have to trust us on how to hook it up.   
So here we go.   You'll have to do a little soldering. I soldered some header 
pins to the SenseAir K30 board to\nmake connecting wires easie
 r using standard jumper wires, but you can also just solder wires\nstraight to 
the board if you prefer.  Here's what your SenseAir board should look like once 
it's wired up:   Now that you have that wired up, let's get the Arduino Primo 
wired up. A couple of things to note:   The Arduino Primo's 'console' UART is 
actually UART1. The secondary (bit-banged) UART is \nUART0, so that's where 
we'll have to hook up the SenseAir.   Here's what your Arduino Primo should now 
look like with everything wired in:   Everything is wired and you're ready to 
go! Build and load your new app:  $ newt build air_q\nBuilding target 

<TRUNCATED>

Reply via email to