mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Merge pull request #1714 from LudwigOrtmann/add_driver_pir
drivers: import PIR motion sensor driver
This commit is contained in:
commit
7e860449f3
@ -37,5 +37,8 @@ endif
|
||||
ifneq (,$(filter servo,$(USEMODULE)))
|
||||
DIRS += servo
|
||||
endif
|
||||
ifneq (,$(filter pir,$(USEMODULE)))
|
||||
DIRS += pir
|
||||
endif
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
||||
|
88
drivers/include/pir.h
Normal file
88
drivers/include/pir.h
Normal file
@ -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 */
|
||||
/** @} */
|
3
drivers/pir/Makefile
Normal file
3
drivers/pir/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
MODULE = pir
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
110
drivers/pir/pir.c
Normal file
110
drivers/pir/pir.c
Normal file
@ -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);
|
||||
}
|
29
tests/driver_pir/Makefile
Normal file
29
tests/driver_pir/Makefile
Normal file
@ -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
|
60
tests/driver_pir/README.md
Normal file
60
tests/driver_pir/README.md
Normal file
@ -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
|
||||
...
|
87
tests/driver_pir/main.c
Normal file
87
tests/driver_pir/main.c
Normal file
@ -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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user