# Tizen Project 생성 (Import)
Template 또는 Sample 타입의 새로운 Tizen Project를 만드는 방법과 달리, 기존에 존재하는 Tizen Project를 타이젠 스튜디오에 이식시켜서 빌드/실행 할 수 있는 방법을 소개합니다.
## Import Project
1. Git에서 clone 받은 프로젝트를 준비합니다.
> 강의에서는 링크에서 다운로드 받은 rcc.zip을 준비합니다. 압축을 풀어주세요.
> [http://tizenappschool.org/tutorial/157/contents/1](http://tizenappschool.org/tutorial/157/contents/1)
> (위 경로에서 스크롤을 조금 내리시면 rcc.zip이 있습니다.)
> Git에서 프로젝트를 clone 받는 방법은 아래 설명을 참고하세요.
> [Appendix > Git에서 프로젝트 가져오기](https://craftroom.tizen.org/hackathon-kick-off-a-tizen-project/#git%EC%97%90%EC%84%9C-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EA%B0%80%EC%A0%B8%EC%98%A4%EA%B8%B0)
- Tizen Git repository : https://git.tizen.org/cgit/
- 실습에서 사용할 Tizen Project : apps/native/rcc
2. 타이젠 스튜디오를 열어 File > Import...를 선택합니다.

3. Tizen > Tizen Project를 선택합니다.

4. Root directory를 선택하고, Browser를 눌러서 준비한 프로젝트의 경로를 넣어줍니다.

> rcc.zip을 그대로 경로에 넣을 수도 있습니다. 이 경우에는 'Archive file'을 선택해주세요.
5. Profile : iot-headless, Version : 5.0을 선택하고 Finish를 눌러 과정을 종료합니다.
drop-down 버튼을 클릭하면 다양한 Profile과 Version 선택이 가능합니다.

> NOTE
> - iot-headed : UI가 있는 IoT Profile
> - iot-headless : UI가 없는 IoT Profile
6. 프로젝트가 타이젠 스튜디오에 Import된 것을 확인합니다.

## Build Project
Import한 프로젝트를 빌드하여 프로젝트에 문제가 없는지 확인해보겠습니다.
1. 프로젝트 이름 위에서 마우스 우버튼을 클릭 > Build Project를 선택합니다.

2. 하단 Console 창에서 빌드 프로세스 로그를 확인합니다.
- 빌드 성공 시

FAILED 메시지 없이 Build Finished 메시지가 보이면 해당 프로젝트가 성공적으로 빌드 된 것입니다.
- 빌드 실패 시

Console 창에서 빌드 결과와 함께 빌드 실패 이유를 확인할 수 있습니다.
빌드 실패 사유는 Problems 창에서도 확인 가능합니다.

# Tizen Project 구조 및 특성
Import한 Tizen Project의 구조를 소개합니다.
rcc 프로젝트를 통해 타이젠 프로젝트가 가지고 있는 구조와 프로젝트의 특성을 정의하는 tizen-manifest.xml에 대해 자세히 알아보겠습니다.
## Tizen Project 디렉토리 구조

- inc/ 폴더는 함수가 선언된 *.h 파일들이 위치해있습니다.
- src/ 폴더는 함수가 정의된 *.c 파일들이 위치해있습니다.
- res/ 폴더는 앱에서 사용하는 리소스 파일이 위치합니다. (ex. image file, mp3 file 등)
## tizen-manifest.xml
tizen-manifest.xml는 프로젝트의 특성을 정의합니다. tizen-manifest.xml 파일을 선택하면 여러 개의 탭이 보이게 됩니다.
### Overview
Overview에서는 프로젝트의 general한 정보를 보여줍니다.
각각의 속성은 개별적으로 변경 가능하지만, 변경 시 유의해야 할 점이 있습니다.
- Package는 여러 개의 Application을 포함할 수 있고, 각 앱은 각각의 Application ID를 가질 수 있습니다. 다만 Package이 하나의 Application을 가지는 경우, Tizen 정책 상 둘의 값은 동일해야 합니다.
- API version 변경은 신중해야 합니다. 앱에서 사용하는 API와 tizen-manifest.xml에서 정의한 API version이 맞지 않을 경우 API 호출에 실패할 수 있습니다.

### Feature
Feature에서는 소프트웨어 또는 하드웨어 기능을 선언할 수 있습니다. 여기서 선언된 기능은 해당 앱을 Tizen 마켓에 올릴 때 어느 카테고리에 속하게 할 것인지를 필터링하는 역할을 합니다.

### Privileges
Privilege는 앱 실행 시에 API를 호출 할 수 있는 권한입니다. 특정 API를 사용하기 위해서는 privilege를 확인하고 해당하는 prilvilege를 추가해주어야 합니다.
예를 들어 alarm_get_notification() 이라는 API를 사용하고자 한다면, Public level의 http://tizen.org/privilege/alarm.get privilege가 필요합니다.

[alarm_get_notification() API](https://developer.tizen.org/development/api-references/native-application?redirect=https://developer.tizen.org/dev-guide/5.0.0/org.tizen.native.mobile.apireference/group__CAPI__ALARM__MODULE.html#ga0a2a83ef400ccbceb92ea9fc3a29ad68)
Public level의 privilege를 추가하는 경우, Internal에서 "alarm"를 검색하여 해당 privilege를 추가합니다.

> Public/Platform level의 privilege를 추가하는 경우에는 Internal에서, 그 외에는 custome privileges에 직접 추가합니다.
> 다만 Peripheral I/O API를 사용하기 위해 사용하는 privilege(http://tizen.org/privilege/peripheralio)는 Platform level이지만, HW에 접근해야 하는 API의 특성 상 custom privileges에 직접 입력해야 합니다.
>
> peripheral_gpio_open() API를 참고하세요.
> [peripheral_gpio_open() API](https://developer.tizen.org/dev-guide/tizen-iot-headless/4.0/group__CAPI__SYSTEM__PERIPHERAL__IO__GPIO__MODULE.html#ga80af0917135ed8043cfb914f1d359d8f)
### Location
Location에서는 언어에 관련된 설정을 할 수 있습니다.
화면에 보여지는 텍스트의 언어를 추가하고, 추가되는 언어의 이름과 그에 대한 설명을 설정 할 수 있습니다.

실습하는 apps/native/rcc는 UI가 없는 IoT Headless 프로젝트이기 때문에 화면에 보여지는 텍스트는 없지만, Location 설정을 통해서 원하는 언어로 로그를 출력할 수 있습니다.
### Advanced
여기에서는 다양한 Advanced 기능을 설정할 수 있습니다.
1. Meta Data
프로젝트에 사용자가 정의한 key-value를 추가할 수 있습니다. 정의된 key-value 값은 App info API를 통해 가져와 사용할 수 있습니다.
> [특정 앱의 metadata 값을 읽을 수 있는 API](https://developer.tizen.org/development/api-references/native-application?redirect=https://developer.tizen.org/dev-guide/5.0.0/org.tizen.native.mobile.apireference/group__CAPI__APP__INFO__MODULE.html#gad3bb1ded5642e42edcb9a2e717ca8efb)

2. Data Control
앱 간 Data 공유가 가능하도록 설정하는 부분입니다.
3. Miscellaneous Options
앱의 동작을 결정하는 부분입니다. Manage task/Auto restart/On boot 세 개 속성의 동작을 정의할 수 있습니다.

- Manager task : Task manager 앱에서 해당 앱을 보여줄지 여부를 설정합니다.
- Auto restart : true 설정 시, 앱이 비정상적으로 종료되면 자동으로 재시작됩니다.
- On boot : true 설정 시, 부팅 시점 및 패키지 설치 또는 업데이트 후 앱이 시작됩니다.
- 두 속성의 조합에 의한 동작은 아래 그림에서 확인할 수 있습니다.
> 좀 더 자세한 사항은 링크에서 확인하세요.
> [Attribute combinations](https://developer.tizen.org/development/guides/native-application/application-management/applications/service-application#attribute)

> 해당 강의에서는 Auto restart : false, On boot : false로 설정하여 실습하겠습니다.
> 그러나 실제 해커톤에서는 Auto restart : true, On boot : true로 설정하셔야 합니다. 그래야 문제가 생겼을 경우에도 자동 실행이 되어 문제점을 파악할 수 있습니다.
4. Application Control
App control을 사용하여 앱의 기능을 다른 앱과 공유할 수 있습니다.
> 자세한 설명은 아래 링크를 참고하세요.
> [Application Controls 알아보기](https://developer.tizen.org/development/guides/native-application/application-management/application-controls?langredirect=1)
5. Background Category
어떤 기능을 background에서 계속 동작하도록 할 것인지 설정합니다.
6. Trust Anchor
HTTPS 통신에 고유한 SSL 루트를 할당 할 수 있습니다.
### Source
Overview, Feature, Privileges, Localization, Advanced에서 설정한 내용을 xml 코드로 확인할 수 있습니다. Source에서 직접 수정도 가능합니다.

# Tizen Service App Lifecycle
다음은 Tizen Application 중 Service Application의 라이프 사이클에 대해 자세히 알아보겠습니다.
## UI App vs Service App
먼저 Tizen Application이 제공하는 모델에 대해 살펴봅시다.
Tizen Application은 2가지 모델을 제공하는데, 1) UI Application과 2) Service Application이 그것입니다. 두 모델의 차이점은 아래와 같습니다.
1) UI Application은 graphical user interface를 가지는 앱입니다. 즉, 디스플레이를 가지는 앱으로 화면에 표시할 수 있습니다. 가장 일반적인 Tizen Application 모델입니다.
2) Service Application은 graphical user interface가 없는, 백그라운드에서 실행되는 앱입니다. 사용자 개입이 필요없는 작업을 수행하는데 유용합니다. (예시 : 센서데이터를 백그라운드로 가져오기)
해당 강의에서 실습하는 apps/native/rcc는 화면이 필요없는 IoT Headless 앱으로 Tizen Application 모델 중 Service Application으로 만들어져 있습니다.
두 모델은 특성에 따라 각각 다른 라이프 사이클을 가지지만, 아래 내용은 실습하는 rcc앱에 따라 Service Application의 라이프 사이클을 설명합니다.
> UI Application과 Service Application 두 모델의 라이프 사이클 및 자세한 설명이 궁금하시면 다음 링크를 참고하세요.
> - [Tizen Application](https://developer.tizen.org/development/guides/native-application/applications)
> - [UI Application](https://developer.tizen.org/development/guides/native-application/applications/ui-application/efl-applications/basic-ui-application)
> - [Service Application](https://developer.tizen.org/development/guides/native-application/application-management/applications/service-application)
## Lifecycle 자세히 알아보기
이 부분에서는 apps/native/rcc 앱을 통해 Service Application의 Lifecycle을 소개하려고 합니다.
먼저 코드를 보겠습니다.
**src/controller.c**

- 앱은 main()에서 service_app_main()을 호출합니다.
- service_app_main() 함수가 불리면 main loop이 시작되고, service_app_exit()이 호출 될 때까지 main loop이 계속 실행됩니다.
### Main loop
프로그램의 main이 되는 loop를 main loop이라고 합니다. 타이젠 앱은 event-driven 방식을 취하고 있는데, event-driven이란 특정 이벤트에 반응하여 동작을 변경하는 방식을 일컫습니다. 즉, event-driven 방식의 앱은 이벤트를 체크하고 처리하는 루틴을 반복합니다. 이 반복되는 루틴을 main loop이라고 합니다. Event handling, Timing handling 등 모든 일 처리를 main loop에서 진행합니다.

반복적으로 이벤트를 체크하고 처리하는 루틴은 [대기 <---> 처리]를 반복합니다. 대기중인 상태를 Idle 상태라고 합니다. Main loop은 처리할 이벤트가 없으면 가만히 대기하고 있다가, 특정 이벤트가 들어오면 Idle 상태에서 벗어나서 이벤트를 처리합니다.
> Main loop에 대해 더 알고 싶으신 분은 아래 링크를 참고하세요.
> [[EFL] ecore main loop의 이해](http://egloos.zum.com/seoz/v/3827472)
Main loop에서 어떤 이벤트를 처리할지는 개발자가 결정합니다. 즉, 개발자는 처리하고자 하는 이벤트를 main loop에 미리 등록해놓습니다.
> 예시
>
> - Lifecycle event : lifecycle event callback을 service_app_main()에서 등록하여 앱의 라이프 사이클에 따라 이벤트를 호출합니다.
> - Timer event : ecore_timer_add()로 타이머 이벤트를 등록하고, 타이머 이벤트를 처리해야 하는 시점이 왔을 때 timer callback 함수를 호출합니다.
### Lifecycle event callback 함수
**src/controller.c**

서비스 앱의 라이프 사이클 이벤트 콜백은 create, terminate, app_control이 있습니다.
각 콜백이 불리는 시점은 다음 그림에서 확인할 수 있습니다.

- service_app_create_cb() : 앱이 실행되면 가장 먼저 호출됩니다. 주로 자원을 할당하거나 초기화 하는 용도로 사용됩니다.
- service_app_control_cb() : 앱이 실행되었을 때 create 바로 다음에 불리거나, 다른 앱이 해당 앱을 호출했을 때 create 없이 바로 수행됩니다.
- service_app_terminate_cb() : 앱이 종료될 때 불리므로 주로 사용했던 자원을 해제하는 용도로 사용됩니다.
**src/controller.c**

service_app_main()의 세 번째 인자인 service_app_lifecycle_callback_s를 통해 라이프 사이클 이벤트 콜백이 main loop에 등록됩니다. main loop은 앱의 라이프 사이클에 따라 등록된 라이프 사이클 이벤트 콜백을 호출합니다.

service_app_lifecycle_callback_s 구조체를 ctrl + click 해봅시다.
서비스 앱이 가지는 라이프 사이클 이벤트 콜백을 볼 수 있습니다.
## 실습
실제 Service Application의 Lifecycle이 어떻게 동작하는지 Lifecyle event callback에 로그를 찍어 확인해봅시다.
> NOTE
>
> 실습을 진행하기 전에 아래 내용을 확인하여 로그를 확인할 수 있는 환경을 세팅해주세요.
> - 로그 입력 방법 : [Appendix > apps/native/rcc에서 로그 입력하기](https://craftroom.tizen.org/hackathon-kick-off-a-tizen-project/#appsnativercc%EC%97%90%EC%84%9C-%EB%A1%9C%EA%B7%B8-%EC%9E%85%EB%A0%A5%ED%95%98%EA%B8%B0)
> - Shell 열기 : [Appendix > Device Manger로 Shell 실행하기](https://craftroom.tizen.org/hackathon-kick-off-a-tizen-project/#device-manager%EB%A5%BC-%ED%86%B5%ED%95%B4-shell-%EC%8B%A4%ED%96%89%ED%95%98%EA%B8%B0)
> - dlogutil 사용하기 : [Appendix > dlogutil 사용하기](https://craftroom.tizen.org/hackathon-kick-off-a-tizen-project/#dlogutil-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0)
각 라이프 사이클 이벤트 콜백에 아래와 같이 로그를 입력하고 앱을 실행해봅시다.(프로젝트 이름 위에서 우클릭 > Run As)
**src/controller.c**
```c
static bool service_app_create(void *data)
{
_D("create");
return true;
}
static void service_app_terminate(void *data)
{
_D("terminate");
}
static void service_app_control(app_control_h app_control, void *data)
{
_D("control");
}
```
'create' > 'control' > 'terminate' 순으로 로그가 출력 될까요?
위 코드는 앱이 종료되지 않기 때문에 'terminate'가 불리지 않습니다.
앱이 종료된다는 이벤트를 받지 않으면 service_app_terminate_cb()은 호출되지 않습니다.
service_app_contorl()에서 서비스 앱을 종료시키는 API인 service_app_exit()을 호출합니다.
```c
static void service_app_control(app_control_h app_control, void *data)
{
_D("control");
service_app_exit();
}
```
service_app_exit()을 호출하게 되면 main loop은 terminate 이벤트 콜백을 부르게 되고, service_app_terminate()이 호출되어 'terminate' 로그를 출력합니다.

> service_app_create_cb()은 main loop에 진입하기 직전에 불리기 때문에 create_cb에서 너무 많은 일처리를 하게되면 앱의 런칭 속도가 느려지는 문제가 있습니다.
> 빠른 앱 런칭을 위해서는 create_cb를 간소하게 짤 필요성이 있습니다.
>
> 이와 관련된 좋은 포스팅이 있어서 공유드립니다. 참고하세요.
> [타이젠 네이티브앱 초보 개발자가 궁금해하는 것들](https://storycompiler.tistory.com/139)
> [타이젠 앱 Life cycle은 어떤 모습일까](https://storycompiler.tistory.com/24)
# Ecore Timer
Tizen은 Ecore라는 라이브러리를 가지고 있고 Ecore에는 timer, idler, idle_enterer, idle_exiter, animator, job, event 등 다양한 이벤트 콜백이 존재합니다. 이 강의에서는 가장 많이 사용되는 timer를 중점적으로 설명하려고 합니다.
Timer는 주로 특정 간격으로 특정 함수를 호출할 수 있게 해주는 기능을 일컫습니다. Tizen의 Ecore Timer는 이를 코드 한 줄로 간단히 수행할 수 있게 해줍니다.
## Ecore_timer API 살펴보기
> [Ecore Timer API Reference](https://developer.tizen.org/development/api-references/native-application?redirect=https://developer.tizen.org/dev-guide/5.0.0/org.tizen.native.mobile.apireference/group__Ecore__Timer__Group.html)
### ecore_timer_add()
```c
Ecore_Timer* ecore_timer_add(double interval, Ecore_Task_Cb func, const void *data)
```
- 이 API는 타이머를 추가하고 성공하면 timer handle을, 실패하면 NULL을 반환합니다.
- interval에서 설정하는 시간 간격으로 func 콜백이 호출됩니다.
- interval은 초단위로 설정합니다.
- 데이터 포인터를 func 콜백에 매개 변수로 전달할 수 있습니다.
- func 콜백이 호출되면 1 (또는 ECORE_CALLBACK_RENEW) 또는 0 (또는 ECORE_CALLBACK_CANCEL) 값을 반환해야합니다.
> ECORE_CALLBACK_RENEW : 다음 tick에서 콜백 함수가 다시 호출됩니다.
> ECORE_CALLBACK_CANCEL : 콜백 함수가 다시 호출되지 않으며 자동으로 timer handle을 삭제합니다.
- ECORE_CALLBACK_CANCEL을 반환하는 경우, 제거 된 timer handle에 NULL을 넣어 ecore_timer_del()로 중복 제거 하지 않도록 해야합니다.
```
Ecore_Timer *timer;
Eina_Bool __func(void *data)
{
timer = NULL;
return ECORE_CALLBACK_CANCEL;
}
```
### ecore_timer_del()
```c
void * ecore_timer_del(Ecore_Timer *timer)
```
- 타이머 목록에서 해당 timer handle을 삭제합니다.
- timer는 유효한 handle이어야합니다. (타이머 콜백 함수가 이미 0을 반환 한 경우, handle은 더 이상 유효하지 않으며 삭제할 필요가 없습니다.)
## 실습
위 설명을 바탕으로 타이머를 돌려봅시다.
먼저 소스코드에서 타이머 변수를 선언합니다.
**src/controller.c**
```c
Ecore_Timer *timer;
```
service_app_control 함수 안에서 timer를 추가합니다.
interval의 단위는 초 입니다. 실습에서는 2초로 설정하겠습니다.
(**코드에는 double 타입으로 입력 : 2.0**)
```c
static void service_app_control(app_control_h app_control, void *data)
{
_D("control");
// Create a timer to call the given function in given period of time
timer = ecore_timer_add(2.0, my_timed_cb, NULL);
if (!timer) {
_E("Failed to add timer");
return;
}
}
```
타이머 콜백 함수도 설정합니다.
지정한 시간 간격으로 5번을 호출합니다.
1~4번째 까지는 콜백 함수가 다시 호출되도록, (**ECORE_CALLBACK_RENEW**)
5번째 호출 시에는 더 이상 콜백 함수가 불리지 않도록 설정합니다.(**ECORE_CALLBACK_CANCEL**)
> ECORE_CALLBACK_CANCEL을 리턴하기 직전에 timer에 NULL을 넣어 ecore_timer_del()로 timer 삭제 시 중복 제거가 되지 않도록 합니다.
```c
Eina_Bool my_timed_cb(void *data)
{
static int count = 0;
count++;
if (count < 5) {
_D("[%d] Timer", count);
return ECORE_CALLBACK_RENEW;
}
_D("[%d] Timer END", count);
timer = NULL;
return ECORE_CALLBACK_CANCEL;
}
```
앱이 종료되면 timer가 삭제되도록 설정합니다.
> timer 삭제 시 중복 제거가 되지 않도록 NULL을 체크합니다.
```c
static void service_app_terminate(void *data)
{
_D("terminate");
if (timer) {
ecore_timer_del(timer);
timer = NULL;
}
}
```
로그를 확인합니다.

### Timer 실습 전체 코드
**src/controller.c**
```c
/*
* Copyright (c) 2017 Samsung Electronics Co., Ltd.
*
* Contact: Jin Yoon <jinny.yoon@samsung.com>
* Geunsun Lee <gs86.lee@samsung.com>
* Eunyoung Lee <ey928.lee@samsung.com>
* Junkyu Han <junkyu.han@samsung.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <unistd.h>
#include <glib.h>
#include <Ecore.h>
#include <tizen.h>
#include <service_app.h>
#include "log.h"
#include "resource.h"
#include "controller.h"
#define CONNECTIVITY_KEY "opened"
#define SENSORING_TIME_INTERVAL 5.0f
typedef struct app_data_s {
// Adds the data you need
} app_data;
Ecore_Timer *timer;
Eina_Bool my_timed_cb(void *data)
{
static int count = 0;
count++;
if (count < 5) {
_D("[%d] Timer", count);
return ECORE_CALLBACK_RENEW;
}
_D("[%d] Timer END", count);
timer = NULL;
return ECORE_CALLBACK_CANCEL;
}
static bool service_app_create(void *data)
{
_D("create");
return true;
}
static void service_app_terminate(void *data)
{
_D("terminate");
if (timer) {
ecore_timer_del(timer);
timer = NULL;
}
}
static void service_app_control(app_control_h app_control, void *data)
{
_D("control");
// Create a timer to call the given function in given period of time
timer = ecore_timer_add(2.0, my_timed_cb, NULL);
if (!timer) {
_E("Failed to add timer");
return;
}
}
static void service_app_lang_changed(app_event_info_h event_info, void *user_data)
{
/*APP_EVENT_LANGUAGE_CHANGED*/
}
static void service_app_region_changed(app_event_info_h event_info, void *user_data)
{
/*APP_EVENT_REGION_FORMAT_CHANGED*/
}
static void service_app_low_battery(app_event_info_h event_info, void *user_data)
{
/*APP_EVENT_LOW_BATTERY*/
}
static void service_app_low_memory(app_event_info_h event_info, void *user_data)
{
/*APP_EVENT_LOW_MEMORY*/
}
int main(int argc, char* argv[])
{
app_data *ad = NULL;
int ret = 0;
service_app_lifecycle_callback_s event_callback;
app_event_handler_h handlers[5] = {NULL, };
ad = calloc(1, sizeof(app_data));
retv_if(!ad, -1);
event_callback.create = service_app_create;
event_callback.terminate = service_app_terminate;
event_callback.app_control = service_app_control;
service_app_add_event_handler(&handlers[APP_EVENT_LOW_BATTERY], APP_EVENT_LOW_BATTERY, service_app_low_battery, &ad);
service_app_add_event_handler(&handlers[APP_EVENT_LOW_MEMORY], APP_EVENT_LOW_MEMORY, service_app_low_memory, &ad);
service_app_add_event_handler(&handlers[APP_EVENT_LANGUAGE_CHANGED], APP_EVENT_LANGUAGE_CHANGED, service_app_lang_changed, &ad);
service_app_add_event_handler(&handlers[APP_EVENT_REGION_FORMAT_CHANGED], APP_EVENT_REGION_FORMAT_CHANGED, service_app_region_changed, &ad);
ret = service_app_main(argc, argv, &event_callback, ad);
return ret;
}
```
## Timer와 Main loop
타이머는 CPU 및 프로세스에 따라 지연 호출 발생할 수 있습니다. 때문에 정교하고 엄격한 시간을 보장하지 않습니다.

렌더링이 완료된 후 모든 작업이 완료되면 main loop는 다음 루프까지 Idle 상태가 됩니다. 이벤트가 오게되면 main loop은 Idle 상태에서 깨어나 큐에 쌓인 이벤트를 처리합니다. 많은 이벤트를 처리하는 상황인 경우, 의도한 시간에 타이머가 불리지 않을 수 있습니다.
# Appendix
## apps/native/rcc에서 로그 입력하기
Tizen Project에서 로그는 dlog_print를 사용하여 출력할 수 있습니다. 하지만 apps/native/rcc 앱에서는 로그를 쉽게 사용하기 위해 미리 정의한 define문이 존재합니다.
**inc/log.h**

- 정의된 LOG_TAG를 사용하여 출력되는 로그를 필터링할 수 있습니다.
- 다양한 DLOG Enum 값이 있지만 주로 사용하는 DLOG_DEBUG, DLOG_INFO, DLOG_WARN, DLOG_ERROR를 _D, _I, _W, _E로 정의했습니다.
- 예를 들어, Debug 로그를 찍고 싶으면 _D("debug"), Error 로그를 찍고 싶으면 _E("error test %d", i) 처럼 사용하면 됩니다.
- 전체 DLOG Enum 값이 궁금하시면 DLOG_DEBUG을 ctrl + click 해보세요.
## Device Manager를 통해 Shell 실행하기
로그를 보기 위해서는 타이젠 스튜디오 창에서 확인하는 방법도 있지만, Shell을 통해 확인할 수도 있습니다. Shell을 통해 로그 확인하는 방법을 살펴보겠습니다.
타이젠 스튜디오에서 Device Manager를 실행합니다.

이미 보드가 연결되어있기 때문에, 보드와 타이젠 스튜디오가 Connected 상태가 되어있습니다.

Shell을 열고 싶다면 우측의 디렉토리를 보여주는 박스에서 "우클릭 > Open shell"을 실행합니다.

오픈된 Shell에서 'su'를 입력하여 권한을 root 권한으로 변경합니다.
```
$ su (root 권한으로 변경하는 명령어)
Password : tizen (패스워드 타이핑 시에 패스워드는 보이지 않습니다.)
```
SDB로 Shell을 열 수 있는 방법도 있습니다. 아래 링크를 확인하세요.
[Appendix > SDB shell 실행하기](https://craftroom.tizen.org/hackathon-kick-off-a-tizen-project/#sdb-shell-%EC%8B%A4%ED%96%89%ED%95%98%EA%B8%B0)
## dlogutil 사용하기
오픈된 Shell에서 다음의 명령어를 입력하여 로그를 확인할 수 있습니다.
```
$ dlogutil [로그태그] & ('&'은 옵션으로 '&'을 입력하면 다음 줄 입력이 가능합니다.)
```
apps/native/rcc앱의 로그 태그는 RCC이고, 이를 확인하기 위해서는 다음과 같이 입력합니다.
```
$ su (root 권한으로 변경하는 명령어 - 이미 root 권한이라면 'su'는 생략합니다.)
$ dlogutil RCC &
```
로그를 종료하고 싶을때에는 다음 명령을 입력합니다.
```
$ fg ('&' 옵션을 사용했을때만 사용합니다.)
ctrl + c
```
## SDB 사용하기
SDB(Smart Development Bridge)는 Tizen에서 사용하는 Command line tool 입니다. 특정장치에 연결하여 명령을 보내거나, 파일 전송, 원격 shell 명령, 디버깅을 위한 포트 전달, 대상 로그 보기, 필터링 및 제어와 같은 앱개발을 위한 기본 명령을 제공합니다.
> SDB에 대한 보다 자세한 설명은 다음 링크에서 볼 수 있습니다.
> [Connecting Devices over Smart Development Bridge](https://developer.tizen.org/development/tizen-studio/web-tools/running-and-testing-your-app/sdb?langredirect=1)
### SDB 실행하기
우분투에서는 터미널, 윈도우에서는 명령 프롬프트(CMD) 통해 보드와 SDB 통신을 할 수 있습니다.
SDB는 Tizen Studio가 설치되면 <TIZEN_STUDIO>/tools/ 아래에 함께 설치됩니다.
```bash
$ cd <TIZEN_STUDIO>/tools/
$ sdb
```
위의 경로에서 sdb를 실행 할 수 있습니다.
### SDB 환경 변수로 설정하기
sdb를 좀 더 편리하게 실행하기 위해서 sdb를 환경 변수로 설정해줍니다. sdb를 환경 변수로 설정하면 경로 지정없이 어디서든 sdb를 사용할 수 있습니다.
**Windows**
```
1. [내 컴퓨터] 우클릭 > 속성 > [고급 시스템 설정]
2. [환경 변수] 선택
3. 시스템 변수의 Path를 선택한 뒤 [편집]
4. Path에 "C:tizen-studiotools" 추가
5. 터미널 또는 명령 프롬프트(CMD) 재실행
```
**Ubuntu**
```
1. vi ~/.bashrc
2. ~/.bashrc의 맨 아래에 "export PATH=~/tizen-studio/tools:$PATH" 추가
3. source ~/.bashrc 명령어로 변경 사항 적용
```
## SDB shell 실행하기
> SDB를 연결하기 위해서는 먼저 아래 과정으로 SDB를 이해하는 것이 좋습니다.
> [Appendix > SDB 사용하기](https://craftroom.tizen.org/hackathon-kick-off-a-tizen-project/#sdb-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0)
sdb sehll을 실행하기 위해서는 터미널 또는 명령 프롬프트(CMD)에서 sdb shell 명령어를 실행합니다.
sdb shell은 sdb로 연결된 디바이스가 있어야 실행되므로 sdb devices로 미리 연결된 디바이스가 있는지 보고 sdb shell을 실행하는 것이 좋습니다.
```bash
$ sdb devices
$ sdb shell
```
root 권한으로 shell을 실행하는 것은 2가지 방법이 있습니다.
```bash
$ sdb root on
$ sdb shell
```
```bash
$ sdb shell
$ su
Password : tizen (패스워드 타이핑 시에 패스워드는 보이지 않습니다.)
```
## Git에서 프로젝트 가져오기
Tizen Git Repository에 있는 Tizen Project를 가져오는 방법을 소개합니다.
- Tizen Git repository : https://git.tizen.org/cgit/
- 실습에서 사용할 Tizen Project : apps/native/rcc
> Git bash가 PC에 설치되어 있어야 이 과정을 진행할 수 있습니다.
> [Git bash 다운로드](https://git-scm.com/downloads)
>
> Git의 자세한 사용법은 아래 링크를 참고하세요.
> [누구나 쉽게 이해할 수 있는 Git 입문](https://backlog.com/git-tutorial/kr/)
Tizen Git Repository 사이트에 접속합니다.
왼쪽 상단에서 "rcc"를 검색하여 apps/native/rcc 프로젝트를 찾습니다.

### git clone
프로젝트를 로컬 PC로 가져오기 위해서는 git clone 명령어를 사용합니다.
```
$ git clone [git repository 주소]
```
Git repository 주소는 사이트 하단에서 찾을 수 있습니다.

git clone 명령어 뒤에 git repository 주소를 입력하면 해당 프로젝트를 로컬 PC에 다운로드 할 수 있습니다.
```
$ git clone https://git.tizen.org/cgit/apps/native/rcc 또는
$ git clone git://git.tizen.org/apps/native/rcc
```
git bash에서 git clone을 실행한 모습입니다.

> 'git' 네트워크 프로토콜을 사용하는 것이 편리합니다. 'https' 네트워크 프로토콜을 사용하여 git clone 하면, 이후 git push 시 자신의 계정을 확인하는 절차가 포함됩니다.
>
> 네트워크 프로토콜에 대해 더 자세하게 알고 싶다면 다음 링크를 참고하세요.
> [Git 서버 - 프로토콜](https://git-scm.com/book/ko/v1/Git-%EC%84%9C%EB%B2%84-%ED%94%84%EB%A1%9C%ED%86%A0%EC%BD%9C)
### git branch와 git checkout
사이트 상단에는 Branch가 보입니다. 브랜치는 보통 master에서 파생되어 독립적인 작업 영역을 설정합니다. 브랜치를 생성하여 사용하면 동일한 소스코드를 기반으로 여러 개발자들이 동시에 다양한 작업을 할 수 있습니다.
이렇게 만들어진 브랜치는 다른 브랜치와 병합(Merge)함으로써, 작업한 내용을 다시 새로운 하나의 브랜치로 모을 수도 있습니다.
> 브랜치의 자세한 설명이 궁금하시면 아래 링크를 참고하세요
> [브랜치란?](https://backlog.com/git-tutorial/kr/stepup/stepup1_1.html)
해당 강의를 위해 준비한 tizen-iot 브랜치를 확인합니다.

git bash에서 방금 clone 받은 rcc 프로젝트에 들어갑니다. 경로의 오른쪽에는 branch가 표시됩니다. git clone 시 아무런 옵션을 주지 않았기 때문에 master 브랜치에 위치하고 있습니다.

브랜치를 전환하기 위해서는 git checkout 명령어를 사용합니다.
```
$ git checkout [브랜치 이름]
$ git checkout tizen-iot
```
해당 프로젝트가 가지고 있는 전체 브랜치를 보고 싶다면 아래 명령어로 확인 가능합니다.
```
$ git branch -a
```
git bash에서 git checkout과 git branch 명령어를 실행한 모습은 다음과 같습니다.

## RCC
apps/native/rcc의 master 브랜치의 intc/resource, src/resource 디렉토리에는 타이젠에서 다양한 리소스를 쉽게 사용할 수 있도록 구현해놓은 코드가 존재합니다.
모델명 및 프로토콜을 확인하고 사용할 수 있습니다.

Notice
Are you sure to delete this post?
[KOR] Kick off a Tizen Project
1
1
|
Last modified on September 5, 2019
Craft info. | |
Maker |
![]() |
Status | In Progress |
Period | 2019-08-12 ~ 2019-09-21 |
About This Craft | |
[KOR] Hackathon lecture (19/8/17) | |
Making Note