Sensor driver: PIR-based occupancy sensing#7823
Sensor driver: PIR-based occupancy sensing#7823MichelRottleuthner merged 1 commit intoRIOT-OS:masterfrom
Conversation
e56e524 to
b851aa2
Compare
|
@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! |
bc1877a to
11e8d4f
Compare
MichelRottleuthner
left a comment
There was a problem hiding this comment.
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?
drivers/ekmb/ekmb.c
Outdated
| bool pin_high; | ||
| uint64_t pin_rise_time; | ||
| uint64_t accum_up_time; | ||
| uint64_t last_reset_time; |
There was a problem hiding this comment.
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.
drivers/ekmb/ekmb.c
Outdated
| int pin_now = gpio_read(dev->p.gpio); | ||
|
|
||
| /* We were busy counting */ | ||
| if (pin_high) { |
There was a problem hiding this comment.
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)
drivers/ekmb/ekmb.c
Outdated
| } | ||
| /* Pin is rising */ | ||
| if (pin_now) { | ||
| pin_rise_time = xtimer_usec_from_ticks64(xtimer_now64()); |
There was a problem hiding this comment.
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.
drivers/ekmb/ekmb.c
Outdated
|
|
||
| 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)); |
There was a problem hiding this comment.
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)
drivers/include/ekmb.h
Outdated
| * @brief Parameters needed for device initialization | ||
| */ | ||
| typedef struct { | ||
| gpio_t gpio; /**< GPIO pin that sensor is connected to */ |
There was a problem hiding this comment.
add a param for active-high/low
drivers/include/ekmb.h
Outdated
| * @{ | ||
| */ | ||
| typedef struct { | ||
| ekmb_params_t p; |
There was a problem hiding this comment.
move the global stete vars here
drivers/include/ekmb.h
Outdated
| * @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 |
drivers/ekmb/ekmb.c
Outdated
| 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; |
There was a problem hiding this comment.
please use names for return codes
drivers/include/ekmb.h
Outdated
| * | ||
| * @return 0 on success | ||
| * @return -1 on error | ||
| * @return -2 on invalid address |
drivers/include/ekmb.h
Outdated
| */ | ||
| int ekmb_init(ekmb_t* dev, const ekmb_params_t* params); | ||
|
|
||
| int ekmb_read(ekmb_t* dev, int16_t *light); |
94107b5 to
9a1d4a6
Compare
|
@MichelRottleuthner, Thank you for your review :) I think adding these features to the existing PIR can be a separate work. |
9a1d4a6 to
7c1b2a9
Compare
51da148 to
4567661
Compare
cbe2c83 to
8c3ec9a
Compare
|
@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! :) |
4d690df to
aebbfc4
Compare
d27221e to
5f32b4b
Compare
|
@MichelRottleuthner changes o.k.? |
MichelRottleuthner
left a comment
There was a problem hiding this comment.
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.
drivers/include/pir.h
Outdated
| * | ||
| * @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 |
There was a problem hiding this comment.
replace from with of?
drivers/include/pir.h
Outdated
| * @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] |
There was a problem hiding this comment.
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).
drivers/pir/include/pir_params.h
Outdated
| * @{ | ||
| */ | ||
| #ifndef PIR_PARAM_GPIO | ||
| #define PIR_PARAM_GPIO GPIO_PIN(PA, 6) |
There was a problem hiding this comment.
please use GPIO_PIN(0, 6) instead to make sure it works on platforms that use other naming schemes
|
|
||
| #ifndef PIR_PARAMS | ||
| #define PIR_PARAMS { .gpio = PIR_PARAM_GPIO, \ | ||
| .active_high = PIR_PARAM_ACTIVE_HIGH } |
drivers/pir/pir.c
Outdated
| dev->active = false; | ||
| dev->accum_active_time = 0; | ||
| dev->start_active_time = 0; | ||
| dev->last_read_time = xtimer_usec_from_ticks64(xtimer_now64()); |
There was a problem hiding this comment.
use xtimer_now_usec64 directly here?
drivers/pir/pir.c
Outdated
| dev->active = true; | ||
| /* Pin is falling */ | ||
| } else { | ||
| dev->start_active_time = 0xFFFFFFFFFFFFFFFF; |
There was a problem hiding this comment.
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?
sys/auto_init/saul/auto_init_pir.c
Outdated
| static saul_reg_t saul_entries[PIR_NUM]; | ||
|
|
||
| /** | ||
| * @brief Reference the occupancy driver struct |
There was a problem hiding this comment.
Reference to...
tests/driver_pir/main.c
Outdated
|
|
||
| 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}; |
There was a problem hiding this comment.
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)
tests/driver_pir/main.c
Outdated
| 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) { |
There was a problem hiding this comment.
as stated above, use params from pir_params here (change to &pir_params[0])
| 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; |
There was a problem hiding this comment.
I think reordering the struct members could save some memory here due to allignment/padding
|
@MichelRottleuthner. Thank you! |
7b442ed to
69ed4d7
Compare
drivers/pir/pir.c
Outdated
| 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) ? |
There was a problem hiding this comment.
careful: the gpio API returns either 0 or >0. You could change gpio_read(..) to (gpio_read(..) > 0)
MichelRottleuthner
left a comment
There was a problem hiding this comment.
Murdock reports errors regarding bool types on some platforms. Adding #include <stdbool.h> to pir.h should help.
|
@MichelRottleuthner, resolved again. Thanks! |
|
Yes, please go ahead and squash |
|
done :) |
|
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? |
|
No worries, done! :) |
This PR provides a driver for EKMB PIR motion sensor.
The current driver operation is: