-
Notifications
You must be signed in to change notification settings - Fork 2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
drivers: import PIR motion sensor driver
Includes an application for manual testing.
- Loading branch information
1 parent
99760f3
commit e75dd40
Showing
7 changed files
with
380 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
/* | ||
* Copyright (C) 2014 Freie Universität Berlin | ||
* | ||
* This file is subject to the terms and conditions of the GNU Lesser | ||
* General Public License v2.1. See the file LICENSE in the top level | ||
* directory for more details. | ||
*/ | ||
|
||
/** | ||
* @defgroup driver_pir PIR Motion Sensor | ||
* @ingroup drivers | ||
* @brief Device driver interface for the PIR motion sensor | ||
* @{ | ||
* | ||
* @file | ||
* @brief Device driver interface for the PIR motion sensor | ||
* | ||
* @author Ludwig Ortmann <ludwig.ortmann@fu-berlin.de> | ||
*/ | ||
|
||
#ifndef __PIR_H | ||
#define __PIR_H | ||
|
||
#include "kernel_types.h" | ||
#include "periph/gpio.h" | ||
|
||
/** | ||
* @brief device descriptor for a PIR sensor | ||
*/ | ||
typedef struct { | ||
gpio_t gpio_dev; /**< GPIO device which is used */ | ||
kernel_pid_t msg_thread_pid; /**< thread to msg on irq */ | ||
} pir_t; | ||
|
||
#ifndef PIR_MSG_T_STATUS_START | ||
#define PIR_MSG_T_STATUS_START 150 | ||
#endif | ||
|
||
typedef enum { | ||
PIR_STATUS_HI = PIR_MSG_T_STATUS_START, /**< motion was detected */ | ||
PIR_STATUS_LO, /**< no motion is detected */ | ||
} pir_event_t; | ||
|
||
/** | ||
* @brief Initialize a PIR motion sensor | ||
* | ||
* The PIR motion sensor is interfaced by a single GPIO pin, specified by | ||
* `gpio`. | ||
* | ||
* @note | ||
* The sensor needs up to a minute to settle down before meaningful | ||
* measurements can be made. | ||
* | ||
* @param[out] dev device descriptor of an PIR sensor | ||
* @param[in] gpio the GPIO device the sensor is connected to | ||
* | ||
* @return 0 on success | ||
* @return -1 on error | ||
*/ | ||
int pir_init(pir_t *dev, gpio_t gpio); | ||
|
||
/** | ||
* @brief Read the current status of the motion sensor | ||
* | ||
* @param[in] dev device descriptor of the PIR motion sensor to read from | ||
* | ||
* @return 1 if motion is detected, 0 otherwise | ||
*/ | ||
pir_event_t pir_get_status(pir_t *dev); | ||
|
||
/** | ||
* @brief Register a thread for notification whan state changes on the | ||
* motion sensor. | ||
* | ||
* @note | ||
* This configures the gpio device for interrupt driven operation. | ||
* | ||
* @param[in] dev device descriptor of the PIR motion sensor to | ||
* register for | ||
* | ||
* @return 0 on succuess, | ||
* @return -1 on internal errors, | ||
* @return -2 if another thread is registered already | ||
*/ | ||
int pir_register_thread(pir_t *dev); | ||
|
||
#endif /* __PIR_H */ | ||
/** @} */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
MODULE = pir | ||
|
||
include $(RIOTBASE)/Makefile.base |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
/* | ||
* Copyright (C) 2014 Freie Universität Berlin | ||
* | ||
* This file is subject to the terms and conditions of the GNU Lesser | ||
* General Public License v2.1. See the file LICENSE in the top level | ||
* directory for more details. | ||
*/ | ||
|
||
/** | ||
* @ingroup driver_pir | ||
* @{ | ||
* | ||
* @file | ||
* @brief Device driver implementation for the PIR motion sensor | ||
* | ||
* @author Ludwig Ortmann <ludwig.ortmann@fu-berlin.de> | ||
* | ||
* @} | ||
*/ | ||
|
||
#include "pir.h" | ||
#include "thread.h" | ||
#include "msg.h" | ||
|
||
#define ENABLE_DEBUG (0) | ||
#include "debug.h" | ||
|
||
/********************************************************************** | ||
* internal API declaration | ||
**********************************************************************/ | ||
|
||
static int pir_activate_int(pir_t *dev); | ||
static void pir_callback(void *dev); | ||
static void pir_send_msg(pir_t *dev, pir_event_t event); | ||
|
||
/********************************************************************** | ||
* public API implementation | ||
**********************************************************************/ | ||
|
||
int pir_init(pir_t *dev, gpio_t gpio) | ||
{ | ||
dev->gpio_dev = gpio; | ||
dev->msg_thread_pid = KERNEL_PID_UNDEF; | ||
return gpio_init_in(dev->gpio_dev, GPIO_NOPULL); | ||
} | ||
|
||
pir_event_t pir_get_status(pir_t *dev) | ||
{ | ||
return ((gpio_read(dev->gpio_dev) == 0) ? PIR_STATUS_LO : PIR_STATUS_HI); | ||
} | ||
|
||
int pir_register_thread(pir_t *dev) | ||
{ | ||
if (dev->msg_thread_pid != KERNEL_PID_UNDEF) { | ||
if (dev->msg_thread_pid != thread_getpid()) { | ||
DEBUG("pir_register_thread: already registered to another thread\n"); | ||
return -2; | ||
} | ||
} | ||
else { | ||
DEBUG("pir_register_thread: activating interrupt for %p..\n", dev); | ||
if (pir_activate_int(dev) != 0) { | ||
DEBUG("\tfailed\n"); | ||
return -1; | ||
} | ||
DEBUG("\tsuccess\n"); | ||
} | ||
dev->msg_thread_pid = thread_getpid(); | ||
|
||
return 0; | ||
} | ||
|
||
/********************************************************************** | ||
* internal API implementation | ||
**********************************************************************/ | ||
|
||
static void pir_send_msg(pir_t *dev, pir_event_t event) | ||
{ | ||
DEBUG("pir_send_msg\n"); | ||
msg_t m = { .type = event, .content.ptr = (char*) dev, }; | ||
|
||
int ret = msg_send_int(&m, dev->msg_thread_pid); | ||
DEBUG("pir_send_msg: msg_send_int: %i\n", ret); | ||
switch (ret) { | ||
case 0: | ||
DEBUG("pir_send_msg: msg_thread_pid not receptive, event is lost"); | ||
break; | ||
case 1: | ||
DEBUG("pir_send_msg: OK"); | ||
break; | ||
case -1: | ||
DEBUG("pir_send_msg: msg_thread_pid is gone, clearing it"); | ||
dev->msg_thread_pid = KERNEL_PID_UNDEF; | ||
break; | ||
} | ||
} | ||
|
||
static void pir_callback(void *arg) | ||
{ | ||
DEBUG("pir_callback: %p\n", arg); | ||
pir_t *dev = (pir_t*) arg; | ||
if (dev->msg_thread_pid != KERNEL_PID_UNDEF) { | ||
pir_send_msg(dev, pir_get_status(dev)); | ||
} | ||
} | ||
|
||
static int pir_activate_int(pir_t *dev) | ||
{ | ||
return gpio_init_int(dev->gpio_dev, GPIO_NOPULL, GPIO_BOTH, pir_callback, dev); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
APPLICATION = driver_pir | ||
include ../Makefile.tests_common | ||
|
||
# These boards do not suport periph/gpio.h at the time of this writing: | ||
BOARD_BLACKLIST = native arduino-mega2560 avsextrem chronos mbed_lpc1768 msb-430 msb-430h msba2 pttu qemu-i386 redbee-econotag telosb wsn430-v1_3b wsn430-v1_4 z1 | ||
|
||
# Define default pin mappings for some boards: | ||
BOARD_WHITELIST = stm32f4discovery arduino-due | ||
ifneq (,$(filter stm32f4discovery,$(BOARD))) | ||
export PIR_GPIO ?= GPIO_8 | ||
endif | ||
ifneq (,$(filter arduino-due,$(BOARD))) | ||
export PIR_GPIO ?= GPIO_10 | ||
endif | ||
|
||
USEMODULE += pir | ||
USEMODULE += vtimer | ||
|
||
ifneq (,$(PIR_GPIO)) | ||
CFLAGS += -DPIR_GPIO=$(PIR_GPIO) | ||
endif | ||
|
||
include $(RIOTBASE)/Makefile.include | ||
|
||
all-polling: CFLAGS += -DTEST_PIR_POLLING | ||
|
||
all-polling: all | ||
|
||
all-interrupt: all |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
# About | ||
This is a manual test application for the PIR motion sensor driver. | ||
|
||
In order to build this application, you need to add the board to the | ||
Makefile's `WHITELIST` first and define a pin mapping (see below). | ||
|
||
|
||
# Usage | ||
There are two ways to test this. You can either actively poll the sensor | ||
state, or you can register a thread which receives messages for state | ||
changes. | ||
|
||
## Interrupt driven | ||
Connect the sensor's "out" pin to a GPIO of your board that can be | ||
configured to create interrupts. | ||
Compile and flash this test application like: | ||
|
||
export BOARD=your_board | ||
export PIR_GPIO=name_of_your_pin | ||
make clean | ||
make all-interrupt | ||
make flash | ||
|
||
The output should look like: | ||
|
||
kernel_init(): jumping into first task... | ||
|
||
PIR motion sensor test application | ||
|
||
Initializing PIR sensor at GPIO_8... [OK] | ||
|
||
Registering PIR handler thread... [OK] | ||
PIR handler got a message: the movement has ceased. | ||
PIR handler got a message: something started moving. | ||
PIR handler got a message: the movement has ceased. | ||
|
||
|
||
## Polling Mode | ||
Connect the sensor's "out" pin to any GPIO pin of you board. | ||
Compile and flash this test application like: | ||
|
||
export BOARD=your_board | ||
export PIR_GPIO=name_of_your_pin | ||
make clean | ||
make all-polling | ||
make flash | ||
|
||
The output should look like this: | ||
|
||
kernel_init(): jumping into first task... | ||
PIR motion sensor test application | ||
|
||
Initializing PIR sensor at GPIO_10... [OK] | ||
|
||
Printing sensor state every second. | ||
Status: lo | ||
... | ||
Status: lo | ||
Status: hi | ||
... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
/* | ||
* Copyright (C) 2014 Freie Universität Berlin | ||
* | ||
* This file is subject to the terms and conditions of the GNU Lesser | ||
* General Public License v2.1. See the file LICENSE in the top level | ||
* directory for more details. | ||
*/ | ||
|
||
/** | ||
* @ingroup tests | ||
* @{ | ||
* | ||
* @file | ||
* @brief Test application for the PIR motion sensor driver | ||
* | ||
* @author Ludwig Ortmann <ludwig.ortmann@fu-berlin.de> | ||
* | ||
* @} | ||
*/ | ||
|
||
#ifndef PIR_GPIO | ||
#error "PIR_GPIO not defined" | ||
#endif | ||
|
||
#include <stdio.h> | ||
|
||
#include "thread.h" | ||
#include "vtimer.h" | ||
#include "pir.h" | ||
|
||
char pir_handler_stack[KERNEL_CONF_STACKSIZE_MAIN]; | ||
pir_t dev; | ||
|
||
void* pir_handler(void *arg) | ||
{ | ||
msg_t msg_q[1]; | ||
msg_init_queue(msg_q, 1); | ||
|
||
printf("Registering PIR handler thread... %s\n", | ||
pir_register_thread(&dev) == 0 ? "[OK]" : "[Failed]"); | ||
|
||
msg_t m; | ||
while (msg_receive(&m)) { | ||
printf("PIR handler got a message: "); | ||
switch (m.type) { | ||
case PIR_STATUS_HI: | ||
puts("something started moving."); | ||
break; | ||
case PIR_STATUS_LO: | ||
puts("the movement has ceased."); | ||
break; | ||
default: | ||
puts("stray message."); | ||
break; | ||
} | ||
} | ||
puts("PIR handler: this should not have happened!"); | ||
|
||
return NULL; | ||
} | ||
|
||
int main(void) | ||
{ | ||
puts("PIR motion sensor test application\n"); | ||
printf("Initializing PIR sensor at GPIO_%i... ", PIR_GPIO); | ||
if (pir_init(&dev, PIR_GPIO) == 0) { | ||
puts("[OK]\n"); | ||
} | ||
else { | ||
puts("[Failed]"); | ||
return 1; | ||
} | ||
|
||
#if TEST_PIR_POLLING | ||
puts("Printing sensor state every second."); | ||
while (1) { | ||
printf("Status: %s\n", pir_get_status(&dev) == PIR_STATUS_LO ? "lo" : "hi"); | ||
vtimer_usleep(1000 * 1000); | ||
} | ||
#else | ||
thread_create( | ||
pir_handler_stack, sizeof(pir_handler_stack), PRIORITY_MAIN - 1, | ||
CREATE_WOUT_YIELD | CREATE_STACKTEST, | ||
pir_handler, NULL, "pir_handler"); | ||
#endif | ||
return 0; | ||
} |