[본 문서는 서울 IoT 센터에서 진행할 교육을 위해 작성된 한글문서입니다.]
[This document is currently written in Korean only for the purpose of being presented in the Seoul IoT tutorial.]
# 준비물
:::hw
Board|Raspberry Pi 3|1|
Sensor|Motion Sensor|1|HC-SR501
Sensor|LED Light|1|
Chip|Resistor|1|330 ohm
:::
:::sw
SDK|Tizen Studio|
:::
### Raspberry Pi

*이미지 출처: https://www.raspberrypi-spy.co.uk/
### Infrared Motion Sensor (HC-SR501)

[HC-SR501 사용자 매뉴얼](https://www.mpja.com/download/31227sc.pdf)
[Arduino HC-SR501 Motion Sensor Tutorial (Personal Blog)](http://henrysbench.capnfatz.com/henrys-bench/arduino-sensors-and-input/arduino-hc-sr501-motion-sensor-tutorial/)
### LED Light & Resistor
* 5파이 LED 전구 (전압 2.2V / 전류 50mA)
* 공급전압 5V 시, 100~400Ω 저항 사용

***
# Hardware Setting
## Motion Sensor 세팅 변경
* 지연 시간: 약 5초 / Repeatable Trigger 모드
* 감지 거리: 약 3m

## Motion Sensor 연결

## LED Light & Resistor 연결

***
# General Purpose Input/Output (GPIO)
Binary input peripheral 상태 읽기/쓰기 가능한 Interface

## GPIO Pin Number
보드에서의 Pin의 위치와 실제 Pin Map의 번호가 상이하여 코딩 시 아래 표의 Pin Param 참고
### Raspberry Pi

*GPIO2 & GPIO3은 미사용
| Pin Order | Pin Param |
|:-:|:-:|
| 4|4 |
| 5|5 |
| 6|6 |
| 12|12 |
| 13|13 |
| 16|16 |
| 17|17 |
| 18|18 |
| 19|19 |
| 20|20 |
| 21|21 |
| 22|22 |
| 23|23 |
| 24|24 |
| 25|25 |
| 26|26 |
| 27|27 |
***
## GPIO APIs
[Tizen Peripheral IO Native APIs - GPIO 가이드](https://developer.tizen.org/development/iot-extension-sdk/api-guides/tizen-peripheral-io-native-api/gpio)
### Opening and Closing a Handle
**peripheral_gpio_open()**
특정 pin 넘버의 Peripheral GPIO 핸들을 열어줌
```c
int peripheral_gpio_open(int gpio_pin, peripheral_gpio_h *gpio);
```
**peripheral_gpio_close()**
더 이상 사용되지 않는 Peripheral GPIO 핸들을 닫아줌
```c
int peripheral_gpio_close(peripheral_gpio_h gpio);
```
### Setting the Data Direction
**peripheral_gpio_set_direction()**
데이터 전송 방향을 설정함
* PERIPHERAL_GPIO_DIRECTION_IN : 데이터 읽기 모드
* PERIPHERAL_GPIO_DIRECTION_OUT_INITIALLY_HIGH : 데이터 쓰기 모드, 초기값을 high(1)로 설정
* PERIPHERAL_GPIO_DIRECTION_OUT_INITIALLY_LOW : 데이터 쓰기 모드, 초기값을 low(0)로 설정
```c
int peripheral_gpio_set_direction(peripheral_gpio_h gpio, peripheral_gpio_direction_e direction);
```
### Setting the Interrupted Callback
**peripheral_gpio_interrupted_cb**
```c
typedef void(*peripheral_gpio_interrupted_cb)(peripheral_gpio_h gpio, peripheral_error_e error, void *user_data);
```
**peripheral_gpio_set_edge_mode()**
```c
int peripheral_gpio_set_direction(peripheral_gpio_h gpio, peripheral_gpio_direction_e direction);
```
**peripheral_gpio_set_interrupted_cb()**
```c
int peripheral_gpio_set_direction(peripheral_gpio_h gpio, peripheral_gpio_direction_e direction);
```
**peripheral_gpio_unset_interrupted_cb()**
```c
int peripheral_gpio_set_direction(peripheral_gpio_h gpio, peripheral_gpio_direction_e direction);
```
### Reading and Writing Binary Data
**peripheral_gpio_read()**
Peripheral 핸들로부터 binary 데이터 값을 읽어옴
```c
int peripheral_gpio_read(peripheral_gpio_h gpio, uint32_t *value);
```
**peripheral_gpio_write()**
Peripheral 핸들에 binary 데이터 값을 입력함
```c
int peripheral_gpio_write(peripheral_gpio_h gpio, uint32_t value);
```
# Code Implementation
## 코드 준비
**1. Git Bash에서 rcc/smart-motion-light 코드 clone 받기**
```C
git clone https://git.tizen.org/cgit/apps/native/st-things-light -b basic st-things-light-basic
```
**2. Tizen Studio에서 smart-light 프로젝트 불러오기**
* File > Import >> Tizen > TIzen Project >> Root directory > Browse

* clone 받은 st-things-light-basic 폴더 선택

* Project Name: smart-light / Profile: iot-headless / Version: 5.0 선택 (이미 열려있는 프로젝트와 프로젝트명이 동일하면 안 열리니 주의)

## Privilege 추가
Peripheral IO API 사용을 위해 peripheralio privilege 추가
* tizen-manifest.xml 파일 선택
* Privileges 탭 > 추가(+) 버튼 >

* Custom Privileges 추가
```
http://tizen.org/privilege/peripheralio
```

* 파일 저장 후 Source 탭에서 privilege 추가된 것을 재확인
> tizen-manifest.xml
```xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<manifest xmlns="http://tizen.org/ns/packages" api-version="4.0" package="org.tizen.motionlight" version="1.0.0">
<profile name="iot-headless"/>
<service-application appid="org.tizen.motionlight" auto-restart="false" exec="motionlight" multiple="false" nodisplay="true" on-boot="false" taskmanage="false" type="capp">
<label>motionlight</label>
<icon>motion-light.png</icon>
</service-application>
<privileges>
<privilege>http://tizen.org/privilege/peripheralio</privilege>
</privileges>
</manifest>
```
## Resource 코드 내 GPIO 설정 확인
> src/resource/resource_infrared_motion_sensor.c
```c
#include <peripheral_io.h>
#include "log.h"
static peripheral_gpio_h g_sensor_h = NULL;
static int g_pin_num = -1;
void resource_close_infrared_motion_sensor(void)
{
if (!g_sensor_h) return;
_I("Infrared Motion Sensor is finishing...");
peripheral_gpio_close(g_sensor_h);
g_sensor_h = NULL;
g_pin_num = -1;
}
int resource_read_infrared_motion_sensor(int pin_num, uint32_t *out_value)
{
int ret = PERIPHERAL_ERROR_NONE;
if (!g_sensor_h) {
peripheral_gpio_h temp = NULL;
ret = peripheral_gpio_open(pin_num, &temp);
retv_if(ret, -1);
ret = peripheral_gpio_set_direction(temp, PERIPHERAL_GPIO_DIRECTION_IN);
if (ret) {
peripheral_gpio_close(temp);
_E("peripheral_gpio_set_direction failed.");
return -1;
}
g_sensor_h = temp;
g_pin_num = pin_num;
}
if (g_pin_num != pin_num) {
_E("Invalid pin number.");
return -1;
}
ret = peripheral_gpio_read(g_sensor_h, out_value);
retv_if(ret < 0, -1);
return 0;
}
```
> src/resource/resource_led.c
```c
#include <peripheral_io.h>
#include "log.h"
static peripheral_gpio_h g_sensor_h = NULL;
static int g_pin_num = -1;
void resource_close_led(void)
{
if (!g_sensor_h) return;
_I("LED is finishing...");
peripheral_gpio_close(g_sensor_h);
g_sensor_h = NULL;
g_pin_num = -1;
}
int resource_write_led(int pin_num, int write_value)
{
int ret = PERIPHERAL_ERROR_NONE;
if (!g_sensor_h) {
peripheral_gpio_h temp = NULL;
ret = peripheral_gpio_open(pin_num, &temp);
retv_if(ret, -1);
ret = peripheral_gpio_set_direction(temp, PERIPHERAL_GPIO_DIRECTION_OUT_INITIALLY_LOW);
if (ret) {
peripheral_gpio_close(temp);
_E("peripheral_gpio_set_direction failed.");
return -1;
}
g_sensor_h = temp;
g_pin_num = pin_num;
}
if (g_pin_num != pin_num) {
_E("Invalid pin number.");
return -1;
}
ret = peripheral_gpio_write(g_sensor_h, write_value);
retv_if(ret < 0, -1);
_I("LED Value : %s", write_value ? "ON":"OFF");
return 0;
}
```
## Motion Sensor 값 읽어오기
Motion Sensor가 연결된 핀에 접근하여 Motion Sensor 값을 읽어옴
> src/controller.c
```c
#include <unistd.h>
#include <Ecore.h>
#include <tizen.h>
#include <service_app.h>
#include "log.h"
#include "resource/resource_infrared_motion_sensor.h"
#include "resource/resource_led.h"
static Eina_Bool _get_motion_sensor_data()
{
int ret = 0;
uint32_t value = 0;
if (!ad) {
_E("failed to get app_data");
return ECORE_CALLBACK_CANCEL;
}
// Get value from motion sensor
ret = resource_read_infrared_motion_sensor(SENSOR_MOTION_GPIO_NUMBER, &value);
if (ret != 0) {
_E("cannot read data from the infrared motion sensor");
return ECORE_CALLBACK_CANCEL;
}
_D("Detected motion value is: %u", value);
return ECORE_CALLBACK_RENEW;
}
```
## LED 값 변경하기
LED가 연결된 핀에 접근하여 LED Light 값을 변경함
> src/controller.c
```c
static int _set_led_data(int state) {
int ret = 0;
// Write state to LED light
ret = resource_write_led(SENSOR_LED_GPIO_NUMBER, state);
if (ret != 0) {
_E("cannot write led data");
return -1;
}
_I("LED : %d",state);
return 0;
}
```
```c
static Eina_Bool _get_motion_sensor_data()
{
int ret = 0;
uint32_t value = 0;
if (!ad) {
_E("failed to get app_data");
return ECORE_CALLBACK_CANCEL;
}
// Get value from motion sensor
ret = resource_read_infrared_motion_sensor(SENSOR_MOTION_GPIO_NUMBER, &value);
if (ret != 0) {
_E("cannot read data from the infrared motion sensor");
return ECORE_CALLBACK_CANCEL;
}
_D("Detected motion value is: %u", value);
// Set LED light with value
_set_led_data(value);
return ECORE_CALLBACK_RENEW;
}
```
## 타이머 설정하기 (app_control)
특정 주기(TIMER_GATHER_INTERVAL)마다 모션 센서 값을 불러오고 LED 값을 설정해주는 __read_motion_write_led 함수 호출
> src/controller.c
```c
typedef struct app_data_s {
Ecore_Timer *getter_timer;
} app_data;
static void service_app_control(app_control_h app_control, void *user_data)
{
app_data *ad = user_data;
// Delete old timer if there is one
if (ad->getter_timer)
ecore_timer_del(ad->getter_timer);
// Create a timer to call the given function in given period of time
ad->getter_timer = ecore_timer_add(TIMER_GATHER_INTERVAL, _get_motion_sensor_data, ad);
if (!ad->getter_timer) {
_E("Failed to add getter timer");
return;
}
}
```
## interrupt_cb 설정하기 (app_control)
> src/controller.c
```c
static void service_app_control(app_control_h app_control, void *user_data)
{
int ret = 0;
// Set an interrupted callback to be invoked when interrupt is triggered on motion sensor
ret = resource_set_interrupted_cb_infrared_motion_sensor(SENSOR_MOTION_GPIO_NUMBER, _motion_interrupted_cb);
if (ret != 0) {
_E("cannot set interrupted callback for motion sensor");
return;
}
}
```
## 리소스 정리하기 (app_terminate)
App 종료 시 App에서 사용하던 리소스 정리
> src/controller.c
```c
static void service_app_terminate(void *user_data)
{
app_data *ad = user_data;
// Delete timer
if (ad->getter_timer)
ecore_timer_del(ad->getter_timer);
// Turn off LED light with __set_led()
_set_led_data(0);
// Close Motion and LED resources
resource_close_infrared_motion_sensor();
resource_close_led();
// Free app data
free(ad);
FN_END;
}
```
## Tizen App 실행
Project Explorer 내 프로젝트 우클릭 > Run As > Tizen Native App

***
# 최종 확인
Motion sensor 값에 따른 LED Light 변화 확인

Notice
Are you sure to delete this post?
Smart Light Basic
1
0
|
Published on August 16, 2019
Craft info. | |
Maker |
|
Status | Planning |
Period | 2019-08-14 ~ 2019-08-31 |
About This Craft | |
Tutorial for basic smart light app | |
Making Note