blob: d461d3cb4e4b420315de5696433b77616bdb01b8 [file] [log] [blame]
Air quality sensor project
--------------------------
Setting up source tree for stuff you need
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To start with, you need to create a new project under which you will do
this development. So you type in:
.. code-block:: console
$ mkdir $HOME/src
$ cd $HOME/src
$ newt new air_quality
Let's say you are using Arduino Primo -- which is based on the Nordic
Semi NRF52 chip -- as the platform. You know you need the board support
package for that hardware. You can look up its location, add it your
project, and fetch that along with the core OS components. Luckily, the
Arduino Primo is supported in the Mynewt Core, so there's nothing much
to do here.
Your project.yml file should look like this:
.. code-block:: console
[user@IsMyLaptop:~/src/air_quality]$ emacs project.yml &
[user@IsMyLaptop:~/src/air_quality]$ cat project.yml
project.name: "air_quality"
project.repositories:
- apache-mynewt-core
# Use github's distribution mechanism for core ASF libraries.
# This provides mirroring automatically for us.
#
repository.apache-mynewt-core:
type: github
vers: 0-latest
user: apache
repo: mynewt-core
[user@IsMyLaptop:~/src/air_quality]$ newt install
apache-mynewt-core
[user@IsMyLaptop:~/src/air_quality]$ ls repos/
apache-mynewt-core
Good. You want to make sure you have all the needed bits for supporting
your board; so 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.
.. code-block:: console
[user@IsMyLaptop:~/src/air_quality]$ newt target copy my_blinky_sim blink_primo
Target successfully copied; targets/my_blinky_sim --> targets/blink_primo
[user@IsMyLaptop:~/src/air_quality]$ newt target set blink_primo bsp=@apache-mynewt-core/hw/bsp/arduino_primo_nrf52
Target targets/blink_nrf successfully set target.bsp to @apache-mynewt-core/hw/bsp/arduino_primo_nrf52
[user@IsMyLaptop:~/src/air_quality]$ newt build blink_primo
Compiling hal_bsp.c
...
Linking blinky.elf
App 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.
.. code-block:: console
[user@IsMyLaptop:~/src/air_quality]$ newt target create boot_primo
Target targets/boot_nrf successfully created
[user@IsMyLaptop:~/src/air_quality]$ newt target show
@apache-mynewt-core/targets/unittest
bsp=hw/bsp/native
build_profile=debug
compiler=compiler/sim
targets/blink_primo
app=apps/blinky
bsp=@apache-mynewt-core/hw/bsp/arduino_primo_nrf52
build_profile=debug
targets/boot_primo
targets/my_blinky_sim
app=apps/blinky
bsp=@apache-mynewt-core/hw/bsp/native
build_profile=debug
[user@IsMyLaptop:~/src/air_quality]$ newt target set boot_nrf bsp=@apache-mynewt-core/hw/bsp/arduino_primo_nrf52
Target targets/boot_nrf successfully set target.bsp to @apache-mynewt-core/hw/bsp/arduino_primo_nrf52
[user@IsMyLaptop:~/src/air_quality]$ newt target set boot_nrf app=@apache-mynewt-core/apps/boot
Target targets/boot_nrf successfully set target.app to @apache-mynewt-core/apps/boot
[user@IsMyLaptop:~/src/air_quality]$ newt target set boot_nrf build_profile=optimized
Target targets/boot_nrf successfully set target.build_profile to optimized
And then build it, and load it onto the board.
.. code-block:: console
newt build boot_primo
....
Linking boot.elf
App successfully built: /Users/user/src/air_quality/bin/boot_primo/apps/boot/boot.elf
[user@IsMyLaptop:~/src/air_quality]
$ 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 your board, not being able to load the
image, etc. If that's the case, and you haven't already, you should most
definitely go worth through the :doc:`blinky_primo <../blinky/blinky_primo>`
tutorial so that you can properly communicate with your board.
Next you must download the targets to board, and see that the LED
actually blinks. You plug in the Arduino Primo board to your laptop, and
say:
.. code-block:: console
[user@IsMyLaptop:~/src/air_quality]$ newt load blink_primo
Loading app image into slot 1
Error: couldn't open /Users/user/src/air_quality/bin/blink_primo/apps/blinky/blinky.img
Error: exit status 1
load - Load app image to target for <target-name>.
Usage:
newt load [flags]
Examples:
newt load <target-name>
Global Flags:
-l, --loglevel string Log level, defaults to WARN. (default "WARN")
-o, --outfile string Filename to tee log output to
-q, --quiet Be quiet; only display error output.
-s, --silent Be silent; don't output anything.
-v, --verbose Enable verbose output when executing commands.
exit status 1
Ah. Forgot to create an image out of the blinky binary. Note that every
time you want to build and load a new firmware image to a target board,
you need to run 'create-image' on it.
.. code-block:: console
[user@IsMyLaptop:~/src/air_quality]$ newt create-image blink_primo 0.0.1
App image successfully generated: /Users/user/src/air_quality/bin/blink_primo/apps/blinky/blinky.img
Build manifest: /Users/user/src/air_quality/bin/blink_nrf/apps/blinky/manifest.json
[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 out the usage from command line help.
Create test project
~~~~~~~~~~~~~~~~~~~
Now that you have your system setup, you can start creating your own
stuff. First you want to create a project for yourself - you could start
by using blinky as a project template, but since we're going to want to
be able to access the data via Bluetooth, let's use the ``bleprph``
Bluetooth Peripheral project instead.
.. code-block:: console
[user@IsMyLaptop:~/src/air_quality]$ mkdir apps/air_quality
[user@IsMyLaptop:~/src/air_quality]$ cp repos/apache-mynewt-core/apps/bleprph/pkg.yml apps/air_quality/
[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*. You'll need to add
the ``@apache-mynewt-core/`` path to all the package dependencies, since
the app no longer resides within the apache-mynewt-core repository.
.. code-block:: console
[user@IsMyLaptop:~/src/air_quality]$ cat apps/air_quality/pkg.yml
pkg.name: apps/air_quality
pkg.type: app
pkg.description: BLE Air Quality application.
pkg.author: "Apache Mynewt <dev@mynewt.apache.org>"
pkg.homepage: "http://mynewt.apache.org/"
pkg.keywords:
pkg.deps:
- "@apache-mynewt-core/kernel/os"
- "@apache-mynewt-core/sys/shell"
- "@apache-mynewt-core/sys/stats/full"
- "@apache-mynewt-core/sys/log/full"
- "@apache-mynewt-core/mgmt/newtmgr"
- "@apache-mynewt-core/mgmt/newtmgr/transport/ble"
- "@apache-mynewt-core/net/nimble/controller"
- "@apache-mynewt-core/net/nimble/host"
- "@apache-mynewt-core/net/nimble/host/services/ans"
- "@apache-mynewt-core/net/nimble/host/services/gap"
- "@apache-mynewt-core/net/nimble/host/services/gatt"
- "@apache-mynewt-core/net/nimble/host/store/ram"
- "@apache-mynewt-core/net/nimble/transport/ram"
- "@apache-mynewt-core/sys/console/full"
- "@apache-mynewt-core/sys/sysinit"
- "@apache-mynewt-core/sys/id"
And create a target for it:
.. code-block:: console
[user@IsMyLaptop:~/src/air_quality]$ newt target create air_q
Target targets/air_q successfully created
[user@IsMyLaptop:~/src/air_quality]$ newt target set air_q bsp=@apache-mynewt-core/hw/bsp/arduino_primo_nrf52
Target targets/air_q successfully set target.bsp to @apache-mynewt-core/hw/bsp/arduino_primo_nrf52
[user@IsMyLaptop:~/src/air_quality]$ newt target set air_q app=apps/air_quality
Target targets/air_q successfully set target.app to apps/air_quality
[user@IsMyLaptop:~/src/air_quality]$ newt target set air_q build_profile=debug
Target targets/air_q successfully set target.build_profile to debug
[user@IsMyLaptop:~/src/air_quality]$ newt build air_q
....
Linking /Users/dsimmons/dev/myproj/bin/targets/air_q/app/apps/air_quality/air_quality.elf
Target successfully built: targets/air_q
Create packages for drivers
~~~~~~~~~~~~~~~~~~~~~~~~~~~
One of the sensors you want to enable is SenseAir K30, which will
connect to the board over a serial port. To start development of the
driver, you first need to create a package description for it, and add
stubs for sources.
The first thing to do is to create the directory structure for your
driver:
.. code-block:: console
[user@IsMyLaptop:~/src/air_quality]$ mkdir -p libs/my_drivers/senseair/include/senseair
[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.
.. code-block:: console
[user@IsMyLaptop:~/src/air_quality]$ cat libs/my_drivers/senseair/pkg.yml
.. code-block:: c
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, 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 <dev@mynewt.apache.org>"
pkg.homepage: "http://mynewt.apache.org/"
pkg.keywords:
- ble
- bluetooth
pkg.deps:
- "@apache-mynewt-core/kernel/os"
.. code-block:: console
[user@IsMyLaptop:~/src/air_quality]$ cat libs/my_drivers/senseair/include/senseair/senseair.h
.. code-block:: c
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, 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_ */
.. code-block:: console
[user@IsMyLaptop:~/src/air_quality]$ cat libs/my_drivers/senseair/src/senseair.c
.. code-block:: c
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, 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)
{
}
And add dependency to this package in your project yml file.
Here's the listing from apps/air\_quality/pkg.yml
.. code-block:: console
pkg.name: apps/air_quality
pkg.type: app
pkg.description: Air quality sensor test
pkg.keywords:
pkg.deps:
- "@apache-mynewt-core/libs/console/full"
- "@apache-mynewt-core/libs/newtmgr"
- "@apache-mynewt-core/libs/os"
- "@apache-mynewt-core/libs/shell"
- "@apache-mynewt-core/sys/config"
- "@apache-mynewt-core/sys/log/full"
- "@apache-mynewt-core/sys/stats/full"
- libs/my_drivers/senseair
And add a call to your main() to initialize this driver.
.. code-block:: console
[user@IsMyLaptop:~/src/air_quality]$ diff project/blinky/src/main.c project/air_quality/src/main.c
28a29
> #include <senseair/senseair.h>
190a192
> senseair_init();
[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 task handler to respond to the shell, and
then handle communicating with the senseair sensor for us.
.. code-block:: c
/** 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 use this task as our default task handler.
.. code-block:: c
/**
* Event loop for the main shell task.
*/
static void
shell_task_handler(void *unused)
{
while (1) {
os_eventq_run(&shell_evq);
}
}
And in your ``main()`` add:
.. code-block:: c
/* Initialize shell eventq */
os_eventq_init(&shell_evq);
/* Create the shell task.
* All shell operations are performed in this task.
*/
os_task_init(&shell_task, "shell", shell_task_handler,
NULL, SHELL_TASK_PRIO, OS_WAIT_FOREVER,
shell_stack, SHELL_STACK_SIZE);
Don't forget to change your default task handler!
.. code-block:: c
os_eventq_dflt_set(&shell_evq);
And then build it to make sure all goes well.
.. code-block:: console
[user@IsMyLaptop:~/src/air_quality]$ newt build air_q
Compiling senseair.c
Archiving senseair.a
Linking air_quality.elf
App successfully built: /Users/user/src/air_quality/bin/air_q/apps/air_quality/air_quality.elf
All looks good.
Add CLI commands for testing drivers
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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 on how to :doc:`enable the CLI <../blinky/blinky_console>`, so all
we'll need to do is add the propper values to the project's
``syscfg.yml`` file:
.. code-block:: console
[user@IsMyLaptop:~/src/air_quality]$ cat targets/air_q/syscfg.yml
syscfg.vals:
# Set as per blinky_primo
OPENOCD_DEBUG: 1
# Enable the shell task.
SHELL_TASK: 1
STATS_CLI: 1
CONSOLE_TICKS: 1
CONSOLE_PROMPT: 1
Then register your senseair command with the shell by adding the
following to ``libs/my_drivers/senseair/src/senseair.c``
.. code-block:: 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 = {
.sc_cmd = "senseair",
.sc_cmd_func = senseair_shell_func,
};
void
senseair_init(void)
{
int rc;
rc = shell_cmd_register(&senseair_cmd);
assert(rc == 0);
}
static int
senseair_shell_func(int argc, char **argv)
{
console_printf("Yay! Somebody called!\n");
return 0;
}
Now you can you build this, download to target, and start minicom on
your console port. If you haven't already, familiarize yourself with the
tutorial on how to connect a serial port to your board
:doc:`here <../../get_started/serial_access>`.
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.
.. code-block:: console
[user@IsMyLaptop:~]$ minicom -D /dev/tty.usbserial-AH02MIE2
Welcome to minicom 2.7
OPTIONS:
Compiled on Oct 12 2015, 07:48:30.
Port /dev/tty.usbserial-AH02MIE2, 13:44:40
Press CTRL-X Z for help on special keys
?
419: > ?
Commands:
641: stat echo ? prompt ticks tasks
643: mempools date senseair
644: > senseair
Yay! Somebody called!
1125: >
53611: > tasks
Tasks:
54047: task pri tid runtime csw stksz stkuse lcheck ncheck flg
54057: idle 255 0 54048 66890 64 30 0 0 0
54068: ble_ll 0 1 9 64986 80 58 0 0 0
54079: bleprph 1 2 0 1 336 32 0 0 0
54090: shell 2 3 0 2077 336 262 0 0 0
54101: >
That's great. Your shell task is running, and is responding
appropriately! You can connect the hardware to your board and start
developing code for the driver itself.
Use of HAL for drivers
~~~~~~~~~~~~~~~~~~~~~~
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. We'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 communicate 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 for this second
UART. Those changes are as follows:
.. code-block:: console
UART_0_PIN_TX: 23
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 will now see what the driver code ends up looking like. Here's the
header file, filled in from the stub you created earlier.
.. code-block:: c
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef _SENSEAIR_H_
#define _SENSEAIR_H_
enum senseair_read_type {
SENSEAIR_CO2,
};
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, 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.
.. code-block:: c
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, 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.
*/
#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[] = {
0xFE, 0X44, 0X00, 0X08, 0X02, 0X9F, 0X25
};
static int senseair_shell_func(int argc, char **argv);
static struct shell_cmd senseair_cmd = {
.sc_cmd = "senseair",
.sc_cmd_func = senseair_shell_func,
};
struct senseair {
int uart;
struct os_sem sema;
const uint8_t *tx_data;
int tx_off;
int tx_len;
uint8_t rx_data[32];
int rx_off;
int value;
} senseair;
static int
senseair_tx_char(void *arg)
{
struct senseair *s = &senseair;
int rc;
if (s->tx_off >= s->tx_len) {
/*
* Command tx finished.
*/
s->tx_data = NULL;
return -1;
}
rc = s->tx_data[s->tx_off];
s->tx_off++;
return rc;
}
/*
* CRC for modbus over serial port.
*/
static const uint16_t mb_crc_tbl[] = {
0x0000, 0xcc01, 0xd801, 0x1400, 0xf001, 0x3c00, 0x2800, 0xe401,
0xa001, 0x6c00, 0x7800, 0xb401, 0x5000, 0x9c01, 0x8801, 0x4400
};
static uint16_t
mb_crc(const uint8_t *data, int len, uint16_t crc)
{
while (len-- > 0) {
crc ^= *data++;
crc = (crc >> 4) ^ mb_crc_tbl[crc & 0xf];
crc = (crc >> 4) ^ mb_crc_tbl[crc & 0xf];
}
return crc;
}
static int
mb_crc_check(const void *pkt, int len)
{
uint16_t crc, cmp;
uint8_t *bp = (uint8_t *)pkt;
if (len < sizeof(crc) + 1) {
return -1;
}
crc = mb_crc(pkt, len - 2, 0xffff);
cmp = bp[len - 2] | (bp[len - 1] << 8);
if (crc != cmp) {
return -1;
} else {
return 0;
}
}
static int
senseair_rx_char(void *arg, uint8_t data)
{
struct senseair *s = (struct senseair *)arg;
int rc;
if (s->rx_off >= sizeof(s->rx_data)) {
s->rx_off = 0;
}
s->rx_data[s->rx_off] = data;
s->rx_off++;
if (s->rx_off == 7) {
rc = mb_crc_check(s->rx_data, s->rx_off);
if (rc == 0) {
s->value = s->rx_data[3] * 256 + s->rx_data[4];
os_sem_release(&s->sema);
}
}
return 0;
}
void
senseair_tx(struct senseair *s, const uint8_t *tx_data, int data_len)
{
s->tx_data = tx_data;
s->tx_len = data_len;
s->tx_off = 0;
s->rx_off = 0;
hal_uart_start_tx(s->uart);
}
int
senseair_read(enum senseair_read_type type)
{
struct senseair *s = &senseair;
const uint8_t *cmd;
int cmd_len;
int rc;
if (s->tx_data) {
/*
* busy
*/
return -1;
}
switch (type) {
case SENSEAIR_CO2:
cmd = cmd_read_co2;
cmd_len = sizeof(cmd_read_co2);
break;
default:
return -1;
}
senseair_tx(s, cmd, cmd_len);
rc = os_sem_pend(&s->sema, OS_TICKS_PER_SEC / 2);
if (rc == OS_TIMEOUT) {
/*
* timeout
*/
return -2;
}
return s->value;
}
static int
senseair_shell_func(int argc, char **argv)
{
int value;
enum senseair_read_type type;
if (argc < 2) {
usage:
console_printf("%s co2\n", argv[0]);
return 0;
}
if (!strcmp(argv[1], "co2")) {
type = SENSEAIR_CO2;
} else {
goto usage;
}
value = senseair_read(type);
if (value >= 0) {
console_printf("Got %d\n", value);
} else {
console_printf("Error while reading: %d\n", value);
}
return 0;
}
int
senseair_init(int uartno)
{
int rc;
struct senseair *s = &senseair;
rc = shell_cmd_register(&senseair_cmd);
if (rc) {
return rc;
}
rc = os_sem_init(&s->sema, 1);
if (rc) {
return rc;
}
rc = hal_uart_init_cbs(uartno, senseair_tx_char, NULL,
senseair_rx_char, &senseair);
if (rc) {
return rc;
}
rc = hal_uart_config(uartno, 9600, 8, 1, HAL_UART_PARITY_NONE,
HAL_UART_FLOW_CTL_NONE);
if (rc) {
return rc;
}
s->uart = uartno;
return 0;
}
And your modified main() for senseair driver init.
.. code-block:: c
int
main(int argc, char **argv)
{
....
senseair_init(0);
....
}
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.
Now comes the fun part: Hooking up the sensor! It's fun because a)
hooking up a sensor is always fun and b) the SenseAir sensor's PCB is
entirely unlabeled, so you'll have to trust us on how to hook it up.
So here we go.
You'll have to do a little soldering. I soldered some header pins to the
SenseAir K30 board to make connecting wires easier using standard jumper
wires, but you can also just solder wires straight to the board if you
prefer.
Here's what your SenseAir board should look like once it's wired up:
.. figure:: ../pics/Senseair1.png
:alt: SenseAir Wiring
SenseAir Wiring
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:
.. figure:: ../pics/Senseair2.png
:alt: SenseAir and Arduino Primo Wiring
SenseAir and Arduino Primo Wiring
Everything is wired and you're ready to go! Build and load your new app:
.. code-block:: console
$ newt build air_q
Building target targets/air_q
Compiling apps/air_quality/src/main.c
Archiving apps_air_quality.a
Linking myproj/bin/targets/air_q/app/apps/air_quality/air_quality.elf
Target successfully built: targets/air_q
$ newt create-image air_q 1.0.0
App image succesfully generated: myproj/bin/targets/air_q/app/apps/air_quality/air_quality.img
$ newt load air_q
Loading app image into slot 1
Now, you should be able to connect to your serial port and read values:
.. code-block:: console
user@IsMyLaptop:~]$ minicom -D /dev/tty.usbserial-AH02MIE2
Welcome to minicom 2.7
OPTIONS:
Compiled on Oct 12 2015, 07:48:30.
Port /dev/tty.usbserial-AH02MIE2, 13:44:40
Press CTRL-X Z for help on special keys
1185: > ?
Commands:
1382: stat echo ? prompt ticks tasks
1390: mempools date senseair
1395: > senseair
senseair co2
2143: > senseair co2
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.