Skip to content

Sensor driver: PIR-based occupancy sensing#7823

Merged
MichelRottleuthner merged 1 commit intoRIOT-OS:masterfrom
Hyungsin:hamilton-ekmb
Jun 27, 2018
Merged

Sensor driver: PIR-based occupancy sensing#7823
MichelRottleuthner merged 1 commit intoRIOT-OS:masterfrom
Hyungsin:hamilton-ekmb

Conversation

@Hyungsin
Copy link
Copy Markdown

This PR provides a driver for EKMB PIR motion sensor.

The current driver operation is:

  1. When the sensor detects motion, the connected GPIO pin goes high. Otherwise, it goes low.
  2. The current driver supports to detect occupancy in % (how long has the GPIO been high?).
  3. It supports AUTO_INIT and SAUL.

@Hyungsin Hyungsin changed the title EKMB PIR motion sensor driver Sensor driver: EKMB PIR motion sensor driver Oct 24, 2017
@Hyungsin Hyungsin force-pushed the hamilton-ekmb branch 2 times, most recently from e56e524 to b851aa2 Compare October 27, 2017 00:24
@miri64 miri64 added Area: drivers Area: Device drivers Type: new feature The issue requests / The PR implemements a new feature for RIOT labels Oct 28, 2017
@PeterKietzmann
Copy link
Copy Markdown
Member

@Hyungsin pleas rebase. @MichelRottleuthner can you have a look at this PR? I've seen you playing with your PIR motion sensor so often, now please provide a review!

@PeterKietzmann PeterKietzmann requested review from MichelRottleuthner and removed request for haukepetersen November 16, 2017 12:31
@Hyungsin Hyungsin force-pushed the hamilton-ekmb branch 3 times, most recently from bc1877a to 11e8d4f Compare November 16, 2017 23:04
Copy link
Copy Markdown
Contributor

@MichelRottleuthner MichelRottleuthner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for providing this PR.
My thoughts on this: The name of the driver is to specific. There are countless PIR sensors that could be used with this driver - not only EKMB/Panasonic. They all share the same simple concept that a pin changes state when presence/movement was detected. Also, there already is a PIR driver in RIOT: https://github.com/RIOT-OS/RIOT/tree/master/drivers/pir. Your driver indeed adds useful features that the current one lacks (SAUL/occupancy %). What do you think about adding your features to the already existing driver instead providing a new driver?

bool pin_high;
uint64_t pin_rise_time;
uint64_t accum_up_time;
uint64_t last_reset_time;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Global state variables like the ones above must be avoided. Move all data that is needed for a single sensor-instance to the ekmb_t type. This allows the use of the driver for more than one device.

int pin_now = gpio_read(dev->p.gpio);

/* We were busy counting */
if (pin_high) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As written above: don't use global state. The pin state of a triggered sensor should be configurable for each sensor (active high vs. active low)

}
/* Pin is rising */
if (pin_now) {
pin_rise_time = xtimer_usec_from_ticks64(xtimer_now64());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one of the xtimer calls is always executed so the call could always be executed at the beginning of the function. It only depends on the state how you use that value afterwards.


int ekmb_read(ekmb_t *dev, int16_t *occup) {
uint64_t now = xtimer_usec_from_ticks64(xtimer_now64());
*occup = (uint16_t)((accum_up_time * 10000) / (now - last_reset_time));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

now - last_reset_time could evaluate to 0 and thus crash the system if ekmb_read is called fast enough (especially if xtimer only has ms resolution)

* @brief Parameters needed for device initialization
*/
typedef struct {
gpio_t gpio; /**< GPIO pin that sensor is connected to */
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add a param for active-high/low

* @{
*/
typedef struct {
ekmb_params_t p;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move the global stete vars here

* @param[out] dev device descriptor
* @param[in] params GPIO bus the device is connected to
*
* The valid address range is 0x1E - 0x1F depending on the configuration of the
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

copy pasta?

pin_rise_time = 0;
last_reset_time = xtimer_usec_from_ticks64(xtimer_now64());
if (gpio_init_int(params->gpio, GPIO_IN_PD, GPIO_BOTH, ekmb_trigger, dev)) {
return -1;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please use names for return codes

*
* @return 0 on success
* @return -1 on error
* @return -2 on invalid address
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

copy pasta?

*/
int ekmb_init(ekmb_t* dev, const ekmb_params_t* params);

int ekmb_read(ekmb_t* dev, int16_t *light);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

*light?

@Hyungsin
Copy link
Copy Markdown
Author

Hyungsin commented Nov 18, 2017

@MichelRottleuthner, Thank you for your review :)
I first reflected your comments. Please check.

I think adding these features to the existing PIR can be a separate work.
The PIR driver seems like using an additional thread right? That may consume more memory, which I don't like.

@Hyungsin Hyungsin force-pushed the hamilton-ekmb branch 2 times, most recently from 51da148 to 4567661 Compare April 18, 2018 05:12
@Hyungsin Hyungsin changed the title Sensor driver: EKMB PIR motion sensor driver Sensor driver: PIR-based occupancy sensing Apr 18, 2018
@Hyungsin Hyungsin force-pushed the hamilton-ekmb branch 3 times, most recently from cbe2c83 to 8c3ec9a Compare April 18, 2018 05:26
@Hyungsin
Copy link
Copy Markdown
Author

Hyungsin commented Apr 18, 2018

@MichelRottleuthner, @PeterKietzmann, I checked that the PIR driver does not necessarily add another thread, and revised this PR based on the existing PIR driver. I think it is good to be reviewed! :)

@Hyungsin Hyungsin force-pushed the hamilton-ekmb branch 3 times, most recently from 4d690df to aebbfc4 Compare April 18, 2018 22:17
@Hyungsin Hyungsin force-pushed the hamilton-ekmb branch 3 times, most recently from d27221e to 5f32b4b Compare April 20, 2018 00:17
@tcschmidt
Copy link
Copy Markdown
Member

@MichelRottleuthner changes o.k.?

Copy link
Copy Markdown
Contributor

@MichelRottleuthner MichelRottleuthner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for my poor response time here - let's get this done finally :)
Thanks for moving your improvements to the old driver instead of creating another driver. I marked quite a few things that need some cleanup but most of it should be straightforward to apply.

*
* @param[out] dev device descriptor of an PIR sensor
* @param[in] gpio the GPIO device the sensor is connected to
* @param[in] params parameters from the PIR sensor
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

replace from with of?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

* @brief Read OCCUPANCY value
*
* @param[in] dev device descriptor of the PIR motion sensor to read from
* @param[out] occup occupancy radio [in 100 * percentage]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: ratio
Maybe enhance documentation on what this value actually stands for. Also it should be made clear that the value is affected by calling this function (e.g. percentage of occupancy since the last read).

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

* @{
*/
#ifndef PIR_PARAM_GPIO
#define PIR_PARAM_GPIO GPIO_PIN(PA, 6)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please use GPIO_PIN(0, 6) instead to make sure it works on platforms that use other naming schemes

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


#ifndef PIR_PARAMS
#define PIR_PARAMS { .gpio = PIR_PARAM_GPIO, \
.active_high = PIR_PARAM_ACTIVE_HIGH }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

align

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

dev->active = false;
dev->accum_active_time = 0;
dev->start_active_time = 0;
dev->last_read_time = xtimer_usec_from_ticks64(xtimer_now64());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use xtimer_now_usec64 directly here?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

dev->active = true;
/* Pin is falling */
} else {
dev->start_active_time = 0xFFFFFFFFFFFFFFFF;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this marking actuallly needed i.e. isn't the active flag sufficient? After all this callback is only called when the pin level changes, right?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think so too. Thanks!

static saul_reg_t saul_entries[PIR_NUM];

/**
* @brief Reference the occupancy driver struct
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reference to...

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


static char pir_handler_stack[THREAD_STACKSIZE_MAIN];
static pir_t dev;
static const pir_params_t pir_param = {.gpio = PIR_GPIO, .active_high = true};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't define params here. Instead, include pir_params.h to use default parameters defined there. This also enables overwriting the active high parameter by CFLAGS commandline parameter. References to the old PIR_GPIO in the driver_pir's Makefile and main.c should then also be adapted to your newly introduced param defines (PIR_PARAM_GPIO and PIR_PARAM_ACTIVE_HIGH)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

puts("PIR motion sensor test application\n");
printf("Initializing PIR sensor at GPIO_%ld... ", (long)PIR_GPIO);
if (pir_init(&dev, PIR_GPIO) == 0) {
if (pir_init(&dev, &pir_param) == 0) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as stated above, use params from pir_params here (change to &pir_params[0])

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

uint64_t accum_active_time; /**< Accumulated active time */
uint64_t last_read_time; /**< Last time when PIR status is read */
pir_params_t p; /**< Configuration parameters */
} pir_t;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think reordering the struct members could save some memory here due to allignment/padding

Copy link
Copy Markdown
Author

@Hyungsin Hyungsin Jun 19, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@Hyungsin
Copy link
Copy Markdown
Author

Hyungsin commented Jun 19, 2018

@MichelRottleuthner. Thank you!
I reflected your comments. Please go through it!

@Hyungsin Hyungsin force-pushed the hamilton-ekmb branch 3 times, most recently from 7b442ed to 69ed4d7 Compare June 19, 2018 23:27
pir_event_t pir_get_status(const pir_t *dev)
{
return ((gpio_read(dev->p.gpio) == 0) ? PIR_STATUS_LO : PIR_STATUS_HI);
return ((gpio_read(dev->p.gpio) == dev->p.active_high) ?
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

careful: the gpio API returns either 0 or >0. You could change gpio_read(..) to (gpio_read(..) > 0)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@MichelRottleuthner MichelRottleuthner added the CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR label Jun 20, 2018
Copy link
Copy Markdown
Contributor

@MichelRottleuthner MichelRottleuthner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Murdock reports errors regarding bool types on some platforms. Adding #include <stdbool.h> to pir.h should help.

@Hyungsin
Copy link
Copy Markdown
Author

Hyungsin commented Jun 20, 2018

@MichelRottleuthner, resolved again. Thanks!
Good to squash now?

@MichelRottleuthner
Copy link
Copy Markdown
Contributor

Yes, please go ahead and squash

@Hyungsin
Copy link
Copy Markdown
Author

done :)

@MichelRottleuthner
Copy link
Copy Markdown
Contributor

I just tested the github webeditor for resolving the remaining (minor) merge conflict. Seems like this was a bad idea and it messed something up :/ can you remove my commit and just do a proper rebase?

@Hyungsin
Copy link
Copy Markdown
Author

No worries, done! :)

@MichelRottleuthner MichelRottleuthner merged commit a34f9c1 into RIOT-OS:master Jun 27, 2018
@cladmi cladmi added this to the Release 2018.07 milestone Jul 10, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area: drivers Area: Device drivers CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR Type: new feature The issue requests / The PR implemements a new feature for RIOT

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants