2015. 2. 27.

#ifdef 란?

  #define은 PI = 3.141592 처럼 어떤 고정된 숫자를 정의할 때 자주 쓰곤 했다.
그런데 .h 헤더파일에서 #ifdef란 것이 쓰이는 것을 알 수 있었다. 이것은 무엇일까?

 아래 <그림1>과 같이 컴파일을 할 때 여러 .c파일이 하나의 .h파일을 쓴다고 하자.  이들은 나중에 하나의 .o 파일이 될것이다.
그런데 컴파일을 하게 되면 사실 .h파일과 .c파일이 하나로 묶이게 되는데, 불필요하게 3개 모두 같은 걸 묶을 필요가 없고 또한
컴파일러에 따라 같은 이름의 .h를 쓰기 때문에 오류가 난다. <그림2>와 같은 상황이 되어 버리는 것이다.
 따라서 #ifdef를 쓰자. 이것을 쓰게 되면 .c파일 중 어느 하나만 .h와 묶이게 되어 중복을 피하게 된다. 아래와 같은 방법으로 사용하면 된다.


#ifndef __CJM_H //컴파일러가 이전에 define된 것이 있는지 확인하고 있다면 걍 end_if로 간다.
#define __CJM_H //없다면 새로 define을 한다.

...

#end_if //__CJM_H
<그림1>



<그림2>

2015. 2. 26.

has modification time ~~s in the future. Clock skew detected. - 해결법

make를 하려고 하는데 저런 문구가 나온다. 미래에 수정이 되었다고?!

이것은 내가 가지고 있는 시스템의 시각이 파일의 수정된 시각보다 과거로 맞추어져 있기 때문이다.
국제표준시각이나 개인이 맞춘 시각등에 의해서 상대적으로 미래에 수정된 파일을 make하려고 하면 저렇게 된다.
이럴땐 

touch *

명령어를 입력하여 각 파일들의 엑세스 및 수정시간을 현재시간으로 맞춘다.

그리고 다시 make를 하면 잘 된다.

2015. 2. 24.

Xenomai의 성능비교

 Xenomai는 리눅스에서 실시간 처리가 보장되도록 하는 역할을 하게 된다.
이번에는 Xenomai에서 제공하는 예제인 trival-periodic과 리눅스 제공 함수인 CLOCK_gettime()을 이용한 예제를 가지고 비교를 해보겠다.


<< trivial-periodic.c 예제 >>

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <sys/mman.h>

#include <native/task.h>
#include <native/timer.h>

RT_TASK demo_task;

/* NOTE: error handling omitted. */

void demo(void *arg)
{
RTIME now, previous; //RTIME 변수 선언

/*
* Arguments: &task (NULL=self),
*            start time,
*            period (here: 1 s)
*/
rt_task_set_periodic(NULL, TM_NOW, 1000000000); //1초짜리 주기를 갖는 테스크 set
previous = rt_timer_read(); //현재 시간 저장

while (1) {
rt_task_wait_period(NULL); //한 주기가 끝날 때 까지 기다림
now = rt_timer_read(); //현재 시간 저장

/*
* NOTE: printf may have unexpected impact on the timing of
*       your program. It is used here in the critical loop
*       only for demonstration purposes.
*/
rt_printf("Time since last turn: %ld.%06ld ms\n",
      (long)(now - previous) / 1000000,
      (long)(now - previous) % 1000000); //시간 차이 출력

      previous = now; //'현재' -> '과거'로 업데이트
}
}

void catch_signal(int sig)
{
}

int main(int argc, char* argv[])
{
signal(SIGTERM, catch_signal);
signal(SIGINT, catch_signal);

/* Avoids memory swapping for this program */
mlockall(MCL_CURRENT|MCL_FUTURE); //메모리 lock

rt_print_auto_init(1);

/*
* Arguments: &task,
*            name,
*            stack size (0=default),
*            priority,
*            mode (FPU, start suspended, ...)
*/
rt_task_create(&demo_task, "trivial", 0, 99, 0); //위에서 만든 테스크로 테스크 생성

/*
* Arguments: &task,
*            task function,
*            function argument
*/
rt_task_start(&demo_task, &demo, NULL); //테스크 시작

pause();

rt_task_delete(&demo_task);

return 0;
}

- 결과 - 









<< gettime.c 예제 >>

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <time.h>

#define BILLION 1000000000L

int loclapid(void){
static int a[9] = {0};
return a[0];
}

main (int argc, char **argv)
{
while(1)
{
uint64_t diff;
struct timespec start, end;
int i;

clock_gettime(CLOCK_MONOTONIC, &start); //현재 시간 저장
sleep(1); //1초간 sleep
clock_gettime(CLOCK_MONOTONIC, &end); //현재 시간 저장

             //시간 차 출력 (MONOTONIC)
diff = BILLION * (end.tv_sec - start.tv_sec) + end.tv_nsec -start.tv_nsec;
printf("MONOTONIC       = %11u nanosec\n", (long long unsigned int) diff );
printf("start : %10ld sec, %06ld nanosec\n",(long int)start.tv_sec, (long int)start.tv_nsec);
printf("end   : %10ld sec, %06ld nanosec\n",(long int)end.tv_sec, (long int)end.tv_nsec);

clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start);
sleep(1);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end);
           
             //시간 차 출력 (Process_CPUTime)
diff = BILLION * (end.tv_sec - start.tv_sec) + end.tv_nsec - start.tv_nsec;
printf("Process_CPUTime = %11u nanosec\n", (long long unsigned int) diff );
printf("start : %10ld sec, %06ld nanosec\n",(long int)start.tv_sec, (long int)start.tv_nsec);
printf("end   : %10ld sec, %06ld nanosec\n",(long int)end.tv_sec, (long int)end.tv_nsec);


clock_gettime(CLOCK_REALTIME, &start);
sleep(1);
clock_gettime(CLOCK_REALTIME, &end);

             //시간 차 출력 (RealTime)
diff = BILLION * (end.tv_sec - start.tv_sec) + end.tv_nsec - start.tv_nsec;
printf("RealTime        = %11u nanosec\n", (long long unsigned int) diff );
printf("start : %10ld sec, %06ld nanosec\n",(long int)start.tv_sec, (long int)start.tv_nsec);
printf("end   : %10ld sec, %06ld nanosec\n\n",(long int)end.tv_sec, (long int)end.tv_nsec);

}
}

- 결과 -


CLOCK종류에 따라 시간 기준이 다른 것을 알 수 있다.



  위의 예제는 단위가 밀리초, 아래 예제는 단위가 나노초 단위이기 때문에 단위 환산을 하여 비교해야 한다. 

 그런데 결과는 이론과는 다르게 어째 제노마이가 더 보장되지 않는 것이냐ㅠㅠ
시간을 늘려서 해보아도 같은 결과이다...


출처 :
https://www.cs.rutgers.edu/~pxk/416/notes/c-tutorials/gettime.html
https://xenomai.org/documentation/trunk/html/api/trivial-periodic_8c-example.html

2015. 2. 23.

리눅스 함수 - clock_gettime

 리눅스에서 시간을 측정하는 함수로 clock_gettime이 있다. 아래와 같이 사용하면 된다.

#include <time.h>

int clock_gettime(clockid_t clk_id, struct timespec *tp);



위 함수에서 두번째 인자는 아래의 구조체인데 시간값을 저장할 때 쓴다. <time.h>에서 제공 하는듯..

struct timespec{
   time_t  tv_sec; /초
   long    tv_nes; /나노초
}



이때 첫번째 인자는 여러가지 종류를 쓸 수 있고 상황에 따라 알맞은 것을 쓰면 된다.

clock IDmeaning
CLOCK_REALTIMESystem-wide real-time clock. This clock is supported by all implementations and returns the number of seconds and nanoseconds since the Epoch. This clock can be set viaclock_settime but doing so requires appropriate privileges. When the system time is changed, timers that measure relative intervals are not affected but timers for absolute point in times are.
CLOCK_REALTIME_COARSE (Linux-specific)Faster than CLOCK_REALTIME but not as accurate.
CLOCK_MONOTONICRepresents monotonic time since some unspecified starting point. This clock cannot be set.
CLOCK_MONOTONIC_RAW (Linux-specific)Similar to CLOCK_MONOTONIC, but provides access to a raw hardware-based time that is not subject to NTP adjustments.
CLOCK_MONOTONIC_COARSE (Linux-specific)Like CLOCK_MONOTONIC but faster and not as accurate.
CLOCK_PROCESS_CPUTIME_IDHigh-resolution per-process timer from the CPU.
CLOCK_THREAD_CPUTIME_IDThread-specific CPU-time clock.

CLOCK_REALTIME : 시스템 전역의 실제 시계(Epoch 시간)이다. 이 clock은 특권을 통해 clock_settime으로 set이 가능하다. 시스템 시간이 변경되었을 때 상대적인 인터벌 측정 타이머는 영향을 안받지만 절대적 시간 타이머는 영향을 받는다고 한다.

CLOCK_REALTIME_COARSE : 위 clock보다 빠르지만 정확하진 않다.

CLOCK_MONOTONIC : 어떠한 특정 시점(보통 부팅부터 시작)부터 흐른 시간을 나타낸다. set이 불가능하다.

CLOCK_MONOTONIC_RAW : 위와 비슷하지만 NTP에 전혀 영향을 받지 않는 raw hardware-based time에 대한 접근이 가능하다.

CLOCK_MONOTONIC_COARSE : MONOTONIC과 비슷하지만 빠르고 부정확하다.

CLOCK_PROCESS_CPUTIME_ID : 프로세스 단위 CPU 사용 시간.

CLOCK_THREAD_CPUTIME_ID : 쓰레드 단위 CPU 사용 시간




  만약 시간이 흐른 것을 측정하려면 CLOCK_MONOTONIC을 추천한다. 왜냐하면 CLOCK_REALTIME과 다르게 선형적으로 증가하는 것을 보장하기 때문이다. NTP deamon에 의해 영향을 받지만 시간조정 후에 앞이나 뒤로 이동하는 CLOCK_REALTIME과는 다르게 CLOCK_MONOTONIC은 jump하지 않고 끌려내려오는(clock drift)에 의해 보상이 되기 때문.

  CLOCK_MONOTONIC_RAW는 짦은 프로그램에는 괜찮지만 긴 주기를 가지고 있는 프로그램에서는 오차가 발생할 수 있다.

  CLOCK_PROCESS_CPU_TIME_ID 는 오직 프로세스에 의해 소비되는 CPU 시간을 측정한다. 만약 커털이 프로세스를 sleep상태로 해놓았다면 waiting하는 시간은 측정하지 않는다. 만약 프로세스가 multiple threads라면 CLOCK_THREAD_CPUTIME_ID가 비슷한 역할을 하긴 하는데 요구가 이쓴 쓰레드에 대해서만 소비한 CPU 시간을 측정한다.





아래는 예제이다. ( gcc -o gettime gettime.c -lrt )
컴파일 할때는 -lrt를 붙여줘야 한다. (라이브러리를 참조해야하나 보다.)


#include <stdio.h> /* for printf */
#include <stdint.h> /* for uint64 definition */
#include <stdlib.h> /* for exit() definition */
#include <time.h> /* for clock_gettime */

#define BILLION 1000000000L

int localpid(void) {
static int a[9] = { 0 };
return a[0];
}

main(int argc, char **argv)
{
uint64_t diff;
struct timespec start, end;
int i;

/* measure monotonic time */
clock_gettime(CLOCK_MONOTONIC, &start); /* mark start time */
sleep(1); /* do stuff */
clock_gettime(CLOCK_MONOTONIC, &end); /* mark the end time */

diff = BILLION * (end.tv_sec - start.tv_sec) + end.tv_nsec - start.tv_nsec;
printf("elapsed time = %llu nanoseconds\n", (long long unsigned int) diff);

/* now re-do this and measure CPU time */
/* the time spent sleeping will not count (but there is a bit of overhead */
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start); /* mark start time */
sleep(1); /* do stuff */
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end); /* mark the end time */

diff = BILLION * (end.tv_sec - start.tv_sec) + end.tv_nsec - start.tv_nsec;
printf("elapsed process CPU time = %llu nanoseconds\n", (long long unsigned int) diff);

exit(0);
}



 1초간 sleep를 하고 시간을 측정하는 것인데 각 CLOCK마다 다른 결과값이 나온다.
이론적으로는 CLOCK_PROCESS_CPU_TIME_ID은 waiting일 때 시간을 측정하지 않으므로 대체로 더 작은 값이 나와야한다.



출처 :
https://www.cs.rutgers.edu/~pxk/416/notes/c-tutorials/gettime.html

Raspberry pi에 Xenomai 설치하기

라즈베리파이(RPi)에 제노마이 설치를 하겠습니다.

 RPi에서 컴파일을 하려면 많은 시간이 필요하므로 일반적인 컴퓨터에서 모든 작업을 한 후
라즈베리파이에는 마지막에 이미지파일만 바꿔치기 하겠습니다.


1. 커널 빌드와 menuconfig 하기 위한 패키지 설치

sudo apt-get update
sudo apt-get upgrade
sudo apt-get install ncurses-dev
sudo apt-get install kernel-package
sudo apt-get install ia32-libs


2. working 이라는 디렉토리를 만들고 그 안에 tool 다운 후 압축 해제
wget https://github.com/raspberrypi/tools/archive/master.tar.gz
tar xzf master.tar.gz


3. kernel 다운로드
git clone -b rpi-3.8.y --depth 1 git://github.com/raspberrypi/linux.git linux-rpi-3.8.y


4. xenomai 다운로드
git clone git://git.xenomai.org/xenomai-head.git xenomai-head


5. minimal config 다운로드
wget https://www.dropbox.com/s/dcju74md5sz45at/rpi_xenomai_config


6. 패치 적용(버젼 숫자는 다를 수 있으므로 확인할 것)
cd linux-rpi-3.8.y

patch -Np1 < ../xenomai-head/ksrc/arch/arm/patches/raspberry/ipipe-core-3.8.13-raspberry-pre-2.patch

cd ..

xenomai-head/scripts/prepare-kernel.sh --arch=arm --linux=linux-rpi-3.8.y --adeos=xenomai-head/ksrc/arch/arm/patches/ipipe-core-3.8.13-arm-4.patch

cd linux-rpi-3.8.y

patch -Np1 < ../xenomai-head/ksrc/arch/arm/patches/raspberry/ipipe-core-3.8.13-raspberry-post-2.patch


7. 위 과정으로 리눅스 커널에 제노마이가 설치 되었고 이제 리눅스를 빌드한다

mkdir linux-rpi-3.8.y/build


미리 만들어진 config 파일 사용

cp rpi_xenomai_config linux-rpi-3.8.y/build/.config
cd linux-rpi-3.8.y
make mrproper
make ARCH=arm O=build oldconfig


컴파일

make ARCH=arm O=build CROSS_COMPILE=../../tools-master/arm-bcm2708/arm-bcm2708hardfp-linux-gnueabi/bin/arm-bcm2708hardfp-linux-gnueabi-

모듈 설치

make ARCH=arm O=build INSTALL_MOD_PATH=dist modules_install

헤더 설치

make ARCH=arm O=build INSTALL_HDR_PATH=dist headers_install

find build/dist/include \( -name .install -o -name ..install.cmd \) -delete


8. USB FIQ 설치
cd working

패치 다운로드

wget https://gist.githubusercontent.com/kinsamanka/10256843/raw/4d5d3e02a443e4d17d9b82a1fe027ef17fb14470/usb_fiq.patch


패치 적용

cd linux-rpi-3.8.y

patch -p1 < ../usb_fiq.patch


커널 재컴파일

make ARCH=arm O=build CROSS_COMPILE=../../tools-master/arm-bcm2708/arm-
bcm2708hardfp-linux-gnueabi/bin/arm-bcm2708hardfp-linux-gnueabi-



9. 라즈베리파이로 이동!

 이제 빌드된 이미지 파일(zImage)은 linux-rpi-3.8.y/build/arch/arm/boot/ 에 위치하게 된다. 이 파일을 라즈베리파이의 /boot(fat32파티션)에 있는 kernel.img와 바꾸면 된다.
바꿀 시에는 확장자를 img로 바꾸고 이름도 kernel로 바꾸어야 한다.

또한 자신이 작업할 폴더에 리눅스에서 작업했던 xenomai-head 폴더와 linux-rpi-3.8.y/dist/lib 를 가져온다.

sudo cp lib / -r
cd xenomai-head
./configure
make
sudo make install
sudo reboot

이제 제노마이가 설치되었고 테스트 하기 위해 latency를 실행.

sudo /usr/xenomai/bin/latency -p 100 -T 3000 


출처 :
http://naudhizb.tistory.com/280
https://code.google.com/p/picnc/wiki/RPiXenomaiKernel

vi 명령어 & gcc 옵션

<<vi 명령어>>
dd  현재라인 잘라내기
yy  현재 라인 복사
p  아래쪽으로 붙여넣기
v  visual 모드로 블록 지정
u  undo
.  이전 명령 실행
/  검색기능
q!  강제 종료
wq  저장 후 종료

<<GCC 전역 옵션>>
-E  전처리 과정을 출력
-v  컴파일 과정 출력
-S  어셈블리 파일 생성
-c   오브젝트 파일 생성
--save-tmps  컴파일 시 생성되는 중간 파일 저장
-da  컴파일 과정에서 생성되는 중간 코드 생성(RTL 파일 등 생성)
-o  출력파일 이름 지정 ex) gcc 출력파일이름 컴파일 대상이름 -->  gcc -o gettime gettime.c

<<전처리기(cpp0) 옵션>>
-I (+경로)  헤더 파일을 탐색할 디렉토리 지정 ex) -I/Desktop/test
-include (+헤더파일 경로)  해당 헤더 파일을 모든 소스 내 추가

<<C컴파일러(cc1) 옵션>>
▲C언어 옵션
-ansi  ANSI C 문법으로 문법 검사
-std=(+C표준)  지정한 C표준으로 문법 검사 (표준:c89, c99, gnu89 등)
-traditional  K&R C 문법으로 문법 검사
-fno-asm  asm, inline, typeof 키워드를 사용하지 않음

경고 옵션
-Wall -W  모든 경고 메시지 출력
-w  모든 경고 메세지 제거
-Werror  모든 경고를 오류로 취급하여 컴파일 중단
-pedantic  C89표준에서 요구하는 모든 경고 메세지 표시
-pedantic-errors  C89표준에서 요구하는 모든 오류 메세지 표시
-Wtraditional  ANSI C와 K&R C 간에 서로 다른 결과를 가져올 수 있는 부분이 있다면 경고

최적화 옵션
-O0  최적화 안함
-O1  최적화 레벨 1
-O2  최적화 레벨 2
-O3  최적화 레벨 3
-O4  사이즈 최적화

디버깅 옵션
-g  바이너리 파일에 디버깅 정보 삽입
-g0  디버깅 정보 사입 안함
-g3  디버깅 정보 가장 많이 제공
-pg  프로파일을 위한 코드 삽입

<<어셈블리 옵션>>
-Wa,(+옵션 리스트)  어셈블러에게 옵션 리스트 전달
-Wa, -al  어셈블리된 코드와 인스트력션을 보임
-Wa, -as  정의된 심볼을 보임

<<링크 옵션>>
-L (+경로)  라이브러리 탐색 디렉토리 지정 ex) -L/Desktop/test
-l (+라이브러리 이름)  링크할 라이브러리 지정 ex) libtest.so 를 쓰려면-ltest 로 써야함.
-shared  공류 라이브러리를 우선하여 링크
-static  정적 라이브러리를 우선하여 링크
-nostdlib  표준 C라이브러리를 사용하지 않음
-Wl,(+옵션 리스트)  옵션 리스트를 링크에 바로 전달
-s  실행파일에서 심볼 테이블 제거
-x  출력파일에 로컬 심볼 제거
-n  텍스트 영역을 읽기전용으로 만듦
-r  추후 링크가 가능하게 오브젝트를 만듦
-M  심볼들의 정보 출력
-oformat (+형식)  지정한 형식의 오브젝트 파일 생성

2015. 2. 21.

피아노 테스트



  Novation 社의 Launchkey Mini를 가지고 Ableton Live 9 Lite로 만들어 본 테스트 음원.
뭔가 아직 어색하다.. ㅋㅋㅋㅋ



<링크>
https://drive.google.com/file/d/0B50lLiCDqflbcmlOX0FLU05Zb1k/view?usp=sharing

2015. 2. 18.

Profile


학교 : 서울시립대학교 기계정보공학과 (University of Seoul, Mechanical Information Engineering)

취미 : 운동, 영화, OST 감상.


2010년 3월 : 서울시립대학교 기계정보공학과 입학
2011년 1월 : 공군입대
2013년 1월 : 만기전역
2013년 2월 : 국가 공인 운전면허 취득(2종 보통)
2013년 3월 : 대학 2학년 복학
2014년 3월 : 3학년 진학
2014년 9월 : 창의공학설계경진대회 교내 장려상(총장상) 수상 (대피시스템개선)
2014년 9월 : 같은 작품으로 킨텍스 전시 (결실 없음)
2014년 12월 : 같은 작품으로 CEDC 2014 참가. (결실 없음) (생각지도 못한 브레이스토밍 최우수상 수상)
2015년 2월 : TEWDA 블로그 및 유튜브 운영 시작
2015년 3월 : 4학년 진학
2016년 1월 : '사회'로 진출


  어릴 때는 영화감독, 작곡 등 예술 분야를 꿈꿔왔지만 현재는 공학의 길을 걷고 있다.
공학 분야가 내 적성에 맞고 흥미롭지만 아직 예술에 대한 꿈은 접지 않았다.

가능하다면 '예술 + 기계 + IT' 쪽으로 하고 싶다.