From 21297e80d415907ee4ae97311f6d10a5dfcedcad Mon Sep 17 00:00:00 2001 From: Jon Trulson Date: Mon, 29 Aug 2016 17:42:54 -0600 Subject: [PATCH] hka5: Initial implementation This module implements support for the DFRobot Laser PM2.5 Sensor. It connects to a UART at 9600 baud. This is the only baud rate supported. It optionally supports Reset and Set/Sleep gpios as well. Signed-off-by: Jon Trulson --- examples/c++/CMakeLists.txt | 1 + examples/c++/hka5.cxx | 86 +++++++++++ examples/c/CMakeLists.txt | 1 + examples/c/hka5.c | 78 ++++++++++ examples/java/CMakeLists.txt | 1 + examples/java/HKA5_Example.java | 59 ++++++++ examples/javascript/hka5.js | 63 ++++++++ examples/python/hka5.py | 62 ++++++++ src/hka5/CMakeLists.txt | 9 ++ src/hka5/hka5.c | 257 ++++++++++++++++++++++++++++++++ src/hka5/hka5.cxx | 80 ++++++++++ src/hka5/hka5.h | 143 ++++++++++++++++++ src/hka5/hka5.hpp | 134 +++++++++++++++++ src/hka5/hka5_fti.c | 67 +++++++++ src/hka5/javaupm_hka5.i | 21 +++ src/hka5/jsupm_hka5.i | 8 + src/hka5/pyupm_hka5.i | 12 ++ 17 files changed, 1082 insertions(+) create mode 100644 examples/c++/hka5.cxx create mode 100644 examples/c/hka5.c create mode 100644 examples/java/HKA5_Example.java create mode 100644 examples/javascript/hka5.js create mode 100644 examples/python/hka5.py create mode 100644 src/hka5/CMakeLists.txt create mode 100644 src/hka5/hka5.c create mode 100644 src/hka5/hka5.cxx create mode 100644 src/hka5/hka5.h create mode 100644 src/hka5/hka5.hpp create mode 100644 src/hka5/hka5_fti.c create mode 100644 src/hka5/javaupm_hka5.i create mode 100644 src/hka5/jsupm_hka5.i create mode 100644 src/hka5/pyupm_hka5.i diff --git a/examples/c++/CMakeLists.txt b/examples/c++/CMakeLists.txt index 6a3444eb..bf7387eb 100644 --- a/examples/c++/CMakeLists.txt +++ b/examples/c++/CMakeLists.txt @@ -276,6 +276,7 @@ add_example (ms5611) add_example (nmea_gps) add_example (mma7361) add_example (bh1750) +add_example (hka5) # These are special cases where you specify example binary, source file and module(s) include_directories (${PROJECT_SOURCE_DIR}/src) diff --git a/examples/c++/hka5.cxx b/examples/c++/hka5.cxx new file mode 100644 index 00000000..f01fe738 --- /dev/null +++ b/examples/c++/hka5.cxx @@ -0,0 +1,86 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2016 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include + +#include "hka5.hpp" + +using namespace std; + +bool shouldRun = true; + +void sig_handler(int signo) +{ + if (signo == SIGINT) + shouldRun = false; +} + +int main() +{ + signal(SIGINT, sig_handler); + +//! [Interesting] + + // Instantiate a HKA5 sensor on uart 0. We don't use the set or + // reset pins, so we pass -1 for them. + upm::HKA5 *sensor = new upm::HKA5(0, -1, -1); + + // update once every 2 seconds and output data + while (shouldRun) + { + sensor->update(); + + cout << "PM 1 : " + << sensor->getPM1() + << " ug/m3" + << endl; + + cout << "PM 2.5: " + << sensor->getPM2_5() + << " ug/m3" + << endl; + + cout << "PM 10 : " + << sensor->getPM10() + << " ug/m3" + << endl; + + cout << endl; + + sleep(2); + } + + if (shouldRun) + cerr << "Timed out" << endl; + +//! [Interesting] + + cout << "Exiting" << endl; + + delete sensor; + + return 0; +} diff --git a/examples/c/CMakeLists.txt b/examples/c/CMakeLists.txt index fde707cf..d4c89c0a 100644 --- a/examples/c/CMakeLists.txt +++ b/examples/c/CMakeLists.txt @@ -92,6 +92,7 @@ add_example (mma7361) add_example (bh1750) add_example (urm37) add_example (urm37-uart) +add_example (hka5) # Custom examples add_custom_example (nmea_gps_i2c-example-c nmea_gps_i2c.c nmea_gps) diff --git a/examples/c/hka5.c b/examples/c/hka5.c new file mode 100644 index 00000000..285ef7a7 --- /dev/null +++ b/examples/c/hka5.c @@ -0,0 +1,78 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2016 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include + +#include "hka5.h" + +bool shouldRun = true; + +void sig_handler(int signo) +{ + if (signo == SIGINT) + shouldRun = false; +} + +int main() +{ + signal(SIGINT, sig_handler); + +//! [Interesting] + + // Instantiate a HKA5 sensor on uart 0. We don't use the set or + // reset pins, so we pass -1 for them. + hka5_context sensor = hka5_init(0, -1, -1); + + if (!sensor) + { + printf("hka5_init() failed.\n"); + return 1; + } + + // update once every 2 seconds and output data + while (shouldRun) + { + if (hka5_update(sensor) != UPM_SUCCESS) + { + printf("hka5_update() failed, exiting.\n"); + shouldRun = false; + } + + printf("PM 1 : %d ug/m3\n", hka5_get_pm1(sensor)); + printf("PM 2.5: %d ug/m3\n", hka5_get_pm2_5(sensor)); + printf("PM 10 : %d ug/m3\n", hka5_get_pm10(sensor)); + printf("\n"); + + sleep(2); + } + +//! [Interesting] + + printf("Exiting\n"); + + hka5_close(sensor); + + return 0; +} diff --git a/examples/java/CMakeLists.txt b/examples/java/CMakeLists.txt index 6444265b..5ed9e8cb 100644 --- a/examples/java/CMakeLists.txt +++ b/examples/java/CMakeLists.txt @@ -133,6 +133,7 @@ add_example(BMX055_Example bmx055) add_example(NMEAGPS_Example nmea_gps) add_example(MMA7361_Example mma7361) add_example(BH1750_Example bh1750) +add_example(HKA5_Example hka5) add_example_with_path(Jhd1313m1_lcdSample lcd i2clcd) add_example_with_path(Jhd1313m1Sample lcd i2clcd) diff --git a/examples/java/HKA5_Example.java b/examples/java/HKA5_Example.java new file mode 100644 index 00000000..e485fa11 --- /dev/null +++ b/examples/java/HKA5_Example.java @@ -0,0 +1,59 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2016 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +import upm_hka5.HKA5; + +public class HKA5_Example +{ + public static void main(String[] args) throws InterruptedException + { +// ! [Interesting] + System.out.println("Initializing..."); + + // Instantiate a HKA5 sensor on uart 0. We don't use the set or + // reset pins, so we pass -1 for them. + HKA5 sensor = new HKA5(0, -1, -1); + + // update once every 2 seconds and output data + while (true) + { + sensor.update(); + + System.out.println("PM 1 : " + + sensor.getPM1() + + " ug/m3"); + System.out.println("PM 2.5: " + + sensor.getPM2_5() + + " ug/m3"); + System.out.println("PM 10 : " + + sensor.getPM10() + + " ug/m3"); + + System.out.println(); + Thread.sleep(2000); + } + +// ! [Interesting] + } +} diff --git a/examples/javascript/hka5.js b/examples/javascript/hka5.js new file mode 100644 index 00000000..b11c895b --- /dev/null +++ b/examples/javascript/hka5.js @@ -0,0 +1,63 @@ +/*jslint node:true, vars:true, bitwise:true, unparam:true */ +/*jshint unused:true */ + +/* + * Author: Jon Trulson + * Copyright (c) 2016 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +var sensorObj = require('jsupm_hka5'); + +// Instantiate a HKA5 sensor on uart 0. We don't use the set or +// reset pins, so we pass -1 for them. +var sensor = new sensorObj.HKA5(0, -1, -1); + +// update once every 2 seconds and output data +setInterval(function() +{ + sensor.update() + + console.log("PM 1 : " + + sensor.getPM1() + + " ug/m3"); + + console.log("PM 2.5: " + + sensor.getPM2_5() + + " ug/m3"); + + console.log("PM 10 : " + + sensor.getPM10() + + " ug/m3"); + + console.log(); + +}, 2000); + +// exit on ^C +process.on('SIGINT', function() +{ + sensor = null; + sensorObj.cleanUp(); + sensorObj = null; + console.log("Exiting."); + process.exit(0); +}); diff --git a/examples/python/hka5.py b/examples/python/hka5.py new file mode 100644 index 00000000..f6ff7cae --- /dev/null +++ b/examples/python/hka5.py @@ -0,0 +1,62 @@ +#!/usr/bin/python +# Author: Jon Trulson +# Copyright (c) 2016 Intel Corporation. +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +import time, sys, signal, atexit +import pyupm_hka5 as sensorObj + +# Instantiate a HKA5 sensor on uart 0. We don't use the set or +# reset pins, so we pass -1 for them. +sensor = sensorObj.HKA5(0, -1, -1) + +## Exit handlers ## +# This function stops python from printing a stacktrace when you hit control-C +def SIGINTHandler(signum, frame): + raise SystemExit + +# This function lets you run code on exit +def exitHandler(): + print "Exiting" + sys.exit(0) + +# Register exit handlers +atexit.register(exitHandler) +signal.signal(signal.SIGINT, SIGINTHandler) + +# update once every 2 seconds and output data +while (True): + sensor.update() + + print "PM 1 :", + print sensor.getPM1(), + print " ug/m3" + + print "PM 2.5:", + print sensor.getPM2_5(), + print " ug/m3" + + print "PM 10 :", + print sensor.getPM10(), + print " ug/m3" + + print + time.sleep(2) diff --git a/src/hka5/CMakeLists.txt b/src/hka5/CMakeLists.txt new file mode 100644 index 00000000..5f769ca8 --- /dev/null +++ b/src/hka5/CMakeLists.txt @@ -0,0 +1,9 @@ +upm_mixed_module_init (NAME hka5 + DESCRIPTION "UPM driver for DFRobot HKA5 PM2.5 particle sensor" + C_HDR hka5.h + C_SRC hka5.c + CPP_HDR hka5.hpp + CPP_SRC hka5.cxx + FTI_SRC hka5_fti.c + CPP_WRAPS_C + REQUIRES mraa) diff --git a/src/hka5/hka5.c b/src/hka5/hka5.c new file mode 100644 index 00000000..0f041705 --- /dev/null +++ b/src/hka5/hka5.c @@ -0,0 +1,257 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2016 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include + +#include "upm_utilities.h" +#include "hka5.h" + +#define HKA5_BAUDRATE 9600 // Only baud supported +#define HKA5_PKT_SIZE 32 +#define HKA5_PKT_START1 0x42 +#define HKA5_PKT_START2 0x4d + +static bool verify_cksum(uint8_t *pkt) +{ + uint16_t pkt_cksum = (pkt[30] << 8) | pkt[31]; + + int i; + uint16_t cksum = 0; + for (i=0; i<(HKA5_PKT_SIZE - 2); i++) + cksum += pkt[i]; + + if (pkt_cksum == cksum) + return true; // all good + else + return false; // :( +} + +hka5_context hka5_init(unsigned int uart, int set_pin, int reset_pin) +{ + hka5_context dev = + (hka5_context)malloc(sizeof(struct _hka5_context)); + + if (!dev) + return NULL; + + // zero out context + memset((void *)dev, 0, sizeof(struct _hka5_context)); + + dev->uart = NULL; + dev->gpio_reset = NULL; + dev->gpio_set = NULL; + + // initialize the MRAA contexts + + // uart, default should be 8N1 + if (!(dev->uart = mraa_uart_init(uart))) + { + printf("%s: mraa_uart_init() failed.\n", __FUNCTION__); + hka5_close(dev); + return NULL; + } + + if (mraa_uart_set_baudrate(dev->uart, HKA5_BAUDRATE)) + { + printf("%s: mraa_uart_set_baudrate(%d) failed.\n", __FUNCTION__, + HKA5_BAUDRATE); + hka5_close(dev); + return NULL; + } + + mraa_uart_set_flowcontrol(dev->uart, false, false); + + // now the set_pin, if enabled + if (set_pin >= 0) + { + if (!(dev->gpio_set = mraa_gpio_init(set_pin))) + { + printf("%s: mraa_gpio_init(set) failed.\n", __FUNCTION__); + hka5_close(dev); + return NULL; + } + + mraa_gpio_dir(dev->gpio_set, MRAA_GPIO_OUT); + + // wake up + hka5_enable(dev, true); + } + + // now the reset_pin, if enabled + if (set_pin >= 0) + { + if (!(dev->gpio_reset = mraa_gpio_init(reset_pin))) + { + printf("%s: mraa_gpio_init(reset) failed.\n", __FUNCTION__); + hka5_close(dev); + return NULL; + } + + mraa_gpio_dir(dev->gpio_reset, MRAA_GPIO_OUT); + + // reset + hka5_reset(dev); + } + return dev; +} + +void hka5_close(hka5_context dev) +{ + assert(dev != NULL); + + // sleep + hka5_enable(dev, false); + + if (dev->uart) + mraa_uart_stop(dev->uart); + if (dev->gpio_set) + mraa_gpio_close(dev->gpio_set); + if (dev->gpio_reset) + mraa_gpio_close(dev->gpio_reset); + + free(dev); +} + +upm_result_t hka5_enable(const hka5_context dev, bool enable) +{ + assert(dev != NULL); + + if (!dev->gpio_set) + return UPM_ERROR_NO_RESOURCES; + + if (enable) + mraa_gpio_write(dev->gpio_set, 1); + else + mraa_gpio_write(dev->gpio_set, 0); + + return UPM_SUCCESS; +} + +upm_result_t hka5_reset(const hka5_context dev) +{ + assert(dev != NULL); + + if (!dev->gpio_reset) + return UPM_ERROR_NO_RESOURCES; + + mraa_gpio_write(dev->gpio_set, 0); + upm_delay(1); + mraa_gpio_write(dev->gpio_set, 1); + upm_delay(1); + +return UPM_SUCCESS; +} + +upm_result_t hka5_update(const hka5_context dev) +{ + assert(dev != NULL); + + uint8_t pkt[HKA5_PKT_SIZE]; + int idx = 0; + bool done = false; + char byte; + + memset((void *)pkt, 0, HKA5_PKT_SIZE); + + while (!done) + { + // wait up to 2 seconds for data and start + if (mraa_uart_data_available(dev->uart, 2000)) + { + while ((mraa_uart_read(dev->uart, &byte, 1) == 1) && + idx < HKA5_PKT_SIZE) + { + // first look for a byte starting with HKA5_PKT_START1 + if (idx == 0 && byte != HKA5_PKT_START1) + continue; + + // look for second byte, make sure it matches + // HKA5_PKT_START1. Start over if it's not found. + if (idx == 1 && byte != HKA5_PKT_START2) + { + // start over + idx = 0; + continue; + } + + // else we found the byte, store it and start reading + // the rest + pkt[idx++] = (uint8_t)byte; + } + + if (idx == HKA5_PKT_SIZE) + { + done = true; + } + else + { + // error + printf("%s: read failed.\n", __FUNCTION__); + return UPM_ERROR_OPERATION_FAILED; + } + } + else + { + printf("%s: read timed out.\n", __FUNCTION__); + return UPM_ERROR_TIMED_OUT; + } + } + + // we have our data + if (verify_cksum(pkt)) + { + dev->pm1 = (pkt[4] << 8) | pkt[5]; + dev->pm2_5 = (pkt[6] << 8) | pkt[7]; + dev->pm10 = (pkt[8] << 8) | pkt[9]; + } + else + { + printf("%s: checksum failure.\n", __FUNCTION__); + // could fail here, but occasional cksum failures are not unusual... + } + + return UPM_SUCCESS; +} + +unsigned int hka5_get_pm1(const hka5_context dev) +{ + assert(dev != NULL); + + return (unsigned int)dev->pm1; +} + +unsigned int hka5_get_pm2_5(const hka5_context dev) +{ + assert(dev != NULL); + + return (unsigned int)dev->pm2_5; +} + +unsigned int hka5_get_pm10(const hka5_context dev) +{ + assert(dev != NULL); + + return (unsigned int)dev->pm10; +} diff --git a/src/hka5/hka5.cxx b/src/hka5/hka5.cxx new file mode 100644 index 00000000..cfcdd91a --- /dev/null +++ b/src/hka5/hka5.cxx @@ -0,0 +1,80 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2016 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include + +#include "hka5.hpp" + +using namespace upm; +using namespace std; + +HKA5::HKA5(unsigned int uart, int set_pin, int reset_pin) : + m_hka5(hka5_init(uart, set_pin, reset_pin)) +{ + if (!m_hka5) + throw std::runtime_error(string(__FUNCTION__) + + ": hka5_init() failed"); +} + +HKA5::~HKA5() +{ + hka5_close(m_hka5); +} + +void HKA5::enable(bool enable) +{ + if (hka5_enable(m_hka5, enable)) + throw std::runtime_error(string(__FUNCTION__) + + ": hka5_enable() failed"); +} + +void HKA5::reset() +{ + if (hka5_reset(m_hka5)) + throw std::runtime_error(string(__FUNCTION__) + + ": hka5_reset() failed"); +} + +void HKA5::update() +{ + if (hka5_update(m_hka5)) + throw std::runtime_error(string(__FUNCTION__) + + ": hka5_update() failed"); +} + +unsigned int HKA5::getPM1() +{ + return hka5_get_pm1(m_hka5); +} + +unsigned int HKA5::getPM2_5() +{ + return hka5_get_pm2_5(m_hka5); +} + +unsigned int HKA5::getPM10() +{ + return hka5_get_pm10(m_hka5); +} diff --git a/src/hka5/hka5.h b/src/hka5/hka5.h new file mode 100644 index 00000000..77fb56db --- /dev/null +++ b/src/hka5/hka5.h @@ -0,0 +1,143 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2016 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#pragma once + +#include +#include "upm.h" +#include "mraa/uart.h" +#include "mraa/gpio.h" + +#ifdef __cplusplus +extern "C" { +#endif + + /** + * @brief UPM C API for the DFRobot Laser PM2.5 Sensor + * + * This driver was tested with a DFRobot Laser PM2.5 Sensor. It + * connects to a UART at 9600 baud. This is the only baud rate + * supported. It optionally supports Reset and Set/Sleep gpios as + * well. + * + * @snippet hka5.c Interesting + */ + + /** + * Device context + */ + typedef struct _hka5_context { + mraa_uart_context uart; + + // these two are optional + mraa_gpio_context gpio_set; + mraa_gpio_context gpio_reset; + + // PM 1.0 + uint16_t pm1; + // PM 2.5 + uint16_t pm2_5; + // PM 10.0 + uint16_t pm10; + } *hka5_context; + + /** + * HKA5 Initializer for generic UART operation + * + * @param uart Specify which uart to use. + * @param set_pin Specify the GPIO pin to use for Set. -1 to not + * use a set pin. + * @param reset_pin Specify the GPIO pin to use for Reset. -1 to + * not use a reset pin. + * @return an initialized device context on success, NULL on error. + */ + hka5_context hka5_init(unsigned int uart, int set_pin, int reset_pin); + + /** + * HKA5 sensor close function + */ + void hka5_close(hka5_context dev); + + /** + * Enable or disable the device. When disabled, the device enters a + * low power mode and does not emit data. You must have initialized + * and connected the Set pin for this function to work. + * + * @param dev sensor context + * @param enable true to enable the device, false otherwise. + * @return UPM result + */ + upm_result_t hka5_enable(const hka5_context dev, bool enable); + + /** + * Reset the device. You must have initialized and connected the + * Reset pin for this function to work. + * + * @param dev sensor context + * @return UPM result + */ + upm_result_t hka5_reset(const hka5_context dev); + + /** + * Query the device and store the latest values. You must call this + * function before calling any of the hka5_get_*() functions. + * + * @param dev sensor context + * @return UPM result + */ + upm_result_t hka5_update(const hka5_context dev); + + /** + * Return the last read PM 1.0 value. The value is in micrograms + * per cubic meter (ug/m3). You must have called the hka5_update() + * function before calling this function. + * + * @param dev sensor context + * @return The value in ug/m3 + */ + unsigned int hka5_get_pm1(const hka5_context dev); + + /** + * Return the last read PM 2.5 value. The value is in micrograms + * per cubic meter (ug/m3). You must have called the hka5_update() + * function before calling this function. + * + * @param dev sensor context + * @return The value in ug/m3 + */ + unsigned int hka5_get_pm2_5(const hka5_context dev); + + /** + * Return the last read PM 10.0 value. The value is in micrograms + * per cubic meter (ug/m3). You must have called the hka5_update() + * function before calling this function. + * + * @param dev sensor context + * @return The value in ug/m3 + */ + unsigned int hka5_get_pm10(const hka5_context dev); + +#ifdef __cplusplus +} +#endif diff --git a/src/hka5/hka5.hpp b/src/hka5/hka5.hpp new file mode 100644 index 00000000..00139cd6 --- /dev/null +++ b/src/hka5/hka5.hpp @@ -0,0 +1,134 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2016 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#pragma once + +#include +#include + +#include +#include + +#include "hka5.h" + +namespace upm { + /** + * @brief UPM C++ API for the DFRobot Laser PM2.5 Sensor + * @defgroup hka5 libupm-hka5 + * @ingroup uart gpio gaseous + */ + + /** + * @library hka5 + * @sensor hka5 + * @comname DFRobot Laser PM2.5 Sensor + * @type gaseous + * @man dfrobot + * @con uart gpio + * + * @brief API for theDFRobot Laser PM2.5 Sensor + * + * This driver was tested with a DFRobot Laser PM2.5 Sensor. It + * connects to a UART at 9600 baud. This is the only baud rate + * supported. It optionally supports Reset and Set/Sleep gpios as + * well. + * + * @snippet hka5.cxx Interesting + */ + + class HKA5 { + public: + + /** + * HKA5 object constructor + * + * @param uart Specify which uart to use. + * @param set_pin Specify the GPIO pin to use for Set. -1 to not + * use a set pin. + * @param reset_pin Specify the GPIO pin to use for Reset. -1 to + * not use a reset pin. + * @return an initialized device context on success, NULL on error. + */ + HKA5(unsigned int uart, int set_pin, int reset_pin); + + /** + * HKA5 object destructor + */ + ~HKA5(); + + /** + * Enable or disable the device. When disabled, the device enters a + * low power mode and does not emit data. You must have initialized + * and connected the Set pin for this function to work. + * + * @param enable true to enable the device, false otherwise. + */ + void enable(bool enable); + + /** + * Reset the device. You must have initialized and connected the + * Reset pin for this function to work. + */ + void reset(); + + /** + * Query the device and store the latest values. You must call this + * function before calling any of the get*() functions. + */ + void update(); + + /** + * Return the last read PM 1.0 value. The value is in micrograms + * per cubic meter (ug/m3). You must have called the update() + * function before calling this function. + * + * @return The value in ug/m3 + */ + unsigned int getPM1(); + + /** + * Return the last read PM 2.5 value. The value is in micrograms + * per cubic meter (ug/m3). You must have called the update() + * function before calling this function. + * + * @return The value in ug/m3 + */ + unsigned int getPM2_5(); + + /** + * Return the last read PM 10.0 value. The value is in micrograms + * per cubic meter (ug/m3). You must have called the update() + * function before calling this function. + * + * @return The value in ug/m3 + */ + unsigned int getPM10(); + + + protected: + // device context + hka5_context m_hka5; + + private: + }; +} diff --git a/src/hka5/hka5_fti.c b/src/hka5/hka5_fti.c new file mode 100644 index 00000000..6349ab52 --- /dev/null +++ b/src/hka5/hka5_fti.c @@ -0,0 +1,67 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2016 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "hka5.h" +#include "upm_fti.h" + +/** + * This file implements the Function Table Interface (FTI) for this sensor + */ + +const char upm_hka5_name[] = "HKA5"; +const char upm_hka5_description[] = "DFRobot Laser PM2.5 Sensor"; +const upm_protocol_t upm_hka5_protocol[] = {UPM_UART, UPM_GPIO, UPM_GPIO}; +const upm_sensor_t upm_hka5_category[] = {}; + +// forward declarations +const void* upm_hka5_get_ft(upm_sensor_t sensor_type); +void* upm_hka5_init_name(); +void upm_hka5_close(void *dev); + +static const upm_sensor_ft ft = +{ + .upm_sensor_init_name = &upm_hka5_init_name, + .upm_sensor_close = &upm_hka5_close, +}; + +const void* upm_hka5_get_ft(upm_sensor_t sensor_type) +{ + switch(sensor_type) + { + case UPM_SENSOR: + return &ft; + default: + return NULL; + } +} + +void* upm_hka5_init_name() +{ + return NULL; +} + +void upm_hka5_close(void *dev) +{ + hka5_close((hka5_context)dev); +} diff --git a/src/hka5/javaupm_hka5.i b/src/hka5/javaupm_hka5.i new file mode 100644 index 00000000..98e9a573 --- /dev/null +++ b/src/hka5/javaupm_hka5.i @@ -0,0 +1,21 @@ +%module javaupm_hka5 +%include "../upm.i" +%include "std_string.i" +%include "stdint.i" +%include "typemaps.i" + +%include "hka5.hpp" +%{ + #include "hka5.hpp" +%} + +%pragma(java) jniclasscode=%{ + static { + try { + System.loadLibrary("javaupm_hka5"); + } catch (UnsatisfiedLinkError e) { + System.err.println("Native code library failed to load. \n" + e); + System.exit(1); + } + } +%} diff --git a/src/hka5/jsupm_hka5.i b/src/hka5/jsupm_hka5.i new file mode 100644 index 00000000..bd37d2f4 --- /dev/null +++ b/src/hka5/jsupm_hka5.i @@ -0,0 +1,8 @@ +%module jsupm_hka5 +%include "../upm.i" +%include "std_string.i" + +%include "hka5.hpp" +%{ + #include "hka5.hpp" +%} diff --git a/src/hka5/pyupm_hka5.i b/src/hka5/pyupm_hka5.i new file mode 100644 index 00000000..9352aaad --- /dev/null +++ b/src/hka5/pyupm_hka5.i @@ -0,0 +1,12 @@ +// Include doxygen-generated documentation +%include "pyupm_doxy2swig.i" +%module pyupm_hka5 +%include "../upm.i" +%include "std_string.i" + +%feature("autodoc", "3"); + +%include "hka5.hpp" +%{ + #include "hka5.hpp" +%}