Tizen Mobile Native App Programming - 네이티브 센서 예제 분석

공대생의 팁 2015. 5. 26. 13:13

 타이젠의 Web 애플리케이션 제작은 개발자가 약간의 직감으로 마치 안드로이드의 XML을 꾸미듯이 작업을 하는 것이 용이합니다만 Native 단계에서 애플리케이션을 제작하려면 무식하게도 C와 C++을 통해 애플리케이션을 설계해야 하지요. 물론 안드로이드에서도 JAVA 소스코드로 UI를 디자인 하는 경우도 있지만 왠만해선 XML를 많이 사용하긴 하죠.


 본 포스팅에서는 타이젠의 Native 애플리케이션의 예제 중 하나인 SensorApp Sample을 예를 들어 설명해 나가도록 하겠습니다.


 SensorApp 샘플 애플리케이션은 타이젠 기반의 디바이스 내의 센서들의 동작을 확인할 수 있도록 만들어져있습니다. 일단 실행을 해보면 대략 어떠한 방식으로 애플리케이션이 센서값을 받고 있는지 짐작하실 수 있을 것입니다.



타이젠 SensorApp 예제의 소스코드는 다음과 같이 구성되어 있습니다.(버전은 2.3.3 기준)






각 소스의 내용을 살펴보면 다음과 같습니다.


General


main.c

SensorApp의 시작포인트를 제공합니다. 애플리케이션의 instance를 생성한 후 실행합니다.


main-app.c

애플리케이션 life-cycle을 관리합니다. 애플리케이션의 main window, naviframe, 센서 리스트의 view를 생성합니다.


Utils


logger.h

로고 메시지를 작성하기 위한 매크로를 제공합니다.


color-utils.h

integer 값으로 저장된 color값에 대한 매크로를 제공합니다.


Model


sensor-info.h

각각의 센서에 대한 데이터 타입을 정의합니다.


sensor-list.h

SensorApp에서 제공하는 센서 리스트를 정의합니다.


sensor-magnetic.c

마그네틱 센서의 세기값을 계산하는 알고리즘을 정의합니다.


View


window.c

애플리케이션의 main window를 담당합니다.


sensor-list-view.c

센서의 리스트뷰를 제공합니다.


snesor-data-view.c

센서로부터 받은 데이터값과 그 값을 그래픽으로 표현하는 부분을 담당합니다.


sensor-data-chart.c

기본적인 데이터의 그림 기능을 정의합니다.


snesor-data-chart-private.h

벡터나 앵글값을 나타내는 챠트에 대한 센서 데이터값을 정의합니다.


snesor-vector-chart.c

화살표를 사용한 벡터값을 그려주는 일을 수행합니다.


sensor-angle-chart.c

각도값을 활용하여 pie chart를 그리는 역할을 합니다.



다음은 SensorApp 애플리케이션이 구현되는 과정을 나타내 보겠습니다.


1. 먼저 Sensor API의 헤더를 등록합니다.

1
#include <sensor.h>
cs


2. 다음으로 센서의 핸들값과 하드웨어의 정보를 검색합니다.

sensor-list.c 코드 내에 있는 sensor_list_init() 함수는 센서의 핸들값과 하드웨어의 정보를 검색한 후 이를 sensor_info 배열에 저장합니다. 검색된 센서의 정보는 이후 센서 데이터를 표현하는데 사용됩니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void sensor_list_init()
{
   sensor_info *info = sensors;
   sensor_info *end = info + sensor_count;
   for (; info != end; ++info)
   {
      float resolution = 1.0;
      // Retrieve sensor handle using sensor type
      sensor_get_default_sensor(info->type, &info->sensor);
      // Retrieve sensor minimal and maximal values
      sensor_get_min_range(info->sensor, &info->value_min);
      sensor_get_max_range(info->sensor, &info->value_max);
      // Retrieve sensor resolution
      sensor_get_resolution(info->sensor, &resolution);
   }
}
cs


<sensor-info.h> 헤더파일은 센서의 리스트와 데이터를 표현하는 데에 사용될 센서에 대한 정보를 저장하기 위한 자료구조를 정의합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
struct _sensor_info
{
   sensor_h sensor; // Sensor handle
   sensor_type_e type; // Sensor type
   sensor_unit_e units; // Value measurement units
 
   const char *name; // Sensor display name
   const char **value_names; // Value names array of value_count size
   int value_count; // Values count
 
   float value_min; // Minimal value
   float value_max; // Maximal value
};
cs


3. 센서의 유효성을 확인합니다.

sensor-list-view.c 파일은 sensor-list.c 파일에 의해 제공되는 센서 리스트들을 사용하는 elm_list 를 생성합니다. 센서의 리스트들이 채워지는 동안, _list_view_fill() 함수는 sensor_is_supported() 함수를 통해 디바이스의 센서 들이 사용가능한지에 대한 여부를 체크합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
static void _list_view_fill(list_view *view)
{
   unsigned count = 0;
   const sensor_info *item = sensor_list_get(&count);
   const sensor_info *end = item + count;
 
   RETM_IF(!item, "item is NULL");
   for (; item != end; ++item)
   {
      bool is_supported = false;
      // Check whether sensor is supported by device
      sensor_is_supported(item->type, &is_supported);
      if (is_supported)
      {
         elm_list_item_append(view->list, item->name, NULL, NULL, _list_view_sel_cb, item);
      }
   }
}
cs


어떤 센서가 선택되었을 때,  _list_view_sel_cb() 함수가 선택된 함수 정보를 보내 센서의 데이터를 찾습니다.

1
2
3
4
5
6
static void _list_view_sel_cb(void *data, Evas_Object *obj, void *event_info)
{
   sensor_info *item = data;
 
   sensor_data_view_create(view->navi, item);
}
cs


4. 센서 데이터를 수신합니다.

 센서 데이터의 수신을 시작할 때, _data_view_sensor_start() 함수가 센서의 listener를 등록한 후, 센서의 event callback를 설정한 다음, 센서의 동작을 개시합니다.

1
2
3
4
5
6
7
8
static void _data_view_sensor_start(data_view *view)
{
   sensor_error_e err = SENSOR_ERROR_NONE;
   err = sensor_create_listener(view->sensor_info->sensor, &view->sensor_listener);
   RETM_IF(err != SENSOR_ERROR_NONE, "sensor_create_listener() failed(%d)", err);
   sensor_listener_set_event_cb(view->sensor_listener, SENSOR_INTERVAL, _data_view_sensor_cb, view);
   sensor_listener_start(view->sensor_listener);
}
cs


_data_view_sensor_cb() 센서 이벤트 callback 함수가 호출되었을 때, _data_view_value_items_update() 함수가 수신된 센서의 데이터값을 chart에 적용합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
static void _data_view_sensor_cb(sensor_h sensor, sensor_event_s *sensor_data, void *user_data)
{
   data_view *view = user_data;
 
   _data_view_value_items_update(view, sensor_data->values);
   _data_view_extra_items_update(view, sensor_data->values);
}
 
static void _data_view_value_items_update(data_view *view, float *values)
{
   bool update_chart = false;
 
   // Update genlist items with values received from the sensor
   for (; item != end; ++item, ++value)
   {
      if (item->value != *value)
      {
         // Chart MUST be updated if any value has changed
         update_chart = true;
         item->value = *value;
         // Update genlist item part that displays value
         elm_genlist_item_fields_update(item->obj_item, PART_VALUE, ELM_GENLIST_ITEM_FIELD_TEXT);
      }
   }
 
   // Update chart if necessary
   if (view->chart && update_chart)
   {
      sensor_data_chart_update(view->chart, view->sensor_info->value_range,
         view->sensor_info->axes, values, data_view_item_colors,
         view->sensor_info->value_count);
   }
}
cs


5. 센서의 동작을 중단합니다.

센서 데이터의 view가 destroy 상태가 되었을 때, 센서의 데이터값 수신을 중단하기 위해, _data_view_destroy_cb() 함수가 sensor_listener_stop() 함수를 호출하고 난 후 sensor_destroy_listener() 함수를 사용하여 listener를 중단시킵니다.

1
2
3
4
5
static void _data_view_destroy_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
{
   sensor_listener_stop(view->sensor_listener);
   sensor_destroy_listener(view->sensor_listener);
}
cs




Reference : Tizen Help guide

300x250