You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by ad...@apache.org on 2016/03/06 20:49:20 UTC

[2/2] incubator-mynewt-site git commit: Added air sensor tutorial. Closes pull request #33.

Added air sensor tutorial. Closes pull request #33.


Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/commit/b71e53e6
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/tree/b71e53e6
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/diff/b71e53e6

Branch: refs/heads/asf-site
Commit: b71e53e68d27b49d5c7609eebea2956ffcb8fe8a
Parents: 2b796b6
Author: aditihilbert <ad...@runtime.io>
Authored: Sun Mar 6 11:49:08 2016 -0800
Committer: aditihilbert <ad...@runtime.io>
Committed: Sun Mar 6 11:49:08 2016 -0800

----------------------------------------------------------------------
 mkdocs/search_index.json                   |   35 +
 os/tutorials/STM32F303/index.html          |    8 +
 os/tutorials/air_quality_sensor/index.html | 1073 +++++++++++++++++++++++
 os/tutorials/arduino_zero/index.html       |    8 +
 os/tutorials/how_to_edit_docs/index.html   |    8 +
 os/tutorials/nRF52/index.html              |    8 +
 os/tutorials/unit_test/index.html          |    8 +
 sitemap.xml                                |   16 +-
 8 files changed, 1156 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/blob/b71e53e6/mkdocs/search_index.json
----------------------------------------------------------------------
diff --git a/mkdocs/search_index.json b/mkdocs/search_index.json
index faf029d..d986559 100644
--- a/mkdocs/search_index.json
+++ b/mkdocs/search_index.json
@@ -326,6 +326,41 @@
             "title": "How to Test an Egg"
         }, 
         {
+            "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 app 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\nLet's say you are using STM32F3discovery board for this project. You know you need the board support package for that hardware. You can look up its location in the repository, fetch the package list from there, and install the egg for the BSP.\n\n\n[user@IsMyLaptop:~/src/air_quality]$ newt app add-pkg-list mynewt_stm32f3 https://github.com/runtimeinc/mynewt_stm32f3.git\nDownloading pkg-list.yml from https://github.com/runtimeinc/mynewt_stm32f3.git/master... ok!\nVerifying pkg-list.yml format...\n ok!\nPackage list mynewt_stm32f3 successfully installed to application.\n[user@IsMyLaptop:~/src/air_quality]$ newt pkg install hw/bsp/stm32f3discovery\nDownloading mynewt_stm32f3 from https://github.com/runtimeinc/mynewt_
 stm32f3.git/master... ok!\nInstalling hw/bsp/stm32f3discovery\nInstalling hw/mcu/stm/stm32f3xx\nError: No package libs/cmsis-core found\n\n\n\n\nOoops. You forgot to bring in the package list for larva itself. That's the one with most of the packages. Including libs/cmsis-core.\n\n\nYou want the latest and greatest from larva, so you want to bring in the 'develop' branch. Note that normally the use of the more stable master branch is recommended. In that case you would drop the '-b develop' from command line.\n\n\nHowever, you want to bring in the packages from develop branch. To make that happen you say:\n\n\n[marko@IsMyLaptop:~/src/air_quality]$ newt app add-pkg-list -b develop larva https://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva.git\nDownloading pkg-list.yml from https://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva.git/develop... ok!\nVerifying pkg-list.yml format...\n ok!\nPackage list larva successfully installed to application.\n[marko@IsMyLaptop:~/sr
 c/air_quality]$ newt pkg install libs/cmsis-core          Downloading larva from https://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/develop... ok!\nInstalling libs/cmsis-core\nInstallation was a success!\n\n\n\n\nThat's better. You want to make sure you have all the needed bits for supporting your board; so you decide to build the blinky project for it first.\n\n\n[marko@IsMyLaptop:~/src/air_quality]$ newt pkg install project/blinky\nDownloading larva from https://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/develop... ok!\nInstalling project/blinky\nInstalling libs/console/full\nInstalling libs/newtmgr\nInstalling libs/json\nInstalling libs/shell\nInstalling sys/config\nInstalling sys/log\nInstalling sys/stats\nInstallation was a success!\n[marko@IsMyLaptop:~/src/air_quality]$ newt pkg install compiler/arm-none-eabi-m4\nDownloading larva from https://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/develop... ok!\nInstalling compiler/arm-none-eabi-m4\nIn
 stallation was a success!\n\n\n\n\nAs you can see, this brought in quite a few other dependencies as well.\n\n\nNow create a target for it and build it.\n\n\n[marko@IsMyLaptop:~/src/air_quality]$ newt target create blink_f3\nCreating target blink_f3\nTarget blink_f3 successfully created!\n[marko@IsMyLaptop:~/src/air_quality]$ newt target set blink_f3 arch=cortex_m4\nTarget blink_f3 successfully set arch to cortex_m4\n[marko@IsMyLaptop:~/src/air_quality]$ newt target set blink_f3 bsp=hw/bsp/stm32f3discovery\nTarget blink_f3 successfully set bsp to hw/bsp/stm32f3discovery\n[marko@IsMyLaptop:~/src/air_quality]$ newt target set blink_f3 compiler=arm-none-eabi-m4\nTarget blink_f3 successfully set compiler to arm-none-eabi-m4\n[marko@IsMyLaptop:~/src/air_quality]$ newt target set blink_f3 compiler_def=debug\nTarget blink_f3 successfully set compiler_def to debug\n[marko@IsMyLaptop:~/src/air_quality]$ newt target set blink_f3 project=blinky\nTarget blink_f3 successfully set project to blin
 ky\n[marko@IsMyLaptop:~/src/air_quality]$ newt target build blink_f3\nBuilding target blink_f3 (project = blinky)\n ...\n[marko@IsMyLaptop:~/src/air_quality]$ newt target build blink_f3\nBuilding target blink_f3 (project = blinky)\nBuilding project blinky\nLinking blinky.elf\n/usr/local/Cellar/gcc-arm-none-eabi-49/20150609/bin/../lib/gcc/arm-none-eabi/4.9.3/../../../../arm-none-eabi/bin/ld: /Users/marko/src/air_quality/project/blinky//bin/blink_f3/blinky.elf section `.text' will not fit in region `FLASH'\n/usr/local/Cellar/gcc-arm-none-eabi-49/20150609/bin/../lib/gcc/arm-none-eabi/4.9.3/../../../../arm-none-eabi/bin/ld: region `FLASH' overflowed by 5180 bytes\ncollect2: error: ld returned 1 exit status\n\n\n\n\nThe error indicates that the images need to be smaller for this board, so you decide to switch over to using baselibc instead of libc.\n\n\nTo do that, you modify the project's egg file project/blinky/pkg.yml. And add \nlibs/baselibc\n to list of package dependencies (pkg.dep
 s).\n\n\nNow:\n\n\n[marko@IsMyLaptop:~/src/air_quality]$ newt target build blink_f3\nBuilding target blink_f3 (project = blinky)\n....\nArchiving libstm32f3discovery.a\nCompiling main.c\nBuilding project blinky\nLinking blinky.elf\nSuccessfully run!\n\n\n\n\nThat's better.\n\n\nYou know that this platform uses bootloader, which means you have to create a target for that too. And download the bootloader package.\n\n\n[marko@IsMyLaptop:~/src/air_quality]$ newt target create boot_f3\nCreating target boot_f3\nTarget boot_f3 successfully created!\n[marko@IsMyLaptop:~/src/air_quality]$ newt target set boot_f3 arch=cortex_m4\nnewTarget boot_f3 successfully set arch to cortex_m4\n[marko@IsMyLaptop:~/src/air_quality]$ newt target set boot_f3 bsp=hw/bsp/stm32f3discovery\nnewtTarget boot_f3 successfully set bsp to hw/bsp/stm32f3discovery\n[marko@IsMyLaptop:~/src/air_quality]$ newt target set boot_f3 compiler=arm-none-eabi-m4\nTarget boot_f3 successfully set compiler to arm-none-eabi-m4\n[marko
 @IsMyLaptop:~/src/air_quality]$ newt target set boot_f3 compiler_def=optimized\nTarget boot_f3 successfully set compiler_def to optimized\n[marko@IsMyLaptop:~/src/air_quality]$ newt target set boot_f3 project=boot\nTarget boot_f3 successfully set project to boot\n[marko@IsMyLaptop:~/src/air_quality]$ newt pkg install project/boot\nDownloading larva from https://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/develop... ok!\nInstalling project/boot\nInstalling fs/nffs\nInstalling fs/fs\nInstalling libs/bootutil\nInstalling libs/mbedtls\nInstalling libs/console/stub\nInstallation was a success!\n\n\n\n\nAnd then build it:\n\n\nnewt target build boot_f3\n....\nLinking boot.elf\nSuccessfully run!\n\n\n\n\nNext you must download the targets to board, and see that the LED actually blinks. You plug in the STM32F3 discovery board to your laptop, and say:\n\n\n[marko@IsMyLaptop:~/src/air_quality]$ newt target download blink_f3\nDownloading with /Users/marko/src/air_quality/hw/bsp/stm3
 2f3discovery/stm32f3discovery_download.sh\nDownloading /Users/marko/src/air_quality/project/blinky/bin/blink_f3/blinky.img to 0x08008000\nOpen On-Chip Debugger 0.9.0 (2015-05-28-12:05)\n...\ntarget state: halted\ntarget halted due to debug-request, current mode: Thread \nxPSR: 0x01000000 pc: 0x0800026c msp: 0x10002000\nauto erase enabled\nError: couldn't open /Users/marko/src/air_quality/project/blinky/bin/blink_f3/blinky.img\n\nError: exit status 1\nexit status 1\n\n\n\n\nAh. Forgot to create an image out of the blinky binary.\n\n\n[marko@IsMyLaptop:~/src/air_quality]$ newt target create-image blink_f3 0.0.1\nBuilding target blink_f3 (project = blinky)\nCompiling hal_flash.c\nArchiving libhal.a\nCompiling cons_tty.c\nArchiving libfull.a\nCompiling hal_uart.c\nArchiving libstm32f3xx.a\nCompiling hal_bsp.c\nArchiving libstm32f3discovery.a\nCompiling main.c\nBuilding project blinky\nLinking blinky.elf\n[marko@IsMyLaptop:~/src/air_quality]$ newt target download blink_f3\nDownloading wi
 th /Users/marko/src/air_quality/hw/bsp/stm32f3discovery/stm32f3discovery_download.sh\n\n\n\n\nAnd it's blinking.\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 myself - you can start by getting project template from blinky, as it pretty much has what you want.\n\n\n[marko@IsMyLaptop:~/src/air_quality]$ mkdir project/air_quality\n[marko@IsMyLaptop:~/src/air_quality]$ cp project/blinky/pkg.yml project/air_quality/\n[marko@IsMyLaptop:~/src/air_quality]$ mkdir project/air_quality/src\n[marko@IsMyLaptop:~/src/air_quality]$ cp project/blinky/src/main.c project/air_quality/src/\n\n\n\n\nThen you modify the pkg.yml for air_quality in order to change the \npkg.name\n to be \nproject/air_quality\n.\n\n\nAnd create a target for it:\n\n\n[marko@IsMyLaptop:~/src/air_quality]$ newt target create air_q\nnewt targCreating target air_q\nTarget air_q successfully created!\n[marko@IsMyLaptop:~/src/air_qu
 ality]$ newt target set air_q arch=cortex_m4\nTarget air_q successfully set arch to cortex_m4\n[marko@IsMyLaptop:~/src/air_quality]$ newt target set air_q bsp=hw/bsp/stm32f3discovery\nTarget air_q successfully set bsp to hw/bsp/stm32f3discovery\n[marko@IsMyLaptop:~/src/air_quality]$ newt target set air_q compiler=arm-none-eabi-m4\nTarget air_q successfully set compiler to arm-none-eabi-m4\n[marko@IsMyLaptop:~/src/air_quality]$ newt target set air_q compiler_def=debug\nTarget air_q successfully set compiler_def to debug\n[marko@IsMyLaptop:~/src/air_quality]$ newt target set air_q project=air_quality\nTarget air_q successfully set project to air_quality\n[marko@IsMyLaptop:~/src/air_quality]$ newt target build air_q\n   ....\nSuccessfully run!\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 my board over 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\nSo you add few files. pkg.yml to describe the driver, and then header stub followed by source stub.\n\n\n[marko@IsMyLaptop:~/src/air_quality]$ cat libs/my_drivers/senseair/pkg.yml\n#\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \nLicense\n); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n# \n#  http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing,\n# software distributed under the License is distributed on an\n# \nAS IS\n BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n# KIND, either express or implied.  See the License for the\n# specific language governing permissions and limitations\n# unde
 r the License.\n#\npkg.name: libs/my_drivers/senseair\npkg.deps:\n    - hw/hal\n\n\n\n\n[marko@IsMyLaptop:~/src/air_quality]$ cat libs/my_drivers/senseair/include/senseair/senseair.h\n/*\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \nLicense\n); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n * \n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \nAS IS\n BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under th
 e License.\n*/\n#ifndef _SENSEAIR_H_\n#define _SENSEAIR_H_\n\nvoid senseair_init(void);\n\n#endif /* _SENSEAIR_H_ */\n\n\n\n\n\n[marko@IsMyLaptop:~/src/air_quality]$ cat libs/my_drivers/senseair/src/senseair.c\n/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \nLicense\n); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n * \n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \nAS IS\n BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions 
 and limitations\n * under the License.\n */\n\nvoid\nsenseair_init(void)\n{\n}\n\n\n\n\nAnd add dependency to this package in my project yml file.\n\n\nHere's from project/air_quality/pkg.yml\n\n\npkg.name: project/air_quality\npkg.vers: 0.8.0\npkg.description: Basic example application which blinks an LED.\npkg.author: Marko Kiiskila \nmarko@runtime.io\n\npkg.homepage: http://mynewt.apache.org/os/get_acclimated/project2/\npkg.repository: https://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva\npkg.keywords:\n\n\npkg.deps:\n    - libs/console/full\n    - libs/newtmgr\n    - libs/os\n    - libs/shell\n    - libs/baselibc\n    - sys/config\n    - sys/log\n    - sys/stats\n    - libs/my_drivers/senseair\n\n\n\n\nAnd add a call to your main() to initialize this driver.\n\n\n[marko@IsMyLaptop:~/src/air_quality]$ diff project/blinky/src/main.c project/air_quality/src/main.c\n28a29\n\n #include \nsenseair/senseair.h\n\n190a192\n\n     senseair_init();\n[marko@IsMyLaptop:~/src/air_qu
 ality\n\n\n\n\nAnd then build it to make sure all goes well.\n\n\n[marko@IsMyLaptop:~/src/air_quality]$ newt target build air_q\nBuilding target air_q (project = air_quality)\nBuilding project air_quality\nSuccessfully run!\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. The way to do this is to register your command handler with shell. Whenever your custom command is issued, you can respond to it.\n\n\nThe way you do this is first adding a dependency to shell package for your senseair driver. So you change libs/my_drivers/senseair/pkg.yml to have the following:\n\n\npkg.name: libs/my_drivers/senseair\npkg.deps:\n    - hw/hal\n    - libs/shell\n\n\n\n\nAnd then register your shell command in \nsenseair_init()\n.\n\n\n[marko@IsMyLaptop:~/src/air_quality]$ cat libs/my_drivers/senseair/src/senseair.c\n ....\n\n#include \nshell/shell.h\n\n#include \nconsole/console.h\n\n
 \nstatic int senseair_shell_func(int argc, char **argv);\nstatic struct shell_cmd senseair_cmd = {\n    .sc_cmd = \nsenseair\n,\n    .sc_cmd_func = senseair_shell_func,\n};\n\nvoid\nsenseair_init(void)\n{\n    int rc;\n\n    rc = shell_cmd_register(\nsenseair_cmd);\n    assert(rc == 0);\n}\n\nstatic int\nsenseair_shell_func(int argc, char **argv)\n{\n    console_printf(\nYay! Somebody called!\\n\n);\n    return 0;\n}\n\n\n\n\nThen you build this, download to target, and start minicom on your console port.\n\n\n[marko@IsMyLaptop:~]$ minicom -D /dev/tty.usbserial-AH02MIE2\n\n\nWelcome to minicom 2.7\n\nOPTIONS: \nCompiled on Oct 12 2015, 07:48:30.\nPort /dev/tty.usbserial-AH02MIE2, 13:44:40\n\nPress CTRL-X Z for help on special keys\n\n?\n141964:Unknown command ?\n?\n143804:config   log     echo    ?       tasks   mempools \n143806:stat     senseair \nsenseair\n150644:Yay! Somebody called!\n\n\n\n\nNow that's great. You can connect the hardware to board and start developing code for t
 he 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/stm32f3discovery, has only one UART set up (as specified in src/hal_bsp.c, include/hal/bsp.h). Therefore, you need to create your own bsp which has configuration for this added hardware.\n\n\nSo in the shell you make a copy of the original BSP, and then change the package file a little.\n\n\n[marko@IsMyLaptop:~/src/air_quality]$ cp -R hw/bsp/stm32f3discovery hw/bsp/stm32f3discovery_with_senseair\n\n\n\n\nThen you modify the pkg.yml in the copied BSP to assign name for this package.\n\n\n[marko@IsMyLaptop:~/src/air_quality]$ grep pkg.name hw/bsp/stm32f3discovery_with_senseair/pkg.yml\npkg.name: \nhw/bsp/stm32f3discovery_with_senseair\n\n\n\n\n\nAnd you want to use this BSP with my target. So you change the BSP in the target definition.\n\n\nHere's your new target.\n\n\n[marko@IsMyLaptop:~/src/air_quality]$ newt target sho
 w air_q                    air_q\n    arch=cortex_m4\n    bsp=hw/bsp/stm32f3discovery_with_senseair\n    compiler=arm-none-eabi-m4\n    compiler_def=debug\n    name=air_q\n    project=air_quality\n    vers=0.0.1\n\n\n\n\nYou add the 2nd serial port to my new BSP.\n\n\nYou modify the include/hal/bsp.h to increase UART_CNT to 2, and add a definition of the 2nd logical UART. You will use this in your sensor driver.\n\n\nstatic const struct stm32f3_uart_cfg uart_cfg[UART_CNT] = {\n    [0] = {\n        .suc_uart = USART1,\n        .suc_rcc_cmd = RCC_APB2PeriphClockCmd,\n        .suc_rcc_dev = RCC_APB2Periph_USART1,\n        .suc_pin_tx = 9,\n        .suc_pin_rx = 10,\n        .suc_pin_rts = 12,\n        .suc_pin_cts = 11,\n        .suc_pin_af = GPIO_AF_7,\n        .suc_irqn = USART1_IRQn\n    },\n    [1] = {\n        .suc_uart = USART2,\n        .suc_rcc_cmd = RCC_APB1PeriphClockCmd,\n        .suc_rcc_dev = RCC_APB1Periph_USART2,\n        .suc_pin_tx = 19, /* PB3 */\n        .suc_pin_rx 
 = 20, /* PB4 */\n        .suc_pin_rts = 1,\n        .suc_pin_cts = 0,\n        .suc_pin_af = GPIO_AF_7,\n        .suc_irqn = USART2_IRQn\n    }\n};\n\n\n\n\nWith this in place, you can refer to serial port where your SenseAir sensor is 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 stub you created earlier.\n\n\n/*\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \nLicense
 \n); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n * \n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \nAS IS\n BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n*/\n#ifndef _SENSEAIR_H_\n#define _SENSEAIR_H_\n\nenum senseair_read_type {\n        SENSEAIR_CO2,\n        SENSEAIR_TEMPERATURE,\n        SENSEAIR_HUMIDITY\n};\n\nint senseair_init(int uartno);\n\nint senseair_read(enum senseair_read_type);\n\n#endif /* _SENSEAIR_H_ */\n\n\n\n\nAs you can see, logical UART number has been added to the init routine. A 'read' function has been added, which 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 * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \nLicense\n); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \nAS IS\n BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n */\n#include \nstring.h\n\n\n#include \nshell/shell.h\n\n#include \nconsole/console.h\n\n#include 
 \nos/os.h\n\n\n#include \nhal/hal_uart.h\n\n\n#include \nsenseair/senseair.h\n\n\nstatic const uint8_t cmd_read_co2[] = {\n    0xFE, 0X44, 0X00, 0X08, 0X02, 0X9F, 0X25\n};\nstatic const uint8_t cmd_read_temp[] = {\n    0xFE, 0X44, 0X00, 0X12, 0X02, 0X94, 0X45\n};\nstatic const uint8_t cmd_read_humidity[] = {\n    0xFE, 0x44, 0x00, 0x14, 0x02, 0x97, 0xE5\n};\n\nstatic int senseair_shell_func(int argc, char **argv);\nstatic struct shell_cmd senseair_cmd = {\n    .sc_cmd = \nsenseair\n,\n    .sc_cmd_func = senseair_shell_func,\n};\n\nstruct 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]; /* XXX what's the max? */\n    int rx_off;\n    int value;\n} senseair;\n\nstatic int\nsenseair_tx_char(void *arg)\n{\n    struct senseair *s = \nsenseair;\n    int rc;\n\n    if (s-\ntx_off \n= s-\ntx_len) {\n        /*\n         * Command tx finished.\n         */\n        s-\ntx_data = NULL;\n        return -
 1;\n    }\n\n    rc = s-\ntx_data[s-\ntx_off];\n    s-\ntx_off++;\n    return rc;\n}\n\n/*\n * CRC for modbus over serial port.\n */\nstatic 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};\n\nstatic uint16_t\nmb_crc(const uint8_t *data, int len, uint16_t crc)\n{\n    while (len-- \n 0) {\n        crc ^= *data++;\n        crc = (crc \n 4) ^ mb_crc_tbl[crc \n 0xf];\n        crc = (crc \n 4) ^ mb_crc_tbl[crc \n 0xf];\n    }\n    return crc;\n}\n\nstatic int\nmb_crc_check(const void *pkt, int len)\n{\n    uint16_t crc, cmp;\n    uint8_t *bp = (uint8_t *)pkt;\n\n    if (len \n sizeof(crc) + 1) {\n        return -1;\n    }\n    crc = mb_crc(pkt, len - 2, 0xffff);\n    cmp = bp[len - 2] | (bp[len - 1] \n 8);\n    if (crc != cmp) {\n        return -1;\n    } else {\n        return 0;\n    }\n}\n\nstatic int\nsenseair_rx_char(void *arg, uint8_t data)\n{\n    struct sen
 seair *s = (struct senseair *)arg;\n    int rc;\n\n    if (s-\nrx_off \n= sizeof(s-\nrx_data)) {\n        s-\nrx_off = 0;\n    }\n    s-\nrx_data[s-\nrx_off] = data;\n    s-\nrx_off++;\n\n    if (s-\nrx_off == 7) {\n        rc = mb_crc_check(s-\nrx_data, s-\nrx_off);\n        if (rc == 0) {\n            s-\nvalue = s-\nrx_data[3] * 256 + s-\nrx_data[4];\n            os_sem_release(\ns-\nsema);\n        }\n    }\n    return 0;\n}\n\nvoid\nsenseair_tx(struct senseair *s, const uint8_t *tx_data, int data_len)\n{\n    s-\ntx_data = tx_data;\n    s-\ntx_len = data_len;\n    s-\ntx_off = 0;\n    s-\nrx_off = 0;\n\n    hal_uart_start_tx(s-\nuart);\n}\n\nint\nsenseair_read(enum senseair_read_type type)\n{\n    struct senseair *s = \nsenseair;\n    const uint8_t *cmd;\n    int cmd_len;\n    int rc;\n\n    if (s-\ntx_data) {\n        /*\n         * busy\n         */\n        return -1;\n    }\n    switch (type) {\n    case SENSEAIR_CO2:\n        cmd = cmd_read_co2;\n        cmd_len = sizeof(c
 md_read_co2);\n        break;\n    case SENSEAIR_TEMPERATURE:\n        cmd = cmd_read_temp;\n        cmd_len = sizeof(cmd_read_temp);\n        break;\n    case SENSEAIR_HUMIDITY:\n        cmd = cmd_read_humidity;\n        cmd_len = sizeof(cmd_read_humidity);\n        break;\n    default:\n        return -1;\n    }\n    senseair_tx(s, cmd, cmd_len);\n    rc = os_sem_pend(\ns-\nsema, OS_TICKS_PER_SEC / 2);\n    if (rc == OS_TIMEOUT) {\n        /*\n         * timeout\n         */\n        return -2;\n    }\n    return s-\nvalue;\n}\n\nstatic int\nsenseair_shell_func(int argc, char **argv)\n{\n    int value;\n    enum senseair_read_type type;\n\n    if (argc \n 2) {\nusage:\n        console_printf(\n%s \nco2|temp|humidity\n\\n\n, argv[0]);\n        return 0;\n    }\n    if (!strcmp(argv[1], \nco2\n)) {\n        type = SENSEAIR_CO2;\n    } else if (!strcmp(argv[1], \ntemp\n)) {\n        type = SENSEAIR_TEMPERATURE;\n    } else if (!strcmp(argv[1], \nhumidity\n)) {\n        /*\n         *
  timeout\n         */\n        return -2;\n    }\n    return s-\nvalue;\n}\n\nstatic int\nsenseair_shell_func(int argc, char **argv)\n{\n    int value;\n    enum senseair_read_type type;\n\n    if (argc \n 2) {\nusage:\n        console_printf(\n%s \nco2|temp|humidity\n\\n\n, argv[0]);\n        return 0;\n    }\n    if (!strcmp(argv[1], \nco2\n)) {\n        type = SENSEAIR_CO2;\n    } else if (!strcmp(argv[1], \ntemp\n)) {\n        type = SENSEAIR_TEMPERATURE;\n    } else if (!strcmp(argv[1], \nhumidity\n)) {\n        type = SENSEAIR_HUMIDITY;\n    } else {\n        goto usage;\n    }\n    value = senseair_read(type);\n    if (value \n= 0) {\n        console_printf(\nGot %d\\n\n, value);\n    } else {\n        console_printf(\nError while reading: %d\\n\n, value);\n    }\n    return 0;\n}\n\nint\nsenseair_init(int uartno)\n{\n    int rc;\n    struct senseair *s = \nsenseair;\n\n    rc = shell_cmd_register(\nsenseair_cmd);\n    if (rc) {\n        return rc;\n    }\n\n    rc = os_sem_i
 nit(\ns-\nsema, 1);\n    if (rc) {\n        return rc;\n    }\n    rc = hal_uart_init_cbs(uartno, senseair_tx_char, NULL,\n      senseair_rx_char, \nsenseair);\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-\nuart = uartno;\n\n    return 0;\n}\n\n\n\n\nAnd you modified your main() for senseair driver init.\n\n\nint\nmain(int argc, char **argv)\n{\n    ....\n    senseair_init(1);\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 semaphore as a way of blocking the task when waiting for read response to come back from the sensor.", 
+            "title": "Adding an 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 app 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 STM32F3discovery board for this project. You know you need the board support package for that hardware. You can look up its location in the repository, fetch the package list from there, and install the egg for the BSP.  [user@IsMyLaptop:~/src/air_quality]$ newt app add-pkg-list mynewt_stm32f3 https://github.com/runtimeinc/mynewt_stm32f3.git\nDownloading pkg-list.yml from https://github.com/runtimeinc/mynewt_stm32f3.git/master... ok!\nVerifying pkg-list.yml format...\n ok!\nPackage list mynewt_stm32f3 successfully installed to application.\n[user@IsMyLaptop:~/src/air_quality]$ newt pkg install hw/bsp/stm32f3discovery\nDownloading mynewt_stm32f3 from https://github.com/runtimeinc/mynewt_stm32f3.git/master... ok!\nInstalling hw/bsp/stm32f3discovery\nInstalling hw/mcu/stm/stm32f3xx\
 nError: No package libs/cmsis-core found  Ooops. You forgot to bring in the package list for larva itself. That's the one with most of the packages. Including libs/cmsis-core.  You want the latest and greatest from larva, so you want to bring in the 'develop' branch. Note that normally the use of the more stable master branch is recommended. In that case you would drop the '-b develop' from command line.  However, you want to bring in the packages from develop branch. To make that happen you say:  [marko@IsMyLaptop:~/src/air_quality]$ newt app add-pkg-list -b develop larva https://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva.git\nDownloading pkg-list.yml from https://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva.git/develop... ok!\nVerifying pkg-list.yml format...\n ok!\nPackage list larva successfully installed to application.\n[marko@IsMyLaptop:~/src/air_quality]$ newt pkg install libs/cmsis-core          Downloading larva from https://git-wip-us.apache.org/repo
 s/asf/incubator-mynewt-larva/develop... ok!\nInstalling libs/cmsis-core\nInstallation was a success!  That's better. You want to make sure you have all the needed bits for supporting your board; so you decide to build the blinky project for it first.  [marko@IsMyLaptop:~/src/air_quality]$ newt pkg install project/blinky\nDownloading larva from https://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/develop... ok!\nInstalling project/blinky\nInstalling libs/console/full\nInstalling libs/newtmgr\nInstalling libs/json\nInstalling libs/shell\nInstalling sys/config\nInstalling sys/log\nInstalling sys/stats\nInstallation was a success!\n[marko@IsMyLaptop:~/src/air_quality]$ newt pkg install compiler/arm-none-eabi-m4\nDownloading larva from https://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/develop... ok!\nInstalling compiler/arm-none-eabi-m4\nInstallation was a success!  As you can see, this brought in quite a few other dependencies as well.  Now create a target for it 
 and build it.  [marko@IsMyLaptop:~/src/air_quality]$ newt target create blink_f3\nCreating target blink_f3\nTarget blink_f3 successfully created!\n[marko@IsMyLaptop:~/src/air_quality]$ newt target set blink_f3 arch=cortex_m4\nTarget blink_f3 successfully set arch to cortex_m4\n[marko@IsMyLaptop:~/src/air_quality]$ newt target set blink_f3 bsp=hw/bsp/stm32f3discovery\nTarget blink_f3 successfully set bsp to hw/bsp/stm32f3discovery\n[marko@IsMyLaptop:~/src/air_quality]$ newt target set blink_f3 compiler=arm-none-eabi-m4\nTarget blink_f3 successfully set compiler to arm-none-eabi-m4\n[marko@IsMyLaptop:~/src/air_quality]$ newt target set blink_f3 compiler_def=debug\nTarget blink_f3 successfully set compiler_def to debug\n[marko@IsMyLaptop:~/src/air_quality]$ newt target set blink_f3 project=blinky\nTarget blink_f3 successfully set project to blinky\n[marko@IsMyLaptop:~/src/air_quality]$ newt target build blink_f3\nBuilding target blink_f3 (project = blinky)\n ...\n[marko@IsMyLaptop:~/sr
 c/air_quality]$ newt target build blink_f3\nBuilding target blink_f3 (project = blinky)\nBuilding project blinky\nLinking blinky.elf\n/usr/local/Cellar/gcc-arm-none-eabi-49/20150609/bin/../lib/gcc/arm-none-eabi/4.9.3/../../../../arm-none-eabi/bin/ld: /Users/marko/src/air_quality/project/blinky//bin/blink_f3/blinky.elf section `.text' will not fit in region `FLASH'\n/usr/local/Cellar/gcc-arm-none-eabi-49/20150609/bin/../lib/gcc/arm-none-eabi/4.9.3/../../../../arm-none-eabi/bin/ld: region `FLASH' overflowed by 5180 bytes\ncollect2: error: ld returned 1 exit status  The error indicates that the images need to be smaller for this board, so you decide to switch over to using baselibc instead of libc.  To do that, you modify the project's egg file project/blinky/pkg.yml. And add  libs/baselibc  to list of package dependencies (pkg.deps).  Now:  [marko@IsMyLaptop:~/src/air_quality]$ newt target build blink_f3\nBuilding target blink_f3 (project = blinky)\n....\nArchiving libstm32f3discovery
 .a\nCompiling main.c\nBuilding project blinky\nLinking blinky.elf\nSuccessfully run!  That's better.  You know that this platform uses bootloader, which means you have to create a target for that too. And download the bootloader package.  [marko@IsMyLaptop:~/src/air_quality]$ newt target create boot_f3\nCreating target boot_f3\nTarget boot_f3 successfully created!\n[marko@IsMyLaptop:~/src/air_quality]$ newt target set boot_f3 arch=cortex_m4\nnewTarget boot_f3 successfully set arch to cortex_m4\n[marko@IsMyLaptop:~/src/air_quality]$ newt target set boot_f3 bsp=hw/bsp/stm32f3discovery\nnewtTarget boot_f3 successfully set bsp to hw/bsp/stm32f3discovery\n[marko@IsMyLaptop:~/src/air_quality]$ newt target set boot_f3 compiler=arm-none-eabi-m4\nTarget boot_f3 successfully set compiler to arm-none-eabi-m4\n[marko@IsMyLaptop:~/src/air_quality]$ newt target set boot_f3 compiler_def=optimized\nTarget boot_f3 successfully set compiler_def to optimized\n[marko@IsMyLaptop:~/src/air_quality]$ newt
  target set boot_f3 project=boot\nTarget boot_f3 successfully set project to boot\n[marko@IsMyLaptop:~/src/air_quality]$ newt pkg install project/boot\nDownloading larva from https://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/develop... ok!\nInstalling project/boot\nInstalling fs/nffs\nInstalling fs/fs\nInstalling libs/bootutil\nInstalling libs/mbedtls\nInstalling libs/console/stub\nInstallation was a success!  And then build it:  newt target build boot_f3\n....\nLinking boot.elf\nSuccessfully run!  Next you must download the targets to board, and see that the LED actually blinks. You plug in the STM32F3 discovery board to your laptop, and say:  [marko@IsMyLaptop:~/src/air_quality]$ newt target download blink_f3\nDownloading with /Users/marko/src/air_quality/hw/bsp/stm32f3discovery/stm32f3discovery_download.sh\nDownloading /Users/marko/src/air_quality/project/blinky/bin/blink_f3/blinky.img to 0x08008000\nOpen On-Chip Debugger 0.9.0 (2015-05-28-12:05)\n...\ntarget state: 
 halted\ntarget halted due to debug-request, current mode: Thread \nxPSR: 0x01000000 pc: 0x0800026c msp: 0x10002000\nauto erase enabled\nError: couldn't open /Users/marko/src/air_quality/project/blinky/bin/blink_f3/blinky.img\n\nError: exit status 1\nexit status 1  Ah. Forgot to create an image out of the blinky binary.  [marko@IsMyLaptop:~/src/air_quality]$ newt target create-image blink_f3 0.0.1\nBuilding target blink_f3 (project = blinky)\nCompiling hal_flash.c\nArchiving libhal.a\nCompiling cons_tty.c\nArchiving libfull.a\nCompiling hal_uart.c\nArchiving libstm32f3xx.a\nCompiling hal_bsp.c\nArchiving libstm32f3discovery.a\nCompiling main.c\nBuilding project blinky\nLinking blinky.elf\n[marko@IsMyLaptop:~/src/air_quality]$ newt target download blink_f3\nDownloading with /Users/marko/src/air_quality/hw/bsp/stm32f3discovery/stm32f3discovery_download.sh  And it's blinking.", 
+            "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 myself - you can start by getting project template from blinky, as it pretty much has what you want.  [marko@IsMyLaptop:~/src/air_quality]$ mkdir project/air_quality\n[marko@IsMyLaptop:~/src/air_quality]$ cp project/blinky/pkg.yml project/air_quality/\n[marko@IsMyLaptop:~/src/air_quality]$ mkdir project/air_quality/src\n[marko@IsMyLaptop:~/src/air_quality]$ cp project/blinky/src/main.c project/air_quality/src/  Then you modify the pkg.yml for air_quality in order to change the  pkg.name  to be  project/air_quality .  And create a target for it:  [marko@IsMyLaptop:~/src/air_quality]$ newt target create air_q\nnewt targCreating target air_q\nTarget air_q successfully created!\n[marko@IsMyLaptop:~/src/air_quality]$ newt target set air_q arch=cortex_m4\nTarget air_q successfully set arch to cortex_m4\n[marko@IsMyLaptop:~/src/air_quality]$ newt target s
 et air_q bsp=hw/bsp/stm32f3discovery\nTarget air_q successfully set bsp to hw/bsp/stm32f3discovery\n[marko@IsMyLaptop:~/src/air_quality]$ newt target set air_q compiler=arm-none-eabi-m4\nTarget air_q successfully set compiler to arm-none-eabi-m4\n[marko@IsMyLaptop:~/src/air_quality]$ newt target set air_q compiler_def=debug\nTarget air_q successfully set compiler_def to debug\n[marko@IsMyLaptop:~/src/air_quality]$ newt target set air_q project=air_quality\nTarget air_q successfully set project to air_quality\n[marko@IsMyLaptop:~/src/air_quality]$ newt target build air_q\n   ....\nSuccessfully run!", 
+            "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 my board over serial port.\nTo start development of the driver, you first need to create a package description for it, and add stubs for sources.  So you add few files. pkg.yml to describe the driver, and then header stub followed by source stub.  [marko@IsMyLaptop:~/src/air_quality]$ cat libs/my_drivers/senseair/pkg.yml\n#\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n#  License ); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n# \n#  http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing,\n# software distributed under the L
 icense is distributed on an\n#  AS IS  BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n# KIND, either express or implied.  See the License for the\n# specific language governing permissions and limitations\n# under the License.\n#\npkg.name: libs/my_drivers/senseair\npkg.deps:\n    - hw/hal  [marko@IsMyLaptop:~/src/air_quality]$ cat libs/my_drivers/senseair/include/senseair/senseair.h\n/*\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n *  License ); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n * \n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distribute
 d on an\n *  AS IS  BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n*/\n#ifndef _SENSEAIR_H_\n#define _SENSEAIR_H_\n\nvoid senseair_init(void);\n\n#endif /* _SENSEAIR_H_ */  [marko@IsMyLaptop:~/src/air_quality]$ cat libs/my_drivers/senseair/src/senseair.c\n/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n *  License ); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n * \n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License
  is distributed on an\n *  AS IS  BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n */\n\nvoid\nsenseair_init(void)\n{\n}  And add dependency to this package in my project yml file.  Here's from project/air_quality/pkg.yml  pkg.name: project/air_quality\npkg.vers: 0.8.0\npkg.description: Basic example application which blinks an LED.\npkg.author: Marko Kiiskila  marko@runtime.io \npkg.homepage: http://mynewt.apache.org/os/get_acclimated/project2/\npkg.repository: https://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva\npkg.keywords:\n\n\npkg.deps:\n    - libs/console/full\n    - libs/newtmgr\n    - libs/os\n    - libs/shell\n    - libs/baselibc\n    - sys/config\n    - sys/log\n    - sys/stats\n    - libs/my_drivers/senseair  And add a call to your main() to initialize this driver.  [marko@IsMyLaptop:~/src/air_quality]$ diff project/b
 linky/src/main.c project/air_quality/src/main.c\n28a29  #include  senseair/senseair.h \n190a192      senseair_init();\n[marko@IsMyLaptop:~/src/air_quality  And then build it to make sure all goes well.  [marko@IsMyLaptop:~/src/air_quality]$ newt target build air_q\nBuilding target air_q (project = air_quality)\nBuilding project air_quality\nSuccessfully run!  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. The way to do this is to register your command handler with shell. Whenever your custom command is issued, you can respond to it.  The way you do this is first adding a dependency to shell package for your senseair driver. So you change libs/my_drivers/senseair/pkg.yml to have the following:  pkg.name: libs/my_drivers/senseair\npkg.deps:\n    - hw/hal\n    - libs/shell  And then register your shell command in  senseair_init() .  [marko@IsMyLaptop:~/src/air_quality]$ cat libs/my_drivers/senseair/src/senseair.c\n ....\n\n#include  shell/shell.h \n#include  console/console.h \n\nstatic int senseair_shell_func(int argc, char **argv);\nstatic struct shell_cmd senseair_cmd = {\n    .sc_cmd =  senseair ,\n    .sc_cmd_func = senseair_shell_func,\n};\n\nvoid\nsenseair_init(void)\n{\n    int rc;\n\n    rc = shell_cmd_register( senseair_cmd);\n    assert(rc == 0);\n}\n\nstatic int
 \nsenseair_shell_func(int argc, char **argv)\n{\n    console_printf( Yay! Somebody called!\\n );\n    return 0;\n}  Then you build this, download to target, and start minicom on your console port.  [marko@IsMyLaptop:~]$ minicom -D /dev/tty.usbserial-AH02MIE2\n\n\nWelcome to minicom 2.7\n\nOPTIONS: \nCompiled on Oct 12 2015, 07:48:30.\nPort /dev/tty.usbserial-AH02MIE2, 13:44:40\n\nPress CTRL-X Z for help on special keys\n\n?\n141964:Unknown command ?\n?\n143804:config   log     echo    ?       tasks   mempools \n143806:stat     senseair \nsenseair\n150644:Yay! Somebody called!  Now that's great. You can connect the hardware to 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/stm32f3discovery, has only one UART set up (as specified in src/hal_bsp.c, include/hal/bsp.h). Therefore, you need to create your own bsp which has configuration for this added hardware.  So in the shell you make a copy of the original BSP, and then change the package file a little.  [marko@IsMyLaptop:~/src/air_quality]$ cp -R hw/bsp/stm32f3discovery hw/bsp/stm32f3discovery_with_senseair  Then you modify the pkg.yml in the copied BSP to assign name for this package.  [marko@IsMyLaptop:~/src/air_quality]$ grep pkg.name hw/bsp/stm32f3discovery_with_senseair/pkg.yml\npkg.name:  hw/bsp/stm32f3discovery_with_senseair   And you want to use this BSP with my target. So you change the BSP in the target definition.  Here's your new target.  [marko@IsMyLaptop:~/src/air_quality]$ newt target show air_q                    air_q\n    arch=cortex_m4\n    bsp=hw/bsp
 /stm32f3discovery_with_senseair\n    compiler=arm-none-eabi-m4\n    compiler_def=debug\n    name=air_q\n    project=air_quality\n    vers=0.0.1  You add the 2nd serial port to my new BSP.  You modify the include/hal/bsp.h to increase UART_CNT to 2, and add a definition of the 2nd logical UART. You will use this in your sensor driver.  static const struct stm32f3_uart_cfg uart_cfg[UART_CNT] = {\n    [0] = {\n        .suc_uart = USART1,\n        .suc_rcc_cmd = RCC_APB2PeriphClockCmd,\n        .suc_rcc_dev = RCC_APB2Periph_USART1,\n        .suc_pin_tx = 9,\n        .suc_pin_rx = 10,\n        .suc_pin_rts = 12,\n        .suc_pin_cts = 11,\n        .suc_pin_af = GPIO_AF_7,\n        .suc_irqn = USART1_IRQn\n    },\n    [1] = {\n        .suc_uart = USART2,\n        .suc_rcc_cmd = RCC_APB1PeriphClockCmd,\n        .suc_rcc_dev = RCC_APB1Periph_USART2,\n        .suc_pin_tx = 19, /* PB3 */\n        .suc_pin_rx = 20, /* PB4 */\n        .suc_pin_rts = 1,\n        .suc_pin_cts = 0,\n        .suc_
 pin_af = GPIO_AF_7,\n        .suc_irqn = USART2_IRQn\n    }\n};  With this in place, you can refer to serial port where your SenseAir sensor is 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 will now see what the driver code ends up looking like. Here's the header file, filled in from stub you created earlier.  /*\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n *  License ); you may not use this file except in compliance\n * with the License.  You may obtain a copy of th
 e License at\n * \n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n *  AS IS  BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n*/\n#ifndef _SENSEAIR_H_\n#define _SENSEAIR_H_\n\nenum senseair_read_type {\n        SENSEAIR_CO2,\n        SENSEAIR_TEMPERATURE,\n        SENSEAIR_HUMIDITY\n};\n\nint senseair_init(int uartno);\n\nint senseair_read(enum senseair_read_type);\n\n#endif /* _SENSEAIR_H_ */  As you can see, logical UART number has been added to the init routine. A 'read' function has been added, which 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.  /**\n * Licensed to the Apache Software Foundat
 ion (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n *  License ); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n *  AS IS  BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n */\n#include  string.h \n\n#include  shell/shell.h \n#include  console/console.h \n#include  os/os.h \n\n#include  hal/hal_uart.h \n\n#include  senseair/senseair.h \n\nstatic const uint8_t cmd_read_co2[] = {\n    0xFE, 0X4
 4, 0X00, 0X08, 0X02, 0X9F, 0X25\n};\nstatic const uint8_t cmd_read_temp[] = {\n    0xFE, 0X44, 0X00, 0X12, 0X02, 0X94, 0X45\n};\nstatic const uint8_t cmd_read_humidity[] = {\n    0xFE, 0x44, 0x00, 0x14, 0x02, 0x97, 0xE5\n};\n\nstatic int senseair_shell_func(int argc, char **argv);\nstatic struct shell_cmd senseair_cmd = {\n    .sc_cmd =  senseair ,\n    .sc_cmd_func = senseair_shell_func,\n};\n\nstruct 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]; /* XXX what's the max? */\n    int rx_off;\n    int value;\n} senseair;\n\nstatic int\nsenseair_tx_char(void *arg)\n{\n    struct senseair *s =  senseair;\n    int rc;\n\n    if (s- tx_off  = s- tx_len) {\n        /*\n         * Command tx finished.\n         */\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}\n\n/*\n * CRC for modbus over serial port.\n */\nstatic 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};\n\nstatic uint16_t\nmb_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}\n\nstatic int\nmb_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}\n\nstatic int\nsenseair_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}\n\nvoid\nsenseair_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}\n\nint\nsenseair_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        /*\n         * busy\n         */\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    case SENSEAIR_TEMPERATURE:\n        cmd = cmd_read_temp;\n        cmd_len = sizeof(cmd_read_temp);\n        break;\n    case SENSEAIR_HUMIDI
 TY:\n        cmd = cmd_read_humidity;\n        cmd_len = sizeof(cmd_read_humidity);\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        /*\n         * timeout\n         */\n        return -2;\n    }\n    return s- value;\n}\n\nstatic int\nsenseair_shell_func(int argc, char **argv)\n{\n    int value;\n    enum senseair_read_type type;\n\n    if (argc   2) {\nusage:\n        console_printf( %s  co2|temp|humidity \\n , argv[0]);\n        return 0;\n    }\n    if (!strcmp(argv[1],  co2 )) {\n        type = SENSEAIR_CO2;\n    } else if (!strcmp(argv[1],  temp )) {\n        type = SENSEAIR_TEMPERATURE;\n    } else if (!strcmp(argv[1],  humidity )) {\n        /*\n         * timeout\n         */\n        return -2;\n    }\n    return s- value;\n}\n\nstatic int\nsenseair_shell_func(int argc, char **argv)\n{\n    int value;\n    enum senseair_read_type type;\n\n
     if (argc   2) {\nusage:\n        console_printf( %s  co2|temp|humidity \\n , argv[0]);\n        return 0;\n    }\n    if (!strcmp(argv[1],  co2 )) {\n        type = SENSEAIR_CO2;\n    } else if (!strcmp(argv[1],  temp )) {\n        type = SENSEAIR_TEMPERATURE;\n    } else if (!strcmp(argv[1],  humidity )) {\n        type = SENSEAIR_HUMIDITY;\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}\n\nint\nsenseair_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_char,  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 you modified your main() for senseair driver init.  int\nmain(int argc, char **argv)\n{\n    ....\n    senseair_init(1);\n    ....\n}  You can see from the code that you are using the HAL interface to open a UART port, and using OS semaphore as a way of blocking the task when waiting for read response to come back from the sensor.", 
+            "title": "Use of HAL for drivers"
+        }, 
+        {
             "location": "/os/tutorials/how_to_edit_docs/", 
             "text": "How to Edit Docs\n\n\nObjective\n\n\nLearn the process of editing docs by adding some content to a test document.\n\n\nMarkdown, MkDocs, Mou\n\n\nThe Mynewt documentation you see on the Apache incubator website is a bunch of HTML files generated using MkDocs which is a simple static site generation tool geared towards building project documentation. You can read about it at \nhttp://www.mkdocs.org\n. Documentation source files are written in Markdown, and configured with a single YAML configuration file. Markdown is a lightweight markup language with plain text formatting syntax designed so that it can be converted to HTML and many other formats using a tool (which in our case is MkDocs).\n\n\nYou do not need to install MkDocs unless you want to actually render your documentation in HTML in order to preview it before pushing your content to the remote repository. Typically, using a Markdown editor such as \nMou\n is enough to check how it will look after the doc
 ument has gone through MkDocs. Go ahead and download \nMou\n. If you are on a Windows machine, download the \neditor of your choice\n.\n\n\nCurrently someone in the project is designated to use MkDocs to generate the HTML pages periodically after changes have been reviewed and accepted into the master branch.\n\n\nAccess to the Apache repo\n\n\nGet an account on Apache. You do not need a committer account to view the website or clone the repository but you need it to push changes to it.\n\n\nIf you are not a committer, you may follow the proposed non-committer workflow to share your work. The direct link to the proposed workflow is \nhttps://git-wip-us.apache.org/docs/workflow.html\n. You will find the steps described in more detail later in this tutorial.\n\n\nMaking a local copy\n\n\n\n\nCopy the document source files into a local directory and look at the contents of the copied directory to get an idea of the directory structure. Use http instead of https if you are a non-committ
 er.\n\n\n\n\n        $ git clone https://git-wip-us.apache.org/repos/asf/incubator-mynewt-site.git\n        Cloning into 'incubator-mynewt-site'...\n        remote: Counting objects: 330, done.\n        remote: Compressing objects: 100% (263/263), done.\n        remote: Total 330 (delta 120), reused 0 (delta 0)\n        Receiving objects: 100% (330/330), 4.34 MiB | 830.00 KiB/s, done.\n        Resolving deltas: 100% (120/120), done.\n        Checking connectivity... done.\n        $ ls\n        incubator-mynewt-site\n        $ ls incubator-mynewt-site/\n        docs        images      mkdocs.yml\n\n\n\n\n\n\nCreate a new branch to work on your documentation and move to that branch.\n\n\n\n\n        $ git checkout -b \nyour-branch-name\n\n\n\n\n\nFile to be edited\n\n\nThe file you will edit is named try_markdown.md. It is in the incubator-mynewt-site/docs/os/tutorials/ directory.\n\n\nEditing an existing page\n\n\n\n\n\n\nOpen the application Mou.\n\n\n\n\n\n\nOpen the file incubato
 r-mynewt-site/docs/os/tutorials/try_markdown.md in Mou.\n\n\n\n\n\n\nEdit the last item on the list.\n\n\n\n\n\n\nSave and quit the application.\n\n\n\n\n\n\nAdding a new page\n\n\nIf you create a new file somewhere in the \ndocs\n subdirectory to add a new page, you have to add a line in the \nmkdocs.yml\n file at the correct level. For example, if you add a new module named \"Ethernet\" by creating a new file named \nethernet.md\n in the \nmodules\n subdirectory, you have to insert the following line under \nModules:\n in the \nmkdocs.yml\n file.\n\n\n        - 'Ethernet': 'modules/ethernet.md'\n\n\n\n\nPushing changes to remote as a committer\n\n\nIf you are not a committer yet, skip this section and proceed to the \nnext section\n.\n\n\n\n\nCheck whether your remote git repository is set up. If you see the remote location as shown below you can skip the next step.\n\n\n\n\n        $ git remote -v\n        origin  https://git-wip-us.apache.org/repos/asf/incubator-mynewt-site.git 
 (fetch)\n        origin  https://git-wip-us.apache.org/repos/asf/incubator-mynewt-site.git (push)\n\n\n\n\n\n\nIf, however, you do not see your remote repository, then set it up as follows.\n\n\n\n\n        $ git remote add origin https://git-wip-us.apache.org/repos/asf/incubator-mynewt-site.git \n\n\n\n\n\n\nFirst check the git status. It will show you that the \ntry_markdown.md\n document has been modified. So you will stage a commit, and then commit the change. Finally, you will push the changes to the remote repository. \n\n\n\n\nDuring staging below using \ngit add\n, we use the \n-A\n option indicating you want to stage all your modifications. Instead, you can choose to specify only the files that you want to. The commit message (specified after \n-m\n) should summarize what your changes are about.\n\n\n        $ git status\n        $ git add -A \n        $ git commit -m \nMy first doc change as a trial run\n\n        $ git push -u origin \nyour-branch-name\n\n\n\n\n\n\n\n\n\n
 You can see the changed Markdown file if you traverse the tree on the git repository \n https://git-wip-us.apache.org/repos/asf/incubator-mynewt-site.git\n.\n\n\n\n\n\n\nA commit notification automatically goes out to the commits@mynewt.incubator.apache.org mailing list. The \"upstream\" manager pulls the notified changes, reviews it, and merges it to the master branch if all is well. Otherwise you get an email for further changes.\n\n\n\n\n\n\nSharing changes as a non-committer\n\n\nWe suggest you follow the proposed non-committer workflow at Apache to share your work. The direct link to the proposed workflow is \nhttps://git-wip-us.apache.org/docs/workflow.html\n. \n\n\n\n\nAssuming you have made changes to the example file, you will first commit your changes.\n\n\n\n\n        $ git add -A \n        $ git commit -m \nMy first doc change as a trial run\n\n\n\n\n\n\n\nOnce you're ready to share your changes with the rest of the project team, you can use the git format-patch command 
 to produce a patch file (or a nice set of patches in the future) and email the patch file to dev@mynewt.incubator.apache.org. Later on you may attach multiple files in your email to the mailing list as part of an existing thread or a new one. Remember to summarize the issue you have tackled and your work if the commit message is not detailed enough.\n\n\n\n\nIf there is a JIRA ticket associated with your work you should post your patch files to the ticket.\n\n\n        $ git format-patch origin/trunk\n\n\n\n\n\n\nAlternatively, you can use the mirror on github.com to submit a pull request. The mirror is located at \nhttps://github.com/apache/incubator-mynewt-site\n. It is up to you to decide whether to create a fork or a branch to work in and submit pull requests from. Remember you cannot push changes to the master on the github mirror, so you have to create a fork or a branch first. Your pull request will be reviewed by a committer for docs and merged into the master branch when th
 e changes are understood and accepted. \n\n\n\n\nConversion to HTML\n\n\nThe conversion of the Markdown files to HTML for the website happens manually and statically using MkDocs. You cannot see automatic and immediate rendering in HTML upon making a change in the Markdown file. You can choose to stop here and proceed to changing other Markdown files in your branch.\n\n\nLocal preview of HTML files\n\n\nHowever, you have the option to download MkDocs and do a local conversion yourself to preview the pages using the built-in devserver that comes with MkDocs. But first you will have to install MkDocs for that. In order to install MkDocs you'll need Python installed on your system, as well as the Python package manager, pip. You can check if you have them already (usually you will).\n\n\n        $ python --version\n        Python 2.7.2\n        $ pip --version\n        pip 1.5.2\n        $ pip install mkdocs\n\n\n\n\nYou will then run the built-in webserver from the root of the documen
 tation directory using the command \nmkdocs serve\n. The root directory for documentation is \nincubator-mynewt-site\n or the directory with the \nmkdocs.yml\n file.\n\n\n        $ ls\n        docs        images      mkdocs.yml\n        $ mkdocs serve\n\n\n\n\nThen go to \nhttp://127.0.0.1:8000\n to preview your pages and see how they will look on the website! Remember that the Myself website itself will not be updated.\n\n\nFor more information on MkDocs go to \nhttp://www.mkdocs.org\n.", 
             "title": "Edit Docs"

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/blob/b71e53e6/os/tutorials/STM32F303/index.html
----------------------------------------------------------------------
diff --git a/os/tutorials/STM32F303/index.html b/os/tutorials/STM32F303/index.html
index 296ff34..6f04a7d 100644
--- a/os/tutorials/STM32F303/index.html
+++ b/os/tutorials/STM32F303/index.html
@@ -185,6 +185,14 @@
               
   
     <li>
+      <a href="../air_quality_sensor/">Adding an air-quality sensor</a>
+    </li>
+  
+
+          
+              
+  
+    <li>
       <a href="../how_to_edit_docs/">Edit Docs</a>
     </li>