GFDM(Generalized Frequency Domain Multiplexing)

공대생의 팁 2015. 6. 6. 18:42

 무선통신 방식은 하루가 다르게 빠른 속도로 발전하고 있습니다. 현세대의 이동통신인 4세대 이동통신인 LTE의 등장으로 우리나라에서의 휴대전화 데이터 전송 속도가 과거 3G 방식에 비해 매우 빨라졌음을 알 수 있습니다.

 본 포스팅에서는 지난 2014년에 발표된 새로운 개념의 통신방식인 GFDM(Generalized Frequency Domain Multiplexing)에 대해 간단하게 설명해볼까 합니다. 혹시 GFDM에 대해 좀 더 자세히 알고 싶으신 분께서는 출저에 표기된 논문을 읽어보셨으면 합니다.


1. Issue about 5G

 


 그래프는 지금까지 등장한 통신방식들과 그 방식의 속도를 나타내고 있습니다. 연도가 올라갈수록 WLAN과 Cellular 의 통신 속도가 급속도로 빨라지고 있는 경향을 확인할 수 있는데요. 통신 속도가 기하급수적으로 증가하여 오늘날의 통신기술인 LTE 방식을 통해 실시간으로 동영상을 다운로드하며 볼수 있는 환경에 도달할 수 있게 되었습니다.

 앞으로의 5G의 이슈로는 현재보다도 더 빠른 무선통신 환경이 구축될 것이며, 통신시 저전력 전송방식 또한 중요해질 것으로 보입니다. 또한, 통신중 latency의 최소화 또한 5G에서의 이슈가 될 것으로 보입니다.


2.GFDM이란 무엇인가?

 GFDM(Generalized Frequency Division Multiplexing)은 기존에는 없었던 새로운 개념의 다중주파수 전송방식입니다. 기존에 존재하였던 OFDM과 SC-FDE의 방식의 장점들을 유연하게 다루고 있으며 현재 사용되는 방식인 LTE 대역에서도 GFDM이 사용될 수 있다는 것이지요.



  


 시간 대 주파수 그래프를 통해 GFDM의 동작방식에 대해 좀 더 자세히 살펴보도록 하겠습니다. OFDM은 각 주파수 대역 별로 각각 데이터를 전송하는 방식입니다. 이는 각 Subcarrier에 동시간대에 데이터를 전송할 수 있어 짧은 시간에 많은 데이터를 전송할 수 있는 장점을 갖추고 있습니다. OFDM의 최대 단점으로는 전력 소모가 매우크며 ISI(Intersymbol Interference)가 발생할 확률이 높다는 점입니다. 반면, SC-FDE의 경우 전력 소모가 OFDM에 비해 낮으며 그로 인해 역방향 채녈의 커버리지를 넓게 사용이 가능하다는 장점을 가지고 있으나 OFDM에 비해 여전히 데이터 속도와 용량 등 전송 데이터량이 적다는 단점을 가지고 있습니다.




 이러한 OFDM과 SC-FDE의 장점을 아우르고 있는 방식이 바로 GFDM인데요 그 특징을 그래프를 통해 살펴보겠습니다. 보시는 바와 같이 GFDM은 각각의 단위를 독립적인 블록과 같은 개념으로 보실 수 있는데요 각 블록은 Subcarrier와 Sub-symbol로 구성되어 있습니다. 하나의 Subcarrier가 여러개의 Sub-symbol을 전송하는 방식으로 구성되어 있기 때문에 블록 구조는 낮은 latency조건을 설계할 수 있습니다.


3.Details of the GFDM modulator

Block diagram of the transceiver


 위 그림은 GFDM의 송수신과정을 블록 다이어그램으로 나타낸 모습입니다. 겉모습으로 보기에는 다른 전파방식과는 큰 차이가 없어보입니다. 이번에는 GFDM modulator을 살펴보도록 합시다.



 위 그림은 GFDM의 modulator의 내부 동작 방식을 그림으로 나타낸 것입니다. GFDM에 입력되는 N개의 입력값 d[n]이 modulator을 통과하고 있는 모습입니다. GFDM은 해당 입력을 각 Subcarrier에 값을 분산시키며 해당 Subcarrier 내에서도 각각 별개의 Sub-symbol에 값을 적용한 후 값을 전달하는 모습을 나타내고 있습니다. 이 때의 값은 D[K-1][M-1]로 타나나고 있습니다. 이때 각 K와 M의 값은 다음과 같습니다.


N : GFDM에 입력된 값의 총 갯수

K : Subcarrier의 총 갯수

M : Sub-Symbol의 총 갯수


 N개의 입력이 K개의 Subcarrier에 나누어 들어가게 되었으며 또한 각 Subcarrier에는 M개의 Sub-symbol로 나누어져 값이 입력됩니다. 즉, 이는 아래의 공식이 성립됩니다.

N = K × M


 각 Subcarrier에 도달하게 된 데이터값 d는 해당 Subcarrier의 Sub-symbol에 할당되었을 때 d[k][m]에 값이 들어가게 됩니다. 이는 곧 위에서 설명해드린 한 단위의 '블록'이 되는 것이지요. 이렇게 만들어진 각 블록은 이에 해당되는 파형에 적용되는데요 해당 파형의 공식은 다음과 같습니다.




그리고 위의 파형화 블록의 곱을 모두 합하면 전송되는 실제 파형이 만들어지게 됩니다.




 이 때 x[n]의 값이 GFDM을 통해 출력되는 값을 나타냅니다. 위 식은 아래와 같이 간단하게 표현될 수 있습니다.



 이 때 A가 바로 GFDM의 modulation matrix라 할 수 있겠습니다. 입력벡터 d에 modulation matrix를 행렬곱하면 출력값으로 벡터 x가 나온다고 이해하시면 되겠습니다. 아래는 modulation matrix인 A의 값을 그램으로 표현한 모습입니다. 해당 예시의 그림은 4개의 Subcarrier와 7깨의 Sub-Symbol로 구성된 28 × 28 matrix입니다.



 이렇게 GFDM modulation을 통과한 x[n]이 실제 전파될 때는 수신측에서 받게되는 신호 y[n]는 아래의 식으로 표현될 수 있습니다.


 여기서 GFDM 모듈레이터 값인 x와 h는 순환 컨볼루션을 적용한 후 AWGN 값을 더해줍니다. 여기서 AWGN(Additive White Gaussian Noise)이란 노이즈 주파수를 값에 더하여 실제 신호와 같게 만들어 기 위해서 적용하는 값입니다.


4.Details of the GFDM demodulator


 다음으로 GFDM의 demodulator에 대해 살펴보도록 하겠습니다. demodulator에 값을 적용하기 전에 먼저 Frequency Domain Equalization을 통해 새로운 y[n]값을 얻습니다. 


 그렇게 FDE가 적용된 새로운 y[n]값에 Demodulation matrix인 B를 행렬곱하면 수신값 d[n]을 얻게 됩니다.


 여기서 Demodulation matrix인 B의 값을 구하는 방법 3가지를 살펴보도록 하겠습니다.


-Matched Filter Receiver

 이 방식은 애르미드 공액 방식을 활용하는 방식으로 각 서브캐리어 당 SNR 값을 최적화 함으로서 전송 도중 손상되는 데이터 심볼을 회복시키는 것을 목표로 합니다. 단점으로는 ISI와 ICI(Intercarriers Interference) 문제가 발생한다는 점입니다.


-Zero-forcing Receiver

 이 방식은 단순히 modulation matrix A의 역행렬 방식을 취하며 Subcarrier 간의 간섭을 없애는 것을 목표로 하고 있습니다. 이를 통해 ISI와 ICI 문제를 해결할 수 있으나 송신측에서 전송하는 데이터 값에 따라 값이 손실될 가능성이 발생합니다.


-Minimum Mean Square Error Receiver

 이 방식은 이전 두 가지 방식인 Matched Filter Receiver 방식과 Zero-forcing Receiver 방식을 혼합한 방법으로 이 식 자체에 신호를 equalize하는 기능이 포함되어 있기 때문에 Frequency Domain Equalization을 사용하지 않아도 된다는 장점이 있습니다만, 이와 같은 구조는 수신측에서 값을 계산하는 방식이 복잡해진다는 단점을 가지고 있습니다.

 

5. LTE compatibility

 GFDM은 5세대 이동통신으로서의 머물지 않고 현재 4세대 통신기술인 LTE에도 이론적으로 적용할 수 있다는 특징을 가지고 있습니다. 이러한 GFDM의 특성을 활용한다면 이전 세대에서 사용하던 기술들을 혼용함으로서 혼합형 디바이스를 설계하는 것이 좀 더 수월해질 수 있습니다. GFDM의 주파수를 현재 운용중인 LTE의 클럭주파수인 30.72MHz를 활용하면 LTE의 시간-주파수 grid를 사용할 수 있습니다. 또한, 이렇게 적용된 GFDM 방식을 통해 기존 LTE 방식에서도 좀더 짫은 Latency를 기대할 수 있게 됩니다.


 GFDM 방식이 LTE에 적용되는 방법을 설명하기에 앞서 먼저 LTE의 프레임 구조를 살펴보도록 하겠습니다. 그림에서 보시는 바와 같이 LTE는 프레임 단위로 단말기와 통신을 하고 있는 것을 확인하실 수 있습니다. 하나의 프레임은 10개의 서브프레임으로 구성되어 있으며, 서브프레임은 2개의 슬롯으로 이루어져 있으며 해당 슬롯은 Cyclic prefix와 심볼로 구성되어 있음을 확인하실 수 있습니다.


- LTE-FDD 방식에서의 OFDM


CP : 16μs

Symbol : 66.7μs

 LTE 기술 중 하나인 LTE-FDD 방식에 대해 살펴보도록 하겠습니다. 위 그림에서 보시는 바와 같이 LTE-FDD 방식은 여러개의 Subcarrier를 활용하는 OFDM 방식을 사용하고 있음을 확 수 있습니다. Cyclic prefix의 간격은 16μs이며, 각 심볼은 66.7μs입니다. GFDM 방식과 비교하였을 때, LTE-FDD 방식의 단점으로는, 각 Symbol이 만들어질 때 마다 Cyclic prefix가 사용되어지고 있으며, 이는 전송시 Frame의 간격을 최대한으로 줄일 수 없어 Latency 문제가 발생하게 됩니다.


- GFDM 방식이 적용된 LTE-FDD

CP : 4.17μs

Subsymbol : 4.17μs

 그렇다면 LTE 통신방식에 GFDM을 적용하였을 때 어떤 효과가 나타나는지 보도록 하겠습니다. 보시는 바와 같이 스펙적인 면에서 확인하였을 때, Cyclic prefix와 Symbol이 4.17μs로 눈에 띄게 줄어들었음을 확인하실 수 있습니다. GFDM의 경우 LTE-FDD와는 달리 여러개의 Subsymbol을 하나의 Cyclic prefix를 통해 전송하는 것이 가능하며, Symbol duration을 무려 7.5배 작게 할 수 있기 때문에 전송시 프레임 단위 하나의 duration을 줄일 수 있습니다. 즉, 이는 무선통신시의 Latency를 확연히 줄일 수 있어 이론적으로 통신 속도가 증가함을 알 수 있습니다.


 GFDM이 OFDM을 대체하게 되었을 경우 얻을 수 있는 또 다른 장점으로는 Out-of-Base emission을 줄일 수 있다는 점입니다. 여기서 Out-of-Base emission이란 통신시 자신에게 해당되는 대역폭을 벗어난 주파수 영역으로 데이터가 전송되는 현상으로 이는 신호간의 간섭을 유발할 수 있습니다. 특히 각 주파수 대역별로 근접해 있는 OFDM의 경우 Out-of-Base emission에 취약하다는 단점을 가지고 있습니다. 반면 GFDM은 시간-주파수 영역이 블록 단위로 구성되어 있고 이 구조는 순환적으로 변하기 때문에 Out-of-Base emission 문제를 해결할 수 있습니다. 이렇게 GFDM이 오늘날의 통신 방식인 LTE에 적용하였을 때에도 상당히 효율이 높아질 것으로 기대할 수 있겠습니다.


- Conclusion

 GFDM 방식은 기존의 통신방식인 LTE에서도 적용할 수 있어 이전 세대의 통신방식을 아우를 수 있는 기존에는 없던 새로운 방식이라는 점이 상당히 매력적입니다. GFDM의 특성으로 Latency 이슈가 해결된다면 머지않은 미래에는 촉감 인터넷(Tactile Internet)과 같이 기존의 방식으로는 구현하기 힘들었던 분야가 새롭게 부상할 것으로 보입니다. 또한, MIMO와 같이 GFDM 또한 잠재적인 5G 시대의 기술이 될 것으로 기대됩니다.


- Reference

1. I.Gaspar, L.Mendes, M.Matthe, N.Michailow, A.Festag, G.Fettweis, "LTE-compatible 5G PHY base on Generalized Frequency Division Multiplexing", Wireless Communications Systems (ISWCS), 2014 11th International Symposium, pp. 209 - 213, 26-29 Aug. 2014


2. N. Michailow, M.Matthe, I.S.Gaspar, A.N.Caldevilla, L.L.Mendes, A.Festag, G.Fettweis, "Generalized Frequency Division Multiplexing for 5th Generation Cellular Networks", IEEE Transactions Communications, Vol.62, pp.3045 - 3061, Sept. 2014

300x250

TIZEN Native 단계에서 LOG를 활용해보자!

공대생의 팁 2015. 6. 5. 23:59

 프로그래머로서 코딩을 할 때 가장 중요한 요소가 무엇이냐 누군가가 묻는다면 저는 자신의 결과물을 직접 확인할 수 있는 LOG를 보는 것이라고 말하고 싶군요. 프로그램을 제작하던 도중 잘못된 동작을 하는 부분이 어떠한 문제가 있는지 알고 싶을 때 이 LOG가 어떤 때보다 가장 빛을 발하게 되지요!

 특히 안드로이드의 경우 logcat(로그캣)이라는 기능이 있어 자신이 제작한 프로그램의 로그를 손쉽게 확인할 수 있는 기능을 갖추고 있습니다.


 이토록 편리한 로그캣과 같은 기능이 TIZEN에서도 사용이 가능할까요? 정답을 말씀드리자면 Yes입니다. 다만, Android의 로그캣을 쓰는 것 처럼 Java 단계에서 손쉽게 로그를 보는 방식이 아니라는 점이 상당히 아쉬운 부분입니다.




 어찌보면 타이젠의 SDK도 안드로이드의 로그캣을 밴치마킹한 듯 비슷해 보이지만 아무쪼록 TIZEN의 Native 단계에서 로그를 확인하는 방법을 살펴보도록 하겠습니다!


#include <dlog.h>

TIZEN의 Native 단계에서 로그를 확인하고 싶을 때 해당 소스코드에 dlog.h를 include 해줍니다.


int      dlog_print (log_priority prio, const char *tag, const char *fmt,...)


이 부분에서 자신이 출력하고자 하는 내용을 입력합니다.


log_priority prio

log_priority 부분에는 해당 로그의 속성을 설정합니다. 로그 속성의 종류는 다음과 같습니다.


DLOG_DEBUG    : 개발자가 확인해보고자 하는 내용

DLOG_INFO         : 일반적인 정보 메시지. 이 로그는 항상 출력됩니다.

DLOG_WARN      : 에러는 아니지만 의도하지 않은 에러가 발생할 가능성이 있을 때 나타나는 메시지. 이 로그는 항상 출력됩니다.

DLOG_ERROR     : 에러 발생시 출력. 이 로그는 항상 출력됩니다.


대략적으로 로그의 속성들은 위와 같이 정의되고 있습니다만, 자신이 쓰고 싶은 속성을 선택하시면 해당 선택사항대로 로그가 출력됩니다.


const char *tag

 해당 로그의 태그를 입력합니다 태그를 설정해두면 이후 자신이 찾고자 하는 로그를 확인하는 것이 수월해집니다.


const char *fmt,...

 해당 로그에서 출력하고자 하는 메시지를 입력합니다.


 위에서 설명드린 dlog_print() 함수를 적절히 사용하신다면 TIZEN의 Native 환경에서 로그를 보는 것이 상당히 수월해질 것입니다. 혹시 출력하고자 하는 메시지가 있다면  sprintf() 함수를 통해 출력하고자 하는 내용을 설정해 주시면 되겠습니다.


 아래는 dlog_print() 함수가 적용된 예제와 그 결과를 나타내고 있습니다. 아래의 소스코드를 참조하시고 여러분들도 TIZEN Native 프로그레밍이 한층 더 수월하게 진행되셨으면 합니다!


/framework/system/deviced/src/display/core.c
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include <dlog.h>
#include <signal.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <vconf-keys.h>
#include <Ecore.h>
 
....
 
static int default_trans(int evt)
{
    struct state *st = &states[pm_cur_state];
    int next_state;
 
    next_state = (enum state_t)trans_table[pm_cur_state][evt];
 
 
    sprintf(pbuffer,"current state : %d, next state : %d, evt : %d", pm_cur_state ,next_state, evt);
    dlog_print(DLOG_INFO, "USR_TAG", pbuffer);
 
    /* check conditions */
    while (st->check && !st->check(next_state)) {
        /* There is a condition. */
        if (standby_mode) {
            _D("standby mode, goto next_state %s",
                state_string[next_state]);
            break;
        }
        _I("%s -> %s : check fail", state_string[pm_cur_state],
               state_string[next_state]);
        if (!check_processes(next_state)) {
            /* this is valid condition - the application that sent the condition is running now. */
            return -1;
        }
    }
 
    /* smart stay */
    if (display_info.face_detection &&
        (pm_status_flag & SMAST_FLAG) && hallic_open) {
        if (display_info.face_detection(evt, pm_cur_state, next_state))
            return 0;
    }
 
    /* state transition */
    pm_old_state = pm_cur_state;
    pm_cur_state = next_state;
    st = &states[pm_cur_state];
 
    /* enter action */
    if (st->action) {
        if (pm_cur_state == S_LCDOFF)
            update_lcdoff_source(VCONFKEY_PM_LCDOFF_BY_TIMEOUT);
 
        if (pm_cur_state == S_NORMAL || pm_cur_state == S_LCDOFF)
            if (set_custom_lcdon_timeout(0== true)
                update_display_time();
 
        if (check_lcdoff_direct() == true) {
            /* enter next state directly */
            states[pm_cur_state].trans(EVENT_TIMEOUT);
        }
        else {
            st->action(st->timeout);
        }
    }
 
    return 0;
}
cs



/framework/system/deviced/src/display/device-interface.c

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <dlog.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include <math.h>
#include <journal/display.h>
 
....
 
static int _bl_brt(PMSys *p, int brightness, int delay)
{
    int ret = -1;
    int cmd;
    int prev;
    char pbuffer[100];
 
    sprintf(pbuffer,"bright : %d, delay : %d", brightness, delay);
    dlog_print(DLOG_INFO, "USR_TAG", pbuffer);
 
    if (delay > 0)
        usleep(delay);
 
    if (force_brightness > 0 && brightness != p->dim_brt) {
        _I("brightness(%d), force brightness(%d)",
            brightness, force_brightness);
        brightness = force_brightness;
    }
 
    cmd = DISP_CMD(PROP_DISPLAY_BRIGHTNESS, DEFAULT_DISPLAY);
    ret = device_get_property(DEVICE_TYPE_DISPLAY, cmd, &prev);
 
    /* Update new brightness to vconf */
    if (!ret && (brightness != prev)) {
        vconf_set_int(VCONFKEY_PM_CURRENT_BRIGHTNESS, brightness);
    }
 
    /* Update device brightness */
    ret = device_set_property(DEVICE_TYPE_DISPLAY, cmd, brightness);
 
    _I("set brightness %d, %d", brightness, ret);
 
    return ret;
}
cs


Native 단계에서 위와 같이 설정을 해주셨다면 아래와 같이 자신이 설정한 프로그램의 진행중인 값을 로그를 통해 실시간으로 확인하실 수 있습니다.

(아래 스크린샷의 경우 필자가 내용을 수정하였기 때문에 각자의 환경에서는 로그가 다른 결과로 출력됩니다.)




300x250

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