http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/blob/a4d946d9/latest/mkdocs/search_index.json
----------------------------------------------------------------------
diff --git a/latest/mkdocs/search_index.json b/latest/mkdocs/search_index.json
index 245f7c7..5613d59 100644
--- a/latest/mkdocs/search_index.json
+++ b/latest/mkdocs/search_index.json
@@ -1276,56 +1276,6 @@
             "title": "Testing on your target"
         }, 
         {
-            "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\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 
\n...@mynewt.incubator.apache.org\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-c
 ore/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.b
 sp 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[us
 er@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 WARRANTIE
 S 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 \n...@mynewt.incubator.apache.org\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 * dis
 tributed 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 qualit
 y 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    - 
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_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(\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_S
 TACK_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_PROM
 PT: 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 se
 rial 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: bl
 eprph   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 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 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\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 * Li
 censed 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#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*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        \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_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    \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 
\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(\n
 Got %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 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. 
\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 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    P
 ort /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"
-        }, 
-        {
-            "location": 
"/os/tutorials/air_quality_sensor/#air-quality-sensor-project", 
-            "text": "", 
-            "title": "Air quality sensor project"
-        }, 
-        {
-            "location": 
"/os/tutorials/air_quality_sensor/#setting-up-source-tree-for-stuff-you-need", 
-            "text": "To start with, you need to create a new project under 
which you will do this development. So you type in:      $ mkdir $HOME/src\n    
$ cd $HOME/src\n    $ newt new air_quality  Let'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.   Your project.yml file should look like this: 
     [user@IsMyLaptop:~/src/air_quality]$ emacs project.yml  \n    
[user@IsMyLaptop:~/src/air_quality]$ cat project.yml\n    project.name:  
air_quality \n\n    project.repositories:\n        - apache-mynewt-core\n\n    
# Use github s distribution mechanism for core ASF libraries.\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  Good. 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.  Now 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.  [user@IsMyLaptop:~/src/air_quality]$ newt 
target copy my_blinky_sim blink_primo\nTarget successfully copied; 
targets/my_blinky_sim --  
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 successfully set target.bsp to 
@apache-mynewt-core/hw/bsp/arduino_primo_nrf52\n[user@IsMyLaptop:~/src/air_quality]$
 newt build bl
 ink_primo\nCompiling hal_bsp.c\n...\nLinking blinky.elf\nApp successfully 
built: /Users/user/src/air_quality/bin/blink_primo/apps/blinky/blinky.elf  
Good.  You know that this platform uses bootloader, which means you have to 
create a target for that too.  [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  And then build it, and load it onto the 
board.  newt 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  At 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  blinky_primo  tutorial so that you\ncan 
properly communicate with your board.  Next you must download the targets to 
board, and see that the LED ac
 tually blinks. You plug in the \nArduino Primo board to your laptop, and say:  
[user@IsMyLaptop:~/src/air_quality]$ newt load blink_primo\nLoading app image 
into slot 1\nError: couldn t 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  target-name .\n\nUsage:\n 
 newt load [flags]\n\nExamples:\n  newt load  target-name \n\n\nGlobal Flags:\n 
 -l, --loglevel string   Log level, defaults to WARN. (default  WARN )\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 t 
output anything.\n  -v, --verbose           Enable verbose output when 
executing commands.\nexit status 1  Ah. Forgot to create an image out 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.  
[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  And it's blinking.  Shortcut for doing 
build/create-image/load/debug steps all in one is 'newt run' command. Check 
\nout the usage from command line help.", 
-            "title": "Setting up source tree for stuff you need"
-        }, 
-        {
-            "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.  [user@IsMyLaptop:~/src/air_quality]$ cat 
apps/air_quality/pkg.yml\npkg.name: apps/air_q
 uality\npkg.type: app\npkg.description: BLE Air Quality 
application.\npkg.author:  Apache Mynewt  d...@mynewt.incubator.apache.org 
\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 . description :  Host   side   of   the   nimble  
 Bluetooth   Smart   stack . pkg . author :  Apache Mynewt  
d...@mynewt.incubator.apache.org  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    - 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:~/s
 rc/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"
-        }, 
-        {
-            "location": 
"/os/tutorials/air_quality_sensor/#add-cli-commands-for-testing-drivers", 
-            "text": "While 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  enable the CLI , so all we'll need to do is 
add the propper values to the project's  syscfg.yml  file:  
[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  Then register your 
senseair command with the shell by adding the following to  
libs/my_drivers/senseair/src/senseair.c  #include  shell/shell.h  #include  
console/console.h  #include  assert.h  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}; 
void  senseair_init ( void )\n{\n     int   rc ;\n\n     rc   = 
   shell_cmd_register ( senseair_cmd );\n     assert ( rc   ==   0 );\n} static 
  int  senseair_shell_func ( int   argc ,  char   **argv )\n{\n     
console_printf ( Yay! Somebody called!\\n );\n     return   0 ;\n\n}  Now 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  here .  You'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.   
   [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    Commands:\n    641:     stat      echo 
        ?    prompt     ticks     tasks\n    643: mempools      dat
 e  senseair\n    644:   senseair\n    Yay! Somebody called!\n    1125:  \n    
53611:   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:    
That'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.", 
-            "title": "Add CLI commands for testing drivers"
-        }, 
-        {
-            "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 change  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 w
 ill 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_  enu
 m   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 wri
 ting,   * 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   i
 nt  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  se
 nseair_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   
 int  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_c
 har ,  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 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 easier u
 sing 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 UART0, 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 
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  Now, 
 you should be able to connect to your serial port and read values:  
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    1185:   ?\n    Commands:\n    1382:     stat      echo         ?    
prompt     ticks     tasks\n    1390: mempools      date  senseair\n    1395:   
senseair\n    senseair co2\n    2143:   senseair co2\n    Got 973  And you're 
getting valid readings! Congratulations!  Next we'll hook this all up via 
Bluetooth so that you can read those values remotely.", 
-            "title": "Use of HAL for drivers"
-        }, 
-        {
-            "location": "/os/tutorials/air_quality_ble/", 
-            "text": "Air quality sensor project via Bluetooth\n\n\nThis is a 
follow-on project to the \nBasic Air Quality Sensor\n project; so it 
is\nassumed that you have worked through that project and have your CO\n2\n 
sensor working properly with\nyour Arduino Primo board. \n\n\nSo let's get 
started making this thing Bluetooth enabled!\n\n\nAdd Bluetooth GATT 
Services\n\n\nSince we already built the previous demo on the \nbluetooth 
peripheral\n basic\napp most of the bluetooth plumbing has already been taken 
care of for us. What's left is for us\nto add the required GATT services for 
advertising the Carbon Dioxide sensor so that\nother devices can get those 
values.\n\n\nFirst, we'll define the GATT Services in 
\napps/air_quality/src/bleprph.h\n.\n\n\n/* Sensor Data */\n\n\n/* 
e761d2af-1c15-4fa7-af80-b5729002b340 */\n\n\nstatic\n \nconst\n 
\nble_uuid128_t\n \ngatt_svr_svc_co2_uuid\n \n=\n\n    
\nBLE_UUID128_INIT\n(\n0x40\n, \n0xb3\n, \n0x20\n, \n0x90\n, \n0x72\n, 
\n0xb5\n, \n0x80
 \n, \n0xaf\n,\n                     \n0xa7\n, \n0x4f\n, \n0x15\n, \n0x1c\n, 
\n0xaf\n, \n0xd2\n, \n0x61\n, \n0xe7\n);\n\n#define CO2_SNS_TYPE          
0xDEAD\n\n\n#define CO2_SNS_STRING \nSenseAir K30 CO2 Sensor\n\n\n#define 
CO2_SNS_VAL           0xBEAD\n\n\n\nuint16_t\n \ngatt_co2_val\n; 
\n\n\n\n\n\nYou can use any hex values you choose for the sensor type and 
sensor values, and you can \neven forget the sensor type and sensor string 
definitions altogether but they make\nthe results look nice in our Bluetooth 
App for Mac OS X and iOS.\n\n\nNext we'll add those services to 
\napps/air_quality/src/gatt_svr.c\n.\n\n\nstatic\n 
\nint\n\n\ngatt_svr_sns_access\n(\nuint16_t\n \nconn_handle\n, \nuint16_t\n 
\nattr_handle\n,\n    \nstruct\n \nble_gatt_access_ctxt\n \n*ctxt\n,\n    
\nvoid\n \n*arg\n);\n\n\nstatic\n \nuint16_t\n 
\ngatt_co2_val_len\n;\n\n\n\n\n\nMake sure it is added as \nprimary\n 
service.\n\n\nstatic\n \nconst\n \nstruct\n \nble_gatt_svc_def\n 
\ngatt_svr_svcs\n[] \n=\n {\n    {\
 n        \n/*** Service: Security test. */\n\n        .\ntype\n \n=\n 
\nBLE_GATT_SVC_TYPE_PRIMARY\n,\n        .\nuuid\n \n=\n 
\ngatt_svr_svc_sec_test_uuid\n.\nu\n,\n        .\ncharacteristics\n \n=\n 
(\nstruct\n \nble_gatt_chr_def\n[]) { {\n            \n/*** Characteristic: 
Random number generator. */\n\n            .\nuuid\n \n=\n 
\ngatt_svr_chr_sec_test_rand_uuid\n.\nu\n,\n            .\naccess_cb\n \n=\n 
\ngatt_svr_chr_access_sec_test\n,\n            .\nflags\n \n=\n 
\nBLE_GATT_CHR_F_READ\n \n|\n \nBLE_GATT_CHR_F_READ_ENC\n,\n        }, {\n      
      \n/*** Characteristic: Static value. */\n\n            .\nuuid\n \n=\n 
\ngatt_svr_chr_sec_test_static_uuid\n,.\nu\n\n            .\naccess_cb\n \n=\n 
\ngatt_svr_chr_access_sec_test\n,\n            .\nflags\n \n=\n 
\nBLE_GATT_CHR_F_READ\n \n|\n\n                     \nBLE_GATT_CHR_F_WRITE\n 
\n|\n \nBLE_GATT_CHR_F_WRITE_ENC\n,\n        }, {\n            \n0\n, \n/* No 
more characteristics in this service. */\n\n        } },\n    },\n
         {\n            \n/*** CO2 Level Notification Service. */\n\n           
 .\ntype\n \n=\n \nBLE_GATT_SVC_TYPE_PRIMARY\n,\n            .\nuuid\n \n=\n 
\ngatt_svr_svc_co2_uuid\n.\nu\n,\n            .\ncharacteristics\n \n=\n 
(\nstruct\n \nble_gatt_chr_def\n[]) { {\n                .\nuuid\n \n=\n 
\nBLE_UUID16_DECLARE\n(\nCO2_SNS_TYPE\n),\n                .\naccess_cb\n \n=\n 
\ngatt_svr_sns_access\n,\n                .\nflags\n \n=\n 
\nBLE_GATT_CHR_F_READ\n,\n            }, {\n                .\nuuid\n \n=\n 
\nBLE_UUID16_DECLARE\n(\nCO2_SNS_VAL\n),\n                .\naccess_cb\n \n=\n 
\ngatt_svr_sns_access\n,\n                .\nflags\n \n=\n 
\nBLE_GATT_CHR_F_NOTIFY\n,\n            }, {\n                \n0\n, \n/* No 
more characteristics in this service. */\n\n            } },\n        },\n\n    
    {\n            \n0\n, \n/* No more services. */\n\n        },\n    
};\n\n\n\n\n\nNext we need to tell the GATT Server how to handle requests for 
CO\n2\n readings :\n\n\nsstatic\n \n
 int\n\n\ngatt_svr_sns_access\n(\nuint16_t\n \nconn_handle\n, \nuint16_t\n 
\nattr_handle\n,\n                          \nstruct\n \nble_gatt_access_ctxt\n 
\n*ctxt\n,\n                          \nvoid\n \n*arg\n)\n{\n    \nuint16_t\n 
\nuuid16\n;\n    \nint\n \nrc\n;\n\n    \nuuid16\n \n=\n 
\nble_uuid_u16\n(\nctxt-\nchr-\nuuid\n);\n\n    \nswitch\n (\nuuid16\n) {\n    
\ncase\n \nCO2_SNS_TYPE\n:\n        \nassert\n(\nctxt-\nop\n \n==\n 
\nBLE_GATT_ACCESS_OP_READ_CHR\n);\n        \nrc\n \n=\n 
\nos_mbuf_append\n(\nctxt-\nom\n, \nCO2_SNS_STRING\n, \nsizeof\n 
\nCO2_SNS_STRING\n);\n        \nBLEPRPH_LOG\n(\nINFO\n, \nCO2 SENSOR TYPE READ: 
%s\\n\n, \nCO2_SNS_STRING\n);\n        \nreturn\n \nrc\n \n==\n \n0\n \n?\n 
\n0\n \n:\n \nBLE_ATT_ERR_INSUFFICIENT_RES\n;\n\n    \ncase\n 
\nCO2_SNS_VAL\n:\n        \nif\n (\nctxt-\nop\n \n==\n 
\nBLE_GATT_ACCESS_OP_WRITE_CHR\n) {\n            \nrc\n \n=\n 
\ngatt_svr_chr_write\n(\nctxt-\nom\n, \n0\n,\n                                  
  \nsizeof\n \ngatt_co2_v
 al\n,\n                                    \ngatt_co2_val\n,\n                 
                   \ngatt_co2_val_len\n);\n            \nreturn\n \nrc\n;\n     
   } \nelse\n \nif\n (\nctxt-\nop\n \n==\n \nBLE_GATT_ACCESS_OP_READ_CHR\n) {\n 
           \nrc\n \n=\n \nos_mbuf_append\n(\nctxt-\nom\n, \ngatt_co2_val\n,\n   
                             \nsizeof\n \ngatt_co2_val\n);\n            
\nreturn\n \nrc\n \n==\n \n0\n \n?\n \n0\n \n:\n 
\nBLE_ATT_ERR_INSUFFICIENT_RES\n;\n        }\n\n    \ndefault\n:\n\n        
\nassert\n(\n0\n);\n        \nreturn\n \nBLE_ATT_ERR_UNLIKELY\n;\n    
}\n}\n\n\n\n\n\nNow it's time to go into our \napps/air_quality/src/main.c\n 
and change how we read CO\n2\n readings and \nrespond to requests. \n\n\nWe'll 
need a task handler with an event queue for the CO\n2\n readings -- they were 
handled by the shell task in the previous tutorial but now it needs to be 
replaced by a different handler as shown below.\n\n\n/* CO2 Task settings 
*/\n\n\n#define CO2_TASK_PRIO
            5\n\n\n#define CO2_STACK_SIZE          
(OS_STACK_ALIGN(336))\n\n\nstruct\n \nos_eventq\n \nco2_evq\n;\n\nstruct\n 
\nos_task\n \nco2_task\n;\n\nbssnz_t\n \nos_stack_t\n 
\nco2_stack\n[\nCO2_STACK_SIZE\n];\n\n\n\n\n\nAnd of course we'll need to go to 
our \nmain()\n and do all the standard task and event setup we\nnormally do by 
adding the following. Again, remember to delete all the shell event queues and 
tasks.\n\n\n/* Initialize sensor eventq 
*/\n\n\nos_eventq_init\n(\nco2_evq\n);\n\n\n/* Create the CO2 reader task.  
\n\n\n * All sensor reading operations are performed in this task.\n\n\n 
*/\n\n\nos_task_init\n(\nco2_task\n, \nsensor\n, \nco2_task_handler\n,\n        
    \nNULL\n, \nCO2_TASK_PRIO\n, \nOS_WAIT_FOREVER\n,\n            
\nco2_stack\n, \nCO2_STACK_SIZE\n);\n\n\n\n\n\nWe'll also need to add a task 
handler -- since we initialized it above:\n\n\n/**\n\n\n * Event loop for the 
sensor task.\n\n\n */\n\n\nstatic\n \nvoid\n\n\nco2_task_handler\n(\nvoid\n 
\n*unused\n)\
 n{    \n    \nwhile\n (\n1\n) {\n        \nco2_read_event\n();\n        \n/* 
Wait 2 second */\n\n        \nos_time_delay\n(\nOS_TICKS_PER_SEC\n \n*\n 
\n2\n);\n\n    }\n}\n\n\n\n\n\nAnd finally, we'll take care of that 
\nco2_read_event()\n function:\n\n\nint\n\n\nco2_read_event\n(\nvoid\n)\n{\n    
\nint\n \nvalue\n;\n    \nenum\n \nsenseair_read_type\n \ntype\n \n=\n 
\nSENSEAIR_CO2\n;\n    \nuint16_t\n \nchr_val_handle\n;\n    \nint\n 
\nrc\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        \ngoto\n \nerr\n;\n    }\n    
\ngatt_co2_val\n \n=\n \nvalue\n;\n    \nrc\n \n=\n 
\nble_gatts_find_chr\n(\ngatt_svr_svc_co2_uuid\n.\nu\n, 
\nBLE_UUID16_DECLARE\n(\nCO2_SNS_VAL\n), \nNULL\n, \nchr_val_handle\n);\n    
\nassert\n(\nrc\n \n==\n \n0\n);\n    
\nble_gatts_chr_updated\n(\nchr_val_handle\n);\n    \n
 return\n (\n0\n);\n\nerr\n:\n    \nreturn\n (\nrc\n);\n}\n\n\n\n\n\nYou'll 
notice that it looks eeirily similar to a portion of the shell event we created 
\nearlier. This one simply reads and updates the CO\n2\n value and sends that 
over BLE to any\nconnected clients instead. \n\n\nWe can now build, 
create-image and load the app onto our Arduino Primo board, and then \nconnect 
and see the updated values! The image below shows the results using MyNewt 
Sensor Reader,\na Mac OS X app developed for connecting to MyNewt devices over 
Bluetooth but you can also use LightBlue\nor any other application that can 
connect to, and read, Bluetooth data.\n\n\n\n\nCongratulations!!", 
-            "title": "Bluetooth-enabled Air Quality Sensor"
-        }, 
-        {
-            "location": 
"/os/tutorials/air_quality_ble/#air-quality-sensor-project-via-bluetooth", 
-            "text": "This is a follow-on project to the  Basic Air Quality 
Sensor  project; so it is\nassumed that you have worked through that project 
and have your CO 2  sensor working properly with\nyour Arduino Primo board.   
So let's get started making this thing Bluetooth enabled!", 
-            "title": "Air quality sensor project via Bluetooth"
-        }, 
-        {
-            "location": 
"/os/tutorials/air_quality_ble/#add-bluetooth-gatt-services", 
-            "text": "Since we already built the previous demo on the  
bluetooth peripheral  basic\napp most of the bluetooth plumbing has already 
been taken care of for us. What's left is for us\nto add the required GATT 
services for advertising the Carbon Dioxide sensor so that\nother devices can 
get those values.  First, we'll define the GATT Services in  
apps/air_quality/src/bleprph.h .  /* Sensor Data */  /* 
e761d2af-1c15-4fa7-af80-b5729002b340 */  static   const   ble_uuid128_t   
gatt_svr_svc_co2_uuid   = \n     BLE_UUID128_INIT ( 0x40 ,  0xb3 ,  0x20 ,  
0x90 ,  0x72 ,  0xb5 ,  0x80 ,  0xaf ,\n                      0xa7 ,  0x4f ,  
0x15 ,  0x1c ,  0xaf ,  0xd2 ,  0x61 ,  0xe7 ); #define CO2_SNS_TYPE          
0xDEAD  #define CO2_SNS_STRING  SenseAir K30 CO2 Sensor  #define CO2_SNS_VAL    
       0xBEAD  uint16_t   gatt_co2_val ;   You can use any hex values you 
choose for the sensor type and sensor values, and you can \neven forget the 
sensor type and sensor string definitions alt
 ogether but they make\nthe results look nice in our Bluetooth App for Mac OS X 
and iOS.  Next we'll add those services to  apps/air_quality/src/gatt_svr.c .  
static   int  gatt_svr_sns_access ( uint16_t   conn_handle ,  uint16_t   
attr_handle ,\n     struct   ble_gatt_access_ctxt   *ctxt ,\n     void   *arg 
); static   uint16_t   gatt_co2_val_len ;  Make sure it is added as  primary  
service.  static   const   struct   ble_gatt_svc_def   gatt_svr_svcs []  =  {\n 
   {\n         /*** Service: Security test. */ \n        . type   =   
BLE_GATT_SVC_TYPE_PRIMARY ,\n        . uuid   =   gatt_svr_svc_sec_test_uuid . 
u ,\n        . characteristics   =  ( struct   ble_gatt_chr_def []) { {\n       
      /*** Characteristic: Random number generator. */ \n            . uuid   = 
  gatt_svr_chr_sec_test_rand_uuid . u ,\n            . access_cb   =   
gatt_svr_chr_access_sec_test ,\n            . flags   =   BLE_GATT_CHR_F_READ   
|   BLE_GATT_CHR_F_READ_ENC ,\n        }, {\n             /*** Charact
 eristic: Static value. */ \n            . uuid   =   
gatt_svr_chr_sec_test_static_uuid ,. u \n            . access_cb   =   
gatt_svr_chr_access_sec_test ,\n            . flags   =   BLE_GATT_CHR_F_READ   
| \n                      BLE_GATT_CHR_F_WRITE   |   BLE_GATT_CHR_F_WRITE_ENC 
,\n        }, {\n             0 ,  /* No more characteristics in this service. 
*/ \n        } },\n    },\n        {\n             /*** CO2 Level Notification 
Service. */ \n            . type   =   BLE_GATT_SVC_TYPE_PRIMARY ,\n            
. uuid   =   gatt_svr_svc_co2_uuid . u ,\n            . characteristics   =  ( 
struct   ble_gatt_chr_def []) { {\n                . uuid   =   
BLE_UUID16_DECLARE ( CO2_SNS_TYPE ),\n                . access_cb   =   
gatt_svr_sns_access ,\n                . flags   =   BLE_GATT_CHR_F_READ ,\n    
        }, {\n                . uuid   =   BLE_UUID16_DECLARE ( CO2_SNS_VAL 
),\n                . access_cb   =   gatt_svr_sns_access ,\n                . 
flags   =   BLE_GATT_CHR_F_
 NOTIFY ,\n            }, {\n                 0 ,  /* No more characteristics 
in this service. */ \n            } },\n        },\n\n        {\n             0 
,  /* No more services. */ \n        },\n    };  Next we need to tell the GATT 
Server how to handle requests for CO 2  readings :  sstatic   int  
gatt_svr_sns_access ( uint16_t   conn_handle ,  uint16_t   attr_handle ,\n      
                     struct   ble_gatt_access_ctxt   *ctxt ,\n                  
         void   *arg )\n{\n     uint16_t   uuid16 ;\n     int   rc ;\n\n     
uuid16   =   ble_uuid_u16 ( ctxt- chr- uuid );\n\n     switch  ( uuid16 ) {\n   
  case   CO2_SNS_TYPE :\n         assert ( ctxt- op   ==   
BLE_GATT_ACCESS_OP_READ_CHR );\n         rc   =   os_mbuf_append ( ctxt- om ,  
CO2_SNS_STRING ,  sizeof   CO2_SNS_STRING );\n         BLEPRPH_LOG ( INFO ,  
CO2 SENSOR TYPE READ: %s\\n ,  CO2_SNS_STRING );\n         return   rc   ==   0 
  ?   0   :   BLE_ATT_ERR_INSUFFICIENT_RES ;\n\n     case   CO2_SNS_VAL :\n     
  
   if  ( ctxt- op   ==   BLE_GATT_ACCESS_OP_WRITE_CHR ) {\n             rc   =  
 gatt_svr_chr_write ( ctxt- om ,  0 ,\n                                     
sizeof   gatt_co2_val ,\n                                     gatt_co2_val ,\n  
                                   gatt_co2_val_len );\n             return   
rc ;\n        }  else   if  ( ctxt- op   ==   BLE_GATT_ACCESS_OP_READ_CHR ) {\n 
            rc   =   os_mbuf_append ( ctxt- om ,  gatt_co2_val ,\n              
                   sizeof   gatt_co2_val );\n             return   rc   ==   0  
 ?   0   :   BLE_ATT_ERR_INSUFFICIENT_RES ;\n        }\n\n     default : \n     
    assert ( 0 );\n         return   BLE_ATT_ERR_UNLIKELY ;\n    }\n}  Now it's 
time to go into our  apps/air_quality/src/main.c  and change how we read CO 2  
readings and \nrespond to requests.   We'll need a task handler with an event 
queue for the CO 2  readings -- they were handled by the shell task in the 
previous tutorial but now it needs to be replaced by
  a different handler as shown below.  /* CO2 Task settings */  #define 
CO2_TASK_PRIO           5  #define CO2_STACK_SIZE          
(OS_STACK_ALIGN(336))  struct   os_eventq   co2_evq ; struct   os_task   
co2_task ; bssnz_t   os_stack_t   co2_stack [ CO2_STACK_SIZE ];  And of course 
we'll need to go to our  main()  and do all the standard task and event setup 
we\nnormally do by adding the following. Again, remember to delete all the 
shell event queues and tasks.  /* Initialize sensor eventq */  os_eventq_init ( 
co2_evq ); /* Create the CO2 reader task.     * All sensor reading operations 
are performed in this task.   */  os_task_init ( co2_task ,  sensor ,  
co2_task_handler ,\n             NULL ,  CO2_TASK_PRIO ,  OS_WAIT_FOREVER ,\n   
          co2_stack ,  CO2_STACK_SIZE );  We'll also need to add a task handler 
-- since we initialized it above:  /**   * Event loop for the sensor task.   */ 
 static   void  co2_task_handler ( void   *unused )\n{    \n     while  ( 1 ) 
{\n         co2
 _read_event ();\n         /* Wait 2 second */ \n         os_time_delay ( 
OS_TICKS_PER_SEC   *   2 );\n\n    }\n}  And finally, we'll take care of that  
co2_read_event()  function:  int  co2_read_event ( void )\n{\n     int   value 
;\n     enum   senseair_read_type   type   =   SENSEAIR_CO2 ;\n     uint16_t   
chr_val_handle ;\n     int   rc ;\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         goto   err ;\n    }\n     gatt_co2_val   =   value ;\n     rc   =  
 ble_gatts_find_chr ( gatt_svr_svc_co2_uuid . u ,  BLE_UUID16_DECLARE ( 
CO2_SNS_VAL ),  NULL ,  chr_val_handle );\n     assert ( rc   ==   0 );\n     
ble_gatts_chr_updated ( chr_val_handle );\n     return  ( 0 ); err :\n     
return  ( rc );\n}  You'll notice that it looks eeirily similar to a portion of 
the shell event we created \nearlier. This one simply reads and up
 dates the CO 2  value and sends that over BLE to any\nconnected clients 
instead.   We can now build, create-image and load the app onto our Arduino 
Primo board, and then \nconnect and see the updated values! The image below 
shows the results using MyNewt Sensor Reader,\na Mac OS X app developed for 
connecting to MyNewt devices over Bluetooth but you can also use LightBlue\nor 
any other application that can connect to, and read, Bluetooth data.   
Congratulations!!", 
-            "title": "Add Bluetooth GATT Services"
-        }, 
-        {
             "location": "/os/tutorials/event_queue/", 
             "text": "How to define a task which uses event queues to manage 
multiple events\n\n\nIntroduction\n\n\nEvent queue is a mechanism by which you 
can serialize incoming events for your task. You can use it to get info about 
arrived hardware interrupts, callout expirations and messages from other 
tasks.\n\n\nThe benefit of doing inter-task communication this way is that 
there should be less resources that need to be locked.\n\n\nThe benefit of 
doing interrupt processing in a task context instead of inside an interrupt 
context is that you are not blocking other HW interrupts when doing the work. 
The same goes for high priority tasks in the system; they're blocked until the 
interrupt handler returns. From the task context you'll also be able to access 
other OS facilities; you can sleep while waiting for a lock, for 
example.\n\n\n\n\nExample app\n\n\nHere you are going to write an app which 
demonstrates the use of event queues for communication between tasks. You will  
also use
  OS callouts for timer expiration and another event from a GPIO 
interrupt.\n\n\nYou will  use inputs from 3 sources to toggle 3 GPIO outputs on 
my STM32F3discovery board.\n\n\n\n\nCreate project\n\n\nYou start by creating a 
project and populating it with repositories incubator-mynewt-core and 
mynewt_stm32f3. See \nSTM32F3 tutorial\n if you need help with this. You can 
also read the tutorial on \nAdditional Repositories\n for a more thorough 
understanding. \n\n\n \n\n\nCreate application\n\n\nHere's what the pkg.yml 
looks for the application.\n\n\n[marko@IsMyLaptop:~/src/events]$ cat 
apps/event_sample/pkg.yml\npkg.name: apps/event_sample\npkg.type: 
app\n\npkg.deps:\n    - \n@apache-mynewt-core/libs/os\n\n    - 
\n@apache-mynewt-core/hw/hal\n\n    - 
\n@apache-mynewt-core/libs/console/stub\n\n\n\n\n\n\n\n\nInitialize the event 
queue structure\n\n\nThis must be done before anyone tries to place events to 
the queue. Here it's done before any task gets created. Initialization is done 
by ca
 lling \nos_eventq_init()\n.\n\n\n#define MY_TASK_PRIO        4\n\n\n#define 
MY_TASK_STACK_SZ    512\n\n\n\nstatic\n \nstruct\n \nos_eventq\n 
\nmy_eventq\n;\n\nstatic\n \nos_stack_t\n 
\nmy_task_stack\n[\nMY_TASK_STACK_SZ\n];\n\nstatic\n \nstruct\n \nos_task\n 
\nmy_task_str\n;\n\n\nvoid\n\n\ninit_tasks\n(\nvoid\n)\n{\n    \nstruct\n 
\nos_task\n \ntaskid\n;\n\n    \nos_eventq_init\n(\nmy_eventq\n);\n    
\nos_task_init\n(\nmy_task_str\n, \ntask\n, \nmy_task\n, \nNULL\n, 
\nMY_TASK_PRIO\n,\n        \nOS_WAIT_FOREVER\n, \nmy_task_stack\n, 
\nMY_TASK_STACK_SZ\n);\n\n\n\n\n\n\n\nProcessing events\n\n\nHere event 
processing is done inside \nmy_task\n. The main loop of the task is pulling 
events from the queue, and then taking action. We look at the type of the event 
to figure out what to do.\n\n\nThe code snippet shows what the main loop of the 
event handler looks like. Events are removed from the head of the queue using 
os_eventq_get\n\n\nvoid\n\n\nmy_task\n(\nvoid\n \n*arg\n)\n{\n    \nstruc
 t\n \nos_event\n \n*ev\n;\n\n    \nwhile\n (\n1\n) {\n        \nev\n \n=\n 
\nos_eventq_get\n(\nmy_eventq\n);\n        \nswitch\n (\nev-\nev_type\n) {\n    
    \n/* more event types here */\n\n        \ndefault\n:\n\n            
\nassert\n(\n0\n);\n        }\n    }\n}\n\n\n\n\n\n\n\nEvent types\n\n\nYou can 
define your own event types. Some numbers are already reserved by the OS, so 
you should not use those as your own types.\n\n\nReserved event types are 
defined in \nlibs/os/include/os/os_eventq.h\n. One example of a reserved type 
is OS_EVENT_T_TIMER, which is used as type in OS callouts.\n\n\nYou should 
start your event numbers from \nOS_EVENT_T_PERUSER\n, and go higher.\n\n\nYou 
are going to generate events from GPIO interrupt handler, from another task as 
well as from a callout. OS callout already has a type, but you'll need to 
define types for the other uses.\n\n\n#define MY_TASK_GPIO_EVENT  
(OS_EVENT_T_PERUSER)\n\n\n#define MY_TASK_TASK_EVENT  (OS_EVENT_T_PERUSER + 
1)\n\n\n\n\n
 \n\n\n\nPosting events from another task\n\n\nEvents are posted to a queue by 
calling \nos_eventq_put()\n. You need to preallocate memory for the event 
structure. Here it's done by declaring the event structure as a global 
variable.\n\n\nNote that you can call \nos_eventq_put()\n with an event which 
has already been queued. In that case, the call has no effect; the position of 
the event is not changed within the queue.\n\n\nIn the code snippet we declare 
the os_event structure, and initialize it. We also create the event generating 
task, and periodically post event to the event queue.\n\n\n#define 
GEN_TASK_PRIO       3\n\n\n#define GEN_TASK_STACK_SZ   512\n\n\n\nstatic\n 
\nstruct\n \nos_event\n \ngen_task_ev\n;\n\nstatic\n \nos_stack_t\n 
\ngen_task_stack\n[\nGEN_TASK_STACK_SZ\n];\n\nstatic\n \nstruct\n \nos_task\n 
\ngen_task_str\n;\n\n\nvoid\n\n\ngen_task\n(\nvoid\n \n*arg\n)\n{\n    
\nwhile\n (\n1\n) {\n        \nos_time_delay\n(\nOS_TICKS_PER_SEC\n \n/\n 
\n4\n);\n        \nos_even
 tq_put\n(\nmy_eventq\n, \ngen_task_ev\n);\n    
}\n}\n\n\nvoid\n\n\ninit_tasks\n(\nvoid\n)\n{\n    \n/* .... */\n\n    
\ngen_task_ev\n.\nev_type\n \n=\n \nMY_TASK_TASK_EVENT\n;\n    
\nos_task_init\n(\ngen_task_str\n, \ngen_task\n, \ngen_task\n, \nNULL\n, 
\nGEN_TASK_PRIO\n,\n        \nOS_WAIT_FOREVER\n, \ngen_task_stack\n, 
\nGEN_TASK_STACK_SZ\n);\n}\n\n\n\n\n\n\n\nCallout events\n\n\nYou can get timer 
events delivered to your task's event queue with OS callout. Check \ncallout 
documentation\n for description on how to use the API.\n\n\nFor this example, 
you'll use only one type of callout; so you can use the simpler 
structure.\n\n\nIn the code snippet we declare the os_callout structure and 
initialize it. Then we arm the timer.\n\n\nstatic\n \nstruct\n \nos_callout\n 
\nmy_callout\n;\n\n\nvoid\n\n\ninit_tasks\n(\nvoid\n)\n{\n    \n/* .... 
*/\n\n\n    \nos_callout_init\n(\nmy_callout\n, \nmy_eventq\n, \nNULL\n);\n    
\nos_callout_reset\n(\nmy_callout\n, \nOS_TICKS_PER_SEC\n);\n}\n\n\n\n
 \n\n\n\nPosting events from interrupt handler\n\n\nAnother place where posting 
events makes sense is from an interrupt handler. In this tutorial you will do 
it when GPIO changes state.\n\n\nYou'll use HAL GPIO interface to register a 
routine which is getting called from the interrupt handler context. This 
routine will then post event to your queue.\n\n\nOn STM32F3Discovery board, 
there is a button connected to PA0. The identifier for this GPIO pin is 
0.\n\n\nstatic\n \nstruct\n \nos_event\n 
\ngpio_ev\n;\n\n\nvoid\n\n\ninit_tasks\n(\nvoid\n)\n{\n    \n/* .... */\n\n\n   
 \ngpio_ev\n.\nev_type\n \n=\n \nMY_TASK_GPIO_EVENT\n;\n    
\nhal_gpio_irq_init\n(\n0\n, \nmy_gpio_irq\n, \nNULL\n, \nGPIO_TRIG_RISING\n,\n 
       \nGPIO_PULL_NONE\n);\n    
\nhal_gpio_irq_enable\n(\n0\n);\n}\n\n\nstatic\n 
\nvoid\n\n\nmy_gpio_irq\n(\nvoid\n \n*arg\n)\n{\n    
\nos_eventq_put\n(\nmy_eventq\n, \ngpio_ev\n);\n}\n\n\n\n\n\n\n\nEvent 
processing finalized\n\n\nNow that you are posting events from different so
 urces, you will fill in the parts in the task main loop to trigger different 
behaviors depending on event type.\n\n\nYou'll drive different LEDs depending 
on what type of event arrived. LEDs on this board are connected to PE8, PE9, 
PE10 and so on. These have GPIO identifiers starting from 72 
onwards.\n\n\n#define TASK_LED        72\n\n\n#define CALLOUT_LED     
73\n\n\n#define GPIO_LED        74\n\n\n\nvoid\n\n\ninit_tasks\n(\nvoid\n)\n{\n 
   \n/* .... */\n\n    \nhal_gpio_init_out\n(\nTASK_LED\n, \n1\n);\n    
\nhal_gpio_init_out\n(\nCALLOUT_LED\n, \n1\n);\n    
\nhal_gpio_init_out\n(\nGPIO_LED\n, \n1\n);\n}\n\n\n\n\n\nAnd here is the new 
main loop for your task. Note that when callout event arrives, we re-arm the 
callout.\n\n\nvoid\n\n\nmy_task\n(\nvoid\n \n*arg\n)\n{\n    \nstruct\n 
\nos_event\n \n*ev\n;\n\n    \nwhile\n (\n1\n) {\n        \nev\n \n=\n 
\nos_eventq_get\n(\nmy_eventq\n);\n        \nswitch\n (\nev-\nev_type\n) {\n    
    \ncase\n \nMY_TASK_TASK_EVENT\n:\n            \n
 hal_gpio_toggle\n(\nTASK_LED\n);\n            \nbreak\n;\n        \ncase\n 
\nOS_EVENT_T_TIMER\n:\n            \nhal_gpio_toggle\n(\nCALLOUT_LED\n);\n      
      \nos_callout_reset\n(\nmy_callout\n, \nOS_TICKS_PER_SEC\n \n/\n \n2\n);\n 
           \nbreak\n;\n        \ncase\n \nMY_TASK_GPIO_EVENT\n:\n            
\nhal_gpio_toggle\n(\nGPIO_LED\n);\n            \nbreak\n;\n        
\ndefault\n:\n\n            \nassert\n(\n0\n);\n        }\n    
}\n}\n\n\n\n\n\n\n\nNow you're done. Once you load this to your board, the task 
LED will blink at an interval of 250ms, the callout LED with an interval of 
500ms, and the GPIO LED every time you press the button.\n\n\n\n\nCode for the 
example\n\n\n#include \nos/os.h\n\n\n#include \nbsp/bsp.h\n\n\n#include 
\nhal/hal_gpio.h\n\n\n#include \nassert.h\n\n\n\n\n#define MY_TASK_PRIO        
4\n\n\n#define MY_TASK_STACK_SZ    512\n\n\n\n#define GEN_TASK_PRIO       
3\n\n\n#define GEN_TASK_STACK_SZ   512\n\n\n\n#define MY_TASK_GPIO_EVENT  
(OS_EVENT_T_PERUSER)
 \n\n\n#define MY_TASK_TASK_EVENT  (OS_EVENT_T_PERUSER + 1)\n\n\n\n#define 
TASK_LED        72\n\n\n#define CALLOUT_LED     73\n\n\n#define GPIO_LED        
74\n\n\n\nstatic\n \nstruct\n \nos_eventq\n \nmy_eventq\n;\n\nstatic\n 
\nos_stack_t\n \nmy_task_stack\n[\nMY_TASK_STACK_SZ\n];\n\nstatic\n \nstruct\n 
\nos_task\n \nmy_task_str\n;\n\n\nstatic\n \nstruct\n \nos_event\n 
\ngen_task_ev\n;\n\nstatic\n \nos_stack_t\n 
\ngen_task_stack\n[\nGEN_TASK_STACK_SZ\n];\n\nstatic\n \nstruct\n \nos_task\n 
\ngen_task_str\n;\n\n\nstatic\n \nstruct\n \nos_callout\n 
\nmy_callout\n;\n\n\nstatic\n \nstruct\n \nos_event\n 
\ngpio_ev\n;\n\n\nvoid\n\n\nmy_task\n(\nvoid\n \n*arg\n)\n{\n    \nstruct\n 
\nos_event\n \n*ev\n;\n\n    \nwhile\n (\n1\n) {\n        \nev\n \n=\n 
\nos_eventq_get\n(\nmy_eventq\n);\n        \nswitch\n (\nev-\nev_type\n) {\n    
    \ncase\n \nMY_TASK_TASK_EVENT\n:\n            
\nhal_gpio_toggle\n(\nTASK_LED\n);\n            \nbreak\n;\n        \ncase\n 
\nOS_EVENT_T_TIMER\n:\n            \nh
 al_gpio_toggle\n(\nCALLOUT_LED\n);\n            
\nos_callout_reset\n(\nmy_callout\n, \nOS_TICKS_PER_SEC\n \n/\n \n2\n);\n       
     \nbreak\n;\n        \ncase\n \nMY_TASK_GPIO_EVENT\n:\n            
\nhal_gpio_toggle\n(\nGPIO_LED\n);\n            \nbreak\n;\n        
\ndefault\n:\n\n            \nassert\n(\n0\n);\n        }\n    
}\n}\n\n\nstatic\n \nvoid\n\n\nmy_gpio_irq\n(\nvoid\n \n*arg\n)\n{\n    
\nos_eventq_put\n(\nmy_eventq\n, 
\ngpio_ev\n);\n}\n\n\nvoid\n\n\ngen_task\n(\nvoid\n \n*arg\n)\n{\n    \nwhile\n 
(\n1\n) {\n        \nos_time_delay\n(\nOS_TICKS_PER_SEC\n \n/\n \n4\n);\n       
 \nos_eventq_put\n(\nmy_eventq\n, \ngen_task_ev\n);\n    
}\n}\n\n\nvoid\n\n\ninit_tasks\n(\nvoid\n)\n{\n    
\nos_eventq_init\n(\nmy_eventq\n);\n    \nos_task_init\n(\nmy_task_str\n, 
\ntask\n, \nmy_task\n, \nNULL\n, \nMY_TASK_PRIO\n,\n        
\nOS_WAIT_FOREVER\n, \nmy_task_stack\n, \nMY_TASK_STACK_SZ\n);\n\n    
\ngen_task_ev\n.\nev_type\n \n=\n \nMY_TASK_TASK_EVENT\n;\n    
\nos_task_init\n(\ngen_task
 _str\n, \ngen_task\n, \ngen_task\n, \nNULL\n, \nGEN_TASK_PRIO\n,\n        
\nOS_WAIT_FOREVER\n, \ngen_task_stack\n, \nGEN_TASK_STACK_SZ\n);\n\n    
\nos_callout_init\n(\nmy_callout\n, \nmy_eventq\n, \nNULL\n);\n    
\nos_callout_reset\n(\nmy_callout\n, \nOS_TICKS_PER_SEC\n);\n\n    
\ngpio_ev\n.\nev_type\n \n=\n \nMY_TASK_GPIO_EVENT\n;\n    
\nhal_gpio_irq_init\n(\n0\n, \nmy_gpio_irq\n, \nNULL\n, \nGPIO_TRIG_RISING\n,\n 
       \nGPIO_PULL_NONE\n);\n    \nhal_gpio_irq_enable\n(\n0\n);\n\n    
\nhal_gpio_init_out\n(\nTASK_LED\n, \n1\n);\n    
\nhal_gpio_init_out\n(\nCALLOUT_LED\n, \n1\n);\n    
\nhal_gpio_init_out\n(\nGPIO_LED\n, \n1\n);\n}\n\n\nint\n\n\nmain\n(\nint\n 
\nargc\n, \nchar\n \n**argv\n)\n{\n    \nos_init\n();\n\n    
\ninit_tasks\n();\n    \nos_start\n();\n    \nassert\n(\n0\n);\n    \nreturn\n 
\n0\n;\n}", 
             "title": "Add task to manage multiple events"
@@ -1966,6 +1916,146 @@
             "title": "Start btmgmt to send commands"
         }, 
         {
+            "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 loo

<TRUNCATED>

Reply via email to